• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mobxjs / serializr / 14498102528

16 Apr 2025 04:49PM UTC coverage: 90.687% (+0.4%) from 90.257%
14498102528

push

github

web-flow
Decrease tech debt  (#191)

* Decrease tech debt by updating babel and switching to jest testing framework
* Removed node 12.x from the testing matrix as the typescript compiler doesn't run on it anymore.

687 of 885 branches covered (77.63%)

1003 of 1106 relevant lines covered (90.69%)

42.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.44
/src/api/serializable.ts
1
import { invariant, isPropSchema, isAliasedPropSchema } from "../utils/utils";
2
import { _defaultPrimitiveProp } from "../constants";
2✔
3
import primitive from "../types/primitive";
6!
4
import getDefaultModelSchema from "../api/getDefaultModelSchema";
5
import createModelSchema from "../api/createModelSchema";
2✔
6
import { PropSchema, ModelSchema, PropDef } from "./types";
2✔
7
import Context from "../core/Context";
2✔
8

2✔
9
// Ugly way to get the parameter names since they aren't easily retrievable via reflection
2✔
10
const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm;
4✔
11
const ARGUMENT_NAMES = /([^\s,]+)/g;
4✔
12

13
function getParamNames(func: (...args: any[]) => any) {
2✔
14
    const fnStr = func.toString().replace(STRIP_COMMENTS, "");
2✔
15
    return fnStr.slice(fnStr.indexOf("(") + 1, fnStr.indexOf(")")).match(ARGUMENT_NAMES) ?? [];
×
16
}
×
17

×
18
function serializableDecorator(
19
    propSchema: PropSchema,
20
    target: any,
70✔
21
    propName: string,
22
    descriptor: PropertyDescriptor | undefined
23
) {
70!
24
    invariant(
103✔
25
        arguments.length >= 2,
26
        "too few arguments. Please use @serializable as property decorator"
27
    );
28
    // Fix for @serializable used in class constructor params (typescript)
×
29
    let factory;
×
30
    if (
33!
31
        propName === undefined &&
33!
32
        typeof target === "function" &&
33✔
33
        target.prototype &&
33✔
34
        descriptor !== undefined &&
33✔
35
        typeof descriptor === "number"
33✔
36
    ) {
37
        invariant(isPropSchema(propSchema), "Constructor params must use alias(name)");
33✔
38
        invariant(isAliasedPropSchema(propSchema), "Constructor params must use alias(name)");
×
39
        const paramNames = getParamNames(target);
33✔
40
        if (paramNames.length >= descriptor) {
×
41
            propName = paramNames[descriptor];
×
42
            propSchema.paramNumber = descriptor;
×
43
            descriptor = undefined;
×
44
            target = target.prototype;
×
45
            // Create a factory so the constructor is called properly
46
            factory = function (context: Context) {
×
47
                const params: any = [];
×
48
                for (let i = 0; i < target.constructor.length; i++) {
×
49
                    Object.keys(context.modelSchema.props).forEach(function (key) {
×
50
                        const prop = context.modelSchema.props[key];
×
51
                        if ((prop as PropSchema).paramNumber === i) {
70!
52
                            params[i] = context.json[(prop as PropSchema).jsonname!];
70✔
53
                        }
70✔
54
                    });
28✔
55
                }
70!
56

57
                return target.constructor.bind(undefined, ...params);
×
58
            };
70✔
59
        }
60
    }
70!
61
    invariant(typeof propName === "string", "incorrect usage of @serializable decorator");
33✔
62
    let info: ModelSchema<any> | undefined = getDefaultModelSchema(target);
70✔
63

64
    if (!info || !Object.prototype.hasOwnProperty.call(target.constructor, "serializeInfo"))
33✔
65
        info = createModelSchema(target.constructor, {}, factory);
89✔
66
    if (info && info.targetClass !== target.constructor)
103✔
67
        // fixes typescript issue that tends to copy fields from super constructor to sub constructor in extends
40✔
68
        info = createModelSchema(target.constructor, {}, factory);
40✔
69
    info.props[propName] = propSchema;
103✔
70
    // MWE: why won't babel work without?
40✔
71
    if (descriptor && !descriptor.get && !descriptor.set) descriptor.writable = true;
103✔
72
    return descriptor;
103✔
73
}
74

75
/**
76
 * Decorator that defines a new property mapping on the default model schema for the class
30✔
77
 * it is used in.
78
 *
79
 * When using typescript, the decorator can also be used on fields declared as constructor arguments (using the `private` / `protected` / `public` keywords).
80
 * The default factory will then invoke the constructor with the correct arguments as well.
81
 *
82
 * @example
83
 * class Todo {
84
 *     \@serializable(primitive())
85
 *     title // shorthand for primitves
86
 *
87
 *     \@serializable
88
 *     done
89
 *
90
 *     constructor(title, done) {
91
 *         this.title = title
92
 *         this.done = done
93
 *     }
94
 * }
95
 *
96
 * const json = serialize(new Todo('Test', false))
97
 * const todo = deserialize(Todo, json)
98
 */
99
export default function serializable(
100
    propSchema: PropDef
101
): (target: any, key: string, baseDescriptor?: PropertyDescriptor) => void;
102
export default function serializable(
103
    target: any,
104
    key: string,
105
    baseDescriptor?: PropertyDescriptor
106
): void;
107
export default function serializable(
108
    targetOrPropSchema: any | PropDef,
109
    key?: string,
110
    baseDescriptor?: PropertyDescriptor
111
) {
112
    if (!key) {
33✔
113
        // decorated with propSchema
114
        const propSchema =
115
            targetOrPropSchema === true
12✔
116
                ? _defaultPrimitiveProp
117
                : (targetOrPropSchema as PropSchema);
118
        invariant(isPropSchema(propSchema), "@serializable expects prop schema");
12✔
119
        const result: (target: object, key2: string, baseDescriptor2: PropertyDescriptor) => void =
120
            serializableDecorator.bind(null, propSchema);
12✔
121
        return result;
12✔
122
    } else {
123
        // decorated without arguments, treat as primitive
124
        serializableDecorator(primitive(), targetOrPropSchema, key, baseDescriptor);
21✔
125
    }
126
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc