fat-json 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "fat-json",
3
+ "version": "0.0.1",
4
+ "main": "./src/index.mjs",
5
+ "type": "module",
6
+ "types": "./src/index.d.mts",
7
+ "author": {
8
+ "name": "Jonathan Perry for Sequence Media Limited",
9
+ "email": "sequencemedia@sequencemedia.net",
10
+ "url": "https://sequencemedia.net"
11
+ },
12
+ "license": "ISC",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/sequencemedia/fat-json.git"
16
+ },
17
+ "scripts": {
18
+ "lint": "eslint .",
19
+ "lint:fix": "npm run lint -- --fix"
20
+ },
21
+ "devDependencies": {
22
+ "@sequencemedia/eslint-config-standard": "^0.2.82",
23
+ "@sequencemedia/eslint-config-typescript": "^0.1.141",
24
+ "@sequencemedia/sinon-chai": "^0.0.186",
25
+ "@types/chai": "^5.2.2",
26
+ "@types/mocha": "^10.0.10",
27
+ "@types/node": "^24.5.0",
28
+ "@types/sinon": "^17.0.4",
29
+ "chai": "^6.0.1",
30
+ "eslint": "^9.35.0",
31
+ "globals": "^16.4.0",
32
+ "mocha": "^11.7.2",
33
+ "sinon": "^21.0.0"
34
+ },
35
+ "imports": {
36
+ "#fat-json": "./src/index.mjs",
37
+ "#common": "./src/common/index.mjs",
38
+ "#transformers": "./src/transformers/index.mjs"
39
+ }
40
+ }
@@ -0,0 +1,11 @@
1
+ type ValueType = FatJsonTypes.ValueType
2
+
3
+ declare const BIG_INT: RegExp
4
+
5
+ export {
6
+ BIG_INT
7
+ }
8
+
9
+ export function iArray (v: ValueType | ValueType[]): v is any[]
10
+
11
+ export function isObject (v: ValueType | ValueType[]): v is object
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @typedef {FatJsonTypes.ValueType} ValueType
3
+ */
4
+
5
+ export const BIG_INT = /^(\d+)n$/
6
+
7
+ /**
8
+ * @param {ValueType | ValueType[]} v
9
+ * @returns {v is any[]}
10
+ */
11
+ export function isArray (v) {
12
+ return Array.isArray(v)
13
+ }
14
+
15
+ /**
16
+ * @param {ValueType | ValueType[]} v
17
+ * @returns {v is object}
18
+ */
19
+ export function isObject (v) {
20
+ return (v || false) instanceof Object && !Array.isArray(v)
21
+ }
@@ -0,0 +1,9 @@
1
+ declare global {
2
+ namespace FatJsonTypes {
3
+ export type ArrayLiteralType = unknown[] | never[]
4
+ export type ObjectLiteralType = Record<PropertyKey, unknown> | Record<PropertyKey, never>
5
+ export type ValueType = string | number | boolean | null | bigint | ArrayLiteralType | ObjectLiteralType | Buffer | undefined | object
6
+ }
7
+ }
8
+
9
+ export {}
package/src/index.mjs ADDED
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @typedef {FatJsonTypes.ValueType} ValueType
3
+ */
4
+ import {
5
+ BIG_INT
6
+ } from './common/index.mjs'
7
+ import getPath from './replacer/index.mjs'
8
+ import genPath from './reviver/index.mjs'
9
+
10
+ /**
11
+ * @param {(key: PropertyKey, value: ValueType, type?: string) => ValueType} replacer
12
+ * @returns {(key: PropertyKey, value: ValueType) => ValueType}
13
+ */
14
+ export function useReplacerWithType (replacer) {
15
+ /**
16
+ * @this {any | any[]}
17
+ * @param {PropertyKey} key
18
+ * @param {ValueType} value
19
+ * @returns {ValueType}
20
+ */
21
+ return function withType (key, value) {
22
+ return replacer.call(this, key, value, typeof value)
23
+ }
24
+ }
25
+
26
+ /**
27
+ * @param {(key: PropertyKey, value: ValueType, type?: string) => ValueType} reviver
28
+ * @returns {(key: PropertyKey, value: ValueType) => ValueType}
29
+ */
30
+ export function useReviverWithType (reviver) {
31
+ /**
32
+ * @this {any | any[]}
33
+ * @param {PropertyKey} key
34
+ * @param {ValueType} value
35
+ * @returns {ValueType}
36
+ */
37
+ // @ts-ignore
38
+ return function withType (key, value) {
39
+ return this[key] = reviver.call(this, key, value, typeof value)
40
+ }
41
+ }
42
+
43
+ /**
44
+ * @param {(key: PropertyKey, value: ValueType, path?: string) => ValueType} replacer
45
+ * @returns {(key: PropertyKey, value: ValueType) => ValueType}
46
+ */
47
+ export function useReplacerWithPath (replacer) {
48
+ /**
49
+ * @this {any | any[]}
50
+ * @param {PropertyKey} key
51
+ * @param {ValueType} value
52
+ * @returns {ValueType}
53
+ */
54
+ return function withPath (key, value) {
55
+ return replacer.call(this, key, value, getPath(key, value, this))
56
+ }
57
+ }
58
+
59
+ /**
60
+ * @param {(key: PropertyKey, value: ValueType, path?: string) => ValueType} reviver
61
+ * @returns {(key: PropertyKey, value: ValueType) => ValueType}
62
+ */
63
+ export function useReviverWithPath (reviver) {
64
+ /**
65
+ * @this {any | any[]}
66
+ *
67
+ * @param {PropertyKey} key
68
+ * @param {ValueType} value
69
+ * @returns {ValueType}
70
+ */
71
+ // @ts-ignore
72
+ return function withPath (key, value) {
73
+ if (!key) {
74
+ for (const { path, ...args } of genPath(key, value, this)) {
75
+ if (path !== '$') {
76
+ const {
77
+ context,
78
+ key,
79
+ value
80
+ } = args
81
+ // @ts-ignore
82
+ context[key] = reviver.call(context, key, value, path)
83
+ }
84
+ }
85
+
86
+ return this[key] = reviver.call(this, key, value, '$')
87
+ }
88
+
89
+ return value
90
+ }
91
+ }
92
+
93
+ /**
94
+ * @param {PropertyKey} key
95
+ * @param {ValueType} value
96
+ * @returns {ValueType}
97
+ */
98
+ export function replacer (key, value) {
99
+ if (typeof value === 'bigint') return String(value) + 'n'
100
+
101
+ return value
102
+ }
103
+
104
+ /**
105
+ * @param {PropertyKey} key
106
+ * @param {ValueType} value
107
+ * @returns {ValueType}
108
+ */
109
+ export function reviver (key, value) {
110
+ if (typeof value === 'string' && BIG_INT.test(value)) return BigInt (value.replace(BIG_INT, '$1'))
111
+
112
+ return value
113
+ }
114
+
115
+ /**
116
+ * @param {Set<PropertyKey>} [set]
117
+ * @returns {(key: PropertyKey, value: ValueType) => ValueType}
118
+ */
119
+ export function getReplacerFor (set = new Set()) {
120
+ /**
121
+ * @param {PropertyKey} key
122
+ * @param {ValueType} value
123
+ * @returns {ValueType}
124
+ */
125
+ return function replacer (key, value) {
126
+ if (set.has(key)) {
127
+ if (typeof value === 'bigint') return String(value)
128
+ }
129
+
130
+ return value
131
+ }
132
+ }
133
+
134
+ /**
135
+ * @param {Set<PropertyKey>} [set]
136
+ * @returns {(key: PropertyKey, value: ValueType) => ValueType}
137
+ */
138
+ export function getReviverFor (set = new Set()) {
139
+ /**
140
+ * @param {PropertyKey} key
141
+ * @param {ValueType} value
142
+ * @returns {ValueType}
143
+ */
144
+ return function reviver (key, value) {
145
+ if (set.has(key)) {
146
+ if (typeof value === 'string') return BigInt(value)
147
+ }
148
+
149
+ return value
150
+ }
151
+ }
@@ -0,0 +1,5 @@
1
+ type ArrayLiteralType = FatJsonTypes.ArrayLiteralType
2
+ type ObjectLiteralType = FatJsonTypes.ObjectLiteralType
3
+ type ValueType = FatJsonTypes.ValueType
4
+
5
+ export default function getPath (key: PropertyKey, value: ValueType, context: ArrayLiteralType | ObjectLiteralType): string
@@ -0,0 +1,39 @@
1
+ import {
2
+ isArray,
3
+ isObject
4
+ } from '#common'
5
+
6
+ const MAP = new WeakMap()
7
+
8
+ /**
9
+ * @param {PropertyKey} key
10
+ * @param {unknown} value
11
+ * @param {any} context
12
+ * @returns {string}
13
+ */
14
+ export default function getPath (key, value, context) {
15
+ let valuePath = String(key) || '$'
16
+
17
+ if (MAP.has(context)) {
18
+ const contextPath = MAP.get(context)
19
+
20
+ valuePath = (
21
+ contextPath + (
22
+ Array.isArray(context)
23
+ ? `[${key}]`
24
+ : ( // valuePath.includes(SP) || valuePath.includes(ST)
25
+ /[ .]/.test(key)
26
+ ? `.['${key}']`
27
+ : `.${key}`
28
+ )
29
+ )
30
+ )
31
+ }
32
+
33
+ if (
34
+ isArray(value) ||
35
+ isObject(value)
36
+ ) MAP.set(value, valuePath)
37
+
38
+ return valuePath
39
+ }
@@ -0,0 +1,5 @@
1
+ type ArrayLiteralType = FatJsonTypes.ArrayLiteralType
2
+ type ObjectLiteralType = FatJsonTypes.ObjectLiteralType
3
+ type ValueType = FatJsonTypes.ValueType
4
+
5
+ export default function genPath (key: PropertyKey, value: ValueType, context: ArrayLiteralType | ObjectLiteralType): IterableIterator<{ key: PropertyKey; value: ValueType; path: string; context: ArrayLiteralType | ObjectLiteralType }>
@@ -0,0 +1,90 @@
1
+ /**
2
+ * @typedef {FatJsonTypes.ArrayLiteralType} ArrayLiteralType
3
+ * @typedef {FatJsonTypes.ObjectLiteralType} ObjectLiteralType
4
+ * @typedef {FatJsonTypes.ValueType} ValueType
5
+ * @typedef {FatJsonTypes.WeakMapType} WeakMapType
6
+ */
7
+
8
+ import {
9
+ isArray,
10
+ isObject
11
+ } from '#common'
12
+
13
+ /**
14
+ * @param {any[]} context
15
+ * @param {string} contextPath
16
+ * @returns {IterableIterator<{ key: PropertyKey; value: unknown; path: string; context: any }>}
17
+ */
18
+ function * genPathForArray (context, contextPath) {
19
+ for (const [index, value] of context.entries()) {
20
+ const valuePath = contextPath + `[${index}]`
21
+
22
+ if (isArray(value)) yield * genPathForArray(value, valuePath)
23
+
24
+ if (isObject(value)) yield * genPathForObject(value, valuePath)
25
+
26
+ yield {
27
+ key: String(index),
28
+ value,
29
+ path: valuePath,
30
+ context
31
+ }
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @param {any} context
37
+ * @param {string} contextPath
38
+ * @returns {IterableIterator<{ key: PropertyKey; value: unknown; path: string; context: any }>}
39
+ */
40
+ function * genPathForObject (context, contextPath) {
41
+ for (const [key, value] of Object.entries(context)) {
42
+ const valuePath = (
43
+ contextPath + (
44
+ /[ .]/.test(key)
45
+ ? `.['${key}']`
46
+ : `.${key}`
47
+ )
48
+ )
49
+
50
+ if (isArray(value)) yield * genPathForArray(value, valuePath)
51
+
52
+ if (isObject(value)) yield * genPathForObject(value, valuePath)
53
+
54
+ yield {
55
+ key: String(key), // should already be a string but
56
+ value,
57
+ path: valuePath,
58
+ context
59
+ }
60
+ }
61
+ }
62
+
63
+ /**
64
+ * @param {PropertyKey} key
65
+ * @param {unknown} value
66
+ * @param {any | any[]} context
67
+ * @returns {IterableIterator<{ key: PropertyKey; value: unknown; path: string; context: any }>}
68
+ */
69
+ export default function * genPath (key, value, context) {
70
+ const valuePath = key
71
+ ? typeof key === 'number'
72
+ ? `[${key}]`
73
+ : (
74
+ /[ .]/.test(key)
75
+ ? `.['${key}']`
76
+ : `.${key}`
77
+ )
78
+ : '$'
79
+
80
+ if (isArray(value)) yield * genPathForArray(value, valuePath)
81
+
82
+ if (isObject(value)) yield * genPathForObject(value, valuePath)
83
+
84
+ yield {
85
+ key: String(key),
86
+ value,
87
+ path: valuePath,
88
+ context
89
+ }
90
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @param {BigInt} value
3
+ * @returns {string}
4
+ */
5
+ export function fromBigIntToString (value) {
6
+ return String(value)
7
+ }
8
+
9
+ /**
10
+ * @param {string} value
11
+ * @returns {BigInt}
12
+ */
13
+ export function fromStringToBigInt (value) {
14
+ return BigInt(value)
15
+ }
16
+
17
+ /**
18
+ * @param {string} b
19
+ * @returns {number}
20
+ */
21
+ function toCodePoint (b) {
22
+ const c = b.codePointAt(0)
23
+
24
+ return Number(c)
25
+ }
26
+
27
+ /**
28
+ * ```javascript
29
+ * Buffer.from(Uint8Array.fromBase64(base64))
30
+ * ```
31
+ * @param {string} base64
32
+ * @returns {Buffer}
33
+ */
34
+ export function fromBase64ToBuffer (base64) {
35
+ const binary = atob(base64) // base64 string to binary string
36
+ const uint8Array = Uint8Array.from(binary, toCodePoint) // binary string to code point integer
37
+ return Buffer.from(uint8Array)
38
+ }
39
+
40
+ /**
41
+ * @param {Buffer} buffer
42
+ * @returns {string}
43
+ */
44
+ export function fromBufferToBase64 (buffer) {
45
+ return buffer.toString('base64')
46
+ }