@naturalcycles/js-lib 14.42.1 → 14.46.0

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.
Files changed (139) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/index.d.ts +3 -1
  3. package/dist/index.js +7 -3
  4. package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +7 -0
  5. package/dist/json-schema/from-data/generateJsonSchemaFromData.js +90 -0
  6. package/dist/json-schema/jsonSchema.model.d.ts +7 -0
  7. package/dist/json-schema/jsonSchemaBuilder.d.ts +3 -0
  8. package/dist/json-schema/jsonSchemaBuilder.js +9 -0
  9. package/dist/string/stringifyAny.d.ts +1 -1
  10. package/dist/string/stringifyAny.js +1 -1
  11. package/dist/typeFest.d.ts +16 -0
  12. package/dist/vendor/is.d.ts +224 -0
  13. package/dist/vendor/is.js +466 -0
  14. package/dist-esm/array/array.util.js +0 -1
  15. package/dist-esm/array/range.js +0 -1
  16. package/dist-esm/decorators/createPromiseDecorator.js +0 -1
  17. package/dist-esm/decorators/debounce.decorator.js +0 -1
  18. package/dist-esm/decorators/debounce.js +0 -1
  19. package/dist-esm/decorators/decorator.util.js +0 -1
  20. package/dist-esm/decorators/logMethod.decorator.js +0 -1
  21. package/dist-esm/decorators/memo.decorator.js +0 -1
  22. package/dist-esm/decorators/memo.util.js +0 -1
  23. package/dist-esm/decorators/memoFn.js +0 -1
  24. package/dist-esm/decorators/memoSimple.decorator.js +0 -1
  25. package/dist-esm/decorators/retry.decorator.js +0 -1
  26. package/dist-esm/decorators/timeout.decorator.js +0 -1
  27. package/dist-esm/error/app.error.js +0 -1
  28. package/dist-esm/error/assert.js +0 -1
  29. package/dist-esm/error/error.model.js +0 -1
  30. package/dist-esm/error/error.util.js +0 -1
  31. package/dist-esm/error/errorMode.js +0 -1
  32. package/dist-esm/error/http.error.js +0 -1
  33. package/dist-esm/error/try.js +0 -1
  34. package/dist-esm/error/tryCatch.js +0 -1
  35. package/dist-esm/index.js +3 -2
  36. package/dist-esm/json-schema/from-data/generateJsonSchemaFromData.js +86 -0
  37. package/dist-esm/json-schema/jsonSchema.cnst.js +0 -1
  38. package/dist-esm/json-schema/jsonSchema.model.js +0 -1
  39. package/dist-esm/json-schema/jsonSchema.util.js +0 -1
  40. package/dist-esm/json-schema/jsonSchemaBuilder.js +9 -1
  41. package/dist-esm/json-schema/jsonSchemas.js +0 -1
  42. package/dist-esm/lodash.types.js +0 -1
  43. package/dist-esm/math/math.util.js +0 -1
  44. package/dist-esm/math/sma.js +0 -1
  45. package/dist-esm/number/createDeterministicRandom.js +0 -1
  46. package/dist-esm/number/number.util.js +0 -1
  47. package/dist-esm/object/deepEquals.js +0 -1
  48. package/dist-esm/object/object.util.js +0 -1
  49. package/dist-esm/object/sortObject.js +0 -1
  50. package/dist-esm/object/sortObjectDeep.js +0 -1
  51. package/dist-esm/promise/AggregatedError.js +0 -1
  52. package/dist-esm/promise/pBatch.js +0 -1
  53. package/dist-esm/promise/pDefer.js +0 -1
  54. package/dist-esm/promise/pDelay.js +0 -1
  55. package/dist-esm/promise/pFilter.js +0 -1
  56. package/dist-esm/promise/pHang.js +0 -1
  57. package/dist-esm/promise/pMap.js +0 -1
  58. package/dist-esm/promise/pProps.js +0 -1
  59. package/dist-esm/promise/pRetry.js +0 -1
  60. package/dist-esm/promise/pState.js +0 -1
  61. package/dist-esm/promise/pTimeout.js +0 -1
  62. package/dist-esm/promise/pTuple.js +0 -1
  63. package/dist-esm/string/case.js +0 -1
  64. package/dist-esm/string/json.util.js +0 -1
  65. package/dist-esm/string/lodash/unicodeWords.js +0 -1
  66. package/dist-esm/string/lodash/words.js +0 -1
  67. package/dist-esm/string/string.util.js +0 -1
  68. package/dist-esm/string/stringifyAny.js +1 -2
  69. package/dist-esm/time/time.util.js +0 -1
  70. package/dist-esm/typeFest.js +0 -1
  71. package/dist-esm/types.js +0 -1
  72. package/dist-esm/unit/size.util.js +0 -1
  73. package/dist-esm/vendor/is.js +463 -0
  74. package/package.json +2 -1
  75. package/src/index.ts +4 -0
  76. package/src/json-schema/from-data/generateJsonSchemaFromData.ts +120 -0
  77. package/src/json-schema/jsonSchema.model.ts +8 -0
  78. package/src/json-schema/jsonSchemaBuilder.ts +16 -10
  79. package/src/string/stringifyAny.ts +2 -2
  80. package/src/typeFest.ts +30 -0
  81. package/src/vendor/is.ts +837 -0
  82. package/dist-esm/array/array.util.js.map +0 -1
  83. package/dist-esm/array/range.js.map +0 -1
  84. package/dist-esm/decorators/createPromiseDecorator.js.map +0 -1
  85. package/dist-esm/decorators/debounce.decorator.js.map +0 -1
  86. package/dist-esm/decorators/debounce.js.map +0 -1
  87. package/dist-esm/decorators/decorator.util.js.map +0 -1
  88. package/dist-esm/decorators/logMethod.decorator.js.map +0 -1
  89. package/dist-esm/decorators/memo.decorator.js.map +0 -1
  90. package/dist-esm/decorators/memo.util.js.map +0 -1
  91. package/dist-esm/decorators/memoFn.js.map +0 -1
  92. package/dist-esm/decorators/memoSimple.decorator.js.map +0 -1
  93. package/dist-esm/decorators/retry.decorator.js.map +0 -1
  94. package/dist-esm/decorators/timeout.decorator.js.map +0 -1
  95. package/dist-esm/error/app.error.js.map +0 -1
  96. package/dist-esm/error/assert.js.map +0 -1
  97. package/dist-esm/error/error.model.js.map +0 -1
  98. package/dist-esm/error/error.util.js.map +0 -1
  99. package/dist-esm/error/errorMode.js.map +0 -1
  100. package/dist-esm/error/http.error.js.map +0 -1
  101. package/dist-esm/error/try.js.map +0 -1
  102. package/dist-esm/error/tryCatch.js.map +0 -1
  103. package/dist-esm/index.js.map +0 -1
  104. package/dist-esm/json-schema/jsonSchema.cnst.js.map +0 -1
  105. package/dist-esm/json-schema/jsonSchema.model.js.map +0 -1
  106. package/dist-esm/json-schema/jsonSchema.util.js.map +0 -1
  107. package/dist-esm/json-schema/jsonSchemaBuilder.js.map +0 -1
  108. package/dist-esm/json-schema/jsonSchemas.js.map +0 -1
  109. package/dist-esm/lodash.types.js.map +0 -1
  110. package/dist-esm/math/math.util.js.map +0 -1
  111. package/dist-esm/math/sma.js.map +0 -1
  112. package/dist-esm/number/createDeterministicRandom.js.map +0 -1
  113. package/dist-esm/number/number.util.js.map +0 -1
  114. package/dist-esm/object/deepEquals.js.map +0 -1
  115. package/dist-esm/object/object.util.js.map +0 -1
  116. package/dist-esm/object/sortObject.js.map +0 -1
  117. package/dist-esm/object/sortObjectDeep.js.map +0 -1
  118. package/dist-esm/promise/AggregatedError.js.map +0 -1
  119. package/dist-esm/promise/pBatch.js.map +0 -1
  120. package/dist-esm/promise/pDefer.js.map +0 -1
  121. package/dist-esm/promise/pDelay.js.map +0 -1
  122. package/dist-esm/promise/pFilter.js.map +0 -1
  123. package/dist-esm/promise/pHang.js.map +0 -1
  124. package/dist-esm/promise/pMap.js.map +0 -1
  125. package/dist-esm/promise/pProps.js.map +0 -1
  126. package/dist-esm/promise/pRetry.js.map +0 -1
  127. package/dist-esm/promise/pState.js.map +0 -1
  128. package/dist-esm/promise/pTimeout.js.map +0 -1
  129. package/dist-esm/promise/pTuple.js.map +0 -1
  130. package/dist-esm/string/case.js.map +0 -1
  131. package/dist-esm/string/json.util.js.map +0 -1
  132. package/dist-esm/string/lodash/unicodeWords.js.map +0 -1
  133. package/dist-esm/string/lodash/words.js.map +0 -1
  134. package/dist-esm/string/string.util.js.map +0 -1
  135. package/dist-esm/string/stringifyAny.js.map +0 -1
  136. package/dist-esm/time/time.util.js.map +0 -1
  137. package/dist-esm/typeFest.js.map +0 -1
  138. package/dist-esm/types.js.map +0 -1
  139. package/dist-esm/unit/size.util.js.map +0 -1
@@ -0,0 +1,463 @@
1
+ /// <reference lib="es2018"/>
2
+ /// <reference lib="dom"/>
3
+ /// <reference types="node"/>
4
+ const typedArrayTypeNames = [
5
+ 'Int8Array',
6
+ 'Uint8Array',
7
+ 'Uint8ClampedArray',
8
+ 'Int16Array',
9
+ 'Uint16Array',
10
+ 'Int32Array',
11
+ 'Uint32Array',
12
+ 'Float32Array',
13
+ 'Float64Array',
14
+ 'BigInt64Array',
15
+ 'BigUint64Array',
16
+ ];
17
+ function isTypedArrayName(name) {
18
+ return typedArrayTypeNames.includes(name);
19
+ }
20
+ const objectTypeNames = [
21
+ 'Function',
22
+ 'Generator',
23
+ 'AsyncGenerator',
24
+ 'GeneratorFunction',
25
+ 'AsyncGeneratorFunction',
26
+ 'AsyncFunction',
27
+ 'Observable',
28
+ 'Array',
29
+ 'Buffer',
30
+ 'Object',
31
+ 'RegExp',
32
+ 'Date',
33
+ 'Error',
34
+ 'Map',
35
+ 'Set',
36
+ 'WeakMap',
37
+ 'WeakSet',
38
+ 'ArrayBuffer',
39
+ 'SharedArrayBuffer',
40
+ 'DataView',
41
+ 'Promise',
42
+ 'URL',
43
+ 'FormData',
44
+ 'URLSearchParams',
45
+ 'HTMLElement',
46
+ ...typedArrayTypeNames,
47
+ ];
48
+ function isObjectTypeName(name) {
49
+ return objectTypeNames.includes(name);
50
+ }
51
+ const primitiveTypeNames = [
52
+ 'null',
53
+ 'undefined',
54
+ 'string',
55
+ 'number',
56
+ 'bigint',
57
+ 'boolean',
58
+ 'symbol',
59
+ ];
60
+ function isPrimitiveTypeName(name) {
61
+ return primitiveTypeNames.includes(name);
62
+ }
63
+ // eslint-disable-next-line @typescript-eslint/ban-types
64
+ function isOfType(type) {
65
+ return (value) => typeof value === type;
66
+ }
67
+ const { toString } = Object.prototype;
68
+ const getObjectType = (value) => {
69
+ const objectTypeName = toString.call(value).slice(8, -1);
70
+ if (/HTML\w+Element/.test(objectTypeName) && is.domElement(value)) {
71
+ return 'HTMLElement';
72
+ }
73
+ if (isObjectTypeName(objectTypeName)) {
74
+ return objectTypeName;
75
+ }
76
+ return undefined;
77
+ };
78
+ const isObjectOfType = (type) => (value) => getObjectType(value) === type;
79
+ export function is(value) {
80
+ if (value === null) {
81
+ return 'null';
82
+ }
83
+ switch (typeof value) {
84
+ case 'undefined':
85
+ return 'undefined';
86
+ case 'string':
87
+ return 'string';
88
+ case 'number':
89
+ return 'number';
90
+ case 'boolean':
91
+ return 'boolean';
92
+ case 'function':
93
+ return 'Function';
94
+ case 'bigint':
95
+ return 'bigint';
96
+ case 'symbol':
97
+ return 'symbol';
98
+ default:
99
+ }
100
+ if (is.observable(value)) {
101
+ return 'Observable';
102
+ }
103
+ if (is.array(value)) {
104
+ return 'Array';
105
+ }
106
+ if (is.buffer(value)) {
107
+ return 'Buffer';
108
+ }
109
+ const tagType = getObjectType(value);
110
+ if (tagType) {
111
+ return tagType;
112
+ }
113
+ if (value instanceof String ||
114
+ value instanceof Boolean ||
115
+ value instanceof Number) {
116
+ throw new TypeError("Please don't use object wrappers for primitive types");
117
+ }
118
+ return 'Object';
119
+ }
120
+ is.undefined = isOfType('undefined');
121
+ is.string = isOfType('string');
122
+ const isNumberType = isOfType('number');
123
+ is.number = (value) => isNumberType(value) && !is.nan(value);
124
+ is.bigint = isOfType('bigint');
125
+ // eslint-disable-next-line @typescript-eslint/ban-types
126
+ is.function_ = isOfType('function');
127
+ is.null_ = (value) => value === null;
128
+ is.class_ = (value) => is.function_(value) && value.toString().startsWith('class ');
129
+ is.boolean = (value) => value === true || value === false;
130
+ is.symbol = isOfType('symbol');
131
+ is.numericString = (value) => is.string(value) && !is.emptyStringOrWhitespace(value) && !Number.isNaN(Number(value));
132
+ is.array = (value, assertion) => {
133
+ if (!Array.isArray(value)) {
134
+ return false;
135
+ }
136
+ if (!is.function_(assertion)) {
137
+ return true;
138
+ }
139
+ return value.every(assertion);
140
+ };
141
+ is.buffer = (value) => { var _a, _b, _c, _d; return (_d = (_c = (_b = (_a = value) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.isBuffer) === null || _c === void 0 ? void 0 : _c.call(_b, value)) !== null && _d !== void 0 ? _d : false; };
142
+ is.nullOrUndefined = (value) => is.null_(value) || is.undefined(value);
143
+ is.object = (value) => !is.null_(value) && (typeof value === 'object' || is.function_(value));
144
+ is.iterable = (value) => { var _a; return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a[Symbol.iterator]); };
145
+ is.asyncIterable = (value) => { var _a; return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a[Symbol.asyncIterator]); };
146
+ is.generator = (value) => is.iterable(value) && is.function_(value.next) && is.function_(value.throw);
147
+ is.asyncGenerator = (value) => is.asyncIterable(value) && is.function_(value.next) && is.function_(value.throw);
148
+ is.nativePromise = (value) => isObjectOfType('Promise')(value);
149
+ const hasPromiseAPI = (value) => { var _a, _b; return is.function_((_a = value) === null || _a === void 0 ? void 0 : _a.then) && is.function_((_b = value) === null || _b === void 0 ? void 0 : _b.catch); };
150
+ is.promise = (value) => is.nativePromise(value) || hasPromiseAPI(value);
151
+ is.generatorFunction = isObjectOfType('GeneratorFunction');
152
+ is.asyncGeneratorFunction = (value) => getObjectType(value) === 'AsyncGeneratorFunction';
153
+ is.asyncFunction = (value) => getObjectType(value) === 'AsyncFunction';
154
+ // eslint-disable-next-line no-prototype-builtins, @typescript-eslint/ban-types
155
+ is.boundFunction = (value) => is.function_(value) && !value.hasOwnProperty('prototype');
156
+ is.regExp = isObjectOfType('RegExp');
157
+ is.date = isObjectOfType('Date');
158
+ is.error = isObjectOfType('Error');
159
+ is.map = (value) => isObjectOfType('Map')(value);
160
+ is.set = (value) => isObjectOfType('Set')(value);
161
+ is.weakMap = (value) => isObjectOfType('WeakMap')(value);
162
+ is.weakSet = (value) => isObjectOfType('WeakSet')(value);
163
+ is.int8Array = isObjectOfType('Int8Array');
164
+ is.uint8Array = isObjectOfType('Uint8Array');
165
+ is.uint8ClampedArray = isObjectOfType('Uint8ClampedArray');
166
+ is.int16Array = isObjectOfType('Int16Array');
167
+ is.uint16Array = isObjectOfType('Uint16Array');
168
+ is.int32Array = isObjectOfType('Int32Array');
169
+ is.uint32Array = isObjectOfType('Uint32Array');
170
+ is.float32Array = isObjectOfType('Float32Array');
171
+ is.float64Array = isObjectOfType('Float64Array');
172
+ is.bigInt64Array = isObjectOfType('BigInt64Array');
173
+ is.bigUint64Array = isObjectOfType('BigUint64Array');
174
+ is.arrayBuffer = isObjectOfType('ArrayBuffer');
175
+ is.sharedArrayBuffer = isObjectOfType('SharedArrayBuffer');
176
+ is.dataView = isObjectOfType('DataView');
177
+ is.directInstanceOf = (instance, class_) => Object.getPrototypeOf(instance) === class_.prototype;
178
+ is.urlInstance = (value) => isObjectOfType('URL')(value);
179
+ is.urlString = (value) => {
180
+ if (!is.string(value)) {
181
+ return false;
182
+ }
183
+ try {
184
+ new URL(value); // eslint-disable-line no-new
185
+ return true;
186
+ }
187
+ catch (_a) {
188
+ return false;
189
+ }
190
+ };
191
+ // TODO: Use the `not` operator with a type guard here when it's available.
192
+ // Example: `is.truthy = (value: unknown): value is (not false | not 0 | not '' | not undefined | not null) => Boolean(value);`
193
+ is.truthy = (value) => Boolean(value);
194
+ // Example: `is.falsy = (value: unknown): value is (not true | 0 | '' | undefined | null) => Boolean(value);`
195
+ is.falsy = (value) => !value;
196
+ is.nan = (value) => Number.isNaN(value);
197
+ is.primitive = (value) => is.null_(value) || isPrimitiveTypeName(typeof value);
198
+ is.integer = (value) => Number.isInteger(value);
199
+ is.safeInteger = (value) => Number.isSafeInteger(value);
200
+ is.plainObject = (value) => {
201
+ // From: https://github.com/sindresorhus/is-plain-obj/blob/main/index.js
202
+ if (toString.call(value) !== '[object Object]') {
203
+ return false;
204
+ }
205
+ const prototype = Object.getPrototypeOf(value);
206
+ return prototype === null || prototype === Object.getPrototypeOf({});
207
+ };
208
+ is.typedArray = (value) => isTypedArrayName(getObjectType(value));
209
+ const isValidLength = (value) => is.safeInteger(value) && value >= 0;
210
+ is.arrayLike = (value) => !is.nullOrUndefined(value) &&
211
+ !is.function_(value) &&
212
+ isValidLength(value.length);
213
+ is.inRange = (value, range) => {
214
+ if (is.number(range)) {
215
+ return value >= Math.min(0, range) && value <= Math.max(range, 0);
216
+ }
217
+ if (is.array(range) && range.length === 2) {
218
+ return value >= Math.min(...range) && value <= Math.max(...range);
219
+ }
220
+ throw new TypeError(`Invalid range: ${JSON.stringify(range)}`);
221
+ };
222
+ const NODE_TYPE_ELEMENT = 1;
223
+ const DOM_PROPERTIES_TO_CHECK = [
224
+ 'innerHTML',
225
+ 'ownerDocument',
226
+ 'style',
227
+ 'attributes',
228
+ 'nodeValue',
229
+ ];
230
+ is.domElement = (value) => {
231
+ return (is.object(value) &&
232
+ value.nodeType === NODE_TYPE_ELEMENT &&
233
+ is.string(value.nodeName) &&
234
+ !is.plainObject(value) &&
235
+ DOM_PROPERTIES_TO_CHECK.every(property => property in value));
236
+ };
237
+ is.observable = (value) => {
238
+ var _a, _b, _c, _d;
239
+ if (!value) {
240
+ return false;
241
+ }
242
+ if (value === ((_b = (_a = value)[Symbol.observable]) === null || _b === void 0 ? void 0 : _b.call(_a))) {
243
+ return true;
244
+ }
245
+ if (value === ((_d = (_c = value)['@@observable']) === null || _d === void 0 ? void 0 : _d.call(_c))) {
246
+ return true;
247
+ }
248
+ return false;
249
+ };
250
+ is.nodeStream = (value) => is.object(value) && is.function_(value.pipe) && !is.observable(value);
251
+ is.infinite = (value) => value === Infinity || value === -Infinity;
252
+ const isAbsoluteMod2 = (remainder) => (value) => is.integer(value) && Math.abs(value % 2) === remainder;
253
+ is.evenInteger = isAbsoluteMod2(0);
254
+ is.oddInteger = isAbsoluteMod2(1);
255
+ is.emptyArray = (value) => is.array(value) && value.length === 0;
256
+ is.nonEmptyArray = (value) => is.array(value) && value.length > 0;
257
+ is.emptyString = (value) => is.string(value) && value.length === 0;
258
+ // TODO: Use `not ''` when the `not` operator is available.
259
+ is.nonEmptyString = (value) => is.string(value) && value.length > 0;
260
+ const isWhiteSpaceString = (value) => is.string(value) && !/\S/.test(value);
261
+ is.emptyStringOrWhitespace = (value) => is.emptyString(value) || isWhiteSpaceString(value);
262
+ is.emptyObject = (value) => is.object(value) && !is.map(value) && !is.set(value) && Object.keys(value).length === 0;
263
+ // TODO: Use `not` operator here to remove `Map` and `Set` from type guard:
264
+ // - https://github.com/Microsoft/TypeScript/pull/29317
265
+ is.nonEmptyObject = (value) => is.object(value) && !is.map(value) && !is.set(value) && Object.keys(value).length > 0;
266
+ is.emptySet = (value) => is.set(value) && value.size === 0;
267
+ is.nonEmptySet = (value) => is.set(value) && value.size > 0;
268
+ is.emptyMap = (value) => is.map(value) && value.size === 0;
269
+ is.nonEmptyMap = (value) => is.map(value) && value.size > 0;
270
+ // `PropertyKey` is any value that can be used as an object key (string, number, or symbol)
271
+ is.propertyKey = (value) => is.any([is.string, is.number, is.symbol], value);
272
+ is.formData = (value) => isObjectOfType('FormData')(value);
273
+ is.urlSearchParams = (value) => isObjectOfType('URLSearchParams')(value);
274
+ const predicateOnArray = (method, predicate, values) => {
275
+ if (!is.function_(predicate)) {
276
+ throw new TypeError(`Invalid predicate: ${JSON.stringify(predicate)}`);
277
+ }
278
+ if (values.length === 0) {
279
+ throw new TypeError('Invalid number of values');
280
+ }
281
+ return method.call(values, predicate);
282
+ };
283
+ is.any = (predicate, ...values) => {
284
+ const predicates = is.array(predicate) ? predicate : [predicate];
285
+ return predicates.some(singlePredicate => predicateOnArray(Array.prototype.some, singlePredicate, values));
286
+ };
287
+ is.all = (predicate, ...values) => predicateOnArray(Array.prototype.every, predicate, values);
288
+ const assertType = (condition, description, value, options = {}) => {
289
+ if (!condition) {
290
+ const { multipleValues } = options;
291
+ const valuesMessage = multipleValues
292
+ ? `received values of types ${[
293
+ ...new Set(value.map(singleValue => `\`${is(singleValue)}\``)),
294
+ ].join(', ')}`
295
+ : `received value of type \`${is(value)}\``;
296
+ throw new TypeError(`Expected value which is \`${description}\`, ${valuesMessage}.`);
297
+ }
298
+ };
299
+ export var AssertionTypeDescription;
300
+ (function (AssertionTypeDescription) {
301
+ AssertionTypeDescription["class_"] = "Class";
302
+ AssertionTypeDescription["numericString"] = "string with a number";
303
+ AssertionTypeDescription["nullOrUndefined"] = "null or undefined";
304
+ AssertionTypeDescription["iterable"] = "Iterable";
305
+ AssertionTypeDescription["asyncIterable"] = "AsyncIterable";
306
+ AssertionTypeDescription["nativePromise"] = "native Promise";
307
+ AssertionTypeDescription["urlString"] = "string with a URL";
308
+ AssertionTypeDescription["truthy"] = "truthy";
309
+ AssertionTypeDescription["falsy"] = "falsy";
310
+ AssertionTypeDescription["nan"] = "NaN";
311
+ AssertionTypeDescription["primitive"] = "primitive";
312
+ AssertionTypeDescription["integer"] = "integer";
313
+ AssertionTypeDescription["safeInteger"] = "integer";
314
+ AssertionTypeDescription["plainObject"] = "plain object";
315
+ AssertionTypeDescription["arrayLike"] = "array-like";
316
+ AssertionTypeDescription["typedArray"] = "TypedArray";
317
+ AssertionTypeDescription["domElement"] = "HTMLElement";
318
+ AssertionTypeDescription["nodeStream"] = "Node.js Stream";
319
+ AssertionTypeDescription["infinite"] = "infinite number";
320
+ AssertionTypeDescription["emptyArray"] = "empty array";
321
+ AssertionTypeDescription["nonEmptyArray"] = "non-empty array";
322
+ AssertionTypeDescription["emptyString"] = "empty string";
323
+ AssertionTypeDescription["nonEmptyString"] = "non-empty string";
324
+ AssertionTypeDescription["emptyStringOrWhitespace"] = "empty string or whitespace";
325
+ AssertionTypeDescription["emptyObject"] = "empty object";
326
+ AssertionTypeDescription["nonEmptyObject"] = "non-empty object";
327
+ AssertionTypeDescription["emptySet"] = "empty set";
328
+ AssertionTypeDescription["nonEmptySet"] = "non-empty set";
329
+ AssertionTypeDescription["emptyMap"] = "empty map";
330
+ AssertionTypeDescription["nonEmptyMap"] = "non-empty map";
331
+ AssertionTypeDescription["evenInteger"] = "even integer";
332
+ AssertionTypeDescription["oddInteger"] = "odd integer";
333
+ AssertionTypeDescription["directInstanceOf"] = "T";
334
+ AssertionTypeDescription["inRange"] = "in range";
335
+ AssertionTypeDescription["any"] = "predicate returns truthy for any value";
336
+ AssertionTypeDescription["all"] = "predicate returns truthy for all values";
337
+ })(AssertionTypeDescription || (AssertionTypeDescription = {}));
338
+ export const assert = {
339
+ // Unknowns.
340
+ undefined: (value) => assertType(is.undefined(value), 'undefined', value),
341
+ string: (value) => assertType(is.string(value), 'string', value),
342
+ number: (value) => assertType(is.number(value), 'number', value),
343
+ bigint: (value) => assertType(is.bigint(value), 'bigint', value),
344
+ // eslint-disable-next-line @typescript-eslint/ban-types
345
+ function_: (value) => assertType(is.function_(value), 'Function', value),
346
+ null_: (value) => assertType(is.null_(value), 'null', value),
347
+ class_: (value) => assertType(is.class_(value), AssertionTypeDescription.class_, value),
348
+ boolean: (value) => assertType(is.boolean(value), 'boolean', value),
349
+ symbol: (value) => assertType(is.symbol(value), 'symbol', value),
350
+ numericString: (value) => assertType(is.numericString(value), AssertionTypeDescription.numericString, value),
351
+ array: (value, assertion) => {
352
+ const assert = assertType;
353
+ assert(is.array(value), 'Array', value);
354
+ if (assertion) {
355
+ value.forEach(assertion);
356
+ }
357
+ },
358
+ buffer: (value) => assertType(is.buffer(value), 'Buffer', value),
359
+ nullOrUndefined: (value) => assertType(is.nullOrUndefined(value), AssertionTypeDescription.nullOrUndefined, value),
360
+ object: (value) => assertType(is.object(value), 'Object', value),
361
+ iterable: (value) => assertType(is.iterable(value), AssertionTypeDescription.iterable, value),
362
+ asyncIterable: (value) => assertType(is.asyncIterable(value), AssertionTypeDescription.asyncIterable, value),
363
+ generator: (value) => assertType(is.generator(value), 'Generator', value),
364
+ asyncGenerator: (value) => assertType(is.asyncGenerator(value), 'AsyncGenerator', value),
365
+ nativePromise: (value) => assertType(is.nativePromise(value), AssertionTypeDescription.nativePromise, value),
366
+ promise: (value) => assertType(is.promise(value), 'Promise', value),
367
+ generatorFunction: (value) => assertType(is.generatorFunction(value), 'GeneratorFunction', value),
368
+ asyncGeneratorFunction: (value) => assertType(is.asyncGeneratorFunction(value), 'AsyncGeneratorFunction', value),
369
+ // eslint-disable-next-line @typescript-eslint/ban-types
370
+ asyncFunction: (value) => assertType(is.asyncFunction(value), 'AsyncFunction', value),
371
+ // eslint-disable-next-line @typescript-eslint/ban-types
372
+ boundFunction: (value) => assertType(is.boundFunction(value), 'Function', value),
373
+ regExp: (value) => assertType(is.regExp(value), 'RegExp', value),
374
+ date: (value) => assertType(is.date(value), 'Date', value),
375
+ error: (value) => assertType(is.error(value), 'Error', value),
376
+ map: (value) => assertType(is.map(value), 'Map', value),
377
+ set: (value) => assertType(is.set(value), 'Set', value),
378
+ weakMap: (value) => assertType(is.weakMap(value), 'WeakMap', value),
379
+ weakSet: (value) => assertType(is.weakSet(value), 'WeakSet', value),
380
+ int8Array: (value) => assertType(is.int8Array(value), 'Int8Array', value),
381
+ uint8Array: (value) => assertType(is.uint8Array(value), 'Uint8Array', value),
382
+ uint8ClampedArray: (value) => assertType(is.uint8ClampedArray(value), 'Uint8ClampedArray', value),
383
+ int16Array: (value) => assertType(is.int16Array(value), 'Int16Array', value),
384
+ uint16Array: (value) => assertType(is.uint16Array(value), 'Uint16Array', value),
385
+ int32Array: (value) => assertType(is.int32Array(value), 'Int32Array', value),
386
+ uint32Array: (value) => assertType(is.uint32Array(value), 'Uint32Array', value),
387
+ float32Array: (value) => assertType(is.float32Array(value), 'Float32Array', value),
388
+ float64Array: (value) => assertType(is.float64Array(value), 'Float64Array', value),
389
+ bigInt64Array: (value) => assertType(is.bigInt64Array(value), 'BigInt64Array', value),
390
+ bigUint64Array: (value) => assertType(is.bigUint64Array(value), 'BigUint64Array', value),
391
+ arrayBuffer: (value) => assertType(is.arrayBuffer(value), 'ArrayBuffer', value),
392
+ sharedArrayBuffer: (value) => assertType(is.sharedArrayBuffer(value), 'SharedArrayBuffer', value),
393
+ dataView: (value) => assertType(is.dataView(value), 'DataView', value),
394
+ urlInstance: (value) => assertType(is.urlInstance(value), 'URL', value),
395
+ urlString: (value) => assertType(is.urlString(value), AssertionTypeDescription.urlString, value),
396
+ truthy: (value) => assertType(is.truthy(value), AssertionTypeDescription.truthy, value),
397
+ falsy: (value) => assertType(is.falsy(value), AssertionTypeDescription.falsy, value),
398
+ nan: (value) => assertType(is.nan(value), AssertionTypeDescription.nan, value),
399
+ primitive: (value) => assertType(is.primitive(value), AssertionTypeDescription.primitive, value),
400
+ integer: (value) => assertType(is.integer(value), AssertionTypeDescription.integer, value),
401
+ safeInteger: (value) => assertType(is.safeInteger(value), AssertionTypeDescription.safeInteger, value),
402
+ plainObject: (value) => assertType(is.plainObject(value), AssertionTypeDescription.plainObject, value),
403
+ typedArray: (value) => assertType(is.typedArray(value), AssertionTypeDescription.typedArray, value),
404
+ arrayLike: (value) => assertType(is.arrayLike(value), AssertionTypeDescription.arrayLike, value),
405
+ domElement: (value) => assertType(is.domElement(value), AssertionTypeDescription.domElement, value),
406
+ observable: (value) => assertType(is.observable(value), 'Observable', value),
407
+ nodeStream: (value) => assertType(is.nodeStream(value), AssertionTypeDescription.nodeStream, value),
408
+ infinite: (value) => assertType(is.infinite(value), AssertionTypeDescription.infinite, value),
409
+ emptyArray: (value) => assertType(is.emptyArray(value), AssertionTypeDescription.emptyArray, value),
410
+ nonEmptyArray: (value) => assertType(is.nonEmptyArray(value), AssertionTypeDescription.nonEmptyArray, value),
411
+ emptyString: (value) => assertType(is.emptyString(value), AssertionTypeDescription.emptyString, value),
412
+ nonEmptyString: (value) => assertType(is.nonEmptyString(value), AssertionTypeDescription.nonEmptyString, value),
413
+ emptyStringOrWhitespace: (value) => assertType(is.emptyStringOrWhitespace(value), AssertionTypeDescription.emptyStringOrWhitespace, value),
414
+ emptyObject: (value) => assertType(is.emptyObject(value), AssertionTypeDescription.emptyObject, value),
415
+ nonEmptyObject: (value) => assertType(is.nonEmptyObject(value), AssertionTypeDescription.nonEmptyObject, value),
416
+ emptySet: (value) => assertType(is.emptySet(value), AssertionTypeDescription.emptySet, value),
417
+ nonEmptySet: (value) => assertType(is.nonEmptySet(value), AssertionTypeDescription.nonEmptySet, value),
418
+ emptyMap: (value) => assertType(is.emptyMap(value), AssertionTypeDescription.emptyMap, value),
419
+ nonEmptyMap: (value) => assertType(is.nonEmptyMap(value), AssertionTypeDescription.nonEmptyMap, value),
420
+ propertyKey: (value) => assertType(is.propertyKey(value), 'PropertyKey', value),
421
+ formData: (value) => assertType(is.formData(value), 'FormData', value),
422
+ urlSearchParams: (value) => assertType(is.urlSearchParams(value), 'URLSearchParams', value),
423
+ // Numbers.
424
+ evenInteger: (value) => assertType(is.evenInteger(value), AssertionTypeDescription.evenInteger, value),
425
+ oddInteger: (value) => assertType(is.oddInteger(value), AssertionTypeDescription.oddInteger, value),
426
+ // Two arguments.
427
+ directInstanceOf: (instance, class_) => assertType(is.directInstanceOf(instance, class_), AssertionTypeDescription.directInstanceOf, instance),
428
+ inRange: (value, range) => assertType(is.inRange(value, range), AssertionTypeDescription.inRange, value),
429
+ // Variadic functions.
430
+ any: (predicate, ...values) => {
431
+ return assertType(is.any(predicate, ...values), AssertionTypeDescription.any, values, {
432
+ multipleValues: true,
433
+ });
434
+ },
435
+ all: (predicate, ...values) => assertType(is.all(predicate, ...values), AssertionTypeDescription.all, values, {
436
+ multipleValues: true,
437
+ }),
438
+ };
439
+ // Some few keywords are reserved, but we'll populate them for Node.js users
440
+ // See https://github.com/Microsoft/TypeScript/issues/2536
441
+ Object.defineProperties(is, {
442
+ class: {
443
+ value: is.class_,
444
+ },
445
+ function: {
446
+ value: is.function_,
447
+ },
448
+ null: {
449
+ value: is.null_,
450
+ },
451
+ });
452
+ Object.defineProperties(assert, {
453
+ class: {
454
+ value: assert.class_,
455
+ },
456
+ function: {
457
+ value: assert.function_,
458
+ },
459
+ null: {
460
+ value: assert.null_,
461
+ },
462
+ });
463
+ // export {Class, TypedArray, ObservableLike, Primitive} from './types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.42.1",
3
+ "version": "14.46.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -12,6 +12,7 @@
12
12
  },
13
13
  "devDependencies": {
14
14
  "@naturalcycles/dev-lib": "^12.0.0",
15
+ "@naturalcycles/nodejs-lib": "^12.33.4",
15
16
  "@types/benchmark": "^2.1.0",
16
17
  "@types/node": "^16.0.0",
17
18
  "benchmark": "^2.1.4",
package/src/index.ts CHANGED
@@ -68,6 +68,7 @@ import { ErrorMode } from './error/errorMode'
68
68
  import { HttpError } from './error/http.error'
69
69
  import { _try } from './error/try'
70
70
  import { TryCatchOptions, _TryCatch, _tryCatch } from './error/tryCatch'
71
+ import { generateJsonSchemaFromData } from './json-schema/from-data/generateJsonSchemaFromData'
71
72
  import { JSON_SCHEMA_ORDER } from './json-schema/jsonSchema.cnst'
72
73
  import {
73
74
  JsonSchema,
@@ -210,6 +211,7 @@ import {
210
211
  _stringMapValues,
211
212
  } from './types'
212
213
  import { _gb, _hb, _kb, _mb } from './unit/size.util'
214
+ import { is } from './vendor/is'
213
215
 
214
216
  export type {
215
217
  MemoCache,
@@ -275,6 +277,7 @@ export type {
275
277
  }
276
278
 
277
279
  export {
280
+ is,
278
281
  _Memo,
279
282
  _memoFn,
280
283
  _LogMethod,
@@ -422,4 +425,5 @@ export {
422
425
  jsonSchema,
423
426
  JsonSchemaAnyBuilder,
424
427
  JSON_SCHEMA_ORDER,
428
+ generateJsonSchemaFromData,
425
429
  }
@@ -0,0 +1,120 @@
1
+ import {
2
+ JsonSchema,
3
+ JsonSchemaArray,
4
+ JsonSchemaBoolean,
5
+ JsonSchemaNull,
6
+ JsonSchemaNumber,
7
+ JsonSchemaObject,
8
+ JsonSchemaOneOf,
9
+ JsonSchemaString,
10
+ StringMap,
11
+ _stringMapEntries,
12
+ _uniq,
13
+ } from '../..'
14
+
15
+ type PrimitiveType = 'undefined' | 'null' | 'boolean' | 'string' | 'number'
16
+ type Type = PrimitiveType | 'array' | 'object'
17
+
18
+ /**
19
+ * Each row must be an object (current limitation).
20
+ *
21
+ * `additionalProperties` is set to `true`, cause it's safer.
22
+ */
23
+ export function generateJsonSchemaFromData<T = unknown>(rows: any[]): JsonSchema<T> {
24
+ return objectToJsonSchema(rows as any) as JsonSchema<T>
25
+ }
26
+
27
+ function objectToJsonSchema(rows: Record<string, any>[]): JsonSchema {
28
+ const typesByKey: StringMap<Set<Type>> = {}
29
+
30
+ rows.forEach(r => {
31
+ Object.keys(r).forEach(key => {
32
+ typesByKey[key] ||= new Set<Type>()
33
+ typesByKey[key]!.add(getTypeOfValue(r[key]))
34
+ })
35
+ })
36
+
37
+ const s: JsonSchemaObject = {
38
+ type: 'object',
39
+ properties: {},
40
+ required: [],
41
+ additionalProperties: true,
42
+ }
43
+
44
+ _stringMapEntries(typesByKey).forEach(([key, types]) => {
45
+ const schema = mergeTypes(
46
+ [...types],
47
+ rows.map(r => r[key]),
48
+ )
49
+ if (!schema) return
50
+ s.properties[key] = schema
51
+ })
52
+
53
+ // console.log(typesByKey)
54
+
55
+ return s
56
+ }
57
+
58
+ function mergeTypes(types: Type[], samples: any[]): JsonSchema | undefined {
59
+ // skip "undefined" types
60
+ types = types.filter(t => t !== 'undefined')
61
+
62
+ if (!types.length) return undefined
63
+
64
+ if (types.length > 1) {
65
+ // oneOf
66
+ const s: JsonSchemaOneOf = {
67
+ oneOf: types.map(type => mergeTypes([type], samples)!),
68
+ }
69
+
70
+ return s
71
+ }
72
+
73
+ const type = types[0]!
74
+
75
+ if (type === 'null') {
76
+ return {
77
+ type: 'null',
78
+ } as JsonSchemaNull
79
+ }
80
+
81
+ if (type === 'boolean') {
82
+ return {
83
+ type: 'boolean',
84
+ } as JsonSchemaBoolean
85
+ }
86
+
87
+ if (type === 'string') {
88
+ return {
89
+ type: 'string',
90
+ } as JsonSchemaString
91
+ }
92
+
93
+ if (type === 'number') {
94
+ return {
95
+ type: 'number',
96
+ } as JsonSchemaNumber
97
+ }
98
+
99
+ if (type === 'object') {
100
+ return objectToJsonSchema(samples.filter((r: any) => r && typeof r === 'object'))
101
+ }
102
+
103
+ if (type === 'array') {
104
+ // possible feature: detect if it's a tuple
105
+ // currently assume no-tuple
106
+ const items = samples.filter(r => Array.isArray(r)).flat(1)
107
+ const itemTypes = _uniq(items.map(i => getTypeOfValue(i)))
108
+
109
+ return {
110
+ type: 'array',
111
+ items: mergeTypes(itemTypes, items),
112
+ } as JsonSchemaArray
113
+ }
114
+ }
115
+
116
+ function getTypeOfValue(v: any): Type {
117
+ if (v === null) return 'null'
118
+ if (Array.isArray(v)) return 'array'
119
+ return typeof v as Type
120
+ }
@@ -38,6 +38,14 @@ export interface JsonSchemaAny<T = unknown> {
38
38
  then?: JsonSchema
39
39
  else?: JsonSchema
40
40
 
41
+ /**
42
+ * https://ajv.js.org/packages/ajv-keywords.html#instanceof
43
+ *
44
+ * Useful for Node.js Buffer, you can use it like:
45
+ * `instanceof: 'Buffer'`
46
+ */
47
+ instanceof?: string | string[]
48
+
41
49
  /**
42
50
  * This is a temporary "intermediate AST" field that is used inside the parser.
43
51
  * In the final schema this field will NOT be present.