From 0b3dabddde89645a8de11a5d168687d89c609eb7 Mon Sep 17 00:00:00 2001
From: rowan <rowan@kitsu.cafe>
Date: Thu, 15 May 2025 14:24:06 -0500
Subject: [PATCH] initial commitl

---
 .gitignore           |   2 +
 package-lock.json    | 505 +++++++++++++++++++++++++++++++++++++++++++
 package.json         |  18 ++
 src/de/generic.ts    |  81 +++++++
 src/de/index.ts      |   4 +
 src/de/interface.ts  |  88 ++++++++
 src/de/mixin.ts      |  30 +++
 src/index.ts         | 400 ++++++++++++++++++++++++++++++++++
 src/json.ts          | 388 +++++++++++++++++++++++++++++++++
 src/ser/impl.ts      |  78 +++++++
 src/ser/index.ts     |   4 +
 src/ser/interface.ts |  65 ++++++
 src/ser/mixin.ts     |  37 ++++
 src/test.ts          |  33 +++
 src/utils.ts         |  72 ++++++
 tsconfig.json        | 113 ++++++++++
 16 files changed, 1918 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 package-lock.json
 create mode 100644 package.json
 create mode 100644 src/de/generic.ts
 create mode 100644 src/de/index.ts
 create mode 100644 src/de/interface.ts
 create mode 100644 src/de/mixin.ts
 create mode 100644 src/index.ts
 create mode 100644 src/json.ts
 create mode 100644 src/ser/impl.ts
 create mode 100644 src/ser/index.ts
 create mode 100644 src/ser/interface.ts
 create mode 100644 src/ser/mixin.ts
 create mode 100644 src/test.ts
 create mode 100644 src/utils.ts
 create mode 100644 tsconfig.json

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ed1bf77
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+out/
+node_modules/
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..08e30e5
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,505 @@
+{
+  "name": "serde",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "serde",
+      "version": "1.0.0",
+      "license": "ISC",
+      "devDependencies": {
+        "@types/text-encoding": "^0.0.40",
+        "esbuild": "^0.25.4",
+        "typescript": "^5.8.3"
+      }
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz",
+      "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz",
+      "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz",
+      "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz",
+      "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz",
+      "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz",
+      "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz",
+      "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz",
+      "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz",
+      "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz",
+      "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz",
+      "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz",
+      "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz",
+      "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz",
+      "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz",
+      "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz",
+      "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz",
+      "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-arm64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz",
+      "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz",
+      "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-arm64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz",
+      "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz",
+      "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz",
+      "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz",
+      "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz",
+      "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz",
+      "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/@types/text-encoding": {
+      "version": "0.0.40",
+      "resolved": "https://registry.npmjs.org/@types/text-encoding/-/text-encoding-0.0.40.tgz",
+      "integrity": "sha512-dHzoIdwBfY7jcSTTt6XBkaeiuFQAQD7r/7aJySKDdHkYBCDOvs9jPVt4NYXuwBMn89PP6gSd29WubIS19wTiXg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/esbuild": {
+      "version": "0.25.4",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz",
+      "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.25.4",
+        "@esbuild/android-arm": "0.25.4",
+        "@esbuild/android-arm64": "0.25.4",
+        "@esbuild/android-x64": "0.25.4",
+        "@esbuild/darwin-arm64": "0.25.4",
+        "@esbuild/darwin-x64": "0.25.4",
+        "@esbuild/freebsd-arm64": "0.25.4",
+        "@esbuild/freebsd-x64": "0.25.4",
+        "@esbuild/linux-arm": "0.25.4",
+        "@esbuild/linux-arm64": "0.25.4",
+        "@esbuild/linux-ia32": "0.25.4",
+        "@esbuild/linux-loong64": "0.25.4",
+        "@esbuild/linux-mips64el": "0.25.4",
+        "@esbuild/linux-ppc64": "0.25.4",
+        "@esbuild/linux-riscv64": "0.25.4",
+        "@esbuild/linux-s390x": "0.25.4",
+        "@esbuild/linux-x64": "0.25.4",
+        "@esbuild/netbsd-arm64": "0.25.4",
+        "@esbuild/netbsd-x64": "0.25.4",
+        "@esbuild/openbsd-arm64": "0.25.4",
+        "@esbuild/openbsd-x64": "0.25.4",
+        "@esbuild/sunos-x64": "0.25.4",
+        "@esbuild/win32-arm64": "0.25.4",
+        "@esbuild/win32-ia32": "0.25.4",
+        "@esbuild/win32-x64": "0.25.4"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.8.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
+      "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=14.17"
+      }
+    }
+  }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..d4196c6
--- /dev/null
+++ b/package.json
@@ -0,0 +1,18 @@
+{
+  "name": "serde",
+  "version": "1.0.0",
+  "description": "",
+  "main": "src/index.ts",
+  "scripts": {
+    "build": "tsc",
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC",
+  "type": "commonjs",
+  "devDependencies": {
+    "esbuild": "^0.25.4",
+    "typescript": "^5.8.3"
+  }
+}
diff --git a/src/de/generic.ts b/src/de/generic.ts
new file mode 100644
index 0000000..84115b1
--- /dev/null
+++ b/src/de/generic.ts
@@ -0,0 +1,81 @@
+import { staticImplements } from '../utils'
+import { Deserialize, Deserializer, IterableAccess, MapAccess, Visitor } from './interface'
+
+@staticImplements<Deserialize<any>>()
+export class GenericSeed<T> implements Deserialize<T> {
+  static deserialize<T, D extends Deserializer>(deserializer: D): T {
+    return deserializer.deserializeAny(new GenericVisitor<T>())
+  }
+
+  deserialize<D extends Deserializer>(deserializer: D): T {
+    return GenericSeed.deserialize(deserializer)
+  }
+}
+
+export class GenericVisitor<T> implements Visitor<T> {
+  visitString(value: string): T {
+    return value as T
+  }
+
+  visitNumber(value: number): T {
+    return value as T
+  }
+
+  visitBigInt(value: bigint): T {
+    return value as T
+  }
+
+  visitBoolean(value: boolean): T {
+    return value as T
+  }
+
+  visitSymbol(value: symbol): T {
+    return value as T
+  }
+
+  visitNull(): T {
+    return null as T
+  }
+
+  visitObject(access: MapAccess): T {
+    const result: Record<PropertyKey, any> = {}
+    let entry
+
+    while ((entry = access.nextEntry<string, any>())) {
+      result[entry[0]] = entry[1]
+    }
+
+    return result
+  }
+
+  visitFunction?(value: Function): T {
+    return value as T
+  }
+
+  visitMap?(access: MapAccess): T {
+    const result = new Map()
+    let entry
+
+    while ((entry = access.nextEntry<string, any>())) {
+      result.set(entry[0], entry[1])
+    }
+
+    return result as T
+  }
+
+  visitIterable?(access: IterableAccess): T {
+    const result = new Array(access.sizeHint())
+    let element
+
+    while ((element = access.nextElement())) {
+      result.push(element)
+    }
+
+    return result as T
+  }
+
+  visitClass?(_name: string, _fields: string[], _value: any): T {
+    throw new Error('Method not implemented.')
+  }
+}
+
diff --git a/src/de/index.ts b/src/de/index.ts
new file mode 100644
index 0000000..62e48a6
--- /dev/null
+++ b/src/de/index.ts
@@ -0,0 +1,4 @@
+export * from './interface'
+export * from './generic'
+export * from './mixin'
+
diff --git a/src/de/interface.ts b/src/de/interface.ts
new file mode 100644
index 0000000..165b538
--- /dev/null
+++ b/src/de/interface.ts
@@ -0,0 +1,88 @@
+import { Nullable } from '../utils'
+import { GenericSeed } from './generic'
+
+export interface MapAccess {
+  nextKeySeed<T, K extends Deserialize<T>>(seed: K): Nullable<T>
+  nextValueSeed<T, V extends Deserialize<T>>(seed: V): Nullable<T>
+  nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Nullable<[TK, TV]>
+  nextKey<T>(): Nullable<T>
+  nextValue<T>(): Nullable<T>
+  nextEntry<K, V>(): Nullable<[K, V]>
+}
+
+export abstract class DefaultMapAccessImpl implements MapAccess {
+  abstract nextKeySeed<T, K extends Deserialize<T>>(seed: K): Nullable<T>
+  abstract nextValueSeed<T, V extends Deserialize<T>>(seed: V): Nullable<T>
+
+  nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Nullable<[TK, TV]> {
+    const key = this.nextKeySeed(kseed) as Nullable<TK>
+    if (key) {
+      const value = this.nextValueSeed(vseed) as Nullable<TV>
+
+      if (value) {
+        return [key, value]
+      }
+    }
+  }
+
+  nextKey<T>(): Nullable<T> {
+    return this.nextValueSeed(GenericSeed<T>)
+  }
+
+  nextValue<T>(): Nullable<T> {
+    return this.nextValueSeed(GenericSeed<T>)
+  }
+
+  nextEntry<K, V>(): Nullable<[K, V]> {
+    return this.nextEntrySeed(GenericSeed<K>, GenericSeed<V>)
+  }
+}
+
+export interface IterableAccess {
+  nextElementSeed<T, I extends Deserialize<T>>(seed: I): Nullable<T>
+  nextElement<T>(): Nullable<T>
+  sizeHint(): number
+}
+
+export abstract class DefaultIterableAccessImpl implements IterableAccess {
+  abstract nextElementSeed<T, I extends Deserialize<T>>(seed: I): Nullable<T>
+
+  nextElement<T>(): Nullable<T> {
+    return this.nextElementSeed(GenericSeed<T>)
+  }
+
+  sizeHint(): number { return 0 }
+}
+
+export interface Visitor<T> {
+  visitString(value: string): T
+  visitNumber(value: number): T
+  visitBigInt(value: bigint): T
+  visitBoolean(value: boolean): T
+  visitSymbol(value: symbol): T
+  visitNull(): T
+  visitObject(value: MapAccess): T
+  visitFunction?(value: Function): T
+  visitMap?(value: MapAccess): T
+  visitIterable?(value: IterableAccess): T
+  visitClass?(name: string, fields: string[], value: any): T
+}
+
+export interface Deserializer {
+  deserializeAny<T, V extends Visitor<T>>(visitor: V): T
+  deserializeString<T, V extends Visitor<T>>(visitor: V): T
+  deserializeNumber<T, V extends Visitor<T>>(visitor: V): T
+  deserializeBigInt<T, V extends Visitor<T>>(visitor: V): T
+  deserializeBoolean<T, V extends Visitor<T>>(visitor: V): T
+  deserializeSymbol<T, V extends Visitor<T>>(visitor: V): T
+  deserializeNull<T, V extends Visitor<T>>(visitor: V): T
+  deserializeObject<T, V extends Visitor<T>>(visitor: V): T
+  deserializeFunction?<T, V extends Visitor<T>>(visitor: V): T
+  deserializeMap?<T, V extends Visitor<T>>(visitor: V): T
+  deserializeIterable?<T, V extends Visitor<T>>(visitor: V): T
+  deserializeClass?<T, V extends Visitor<T>>(name: string, fields: string[], visitor: V): T
+}
+
+export interface Deserialize<T> {
+  deserialize<D extends Deserializer>(deserializer: D): T
+}
diff --git a/src/de/mixin.ts b/src/de/mixin.ts
new file mode 100644
index 0000000..2c7cc9f
--- /dev/null
+++ b/src/de/mixin.ts
@@ -0,0 +1,30 @@
+import { CaseConvention, Constructor, staticImplements } from '../utils'
+import { GenericVisitor } from './generic'
+import { Deserialize, Deserializer } from './interface'
+
+export interface DeserializationOptions {
+  rename?: string
+  renameAll?: CaseConvention
+}
+
+const DefaultDeserializationOptions = {}
+
+export function deserialize(options?: DeserializationOptions) {
+  options = {
+    ...DefaultDeserializationOptions,
+    ...options
+  }
+
+  return function <T, C extends Constructor>(constructor: C) {
+    @staticImplements<Deserialize<T>>()
+    class Deserializable extends constructor {
+      static deserialize<D extends Deserializer>(deserializer: D): T {
+        const visitor = new GenericVisitor<T>()
+        return deserializer.deserializeAny(visitor)
+      }
+    }
+
+    return Deserializable
+  }
+}
+
diff --git a/src/index.ts b/src/index.ts
new file mode 100644
index 0000000..acf717a
--- /dev/null
+++ b/src/index.ts
@@ -0,0 +1,400 @@
+//export type Nullable<T> = T | undefined
+//
+//function staticImplements<T>() {
+//  return <U extends T>(constructor: U) => { constructor }
+//}
+//
+//@staticImplements<Deserialize<any>>()
+//class GenericSeed<T> implements Deserialize<T> {
+//  static deserialize<T, D extends Deserializer>(deserializer: D): T {
+//    return deserializer.deserializeAny(new GenericVisitor<T>())
+//  }
+//
+//  deserialize<D extends Deserializer>(deserializer: D): T {
+//    return GenericSeed.deserialize(deserializer)
+//  }
+//}
+//
+//class GenericVisitor<T> implements Visitor<T> {
+//  visitString(value: string): T {
+//    return value as T
+//  }
+//
+//  visitNumber(value: number): T {
+//    return value as T
+//  }
+//
+//  visitBigInt(value: bigint): T {
+//    return value as T
+//  }
+//
+//  visitBoolean(value: boolean): T {
+//    return value as T
+//  }
+//
+//  visitSymbol(value: symbol): T {
+//    return value as T
+//  }
+//
+//  visitNull(): T {
+//    return null as T
+//  }
+//
+//  visitObject(access: MapAccess): T {
+//    const result: Record<PropertyKey, any> = {}
+//    let entry
+//
+//    while ((entry = access.nextEntry<string, any>())) {
+//      result[entry[0]] = entry[1]
+//    }
+//
+//    return result
+//  }
+//
+//  visitFunction?(value: Function): T {
+//    return value as T
+//  }
+//
+//  visitMap?(access: MapAccess): T {
+//    const result = new Map()
+//    let entry
+//
+//    while ((entry = access.nextEntry<string, any>())) {
+//      result.set(entry[0], entry[1])
+//    }
+//
+//    return result as T
+//  }
+//
+//  visitIterable?(access: IterableAccess): T {
+//    const result = new Array(access.sizeHint())
+//    let element
+//
+//    while ((element = access.nextElement())) {
+//      result.push(element)
+//    }
+//
+//    return result as T
+//  }
+//
+//  visitClass?(_name: string, _fields: string[], _value: any): T {
+//    throw new Error("Method not implemented.")
+//  }
+//}
+//
+//export abstract class MapAccess {
+//  abstract nextKeySeed<T, K extends Deserialize<T>>(seed: K): Nullable<T>
+//  abstract nextValueSeed<T, V extends Deserialize<T>>(seed: V): Nullable<T>
+//
+//  nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Nullable<[TK, TV]> {
+//    const key = this.nextKeySeed(kseed) as Nullable<TK>
+//    if (key) {
+//      const value = this.nextValueSeed(vseed) as Nullable<TV>
+//
+//      if (value) {
+//        return [key, value]
+//      }
+//    }
+//  }
+//
+//  nextKey<T>(): Nullable<T> {
+//    return this.nextValueSeed(GenericSeed<T>)
+//  }
+//
+//  nextValue<T>(): Nullable<T> {
+//    return this.nextValueSeed(GenericSeed<T>)
+//  }
+//
+//  nextEntry<K, V>(): Nullable<[K, V]> {
+//    return this.nextEntrySeed(GenericSeed<K>, GenericSeed<V>)
+//  }
+//}
+//
+//export abstract class IterableAccess {
+//  abstract nextElementSeed<T, I extends Deserialize<T>>(seed: I): Nullable<T>
+//
+//  nextElement<T>(): Nullable<T> {
+//    return this.nextElementSeed(GenericSeed<T>)
+//  }
+//
+//  sizeHint(): number { return 0 }
+//}
+//
+//export interface ObjectSerializer<T = void> {
+//  serializeKey<U extends Serializable>(key: U): T
+//  serializeValue<U extends Serializable>(value: U): T
+//  end(): T
+//}
+//
+//export interface IterableSerializer<T = void> {
+//  serializeElement<U extends Serializable>(element: U): T
+//  end(): T
+//}
+//
+//export interface ClassSerializer<T = void> {
+//  serializeField<U extends Serializable>(name: PropertyKey, value: U): T
+//  end(): T
+//}
+//
+//const TypeSerializerMethods = [
+//  'serializeString',
+//  'serializeNumber',
+//  'serializeBigInt',
+//  'serializeBoolean',
+//  'serializeSymbol',
+//  'serializeMap',
+//  'serializeIterable',
+//  'serializeNull',
+//  'serializeObject',
+//  'serializeInstance',
+//  'serializeFunction'
+//] as const
+//
+//interface TypeSerializer<T> {
+//  serializeString(value: string): T
+//  serializeNumber(value: number): T
+//  serializeBigInt(value: bigint): T
+//  serializeBoolean(value: boolean): T
+//  serializeSymbol(value: Symbol): T
+//  serializeNull(): T
+//  serializeObject(): ObjectSerializer<T>
+//  serializeFunction?(value: Function): T
+//  serializeMap?(): ObjectSerializer<T>
+//  serializeIterable?(): IterableSerializer<T>
+//  serializeClass?(name: PropertyKey): ClassSerializer<T>
+//}
+//
+//const AnySerializerMethods = ['serializeAny']
+//
+//interface AnySerializer<T> {
+//  serializeAny?(value?: any): T
+//}
+//
+//function isGenericSerializer(value: any): boolean {
+//  return AnySerializerMethods.every(k => isFunction(value[k])) &&
+//    TypeSerializerMethods.every(k => !isFunction(value[k]))
+//}
+//
+//function isPlainObject(value: any): boolean {
+//  return Object.getPrototypeOf(value) === Object.prototype
+//}
+//
+//function isFunction(value: any): value is Function {
+//  return value != null && typeof value === 'function'
+//}
+//
+//function isIterable(value: any): value is Iterable<any> {
+//  return isFunction(value[Symbol.iterator])
+//}
+//
+//export type Serializer<T> = Partial<TypeSerializer<T>> & Partial<AnySerializer<T>>
+//
+//export interface Visitor<T> {
+//  visitString(value: string): T
+//  visitNumber(value: number): T
+//  visitBigInt(value: bigint): T
+//  visitBoolean(value: boolean): T
+//  visitSymbol(value: symbol): T
+//  visitNull(): T
+//  visitObject(value: MapAccess): T
+//  visitFunction?(value: Function): T
+//  visitMap?(value: MapAccess): T
+//  visitIterable?(value: IterableAccess): T
+//  visitClass?(name: string, fields: string[], value: any): T
+//}
+//
+//export interface Deserializer {
+//  deserializeAny<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeString<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeNumber<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeBigInt<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeBoolean<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeSymbol<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeNull<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeObject<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeFunction?<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeMap?<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeIterable?<T, V extends Visitor<T>>(visitor: V): T
+//  deserializeClass?<T, V extends Visitor<T>>(name: string, fields: string[], visitor: V): T
+//}
+//
+//export type Primitive = string | number | boolean | symbol | bigint | null | undefined
+//export interface ToString {
+//  toString(): string
+//}
+//
+//export interface Serialize {
+//  serialize<T, S extends Serializer<T>>(serializer: S): T
+//}
+//
+//export type Serializable = Primitive | ToString | Serialize
+//
+//export interface Deserialize<T> {
+//  deserialize<D extends Deserializer>(deserializer: D): T
+//}
+//
+//type Constructor = new (...args: any[]) => object
+//
+//export const CaseConvention = Object.freeze({
+//  Lowercase: 0,
+//  Uppercase: 1,
+//  PascalCase: 2,
+//  CamelCase: 3,
+//  SnakeCase: 4,
+//  ScreamingSnakeCase: 5,
+//  KebabCase: 6,
+//  ScreamingKebabCase: 7
+//} as const)
+//
+//export type CaseConvention = typeof CaseConvention[keyof typeof CaseConvention]
+//
+//function orElse(thisArg: any, a: Nullable<Function>, b: Function) {
+//  return function(...args: any) {
+//    const fn = a != null ? a : b
+//    return fn.apply(thisArg, args)
+//  }
+//}
+//
+//// helper for better ergonomics
+//// allows us to capture this, the fallback method, and the args in a closure
+//function ifNull(thisArg: any, b: Function, ...args: any) {
+//  return function(a: Nullable<Function>) {
+//    return orElse(thisArg, a, b).call(thisArg, args)
+//  }
+//}
+//
+//const unhandledType = (serializer: any, value: any) => new TypeError(`"${serializer.constructor.name}" has no method for value type "${typeof value}"`)
+//
+//function serializeEntries<T, K extends Serializable, V extends Serializable, E extends Iterable<[K, V]>>(serializer: ObjectSerializer<T>, value: E) {
+//  let state
+//
+//  for (const [key, val] of value) {
+//    state = serializer.serializeKey(key)
+//    state = serializer.serializeValue(val)
+//  }
+//
+//  return serializer.end()
+//}
+//
+//function serializeObject<T, K extends PropertyKey, V extends Serializable, R extends Record<K, V>>(serializer: ObjectSerializer<T>, value: R) {
+//  return serializeEntries(serializer, Object.entries(value) as Iterable<[K, V]>)
+//}
+//
+//function getClassName(value: any): Nullable<string> {
+//  return value?.constructor.name
+//}
+//
+//function serializeClass<T, K extends PropertyKey, V extends Serializable, R extends Record<K, V>>(serializer: ClassSerializer<T>, value: R) {
+//  for (const prop in value) {
+//    serializer.serializeField(prop, value[prop])
+//  }
+//
+//  return serializer.end()
+//}
+//
+//function serializeIter<T, V extends Iterable<any>>(serializer: IterableSerializer<T>, value: V) {
+//  let state
+//
+//  for (const val of value) {
+//    state = serializer.serializeElement(val)
+//  }
+//
+//  return serializer.end()
+//}
+//
+//// dispatches in the order of serialize<type> -> serializeAny -> throw TypeError
+//export function serializeWith<T>(serializer: Serializer<T>, value: Serializable): Nullable<T> {
+//  // prepare fallback methods
+//  const serializeAny = orElse(
+//    serializer,
+//    serializer.serializeAny,
+//    (value: Serializable) => unhandledType(serializer, value)
+//  )
+//
+//  const serialize = ifNull(serializer, serializeAny, value)
+//
+//  switch (typeof value) {
+//    case 'string': return serialize(serializer.serializeString)
+//    case 'number': return serialize(serializer.serializeNumber)
+//    case 'bigint': return serialize(serializer.serializeBigInt)
+//    case 'boolean': return serialize(serializer.serializeBoolean)
+//    case 'symbol': return serialize(serializer.serializeSymbol)
+//    case 'undefined': return serialize(serializer.serializeNull)
+//    case 'function': return serialize(serializer.serializeFunction)
+//
+//    case 'object':
+//      if (value instanceof Map && isFunction(serializer.serializeMap)) {
+//        return serializeEntries(serializer.serializeMap(), value)
+//      } else if (isIterable(value) && isFunction(serializer.serializeIterable)) {
+//        return serializeIter(serializer.serializeIterable(), value)
+//      } else if (isFunction(serializer.serializeClass) && !isPlainObject(value)) {
+//        const name = getClassName(value)
+//        return serializeClass(serializer.serializeClass(name!), value as any)
+//      } else if (isFunction(serializer.serializeObject)) {
+//        return serializeObject(serializer.serializeObject!(), value as Record<PropertyKey, any>)
+//      } // deliberate fallthrough when the above fail
+//
+//    default: return serializeAny(value)
+//  }
+//}
+//
+//export interface SerializationOptions {
+//  default?: <T>() => T
+//  rename?: string
+//  renameAll?: CaseConvention
+//  tag?: string
+//  untagged?: boolean
+//  withInherited?: boolean
+//}
+//
+//const DefaultSerializationOptions: SerializationOptions = {
+//  withInherited: true
+//}
+//
+//export function serialize(options?: SerializationOptions) {
+//  options = {
+//    ...DefaultSerializationOptions,
+//    ...options
+//  }
+//
+//  return function <T extends Constructor>(constructor: T) {
+//    return class Serializable extends constructor implements Serializable {
+//      static name = constructor.name
+//      serialize<U>(serializer: Serializer<U>): U {
+//        // shortcut for serializers with only the serializeAny method
+//        if (isGenericSerializer(serializer)) {
+//          return serializer.serializeAny!(this) as U
+//        } else {
+//          return serializeWith(serializer, this) as U
+//        }
+//      }
+//    }
+//  }
+//}
+//
+//export interface DeserializationOptions {
+//  rename?: string
+//  renameAll?: CaseConvention
+//}
+//
+//const DefaultDeserializationOptions = {
+//}
+//
+//export function deserialize(options?: DeserializationOptions) {
+//  options = {
+//    ...DefaultDeserializationOptions,
+//    ...options
+//  }
+//
+//  return function <T, C extends Constructor>(constructor: C) {
+//    @staticImplements<Deserialize<T>>()
+//    class Deserializable extends constructor {
+//      static deserialize<D extends Deserializer>(deserializer: D): T {
+//        const visitor = new GenericVisitor<T>()
+//        return deserializer.deserializeAny(visitor)
+//      }
+//    }
+//
+//    return Deserializable
+//  }
+//}
diff --git a/src/json.ts b/src/json.ts
new file mode 100644
index 0000000..0f75479
--- /dev/null
+++ b/src/json.ts
@@ -0,0 +1,388 @@
+import { DefaultIterableAccessImpl, DefaultMapAccessImpl, Deserialize, Deserializer, IterableAccess, MapAccess, Visitor } from './de'
+import { Serializer, serializeWith } from './ser'
+import { mixin, Nullable } from './utils'
+
+export function toString(value: any): string {
+  return serializeWith(new JSONSerializer(), value)!
+}
+
+export function fromString<T, D extends Deserialize<T>>(value: string, into: D): T {
+  const deserializer = JSONDeserializer.fromString(value)
+  return into.deserialize(deserializer)
+}
+
+type Byte = number
+
+const clamp = (value: number, min: number, max: number): number => {
+  return Math.min(Math.max(value, min), max)
+}
+
+const isNumeric = (value: any): value is number => {
+  return !isNaN(value)
+}
+
+const isNumericToken = (value: Byte) => {
+  return value === Token.Period || value === Token.Hyphen || Token.Digit.includes(value)
+}
+
+interface Predicate<T> {
+  (value: T): boolean
+}
+
+const encoder = new TextEncoder()
+const b = (strings: TemplateStringsArray) => encoder.encode(strings[0])
+const char = (strings: TemplateStringsArray) => b(strings)[0]
+
+const Literal = Object.freeze({
+  True: b`true`,
+  False: b`false`
+} as const)
+
+const Token = Object.freeze({
+  Space: char` `,
+  LeftCurly: char`{`,
+  RightCurly: char`}`,
+  LeftSquare: char`[`,
+  RightSquare: char`]`,
+  Quote: char`"`,
+  ForwardSlash: char`\\`,
+  Digit: b`0123456789`,
+  Hyphen: char`-`,
+  Period: char`.`,
+  Comma: char`,`,
+  Colon: char`:`
+} as const)
+
+
+export interface CommaSeparated extends MapAccess, IterableAccess { }
+@mixin<MapAccess>(DefaultMapAccessImpl)
+@mixin<IterableAccess>(DefaultIterableAccessImpl)
+export class CommaSeparated implements MapAccess, IterableAccess {
+  private readonly de: JSONDeserializer
+  private first: boolean = true
+
+  constructor(deserializer: JSONDeserializer) {
+    this.de = deserializer
+  }
+
+  nextKeySeed<T, K extends Deserialize<T>>(seed: K): Nullable<T> {
+    if (this.de.buffer.peek().next() === Token.RightCurly) {
+      return
+    }
+
+    if (!this.first) {
+      const take = this.de.buffer.take()
+      if (take.next() !== Token.Comma) {
+        throw unexpected(',', take.toString(), this.de.buffer.position)
+      }
+    }
+
+    this.first = false
+    return seed.deserialize(this.de)
+  }
+
+  nextValueSeed<T, V extends Deserialize<T>>(seed: V): Nullable<T> {
+    const next = this.de.buffer.next()
+    if (next !== Token.Colon) {
+      throw unexpected(':', next.toString(), this.de.buffer.position)
+    }
+
+    return seed.deserialize(this.de)
+  }
+
+  nextElementSeed<T, I extends Deserialize<T>>(seed: I): Nullable<T> {
+    if (this.de.buffer.peek().next() === Token.RightSquare) {
+      return
+    }
+
+    if (!this.first) {
+      const take = this.de.buffer.take()
+      if (take.next() !== Token.Comma) {
+        throw unexpected(',', take.toString(), this.de.buffer.position)
+      }
+    }
+
+    this.first = false
+    return seed.deserialize(this.de)
+  }
+}
+
+class StringBuffer {
+  private readonly view: Uint8Array
+  private index: number = 0
+  private readonly encoder: TextEncoder
+  private readonly decoder: TextDecoder
+
+  get position() {
+    return this.index
+  }
+
+  get length() {
+    return this.view.byteLength
+  }
+
+  constructor(view: Uint8Array, encoder: TextEncoder = new TextEncoder(), decoder: TextDecoder = new TextDecoder()) {
+    this.view = view
+    this.encoder = encoder
+    this.decoder = decoder
+  }
+
+  static fromArrayBuffer(value: ArrayBuffer, encoder?: TextEncoder, decoder?: TextDecoder): StringBuffer {
+    return new this(new Uint8Array(value), encoder, decoder)
+  }
+
+  static fromString(value: string, encoder: TextEncoder = new TextEncoder(), decoder?: TextDecoder): StringBuffer {
+    return this.fromArrayBuffer(
+      encoder.encode(value),
+      encoder,
+      decoder
+    )
+  }
+
+  next() {
+    const value = this.view[this.index]
+    this.index += 1
+    return value
+  }
+
+  nextChar() {
+    return this.take().toString()
+  }
+
+  done(): boolean {
+    return this.index >= this.view.byteLength
+  }
+
+  toBytes() {
+    return this.view.slice(this.index)
+  }
+
+  toString() {
+    return this.decoder.decode(this.toBytes())
+  }
+
+  take(limit: number = 1): StringBuffer {
+    const bytes = this.peek(limit)
+    this.index += limit
+    return bytes
+  }
+
+  at(index: number) {
+    return this.view[this.index + index]
+  }
+
+  takeWhile(fn: Predicate<number>): StringBuffer {
+    let index = 0
+
+    while (!this.done() && fn(this.at(index))) {
+      index += 1
+    }
+
+    return this.take(index)
+  }
+
+  drop(limit: number) {
+    this.index += limit
+    return this
+  }
+
+  peek(limit: number = 1): StringBuffer {
+    const index = this.index
+    return this.slice(index, index + limit)
+  }
+
+  startsWith(value: string | ArrayBufferLike): boolean {
+    if (typeof value === 'string') {
+      return this.startsWith(this.encoder.encode(value))
+    }
+
+    const length = value.byteLength
+    const bytes = new Uint8Array(value)
+
+    return this.peek(length).toBytes().every((v, i) => v === bytes[i])
+  }
+
+  slice(start?: number, end?: number) {
+    return new StringBuffer(
+      this.view.subarray(start, end),
+      this.encoder,
+      this.decoder
+    )
+  }
+
+  indexOf(value: number | ArrayBufferLike, start: number = 0) {
+    const search = new Uint8Array(isNumeric(value) ? [value] : value)
+    start = clamp(start, this.index, this.length)
+    const bytes = this.slice(start)
+
+    for (let i = 0, len = bytes.length; i < len; i++) {
+      if (bytes.at(i) === search[0] && bytes.slice(i).startsWith(search)) {
+        return i
+      }
+    }
+
+    return -1
+  }
+}
+
+export class JSONSerializer implements Serializer<string> {
+  serializeAny(value?: any): string {
+    return JSON.stringify(value)
+  }
+}
+
+const unexpected = (expected: string, actual: string, position: number) => new SyntaxError(`Expected ${expected} at position ${position} (got '${actual}')`)
+
+export class JSONDeserializer implements Deserializer {
+  readonly buffer: StringBuffer
+
+  constructor(buffer: StringBuffer) {
+    this.buffer = buffer
+  }
+
+  static fromString(value: string): JSONDeserializer {
+    return new this(StringBuffer.fromString(value))
+  }
+
+  deserializeAny<T, V extends Visitor<T>>(visitor: V): T {
+    const peek = this.buffer.peek()
+    const nextByte = peek.take()
+    const byte = nextByte.next()
+
+    switch (true) {
+      case b`n`.includes(byte):
+        return this.deserializeNull(visitor)
+      case b`tf`.includes(byte):
+        return this.deserializeBoolean(visitor)
+      case b`-0123456789`.includes(byte):
+        return this.deserializeNumber(visitor)
+      case Token.Quote === byte:
+        return this.deserializeString(visitor)
+      case Token.LeftSquare === byte:
+        return this.deserializeIterable!(visitor)
+      case Token.LeftCurly === byte:
+        return this.deserializeObject(visitor)
+      default:
+        throw new SyntaxError(`Invalid syntax at position ${this.buffer.position}: "${nextByte.toString()}"`)
+    }
+  }
+
+  deserializeNull<T, V extends Visitor<T>>(visitor: V): T {
+    if (this.buffer.startsWith('null')) {
+      this.buffer.take(4)
+    }
+
+    return visitor.visitNull()
+  }
+
+  deserializeObject<T, V extends Visitor<T>>(visitor: V): T {
+    let next = this.buffer.take()
+    if (next.next() === Token.LeftCurly) {
+
+      const value = visitor.visitObject(new CommaSeparated(this))
+
+      next = this.buffer.take()
+      if (next.next() === Token.RightCurly) {
+        return value
+      } else {
+        throw unexpected('}', next.toString(), this.buffer.position)
+      }
+    } else {
+      throw unexpected('{', next.toString(), this.buffer.position)
+    }
+  }
+
+  deserializeString<T, V extends Visitor<T>>(visitor: V): T {
+    const next = this.buffer.take()
+    if (next.next() === Token.Quote) {
+      let index = -1
+
+      do {
+        index = this.buffer.indexOf(Token.Quote, index)
+      } while (index > -1 && this.buffer.at(index - 1) === Token.ForwardSlash)
+
+      if (index === -1) {
+        throw new SyntaxError('Unterminated string literal')
+      }
+
+      const bytes = this.buffer.take(index)
+      this.buffer.take()
+      return visitor.visitString(bytes.toString())
+    } else {
+      throw unexpected('"', next.toString(), this.buffer.position)
+    }
+  }
+
+  deserializeNumber<T, V extends Visitor<T>>(visitor: V): T {
+    const next = this.buffer.peek().next()
+
+    if (isNumericToken(next)) {
+      const digits = this.buffer.takeWhile(isNumericToken).toString()
+      if (digits.length >= 16) {
+        const number = BigInt(digits)
+        return visitor.visitBigInt(number)
+      } else if (digits.length > 0) {
+        let number = parseInt(digits.toString(), 10)
+        return visitor.visitNumber(number)
+      }
+    }
+
+    throw unexpected('"-", ".", or 0..=9', next.toString(), this.buffer.position)
+  }
+
+  deserializeBigInt<T, V extends Visitor<T>>(visitor: V): T {
+    return this.deserializeNumber(visitor)
+  }
+
+  deserializeBoolean<T, V extends Visitor<T>>(visitor: V): T {
+    const next = this.buffer.next()
+    let length = 3
+
+    switch (next) {
+      case Literal.False[0]:
+        length = 4
+      case Literal.True[0]:
+        break
+      default:
+        throw unexpected('"true" or "false"', this.buffer.next().toString(), this.buffer.position)
+    }
+
+    this.buffer.take(length)
+    return visitor.visitBoolean(length === 3)
+  }
+
+  deserializeSymbol<T, V extends Visitor<T>>(_visitor: V): T {
+    throw new Error('Method not implemented.')
+  }
+
+  deserializeFunction?<T, V extends Visitor<T>>(_visitor: V): T {
+    throw new Error('Method not implemented.')
+  }
+
+  deserializeMap?<T, V extends Visitor<T>>(_visitor: V): T {
+    throw new Error('Method not implemented.')
+  }
+
+  deserializeIterable?<T, V extends Visitor<T>>(visitor: V): T {
+    let next = this.buffer.take()
+    if (next.next() === Token.LeftSquare) {
+
+      const value = visitor.visitIterable!(new CommaSeparated(this))
+
+      next = this.buffer.take()
+      if (next.next() === Token.RightSquare) {
+        return value
+      } else {
+        throw unexpected(']', next.toString(), this.buffer.position)
+      }
+    } else {
+      throw unexpected('[', next.toString(), this.buffer.position)
+    }
+  }
+
+  deserializeClass?<T, V extends Visitor<T>>(name: string, fields: string[], visitor: V): T {
+    throw new Error('Method not implemented.')
+  }
+}
+
+
diff --git a/src/ser/impl.ts b/src/ser/impl.ts
new file mode 100644
index 0000000..68495c5
--- /dev/null
+++ b/src/ser/impl.ts
@@ -0,0 +1,78 @@
+import { ifNull, isFunction, isIterable, isPlainObject, Nullable, orElse } from '../utils'
+import { ClassSerializer, IterableSerializer, ObjectSerializer, Serializable, Serializer } from './interface'
+
+const unhandledType = (serializer: any, value: any) => new TypeError(`'${serializer.constructor.name}' has no method for value type '${typeof value}'`)
+
+function serializeEntries<T, K extends Serializable, V extends Serializable, E extends Iterable<[K, V]>>(serializer: ObjectSerializer<T>, value: E) {
+  let state
+
+  for (const [key, val] of value) {
+    state = serializer.serializeKey(key)
+    state = serializer.serializeValue(val)
+  }
+
+  return serializer.end()
+}
+
+function serializeObject<T, K extends PropertyKey, V extends Serializable, R extends Record<K, V>>(serializer: ObjectSerializer<T>, value: R) {
+  return serializeEntries(serializer, Object.entries(value) as Iterable<[K, V]>)
+}
+
+function getClassName(value: any): Nullable<string> {
+  return value?.constructor.name
+}
+
+function serializeClass<T, K extends PropertyKey, V extends Serializable, R extends Record<K, V>>(serializer: ClassSerializer<T>, value: R) {
+  for (const prop in value) {
+    serializer.serializeField(prop, value[prop])
+  }
+
+  return serializer.end()
+}
+
+function serializeIter<T, V extends Iterable<any>>(serializer: IterableSerializer<T>, value: V) {
+  let state
+
+  for (const val of value) {
+    state = serializer.serializeElement(val)
+  }
+
+  return serializer.end()
+}
+
+// dispatches in the order of serialize<type> -> serializeAny -> throw TypeError
+export function serializeWith<T>(serializer: Serializer<T>, value: Serializable): Nullable<T> {
+  // prepare fallback methods
+  const serializeAny = orElse(
+    serializer,
+    serializer.serializeAny,
+    (value: Serializable) => unhandledType(serializer, value)
+  )
+
+  const serialize = ifNull(serializer, serializeAny, value)
+
+  switch (typeof value) {
+    case 'string': return serialize(serializer.serializeString)
+    case 'number': return serialize(serializer.serializeNumber)
+    case 'bigint': return serialize(serializer.serializeBigInt)
+    case 'boolean': return serialize(serializer.serializeBoolean)
+    case 'symbol': return serialize(serializer.serializeSymbol)
+    case 'undefined': return serialize(serializer.serializeNull)
+    case 'function': return serialize(serializer.serializeFunction)
+
+    case 'object':
+      if (value instanceof Map && isFunction(serializer.serializeMap)) {
+        return serializeEntries(serializer.serializeMap(), value)
+      } else if (isIterable(value) && isFunction(serializer.serializeIterable)) {
+        return serializeIter(serializer.serializeIterable(), value)
+      } else if (isFunction(serializer.serializeClass) && !isPlainObject(value)) {
+        const name = getClassName(value)
+        return serializeClass(serializer.serializeClass(name!), value as any)
+      } else if (isFunction(serializer.serializeObject)) {
+        return serializeObject(serializer.serializeObject!(), value as Record<PropertyKey, any>)
+      } // deliberate fallthrough when the above fail
+
+    default: return serializeAny(value)
+  }
+}
+
diff --git a/src/ser/index.ts b/src/ser/index.ts
new file mode 100644
index 0000000..31ca20c
--- /dev/null
+++ b/src/ser/index.ts
@@ -0,0 +1,4 @@
+export * from './interface'
+export * from './mixin'
+export * from './impl'
+
diff --git a/src/ser/interface.ts b/src/ser/interface.ts
new file mode 100644
index 0000000..3eac4b9
--- /dev/null
+++ b/src/ser/interface.ts
@@ -0,0 +1,65 @@
+import { isFunction, Primitive, ToString } from "../utils"
+
+export interface ObjectSerializer<T = void> {
+  serializeKey<U extends Serializable>(key: U): T
+  serializeValue<U extends Serializable>(value: U): T
+  end(): T
+}
+
+export interface IterableSerializer<T = void> {
+  serializeElement<U extends Serializable>(element: U): T
+  end(): T
+}
+
+export interface ClassSerializer<T = void> {
+  serializeField<U extends Serializable>(name: PropertyKey, value: U): T
+  end(): T
+}
+
+const TypeSerializerMethods = [
+  'serializeString',
+  'serializeNumber',
+  'serializeBigInt',
+  'serializeBoolean',
+  'serializeSymbol',
+  'serializeMap',
+  'serializeIterable',
+  'serializeNull',
+  'serializeObject',
+  'serializeInstance',
+  'serializeFunction'
+] as const
+
+interface TypeSerializer<T> {
+  serializeString(value: string): T
+  serializeNumber(value: number): T
+  serializeBigInt(value: bigint): T
+  serializeBoolean(value: boolean): T
+  serializeSymbol(value: Symbol): T
+  serializeNull(): T
+  serializeObject(): ObjectSerializer<T>
+  serializeFunction?(value: Function): T
+  serializeMap?(): ObjectSerializer<T>
+  serializeIterable?(): IterableSerializer<T>
+  serializeClass?(name: PropertyKey): ClassSerializer<T>
+}
+
+const AnySerializerMethods = ['serializeAny']
+
+interface AnySerializer<T> {
+  serializeAny?(value?: any): T
+}
+
+export function isGenericSerializer(value: any): boolean {
+  return AnySerializerMethods.every(k => isFunction(value[k])) &&
+    TypeSerializerMethods.every(k => !isFunction(value[k]))
+}
+
+export type Serializer<T> = Partial<TypeSerializer<T>> & Partial<AnySerializer<T>>
+
+export type Serializable = Primitive | ToString | Serialize
+
+export interface Serialize {
+  serialize<T, S extends Serializer<T>>(serializer: S): T
+}
+
diff --git a/src/ser/mixin.ts b/src/ser/mixin.ts
new file mode 100644
index 0000000..b0cf375
--- /dev/null
+++ b/src/ser/mixin.ts
@@ -0,0 +1,37 @@
+import { CaseConvention, Constructor } from '../utils'
+import { serializeWith } from './impl'
+import { isGenericSerializer, Serializer } from './interface'
+
+export interface SerializationOptions {
+  default?: <T>() => T
+  rename?: string
+  renameAll?: CaseConvention
+  tag?: string
+  untagged?: boolean
+  withInherited?: boolean
+}
+
+const DefaultSerializationOptions: SerializationOptions = {
+  withInherited: true
+}
+
+export function serialize(options?: SerializationOptions) {
+  options = {
+    ...DefaultSerializationOptions,
+    ...options
+  }
+
+  return function <T extends Constructor>(constructor: T) {
+    return class Serializable extends constructor implements Serializable {
+      static name = constructor.name
+      serialize<U>(serializer: Serializer<U>): U {
+        // shortcut for serializers with only the serializeAny method
+        if (isGenericSerializer(serializer)) {
+          return serializer.serializeAny!(this) as U
+        } else {
+          return serializeWith(serializer, this) as U
+        }
+      }
+    }
+  }
+}
diff --git a/src/test.ts b/src/test.ts
new file mode 100644
index 0000000..53ae095
--- /dev/null
+++ b/src/test.ts
@@ -0,0 +1,33 @@
+import { deserialize } from './de'
+import { fromString, toString } from './json'
+import { serialize } from './ser'
+
+const InnerStruct = deserialize()(
+  @serialize()
+    class {
+    c = 'awawa'
+  })
+
+const TestStruct = deserialize()(
+  @serialize()
+    class {
+    a = 1
+    b
+    inner = new InnerStruct()
+    d = true
+    e = Math.pow(2, 53)
+    f = Symbol('test')
+    g = [1, 'a', [3]]
+
+    constructor() {
+      this.b = new Map()
+      this.b.set('test key', 2)
+    }
+  })
+
+const test = new TestStruct()
+const value = toString(test)
+console.log(value)
+const test2 = fromString(value, TestStruct)
+console.log(test2)
+
diff --git a/src/utils.ts b/src/utils.ts
new file mode 100644
index 0000000..51aeb72
--- /dev/null
+++ b/src/utils.ts
@@ -0,0 +1,72 @@
+export type Nullable<T> = T | undefined
+
+export type Primitive = string | number | boolean | symbol | bigint | null | undefined
+
+export interface ToString {
+  toString(): string
+}
+
+export function staticImplements<T>() {
+  return <U extends T>(constructor: U) => { constructor }
+}
+
+export function isPlainObject(value: any): boolean {
+  return Object.getPrototypeOf(value) === Object.prototype
+}
+
+export function isFunction(value: any): value is Function {
+  return value != null && typeof value === 'function'
+}
+
+export function isIterable(value: any): value is Iterable<any> {
+  return isFunction(value[Symbol.iterator])
+}
+
+export type Constructor<T = any> = new (...args: any[]) => T
+
+export const CaseConvention = Object.freeze({
+  Lowercase: 0,
+  Uppercase: 1,
+  PascalCase: 2,
+  CamelCase: 3,
+  SnakeCase: 4,
+  ScreamingSnakeCase: 5,
+  KebabCase: 6,
+  ScreamingKebabCase: 7
+} as const)
+
+export type CaseConvention = typeof CaseConvention[keyof typeof CaseConvention]
+
+export function orElse(thisArg: any, a: Nullable<Function>, b: Function) {
+  return function(...args: any) {
+    const fn = a != null ? a : b
+    return fn.apply(thisArg, args)
+  }
+}
+
+export function ifNull(thisArg: any, b: Function, ...args: any) {
+  return function(a: Nullable<Function>) {
+    return orElse(thisArg, a, b).call(thisArg, args)
+  }
+}
+
+function applyMixins(derivedCtor: any, constructors: any[]) {
+  constructors.forEach((baseCtor) => {
+    Object.getOwnPropertyNames(baseCtor.prototype).forEach((name) => {
+      Object.defineProperty(
+        derivedCtor.prototype,
+        name,
+        Object.getOwnPropertyDescriptor(baseCtor.prototype, name) ||
+        Object.create(null)
+      )
+    })
+  })
+}
+
+export function mixin<U = any>(impl: Function) {
+  return function <TBase extends Constructor<U>>(constructor: TBase) {
+    applyMixins(constructor, [impl])
+    return constructor
+  }
+}
+
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..fd0def4
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,113 @@
+{
+  "compilerOptions": {
+    /* Visit https://aka.ms/tsconfig to read more about this file */
+
+    /* Projects */
+    // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
+    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
+    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
+    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
+    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
+    // "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */
+
+    /* Language and Environment */
+    "target": "es2016",                                  /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
+    "lib": ["es2020", "dom"],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */
+    // "jsx": "preserve",                                /* Specify what JSX code is generated. */
+    // "libReplacement": true,                           /* Enable lib replacement. */
+    // "experimentalDecorators": true,                   /* Enable experimental support for legacy experimental decorators. */
+    // "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */
+    // "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
+    // "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
+    // "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
+    // "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
+    // "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */
+    "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */
+    // "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */
+
+    /* Modules */
+    "module": "commonjs",                                /* Specify what module code is generated. */
+    // "rootDir": "./",                                  /* Specify the root folder within your source files. */
+    // "moduleResolution": "node10",                     /* Specify how TypeScript looks up a file from a given module specifier. */
+    // "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */
+    // "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */
+    // "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */
+    // "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */
+    // "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */
+    // "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */
+    // "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */
+    // "allowImportingTsExtensions": true,               /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */
+    // "rewriteRelativeImportExtensions": true,          /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */
+    // "resolvePackageJsonExports": true,                /* Use the package.json 'exports' field when resolving package imports. */
+    // "resolvePackageJsonImports": true,                /* Use the package.json 'imports' field when resolving imports. */
+    // "customConditions": [],                           /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */
+    // "noUncheckedSideEffectImports": true,             /* Check side effect imports. */
+    // "resolveJsonModule": true,                        /* Enable importing .json files. */
+    // "allowArbitraryExtensions": true,                 /* Enable importing files with any extension, provided a declaration file is present. */
+    // "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
+
+    /* JavaScript Support */
+    // "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
+    // "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */
+    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
+
+    /* Emit */
+    // "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
+    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
+    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
+    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
+    // "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */
+    // "noEmit": true,                                   /* Disable emitting files from a compilation. */
+    // "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
+    "outDir": "./out",                                   /* Specify an output folder for all emitted files. */
+    // "removeComments": true,                           /* Disable emitting comments. */
+    // "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
+    // "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
+    // "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */
+    // "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */
+    // "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */
+    // "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
+    // "newLine": "crlf",                                /* Set the newline character for emitting files. */
+    // "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
+    // "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */
+    // "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */
+    // "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */
+    // "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */
+
+    /* Interop Constraints */
+    // "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */
+    // "verbatimModuleSyntax": true,                     /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */
+    // "isolatedDeclarations": true,                     /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */
+    // "erasableSyntaxOnly": true,                       /* Do not allow runtime constructs that are not part of ECMAScript. */
+    // "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */
+    "esModuleInterop": true,                             /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
+    // "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
+    "forceConsistentCasingInFileNames": true,            /* Ensure that casing is correct in imports. */
+
+    /* Type Checking */
+    "strict": true,                                      /* Enable all strict type-checking options. */
+    // "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */
+    // "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */
+    // "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
+    // "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
+    // "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */
+    // "strictBuiltinIteratorReturn": true,              /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */
+    // "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */
+    // "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */
+    // "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */
+    // "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */
+    // "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */
+    // "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */
+    // "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */
+    // "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */
+    // "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */
+    // "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */
+    // "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */
+    // "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */
+    // "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */
+
+    /* Completeness */
+    // "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */
+    "skipLibCheck": true                                 /* Skip type checking all .d.ts files. */
+  }
+}