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.
@@ -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;
@@ -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
- extend(newArgs, newReturns) {
57
- const args = this.definition.arguments,
58
- mixedArgs = newArgs.map((a, i) => extendDefinition(i in args ? args[i] : [], newArgs[i])),
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;