@vlad_kramarukha/json-statham 1.0.0
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/README.md +2 -0
- package/index.ts +13 -0
- package/lib/decorators/field.ts +7 -0
- package/lib/decorators/fieldName.ts +5 -0
- package/lib/decorators/mapper.ts +5 -0
- package/lib/decorators/schema.ts +5 -0
- package/lib/decorators/skip.ts +4 -0
- package/lib/decorators/skipIf.ts +5 -0
- package/lib/decorators/value.ts +5 -0
- package/lib/index.d.ts +22 -0
- package/lib/mappers.ts +74 -0
- package/lib/meta.ts +30 -0
- package/package.json +22 -0
package/README.md
ADDED
package/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* Decorators */
|
|
2
|
+
import field from '@decorators/field.ts'
|
|
3
|
+
import skip from '@decorators/skip.ts'
|
|
4
|
+
import skipIf from '@decorators/skipIf.ts'
|
|
5
|
+
import schema from '@decorators/schema.ts'
|
|
6
|
+
import value from '@decorators/value.ts'
|
|
7
|
+
import mapper from '@decorators/mapper.ts'
|
|
8
|
+
import fieldName from '@decorators/fieldName.ts'
|
|
9
|
+
|
|
10
|
+
/* Mappers */
|
|
11
|
+
import { fromJson, toJson } from '@mappers'
|
|
12
|
+
|
|
13
|
+
export default { field, skip, skipIf, schema, value, mapper, fieldName, fromJson, toJson }
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
interface Mapper<Record extends object> {
|
|
2
|
+
from?: (field: any, record: Record) => any
|
|
3
|
+
to?: (field: any, record: Record) => any
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
interface SkipMapper {
|
|
7
|
+
<Record>(field: any, record: Record): boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface FieldOptions {
|
|
11
|
+
skip?: boolean | SkipMapper
|
|
12
|
+
value?: any
|
|
13
|
+
mapper?: Mapper
|
|
14
|
+
fieldName?: string
|
|
15
|
+
isArray?: boolean
|
|
16
|
+
reconstruct?: boolean
|
|
17
|
+
schema?: new () => object
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface MetaInfo {
|
|
21
|
+
[p: string]: FieldOptions | SimpleFieldOptions
|
|
22
|
+
}
|
package/lib/mappers.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import Meta from '@meta'
|
|
2
|
+
|
|
3
|
+
export function fromJson<Schema, Json extends object>(
|
|
4
|
+
schema: new () => Schema & MetaInfo,
|
|
5
|
+
json: Json
|
|
6
|
+
): (Schema & MetaInfo) | Schema {
|
|
7
|
+
const result = {} as Record<string, any>
|
|
8
|
+
const instance = new schema()
|
|
9
|
+
|
|
10
|
+
const metaInfo = Meta.getMeta(instance)
|
|
11
|
+
|
|
12
|
+
for (const key of [...Object.keys(metaInfo), ...Object.keys(instance)]) {
|
|
13
|
+
const options = metaInfo[key]
|
|
14
|
+
|
|
15
|
+
if (!options) {
|
|
16
|
+
result[key] = json[key as keyof Json]
|
|
17
|
+
continue
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const { fieldName, value, mapper, schema, isArray } = options as FieldOptions
|
|
21
|
+
const dataKey = fieldName !== undefined ? fieldName : key
|
|
22
|
+
const data = json[dataKey as keyof Json]
|
|
23
|
+
|
|
24
|
+
if (schema && data) {
|
|
25
|
+
result[key] = isArray ? (data as object[]).map((v: object) => fromJson(schema, v)) : fromJson(schema, data)
|
|
26
|
+
continue
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (mapper?.from) {
|
|
30
|
+
result[key] = mapper.from(data, json)
|
|
31
|
+
} else {
|
|
32
|
+
result[key] = data === undefined ? value : data
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return Object.assign(instance, result)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function toJson<Json extends object>(json: Json): Json {
|
|
40
|
+
const result = {} as Record<string, any>
|
|
41
|
+
const metaInfo = Meta.getMeta(json)
|
|
42
|
+
|
|
43
|
+
for (const key of [...Object.keys(metaInfo), ...Object.keys(json)]) {
|
|
44
|
+
const options = metaInfo[key]
|
|
45
|
+
|
|
46
|
+
if (!options) {
|
|
47
|
+
result[key] = json[key as keyof Json]
|
|
48
|
+
continue
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const { mapper, schema, isArray, fieldName, reconstruct, skip } = options as FieldOptions
|
|
52
|
+
const data = json[key as keyof Json]
|
|
53
|
+
|
|
54
|
+
if (skip !== undefined) {
|
|
55
|
+
const skipped = typeof skip === 'function' ? skip(data, json) : skip
|
|
56
|
+
if (skipped) continue
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const resultKey = fieldName && reconstruct ? fieldName : key
|
|
60
|
+
|
|
61
|
+
if (schema && data) {
|
|
62
|
+
result[resultKey] = isArray ? (data as object[]).map(toJson) : toJson(data)
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (mapper?.to) {
|
|
67
|
+
result[resultKey] = mapper.to(data, json)
|
|
68
|
+
} else {
|
|
69
|
+
result[resultKey] = data
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return result as Json
|
|
74
|
+
}
|
package/lib/meta.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const META_KEY = Symbol('meta')
|
|
2
|
+
|
|
3
|
+
const pt = (target: object) => target.constructor.prototype
|
|
4
|
+
const meta = (target: object) => pt(target)[META_KEY] || {}
|
|
5
|
+
|
|
6
|
+
export default class Meta {
|
|
7
|
+
static isMeta<Target extends object>(target: Target | (Target & MetaInfo)): target is Target & MetaInfo {
|
|
8
|
+
return META_KEY in pt(target)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
static addMeta<Target extends object>(
|
|
12
|
+
target: Target,
|
|
13
|
+
property: keyof Target,
|
|
14
|
+
info: FieldOptions
|
|
15
|
+
) {
|
|
16
|
+
if (!Meta.isMeta(target)) {
|
|
17
|
+
pt(target)[META_KEY] = {}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!meta(target)[property]) {
|
|
21
|
+
meta(target)[property] = {}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
Object.assign(meta(target)[property], info)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static getMeta<Target extends object>(target: Target | Target & MetaInfo): MetaInfo {
|
|
28
|
+
return meta(target)
|
|
29
|
+
}
|
|
30
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vlad_kramarukha/json-statham",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "vlad_kramarukha",
|
|
5
|
+
"private": false,
|
|
6
|
+
"description": "Mapper for convenient work with data",
|
|
7
|
+
"module": "index.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"files": [
|
|
11
|
+
"index.ts",
|
|
12
|
+
"lib/*",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@types/bun": "latest",
|
|
17
|
+
"prettier": "^3.8.1"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"typescript": "^5"
|
|
21
|
+
}
|
|
22
|
+
}
|