objectmodel 4.3.1 → 4.4.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/dist/object-model.cjs +380 -387
- package/dist/object-model.js +380 -387
- package/dist/object-model.js.map +1 -1
- package/dist/object-model.min.js +2 -2
- package/dist/object-model.min.js.map +1 -1
- package/index.html +4 -4
- package/package.json +70 -64
- package/src/array-model.d.ts +16 -0
- package/src/array-model.js +68 -68
- package/src/devtool-formatter.js +198 -198
- package/src/function-model.d.ts +24 -0
- package/src/function-model.js +58 -65
- package/src/index.js +4 -4
- package/src/map-model.d.ts +18 -0
- package/src/map-model.js +48 -48
- package/src/object-model.d.ts +74 -0
- package/src/set-model.d.ts +16 -0
- package/src/set-model.js +41 -41
- package/test/array-model.test-d.ts +24 -0
- package/test/basic-model.test-d.ts +30 -0
- package/test/function-model.spec.cjs +161 -162
- package/test/function-model.test-d.ts +18 -0
- package/test/map-model.test-d.ts +21 -0
- package/test/object-model.spec.cjs +1345 -1346
- package/test/object-model.test-d.ts +53 -0
- package/test/set-model.test-d.ts +17 -0
- package/types/definitions.d.ts +43 -0
- package/types/helpers.d.ts +4 -0
- package/types/index.d.ts +6 -128
- package/.travis.yml +0 -3
package/src/devtool-formatter.js
CHANGED
|
@@ -1,199 +1,199 @@
|
|
|
1
|
-
import { _original, Model, Any, BasicModel, ObjectModel } from "./object-model.js"
|
|
2
|
-
import ArrayModel from "./array-model.js"
|
|
3
|
-
import SetModel from "./set-model.js"
|
|
4
|
-
import MapModel from "./map-model.js"
|
|
5
|
-
import FunctionModel from "./function-model.js"
|
|
6
|
-
import { getProto, has, is, isFunction, isPlainObject } from "./helpers.js"
|
|
7
|
-
|
|
8
|
-
const styles = {
|
|
9
|
-
list: "list-style-type: none; padding: 0; margin: 0;",
|
|
10
|
-
listItem: "padding: 0 0 0 1em;",
|
|
11
|
-
model: "color: #3e999f;",
|
|
12
|
-
instance: "color: #718c00; font-style: italic",
|
|
13
|
-
function: "color: #4271AE",
|
|
14
|
-
string: "color: #C41A16",
|
|
15
|
-
number: "color: #1C00CF",
|
|
16
|
-
boolean: "color: #AA0D91",
|
|
17
|
-
property: "color: #8959a8",
|
|
18
|
-
private: "color: #C19ED8",
|
|
19
|
-
constant: "color: #8959a8; font-weight: bold",
|
|
20
|
-
privateConstant: "color: #C19ED8; font-weight: bold",
|
|
21
|
-
null: "color: #8e908c",
|
|
22
|
-
undeclared: "color: #C0C0C0;",
|
|
23
|
-
proto: "color: #B871BD; font-style: italic"
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const getModel = (instance) => {
|
|
27
|
-
if (instance === undefined || instance === null)
|
|
28
|
-
return null
|
|
29
|
-
|
|
30
|
-
const proto = getProto(instance);
|
|
31
|
-
if (!proto || !proto.constructor || !is(Model, proto.constructor))
|
|
32
|
-
return null
|
|
33
|
-
|
|
34
|
-
return proto.constructor
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const span = (style, ...children) => ["span", { style }, ...children]
|
|
38
|
-
|
|
39
|
-
const format = (x, config = {}) => {
|
|
40
|
-
if (x === null || x === undefined)
|
|
41
|
-
return span(styles.null, "" + x);
|
|
42
|
-
|
|
43
|
-
if (typeof x === "boolean")
|
|
44
|
-
return span(styles.boolean, x);
|
|
45
|
-
|
|
46
|
-
if (typeof x === "number")
|
|
47
|
-
return span(styles.number, x);
|
|
48
|
-
|
|
49
|
-
if (typeof x === "string")
|
|
50
|
-
return span(styles.string, `"${x}"`);
|
|
51
|
-
|
|
52
|
-
if (Array.isArray(x) && config.isModelDefinition) {
|
|
53
|
-
return span("", ...x.flatMap(part => [format(part, config), " or "]).slice(0, -1))
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (isPlainObject(x))
|
|
57
|
-
return formatObject(x, getModel(x), config)
|
|
58
|
-
|
|
59
|
-
if (isFunction(x) && !is(Model, x) && config.isModelDefinition)
|
|
60
|
-
return span(styles.function, x.name || x.toString());
|
|
61
|
-
|
|
62
|
-
return ["object", { object: x, config }]
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const formatObject = (o, model, config) => span("",
|
|
66
|
-
"{",
|
|
67
|
-
["ol", { style: styles.list }, ...Object.keys(o).map(prop =>
|
|
68
|
-
["li", { style: styles.listItem }, span(styles.property, prop), ": ", format(o[prop], config)])
|
|
69
|
-
],
|
|
70
|
-
"}"
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
const formatModel = model => {
|
|
74
|
-
const
|
|
75
|
-
cfg = { isModelDefinition: true },
|
|
76
|
-
def = model.definition,
|
|
77
|
-
formatList = (list, map) => list.flatMap(e => [map(e), ", "]).slice(0, -1);
|
|
78
|
-
let parts = []
|
|
79
|
-
|
|
80
|
-
if (is(BasicModel, model)) parts = [format(def, cfg)]
|
|
81
|
-
if (is(ArrayModel, model)) parts = ["Array of ", format(def, cfg)]
|
|
82
|
-
if (is(SetModel, model)) parts = ["Set of ", format(def, cfg)]
|
|
83
|
-
if (is(MapModel, model)) parts = ["Map of ", format(def.key, cfg), " : ", format(def.value, cfg)]
|
|
84
|
-
if (is(FunctionModel, model)) {
|
|
85
|
-
parts = ["Function(", ...formatList(def.arguments, arg => format(arg, cfg)), ")"]
|
|
86
|
-
if ("return" in def) parts.push(" => ", format(def.return, cfg))
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (model.assertions.length > 0) {
|
|
90
|
-
parts.push("\n(assertions: ", ...formatList(model.assertions, f => ["object", { object: f }]), ")")
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return span(styles.model, ...parts)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const ModelFormatter = {
|
|
97
|
-
header(x, config = {}) {
|
|
98
|
-
if (x === Any)
|
|
99
|
-
return span(styles.model, "Any")
|
|
100
|
-
|
|
101
|
-
if (is(Any.remaining, x))
|
|
102
|
-
return span(styles.model, "...", format(x.definition, { isModelDefinition: true }))
|
|
103
|
-
|
|
104
|
-
if (is(ObjectModel, x))
|
|
105
|
-
return span(styles.model, x.name)
|
|
106
|
-
|
|
107
|
-
if (is(Model, x)) {
|
|
108
|
-
return formatModel(x)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (config.isModelDefinition && isPlainObject(x))
|
|
112
|
-
return format(x, config)
|
|
113
|
-
|
|
114
|
-
return null;
|
|
115
|
-
},
|
|
116
|
-
hasBody(x) {
|
|
117
|
-
return is(ObjectModel, x)
|
|
118
|
-
},
|
|
119
|
-
body(model) {
|
|
120
|
-
return span("",
|
|
121
|
-
"{",
|
|
122
|
-
["ol", { style: styles.list }, ...Object.keys(model.definition).map(prop => {
|
|
123
|
-
const isPrivate = model.conventionForPrivate(prop)
|
|
124
|
-
const isConstant = model.conventionForConstant(prop)
|
|
125
|
-
const hasDefault = model.default && has(model.default, prop);
|
|
126
|
-
let style = styles.property;
|
|
127
|
-
|
|
128
|
-
if (isPrivate) {
|
|
129
|
-
style = isConstant ? styles.privateConstant : styles.private
|
|
130
|
-
} else if (isConstant) {
|
|
131
|
-
style = styles.constant
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return ["li", { style: styles.listItem },
|
|
135
|
-
span(style, prop), ": ", format(model.definition[prop], { isModelDefinition: true }),
|
|
136
|
-
hasDefault ? span(styles.proto, " = ", format(model.default[prop])) : ""
|
|
137
|
-
]
|
|
138
|
-
})],
|
|
139
|
-
"}"
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const ModelInstanceFormatter = {
|
|
145
|
-
header(x, config = {}) {
|
|
146
|
-
if (config.isInstanceProperty && isPlainObject(x)) {
|
|
147
|
-
return format(x, config)
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const model = getModel(x);
|
|
151
|
-
if (is(Model, model)) {
|
|
152
|
-
const parts = is(ObjectModel, model) ? [model.name] : [["object", { object: x[_original] }], ` (${model.name})`];
|
|
153
|
-
return span(styles.instance, ...parts)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return null;
|
|
157
|
-
},
|
|
158
|
-
hasBody(x) {
|
|
159
|
-
return x && is(ObjectModel, getModel(x))
|
|
160
|
-
},
|
|
161
|
-
body(x) {
|
|
162
|
-
const model = getModel(x)
|
|
163
|
-
const o = x[_original] || x;
|
|
164
|
-
return span("",
|
|
165
|
-
"{",
|
|
166
|
-
[
|
|
167
|
-
"ol",
|
|
168
|
-
{ style: styles.list },
|
|
169
|
-
...Object.keys(o).map(prop => {
|
|
170
|
-
const isPrivate = model.conventionForPrivate(prop)
|
|
171
|
-
const isConstant = model.conventionForConstant(prop)
|
|
172
|
-
const isDeclared = prop in model.definition;
|
|
173
|
-
let style = styles.property;
|
|
174
|
-
|
|
175
|
-
if (!isDeclared) {
|
|
176
|
-
style = styles.undeclared
|
|
177
|
-
} else if (isPrivate) {
|
|
178
|
-
style = isConstant ? styles.privateConstant : styles.private
|
|
179
|
-
} else if (isConstant) {
|
|
180
|
-
style = styles.constant
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return ["li", { style: styles.listItem },
|
|
184
|
-
span(style, prop), ": ", format(o[prop], { isInstanceProperty: true })
|
|
185
|
-
]
|
|
186
|
-
}),
|
|
187
|
-
["li", { style: styles.listItem },
|
|
188
|
-
span(styles.proto, "__proto__", ": ", ["object", { object: getProto(x) }])
|
|
189
|
-
]
|
|
190
|
-
],
|
|
191
|
-
"}"
|
|
192
|
-
)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (typeof window !== "undefined") {
|
|
197
|
-
window.devtoolsFormatters = (window.devtoolsFormatters || [])
|
|
198
|
-
.concat(ModelFormatter, ModelInstanceFormatter);
|
|
1
|
+
import { _original, Model, Any, BasicModel, ObjectModel } from "./object-model.js"
|
|
2
|
+
import ArrayModel from "./array-model.js"
|
|
3
|
+
import SetModel from "./set-model.js"
|
|
4
|
+
import MapModel from "./map-model.js"
|
|
5
|
+
import FunctionModel from "./function-model.js"
|
|
6
|
+
import { getProto, has, is, isFunction, isPlainObject } from "./helpers.js"
|
|
7
|
+
|
|
8
|
+
const styles = {
|
|
9
|
+
list: "list-style-type: none; padding: 0; margin: 0;",
|
|
10
|
+
listItem: "padding: 0 0 0 1em;",
|
|
11
|
+
model: "color: #3e999f;",
|
|
12
|
+
instance: "color: #718c00; font-style: italic",
|
|
13
|
+
function: "color: #4271AE",
|
|
14
|
+
string: "color: #C41A16",
|
|
15
|
+
number: "color: #1C00CF",
|
|
16
|
+
boolean: "color: #AA0D91",
|
|
17
|
+
property: "color: #8959a8",
|
|
18
|
+
private: "color: #C19ED8",
|
|
19
|
+
constant: "color: #8959a8; font-weight: bold",
|
|
20
|
+
privateConstant: "color: #C19ED8; font-weight: bold",
|
|
21
|
+
null: "color: #8e908c",
|
|
22
|
+
undeclared: "color: #C0C0C0;",
|
|
23
|
+
proto: "color: #B871BD; font-style: italic"
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const getModel = (instance) => {
|
|
27
|
+
if (instance === undefined || instance === null)
|
|
28
|
+
return null
|
|
29
|
+
|
|
30
|
+
const proto = getProto(instance);
|
|
31
|
+
if (!proto || !proto.constructor || !is(Model, proto.constructor))
|
|
32
|
+
return null
|
|
33
|
+
|
|
34
|
+
return proto.constructor
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const span = (style, ...children) => ["span", { style }, ...children]
|
|
38
|
+
|
|
39
|
+
const format = (x, config = {}) => {
|
|
40
|
+
if (x === null || x === undefined)
|
|
41
|
+
return span(styles.null, "" + x);
|
|
42
|
+
|
|
43
|
+
if (typeof x === "boolean")
|
|
44
|
+
return span(styles.boolean, x);
|
|
45
|
+
|
|
46
|
+
if (typeof x === "number")
|
|
47
|
+
return span(styles.number, x);
|
|
48
|
+
|
|
49
|
+
if (typeof x === "string")
|
|
50
|
+
return span(styles.string, `"${x}"`);
|
|
51
|
+
|
|
52
|
+
if (Array.isArray(x) && config.isModelDefinition) {
|
|
53
|
+
return span("", ...x.flatMap(part => [format(part, config), " or "]).slice(0, -1))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (isPlainObject(x))
|
|
57
|
+
return formatObject(x, getModel(x), config)
|
|
58
|
+
|
|
59
|
+
if (isFunction(x) && !is(Model, x) && config.isModelDefinition)
|
|
60
|
+
return span(styles.function, x.name || x.toString());
|
|
61
|
+
|
|
62
|
+
return ["object", { object: x, config }]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const formatObject = (o, model, config) => span("",
|
|
66
|
+
"{",
|
|
67
|
+
["ol", { style: styles.list }, ...Object.keys(o).map(prop =>
|
|
68
|
+
["li", { style: styles.listItem }, span(styles.property, prop), ": ", format(o[prop], config)])
|
|
69
|
+
],
|
|
70
|
+
"}"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
const formatModel = model => {
|
|
74
|
+
const
|
|
75
|
+
cfg = { isModelDefinition: true },
|
|
76
|
+
def = model.definition,
|
|
77
|
+
formatList = (list, map) => list.flatMap(e => [map(e), ", "]).slice(0, -1);
|
|
78
|
+
let parts = []
|
|
79
|
+
|
|
80
|
+
if (is(BasicModel, model)) parts = [format(def, cfg)]
|
|
81
|
+
if (is(ArrayModel, model)) parts = ["Array of ", format(def, cfg)]
|
|
82
|
+
if (is(SetModel, model)) parts = ["Set of ", format(def, cfg)]
|
|
83
|
+
if (is(MapModel, model)) parts = ["Map of ", format(def.key, cfg), " : ", format(def.value, cfg)]
|
|
84
|
+
if (is(FunctionModel, model)) {
|
|
85
|
+
parts = ["Function(", ...formatList(def.arguments, arg => format(arg, cfg)), ")"]
|
|
86
|
+
if ("return" in def) parts.push(" => ", format(def.return, cfg))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (model.assertions.length > 0) {
|
|
90
|
+
parts.push("\n(assertions: ", ...formatList(model.assertions, f => ["object", { object: f }]), ")")
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return span(styles.model, ...parts)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const ModelFormatter = {
|
|
97
|
+
header(x, config = {}) {
|
|
98
|
+
if (x === Any)
|
|
99
|
+
return span(styles.model, "Any")
|
|
100
|
+
|
|
101
|
+
if (is(Any.remaining, x))
|
|
102
|
+
return span(styles.model, "...", format(x.definition, { isModelDefinition: true }))
|
|
103
|
+
|
|
104
|
+
if (is(ObjectModel, x))
|
|
105
|
+
return span(styles.model, x.name)
|
|
106
|
+
|
|
107
|
+
if (is(Model, x)) {
|
|
108
|
+
return formatModel(x)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (config.isModelDefinition && isPlainObject(x))
|
|
112
|
+
return format(x, config)
|
|
113
|
+
|
|
114
|
+
return null;
|
|
115
|
+
},
|
|
116
|
+
hasBody(x) {
|
|
117
|
+
return is(ObjectModel, x)
|
|
118
|
+
},
|
|
119
|
+
body(model) {
|
|
120
|
+
return span("",
|
|
121
|
+
"{",
|
|
122
|
+
["ol", { style: styles.list }, ...Object.keys(model.definition).map(prop => {
|
|
123
|
+
const isPrivate = model.conventionForPrivate(prop)
|
|
124
|
+
const isConstant = model.conventionForConstant(prop)
|
|
125
|
+
const hasDefault = model.default && has(model.default, prop);
|
|
126
|
+
let style = styles.property;
|
|
127
|
+
|
|
128
|
+
if (isPrivate) {
|
|
129
|
+
style = isConstant ? styles.privateConstant : styles.private
|
|
130
|
+
} else if (isConstant) {
|
|
131
|
+
style = styles.constant
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return ["li", { style: styles.listItem },
|
|
135
|
+
span(style, prop), ": ", format(model.definition[prop], { isModelDefinition: true }),
|
|
136
|
+
hasDefault ? span(styles.proto, " = ", format(model.default[prop])) : ""
|
|
137
|
+
]
|
|
138
|
+
})],
|
|
139
|
+
"}"
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const ModelInstanceFormatter = {
|
|
145
|
+
header(x, config = {}) {
|
|
146
|
+
if (config.isInstanceProperty && isPlainObject(x)) {
|
|
147
|
+
return format(x, config)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const model = getModel(x);
|
|
151
|
+
if (is(Model, model)) {
|
|
152
|
+
const parts = is(ObjectModel, model) ? [model.name] : [["object", { object: x[_original] }], ` (${model.name})`];
|
|
153
|
+
return span(styles.instance, ...parts)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return null;
|
|
157
|
+
},
|
|
158
|
+
hasBody(x) {
|
|
159
|
+
return x && is(ObjectModel, getModel(x))
|
|
160
|
+
},
|
|
161
|
+
body(x) {
|
|
162
|
+
const model = getModel(x)
|
|
163
|
+
const o = x[_original] || x;
|
|
164
|
+
return span("",
|
|
165
|
+
"{",
|
|
166
|
+
[
|
|
167
|
+
"ol",
|
|
168
|
+
{ style: styles.list },
|
|
169
|
+
...Object.keys(o).map(prop => {
|
|
170
|
+
const isPrivate = model.conventionForPrivate(prop)
|
|
171
|
+
const isConstant = model.conventionForConstant(prop)
|
|
172
|
+
const isDeclared = prop in model.definition;
|
|
173
|
+
let style = styles.property;
|
|
174
|
+
|
|
175
|
+
if (!isDeclared) {
|
|
176
|
+
style = styles.undeclared
|
|
177
|
+
} else if (isPrivate) {
|
|
178
|
+
style = isConstant ? styles.privateConstant : styles.private
|
|
179
|
+
} else if (isConstant) {
|
|
180
|
+
style = styles.constant
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return ["li", { style: styles.listItem },
|
|
184
|
+
span(style, prop), ": ", format(o[prop], { isInstanceProperty: true })
|
|
185
|
+
]
|
|
186
|
+
}),
|
|
187
|
+
["li", { style: styles.listItem },
|
|
188
|
+
span(styles.proto, "__proto__", ": ", ["object", { object: getProto(x) }])
|
|
189
|
+
]
|
|
190
|
+
],
|
|
191
|
+
"}"
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (typeof window !== "undefined") {
|
|
197
|
+
window.devtoolsFormatters = (window.devtoolsFormatters || [])
|
|
198
|
+
.concat(ModelFormatter, ModelInstanceFormatter);
|
|
199
199
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FromDefinition, ModelDefinition } from "../types/definitions";
|
|
2
|
+
import { Model } from "./object-model";
|
|
3
|
+
|
|
4
|
+
type FromArgsDef<T> = T extends [infer A, ...infer Rest] ? [FromDefinition<A>, ...FromArgsDef<Rest>] : T
|
|
5
|
+
|
|
6
|
+
export type FunctionSignature<Args extends any[], Return> = {
|
|
7
|
+
(...args: FromArgsDef<Args>): FromDefinition<Return>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface FunctionModel<Args extends ModelDefinition[], Return extends ModelDefinition> extends Model<{ arguments: Args, return: Return }> {
|
|
11
|
+
(): FunctionSignature<Args, Return>;
|
|
12
|
+
(fn: FunctionSignature<Args, Return>): FunctionSignature<Args, Return>;
|
|
13
|
+
new (fn: FunctionSignature<Args, Return>): FunctionSignature<Args, Return>;
|
|
14
|
+
definition: { arguments: Args, return: Return };
|
|
15
|
+
|
|
16
|
+
return<R extends ModelDefinition>(returnValueDefinition: R): FunctionModel<Args, R>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface FunctionModelConstructor {
|
|
20
|
+
<Args extends ModelDefinition[]>(...argumentsDefinitions: Args): FunctionModel<Args, any>;
|
|
21
|
+
new<Args extends ModelDefinition[]>(...argumentsDefinitions: Args): FunctionModel<Args, any>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const FunctionModel: FunctionModelConstructor;
|
package/src/function-model.js
CHANGED
|
@@ -1,66 +1,59 @@
|
|
|
1
|
-
import {
|
|
2
|
-
_check, _original, Any, checkAssertions, checkDefinition, extendDefinition, extendModel,
|
|
3
|
-
formatDefinition, initModel, Model, stackError, unstackErrors
|
|
4
|
-
} from "./object-model.js"
|
|
5
|
-
import { extend, is, isFunction } from "./helpers.js"
|
|
6
|
-
|
|
7
|
-
export default function FunctionModel(...argsDef) {
|
|
8
|
-
return initModel({ arguments: argsDef }, FunctionModel, Function, null, model => ({
|
|
9
|
-
getPrototypeOf: () => model.prototype,
|
|
10
|
-
|
|
11
|
-
get(fn, key) {
|
|
12
|
-
return key === _original ? fn : fn[key]
|
|
13
|
-
},
|
|
14
|
-
|
|
15
|
-
apply(fn, ctx, args) {
|
|
16
|
-
const def = model.definition
|
|
17
|
-
const remainingArgDef = def.arguments.find(argDef => is(Any.remaining, argDef))
|
|
18
|
-
const nbArgsToCheck = remainingArgDef ? Math.max(args.length, def.arguments.length - 1) : def.arguments.length
|
|
19
|
-
|
|
20
|
-
for (let i = 0; i < nbArgsToCheck; i++) {
|
|
21
|
-
const argDef = remainingArgDef && i >= def.arguments.length - 1 ? remainingArgDef.definition : def.arguments[i]
|
|
22
|
-
args[i] = checkDefinition(args[i], argDef, `arguments[${i}]`, model.errors, [], true)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
checkAssertions(args, model, "arguments")
|
|
26
|
-
|
|
27
|
-
let result
|
|
28
|
-
if (!model.errors.length) {
|
|
29
|
-
result = Reflect.apply(fn, ctx, args)
|
|
30
|
-
if ("return" in def)
|
|
31
|
-
result = checkDefinition(result, def.return, "return value", model.errors, [], true)
|
|
32
|
-
}
|
|
33
|
-
unstackErrors(model)
|
|
34
|
-
return result
|
|
35
|
-
}
|
|
36
|
-
}))
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
extend(FunctionModel, Model, {
|
|
40
|
-
toString(stack = []) {
|
|
41
|
-
let out = `Function(${this.definition.arguments.map(
|
|
42
|
-
argDef => formatDefinition(argDef, [...stack])
|
|
43
|
-
).join(", ")})`
|
|
44
|
-
|
|
45
|
-
if ("return" in this.definition) {
|
|
46
|
-
out += " => " + formatDefinition(this.definition.return, stack)
|
|
47
|
-
}
|
|
48
|
-
return out
|
|
49
|
-
},
|
|
50
|
-
|
|
51
|
-
return(def) {
|
|
52
|
-
this.definition.return = def
|
|
53
|
-
return this
|
|
54
|
-
},
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
mixedReturns = extendDefinition(this.definition.return, newReturns)
|
|
60
|
-
return extendModel(new FunctionModel(...mixedArgs).return(mixedReturns), this)
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
[_check](f, path, errors) {
|
|
64
|
-
if (!isFunction(f)) stackError(errors, "Function", f, path)
|
|
65
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
_check, _original, Any, checkAssertions, checkDefinition, extendDefinition, extendModel,
|
|
3
|
+
formatDefinition, initModel, Model, stackError, unstackErrors
|
|
4
|
+
} from "./object-model.js"
|
|
5
|
+
import { extend, is, isFunction } from "./helpers.js"
|
|
6
|
+
|
|
7
|
+
export default function FunctionModel(...argsDef) {
|
|
8
|
+
return initModel({ arguments: argsDef }, FunctionModel, Function, null, model => ({
|
|
9
|
+
getPrototypeOf: () => model.prototype,
|
|
10
|
+
|
|
11
|
+
get(fn, key) {
|
|
12
|
+
return key === _original ? fn : fn[key]
|
|
13
|
+
},
|
|
14
|
+
|
|
15
|
+
apply(fn, ctx, args) {
|
|
16
|
+
const def = model.definition
|
|
17
|
+
const remainingArgDef = def.arguments.find(argDef => is(Any.remaining, argDef))
|
|
18
|
+
const nbArgsToCheck = remainingArgDef ? Math.max(args.length, def.arguments.length - 1) : def.arguments.length
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < nbArgsToCheck; i++) {
|
|
21
|
+
const argDef = remainingArgDef && i >= def.arguments.length - 1 ? remainingArgDef.definition : def.arguments[i]
|
|
22
|
+
args[i] = checkDefinition(args[i], argDef, `arguments[${i}]`, model.errors, [], true)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
checkAssertions(args, model, "arguments")
|
|
26
|
+
|
|
27
|
+
let result
|
|
28
|
+
if (!model.errors.length) {
|
|
29
|
+
result = Reflect.apply(fn, ctx, args)
|
|
30
|
+
if ("return" in def)
|
|
31
|
+
result = checkDefinition(result, def.return, "return value", model.errors, [], true)
|
|
32
|
+
}
|
|
33
|
+
unstackErrors(model)
|
|
34
|
+
return result
|
|
35
|
+
}
|
|
36
|
+
}))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
extend(FunctionModel, Model, {
|
|
40
|
+
toString(stack = []) {
|
|
41
|
+
let out = `Function(${this.definition.arguments.map(
|
|
42
|
+
argDef => formatDefinition(argDef, [...stack])
|
|
43
|
+
).join(", ")})`
|
|
44
|
+
|
|
45
|
+
if ("return" in this.definition) {
|
|
46
|
+
out += " => " + formatDefinition(this.definition.return, stack)
|
|
47
|
+
}
|
|
48
|
+
return out
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
return(def) {
|
|
52
|
+
this.definition.return = def
|
|
53
|
+
return this
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
[_check](f, path, errors) {
|
|
57
|
+
if (!isFunction(f)) stackError(errors, "Function", f, path)
|
|
58
|
+
}
|
|
66
59
|
})
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { Model, BasicModel, ObjectModel, Any } from "./object-model.js"
|
|
2
|
-
export { default as ArrayModel } from "./array-model.js"
|
|
3
|
-
export { default as FunctionModel } from "./function-model.js"
|
|
4
|
-
export { default as MapModel } from "./map-model.js"
|
|
1
|
+
export { Model, BasicModel, ObjectModel, Any } from "./object-model.js"
|
|
2
|
+
export { default as ArrayModel } from "./array-model.js"
|
|
3
|
+
export { default as FunctionModel } from "./function-model.js"
|
|
4
|
+
export { default as MapModel } from "./map-model.js"
|
|
5
5
|
export { default as SetModel } from "./set-model.js"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FromDefinition, ModelDefinition } from "../types/definitions";
|
|
2
|
+
import { Model } from "./object-model";
|
|
3
|
+
|
|
4
|
+
export interface MapModel<Key extends ModelDefinition, Value extends ModelDefinition> extends Model<{ key: Key, value: Value}> {
|
|
5
|
+
(iterable: Map<FromDefinition<Key>, FromDefinition<Value>> | Array<[FromDefinition<Key>, FromDefinition<Value>]>): Map<FromDefinition<Key>, FromDefinition<Value>>;
|
|
6
|
+
new(iterable: Map<FromDefinition<Key>, FromDefinition<Value>> | Array<[FromDefinition<Key>, FromDefinition<Value>]>): Map<FromDefinition<Key>, FromDefinition<Value>>;
|
|
7
|
+
|
|
8
|
+
definition: { key: Key, value: Value };
|
|
9
|
+
|
|
10
|
+
extend<Keys extends ModelDefinition[], Values extends ModelDefinition[]>(otherKeys: Keys, otherValues: Values): MapModel<[Key, ...Keys], [Value, ...Values]>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface MapModelConstructor {
|
|
14
|
+
<Key extends ModelDefinition, Value extends ModelDefinition>(keyDefinition: Key, valueDefinition: Value): MapModel<Key, Value>;
|
|
15
|
+
new<Key extends ModelDefinition, Value extends ModelDefinition>(keyDefinition: Key, valueDefinition: Value): MapModel<Key, Value>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const MapModel: MapModelConstructor;
|