@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 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,7 @@
1
+ import { JsonSchema } 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 declare function generateJsonSchemaFromData<T = unknown>(rows: any[]): JsonSchema<T>;
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.45.0",
3
+ "version": "14.46.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
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
+ }