-
Notifications
You must be signed in to change notification settings - Fork 2k
/
Copy pathuser_defined_metadata.ts
104 lines (99 loc) · 3.74 KB
/
user_defined_metadata.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
* @license
* Copyright 2019 Google LLC
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
/** Utility functions related to user-defined metadata. */
// Maximum recommended serialized size for user-defined metadata.
// Beyond this limit, a warning message will be printed during model loading and
// saving.
export const MAX_USER_DEFINED_METADATA_SERIALIZED_LENGTH = 1 * 1024 * 1024;
/**
* Check validity of user-defined metadata.
*
* @param userDefinedMetadata
* @param modelName Name of the model that the user-defined metadata belongs to.
* Used during construction of error messages.
* @param checkSize Whether to check the size of the metadata is under
* recommended limit. Default: `false`. If `true`, will try stringify the
* JSON object and print a console warning if the serialzied size is above the
* limit.
* @throws Error if `userDefinedMetadata` is not a plain JSON object.
*/
export function checkUserDefinedMetadata(
userDefinedMetadata: {}, modelName: string, checkSize = false): void {
if (userDefinedMetadata == null ||
typeof userDefinedMetadata !== 'object' ||
Object.getPrototypeOf(userDefinedMetadata) !== Object.prototype ||
!plainObjectCheck(userDefinedMetadata)) {
throw new Error(
'User-defined metadata is expected to be a JSON object, but is not.');
}
if (checkSize) {
const out = JSON.stringify(userDefinedMetadata);
if (out.length > MAX_USER_DEFINED_METADATA_SERIALIZED_LENGTH) {
console.warn(
`User-defined metadata of model "${modelName}" is too large in ` +
`size (length=${out.length} when serialized). It is not ` +
`recommended to store such large objects in user-defined metadata. ` +
`Please make sure its serialized length is <= ` +
`${MAX_USER_DEFINED_METADATA_SERIALIZED_LENGTH}.`);
}
}
}
/**
* Check if an input is plain JSON object or any valid subfield of it.
*
* @param x The input to be checked.
* @param assertObject Whether to assert `x` is a JSON object, i.e., reject
* cases of arrays and primitives.
* @return Returns `true` if and only if `x` is a plain JSON object,
* a JSON-valid primitive including string, number, boolean and null,
* or an array of the said types.
*/
// tslint:disable-next-line:no-any
export function plainObjectCheck(x: any): boolean {
if (x === null) {
// Note: typeof `null` is 'object', and `null` is valid in JSON.
return true;
} else if (typeof x === 'object') {
if (Object.getPrototypeOf(x) === Object.prototype) {
// `x` is a JavaScript object and its prototype is Object.
const keys = Object.keys(x);
for (const key of keys) {
if (typeof key !== 'string') {
// JSON keys must be strings.
return false;
}
if (!plainObjectCheck(x[key])) { // Recursive call.
return false;
}
}
return true;
} else {
// `x` is a JavaScript object but its prototype is not Object.
if (Array.isArray(x)) {
// `x` is a JavaScript array.
for (const item of x) {
if (!plainObjectCheck(item)) { // Recursive call.
return false;
}
}
return true;
} else {
// `x` is a JavaScript object and its prototype is not Object,
// and it's not an Array. I.e., it's a complex object such as
// `Error` and `Date`.
return false;
}
}
} else {
// `x` is not a JavaScript object or `null`.
const xType = typeof x;
return xType === 'string' || xType === 'number' || xType === 'boolean';
}
}