@naturalcycles/js-lib 14.45.0 → 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.
- package/CHANGELOG.md +7 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +7 -0
- package/dist/json-schema/from-data/generateJsonSchemaFromData.js +90 -0
- package/dist-esm/index.js +2 -1
- package/dist-esm/json-schema/from-data/generateJsonSchemaFromData.js +86 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/json-schema/from-data/generateJsonSchemaFromData.ts +120 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [14.46.0](https://github.com/NaturalCycles/js-lib/compare/v14.45.0...v14.46.0) (2021-10-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* generateJsonSchemaFromData (experimental) ([87a74e9](https://github.com/NaturalCycles/js-lib/commit/87a74e9f033d8bb43d3137855044c09c63751b2c))
|
|
7
|
+
|
|
1
8
|
# [14.45.0](https://github.com/NaturalCycles/js-lib/compare/v14.44.0...v14.45.0) (2021-10-01)
|
|
2
9
|
|
|
3
10
|
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { ErrorMode } from './error/errorMode';
|
|
|
18
18
|
import { HttpError } from './error/http.error';
|
|
19
19
|
import { _try } from './error/try';
|
|
20
20
|
import { TryCatchOptions, _TryCatch, _tryCatch } from './error/tryCatch';
|
|
21
|
+
import { generateJsonSchemaFromData } from './json-schema/from-data/generateJsonSchemaFromData';
|
|
21
22
|
import { JSON_SCHEMA_ORDER } from './json-schema/jsonSchema.cnst';
|
|
22
23
|
import { JsonSchema, JsonSchemaAllOf, JsonSchemaAny, JsonSchemaAnyOf, JsonSchemaArray, JsonSchemaBoolean, JsonSchemaConst, JsonSchemaEnum, JsonSchemaNot, JsonSchemaNull, JsonSchemaNumber, JsonSchemaObject, JsonSchemaOneOf, JsonSchemaRef, JsonSchemaString, JsonSchemaTuple } from './json-schema/jsonSchema.model';
|
|
23
24
|
import { mergeJsonSchemaObjects } from './json-schema/jsonSchema.util';
|
|
@@ -52,4 +53,4 @@ import { AsyncMapper, AsyncPredicate, BaseDBEntity, BatchResult, InstanceId, Iso
|
|
|
52
53
|
import { _gb, _hb, _kb, _mb } from './unit/size.util';
|
|
53
54
|
import { is } from './vendor/is';
|
|
54
55
|
export type { MemoCache, PromiseDecoratorCfg, PromiseDecoratorResp, ErrorData, ErrorObject, HttpErrorData, HttpErrorResponse, Admin401ErrorData, Admin403ErrorData, StringMap, PromiseMap, ValuesOf, ValueOf, KeyValueTuple, ObjectMapper, ObjectPredicate, InstanceId, IsoDate, IsoDateTime, Reviver, PMapOptions, Mapper, AsyncMapper, Predicate, AsyncPredicate, BatchResult, DeferredPromise, PRetryOptions, PTimeoutOptions, TryCatchOptions, StringifyAnyOptions, JsonStringifyFunction, Merge, ReadonlyDeep, Promisable, PromiseValue, Simplify, ConditionalPick, ConditionalExcept, Class, UnixTimestamp, BaseDBEntity, SavedDBEntity, JsonSchema, JsonSchemaAny, JsonSchemaOneOf, JsonSchemaAllOf, JsonSchemaAnyOf, JsonSchemaNot, JsonSchemaRef, JsonSchemaConst, JsonSchemaEnum, JsonSchemaString, JsonSchemaNumber, JsonSchemaBoolean, JsonSchemaNull, JsonSchemaObject, JsonSchemaArray, JsonSchemaTuple, JsonSchemaBuilder, };
|
|
55
|
-
export { is, _Memo, _memoFn, _LogMethod, _getArgsSignature, _createPromiseDecorator, AppError, HttpError, AssertionError, _isErrorObject, _isHttpErrorObject, _isHttpErrorResponse, _assert, _assertEquals, _assertDeepEquals, _assertIsError, _assertIsString, _assertIsNumber, _assertTypeOf, _randomInt, _createDeterministicRandom, _inRange, _stringMapValues, _stringMapEntries, _objectKeys, _capitalize, _upperFirst, _lowerFirst, _split, _removeWhitespace, _substringBefore, _substringBeforeLast, _substringAfter, _substringAfterLast, _substringBetweenLast, _replaceAll, _nl2br, _truncate, _truncateMiddle, _pick, _omit, _filterFalsyValues, _filterUndefinedValues, _filterNullishValues, _filterEmptyArrays, _filterEmptyValues, _filterObject, _undefinedIfEmpty, _isObject, _isPrimitive, _mapKeys, _mapValues, _mapObject, _objectNullValuesToUndefined, _deepEquals, _deepCopy, _isEmptyObject, _isEmpty, _merge, _deepTrim, _sortObjectDeep, _sortObject, _get, _set, _has, _unset, _mask, _invert, _invertMap, _by, _groupBy, _sortBy, _sortNumbers, _toFixed, _toPrecision, _round, _findLast, _takeWhile, _takeRightWhile, _dropWhile, _dropRightWhile, _countBy, _intersection, _difference, _shuffle, _mapToObject, _findKeyByValue, _anyToError, _anyToErrorObject, _errorToErrorObject, _errorObjectToAppError, _range, _uniq, _uniqBy, _flatten, _flattenDeep, _chunk, SimpleMovingAverage, _average, _averageWeighted, _percentile, _median, _debounce, _throttle, _Debounce, _Throttle, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, pBatch, ErrorMode, pFilter, pProps, pDelay, pDefer, pHang, pState, AggregatedError, pRetry, pTimeout, pTuple, _Retry, _Timeout, _tryCatch, _TryCatch, _try, _jsonParseIfPossible, _stringifyAny, _ms, _since, _hb, _gb, _mb, _kb, _snakeCase, _camelCase, _kebabCase, _sum, _sumBy, _clamp, _last, mergeJsonSchemaObjects, jsonSchema, JsonSchemaAnyBuilder, JSON_SCHEMA_ORDER, };
|
|
56
|
+
export { is, _Memo, _memoFn, _LogMethod, _getArgsSignature, _createPromiseDecorator, AppError, HttpError, AssertionError, _isErrorObject, _isHttpErrorObject, _isHttpErrorResponse, _assert, _assertEquals, _assertDeepEquals, _assertIsError, _assertIsString, _assertIsNumber, _assertTypeOf, _randomInt, _createDeterministicRandom, _inRange, _stringMapValues, _stringMapEntries, _objectKeys, _capitalize, _upperFirst, _lowerFirst, _split, _removeWhitespace, _substringBefore, _substringBeforeLast, _substringAfter, _substringAfterLast, _substringBetweenLast, _replaceAll, _nl2br, _truncate, _truncateMiddle, _pick, _omit, _filterFalsyValues, _filterUndefinedValues, _filterNullishValues, _filterEmptyArrays, _filterEmptyValues, _filterObject, _undefinedIfEmpty, _isObject, _isPrimitive, _mapKeys, _mapValues, _mapObject, _objectNullValuesToUndefined, _deepEquals, _deepCopy, _isEmptyObject, _isEmpty, _merge, _deepTrim, _sortObjectDeep, _sortObject, _get, _set, _has, _unset, _mask, _invert, _invertMap, _by, _groupBy, _sortBy, _sortNumbers, _toFixed, _toPrecision, _round, _findLast, _takeWhile, _takeRightWhile, _dropWhile, _dropRightWhile, _countBy, _intersection, _difference, _shuffle, _mapToObject, _findKeyByValue, _anyToError, _anyToErrorObject, _errorToErrorObject, _errorObjectToAppError, _range, _uniq, _uniqBy, _flatten, _flattenDeep, _chunk, SimpleMovingAverage, _average, _averageWeighted, _percentile, _median, _debounce, _throttle, _Debounce, _Throttle, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, pBatch, ErrorMode, pFilter, pProps, pDelay, pDefer, pHang, pState, AggregatedError, pRetry, pTimeout, pTuple, _Retry, _Timeout, _tryCatch, _TryCatch, _try, _jsonParseIfPossible, _stringifyAny, _ms, _since, _hb, _gb, _mb, _kb, _snakeCase, _camelCase, _kebabCase, _sum, _sumBy, _clamp, _last, mergeJsonSchemaObjects, jsonSchema, JsonSchemaAnyBuilder, JSON_SCHEMA_ORDER, generateJsonSchemaFromData, };
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports._isPrimitive = exports._isObject = exports._undefinedIfEmpty = exports._filterObject = exports._filterEmptyValues = exports._filterEmptyArrays = exports._filterNullishValues = exports._filterUndefinedValues = exports._filterFalsyValues = exports._omit = exports._pick = exports._truncateMiddle = exports._truncate = exports._nl2br = exports._replaceAll = exports._substringBetweenLast = exports._substringAfterLast = exports._substringAfter = exports._substringBeforeLast = exports._substringBefore = exports._removeWhitespace = exports._split = exports._lowerFirst = exports._upperFirst = exports._capitalize = exports._objectKeys = exports._stringMapEntries = exports._stringMapValues = exports._inRange = exports._createDeterministicRandom = exports._randomInt = exports._assertTypeOf = exports._assertIsNumber = exports._assertIsString = exports._assertIsError = exports._assertDeepEquals = exports._assertEquals = exports._assert = exports._isHttpErrorResponse = exports._isHttpErrorObject = exports._isErrorObject = exports.AssertionError = exports.HttpError = exports.AppError = exports._createPromiseDecorator = exports._getArgsSignature = exports._LogMethod = exports._memoFn = exports._Memo = exports.is = void 0;
|
|
4
4
|
exports._averageWeighted = exports._average = exports.SimpleMovingAverage = exports._chunk = exports._flattenDeep = exports._flatten = exports._uniqBy = exports._uniq = exports._range = exports._errorObjectToAppError = exports._errorToErrorObject = exports._anyToErrorObject = exports._anyToError = exports._findKeyByValue = exports._mapToObject = exports._shuffle = exports._difference = exports._intersection = exports._countBy = exports._dropRightWhile = exports._dropWhile = exports._takeRightWhile = exports._takeWhile = exports._findLast = exports._round = exports._toPrecision = exports._toFixed = exports._sortNumbers = exports._sortBy = exports._groupBy = exports._by = exports._invertMap = exports._invert = exports._mask = exports._unset = exports._has = exports._set = exports._get = exports._sortObject = exports._sortObjectDeep = exports._deepTrim = exports._merge = exports._isEmpty = exports._isEmptyObject = exports._deepCopy = exports._deepEquals = exports._objectNullValuesToUndefined = exports._mapObject = exports._mapValues = exports._mapKeys = void 0;
|
|
5
|
-
exports.JSON_SCHEMA_ORDER = exports.JsonSchemaAnyBuilder = exports.jsonSchema = exports.mergeJsonSchemaObjects = exports._last = exports._clamp = exports._sumBy = exports._sum = exports._kebabCase = exports._camelCase = exports._snakeCase = exports._kb = exports._mb = exports._gb = exports._hb = exports._since = exports._ms = exports._stringifyAny = exports._jsonParseIfPossible = exports._try = exports._TryCatch = exports._tryCatch = exports._Timeout = exports._Retry = exports.pTuple = exports.pTimeout = exports.pRetry = exports.AggregatedError = exports.pState = exports.pHang = exports.pDefer = exports.pDelay = exports.pProps = exports.pFilter = exports.ErrorMode = exports.pBatch = exports._noop = exports._passNothingPredicate = exports._passthroughPredicate = exports._passUndefinedMapper = exports._passthroughMapper = exports.pMap = exports._Throttle = exports._Debounce = exports._throttle = exports._debounce = exports._median = exports._percentile = void 0;
|
|
5
|
+
exports.generateJsonSchemaFromData = exports.JSON_SCHEMA_ORDER = exports.JsonSchemaAnyBuilder = exports.jsonSchema = exports.mergeJsonSchemaObjects = exports._last = exports._clamp = exports._sumBy = exports._sum = exports._kebabCase = exports._camelCase = exports._snakeCase = exports._kb = exports._mb = exports._gb = exports._hb = exports._since = exports._ms = exports._stringifyAny = exports._jsonParseIfPossible = exports._try = exports._TryCatch = exports._tryCatch = exports._Timeout = exports._Retry = exports.pTuple = exports.pTimeout = exports.pRetry = exports.AggregatedError = exports.pState = exports.pHang = exports.pDefer = exports.pDelay = exports.pProps = exports.pFilter = exports.ErrorMode = exports.pBatch = exports._noop = exports._passNothingPredicate = exports._passthroughPredicate = exports._passUndefinedMapper = exports._passthroughMapper = exports.pMap = exports._Throttle = exports._Debounce = exports._throttle = exports._debounce = exports._median = exports._percentile = void 0;
|
|
6
6
|
const array_util_1 = require("./array/array.util");
|
|
7
7
|
Object.defineProperty(exports, "_by", { enumerable: true, get: function () { return array_util_1._by; } });
|
|
8
8
|
Object.defineProperty(exports, "_chunk", { enumerable: true, get: function () { return array_util_1._chunk; } });
|
|
@@ -75,6 +75,8 @@ Object.defineProperty(exports, "_try", { enumerable: true, get: function () { re
|
|
|
75
75
|
const tryCatch_1 = require("./error/tryCatch");
|
|
76
76
|
Object.defineProperty(exports, "_TryCatch", { enumerable: true, get: function () { return tryCatch_1._TryCatch; } });
|
|
77
77
|
Object.defineProperty(exports, "_tryCatch", { enumerable: true, get: function () { return tryCatch_1._tryCatch; } });
|
|
78
|
+
const generateJsonSchemaFromData_1 = require("./json-schema/from-data/generateJsonSchemaFromData");
|
|
79
|
+
Object.defineProperty(exports, "generateJsonSchemaFromData", { enumerable: true, get: function () { return generateJsonSchemaFromData_1.generateJsonSchemaFromData; } });
|
|
78
80
|
const jsonSchema_cnst_1 = require("./json-schema/jsonSchema.cnst");
|
|
79
81
|
Object.defineProperty(exports, "JSON_SCHEMA_ORDER", { enumerable: true, get: function () { return jsonSchema_cnst_1.JSON_SCHEMA_ORDER; } });
|
|
80
82
|
const jsonSchema_util_1 = require("./json-schema/jsonSchema.util");
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateJsonSchemaFromData = void 0;
|
|
4
|
+
const __1 = require("../..");
|
|
5
|
+
/**
|
|
6
|
+
* Each row must be an object (current limitation).
|
|
7
|
+
*
|
|
8
|
+
* `additionalProperties` is set to `true`, cause it's safer.
|
|
9
|
+
*/
|
|
10
|
+
function generateJsonSchemaFromData(rows) {
|
|
11
|
+
return objectToJsonSchema(rows);
|
|
12
|
+
}
|
|
13
|
+
exports.generateJsonSchemaFromData = generateJsonSchemaFromData;
|
|
14
|
+
function objectToJsonSchema(rows) {
|
|
15
|
+
const typesByKey = {};
|
|
16
|
+
rows.forEach(r => {
|
|
17
|
+
Object.keys(r).forEach(key => {
|
|
18
|
+
typesByKey[key] || (typesByKey[key] = new Set());
|
|
19
|
+
typesByKey[key].add(getTypeOfValue(r[key]));
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
const s = {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {},
|
|
25
|
+
required: [],
|
|
26
|
+
additionalProperties: true,
|
|
27
|
+
};
|
|
28
|
+
(0, __1._stringMapEntries)(typesByKey).forEach(([key, types]) => {
|
|
29
|
+
const schema = mergeTypes([...types], rows.map(r => r[key]));
|
|
30
|
+
if (!schema)
|
|
31
|
+
return;
|
|
32
|
+
s.properties[key] = schema;
|
|
33
|
+
});
|
|
34
|
+
// console.log(typesByKey)
|
|
35
|
+
return s;
|
|
36
|
+
}
|
|
37
|
+
function mergeTypes(types, samples) {
|
|
38
|
+
// skip "undefined" types
|
|
39
|
+
types = types.filter(t => t !== 'undefined');
|
|
40
|
+
if (!types.length)
|
|
41
|
+
return undefined;
|
|
42
|
+
if (types.length > 1) {
|
|
43
|
+
// oneOf
|
|
44
|
+
const s = {
|
|
45
|
+
oneOf: types.map(type => mergeTypes([type], samples)),
|
|
46
|
+
};
|
|
47
|
+
return s;
|
|
48
|
+
}
|
|
49
|
+
const type = types[0];
|
|
50
|
+
if (type === 'null') {
|
|
51
|
+
return {
|
|
52
|
+
type: 'null',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
if (type === 'boolean') {
|
|
56
|
+
return {
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (type === 'string') {
|
|
61
|
+
return {
|
|
62
|
+
type: 'string',
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (type === 'number') {
|
|
66
|
+
return {
|
|
67
|
+
type: 'number',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
if (type === 'object') {
|
|
71
|
+
return objectToJsonSchema(samples.filter((r) => r && typeof r === 'object'));
|
|
72
|
+
}
|
|
73
|
+
if (type === 'array') {
|
|
74
|
+
// possible feature: detect if it's a tuple
|
|
75
|
+
// currently assume no-tuple
|
|
76
|
+
const items = samples.filter(r => Array.isArray(r)).flat(1);
|
|
77
|
+
const itemTypes = (0, __1._uniq)(items.map(i => getTypeOfValue(i)));
|
|
78
|
+
return {
|
|
79
|
+
type: 'array',
|
|
80
|
+
items: mergeTypes(itemTypes, items),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function getTypeOfValue(v) {
|
|
85
|
+
if (v === null)
|
|
86
|
+
return 'null';
|
|
87
|
+
if (Array.isArray(v))
|
|
88
|
+
return 'array';
|
|
89
|
+
return typeof v;
|
|
90
|
+
}
|
package/dist-esm/index.js
CHANGED
|
@@ -16,6 +16,7 @@ import { ErrorMode } from './error/errorMode';
|
|
|
16
16
|
import { HttpError } from './error/http.error';
|
|
17
17
|
import { _try } from './error/try';
|
|
18
18
|
import { _TryCatch, _tryCatch } from './error/tryCatch';
|
|
19
|
+
import { generateJsonSchemaFromData } from './json-schema/from-data/generateJsonSchemaFromData';
|
|
19
20
|
import { JSON_SCHEMA_ORDER } from './json-schema/jsonSchema.cnst';
|
|
20
21
|
import { mergeJsonSchemaObjects } from './json-schema/jsonSchema.util';
|
|
21
22
|
import { jsonSchema, JsonSchemaAnyBuilder, } from './json-schema/jsonSchemaBuilder';
|
|
@@ -47,4 +48,4 @@ import { _ms, _since } from './time/time.util';
|
|
|
47
48
|
import { _noop, _objectKeys, _passNothingPredicate, _passthroughMapper, _passthroughPredicate, _passUndefinedMapper, _stringMapEntries, _stringMapValues, } from './types';
|
|
48
49
|
import { _gb, _hb, _kb, _mb } from './unit/size.util';
|
|
49
50
|
import { is } from './vendor/is';
|
|
50
|
-
export { is, _Memo, _memoFn, _LogMethod, _getArgsSignature, _createPromiseDecorator, AppError, HttpError, AssertionError, _isErrorObject, _isHttpErrorObject, _isHttpErrorResponse, _assert, _assertEquals, _assertDeepEquals, _assertIsError, _assertIsString, _assertIsNumber, _assertTypeOf, _randomInt, _createDeterministicRandom, _inRange, _stringMapValues, _stringMapEntries, _objectKeys, _capitalize, _upperFirst, _lowerFirst, _split, _removeWhitespace, _substringBefore, _substringBeforeLast, _substringAfter, _substringAfterLast, _substringBetweenLast, _replaceAll, _nl2br, _truncate, _truncateMiddle, _pick, _omit, _filterFalsyValues, _filterUndefinedValues, _filterNullishValues, _filterEmptyArrays, _filterEmptyValues, _filterObject, _undefinedIfEmpty, _isObject, _isPrimitive, _mapKeys, _mapValues, _mapObject, _objectNullValuesToUndefined, _deepEquals, _deepCopy, _isEmptyObject, _isEmpty, _merge, _deepTrim, _sortObjectDeep, _sortObject, _get, _set, _has, _unset, _mask, _invert, _invertMap, _by, _groupBy, _sortBy, _sortNumbers, _toFixed, _toPrecision, _round, _findLast, _takeWhile, _takeRightWhile, _dropWhile, _dropRightWhile, _countBy, _intersection, _difference, _shuffle, _mapToObject, _findKeyByValue, _anyToError, _anyToErrorObject, _errorToErrorObject, _errorObjectToAppError, _range, _uniq, _uniqBy, _flatten, _flattenDeep, _chunk, SimpleMovingAverage, _average, _averageWeighted, _percentile, _median, _debounce, _throttle, _Debounce, _Throttle, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, pBatch, ErrorMode, pFilter, pProps, pDelay, pDefer, pHang, pState, AggregatedError, pRetry, pTimeout, pTuple, _Retry, _Timeout, _tryCatch, _TryCatch, _try, _jsonParseIfPossible, _stringifyAny, _ms, _since, _hb, _gb, _mb, _kb, _snakeCase, _camelCase, _kebabCase, _sum, _sumBy, _clamp, _last, mergeJsonSchemaObjects, jsonSchema, JsonSchemaAnyBuilder, JSON_SCHEMA_ORDER, };
|
|
51
|
+
export { is, _Memo, _memoFn, _LogMethod, _getArgsSignature, _createPromiseDecorator, AppError, HttpError, AssertionError, _isErrorObject, _isHttpErrorObject, _isHttpErrorResponse, _assert, _assertEquals, _assertDeepEquals, _assertIsError, _assertIsString, _assertIsNumber, _assertTypeOf, _randomInt, _createDeterministicRandom, _inRange, _stringMapValues, _stringMapEntries, _objectKeys, _capitalize, _upperFirst, _lowerFirst, _split, _removeWhitespace, _substringBefore, _substringBeforeLast, _substringAfter, _substringAfterLast, _substringBetweenLast, _replaceAll, _nl2br, _truncate, _truncateMiddle, _pick, _omit, _filterFalsyValues, _filterUndefinedValues, _filterNullishValues, _filterEmptyArrays, _filterEmptyValues, _filterObject, _undefinedIfEmpty, _isObject, _isPrimitive, _mapKeys, _mapValues, _mapObject, _objectNullValuesToUndefined, _deepEquals, _deepCopy, _isEmptyObject, _isEmpty, _merge, _deepTrim, _sortObjectDeep, _sortObject, _get, _set, _has, _unset, _mask, _invert, _invertMap, _by, _groupBy, _sortBy, _sortNumbers, _toFixed, _toPrecision, _round, _findLast, _takeWhile, _takeRightWhile, _dropWhile, _dropRightWhile, _countBy, _intersection, _difference, _shuffle, _mapToObject, _findKeyByValue, _anyToError, _anyToErrorObject, _errorToErrorObject, _errorObjectToAppError, _range, _uniq, _uniqBy, _flatten, _flattenDeep, _chunk, SimpleMovingAverage, _average, _averageWeighted, _percentile, _median, _debounce, _throttle, _Debounce, _Throttle, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, pBatch, ErrorMode, pFilter, pProps, pDelay, pDefer, pHang, pState, AggregatedError, pRetry, pTimeout, pTuple, _Retry, _Timeout, _tryCatch, _TryCatch, _try, _jsonParseIfPossible, _stringifyAny, _ms, _since, _hb, _gb, _mb, _kb, _snakeCase, _camelCase, _kebabCase, _sum, _sumBy, _clamp, _last, mergeJsonSchemaObjects, jsonSchema, JsonSchemaAnyBuilder, JSON_SCHEMA_ORDER, generateJsonSchemaFromData, };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { _stringMapEntries, _uniq, } from '../..';
|
|
2
|
+
/**
|
|
3
|
+
* Each row must be an object (current limitation).
|
|
4
|
+
*
|
|
5
|
+
* `additionalProperties` is set to `true`, cause it's safer.
|
|
6
|
+
*/
|
|
7
|
+
export function generateJsonSchemaFromData(rows) {
|
|
8
|
+
return objectToJsonSchema(rows);
|
|
9
|
+
}
|
|
10
|
+
function objectToJsonSchema(rows) {
|
|
11
|
+
const typesByKey = {};
|
|
12
|
+
rows.forEach(r => {
|
|
13
|
+
Object.keys(r).forEach(key => {
|
|
14
|
+
typesByKey[key] || (typesByKey[key] = new Set());
|
|
15
|
+
typesByKey[key].add(getTypeOfValue(r[key]));
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
const s = {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {},
|
|
21
|
+
required: [],
|
|
22
|
+
additionalProperties: true,
|
|
23
|
+
};
|
|
24
|
+
_stringMapEntries(typesByKey).forEach(([key, types]) => {
|
|
25
|
+
const schema = mergeTypes([...types], rows.map(r => r[key]));
|
|
26
|
+
if (!schema)
|
|
27
|
+
return;
|
|
28
|
+
s.properties[key] = schema;
|
|
29
|
+
});
|
|
30
|
+
// console.log(typesByKey)
|
|
31
|
+
return s;
|
|
32
|
+
}
|
|
33
|
+
function mergeTypes(types, samples) {
|
|
34
|
+
// skip "undefined" types
|
|
35
|
+
types = types.filter(t => t !== 'undefined');
|
|
36
|
+
if (!types.length)
|
|
37
|
+
return undefined;
|
|
38
|
+
if (types.length > 1) {
|
|
39
|
+
// oneOf
|
|
40
|
+
const s = {
|
|
41
|
+
oneOf: types.map(type => mergeTypes([type], samples)),
|
|
42
|
+
};
|
|
43
|
+
return s;
|
|
44
|
+
}
|
|
45
|
+
const type = types[0];
|
|
46
|
+
if (type === 'null') {
|
|
47
|
+
return {
|
|
48
|
+
type: 'null',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (type === 'boolean') {
|
|
52
|
+
return {
|
|
53
|
+
type: 'boolean',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (type === 'string') {
|
|
57
|
+
return {
|
|
58
|
+
type: 'string',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (type === 'number') {
|
|
62
|
+
return {
|
|
63
|
+
type: 'number',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (type === 'object') {
|
|
67
|
+
return objectToJsonSchema(samples.filter((r) => r && typeof r === 'object'));
|
|
68
|
+
}
|
|
69
|
+
if (type === 'array') {
|
|
70
|
+
// possible feature: detect if it's a tuple
|
|
71
|
+
// currently assume no-tuple
|
|
72
|
+
const items = samples.filter(r => Array.isArray(r)).flat(1);
|
|
73
|
+
const itemTypes = _uniq(items.map(i => getTypeOfValue(i)));
|
|
74
|
+
return {
|
|
75
|
+
type: 'array',
|
|
76
|
+
items: mergeTypes(itemTypes, items),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function getTypeOfValue(v) {
|
|
81
|
+
if (v === null)
|
|
82
|
+
return 'null';
|
|
83
|
+
if (Array.isArray(v))
|
|
84
|
+
return 'array';
|
|
85
|
+
return typeof v;
|
|
86
|
+
}
|
package/package.json
CHANGED
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,
|
|
@@ -424,4 +425,5 @@ export {
|
|
|
424
425
|
jsonSchema,
|
|
425
426
|
JsonSchemaAnyBuilder,
|
|
426
427
|
JSON_SCHEMA_ORDER,
|
|
428
|
+
generateJsonSchemaFromData,
|
|
427
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
|
+
}
|