@rebasepro/schema-inference 0.5.0 → 0.6.1

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/dist/index.es.js CHANGED
@@ -1,525 +1,422 @@
1
- import { unslugify, mergeDeep, prettifyIdentifier } from "@rebasepro/utils";
2
- import { isObject, isPlainObject, mergeDeep as mergeDeep2, prettifyIdentifier as prettifyIdentifier2, unslugify as unslugify2 } from "@rebasepro/utils";
1
+ import { isObject, isPlainObject, mergeDeep, prettifyIdentifier, unslugify, unslugify as unslugify$1 } from "@rebasepro/utils";
3
2
  import { Vector } from "@rebasepro/types";
3
+ //#region src/strings.ts
4
+ /**
5
+ * Parse a reference string value which can be in the format:
6
+ * - Simple: "path/entityId"
7
+ * - With database: "database_name:::path/entityId"
8
+ * Returns the path and database (undefined if not specified or if "(default)")
9
+ */
4
10
  function parseReferenceString(value) {
5
- if (!value) return null;
6
- let database = void 0;
7
- let fullPath = value;
8
- if (value.includes(":::")) {
9
- const [dbName, pathPart] = value.split(":::");
10
- if (dbName && dbName !== "(default)") {
11
- database = dbName;
12
- }
13
- fullPath = pathPart;
14
- }
15
- if (!fullPath || !fullPath.includes("/")) {
16
- return null;
17
- }
18
- const path = fullPath.substring(0, fullPath.lastIndexOf("/"));
19
- return {
20
- path,
21
- database
22
- };
11
+ if (!value) return null;
12
+ let database = void 0;
13
+ let fullPath = value;
14
+ if (value.includes(":::")) {
15
+ const [dbName, pathPart] = value.split(":::");
16
+ if (dbName && dbName !== "(default)") database = dbName;
17
+ fullPath = pathPart;
18
+ }
19
+ if (!fullPath || !fullPath.includes("/")) return null;
20
+ return {
21
+ path: fullPath.substring(0, fullPath.lastIndexOf("/")),
22
+ database
23
+ };
23
24
  }
25
+ /**
26
+ * Check if a string value looks like a reference
27
+ */
24
28
  function looksLikeReference(value) {
25
- if (typeof value !== "string") return false;
26
- return parseReferenceString(value) !== null;
29
+ if (typeof value !== "string") return false;
30
+ return parseReferenceString(value) !== null;
27
31
  }
28
32
  function findCommonInitialStringInPath(valuesCount) {
29
- if (!valuesCount) return void 0;
30
- function getPath(value) {
31
- let pathString;
32
- if (typeof value === "string") {
33
- pathString = value;
34
- } else if (value && typeof value === "object" && "slug" in value && typeof value.slug === "string") {
35
- pathString = value.slug;
36
- } else {
37
- console.warn("findCommonInitialStringInPath: value is not a string or document with path", value);
38
- return void 0;
39
- }
40
- if (!pathString) return void 0;
41
- if (pathString.includes(":::")) {
42
- const [, pathPart] = pathString.split(":::");
43
- pathString = pathPart;
44
- }
45
- return pathString;
46
- }
47
- const strings = valuesCount.values.map((v) => getPath(v)).filter((v) => !!v);
48
- const pathWithSlash = strings.find((s) => s.includes("/"));
49
- if (!pathWithSlash)
50
- return void 0;
51
- const searchedPath = pathWithSlash.substring(0, pathWithSlash.lastIndexOf("/"));
52
- const yep = valuesCount.values.filter((value) => {
53
- const path = getPath(value);
54
- if (!path) return false;
55
- return path.startsWith(searchedPath);
56
- }).length > valuesCount.values.length / 3 * 2;
57
- return yep ? searchedPath : void 0;
33
+ if (!valuesCount) return void 0;
34
+ function getPath(value) {
35
+ let pathString;
36
+ if (typeof value === "string") pathString = value;
37
+ else if (value && typeof value === "object" && "slug" in value && typeof value.slug === "string") pathString = value.slug;
38
+ else {
39
+ console.warn("findCommonInitialStringInPath: value is not a string or document with path", value);
40
+ return;
41
+ }
42
+ if (!pathString) return void 0;
43
+ if (pathString.includes(":::")) {
44
+ const [, pathPart] = pathString.split(":::");
45
+ pathString = pathPart;
46
+ }
47
+ return pathString;
48
+ }
49
+ const pathWithSlash = valuesCount.values.map((v) => getPath(v)).filter((v) => !!v).find((s) => s.includes("/"));
50
+ if (!pathWithSlash) return void 0;
51
+ const searchedPath = pathWithSlash.substring(0, pathWithSlash.lastIndexOf("/"));
52
+ return valuesCount.values.filter((value) => {
53
+ const path = getPath(value);
54
+ if (!path) return false;
55
+ return path.startsWith(searchedPath);
56
+ }).length > valuesCount.values.length / 3 * 2 ? searchedPath : void 0;
58
57
  }
59
58
  function removeInitialAndTrailingSlashes(s) {
60
- return removeInitialSlash(removeTrailingSlash(s));
59
+ return removeInitialSlash(removeTrailingSlash(s));
61
60
  }
62
61
  function removeInitialSlash(s) {
63
- if (s.startsWith("/"))
64
- return s.slice(1);
65
- else return s;
62
+ if (s.startsWith("/")) return s.slice(1);
63
+ else return s;
66
64
  }
67
65
  function removeTrailingSlash(s) {
68
- if (s.endsWith("/"))
69
- return s.slice(0, -1);
70
- else return s;
66
+ if (s.endsWith("/")) return s.slice(0, -1);
67
+ else return s;
71
68
  }
69
+ //#endregion
70
+ //#region src/util.ts
71
+ /**
72
+ * Extract enum values from a list of sample values.
73
+ * This is schema-inference-specific logic (not a general utility).
74
+ */
72
75
  function extractEnumFromValues(values) {
73
- if (!Array.isArray(values)) {
74
- return [];
75
- }
76
- const enumValues = values.map((value) => {
77
- if (typeof value === "string") {
78
- return {
79
- id: value,
80
- label: unslugify(value)
81
- };
82
- } else
83
- return null;
84
- }).filter(Boolean);
85
- enumValues.sort((a, b) => a.label.localeCompare(b.label));
86
- return enumValues;
76
+ if (!Array.isArray(values)) return [];
77
+ const enumValues = values.map((value) => {
78
+ if (typeof value === "string") return {
79
+ id: value,
80
+ label: unslugify$1(value)
81
+ };
82
+ else return null;
83
+ }).filter(Boolean);
84
+ enumValues.sort((a, b) => a.label.localeCompare(b.label));
85
+ return enumValues;
87
86
  }
88
87
  function resolveEnumValues(input) {
89
- if (Array.isArray(input)) {
90
- return input;
91
- } else if (typeof input === "object" && input !== null) {
92
- return Object.entries(input).map(([id, value]) => typeof value === "string" ? {
93
- id,
94
- label: value
95
- } : value);
96
- } else {
97
- return void 0;
98
- }
88
+ if (Array.isArray(input)) return input;
89
+ else if (typeof input === "object" && input !== null) return Object.entries(input).map(([id, value]) => typeof value === "string" ? {
90
+ id,
91
+ label: value
92
+ } : value);
93
+ else return;
99
94
  }
100
- const IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".webp", ".gif", ".avif"];
101
- const AUDIO_EXTENSIONS = [".mp3", ".ogg", ".opus", ".aac"];
102
- const VIDEO_EXTENSIONS = [".avi", ".mp4"];
103
- const emailRegEx = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
104
- function buildStringProperty({
105
- name,
106
- totalDocsCount,
107
- valuesResult
108
- }) {
109
- let stringProperty = {
110
- name: name ?? "",
111
- type: "string"
112
- };
113
- if (valuesResult) {
114
- const totalEntriesCount = valuesResult.values.length;
115
- const totalValues = Array.from(valuesResult.valuesCount.keys()).length;
116
- const config = {};
117
- const probablyAURL = valuesResult.values.filter((value) => typeof value === "string" && value.toString().startsWith("http")).length > totalDocsCount / 3 * 2;
118
- if (probablyAURL) {
119
- config.ui = { url: true };
120
- }
121
- const probablyAnEmail = valuesResult.values.filter((value) => typeof value === "string" && emailRegEx.test(value)).length > totalDocsCount / 3 * 2;
122
- if (probablyAnEmail) {
123
- config.email = true;
124
- }
125
- const probablyUserIds = valuesResult.values.filter((value) => typeof value === "string" && value.length === 28 && !value.includes(" ")).length > totalDocsCount / 3 * 2;
126
- if (probablyUserIds)
127
- config.ui = { ...config.ui, readOnly: true };
128
- if (!probablyAnEmail && !probablyAURL && !probablyUserIds && !probablyAURL && totalValues < totalEntriesCount / 3) {
129
- const enumValues = extractEnumFromValues(Array.from(valuesResult.valuesCount.keys()));
130
- if (Object.keys(enumValues).length > 1)
131
- config.enum = enumValues;
132
- }
133
- if (!probablyAnEmail && !probablyAURL && !probablyUserIds && !probablyAURL && !config.enum) {
134
- const fileType = probableFileType(valuesResult, totalDocsCount);
135
- if (fileType) {
136
- config.storage = {
137
- acceptedFiles: fileType,
138
- storagePath: findCommonInitialStringInPath(valuesResult) ?? "/"
139
- };
140
- }
141
- }
142
- if (Object.keys(config).length > 0)
143
- stringProperty = {
144
- ...stringProperty,
145
- ...config
146
- };
147
- }
148
- return stringProperty;
95
+ //#endregion
96
+ //#region src/builders/string_property_builder.ts
97
+ var IMAGE_EXTENSIONS = [
98
+ ".jpg",
99
+ ".jpeg",
100
+ ".png",
101
+ ".webp",
102
+ ".gif",
103
+ ".avif"
104
+ ];
105
+ var AUDIO_EXTENSIONS = [
106
+ ".mp3",
107
+ ".ogg",
108
+ ".opus",
109
+ ".aac"
110
+ ];
111
+ var VIDEO_EXTENSIONS = [".avi", ".mp4"];
112
+ var emailRegEx = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
113
+ function buildStringProperty({ name, totalDocsCount, valuesResult }) {
114
+ let stringProperty = {
115
+ name: name ?? "",
116
+ type: "string"
117
+ };
118
+ if (valuesResult) {
119
+ const totalEntriesCount = valuesResult.values.length;
120
+ const totalValues = Array.from(valuesResult.valuesCount.keys()).length;
121
+ const config = {};
122
+ const probablyAURL = valuesResult.values.filter((value) => typeof value === "string" && value.toString().startsWith("http")).length > totalDocsCount / 3 * 2;
123
+ if (probablyAURL) config.ui = { url: true };
124
+ const probablyAnEmail = valuesResult.values.filter((value) => typeof value === "string" && emailRegEx.test(value)).length > totalDocsCount / 3 * 2;
125
+ if (probablyAnEmail) config.email = true;
126
+ const probablyUserIds = valuesResult.values.filter((value) => typeof value === "string" && value.length === 28 && !value.includes(" ")).length > totalDocsCount / 3 * 2;
127
+ if (probablyUserIds) config.ui = {
128
+ ...config.ui,
129
+ readOnly: true
130
+ };
131
+ if (!probablyAnEmail && !probablyAURL && !probablyUserIds && !probablyAURL && totalValues < totalEntriesCount / 3) {
132
+ const enumValues = extractEnumFromValues(Array.from(valuesResult.valuesCount.keys()));
133
+ if (Object.keys(enumValues).length > 1) config.enum = enumValues;
134
+ }
135
+ if (!probablyAnEmail && !probablyAURL && !probablyUserIds && !probablyAURL && !config.enum) {
136
+ const fileType = probableFileType(valuesResult, totalDocsCount);
137
+ if (fileType) config.storage = {
138
+ acceptedFiles: fileType,
139
+ storagePath: findCommonInitialStringInPath(valuesResult) ?? "/"
140
+ };
141
+ }
142
+ if (Object.keys(config).length > 0) stringProperty = {
143
+ ...stringProperty,
144
+ ...config
145
+ };
146
+ }
147
+ return stringProperty;
149
148
  }
150
149
  function probableFileType(valuesCount, totalDocsCount) {
151
- const isImage = (value) => IMAGE_EXTENSIONS.some((extension) => value.toString().endsWith(extension));
152
- const isAudio = (value) => AUDIO_EXTENSIONS.some((extension) => value.toString().endsWith(extension));
153
- const isVideo = (value) => VIDEO_EXTENSIONS.some((extension) => value.toString().endsWith(extension));
154
- const stringValues = valuesCount.values.filter((v) => typeof v === "string");
155
- let imageCount = 0;
156
- let audioCount = 0;
157
- let videoCount = 0;
158
- for (const value of stringValues) {
159
- if (isImage(value)) imageCount++;
160
- else if (isAudio(value)) audioCount++;
161
- else if (isVideo(value)) videoCount++;
162
- }
163
- const totalMediaCount = imageCount + audioCount + videoCount;
164
- if (totalMediaCount > totalDocsCount * 2 / 3) {
165
- const fileTypes = [];
166
- if (imageCount > 0) fileTypes.push("image/*");
167
- if (audioCount > 0) fileTypes.push("audio/*");
168
- if (videoCount > 0) fileTypes.push("video/*");
169
- return fileTypes.length > 0 ? fileTypes : false;
170
- }
171
- return false;
150
+ const isImage = (value) => IMAGE_EXTENSIONS.some((extension) => value.toString().endsWith(extension));
151
+ const isAudio = (value) => AUDIO_EXTENSIONS.some((extension) => value.toString().endsWith(extension));
152
+ const isVideo = (value) => VIDEO_EXTENSIONS.some((extension) => value.toString().endsWith(extension));
153
+ const stringValues = valuesCount.values.filter((v) => typeof v === "string");
154
+ let imageCount = 0;
155
+ let audioCount = 0;
156
+ let videoCount = 0;
157
+ for (const value of stringValues) if (isImage(value)) imageCount++;
158
+ else if (isAudio(value)) audioCount++;
159
+ else if (isVideo(value)) videoCount++;
160
+ if (imageCount + audioCount + videoCount > totalDocsCount * 2 / 3) {
161
+ const fileTypes = [];
162
+ if (imageCount > 0) fileTypes.push("image/*");
163
+ if (audioCount > 0) fileTypes.push("audio/*");
164
+ if (videoCount > 0) fileTypes.push("video/*");
165
+ return fileTypes.length > 0 ? fileTypes : false;
166
+ }
167
+ return false;
172
168
  }
173
- function buildValidation({
174
- totalDocsCount,
175
- valuesResult
176
- }) {
177
- if (valuesResult) {
178
- const totalEntriesCount = valuesResult.values.length;
179
- if (totalDocsCount === totalEntriesCount)
180
- return {
181
- required: true
182
- };
183
- }
184
- return void 0;
169
+ //#endregion
170
+ //#region src/builders/validation_builder.ts
171
+ function buildValidation({ totalDocsCount, valuesResult }) {
172
+ if (valuesResult) {
173
+ if (totalDocsCount === valuesResult.values.length) return { required: true };
174
+ }
185
175
  }
186
- function buildReferenceProperty({
187
- name,
188
- totalDocsCount,
189
- valuesResult
190
- }) {
191
- const property = {
192
- name: name ?? "",
193
- type: "reference",
194
- path: findCommonInitialStringInPath(valuesResult) ?? "!!!FIX_ME!!!"
195
- };
196
- return property;
176
+ //#endregion
177
+ //#region src/builders/reference_property_builder.ts
178
+ function buildReferenceProperty({ name, totalDocsCount, valuesResult }) {
179
+ return {
180
+ name: name ?? "",
181
+ type: "reference",
182
+ path: findCommonInitialStringInPath(valuesResult) ?? "!!!FIX_ME!!!"
183
+ };
197
184
  }
185
+ //#endregion
186
+ //#region src/collection_builder.ts
198
187
  async function buildEntityPropertiesFromData(data, getType) {
199
- const typesCount = {};
200
- const valuesCount = {};
201
- if (data) {
202
- data.forEach((entry) => {
203
- if (entry) {
204
- Object.entries(entry).forEach(([key, value]) => {
205
- if (key.startsWith("_")) return;
206
- increaseMapTypeCount(typesCount, key, value, getType);
207
- increaseValuesCount(valuesCount, key, value, getType);
208
- });
209
- }
210
- });
211
- }
212
- return buildPropertiesFromCount(data.length, typesCount, valuesCount);
188
+ const typesCount = {};
189
+ const valuesCount = {};
190
+ if (data) data.forEach((entry) => {
191
+ if (entry) Object.entries(entry).forEach(([key, value]) => {
192
+ if (key.startsWith("_")) return;
193
+ increaseMapTypeCount(typesCount, key, value, getType);
194
+ increaseValuesCount(valuesCount, key, value, getType);
195
+ });
196
+ });
197
+ return buildPropertiesFromCount(data.length, typesCount, valuesCount);
213
198
  }
214
199
  function buildPropertyFromData(data, property, getType) {
215
- const typesCount = {};
216
- const valuesCount = {};
217
- if (data) {
218
- data.forEach((entry) => {
219
- increaseTypeCount(property.type, typesCount, entry, getType);
220
- increaseValuesCount(valuesCount, "inferred_prop", entry, getType);
221
- });
222
- }
223
- const enumValues = "enum" in property ? resolveEnumValues(property["enum"]) : void 0;
224
- if (enumValues) {
225
- const newEnumValues = extractEnumFromValues(Array.from(valuesCount["inferred_prop"].valuesCount.keys()));
226
- return {
227
- ...property,
228
- enum: [...newEnumValues, ...enumValues]
229
- };
230
- }
231
- const generatedProperty = buildPropertyFromCount(
232
- "inferred_prop",
233
- data.length,
234
- property.type,
235
- typesCount,
236
- valuesCount["inferred_prop"]
237
- );
238
- return mergeDeep(generatedProperty, property);
200
+ const typesCount = {};
201
+ const valuesCount = {};
202
+ if (data) data.forEach((entry) => {
203
+ increaseTypeCount(property.type, typesCount, entry, getType);
204
+ increaseValuesCount(valuesCount, "inferred_prop", entry, getType);
205
+ });
206
+ const enumValues = "enum" in property ? resolveEnumValues(property["enum"]) : void 0;
207
+ if (enumValues) {
208
+ const newEnumValues = extractEnumFromValues(Array.from(valuesCount["inferred_prop"].valuesCount.keys()));
209
+ return {
210
+ ...property,
211
+ enum: [...newEnumValues, ...enumValues]
212
+ };
213
+ }
214
+ return mergeDeep(buildPropertyFromCount("inferred_prop", data.length, property.type, typesCount, valuesCount["inferred_prop"]), property);
239
215
  }
240
216
  function buildPropertiesOrder(properties, propertiesOrder, priorityKeys) {
241
- const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());
242
- function propOrder(s) {
243
- const k = s.toLowerCase();
244
- if (lowerCasePriorityKeys.includes(k)) return 4;
245
- if (k === "title" || k === "name") return 3;
246
- if (k.includes("title") || k.includes("name")) return 2;
247
- if (k.includes("image") || k.includes("picture")) return 1;
248
- return 0;
249
- }
250
- const keys = propertiesOrder ?? Object.keys(properties);
251
- keys.sort();
252
- keys.sort((a, b) => {
253
- return propOrder(b) - propOrder(a);
254
- });
255
- return keys;
217
+ const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());
218
+ function propOrder(s) {
219
+ const k = s.toLowerCase();
220
+ if (lowerCasePriorityKeys.includes(k)) return 4;
221
+ if (k === "title" || k === "name") return 3;
222
+ if (k.includes("title") || k.includes("name")) return 2;
223
+ if (k.includes("image") || k.includes("picture")) return 1;
224
+ return 0;
225
+ }
226
+ const keys = propertiesOrder ?? Object.keys(properties);
227
+ keys.sort();
228
+ keys.sort((a, b) => {
229
+ return propOrder(b) - propOrder(a);
230
+ });
231
+ return keys;
256
232
  }
233
+ /**
234
+ * @param type
235
+ * @param typesCount
236
+ * @param fieldValue
237
+ * @param getType
238
+ */
257
239
  function increaseTypeCount(type, typesCount, fieldValue, getType) {
258
- if (type === "map") {
259
- if (fieldValue) {
260
- let mapTypesCount = typesCount[type];
261
- if (!mapTypesCount) {
262
- mapTypesCount = {};
263
- typesCount[type] = mapTypesCount;
264
- }
265
- Object.entries(fieldValue).forEach(([key, value]) => {
266
- increaseMapTypeCount(mapTypesCount, key, value, getType);
267
- });
268
- }
269
- } else if (type === "array") {
270
- let arrayTypesCount = typesCount[type];
271
- if (!arrayTypesCount) {
272
- arrayTypesCount = {};
273
- typesCount[type] = arrayTypesCount;
274
- }
275
- if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {
276
- const arrayType = getMostProbableTypeInArray(fieldValue, getType);
277
- if (arrayType === "map") {
278
- let mapTypesCount = arrayTypesCount[arrayType];
279
- if (!mapTypesCount) {
280
- mapTypesCount = {};
281
- }
282
- fieldValue.forEach((value) => {
283
- if (value && typeof value === "object" && !Array.isArray(value)) {
284
- Object.entries(value).forEach(
285
- ([key, v]) => increaseMapTypeCount(mapTypesCount, key, v, getType)
286
- );
287
- }
288
- });
289
- arrayTypesCount[arrayType] = mapTypesCount;
290
- } else {
291
- if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;
292
- else arrayTypesCount[arrayType] = Number(arrayTypesCount[arrayType]) + 1;
293
- }
294
- }
295
- } else {
296
- if (!typesCount[type]) typesCount[type] = 1;
297
- else typesCount[type] = Number(typesCount[type]) + 1;
298
- }
240
+ if (type === "map") {
241
+ if (fieldValue) {
242
+ let mapTypesCount = typesCount[type];
243
+ if (!mapTypesCount) {
244
+ mapTypesCount = {};
245
+ typesCount[type] = mapTypesCount;
246
+ }
247
+ Object.entries(fieldValue).forEach(([key, value]) => {
248
+ increaseMapTypeCount(mapTypesCount, key, value, getType);
249
+ });
250
+ }
251
+ } else if (type === "array") {
252
+ let arrayTypesCount = typesCount[type];
253
+ if (!arrayTypesCount) {
254
+ arrayTypesCount = {};
255
+ typesCount[type] = arrayTypesCount;
256
+ }
257
+ if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {
258
+ const arrayType = getMostProbableTypeInArray(fieldValue, getType);
259
+ if (arrayType === "map") {
260
+ let mapTypesCount = arrayTypesCount[arrayType];
261
+ if (!mapTypesCount) mapTypesCount = {};
262
+ fieldValue.forEach((value) => {
263
+ if (value && typeof value === "object" && !Array.isArray(value)) Object.entries(value).forEach(([key, v]) => increaseMapTypeCount(mapTypesCount, key, v, getType));
264
+ });
265
+ arrayTypesCount[arrayType] = mapTypesCount;
266
+ } else if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;
267
+ else arrayTypesCount[arrayType] = Number(arrayTypesCount[arrayType]) + 1;
268
+ }
269
+ } else if (!typesCount[type]) typesCount[type] = 1;
270
+ else typesCount[type] = Number(typesCount[type]) + 1;
299
271
  }
300
272
  function increaseMapTypeCount(typesCountRecord, key, fieldValue, getType) {
301
- if (key.startsWith("_")) return;
302
- let typesCount = typesCountRecord[key];
303
- if (!typesCount) {
304
- typesCount = {};
305
- typesCountRecord[key] = typesCount;
306
- }
307
- if (fieldValue != null) {
308
- const type = getType(fieldValue);
309
- increaseTypeCount(type, typesCount, fieldValue, getType);
310
- }
273
+ if (key.startsWith("_")) return;
274
+ let typesCount = typesCountRecord[key];
275
+ if (!typesCount) {
276
+ typesCount = {};
277
+ typesCountRecord[key] = typesCount;
278
+ }
279
+ if (fieldValue != null) increaseTypeCount(getType(fieldValue), typesCount, fieldValue, getType);
311
280
  }
312
281
  function increaseValuesCount(typeValuesRecord, key, fieldValue, getType) {
313
- if (key.startsWith("_")) return;
314
- const type = getType(fieldValue);
315
- let valuesRecord = typeValuesRecord[key];
316
- if (!valuesRecord) {
317
- valuesRecord = {
318
- values: [],
319
- valuesCount: /* @__PURE__ */ new Map()
320
- };
321
- typeValuesRecord[key] = valuesRecord;
322
- }
323
- if (type === "map") {
324
- let mapValuesRecord = valuesRecord.map;
325
- if (!mapValuesRecord) {
326
- mapValuesRecord = {};
327
- valuesRecord.map = mapValuesRecord;
328
- }
329
- if (fieldValue)
330
- Object.entries(fieldValue).forEach(
331
- ([subKey, value]) => increaseValuesCount(mapValuesRecord, subKey, value, getType)
332
- );
333
- } else if (type === "array") {
334
- if (Array.isArray(fieldValue)) {
335
- fieldValue.forEach((value) => {
336
- valuesRecord.values.push(value);
337
- valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);
338
- });
339
- }
340
- } else {
341
- if (fieldValue !== null && fieldValue !== void 0) {
342
- valuesRecord.values.push(fieldValue);
343
- valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);
344
- }
345
- }
282
+ if (key.startsWith("_")) return;
283
+ const type = getType(fieldValue);
284
+ let valuesRecord = typeValuesRecord[key];
285
+ if (!valuesRecord) {
286
+ valuesRecord = {
287
+ values: [],
288
+ valuesCount: /* @__PURE__ */ new Map()
289
+ };
290
+ typeValuesRecord[key] = valuesRecord;
291
+ }
292
+ if (type === "map") {
293
+ let mapValuesRecord = valuesRecord.map;
294
+ if (!mapValuesRecord) {
295
+ mapValuesRecord = {};
296
+ valuesRecord.map = mapValuesRecord;
297
+ }
298
+ if (fieldValue) Object.entries(fieldValue).forEach(([subKey, value]) => increaseValuesCount(mapValuesRecord, subKey, value, getType));
299
+ } else if (type === "array") {
300
+ if (Array.isArray(fieldValue)) fieldValue.forEach((value) => {
301
+ valuesRecord.values.push(value);
302
+ valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);
303
+ });
304
+ } else if (fieldValue !== null && fieldValue !== void 0) {
305
+ valuesRecord.values.push(fieldValue);
306
+ valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);
307
+ }
346
308
  }
347
309
  function getHighestTypesCount(typesCount) {
348
- let highestCount = 0;
349
- Object.entries(typesCount).forEach(([type, count]) => {
350
- let countValue = 0;
351
- if (type === "map") {
352
- countValue = getHighestRecordCount(count);
353
- } else if (type === "array") {
354
- countValue = getHighestTypesCount(count);
355
- } else {
356
- countValue = Number(count);
357
- }
358
- if (countValue > highestCount) {
359
- highestCount = countValue;
360
- }
361
- });
362
- return highestCount;
310
+ let highestCount = 0;
311
+ Object.entries(typesCount).forEach(([type, count]) => {
312
+ let countValue = 0;
313
+ if (type === "map") countValue = getHighestRecordCount(count);
314
+ else if (type === "array") countValue = getHighestTypesCount(count);
315
+ else countValue = Number(count);
316
+ if (countValue > highestCount) highestCount = countValue;
317
+ });
318
+ return highestCount;
363
319
  }
364
320
  function getHighestRecordCount(record) {
365
- return Object.entries(record).map(([key, typesCount]) => getHighestTypesCount(typesCount)).reduce((a, b) => Math.max(a, b), 0);
321
+ return Object.entries(record).map(([key, typesCount]) => getHighestTypesCount(typesCount)).reduce((a, b) => Math.max(a, b), 0);
366
322
  }
367
323
  function getMostProbableType(typesCount) {
368
- let highestCount = -1;
369
- let probableType = "string";
370
- Object.entries(typesCount).forEach(([type, count]) => {
371
- let countValue;
372
- if (type === "map") {
373
- countValue = getHighestRecordCount(count);
374
- } else if (type === "array") {
375
- countValue = getHighestTypesCount(count);
376
- } else {
377
- countValue = Number(count);
378
- }
379
- if (countValue > highestCount) {
380
- highestCount = countValue;
381
- probableType = type;
382
- }
383
- });
384
- return probableType;
324
+ let highestCount = -1;
325
+ let probableType = "string";
326
+ Object.entries(typesCount).forEach(([type, count]) => {
327
+ let countValue;
328
+ if (type === "map") countValue = getHighestRecordCount(count);
329
+ else if (type === "array") countValue = getHighestTypesCount(count);
330
+ else countValue = Number(count);
331
+ if (countValue > highestCount) {
332
+ highestCount = countValue;
333
+ probableType = type;
334
+ }
335
+ });
336
+ return probableType;
385
337
  }
386
338
  function buildPropertyFromCount(key, totalDocsCount, mostProbableType, typesCount, valuesResult) {
387
- let title;
388
- if (key) {
389
- title = prettifyIdentifier(key);
390
- }
391
- let result = void 0;
392
- if (mostProbableType === "map") {
393
- const highVariability = checkTypesCountHighVariability(typesCount);
394
- if (highVariability) {
395
- result = {
396
- type: "map",
397
- name: title ?? key ?? "",
398
- keyValue: true,
399
- properties: {}
400
- };
401
- }
402
- const properties = buildPropertiesFromCount(
403
- totalDocsCount,
404
- typesCount.map,
405
- valuesResult ? valuesResult.mapValues : void 0
406
- );
407
- result = {
408
- type: "map",
409
- name: title ?? key ?? "",
410
- properties
411
- };
412
- } else if (mostProbableType === "array") {
413
- const arrayTypesCount = typesCount.array;
414
- const arrayMostProbableType = getMostProbableType(arrayTypesCount);
415
- const of = buildPropertyFromCount(
416
- key,
417
- totalDocsCount,
418
- arrayMostProbableType,
419
- arrayTypesCount,
420
- valuesResult
421
- );
422
- result = {
423
- type: "array",
424
- name: title ?? key ?? "",
425
- of
426
- };
427
- }
428
- if (!result) {
429
- const propertyProps = {
430
- name: key,
431
- totalDocsCount,
432
- valuesResult
433
- };
434
- if (mostProbableType === "string") {
435
- result = buildStringProperty(propertyProps);
436
- } else if (mostProbableType === "reference") {
437
- result = buildReferenceProperty(propertyProps);
438
- } else {
439
- result = {
440
- type: mostProbableType
441
- };
442
- }
443
- if (title) {
444
- result.name = title;
445
- }
446
- const validation = buildValidation(propertyProps);
447
- if (validation) {
448
- result.validation = validation;
449
- }
450
- }
451
- return result;
339
+ let title;
340
+ if (key) title = prettifyIdentifier(key);
341
+ let result = void 0;
342
+ if (mostProbableType === "map") {
343
+ if (checkTypesCountHighVariability(typesCount)) result = {
344
+ type: "map",
345
+ name: title ?? key ?? "",
346
+ keyValue: true,
347
+ properties: {}
348
+ };
349
+ const properties = buildPropertiesFromCount(totalDocsCount, typesCount.map, valuesResult ? valuesResult.mapValues : void 0);
350
+ result = {
351
+ type: "map",
352
+ name: title ?? key ?? "",
353
+ properties
354
+ };
355
+ } else if (mostProbableType === "array") {
356
+ const arrayTypesCount = typesCount.array;
357
+ const of = buildPropertyFromCount(key, totalDocsCount, getMostProbableType(arrayTypesCount), arrayTypesCount, valuesResult);
358
+ result = {
359
+ type: "array",
360
+ name: title ?? key ?? "",
361
+ of
362
+ };
363
+ }
364
+ if (!result) {
365
+ const propertyProps = {
366
+ name: key,
367
+ totalDocsCount,
368
+ valuesResult
369
+ };
370
+ if (mostProbableType === "string") result = buildStringProperty(propertyProps);
371
+ else if (mostProbableType === "reference") result = buildReferenceProperty(propertyProps);
372
+ else result = { type: mostProbableType };
373
+ if (title) result.name = title;
374
+ const validation = buildValidation(propertyProps);
375
+ if (validation) result.validation = validation;
376
+ }
377
+ return result;
452
378
  }
453
379
  function buildPropertiesFromCount(totalDocsCount, typesCountRecord, valuesCountRecord) {
454
- const res = {};
455
- Object.entries(typesCountRecord).forEach(([key, typesCount]) => {
456
- const mostProbableType = getMostProbableType(typesCount);
457
- res[key] = buildPropertyFromCount(
458
- key,
459
- totalDocsCount,
460
- mostProbableType,
461
- typesCount,
462
- valuesCountRecord ? valuesCountRecord[key] : void 0
463
- );
464
- });
465
- return res;
380
+ const res = {};
381
+ Object.entries(typesCountRecord).forEach(([key, typesCount]) => {
382
+ res[key] = buildPropertyFromCount(key, totalDocsCount, getMostProbableType(typesCount), typesCount, valuesCountRecord ? valuesCountRecord[key] : void 0);
383
+ });
384
+ return res;
466
385
  }
467
386
  function countMaxDocumentsUnder(typesCount) {
468
- let count = 0;
469
- Object.entries(typesCount).forEach(([type, value]) => {
470
- if (typeof value === "object") {
471
- count = Math.max(count, countMaxDocumentsUnder(value));
472
- } else {
473
- count = Math.max(count, Number(value));
474
- }
475
- });
476
- return count;
387
+ let count = 0;
388
+ Object.entries(typesCount).forEach(([type, value]) => {
389
+ if (typeof value === "object") count = Math.max(count, countMaxDocumentsUnder(value));
390
+ else count = Math.max(count, Number(value));
391
+ });
392
+ return count;
477
393
  }
478
394
  function getMostProbableTypeInArray(array, getType) {
479
- const typesCount = {};
480
- array.forEach((value) => {
481
- increaseTypeCount(getType(value), typesCount, value, getType);
482
- });
483
- return getMostProbableType(typesCount);
395
+ const typesCount = {};
396
+ array.forEach((value) => {
397
+ increaseTypeCount(getType(value), typesCount, value, getType);
398
+ });
399
+ return getMostProbableType(typesCount);
484
400
  }
485
401
  function checkTypesCountHighVariability(typesCount) {
486
- const maxCount = countMaxDocumentsUnder(typesCount);
487
- let keysWithFewValues = 0;
488
- Object.entries(typesCount.map ?? {}).forEach(([key, value]) => {
489
- const count = countMaxDocumentsUnder(value);
490
- if (count < maxCount / 3) {
491
- keysWithFewValues++;
492
- }
493
- });
494
- return keysWithFewValues / Object.entries(typesCount.map ?? {}).length > 0.5;
402
+ const maxCount = countMaxDocumentsUnder(typesCount);
403
+ let keysWithFewValues = 0;
404
+ Object.entries(typesCount.map ?? {}).forEach(([key, value]) => {
405
+ if (countMaxDocumentsUnder(value) < maxCount / 3) keysWithFewValues++;
406
+ });
407
+ return keysWithFewValues / Object.entries(typesCount.map ?? {}).length > .5;
495
408
  }
496
409
  function inferTypeFromValue(value) {
497
- if (value === null || value === void 0) return "string";
498
- if (value instanceof Vector || value && typeof value === "object" && "__type" in value && value.__type === "Vector") return "vector";
499
- if (typeof value === "string") return "string";
500
- if (typeof value === "number") return "number";
501
- if (typeof value === "boolean") return "boolean";
502
- if (Array.isArray(value)) return "array";
503
- if (typeof value === "object") return "map";
504
- return "string";
410
+ if (value === null || value === void 0) return "string";
411
+ if (value instanceof Vector || value && typeof value === "object" && "__type" in value && value.__type === "Vector") return "vector";
412
+ if (typeof value === "string") return "string";
413
+ if (typeof value === "number") return "number";
414
+ if (typeof value === "boolean") return "boolean";
415
+ if (Array.isArray(value)) return "array";
416
+ if (typeof value === "object") return "map";
417
+ return "string";
505
418
  }
506
- export {
507
- buildEntityPropertiesFromData,
508
- buildPropertiesOrder,
509
- buildPropertyFromData,
510
- extractEnumFromValues,
511
- findCommonInitialStringInPath,
512
- inferTypeFromValue,
513
- isObject,
514
- isPlainObject,
515
- looksLikeReference,
516
- mergeDeep2 as mergeDeep,
517
- parseReferenceString,
518
- prettifyIdentifier2 as prettifyIdentifier,
519
- removeInitialAndTrailingSlashes,
520
- removeInitialSlash,
521
- removeTrailingSlash,
522
- resolveEnumValues,
523
- unslugify2 as unslugify
524
- };
525
- //# sourceMappingURL=index.es.js.map
419
+ //#endregion
420
+ export { buildEntityPropertiesFromData, buildPropertiesOrder, buildPropertyFromData, extractEnumFromValues, findCommonInitialStringInPath, inferTypeFromValue, isObject, isPlainObject, looksLikeReference, mergeDeep, parseReferenceString, prettifyIdentifier, removeInitialAndTrailingSlashes, removeInitialSlash, removeTrailingSlash, resolveEnumValues, unslugify };
421
+
422
+ //# sourceMappingURL=index.es.js.map