@firecms/schema_inference 3.0.0-canary.235 → 3.0.0-canary.239

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.
@@ -70,80 +70,6 @@ export declare class Vector {
70
70
  * @group Entity properties
71
71
  */
72
72
  export type Property<T extends CMSType = any> = T extends string ? StringProperty : T extends number ? NumberProperty : T extends boolean ? BooleanProperty : T extends Date ? DateProperty : T extends GeoPoint ? GeopointProperty : T extends EntityReference ? ReferenceProperty : T extends Array<CMSType> ? ArrayProperty<T> : T extends Record<string, any> ? MapProperty<T> : any;
73
- /**
74
- * Interface including all common properties of a CMS property
75
- * @group Entity properties
76
- */
77
- export interface BaseProperty<T extends CMSType, CustomProps = any> {
78
- /**
79
- * Datatype of the property
80
- */
81
- dataType: DataType;
82
- /**
83
- * Property name (e.g. Product)
84
- */
85
- name?: string;
86
- /**
87
- * Property description, always displayed under the field
88
- */
89
- description?: string;
90
- /**
91
- * You can use this prop to reuse a property that has been defined
92
- * in the top level of the CMS in the prop `fields`.
93
- * All the configuration will be taken from the inherited config, and
94
- * overwritten by the current property config.
95
- */
96
- propertyConfig?: string;
97
- /**
98
- * Longer description of a field, displayed under a popover
99
- */
100
- longDescription?: string;
101
- /**
102
- * Width in pixels of this column in the collection view. If not set
103
- * the width is inferred based on the other configurations
104
- */
105
- columnWidth?: number;
106
- /**
107
- * Do not show this property in the collection view
108
- */
109
- hideFromCollection?: boolean;
110
- /**
111
- * Is this a read only property. When set to true, it gets rendered as a
112
- * preview.
113
- */
114
- readOnly?: boolean;
115
- /**
116
- * Is this field disabled.
117
- * When set to true, it gets rendered as a
118
- * disabled field. You can also specify a configuration for defining the
119
- * behaviour of disabled properties (including custom messages, clear value on
120
- * disabled or hide the field completely)
121
- */
122
- disabled?: boolean | PropertyDisabledConfig;
123
- /**
124
- * Rules for validating this property
125
- */
126
- validation?: PropertyValidationSchema;
127
- /**
128
- * Additional props that are passed to the components defined in `field`
129
- * or in `preview`.
130
- */
131
- customProps?: CustomProps;
132
- /**
133
- * This value will be set by default for new entities.
134
- */
135
- defaultValue?: T | null;
136
- /**
137
- * Should this property be editable. If set to true, the user will be able to modify the property and
138
- * save the new config. The saved config will then become the source of truth.
139
- */
140
- editable?: boolean;
141
- /**
142
- * A number between 0 and 100 that indicates the width of the field in the form view.
143
- * It defaults to 100, but you can set it to 50 to have two fields in the same row.
144
- */
145
- widthPercentage?: number;
146
- }
147
73
  /**
148
74
  * @group Entity properties
149
75
  */
@@ -204,15 +130,57 @@ export type Properties<M extends Record<string, any> = any> = {
204
130
  [k in keyof M]: Property<M[keyof M]>;
205
131
  };
206
132
  /**
133
+ * Interface including all common properties of a CMS property
207
134
  * @group Entity properties
208
135
  */
209
- export type PropertyOrBuilder<T extends CMSType = CMSType, M extends Record<string, any> = any> = Property<T>;
210
- /**
211
- * @group Entity properties
212
- */
213
- export type PropertiesOrBuilders<M extends Record<string, any> = any> = {
214
- [k in keyof M]: PropertyOrBuilder<M[k], M>;
215
- };
136
+ export interface BaseProperty<T extends CMSType> {
137
+ /**
138
+ * Datatype of the property
139
+ */
140
+ dataType: DataType;
141
+ /**
142
+ * Property name (e.g. Product)
143
+ */
144
+ name?: string;
145
+ /**
146
+ * Property description, always displayed under the field
147
+ */
148
+ description?: string;
149
+ /**
150
+ * Longer description of a field, displayed under a popover
151
+ */
152
+ longDescription?: string;
153
+ /**
154
+ * Width in pixels of this column in the collection view. If not set
155
+ * the width is inferred based on the other configurations
156
+ */
157
+ columnWidth?: number;
158
+ /**
159
+ * Do not show this property in the collection view
160
+ */
161
+ hideFromCollection?: boolean;
162
+ /**
163
+ * Is this a read only property. When set to true, it gets rendered as a
164
+ * preview.
165
+ */
166
+ readOnly?: boolean;
167
+ /**
168
+ * Is this field disabled.
169
+ * When set to true, it gets rendered as a
170
+ * disabled field. You can also specify a configuration for defining the
171
+ * behaviour of disabled properties (including custom messages, clear value on
172
+ * disabled or hide the field completely)
173
+ */
174
+ disabled?: boolean | PropertyDisabledConfig;
175
+ /**
176
+ * Rules for validating this property
177
+ */
178
+ validation?: PropertyValidationSchema;
179
+ /**
180
+ * This value will be set by default for new entities.
181
+ */
182
+ defaultValue?: T | null;
183
+ }
216
184
  /**
217
185
  * @group Entity properties
218
186
  */
@@ -309,7 +277,7 @@ export interface ArrayProperty<T extends ArrayT[] = any[], ArrayT extends CMSTyp
309
277
  * You can leave this field empty only if you are providing a custom field,
310
278
  * or using the `oneOf` prop, otherwise an error will be thrown.
311
279
  */
312
- of?: PropertyOrBuilder<ArrayT> | Property<ArrayT>[];
280
+ of?: Property<ArrayT>[];
313
281
  /**
314
282
  * Use this field if you would like to have an array of typed objects.
315
283
  * It is useful if you need to have values of different types in the same
@@ -380,7 +348,7 @@ export interface MapProperty<T extends Record<string, CMSType> = Record<string,
380
348
  /**
381
349
  * Record of properties included in this map.
382
350
  */
383
- properties?: PropertiesOrBuilders<T>;
351
+ properties?: Properties<T>;
384
352
  /**
385
353
  * Order in which the properties are displayed.
386
354
  * If you are specifying your collection as code, the order is the same as the
@@ -1,6 +1,6 @@
1
- import { DataType, Properties, PropertiesOrBuilders, Property } from "./cms_types";
1
+ import { DataType, Properties, Property } from "./cms_types";
2
2
  export type InferenceTypeBuilder = (value: any) => DataType;
3
3
  export declare function buildEntityPropertiesFromData(data: object[], getType: InferenceTypeBuilder): Promise<Properties>;
4
4
  export declare function buildPropertyFromData(data: any[], property: Property, getType: InferenceTypeBuilder): Property;
5
- export declare function buildPropertiesOrder(properties: PropertiesOrBuilders, propertiesOrder?: string[], priorityKeys?: string[]): string[];
5
+ export declare function buildPropertiesOrder(properties: Properties, propertiesOrder?: string[], priorityKeys?: string[]): string[];
6
6
  export declare function inferTypeFromValue(value: any): DataType;
package/dist/index.es.js CHANGED
@@ -166,6 +166,7 @@ async function buildEntityPropertiesFromData(data, getType) {
166
166
  data.forEach((entry) => {
167
167
  if (entry) {
168
168
  Object.entries(entry).forEach(([key, value]) => {
169
+ if (key.startsWith("_")) return;
169
170
  increaseMapTypeCount(typesCount, key, value, getType);
170
171
  increaseValuesCount(valuesCount, key, value, getType);
171
172
  });
@@ -243,9 +244,11 @@ function increaseTypeCount(type, typesCount, fieldValue, getType) {
243
244
  mapTypesCount = {};
244
245
  }
245
246
  fieldValue.forEach((value) => {
246
- Object.entries(value).forEach(
247
- ([key, v]) => increaseMapTypeCount(mapTypesCount, key, v, getType)
248
- );
247
+ if (value && typeof value === "object" && !Array.isArray(value)) {
248
+ Object.entries(value).forEach(
249
+ ([key, v]) => increaseMapTypeCount(mapTypesCount, key, v, getType)
250
+ );
251
+ }
249
252
  });
250
253
  arrayTypesCount[arrayType] = mapTypesCount;
251
254
  } else {
@@ -259,6 +262,7 @@ function increaseTypeCount(type, typesCount, fieldValue, getType) {
259
262
  }
260
263
  }
261
264
  function increaseMapTypeCount(typesCountRecord, key, fieldValue, getType) {
265
+ if (key.startsWith("_")) return;
262
266
  let typesCount = typesCountRecord[key];
263
267
  if (!typesCount) {
264
268
  typesCount = {};
@@ -270,6 +274,7 @@ function increaseMapTypeCount(typesCountRecord, key, fieldValue, getType) {
270
274
  }
271
275
  }
272
276
  function increaseValuesCount(typeValuesRecord, key, fieldValue, getType) {
277
+ if (key.startsWith("_")) return;
273
278
  const dataType = getType(fieldValue);
274
279
  let valuesRecord = typeValuesRecord[key];
275
280
  if (!valuesRecord) {
@@ -287,7 +292,7 @@ function increaseValuesCount(typeValuesRecord, key, fieldValue, getType) {
287
292
  }
288
293
  if (fieldValue)
289
294
  Object.entries(fieldValue).forEach(
290
- ([key2, value]) => increaseValuesCount(mapValuesRecord, key2, value, getType)
295
+ ([subKey, value]) => increaseValuesCount(mapValuesRecord, subKey, value, getType)
291
296
  );
292
297
  } else if (dataType === "array") {
293
298
  if (Array.isArray(fieldValue)) {
@@ -297,7 +302,7 @@ function increaseValuesCount(typeValuesRecord, key, fieldValue, getType) {
297
302
  });
298
303
  }
299
304
  } else {
300
- if (fieldValue) {
305
+ if (fieldValue !== null && fieldValue !== void 0) {
301
306
  valuesRecord.values.push(fieldValue);
302
307
  valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);
303
308
  }
@@ -462,6 +467,7 @@ function formatString(input) {
462
467
  return formatted;
463
468
  }
464
469
  function inferTypeFromValue(value) {
470
+ if (value === null || value === void 0) return "string";
465
471
  if (typeof value === "string") return "string";
466
472
  if (typeof value === "number") return "number";
467
473
  if (typeof value === "boolean") return "boolean";
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/strings.ts","../src/util.ts","../src/builders/string_property_builder.ts","../src/builders/validation_builder.ts","../src/builders/reference_property_builder.ts","../src/collection_builder.ts"],"sourcesContent":["import { ValuesCountEntry } from \"./types\";\n\nexport function findCommonInitialStringInPath(valuesCount?: ValuesCountEntry) {\n\n if (!valuesCount) return undefined;\n\n function getPath(value: any) {\n if (typeof value === \"string\") return value;\n else if (value?.type === \"document\" && value.path) return value.path;\n else return undefined;\n }\n\n const strings: string[] = valuesCount.values.map((v) => getPath(v)).filter(v => !!v) as string[];\n const pathWithSlash = strings.find((s) => s.includes(\"/\"));\n if (!pathWithSlash)\n return undefined;\n\n const searchedPath = pathWithSlash.substr(0, pathWithSlash.lastIndexOf(\"/\"));\n\n const yep = valuesCount.values\n .filter((value) => {\n const path = getPath(value);\n if (!path) return false;\n return path.startsWith(searchedPath)\n }).length > valuesCount.values.length / 3 * 2;\n\n return yep ? searchedPath : undefined;\n\n}\n\nexport function removeInitialAndTrailingSlashes(s: string): string {\n return removeInitialSlash(removeTrailingSlash(s));\n}\n\nexport function removeInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s.slice(1);\n else return s;\n}\n\nexport function removeTrailingSlash(s: string) {\n if (s.endsWith(\"/\"))\n return s.slice(0, -1);\n else return s;\n}\n","import { EnumValueConfig, EnumValues } from \"./cms_types\";\n\nexport function extractEnumFromValues(values: unknown[]) {\n if (!Array.isArray(values)) {\n return [];\n }\n const enumValues = values\n .map((value) => {\n if (typeof value === \"string\") {\n return ({ id: value, label: unslugify(value) });\n } else\n return null;\n }).filter(Boolean) as Array<{ id: string, label: string }>;\n enumValues.sort((a, b) => a.label.localeCompare(b.label));\n return enumValues;\n}\n\nexport function unslugify(slug?: string): string {\n if (!slug) return \"\";\n if (slug.includes(\"-\") || slug.includes(\"_\") || !slug.includes(\" \")) {\n const result = slug.replace(/[-_]/g, \" \");\n return result.replace(/\\w\\S*/g, function (txt) {\n return txt.charAt(0).toUpperCase() + txt.substr(1);\n }).trim();\n } else {\n return slug.trim();\n }\n}\n\nexport function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined {\n if (typeof input === \"object\") {\n return Object.entries(input).map(([id, value]) =>\n (typeof value === \"string\"\n ? {\n id,\n label: value\n }\n : value));\n } else if (Array.isArray(input)) {\n return input as EnumValueConfig[];\n } else {\n return undefined;\n }\n}\n\nexport function mergeDeep<T extends Record<any, any>, U extends Record<any, any>>(target: T, source: U, ignoreUndefined: boolean = false): T & U {\n const targetIsObject = isObject(target);\n const output = targetIsObject ? { ...target } : target;\n if (targetIsObject && isObject(source)) {\n Object.keys(source).forEach(key => {\n const sourceElement = source[key];\n // Skip undefined values when ignoreUndefined is true\n if (ignoreUndefined && sourceElement === undefined) {\n return;\n }\n if (sourceElement instanceof Date) {\n // Assign a new Date instance with the same time value\n Object.assign(output, { [key]: new Date(sourceElement.getTime()) });\n } else if (isObject(sourceElement)) {\n if (!(key in target))\n Object.assign(output, { [key]: sourceElement });\n else\n (output as any)[key] = mergeDeep((target as any)[key], sourceElement);\n } else {\n Object.assign(output, { [key]: sourceElement });\n }\n });\n }\n return output as T;\n}\n\nexport function isObject(item: any) {\n return item && typeof item === \"object\" && !Array.isArray(item);\n}\n\n\n","import { InferencePropertyBuilderProps, ValuesCountEntry } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { extractEnumFromValues } from \"../util\";\nimport { FileType, Property, StringProperty } from \"../cms_types\";\n\nconst IMAGE_EXTENSIONS = [\".jpg\", \".jpeg\", \".png\", \".webp\", \".gif\", \".avif\"];\nconst AUDIO_EXTENSIONS = [\".mp3\", \".ogg\", \".opus\", \".aac\"];\nconst VIDEO_EXTENSIONS = [\".avi\", \".mp4\"];\n\nconst 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])?)*$/;\n\nexport function buildStringProperty({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): Property {\n\n let stringProperty: Property = {\n dataType: \"string\",\n\n };\n\n if (valuesResult) {\n\n const totalEntriesCount = valuesResult.values.length;\n const totalValues = Array.from(valuesResult.valuesCount.keys()).length;\n\n const config: Partial<StringProperty> = {};\n\n const probablyAURL = valuesResult.values\n .filter((value) => typeof value === \"string\" &&\n value.toString().startsWith(\"http\")).length > totalDocsCount / 3 * 2;\n if (probablyAURL) {\n config.url = true;\n }\n\n const probablyAnEmail = valuesResult.values\n .filter((value) => typeof value === \"string\" &&\n emailRegEx.test(value)).length > totalDocsCount / 3 * 2;\n if (probablyAnEmail) {\n config.email = true;\n }\n\n const probablyUserIds = valuesResult.values\n .filter((value) => typeof value === \"string\" && value.length === 28 && !value.includes(\" \"))\n .length > totalDocsCount / 3 * 2;\n if (probablyUserIds)\n config.readOnly = true;\n\n if (!probablyAnEmail &&\n !probablyAURL &&\n !probablyUserIds &&\n !probablyAURL &&\n totalValues < totalEntriesCount / 3\n ) {\n const enumValues = extractEnumFromValues(Array.from(valuesResult.valuesCount.keys()));\n\n if (Object.keys(enumValues).length > 1)\n config.enumValues = enumValues;\n }\n\n // regular string\n if (!probablyAnEmail &&\n !probablyAURL &&\n !probablyUserIds &&\n !probablyAURL &&\n !config.enumValues) {\n const fileType = probableFileType(valuesResult, totalDocsCount);\n if (fileType) {\n config.storage = {\n acceptedFiles: [fileType as FileType],\n storagePath: findCommonInitialStringInPath(valuesResult) ?? \"/\"\n };\n }\n }\n\n if (Object.keys(config).length > 0)\n stringProperty = {\n ...stringProperty,\n ...config,\n editable: true\n };\n }\n\n return stringProperty;\n}\n\n// TODO: support returning multiple types\nfunction probableFileType(valuesCount: ValuesCountEntry, totalDocsCount: number): boolean | FileType {\n const probablyAnImage = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n IMAGE_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const probablyAudio = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n AUDIO_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const probablyVideo = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n VIDEO_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const fileType: boolean | FileType = probablyAnImage\n ? \"image/*\"\n : probablyAudio\n ? \"audio/*\"\n : probablyVideo ? \"video/*\" : false;\n return fileType;\n}\n","import { InferencePropertyBuilderProps } from \"../types\";\nimport { PropertyValidationSchema } from \"../cms_types\";\n\nexport function buildValidation({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): PropertyValidationSchema | undefined {\n\n if (valuesResult) {\n const totalEntriesCount = valuesResult.values.length;\n if (totalDocsCount === totalEntriesCount)\n return {\n required: true\n }\n }\n\n return undefined;\n}\n","import { InferencePropertyBuilderProps } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { Property } from \"../cms_types\";\n\nexport function buildReferenceProperty({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): Property {\n\n const property: Property = {\n dataType: \"reference\",\n path: findCommonInitialStringInPath(valuesResult) ?? \"!!!FIX_ME!!!\",\n editable: true\n };\n\n return property;\n}\n","import {\n InferencePropertyBuilderProps,\n TypesCount,\n TypesCountRecord,\n ValuesCountEntry,\n ValuesCountRecord\n} from \"./types\";\nimport { buildStringProperty } from \"./builders/string_property_builder\";\nimport { buildValidation } from \"./builders/validation_builder\";\nimport { buildReferenceProperty } from \"./builders/reference_property_builder\";\nimport { extractEnumFromValues, mergeDeep, resolveEnumValues } from \"./util\";\nimport { DataType, EnumValues, Properties, PropertiesOrBuilders, Property, StringProperty } from \"./cms_types\";\n\nexport type InferenceTypeBuilder = (value: any) => DataType;\n\nexport async function buildEntityPropertiesFromData(\n data: object[],\n getType: InferenceTypeBuilder\n): Promise<Properties> {\n const typesCount: TypesCountRecord = {};\n const valuesCount: ValuesCountRecord = {};\n if (data) {\n data.forEach((entry) => {\n if (entry) {\n Object.entries(entry).forEach(([key, value]) => {\n increaseMapTypeCount(typesCount, key, value, getType);\n increaseValuesCount(valuesCount, key, value, getType);\n });\n }\n });\n }\n return buildPropertiesFromCount(data.length, typesCount, valuesCount);\n}\n\nexport function buildPropertyFromData(\n data: any[],\n property: Property,\n getType: InferenceTypeBuilder\n): Property {\n const typesCount = {};\n const valuesCount: ValuesCountRecord = {};\n if (data) {\n data.forEach((entry) => {\n increaseTypeCount(property.dataType, typesCount, entry, getType);\n increaseValuesCount(valuesCount, \"inferred_prop\", entry, getType);\n });\n }\n const enumValues = \"enumValues\" in property ? resolveEnumValues(property[\"enumValues\"] as EnumValues) : undefined;\n if (enumValues) {\n const newEnumValues = extractEnumFromValues(Array.from(valuesCount[\"inferred_prop\"].valuesCount.keys()));\n return {\n ...property,\n enumValues: [...newEnumValues, ...enumValues]\n } as StringProperty;\n }\n const generatedProperty = buildPropertyFromCount(\n \"inferred_prop\",\n data.length,\n property.dataType,\n typesCount,\n valuesCount[\"inferred_prop\"]\n );\n return mergeDeep(generatedProperty, property);\n}\n\nexport function buildPropertiesOrder(\n properties: PropertiesOrBuilders,\n propertiesOrder?: string[],\n priorityKeys?: string[]\n): string[] {\n const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());\n\n function propOrder(s: string) {\n const k = s.toLowerCase();\n if (lowerCasePriorityKeys.includes(k)) return 4;\n if (k === \"title\" || k === \"name\") return 3;\n if (k.includes(\"title\") || k.includes(\"name\")) return 2;\n if (k.includes(\"image\") || k.includes(\"picture\")) return 1;\n return 0;\n }\n\n const keys = propertiesOrder ?? Object.keys(properties);\n keys.sort(); // alphabetically\n keys.sort((a, b) => {\n return propOrder(b) - propOrder(a);\n });\n return keys;\n}\n\n/**\n * @param type\n * @param typesCount\n * @param fieldValue\n * @param getType\n */\nfunction increaseTypeCount(\n type: DataType,\n typesCount: TypesCount,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (type === \"map\") {\n if (fieldValue) {\n let mapTypesCount = typesCount[type];\n if (!mapTypesCount) {\n mapTypesCount = {};\n typesCount[type] = mapTypesCount;\n }\n Object.entries(fieldValue).forEach(([key, value]) => {\n increaseMapTypeCount(mapTypesCount as TypesCountRecord, key, value, getType);\n });\n }\n } else if (type === \"array\") {\n let arrayTypesCount = typesCount[type];\n if (!arrayTypesCount) {\n arrayTypesCount = {};\n typesCount[type] = arrayTypesCount;\n }\n if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {\n const arrayType = getMostProbableTypeInArray(fieldValue, getType);\n if (arrayType === \"map\") {\n let mapTypesCount = arrayTypesCount[arrayType];\n if (!mapTypesCount) {\n mapTypesCount = {};\n }\n fieldValue.forEach((value) => {\n Object.entries(value).forEach(([key, v]) =>\n increaseMapTypeCount(mapTypesCount, key, v, getType)\n );\n });\n arrayTypesCount[arrayType] = mapTypesCount;\n } else {\n if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;\n else (arrayTypesCount[arrayType] as number)++;\n }\n }\n } else {\n if (!typesCount[type]) typesCount[type] = 1;\n else (typesCount[type] as number)++;\n }\n}\n\nfunction increaseMapTypeCount(\n typesCountRecord: TypesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n let typesCount: TypesCount = typesCountRecord[key];\n if (!typesCount) {\n typesCount = {};\n typesCountRecord[key] = typesCount;\n }\n\n if (fieldValue != null) {\n // Check that fieldValue is not null or undefined before proceeding\n const type = getType(fieldValue);\n increaseTypeCount(type, typesCount, fieldValue, getType);\n }\n}\n\nfunction increaseValuesCount(\n typeValuesRecord: ValuesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n const dataType = getType(fieldValue);\n\n let valuesRecord: {\n values: any[];\n valuesCount: Map<any, number>;\n map?: ValuesCountRecord;\n } = typeValuesRecord[key];\n\n if (!valuesRecord) {\n valuesRecord = {\n values: [],\n valuesCount: new Map()\n };\n typeValuesRecord[key] = valuesRecord;\n }\n\n if (dataType === \"map\") {\n let mapValuesRecord: ValuesCountRecord | undefined = valuesRecord.map;\n if (!mapValuesRecord) {\n mapValuesRecord = {};\n valuesRecord.map = mapValuesRecord;\n }\n if (fieldValue)\n Object.entries(fieldValue).forEach(([key, value]) =>\n increaseValuesCount(mapValuesRecord as ValuesCountRecord, key, value, getType)\n );\n } else if (dataType === \"array\") {\n if (Array.isArray(fieldValue)) {\n fieldValue.forEach((value) => {\n valuesRecord.values.push(value);\n valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);\n });\n }\n } else {\n if (fieldValue) {\n valuesRecord.values.push(fieldValue);\n valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);\n }\n }\n}\n\nfunction getHighestTypesCount(typesCount: TypesCount): number {\n let highestCount = 0;\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue = 0;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n }\n });\n\n return highestCount;\n}\n\nfunction getHighestRecordCount(record: TypesCountRecord): number {\n return Object.entries(record)\n .map(([key, typesCount]) => getHighestTypesCount(typesCount))\n .reduce((a, b) => Math.max(a, b), 0);\n}\n\nfunction getMostProbableType(typesCount: TypesCount): DataType {\n let highestCount = -1;\n let probableType: DataType = \"string\"; // default\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n probableType = type as DataType;\n }\n });\n return probableType;\n}\n\nfunction buildPropertyFromCount(\n key: string,\n totalDocsCount: number,\n mostProbableType: DataType,\n typesCount: TypesCount,\n valuesResult?: ValuesCountEntry\n): Property {\n let title: string | undefined;\n\n if (key) {\n title = formatString(key.toLowerCase());\n }\n\n let result: Property | undefined = undefined;\n if (mostProbableType === \"map\") {\n const highVariability = checkTypesCountHighVariability(typesCount);\n if (highVariability) {\n result = {\n dataType: \"map\",\n name: title,\n keyValue: true,\n properties: {}\n };\n }\n const properties = buildPropertiesFromCount(\n totalDocsCount,\n typesCount.map as TypesCountRecord,\n valuesResult ? valuesResult.mapValues : undefined\n );\n result = {\n dataType: \"map\",\n name: title,\n properties\n };\n } else if (mostProbableType === \"array\") {\n const arrayTypesCount = typesCount.array as TypesCount;\n const arrayMostProbableType = getMostProbableType(arrayTypesCount);\n const of = buildPropertyFromCount(\n key,\n totalDocsCount,\n arrayMostProbableType,\n arrayTypesCount,\n valuesResult\n );\n result = {\n dataType: \"array\",\n name: title,\n of\n };\n }\n\n if (!result) {\n const propertyProps: InferencePropertyBuilderProps = {\n name: key,\n totalDocsCount,\n valuesResult\n };\n if (mostProbableType === \"string\") {\n result = buildStringProperty(propertyProps);\n } else if (mostProbableType === \"reference\") {\n result = buildReferenceProperty(propertyProps);\n } else {\n result = {\n dataType: mostProbableType\n } as Property;\n }\n\n if (title) {\n result.name = title;\n }\n\n const validation = buildValidation(propertyProps);\n if (validation) {\n result.validation = validation;\n }\n }\n\n return {\n ...result,\n editable: true\n };\n}\n\nfunction buildPropertiesFromCount(\n totalDocsCount: number,\n typesCountRecord: TypesCountRecord,\n valuesCountRecord?: ValuesCountRecord\n): Properties {\n const res: Properties = {};\n Object.entries(typesCountRecord).forEach(([key, typesCount]) => {\n const mostProbableType = getMostProbableType(typesCount);\n res[key] = buildPropertyFromCount(\n key,\n totalDocsCount,\n mostProbableType,\n typesCount,\n valuesCountRecord ? valuesCountRecord[key] : undefined\n );\n });\n return res;\n}\n\nfunction countMaxDocumentsUnder(typesCount: TypesCount) {\n let count = 0;\n Object.entries(typesCount).forEach(([type, value]) => {\n if (typeof value === \"object\") {\n count = Math.max(count, countMaxDocumentsUnder(value as TypesCountRecord));\n } else {\n count = Math.max(count, value as number);\n }\n });\n return count;\n}\n\nfunction getMostProbableTypeInArray(\n array: any[],\n getType: InferenceTypeBuilder\n): DataType {\n const typesCount: TypesCount = {};\n array.forEach((value) => {\n increaseTypeCount(getType(value), typesCount, value, getType);\n });\n return getMostProbableType(typesCount);\n}\n\nfunction checkTypesCountHighVariability(typesCount: TypesCount) {\n const maxCount = countMaxDocumentsUnder(typesCount);\n let keysWithFewValues = 0;\n Object.entries(typesCount.map ?? {}).forEach(([key, value]) => {\n const count = countMaxDocumentsUnder(value);\n if (count < maxCount / 3) {\n keysWithFewValues++;\n }\n });\n return keysWithFewValues / Object.entries(typesCount.map ?? {}).length > 0.5;\n}\n\nfunction formatString(input: string): string {\n const normalized = input\n .replace(/[_-]+/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .toLowerCase();\n\n // Split the normalized string into words\n const words = normalized.split(\" \");\n\n // Capitalize the first letter of each word and join them with a space\n const formatted = words\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n\n return formatted;\n}\n\nexport function inferTypeFromValue(value: any): DataType {\n if (typeof value === \"string\") return \"string\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (Array.isArray(value)) return \"array\";\n if (typeof value === \"object\") return \"map\";\n return \"string\";\n}\n"],"names":["key"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/strings.ts","../src/util.ts","../src/builders/string_property_builder.ts","../src/builders/validation_builder.ts","../src/builders/reference_property_builder.ts","../src/collection_builder.ts"],"sourcesContent":["import { ValuesCountEntry } from \"./types\";\n\nexport function findCommonInitialStringInPath(valuesCount?: ValuesCountEntry) {\n\n if (!valuesCount) return undefined;\n\n function getPath(value: any) {\n if (typeof value === \"string\") return value;\n else if (value?.type === \"document\" && value.path) return value.path;\n else return undefined;\n }\n\n const strings: string[] = valuesCount.values.map((v) => getPath(v)).filter(v => !!v) as string[];\n const pathWithSlash = strings.find((s) => s.includes(\"/\"));\n if (!pathWithSlash)\n return undefined;\n\n const searchedPath = pathWithSlash.substr(0, pathWithSlash.lastIndexOf(\"/\"));\n\n const yep = valuesCount.values\n .filter((value) => {\n const path = getPath(value);\n if (!path) return false;\n return path.startsWith(searchedPath)\n }).length > valuesCount.values.length / 3 * 2;\n\n return yep ? searchedPath : undefined;\n\n}\n\nexport function removeInitialAndTrailingSlashes(s: string): string {\n return removeInitialSlash(removeTrailingSlash(s));\n}\n\nexport function removeInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s.slice(1);\n else return s;\n}\n\nexport function removeTrailingSlash(s: string) {\n if (s.endsWith(\"/\"))\n return s.slice(0, -1);\n else return s;\n}\n","import { EnumValueConfig, EnumValues } from \"./cms_types\";\n\nexport function extractEnumFromValues(values: unknown[]) {\n if (!Array.isArray(values)) {\n return [];\n }\n const enumValues = values\n .map((value) => {\n if (typeof value === \"string\") {\n return ({ id: value, label: unslugify(value) });\n } else\n return null;\n }).filter(Boolean) as Array<{ id: string, label: string }>;\n enumValues.sort((a, b) => a.label.localeCompare(b.label));\n return enumValues;\n}\n\nexport function unslugify(slug?: string): string {\n if (!slug) return \"\";\n if (slug.includes(\"-\") || slug.includes(\"_\") || !slug.includes(\" \")) {\n const result = slug.replace(/[-_]/g, \" \");\n return result.replace(/\\w\\S*/g, function (txt) {\n return txt.charAt(0).toUpperCase() + txt.substr(1);\n }).trim();\n } else {\n return slug.trim();\n }\n}\n\nexport function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined {\n if (typeof input === \"object\") {\n return Object.entries(input).map(([id, value]) =>\n (typeof value === \"string\"\n ? {\n id,\n label: value\n }\n : value));\n } else if (Array.isArray(input)) {\n return input as EnumValueConfig[];\n } else {\n return undefined;\n }\n}\n\nexport function mergeDeep<T extends Record<any, any>, U extends Record<any, any>>(target: T, source: U, ignoreUndefined: boolean = false): T & U {\n const targetIsObject = isObject(target);\n const output = targetIsObject ? { ...target } : target;\n if (targetIsObject && isObject(source)) {\n Object.keys(source).forEach(key => {\n const sourceElement = source[key];\n // Skip undefined values when ignoreUndefined is true\n if (ignoreUndefined && sourceElement === undefined) {\n return;\n }\n if (sourceElement instanceof Date) {\n // Assign a new Date instance with the same time value\n Object.assign(output, { [key]: new Date(sourceElement.getTime()) });\n } else if (isObject(sourceElement)) {\n if (!(key in target))\n Object.assign(output, { [key]: sourceElement });\n else\n (output as any)[key] = mergeDeep((target as any)[key], sourceElement);\n } else {\n Object.assign(output, { [key]: sourceElement });\n }\n });\n }\n return output as T;\n}\n\nexport function isObject(item: any) {\n return item && typeof item === \"object\" && !Array.isArray(item);\n}\n\n\n","import { InferencePropertyBuilderProps, ValuesCountEntry } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { extractEnumFromValues } from \"../util\";\nimport { FileType, Property, StringProperty } from \"../cms_types\";\n\nconst IMAGE_EXTENSIONS = [\".jpg\", \".jpeg\", \".png\", \".webp\", \".gif\", \".avif\"];\nconst AUDIO_EXTENSIONS = [\".mp3\", \".ogg\", \".opus\", \".aac\"];\nconst VIDEO_EXTENSIONS = [\".avi\", \".mp4\"];\n\nconst 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])?)*$/;\n\nexport function buildStringProperty({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): Property {\n\n let stringProperty: Property = {\n dataType: \"string\",\n\n };\n\n if (valuesResult) {\n\n const totalEntriesCount = valuesResult.values.length;\n const totalValues = Array.from(valuesResult.valuesCount.keys()).length;\n\n const config: Partial<StringProperty> = {};\n\n const probablyAURL = valuesResult.values\n .filter((value) => typeof value === \"string\" &&\n value.toString().startsWith(\"http\")).length > totalDocsCount / 3 * 2;\n if (probablyAURL) {\n config.url = true;\n }\n\n const probablyAnEmail = valuesResult.values\n .filter((value) => typeof value === \"string\" &&\n emailRegEx.test(value)).length > totalDocsCount / 3 * 2;\n if (probablyAnEmail) {\n config.email = true;\n }\n\n const probablyUserIds = valuesResult.values\n .filter((value) => typeof value === \"string\" && value.length === 28 && !value.includes(\" \"))\n .length > totalDocsCount / 3 * 2;\n if (probablyUserIds)\n config.readOnly = true;\n\n if (!probablyAnEmail &&\n !probablyAURL &&\n !probablyUserIds &&\n !probablyAURL &&\n totalValues < totalEntriesCount / 3\n ) {\n const enumValues = extractEnumFromValues(Array.from(valuesResult.valuesCount.keys()));\n\n if (Object.keys(enumValues).length > 1)\n config.enumValues = enumValues;\n }\n\n // regular string\n if (!probablyAnEmail &&\n !probablyAURL &&\n !probablyUserIds &&\n !probablyAURL &&\n !config.enumValues) {\n const fileType = probableFileType(valuesResult, totalDocsCount);\n if (fileType) {\n config.storage = {\n acceptedFiles: [fileType as FileType],\n storagePath: findCommonInitialStringInPath(valuesResult) ?? \"/\"\n };\n }\n }\n\n if (Object.keys(config).length > 0)\n stringProperty = {\n ...stringProperty,\n ...config,\n editable: true\n };\n }\n\n return stringProperty;\n}\n\n// TODO: support returning multiple types\nfunction probableFileType(valuesCount: ValuesCountEntry, totalDocsCount: number): boolean | FileType {\n const probablyAnImage = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n IMAGE_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const probablyAudio = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n AUDIO_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const probablyVideo = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n VIDEO_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const fileType: boolean | FileType = probablyAnImage\n ? \"image/*\"\n : probablyAudio\n ? \"audio/*\"\n : probablyVideo ? \"video/*\" : false;\n return fileType;\n}\n","import { InferencePropertyBuilderProps } from \"../types\";\nimport { PropertyValidationSchema } from \"../cms_types\";\n\nexport function buildValidation({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): PropertyValidationSchema | undefined {\n\n if (valuesResult) {\n const totalEntriesCount = valuesResult.values.length;\n if (totalDocsCount === totalEntriesCount)\n return {\n required: true\n }\n }\n\n return undefined;\n}\n","import { InferencePropertyBuilderProps } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { Property } from \"../cms_types\";\n\nexport function buildReferenceProperty({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): Property {\n\n const property: Property = {\n dataType: \"reference\",\n path: findCommonInitialStringInPath(valuesResult) ?? \"!!!FIX_ME!!!\",\n editable: true\n };\n\n return property;\n}\n","import {\n InferencePropertyBuilderProps,\n TypesCount,\n TypesCountRecord,\n ValuesCountEntry,\n ValuesCountRecord\n} from \"./types\";\nimport { buildStringProperty } from \"./builders/string_property_builder\";\nimport { buildValidation } from \"./builders/validation_builder\";\nimport { buildReferenceProperty } from \"./builders/reference_property_builder\";\nimport { extractEnumFromValues, mergeDeep, resolveEnumValues } from \"./util\";\nimport { DataType, EnumValues, Properties, Property, StringProperty } from \"./cms_types\";\n\nexport type InferenceTypeBuilder = (value: any) => DataType;\n\nexport async function buildEntityPropertiesFromData(\n data: object[],\n getType: InferenceTypeBuilder\n): Promise<Properties> {\n const typesCount: TypesCountRecord = {};\n const valuesCount: ValuesCountRecord = {};\n if (data) {\n data.forEach((entry) => {\n if (entry) {\n Object.entries(entry).forEach(([key, value]) => {\n if (key.startsWith(\"_\")) return; // Ignore properties starting with _\n increaseMapTypeCount(typesCount, key, value, getType);\n increaseValuesCount(valuesCount, key, value, getType);\n });\n }\n });\n }\n return buildPropertiesFromCount(data.length, typesCount, valuesCount);\n}\n\nexport function buildPropertyFromData(\n data: any[],\n property: Property,\n getType: InferenceTypeBuilder\n): Property {\n const typesCount = {};\n const valuesCount: ValuesCountRecord = {};\n if (data) {\n data.forEach((entry) => {\n increaseTypeCount(property.dataType, typesCount, entry, getType);\n increaseValuesCount(valuesCount, \"inferred_prop\", entry, getType);\n });\n }\n const enumValues = \"enumValues\" in property ? resolveEnumValues(property[\"enumValues\"] as EnumValues) : undefined;\n if (enumValues) {\n const newEnumValues = extractEnumFromValues(Array.from(valuesCount[\"inferred_prop\"].valuesCount.keys()));\n return {\n ...property,\n enumValues: [...newEnumValues, ...enumValues]\n } as StringProperty;\n }\n const generatedProperty = buildPropertyFromCount(\n \"inferred_prop\",\n data.length,\n property.dataType,\n typesCount,\n valuesCount[\"inferred_prop\"]\n );\n return mergeDeep(generatedProperty, property);\n}\n\nexport function buildPropertiesOrder(\n properties: Properties,\n propertiesOrder?: string[],\n priorityKeys?: string[]\n): string[] {\n const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());\n\n function propOrder(s: string) {\n const k = s.toLowerCase();\n if (lowerCasePriorityKeys.includes(k)) return 4;\n if (k === \"title\" || k === \"name\") return 3;\n if (k.includes(\"title\") || k.includes(\"name\")) return 2;\n if (k.includes(\"image\") || k.includes(\"picture\")) return 1;\n return 0;\n }\n\n const keys = propertiesOrder ?? Object.keys(properties);\n keys.sort(); // alphabetically\n keys.sort((a, b) => {\n return propOrder(b) - propOrder(a);\n });\n return keys;\n}\n\n/**\n * @param type\n * @param typesCount\n * @param fieldValue\n * @param getType\n */\nfunction increaseTypeCount(\n type: DataType,\n typesCount: TypesCount,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (type === \"map\") {\n if (fieldValue) {\n let mapTypesCount = typesCount[type];\n if (!mapTypesCount) {\n mapTypesCount = {};\n typesCount[type] = mapTypesCount;\n }\n Object.entries(fieldValue).forEach(([key, value]) => {\n increaseMapTypeCount(mapTypesCount as TypesCountRecord, key, value, getType);\n });\n }\n } else if (type === \"array\") {\n let arrayTypesCount = typesCount[type];\n if (!arrayTypesCount) {\n arrayTypesCount = {};\n typesCount[type] = arrayTypesCount;\n }\n if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {\n const arrayType = getMostProbableTypeInArray(fieldValue, getType);\n if (arrayType === \"map\") {\n let mapTypesCount = arrayTypesCount[arrayType];\n if (!mapTypesCount) {\n mapTypesCount = {};\n }\n fieldValue.forEach((value) => {\n if (value && typeof value === \"object\" && !Array.isArray(value)) { // Ensure value is an object for Object.entries\n Object.entries(value).forEach(([key, v]) =>\n increaseMapTypeCount(mapTypesCount, key, v, getType)\n );\n }\n });\n arrayTypesCount[arrayType] = mapTypesCount;\n } else {\n if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;\n else (arrayTypesCount[arrayType] as number)++;\n }\n }\n } else {\n if (!typesCount[type]) typesCount[type] = 1;\n else (typesCount[type] as number)++;\n }\n}\n\nfunction increaseMapTypeCount(\n typesCountRecord: TypesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (key.startsWith(\"_\")) return; // Ignore properties starting with _\n\n let typesCount: TypesCount = typesCountRecord[key];\n if (!typesCount) {\n typesCount = {};\n typesCountRecord[key] = typesCount;\n }\n\n if (fieldValue != null) {\n // Check that fieldValue is not null or undefined before proceeding\n const type = getType(fieldValue);\n increaseTypeCount(type, typesCount, fieldValue, getType);\n }\n}\n\nfunction increaseValuesCount(\n typeValuesRecord: ValuesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (key.startsWith(\"_\")) return; // Ignore properties starting with _\n\n const dataType = getType(fieldValue);\n\n let valuesRecord: {\n values: any[];\n valuesCount: Map<any, number>;\n map?: ValuesCountRecord;\n } = typeValuesRecord[key];\n\n if (!valuesRecord) {\n valuesRecord = {\n values: [],\n valuesCount: new Map()\n };\n typeValuesRecord[key] = valuesRecord;\n }\n\n if (dataType === \"map\") {\n let mapValuesRecord: ValuesCountRecord | undefined = valuesRecord.map;\n if (!mapValuesRecord) {\n mapValuesRecord = {};\n valuesRecord.map = mapValuesRecord;\n }\n if (fieldValue)\n Object.entries(fieldValue).forEach(([subKey, value]) =>\n increaseValuesCount(mapValuesRecord as ValuesCountRecord, subKey, value, getType)\n );\n } else if (dataType === \"array\") {\n if (Array.isArray(fieldValue)) {\n fieldValue.forEach((value) => {\n valuesRecord.values.push(value);\n valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);\n });\n }\n } else {\n if (fieldValue !== null && fieldValue !== undefined) {\n valuesRecord.values.push(fieldValue);\n valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);\n }\n }\n}\n\nfunction getHighestTypesCount(typesCount: TypesCount): number {\n let highestCount = 0;\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue = 0;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n }\n });\n\n return highestCount;\n}\n\nfunction getHighestRecordCount(record: TypesCountRecord): number {\n return Object.entries(record)\n .map(([key, typesCount]) => getHighestTypesCount(typesCount))\n .reduce((a, b) => Math.max(a, b), 0);\n}\n\nfunction getMostProbableType(typesCount: TypesCount): DataType {\n let highestCount = -1;\n let probableType: DataType = \"string\"; // default\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n probableType = type as DataType;\n }\n });\n return probableType;\n}\n\nfunction buildPropertyFromCount(\n key: string,\n totalDocsCount: number,\n mostProbableType: DataType,\n typesCount: TypesCount,\n valuesResult?: ValuesCountEntry\n): Property {\n let title: string | undefined;\n\n if (key) {\n title = formatString(key.toLowerCase());\n }\n\n let result: Property | undefined = undefined;\n if (mostProbableType === \"map\") {\n const highVariability = checkTypesCountHighVariability(typesCount);\n if (highVariability) {\n result = {\n dataType: \"map\",\n name: title,\n keyValue: true,\n properties: {}\n };\n }\n const properties = buildPropertiesFromCount(\n totalDocsCount,\n typesCount.map as TypesCountRecord,\n valuesResult ? valuesResult.mapValues : undefined\n );\n result = {\n dataType: \"map\",\n name: title,\n properties\n };\n } else if (mostProbableType === \"array\") {\n const arrayTypesCount = typesCount.array as TypesCount;\n const arrayMostProbableType = getMostProbableType(arrayTypesCount);\n const of = buildPropertyFromCount(\n key,\n totalDocsCount,\n arrayMostProbableType,\n arrayTypesCount,\n valuesResult\n );\n result = {\n dataType: \"array\",\n name: title,\n of\n };\n }\n\n if (!result) {\n const propertyProps: InferencePropertyBuilderProps = {\n name: key,\n totalDocsCount,\n valuesResult\n };\n if (mostProbableType === \"string\") {\n result = buildStringProperty(propertyProps);\n } else if (mostProbableType === \"reference\") {\n result = buildReferenceProperty(propertyProps);\n } else {\n result = {\n dataType: mostProbableType\n } as Property;\n }\n\n if (title) {\n result.name = title;\n }\n\n const validation = buildValidation(propertyProps);\n if (validation) {\n result.validation = validation;\n }\n }\n\n return {\n ...result,\n editable: true\n };\n}\n\nfunction buildPropertiesFromCount(\n totalDocsCount: number,\n typesCountRecord: TypesCountRecord,\n valuesCountRecord?: ValuesCountRecord\n): Properties {\n const res: Properties = {};\n Object.entries(typesCountRecord).forEach(([key, typesCount]) => {\n const mostProbableType = getMostProbableType(typesCount);\n res[key] = buildPropertyFromCount(\n key,\n totalDocsCount,\n mostProbableType,\n typesCount,\n valuesCountRecord ? valuesCountRecord[key] : undefined\n );\n });\n return res;\n}\n\nfunction countMaxDocumentsUnder(typesCount: TypesCount) {\n let count = 0;\n Object.entries(typesCount).forEach(([type, value]) => {\n if (typeof value === \"object\") {\n count = Math.max(count, countMaxDocumentsUnder(value as TypesCountRecord));\n } else {\n count = Math.max(count, value as number);\n }\n });\n return count;\n}\n\nfunction getMostProbableTypeInArray(\n array: any[],\n getType: InferenceTypeBuilder\n): DataType {\n const typesCount: TypesCount = {};\n array.forEach((value) => {\n increaseTypeCount(getType(value), typesCount, value, getType);\n });\n return getMostProbableType(typesCount);\n}\n\nfunction checkTypesCountHighVariability(typesCount: TypesCount) {\n const maxCount = countMaxDocumentsUnder(typesCount);\n let keysWithFewValues = 0;\n Object.entries(typesCount.map ?? {}).forEach(([key, value]) => {\n const count = countMaxDocumentsUnder(value);\n if (count < maxCount / 3) {\n keysWithFewValues++;\n }\n });\n return keysWithFewValues / Object.entries(typesCount.map ?? {}).length > 0.5;\n}\n\nfunction formatString(input: string): string {\n const normalized = input\n .replace(/[_-]+/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .toLowerCase();\n\n // Split the normalized string into words\n const words = normalized.split(\" \");\n\n // Capitalize the first letter of each word and join them with a space\n const formatted = words\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n\n return formatted;\n}\n\nexport function inferTypeFromValue(value: any): DataType {\n if (value === null || value === undefined) return \"string\";\n if (typeof value === \"string\") return \"string\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (Array.isArray(value)) return \"array\";\n if (typeof value === \"object\") return \"map\";\n return \"string\";\n}\n"],"names":[],"mappings":"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"}
@@ -170,6 +170,7 @@
170
170
  data.forEach((entry) => {
171
171
  if (entry) {
172
172
  Object.entries(entry).forEach(([key, value]) => {
173
+ if (key.startsWith("_")) return;
173
174
  increaseMapTypeCount(typesCount, key, value, getType);
174
175
  increaseValuesCount(valuesCount, key, value, getType);
175
176
  });
@@ -247,9 +248,11 @@
247
248
  mapTypesCount = {};
248
249
  }
249
250
  fieldValue.forEach((value) => {
250
- Object.entries(value).forEach(
251
- ([key, v]) => increaseMapTypeCount(mapTypesCount, key, v, getType)
252
- );
251
+ if (value && typeof value === "object" && !Array.isArray(value)) {
252
+ Object.entries(value).forEach(
253
+ ([key, v]) => increaseMapTypeCount(mapTypesCount, key, v, getType)
254
+ );
255
+ }
253
256
  });
254
257
  arrayTypesCount[arrayType] = mapTypesCount;
255
258
  } else {
@@ -263,6 +266,7 @@
263
266
  }
264
267
  }
265
268
  function increaseMapTypeCount(typesCountRecord, key, fieldValue, getType) {
269
+ if (key.startsWith("_")) return;
266
270
  let typesCount = typesCountRecord[key];
267
271
  if (!typesCount) {
268
272
  typesCount = {};
@@ -274,6 +278,7 @@
274
278
  }
275
279
  }
276
280
  function increaseValuesCount(typeValuesRecord, key, fieldValue, getType) {
281
+ if (key.startsWith("_")) return;
277
282
  const dataType = getType(fieldValue);
278
283
  let valuesRecord = typeValuesRecord[key];
279
284
  if (!valuesRecord) {
@@ -291,7 +296,7 @@
291
296
  }
292
297
  if (fieldValue)
293
298
  Object.entries(fieldValue).forEach(
294
- ([key2, value]) => increaseValuesCount(mapValuesRecord, key2, value, getType)
299
+ ([subKey, value]) => increaseValuesCount(mapValuesRecord, subKey, value, getType)
295
300
  );
296
301
  } else if (dataType === "array") {
297
302
  if (Array.isArray(fieldValue)) {
@@ -301,7 +306,7 @@
301
306
  });
302
307
  }
303
308
  } else {
304
- if (fieldValue) {
309
+ if (fieldValue !== null && fieldValue !== void 0) {
305
310
  valuesRecord.values.push(fieldValue);
306
311
  valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);
307
312
  }
@@ -466,6 +471,7 @@
466
471
  return formatted;
467
472
  }
468
473
  function inferTypeFromValue(value) {
474
+ if (value === null || value === void 0) return "string";
469
475
  if (typeof value === "string") return "string";
470
476
  if (typeof value === "number") return "number";
471
477
  if (typeof value === "boolean") return "boolean";
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.cjs","sources":["../src/strings.ts","../src/util.ts","../src/builders/string_property_builder.ts","../src/builders/validation_builder.ts","../src/builders/reference_property_builder.ts","../src/collection_builder.ts"],"sourcesContent":["import { ValuesCountEntry } from \"./types\";\n\nexport function findCommonInitialStringInPath(valuesCount?: ValuesCountEntry) {\n\n if (!valuesCount) return undefined;\n\n function getPath(value: any) {\n if (typeof value === \"string\") return value;\n else if (value?.type === \"document\" && value.path) return value.path;\n else return undefined;\n }\n\n const strings: string[] = valuesCount.values.map((v) => getPath(v)).filter(v => !!v) as string[];\n const pathWithSlash = strings.find((s) => s.includes(\"/\"));\n if (!pathWithSlash)\n return undefined;\n\n const searchedPath = pathWithSlash.substr(0, pathWithSlash.lastIndexOf(\"/\"));\n\n const yep = valuesCount.values\n .filter((value) => {\n const path = getPath(value);\n if (!path) return false;\n return path.startsWith(searchedPath)\n }).length > valuesCount.values.length / 3 * 2;\n\n return yep ? searchedPath : undefined;\n\n}\n\nexport function removeInitialAndTrailingSlashes(s: string): string {\n return removeInitialSlash(removeTrailingSlash(s));\n}\n\nexport function removeInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s.slice(1);\n else return s;\n}\n\nexport function removeTrailingSlash(s: string) {\n if (s.endsWith(\"/\"))\n return s.slice(0, -1);\n else return s;\n}\n","import { EnumValueConfig, EnumValues } from \"./cms_types\";\n\nexport function extractEnumFromValues(values: unknown[]) {\n if (!Array.isArray(values)) {\n return [];\n }\n const enumValues = values\n .map((value) => {\n if (typeof value === \"string\") {\n return ({ id: value, label: unslugify(value) });\n } else\n return null;\n }).filter(Boolean) as Array<{ id: string, label: string }>;\n enumValues.sort((a, b) => a.label.localeCompare(b.label));\n return enumValues;\n}\n\nexport function unslugify(slug?: string): string {\n if (!slug) return \"\";\n if (slug.includes(\"-\") || slug.includes(\"_\") || !slug.includes(\" \")) {\n const result = slug.replace(/[-_]/g, \" \");\n return result.replace(/\\w\\S*/g, function (txt) {\n return txt.charAt(0).toUpperCase() + txt.substr(1);\n }).trim();\n } else {\n return slug.trim();\n }\n}\n\nexport function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined {\n if (typeof input === \"object\") {\n return Object.entries(input).map(([id, value]) =>\n (typeof value === \"string\"\n ? {\n id,\n label: value\n }\n : value));\n } else if (Array.isArray(input)) {\n return input as EnumValueConfig[];\n } else {\n return undefined;\n }\n}\n\nexport function mergeDeep<T extends Record<any, any>, U extends Record<any, any>>(target: T, source: U, ignoreUndefined: boolean = false): T & U {\n const targetIsObject = isObject(target);\n const output = targetIsObject ? { ...target } : target;\n if (targetIsObject && isObject(source)) {\n Object.keys(source).forEach(key => {\n const sourceElement = source[key];\n // Skip undefined values when ignoreUndefined is true\n if (ignoreUndefined && sourceElement === undefined) {\n return;\n }\n if (sourceElement instanceof Date) {\n // Assign a new Date instance with the same time value\n Object.assign(output, { [key]: new Date(sourceElement.getTime()) });\n } else if (isObject(sourceElement)) {\n if (!(key in target))\n Object.assign(output, { [key]: sourceElement });\n else\n (output as any)[key] = mergeDeep((target as any)[key], sourceElement);\n } else {\n Object.assign(output, { [key]: sourceElement });\n }\n });\n }\n return output as T;\n}\n\nexport function isObject(item: any) {\n return item && typeof item === \"object\" && !Array.isArray(item);\n}\n\n\n","import { InferencePropertyBuilderProps, ValuesCountEntry } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { extractEnumFromValues } from \"../util\";\nimport { FileType, Property, StringProperty } from \"../cms_types\";\n\nconst IMAGE_EXTENSIONS = [\".jpg\", \".jpeg\", \".png\", \".webp\", \".gif\", \".avif\"];\nconst AUDIO_EXTENSIONS = [\".mp3\", \".ogg\", \".opus\", \".aac\"];\nconst VIDEO_EXTENSIONS = [\".avi\", \".mp4\"];\n\nconst 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])?)*$/;\n\nexport function buildStringProperty({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): Property {\n\n let stringProperty: Property = {\n dataType: \"string\",\n\n };\n\n if (valuesResult) {\n\n const totalEntriesCount = valuesResult.values.length;\n const totalValues = Array.from(valuesResult.valuesCount.keys()).length;\n\n const config: Partial<StringProperty> = {};\n\n const probablyAURL = valuesResult.values\n .filter((value) => typeof value === \"string\" &&\n value.toString().startsWith(\"http\")).length > totalDocsCount / 3 * 2;\n if (probablyAURL) {\n config.url = true;\n }\n\n const probablyAnEmail = valuesResult.values\n .filter((value) => typeof value === \"string\" &&\n emailRegEx.test(value)).length > totalDocsCount / 3 * 2;\n if (probablyAnEmail) {\n config.email = true;\n }\n\n const probablyUserIds = valuesResult.values\n .filter((value) => typeof value === \"string\" && value.length === 28 && !value.includes(\" \"))\n .length > totalDocsCount / 3 * 2;\n if (probablyUserIds)\n config.readOnly = true;\n\n if (!probablyAnEmail &&\n !probablyAURL &&\n !probablyUserIds &&\n !probablyAURL &&\n totalValues < totalEntriesCount / 3\n ) {\n const enumValues = extractEnumFromValues(Array.from(valuesResult.valuesCount.keys()));\n\n if (Object.keys(enumValues).length > 1)\n config.enumValues = enumValues;\n }\n\n // regular string\n if (!probablyAnEmail &&\n !probablyAURL &&\n !probablyUserIds &&\n !probablyAURL &&\n !config.enumValues) {\n const fileType = probableFileType(valuesResult, totalDocsCount);\n if (fileType) {\n config.storage = {\n acceptedFiles: [fileType as FileType],\n storagePath: findCommonInitialStringInPath(valuesResult) ?? \"/\"\n };\n }\n }\n\n if (Object.keys(config).length > 0)\n stringProperty = {\n ...stringProperty,\n ...config,\n editable: true\n };\n }\n\n return stringProperty;\n}\n\n// TODO: support returning multiple types\nfunction probableFileType(valuesCount: ValuesCountEntry, totalDocsCount: number): boolean | FileType {\n const probablyAnImage = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n IMAGE_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const probablyAudio = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n AUDIO_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const probablyVideo = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n VIDEO_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const fileType: boolean | FileType = probablyAnImage\n ? \"image/*\"\n : probablyAudio\n ? \"audio/*\"\n : probablyVideo ? \"video/*\" : false;\n return fileType;\n}\n","import { InferencePropertyBuilderProps } from \"../types\";\nimport { PropertyValidationSchema } from \"../cms_types\";\n\nexport function buildValidation({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): PropertyValidationSchema | undefined {\n\n if (valuesResult) {\n const totalEntriesCount = valuesResult.values.length;\n if (totalDocsCount === totalEntriesCount)\n return {\n required: true\n }\n }\n\n return undefined;\n}\n","import { InferencePropertyBuilderProps } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { Property } from \"../cms_types\";\n\nexport function buildReferenceProperty({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): Property {\n\n const property: Property = {\n dataType: \"reference\",\n path: findCommonInitialStringInPath(valuesResult) ?? \"!!!FIX_ME!!!\",\n editable: true\n };\n\n return property;\n}\n","import {\n InferencePropertyBuilderProps,\n TypesCount,\n TypesCountRecord,\n ValuesCountEntry,\n ValuesCountRecord\n} from \"./types\";\nimport { buildStringProperty } from \"./builders/string_property_builder\";\nimport { buildValidation } from \"./builders/validation_builder\";\nimport { buildReferenceProperty } from \"./builders/reference_property_builder\";\nimport { extractEnumFromValues, mergeDeep, resolveEnumValues } from \"./util\";\nimport { DataType, EnumValues, Properties, PropertiesOrBuilders, Property, StringProperty } from \"./cms_types\";\n\nexport type InferenceTypeBuilder = (value: any) => DataType;\n\nexport async function buildEntityPropertiesFromData(\n data: object[],\n getType: InferenceTypeBuilder\n): Promise<Properties> {\n const typesCount: TypesCountRecord = {};\n const valuesCount: ValuesCountRecord = {};\n if (data) {\n data.forEach((entry) => {\n if (entry) {\n Object.entries(entry).forEach(([key, value]) => {\n increaseMapTypeCount(typesCount, key, value, getType);\n increaseValuesCount(valuesCount, key, value, getType);\n });\n }\n });\n }\n return buildPropertiesFromCount(data.length, typesCount, valuesCount);\n}\n\nexport function buildPropertyFromData(\n data: any[],\n property: Property,\n getType: InferenceTypeBuilder\n): Property {\n const typesCount = {};\n const valuesCount: ValuesCountRecord = {};\n if (data) {\n data.forEach((entry) => {\n increaseTypeCount(property.dataType, typesCount, entry, getType);\n increaseValuesCount(valuesCount, \"inferred_prop\", entry, getType);\n });\n }\n const enumValues = \"enumValues\" in property ? resolveEnumValues(property[\"enumValues\"] as EnumValues) : undefined;\n if (enumValues) {\n const newEnumValues = extractEnumFromValues(Array.from(valuesCount[\"inferred_prop\"].valuesCount.keys()));\n return {\n ...property,\n enumValues: [...newEnumValues, ...enumValues]\n } as StringProperty;\n }\n const generatedProperty = buildPropertyFromCount(\n \"inferred_prop\",\n data.length,\n property.dataType,\n typesCount,\n valuesCount[\"inferred_prop\"]\n );\n return mergeDeep(generatedProperty, property);\n}\n\nexport function buildPropertiesOrder(\n properties: PropertiesOrBuilders,\n propertiesOrder?: string[],\n priorityKeys?: string[]\n): string[] {\n const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());\n\n function propOrder(s: string) {\n const k = s.toLowerCase();\n if (lowerCasePriorityKeys.includes(k)) return 4;\n if (k === \"title\" || k === \"name\") return 3;\n if (k.includes(\"title\") || k.includes(\"name\")) return 2;\n if (k.includes(\"image\") || k.includes(\"picture\")) return 1;\n return 0;\n }\n\n const keys = propertiesOrder ?? Object.keys(properties);\n keys.sort(); // alphabetically\n keys.sort((a, b) => {\n return propOrder(b) - propOrder(a);\n });\n return keys;\n}\n\n/**\n * @param type\n * @param typesCount\n * @param fieldValue\n * @param getType\n */\nfunction increaseTypeCount(\n type: DataType,\n typesCount: TypesCount,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (type === \"map\") {\n if (fieldValue) {\n let mapTypesCount = typesCount[type];\n if (!mapTypesCount) {\n mapTypesCount = {};\n typesCount[type] = mapTypesCount;\n }\n Object.entries(fieldValue).forEach(([key, value]) => {\n increaseMapTypeCount(mapTypesCount as TypesCountRecord, key, value, getType);\n });\n }\n } else if (type === \"array\") {\n let arrayTypesCount = typesCount[type];\n if (!arrayTypesCount) {\n arrayTypesCount = {};\n typesCount[type] = arrayTypesCount;\n }\n if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {\n const arrayType = getMostProbableTypeInArray(fieldValue, getType);\n if (arrayType === \"map\") {\n let mapTypesCount = arrayTypesCount[arrayType];\n if (!mapTypesCount) {\n mapTypesCount = {};\n }\n fieldValue.forEach((value) => {\n Object.entries(value).forEach(([key, v]) =>\n increaseMapTypeCount(mapTypesCount, key, v, getType)\n );\n });\n arrayTypesCount[arrayType] = mapTypesCount;\n } else {\n if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;\n else (arrayTypesCount[arrayType] as number)++;\n }\n }\n } else {\n if (!typesCount[type]) typesCount[type] = 1;\n else (typesCount[type] as number)++;\n }\n}\n\nfunction increaseMapTypeCount(\n typesCountRecord: TypesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n let typesCount: TypesCount = typesCountRecord[key];\n if (!typesCount) {\n typesCount = {};\n typesCountRecord[key] = typesCount;\n }\n\n if (fieldValue != null) {\n // Check that fieldValue is not null or undefined before proceeding\n const type = getType(fieldValue);\n increaseTypeCount(type, typesCount, fieldValue, getType);\n }\n}\n\nfunction increaseValuesCount(\n typeValuesRecord: ValuesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n const dataType = getType(fieldValue);\n\n let valuesRecord: {\n values: any[];\n valuesCount: Map<any, number>;\n map?: ValuesCountRecord;\n } = typeValuesRecord[key];\n\n if (!valuesRecord) {\n valuesRecord = {\n values: [],\n valuesCount: new Map()\n };\n typeValuesRecord[key] = valuesRecord;\n }\n\n if (dataType === \"map\") {\n let mapValuesRecord: ValuesCountRecord | undefined = valuesRecord.map;\n if (!mapValuesRecord) {\n mapValuesRecord = {};\n valuesRecord.map = mapValuesRecord;\n }\n if (fieldValue)\n Object.entries(fieldValue).forEach(([key, value]) =>\n increaseValuesCount(mapValuesRecord as ValuesCountRecord, key, value, getType)\n );\n } else if (dataType === \"array\") {\n if (Array.isArray(fieldValue)) {\n fieldValue.forEach((value) => {\n valuesRecord.values.push(value);\n valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);\n });\n }\n } else {\n if (fieldValue) {\n valuesRecord.values.push(fieldValue);\n valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);\n }\n }\n}\n\nfunction getHighestTypesCount(typesCount: TypesCount): number {\n let highestCount = 0;\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue = 0;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n }\n });\n\n return highestCount;\n}\n\nfunction getHighestRecordCount(record: TypesCountRecord): number {\n return Object.entries(record)\n .map(([key, typesCount]) => getHighestTypesCount(typesCount))\n .reduce((a, b) => Math.max(a, b), 0);\n}\n\nfunction getMostProbableType(typesCount: TypesCount): DataType {\n let highestCount = -1;\n let probableType: DataType = \"string\"; // default\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n probableType = type as DataType;\n }\n });\n return probableType;\n}\n\nfunction buildPropertyFromCount(\n key: string,\n totalDocsCount: number,\n mostProbableType: DataType,\n typesCount: TypesCount,\n valuesResult?: ValuesCountEntry\n): Property {\n let title: string | undefined;\n\n if (key) {\n title = formatString(key.toLowerCase());\n }\n\n let result: Property | undefined = undefined;\n if (mostProbableType === \"map\") {\n const highVariability = checkTypesCountHighVariability(typesCount);\n if (highVariability) {\n result = {\n dataType: \"map\",\n name: title,\n keyValue: true,\n properties: {}\n };\n }\n const properties = buildPropertiesFromCount(\n totalDocsCount,\n typesCount.map as TypesCountRecord,\n valuesResult ? valuesResult.mapValues : undefined\n );\n result = {\n dataType: \"map\",\n name: title,\n properties\n };\n } else if (mostProbableType === \"array\") {\n const arrayTypesCount = typesCount.array as TypesCount;\n const arrayMostProbableType = getMostProbableType(arrayTypesCount);\n const of = buildPropertyFromCount(\n key,\n totalDocsCount,\n arrayMostProbableType,\n arrayTypesCount,\n valuesResult\n );\n result = {\n dataType: \"array\",\n name: title,\n of\n };\n }\n\n if (!result) {\n const propertyProps: InferencePropertyBuilderProps = {\n name: key,\n totalDocsCount,\n valuesResult\n };\n if (mostProbableType === \"string\") {\n result = buildStringProperty(propertyProps);\n } else if (mostProbableType === \"reference\") {\n result = buildReferenceProperty(propertyProps);\n } else {\n result = {\n dataType: mostProbableType\n } as Property;\n }\n\n if (title) {\n result.name = title;\n }\n\n const validation = buildValidation(propertyProps);\n if (validation) {\n result.validation = validation;\n }\n }\n\n return {\n ...result,\n editable: true\n };\n}\n\nfunction buildPropertiesFromCount(\n totalDocsCount: number,\n typesCountRecord: TypesCountRecord,\n valuesCountRecord?: ValuesCountRecord\n): Properties {\n const res: Properties = {};\n Object.entries(typesCountRecord).forEach(([key, typesCount]) => {\n const mostProbableType = getMostProbableType(typesCount);\n res[key] = buildPropertyFromCount(\n key,\n totalDocsCount,\n mostProbableType,\n typesCount,\n valuesCountRecord ? valuesCountRecord[key] : undefined\n );\n });\n return res;\n}\n\nfunction countMaxDocumentsUnder(typesCount: TypesCount) {\n let count = 0;\n Object.entries(typesCount).forEach(([type, value]) => {\n if (typeof value === \"object\") {\n count = Math.max(count, countMaxDocumentsUnder(value as TypesCountRecord));\n } else {\n count = Math.max(count, value as number);\n }\n });\n return count;\n}\n\nfunction getMostProbableTypeInArray(\n array: any[],\n getType: InferenceTypeBuilder\n): DataType {\n const typesCount: TypesCount = {};\n array.forEach((value) => {\n increaseTypeCount(getType(value), typesCount, value, getType);\n });\n return getMostProbableType(typesCount);\n}\n\nfunction checkTypesCountHighVariability(typesCount: TypesCount) {\n const maxCount = countMaxDocumentsUnder(typesCount);\n let keysWithFewValues = 0;\n Object.entries(typesCount.map ?? {}).forEach(([key, value]) => {\n const count = countMaxDocumentsUnder(value);\n if (count < maxCount / 3) {\n keysWithFewValues++;\n }\n });\n return keysWithFewValues / Object.entries(typesCount.map ?? {}).length > 0.5;\n}\n\nfunction formatString(input: string): string {\n const normalized = input\n .replace(/[_-]+/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .toLowerCase();\n\n // Split the normalized string into words\n const words = normalized.split(\" \");\n\n // Capitalize the first letter of each word and join them with a space\n const formatted = words\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n\n return formatted;\n}\n\nexport function inferTypeFromValue(value: any): DataType {\n if (typeof value === \"string\") return \"string\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (Array.isArray(value)) return \"array\";\n if (typeof value === \"object\") return \"map\";\n return \"string\";\n}\n"],"names":["key"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.cjs","sources":["../src/strings.ts","../src/util.ts","../src/builders/string_property_builder.ts","../src/builders/validation_builder.ts","../src/builders/reference_property_builder.ts","../src/collection_builder.ts"],"sourcesContent":["import { ValuesCountEntry } from \"./types\";\n\nexport function findCommonInitialStringInPath(valuesCount?: ValuesCountEntry) {\n\n if (!valuesCount) return undefined;\n\n function getPath(value: any) {\n if (typeof value === \"string\") return value;\n else if (value?.type === \"document\" && value.path) return value.path;\n else return undefined;\n }\n\n const strings: string[] = valuesCount.values.map((v) => getPath(v)).filter(v => !!v) as string[];\n const pathWithSlash = strings.find((s) => s.includes(\"/\"));\n if (!pathWithSlash)\n return undefined;\n\n const searchedPath = pathWithSlash.substr(0, pathWithSlash.lastIndexOf(\"/\"));\n\n const yep = valuesCount.values\n .filter((value) => {\n const path = getPath(value);\n if (!path) return false;\n return path.startsWith(searchedPath)\n }).length > valuesCount.values.length / 3 * 2;\n\n return yep ? searchedPath : undefined;\n\n}\n\nexport function removeInitialAndTrailingSlashes(s: string): string {\n return removeInitialSlash(removeTrailingSlash(s));\n}\n\nexport function removeInitialSlash(s: string) {\n if (s.startsWith(\"/\"))\n return s.slice(1);\n else return s;\n}\n\nexport function removeTrailingSlash(s: string) {\n if (s.endsWith(\"/\"))\n return s.slice(0, -1);\n else return s;\n}\n","import { EnumValueConfig, EnumValues } from \"./cms_types\";\n\nexport function extractEnumFromValues(values: unknown[]) {\n if (!Array.isArray(values)) {\n return [];\n }\n const enumValues = values\n .map((value) => {\n if (typeof value === \"string\") {\n return ({ id: value, label: unslugify(value) });\n } else\n return null;\n }).filter(Boolean) as Array<{ id: string, label: string }>;\n enumValues.sort((a, b) => a.label.localeCompare(b.label));\n return enumValues;\n}\n\nexport function unslugify(slug?: string): string {\n if (!slug) return \"\";\n if (slug.includes(\"-\") || slug.includes(\"_\") || !slug.includes(\" \")) {\n const result = slug.replace(/[-_]/g, \" \");\n return result.replace(/\\w\\S*/g, function (txt) {\n return txt.charAt(0).toUpperCase() + txt.substr(1);\n }).trim();\n } else {\n return slug.trim();\n }\n}\n\nexport function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined {\n if (typeof input === \"object\") {\n return Object.entries(input).map(([id, value]) =>\n (typeof value === \"string\"\n ? {\n id,\n label: value\n }\n : value));\n } else if (Array.isArray(input)) {\n return input as EnumValueConfig[];\n } else {\n return undefined;\n }\n}\n\nexport function mergeDeep<T extends Record<any, any>, U extends Record<any, any>>(target: T, source: U, ignoreUndefined: boolean = false): T & U {\n const targetIsObject = isObject(target);\n const output = targetIsObject ? { ...target } : target;\n if (targetIsObject && isObject(source)) {\n Object.keys(source).forEach(key => {\n const sourceElement = source[key];\n // Skip undefined values when ignoreUndefined is true\n if (ignoreUndefined && sourceElement === undefined) {\n return;\n }\n if (sourceElement instanceof Date) {\n // Assign a new Date instance with the same time value\n Object.assign(output, { [key]: new Date(sourceElement.getTime()) });\n } else if (isObject(sourceElement)) {\n if (!(key in target))\n Object.assign(output, { [key]: sourceElement });\n else\n (output as any)[key] = mergeDeep((target as any)[key], sourceElement);\n } else {\n Object.assign(output, { [key]: sourceElement });\n }\n });\n }\n return output as T;\n}\n\nexport function isObject(item: any) {\n return item && typeof item === \"object\" && !Array.isArray(item);\n}\n\n\n","import { InferencePropertyBuilderProps, ValuesCountEntry } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { extractEnumFromValues } from \"../util\";\nimport { FileType, Property, StringProperty } from \"../cms_types\";\n\nconst IMAGE_EXTENSIONS = [\".jpg\", \".jpeg\", \".png\", \".webp\", \".gif\", \".avif\"];\nconst AUDIO_EXTENSIONS = [\".mp3\", \".ogg\", \".opus\", \".aac\"];\nconst VIDEO_EXTENSIONS = [\".avi\", \".mp4\"];\n\nconst 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])?)*$/;\n\nexport function buildStringProperty({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): Property {\n\n let stringProperty: Property = {\n dataType: \"string\",\n\n };\n\n if (valuesResult) {\n\n const totalEntriesCount = valuesResult.values.length;\n const totalValues = Array.from(valuesResult.valuesCount.keys()).length;\n\n const config: Partial<StringProperty> = {};\n\n const probablyAURL = valuesResult.values\n .filter((value) => typeof value === \"string\" &&\n value.toString().startsWith(\"http\")).length > totalDocsCount / 3 * 2;\n if (probablyAURL) {\n config.url = true;\n }\n\n const probablyAnEmail = valuesResult.values\n .filter((value) => typeof value === \"string\" &&\n emailRegEx.test(value)).length > totalDocsCount / 3 * 2;\n if (probablyAnEmail) {\n config.email = true;\n }\n\n const probablyUserIds = valuesResult.values\n .filter((value) => typeof value === \"string\" && value.length === 28 && !value.includes(\" \"))\n .length > totalDocsCount / 3 * 2;\n if (probablyUserIds)\n config.readOnly = true;\n\n if (!probablyAnEmail &&\n !probablyAURL &&\n !probablyUserIds &&\n !probablyAURL &&\n totalValues < totalEntriesCount / 3\n ) {\n const enumValues = extractEnumFromValues(Array.from(valuesResult.valuesCount.keys()));\n\n if (Object.keys(enumValues).length > 1)\n config.enumValues = enumValues;\n }\n\n // regular string\n if (!probablyAnEmail &&\n !probablyAURL &&\n !probablyUserIds &&\n !probablyAURL &&\n !config.enumValues) {\n const fileType = probableFileType(valuesResult, totalDocsCount);\n if (fileType) {\n config.storage = {\n acceptedFiles: [fileType as FileType],\n storagePath: findCommonInitialStringInPath(valuesResult) ?? \"/\"\n };\n }\n }\n\n if (Object.keys(config).length > 0)\n stringProperty = {\n ...stringProperty,\n ...config,\n editable: true\n };\n }\n\n return stringProperty;\n}\n\n// TODO: support returning multiple types\nfunction probableFileType(valuesCount: ValuesCountEntry, totalDocsCount: number): boolean | FileType {\n const probablyAnImage = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n IMAGE_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const probablyAudio = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n AUDIO_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const probablyVideo = valuesCount.values\n .filter((value) => typeof value === \"string\" &&\n VIDEO_EXTENSIONS.some((extension) => value.toString().endsWith(extension))).length > totalDocsCount / 3 * 2;\n\n const fileType: boolean | FileType = probablyAnImage\n ? \"image/*\"\n : probablyAudio\n ? \"audio/*\"\n : probablyVideo ? \"video/*\" : false;\n return fileType;\n}\n","import { InferencePropertyBuilderProps } from \"../types\";\nimport { PropertyValidationSchema } from \"../cms_types\";\n\nexport function buildValidation({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): PropertyValidationSchema | undefined {\n\n if (valuesResult) {\n const totalEntriesCount = valuesResult.values.length;\n if (totalDocsCount === totalEntriesCount)\n return {\n required: true\n }\n }\n\n return undefined;\n}\n","import { InferencePropertyBuilderProps } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { Property } from \"../cms_types\";\n\nexport function buildReferenceProperty({\n totalDocsCount,\n valuesResult\n }: InferencePropertyBuilderProps): Property {\n\n const property: Property = {\n dataType: \"reference\",\n path: findCommonInitialStringInPath(valuesResult) ?? \"!!!FIX_ME!!!\",\n editable: true\n };\n\n return property;\n}\n","import {\n InferencePropertyBuilderProps,\n TypesCount,\n TypesCountRecord,\n ValuesCountEntry,\n ValuesCountRecord\n} from \"./types\";\nimport { buildStringProperty } from \"./builders/string_property_builder\";\nimport { buildValidation } from \"./builders/validation_builder\";\nimport { buildReferenceProperty } from \"./builders/reference_property_builder\";\nimport { extractEnumFromValues, mergeDeep, resolveEnumValues } from \"./util\";\nimport { DataType, EnumValues, Properties, Property, StringProperty } from \"./cms_types\";\n\nexport type InferenceTypeBuilder = (value: any) => DataType;\n\nexport async function buildEntityPropertiesFromData(\n data: object[],\n getType: InferenceTypeBuilder\n): Promise<Properties> {\n const typesCount: TypesCountRecord = {};\n const valuesCount: ValuesCountRecord = {};\n if (data) {\n data.forEach((entry) => {\n if (entry) {\n Object.entries(entry).forEach(([key, value]) => {\n if (key.startsWith(\"_\")) return; // Ignore properties starting with _\n increaseMapTypeCount(typesCount, key, value, getType);\n increaseValuesCount(valuesCount, key, value, getType);\n });\n }\n });\n }\n return buildPropertiesFromCount(data.length, typesCount, valuesCount);\n}\n\nexport function buildPropertyFromData(\n data: any[],\n property: Property,\n getType: InferenceTypeBuilder\n): Property {\n const typesCount = {};\n const valuesCount: ValuesCountRecord = {};\n if (data) {\n data.forEach((entry) => {\n increaseTypeCount(property.dataType, typesCount, entry, getType);\n increaseValuesCount(valuesCount, \"inferred_prop\", entry, getType);\n });\n }\n const enumValues = \"enumValues\" in property ? resolveEnumValues(property[\"enumValues\"] as EnumValues) : undefined;\n if (enumValues) {\n const newEnumValues = extractEnumFromValues(Array.from(valuesCount[\"inferred_prop\"].valuesCount.keys()));\n return {\n ...property,\n enumValues: [...newEnumValues, ...enumValues]\n } as StringProperty;\n }\n const generatedProperty = buildPropertyFromCount(\n \"inferred_prop\",\n data.length,\n property.dataType,\n typesCount,\n valuesCount[\"inferred_prop\"]\n );\n return mergeDeep(generatedProperty, property);\n}\n\nexport function buildPropertiesOrder(\n properties: Properties,\n propertiesOrder?: string[],\n priorityKeys?: string[]\n): string[] {\n const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());\n\n function propOrder(s: string) {\n const k = s.toLowerCase();\n if (lowerCasePriorityKeys.includes(k)) return 4;\n if (k === \"title\" || k === \"name\") return 3;\n if (k.includes(\"title\") || k.includes(\"name\")) return 2;\n if (k.includes(\"image\") || k.includes(\"picture\")) return 1;\n return 0;\n }\n\n const keys = propertiesOrder ?? Object.keys(properties);\n keys.sort(); // alphabetically\n keys.sort((a, b) => {\n return propOrder(b) - propOrder(a);\n });\n return keys;\n}\n\n/**\n * @param type\n * @param typesCount\n * @param fieldValue\n * @param getType\n */\nfunction increaseTypeCount(\n type: DataType,\n typesCount: TypesCount,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (type === \"map\") {\n if (fieldValue) {\n let mapTypesCount = typesCount[type];\n if (!mapTypesCount) {\n mapTypesCount = {};\n typesCount[type] = mapTypesCount;\n }\n Object.entries(fieldValue).forEach(([key, value]) => {\n increaseMapTypeCount(mapTypesCount as TypesCountRecord, key, value, getType);\n });\n }\n } else if (type === \"array\") {\n let arrayTypesCount = typesCount[type];\n if (!arrayTypesCount) {\n arrayTypesCount = {};\n typesCount[type] = arrayTypesCount;\n }\n if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {\n const arrayType = getMostProbableTypeInArray(fieldValue, getType);\n if (arrayType === \"map\") {\n let mapTypesCount = arrayTypesCount[arrayType];\n if (!mapTypesCount) {\n mapTypesCount = {};\n }\n fieldValue.forEach((value) => {\n if (value && typeof value === \"object\" && !Array.isArray(value)) { // Ensure value is an object for Object.entries\n Object.entries(value).forEach(([key, v]) =>\n increaseMapTypeCount(mapTypesCount, key, v, getType)\n );\n }\n });\n arrayTypesCount[arrayType] = mapTypesCount;\n } else {\n if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;\n else (arrayTypesCount[arrayType] as number)++;\n }\n }\n } else {\n if (!typesCount[type]) typesCount[type] = 1;\n else (typesCount[type] as number)++;\n }\n}\n\nfunction increaseMapTypeCount(\n typesCountRecord: TypesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (key.startsWith(\"_\")) return; // Ignore properties starting with _\n\n let typesCount: TypesCount = typesCountRecord[key];\n if (!typesCount) {\n typesCount = {};\n typesCountRecord[key] = typesCount;\n }\n\n if (fieldValue != null) {\n // Check that fieldValue is not null or undefined before proceeding\n const type = getType(fieldValue);\n increaseTypeCount(type, typesCount, fieldValue, getType);\n }\n}\n\nfunction increaseValuesCount(\n typeValuesRecord: ValuesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (key.startsWith(\"_\")) return; // Ignore properties starting with _\n\n const dataType = getType(fieldValue);\n\n let valuesRecord: {\n values: any[];\n valuesCount: Map<any, number>;\n map?: ValuesCountRecord;\n } = typeValuesRecord[key];\n\n if (!valuesRecord) {\n valuesRecord = {\n values: [],\n valuesCount: new Map()\n };\n typeValuesRecord[key] = valuesRecord;\n }\n\n if (dataType === \"map\") {\n let mapValuesRecord: ValuesCountRecord | undefined = valuesRecord.map;\n if (!mapValuesRecord) {\n mapValuesRecord = {};\n valuesRecord.map = mapValuesRecord;\n }\n if (fieldValue)\n Object.entries(fieldValue).forEach(([subKey, value]) =>\n increaseValuesCount(mapValuesRecord as ValuesCountRecord, subKey, value, getType)\n );\n } else if (dataType === \"array\") {\n if (Array.isArray(fieldValue)) {\n fieldValue.forEach((value) => {\n valuesRecord.values.push(value);\n valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);\n });\n }\n } else {\n if (fieldValue !== null && fieldValue !== undefined) {\n valuesRecord.values.push(fieldValue);\n valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);\n }\n }\n}\n\nfunction getHighestTypesCount(typesCount: TypesCount): number {\n let highestCount = 0;\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue = 0;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n }\n });\n\n return highestCount;\n}\n\nfunction getHighestRecordCount(record: TypesCountRecord): number {\n return Object.entries(record)\n .map(([key, typesCount]) => getHighestTypesCount(typesCount))\n .reduce((a, b) => Math.max(a, b), 0);\n}\n\nfunction getMostProbableType(typesCount: TypesCount): DataType {\n let highestCount = -1;\n let probableType: DataType = \"string\"; // default\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n probableType = type as DataType;\n }\n });\n return probableType;\n}\n\nfunction buildPropertyFromCount(\n key: string,\n totalDocsCount: number,\n mostProbableType: DataType,\n typesCount: TypesCount,\n valuesResult?: ValuesCountEntry\n): Property {\n let title: string | undefined;\n\n if (key) {\n title = formatString(key.toLowerCase());\n }\n\n let result: Property | undefined = undefined;\n if (mostProbableType === \"map\") {\n const highVariability = checkTypesCountHighVariability(typesCount);\n if (highVariability) {\n result = {\n dataType: \"map\",\n name: title,\n keyValue: true,\n properties: {}\n };\n }\n const properties = buildPropertiesFromCount(\n totalDocsCount,\n typesCount.map as TypesCountRecord,\n valuesResult ? valuesResult.mapValues : undefined\n );\n result = {\n dataType: \"map\",\n name: title,\n properties\n };\n } else if (mostProbableType === \"array\") {\n const arrayTypesCount = typesCount.array as TypesCount;\n const arrayMostProbableType = getMostProbableType(arrayTypesCount);\n const of = buildPropertyFromCount(\n key,\n totalDocsCount,\n arrayMostProbableType,\n arrayTypesCount,\n valuesResult\n );\n result = {\n dataType: \"array\",\n name: title,\n of\n };\n }\n\n if (!result) {\n const propertyProps: InferencePropertyBuilderProps = {\n name: key,\n totalDocsCount,\n valuesResult\n };\n if (mostProbableType === \"string\") {\n result = buildStringProperty(propertyProps);\n } else if (mostProbableType === \"reference\") {\n result = buildReferenceProperty(propertyProps);\n } else {\n result = {\n dataType: mostProbableType\n } as Property;\n }\n\n if (title) {\n result.name = title;\n }\n\n const validation = buildValidation(propertyProps);\n if (validation) {\n result.validation = validation;\n }\n }\n\n return {\n ...result,\n editable: true\n };\n}\n\nfunction buildPropertiesFromCount(\n totalDocsCount: number,\n typesCountRecord: TypesCountRecord,\n valuesCountRecord?: ValuesCountRecord\n): Properties {\n const res: Properties = {};\n Object.entries(typesCountRecord).forEach(([key, typesCount]) => {\n const mostProbableType = getMostProbableType(typesCount);\n res[key] = buildPropertyFromCount(\n key,\n totalDocsCount,\n mostProbableType,\n typesCount,\n valuesCountRecord ? valuesCountRecord[key] : undefined\n );\n });\n return res;\n}\n\nfunction countMaxDocumentsUnder(typesCount: TypesCount) {\n let count = 0;\n Object.entries(typesCount).forEach(([type, value]) => {\n if (typeof value === \"object\") {\n count = Math.max(count, countMaxDocumentsUnder(value as TypesCountRecord));\n } else {\n count = Math.max(count, value as number);\n }\n });\n return count;\n}\n\nfunction getMostProbableTypeInArray(\n array: any[],\n getType: InferenceTypeBuilder\n): DataType {\n const typesCount: TypesCount = {};\n array.forEach((value) => {\n increaseTypeCount(getType(value), typesCount, value, getType);\n });\n return getMostProbableType(typesCount);\n}\n\nfunction checkTypesCountHighVariability(typesCount: TypesCount) {\n const maxCount = countMaxDocumentsUnder(typesCount);\n let keysWithFewValues = 0;\n Object.entries(typesCount.map ?? {}).forEach(([key, value]) => {\n const count = countMaxDocumentsUnder(value);\n if (count < maxCount / 3) {\n keysWithFewValues++;\n }\n });\n return keysWithFewValues / Object.entries(typesCount.map ?? {}).length > 0.5;\n}\n\nfunction formatString(input: string): string {\n const normalized = input\n .replace(/[_-]+/g, \" \")\n .replace(/([a-z])([A-Z])/g, \"$1 $2\")\n .toLowerCase();\n\n // Split the normalized string into words\n const words = normalized.split(\" \");\n\n // Capitalize the first letter of each word and join them with a space\n const formatted = words\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n\n return formatted;\n}\n\nexport function inferTypeFromValue(value: any): DataType {\n if (value === null || value === undefined) return \"string\";\n if (typeof value === \"string\") return \"string\";\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"boolean\") return \"boolean\";\n if (Array.isArray(value)) return \"array\";\n if (typeof value === \"object\") return \"map\";\n return \"string\";\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.0.0-canary.235",
2
+ "version": "3.0.0-canary.239",
3
3
  "type": "module",
4
4
  "name": "@firecms/schema_inference",
5
5
  "access": "public",
@@ -29,5 +29,5 @@
29
29
  "build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
30
30
  "clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
31
31
  },
32
- "gitHead": "d3f4ac352f53c76f2b8631e6d0cccec533dd5826"
32
+ "gitHead": "28e265bdb20ddd0d2eb813e9cbc2c082e17c2c65"
33
33
  }
package/src/cms_types.ts CHANGED
@@ -126,95 +126,6 @@ export type Property<T extends CMSType = any> =
126
126
  T extends Array<CMSType> ? ArrayProperty<T> :
127
127
  T extends Record<string, any> ? MapProperty<T> : any;
128
128
 
129
- /**
130
- * Interface including all common properties of a CMS property
131
- * @group Entity properties
132
- */
133
- export interface BaseProperty<T extends CMSType, CustomProps = any> {
134
-
135
- /**
136
- * Datatype of the property
137
- */
138
- dataType: DataType;
139
-
140
- /**
141
- * Property name (e.g. Product)
142
- */
143
- name?: string;
144
-
145
- /**
146
- * Property description, always displayed under the field
147
- */
148
- description?: string;
149
-
150
- /**
151
- * You can use this prop to reuse a property that has been defined
152
- * in the top level of the CMS in the prop `fields`.
153
- * All the configuration will be taken from the inherited config, and
154
- * overwritten by the current property config.
155
- */
156
- propertyConfig?: string;
157
-
158
- /**
159
- * Longer description of a field, displayed under a popover
160
- */
161
- longDescription?: string;
162
-
163
- /**
164
- * Width in pixels of this column in the collection view. If not set
165
- * the width is inferred based on the other configurations
166
- */
167
- columnWidth?: number;
168
-
169
- /**
170
- * Do not show this property in the collection view
171
- */
172
- hideFromCollection?: boolean;
173
-
174
- /**
175
- * Is this a read only property. When set to true, it gets rendered as a
176
- * preview.
177
- */
178
- readOnly?: boolean;
179
-
180
- /**
181
- * Is this field disabled.
182
- * When set to true, it gets rendered as a
183
- * disabled field. You can also specify a configuration for defining the
184
- * behaviour of disabled properties (including custom messages, clear value on
185
- * disabled or hide the field completely)
186
- */
187
- disabled?: boolean | PropertyDisabledConfig;
188
-
189
- /**
190
- * Rules for validating this property
191
- */
192
- validation?: PropertyValidationSchema;
193
-
194
- /**
195
- * Additional props that are passed to the components defined in `field`
196
- * or in `preview`.
197
- */
198
- customProps?: CustomProps;
199
-
200
- /**
201
- * This value will be set by default for new entities.
202
- */
203
- defaultValue?: T | null;
204
-
205
- /**
206
- * Should this property be editable. If set to true, the user will be able to modify the property and
207
- * save the new config. The saved config will then become the source of truth.
208
- */
209
- editable?: boolean;
210
-
211
- /**
212
- * A number between 0 and 100 that indicates the width of the field in the form view.
213
- * It defaults to 100, but you can set it to 50 to have two fields in the same row.
214
- */
215
- widthPercentage?: number;
216
- }
217
-
218
129
  /**
219
130
  * @group Entity properties
220
131
  */
@@ -282,19 +193,70 @@ export type Properties<M extends Record<string, any> = any> = {
282
193
  [k in keyof M]: Property<M[keyof M]>;
283
194
  };
284
195
 
285
- /**
286
- * @group Entity properties
287
- */
288
- export type PropertyOrBuilder<T extends CMSType = CMSType, M extends Record<string, any> = any> =
289
- Property<T>;
290
196
 
291
197
  /**
198
+ * Interface including all common properties of a CMS property
292
199
  * @group Entity properties
293
200
  */
294
- export type PropertiesOrBuilders<M extends Record<string, any> = any> =
295
- {
296
- [k in keyof M]: PropertyOrBuilder<M[k], M>;
297
- };
201
+ export interface BaseProperty<T extends CMSType> {
202
+
203
+ /**
204
+ * Datatype of the property
205
+ */
206
+ dataType: DataType;
207
+
208
+ /**
209
+ * Property name (e.g. Product)
210
+ */
211
+ name?: string;
212
+
213
+ /**
214
+ * Property description, always displayed under the field
215
+ */
216
+ description?: string;
217
+
218
+ /**
219
+ * Longer description of a field, displayed under a popover
220
+ */
221
+ longDescription?: string;
222
+
223
+ /**
224
+ * Width in pixels of this column in the collection view. If not set
225
+ * the width is inferred based on the other configurations
226
+ */
227
+ columnWidth?: number;
228
+
229
+ /**
230
+ * Do not show this property in the collection view
231
+ */
232
+ hideFromCollection?: boolean;
233
+
234
+ /**
235
+ * Is this a read only property. When set to true, it gets rendered as a
236
+ * preview.
237
+ */
238
+ readOnly?: boolean;
239
+
240
+ /**
241
+ * Is this field disabled.
242
+ * When set to true, it gets rendered as a
243
+ * disabled field. You can also specify a configuration for defining the
244
+ * behaviour of disabled properties (including custom messages, clear value on
245
+ * disabled or hide the field completely)
246
+ */
247
+ disabled?: boolean | PropertyDisabledConfig;
248
+
249
+ /**
250
+ * Rules for validating this property
251
+ */
252
+ validation?: PropertyValidationSchema;
253
+
254
+ /**
255
+ * This value will be set by default for new entities.
256
+ */
257
+ defaultValue?: T | null;
258
+
259
+ }
298
260
 
299
261
  /**
300
262
  * @group Entity properties
@@ -414,7 +376,7 @@ export interface ArrayProperty<T extends ArrayT[] = any[], ArrayT extends CMSTyp
414
376
  * You can leave this field empty only if you are providing a custom field,
415
377
  * or using the `oneOf` prop, otherwise an error will be thrown.
416
378
  */
417
- of?: PropertyOrBuilder<ArrayT> | Property<ArrayT>[];
379
+ of?: Property<ArrayT>[];
418
380
 
419
381
  /**
420
382
  * Use this field if you would like to have an array of typed objects.
@@ -498,7 +460,7 @@ export interface MapProperty<T extends Record<string, CMSType> = Record<string,
498
460
  /**
499
461
  * Record of properties included in this map.
500
462
  */
501
- properties?: PropertiesOrBuilders<T>;
463
+ properties?: Properties<T>;
502
464
 
503
465
  /**
504
466
  * Order in which the properties are displayed.
@@ -9,7 +9,7 @@ import { buildStringProperty } from "./builders/string_property_builder";
9
9
  import { buildValidation } from "./builders/validation_builder";
10
10
  import { buildReferenceProperty } from "./builders/reference_property_builder";
11
11
  import { extractEnumFromValues, mergeDeep, resolveEnumValues } from "./util";
12
- import { DataType, EnumValues, Properties, PropertiesOrBuilders, Property, StringProperty } from "./cms_types";
12
+ import { DataType, EnumValues, Properties, Property, StringProperty } from "./cms_types";
13
13
 
14
14
  export type InferenceTypeBuilder = (value: any) => DataType;
15
15
 
@@ -23,6 +23,7 @@ export async function buildEntityPropertiesFromData(
23
23
  data.forEach((entry) => {
24
24
  if (entry) {
25
25
  Object.entries(entry).forEach(([key, value]) => {
26
+ if (key.startsWith("_")) return; // Ignore properties starting with _
26
27
  increaseMapTypeCount(typesCount, key, value, getType);
27
28
  increaseValuesCount(valuesCount, key, value, getType);
28
29
  });
@@ -64,7 +65,7 @@ export function buildPropertyFromData(
64
65
  }
65
66
 
66
67
  export function buildPropertiesOrder(
67
- properties: PropertiesOrBuilders,
68
+ properties: Properties,
68
69
  propertiesOrder?: string[],
69
70
  priorityKeys?: string[]
70
71
  ): string[] {
@@ -124,9 +125,11 @@ function increaseTypeCount(
124
125
  mapTypesCount = {};
125
126
  }
126
127
  fieldValue.forEach((value) => {
127
- Object.entries(value).forEach(([key, v]) =>
128
- increaseMapTypeCount(mapTypesCount, key, v, getType)
129
- );
128
+ if (value && typeof value === "object" && !Array.isArray(value)) { // Ensure value is an object for Object.entries
129
+ Object.entries(value).forEach(([key, v]) =>
130
+ increaseMapTypeCount(mapTypesCount, key, v, getType)
131
+ );
132
+ }
130
133
  });
131
134
  arrayTypesCount[arrayType] = mapTypesCount;
132
135
  } else {
@@ -146,6 +149,8 @@ function increaseMapTypeCount(
146
149
  fieldValue: any,
147
150
  getType: InferenceTypeBuilder
148
151
  ) {
152
+ if (key.startsWith("_")) return; // Ignore properties starting with _
153
+
149
154
  let typesCount: TypesCount = typesCountRecord[key];
150
155
  if (!typesCount) {
151
156
  typesCount = {};
@@ -165,6 +170,8 @@ function increaseValuesCount(
165
170
  fieldValue: any,
166
171
  getType: InferenceTypeBuilder
167
172
  ) {
173
+ if (key.startsWith("_")) return; // Ignore properties starting with _
174
+
168
175
  const dataType = getType(fieldValue);
169
176
 
170
177
  let valuesRecord: {
@@ -188,8 +195,8 @@ function increaseValuesCount(
188
195
  valuesRecord.map = mapValuesRecord;
189
196
  }
190
197
  if (fieldValue)
191
- Object.entries(fieldValue).forEach(([key, value]) =>
192
- increaseValuesCount(mapValuesRecord as ValuesCountRecord, key, value, getType)
198
+ Object.entries(fieldValue).forEach(([subKey, value]) =>
199
+ increaseValuesCount(mapValuesRecord as ValuesCountRecord, subKey, value, getType)
193
200
  );
194
201
  } else if (dataType === "array") {
195
202
  if (Array.isArray(fieldValue)) {
@@ -199,7 +206,7 @@ function increaseValuesCount(
199
206
  });
200
207
  }
201
208
  } else {
202
- if (fieldValue) {
209
+ if (fieldValue !== null && fieldValue !== undefined) {
203
210
  valuesRecord.values.push(fieldValue);
204
211
  valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);
205
212
  }
@@ -406,6 +413,7 @@ function formatString(input: string): string {
406
413
  }
407
414
 
408
415
  export function inferTypeFromValue(value: any): DataType {
416
+ if (value === null || value === undefined) return "string";
409
417
  if (typeof value === "string") return "string";
410
418
  if (typeof value === "number") return "number";
411
419
  if (typeof value === "boolean") return "boolean";