@@ -39,9 +39,9 @@ export const createKipper = (args: CreateKipperOptions = {}): string =>
39
39
if (type.baseType === null) { return false; }
40
40
return this.isInHierarchyOfType(type.baseType);
41
41
}
42
- accepts(obj ) {
43
- if (this === obj ) return true;
44
- return obj instanceof KipperType && (this.customComparer ? this.customComparer(this, obj ) : true);
42
+ accepts(objT ) {
43
+ if (this === objT ) return true;
44
+ return objT instanceof KipperType && (this.customComparer ? this.customComparer(this, objT ) : true);
45
45
}
46
46
acceptsVal(obj) {
47
47
return this.accepts(__tmpKip.typeOf(obj));
@@ -51,12 +51,12 @@ export const createKipper = (args: CreateKipperOptions = {}): string =>
51
51
constructor(name, fields, methods, genericArgs, baseType = null, customComparer = null) {
52
52
super(name, fields, methods, baseType, customComparer); this.genericArgs = genericArgs;
53
53
}
54
- accepts(obj ) {
55
- if (this === obj ) return true;
56
- if (!(obj instanceof KipperGenericType) || this.genericArgs.length !== obj .genericArgs.length) return false;
57
- const foreignGenericArgs = Object.entries(obj .genericArgs);
58
- return this.name === obj .name &&
59
- (this.customComparer ? this.customComparer(this, obj ) : true) &&
54
+ accepts(objT ) {
55
+ if (this === objT ) return true;
56
+ if (!(objT instanceof KipperGenericType) || this.genericArgs.length !== objT .genericArgs.length) return false;
57
+ const foreignGenericArgs = Object.entries(objT .genericArgs);
58
+ return this.name === objT .name &&
59
+ (this.customComparer ? this.customComparer(this, objT ) : true) &&
60
60
Object.entries(this.genericArgs).every((arg, i) => {
61
61
if (Array.isArray(arg)) {
62
62
if (!Array.isArray(foreignGenericArgs[i]) || arg.length !== foreignGenericArgs[i].length) { return false; }
@@ -67,6 +67,32 @@ export const createKipper = (args: CreateKipperOptions = {}): string =>
67
67
}
68
68
changeGenericTypeArguments(genericArgs) { return new KipperGenericType(this.name, this.fields, this.methods, genericArgs, this.baseType) }
69
69
};
70
+ class KipperInterfaceType extends KipperType {
71
+ constructor(name, fields, methods, baseType = null, customComparer = null) {
72
+ super(name, fields, methods, baseType, customComparer);
73
+ }
74
+ accepts(objT) {
75
+ if (this === objT) return true;
76
+ if (!(objT instanceof KipperInterfaceType)) return false;
77
+ return this.isSubsetOfOrEqual(objT) &&
78
+ (this.customComparer ? this.customComparer(this, objT) : true);
79
+ }
80
+ acceptsVal(obj) {
81
+ const objT = __tmpKip.typeOf(obj);
82
+ if (objT !== __tmpKip.builtIn.obj && !(obj instanceof Object)) return false;
83
+ return __tmpKip.matches(obj, this);
84
+ }
85
+ isSubsetOfOrEqual(objT) {
86
+ return this.fields.every((field) => {
87
+ const fieldInObjT = objT.fields.find((f) => f.name === field.name);
88
+ return fieldInObjT && field.type.accepts(fieldInObjT.type);
89
+ }) && this.methods.every((method) => {
90
+ const methodInObjT = objT.methods.find((m) => m.name === method.name);
91
+ return methodInObjT && method.returnType.accepts(methodInObjT.returnType) && method.parameters.length === methodInObjT.parameters.length &&
92
+ method.parameters.every((param, i) => param.type.accepts(methodInObjT.parameters[i].type));
93
+ });
94
+ }
95
+ }
70
96
const __type_any = new KipperType('any', undefined, undefined);
71
97
const __type_null = new KipperType('null', undefined, undefined, undefined, (a, b) => a.name === b.name);
72
98
const __type_undefined = new KipperType('undefined', undefined, undefined, undefined, (a, b) => a.name === b.name);
@@ -77,15 +103,15 @@ export const createKipper = (args: CreateKipperOptions = {}): string =>
77
103
const __type_Array = new KipperGenericType('Array', undefined, undefined, {T: __type_any}, undefined, (a, b) => a.name === b.name);
78
104
const __type_Func = new KipperGenericType('Func', undefined, undefined, {T: [], R: __type_any}, undefined, (a, b) => a.name === b.name);
79
105
__tmpKip.builtIn = {
80
- any: __type_any,
81
- null: __type_null,
82
- undefined: __type_undefined,
83
- str: __type_str,
84
- num: __type_num,
85
- bool: __type_bool,
86
- obj: __type_obj,
87
- Array: __type_Array,
88
- Func: __type_Func,
106
+ any: __type_any,
107
+ null: __type_null,
108
+ undefined: __type_undefined,
109
+ str: __type_str,
110
+ num: __type_num,
111
+ bool: __type_bool,
112
+ obj: __type_obj,
113
+ Array: __type_Array,
114
+ Func: __type_Func,
89
115
};
90
116
__tmpKip.KipperError = KipperError;
91
117
__tmpKip.TypeError = (class KipperTypeError extends KipperError { constructor(msg) { super(msg); this.name = 'KipTypeError'; } });
@@ -96,29 +122,32 @@ export const createKipper = (args: CreateKipperOptions = {}): string =>
96
122
__tmpKip.Method = class KipperMethod { constructor(name, returnType, parameters) { this.name = name; this.returnType = returnType; this.parameters = parameters; } };
97
123
__tmpKip.Type = KipperType;
98
124
__tmpKip.assignTypeMeta = (value, typeMeta) => Object.assign(value, { __kipType: typeMeta });
125
+ __tmpKip.getTypeMeta = (value) => value.__kipType;
99
126
__tmpKip.newArrayT = (type) => __tmpKip.builtIn.Array.changeGenericTypeArguments({ T: type });
127
+ __tmpKip.newFuncT = (params, returnType) => __tmpKip.builtIn.Func.changeGenericTypeArguments({ T: params, R: returnType });
128
+ __tmpKip.newIntfT = (name, fields, methods, baseType = __tmpKip.builtIn.obj, customComparer = null) => new KipperInterfaceType(name, fields, methods, baseType, customComparer);
100
129
__tmpKip.typeOf = (value) => {
101
130
const prim = typeof value;
102
131
switch (prim) {
103
- case 'undefined': return __kipper .builtIn.undefined;
104
- case 'string': return __kipper .builtIn.str;
105
- case 'number': return __kipper .builtIn.num;
106
- case 'boolean': return __kipper .builtIn.bool;
132
+ case 'undefined': return __tmpKip .builtIn.undefined;
133
+ case 'string': return __tmpKip .builtIn.str;
134
+ case 'number': return __tmpKip .builtIn.num;
135
+ case 'boolean': return __tmpKip .builtIn.bool;
107
136
case 'function': {
108
- return '__kipType' in value ? value.__kipType : __kipper .builtIn.Func;
137
+ return '__kipType' in value ? value.__kipType : __tmpKip .builtIn.Func;
109
138
}
110
139
case 'symbol':
111
140
case 'bigint':
112
141
case 'object': {
113
- if (value === null) return __kipper .builtIn.null;
142
+ if (value === null) return __tmpKip .builtIn.null;
114
143
if (Array.isArray(value)) {
115
- return '__kipType' in value ? value.__kipType : __kipper .builtIn.Array;
144
+ return '__kipType' in value ? value.__kipType : __tmpKip .builtIn.Array;
116
145
}
117
146
const prot = Object.getPrototypeOf(value);
118
147
if (prot && prot.constructor !== Object) {
119
148
return prot.constructor;
120
149
}
121
- return __kipper .builtIn.obj;
150
+ return __tmpKip .builtIn.obj;
122
151
}
123
152
}
124
153
};
@@ -134,15 +163,15 @@ export const createKipper = (args: CreateKipperOptions = {}): string =>
134
163
return false;
135
164
}
136
165
const fieldValue = value[fieldName];
137
- const isSameType = __kipper .typeOf(fieldValue) === field.type;
166
+ const isSameType = __tmpKip .typeOf(fieldValue) === field.type;
138
167
if (primTypes.includes(field.type.name) && !isSameType) {
139
168
return false;
140
169
}
141
170
if (genTypes.includes(fieldType.name)) {
142
171
throw new KipperNotImplementedError("Matches does not yet support the 'Array' and 'Func' types");
143
172
}
144
173
if (!primTypes.includes(fieldType.name)) {
145
- if (!__kipper .matches(fieldValue, fieldType)) {
174
+ if (!__tmpKip .matches(fieldValue, fieldType)) {
146
175
return false;
147
176
}
148
177
}
0 commit comments