@firecms/schema_inference 3.0.0-canary.49 → 3.0.0-canary.50

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.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\";\nimport { DocumentReference } from \"@firebase/firestore\";\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 instanceof DocumentReference) 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 { unslugify } from \"@firecms/core\";\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","import { FileType, Property, StringProperty } from \"@firecms/core\";\nimport { InferencePropertyBuilderProps, ValuesCountEntry } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { extractEnumFromValues } from \"../util\";\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 { PropertyValidationSchema } from \"@firecms/core\";\nimport { InferencePropertyBuilderProps } from \"../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 \"@firecms/core\";\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 DataType,\n EnumValues,\n mergeDeep,\n Properties,\n Property,\n resolveEnumValues,\n StringProperty\n} from \"@firecms/core\";\nimport {\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 } from \"./util\";\n\nexport type InferenceTypeBuilder = (value: any) => DataType;\n\nexport async function buildEntityPropertiesFromData(data: object[], getType: InferenceTypeBuilder): 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 // console.log(util.inspect({ typesCount }, { showHidden: false, depth: null, colors: true }));\n return buildPropertiesFromCount(data.length, typesCount, valuesCount);\n}\n\nexport function buildPropertyFromData(data: any[], property: Property, getType: InferenceTypeBuilder): 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(\"inferred_prop\", data.length, property.dataType, typesCount, valuesCount[\"inferred_prop\"]);\n return mergeDeep(generatedProperty, property);\n}\n\nexport function buildPropertiesOrder(properties: Properties<any>, priorityKeys?: string[]): 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 === \"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 = 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(type: DataType, typesCount: TypesCount, fieldValue: any, getType: InferenceTypeBuilder) {\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); // get type of first element\n if (!arrayTypesCount[arrayType]) (arrayTypesCount[arrayType] as number) = 1;\n else (arrayTypesCount[arrayType] as number)++;\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) { // 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\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]) => increaseValuesCount(mapValuesRecord as ValuesCountRecord, key, value, getType))\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}\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(key: string, totalDocsCount: number, mostProbableType: DataType, typesCount: TypesCount, valuesResult?: ValuesCountEntry): 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\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(totalDocsCount, typesCount.map as TypesCountRecord, valuesResult ? valuesResult.mapValues : undefined);\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(key, totalDocsCount, arrayMostProbableType, arrayTypesCount, valuesResult);\n result = {\n dataType: \"array\",\n name: title,\n of\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(totalDocsCount: number, typesCountRecord: TypesCountRecord, valuesCountRecord?: ValuesCountRecord): Properties {\n const res: Properties = {};\n Object.entries(typesCountRecord).forEach(([key, typesCount]) => {\n const mostProbableType = getMostProbableType(typesCount);\n res[key] = buildPropertyFromCount(key, totalDocsCount, mostProbableType, typesCount, valuesCountRecord ? valuesCountRecord[key] : undefined);\n })\n return res;\n}\n\nfunction countMaxDocumentsUnder(typesCount: TypesCount) {\n let count = 0;\n Object.entries(typesCount).forEach(([type, value]) => {\n // console.log(util.inspect({ type, value }, { showHidden: false, depth: null, colors: true }));\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(array: any[], getType: InferenceTypeBuilder): DataType {\n let 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 ?? {})\n .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\n"],"names":["findCommonInitialStringInPath","valuesCount","getPath","value","DocumentReference","pathWithSlash","v","s","searchedPath","path","extractEnumFromValues","values","enumValues","unslugify","a","b","IMAGE_EXTENSIONS","AUDIO_EXTENSIONS","VIDEO_EXTENSIONS","emailRegEx","buildStringProperty","totalDocsCount","valuesResult","stringProperty","totalEntriesCount","totalValues","config","probablyAURL","probablyAnEmail","probablyUserIds","fileType","probableFileType","probablyAnImage","extension","probablyAudio","probablyVideo","buildValidation","buildReferenceProperty","buildEntityPropertiesFromData","data","getType","typesCount","entry","key","increaseMapTypeCount","increaseValuesCount","buildPropertiesFromCount","buildPropertyFromData","property","increaseTypeCount","resolveEnumValues","newEnumValues","generatedProperty","buildPropertyFromCount","mergeDeep","buildPropertiesOrder","properties","priorityKeys","lowerCasePriorityKeys","propOrder","k","keys","type","fieldValue","mapTypesCount","arrayTypesCount","arrayType","getMostProbableTypeInArray","typesCountRecord","typeValuesRecord","dataType","valuesRecord","mapValuesRecord","getHighestTypesCount","highestCount","count","countValue","getHighestRecordCount","record","getMostProbableType","probableType","mostProbableType","title","formatString","result","checkTypesCountHighVariability","arrayMostProbableType","of","propertyProps","validation","valuesCountRecord","res","countMaxDocumentsUnder","array","maxCount","keysWithFewValues","input","word","inferTypeFromValue"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.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\";\nimport { DocumentReference } from \"@firebase/firestore\";\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 instanceof DocumentReference) 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 { unslugify } from \"@firecms/core\";\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","import { FileType, Property, StringProperty } from \"@firecms/core\";\nimport { InferencePropertyBuilderProps, ValuesCountEntry } from \"../types\";\nimport { findCommonInitialStringInPath } from \"../strings\";\nimport { extractEnumFromValues } from \"../util\";\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 { PropertyValidationSchema } from \"@firecms/core\";\nimport { InferencePropertyBuilderProps } from \"../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 \"@firecms/core\";\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 DataType,\n EnumValues,\n mergeDeep,\n Properties,\n Property,\n resolveEnumValues,\n StringProperty\n} from \"@firecms/core\";\nimport {\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 } from \"./util\";\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: Properties<any>,\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 = 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 let 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":["findCommonInitialStringInPath","valuesCount","getPath","value","DocumentReference","pathWithSlash","v","s","searchedPath","path","extractEnumFromValues","values","enumValues","unslugify","a","b","IMAGE_EXTENSIONS","AUDIO_EXTENSIONS","VIDEO_EXTENSIONS","emailRegEx","buildStringProperty","totalDocsCount","valuesResult","stringProperty","totalEntriesCount","totalValues","config","probablyAURL","probablyAnEmail","probablyUserIds","fileType","probableFileType","probablyAnImage","extension","probablyAudio","probablyVideo","buildValidation","buildReferenceProperty","buildEntityPropertiesFromData","data","getType","typesCount","entry","key","increaseMapTypeCount","increaseValuesCount","buildPropertiesFromCount","buildPropertyFromData","property","increaseTypeCount","resolveEnumValues","newEnumValues","generatedProperty","buildPropertyFromCount","mergeDeep","buildPropertiesOrder","properties","priorityKeys","lowerCasePriorityKeys","propOrder","k","keys","type","fieldValue","mapTypesCount","arrayTypesCount","arrayType","getMostProbableTypeInArray","typesCountRecord","typeValuesRecord","dataType","valuesRecord","mapValuesRecord","getHighestTypesCount","highestCount","count","countValue","getHighestRecordCount","record","getMostProbableType","probableType","mostProbableType","title","formatString","result","checkTypesCountHighVariability","arrayMostProbableType","of","propertyProps","validation","valuesCountRecord","res","countMaxDocumentsUnder","array","maxCount","keysWithFewValues","input","word","inferTypeFromValue"],"mappings":"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"}
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.0.0-canary.49",
2
+ "version": "3.0.0-canary.50",
3
3
  "type": "module",
4
4
  "name": "@firecms/schema_inference",
5
5
  "access": "public",
@@ -8,7 +8,7 @@
8
8
  "types": "dist/index.d.ts",
9
9
  "source": "src/index.ts",
10
10
  "devDependencies": {
11
- "@firecms/core": "^3.0.0-canary.49",
11
+ "@firecms/core": "^3.0.0-canary.50",
12
12
  "@types/node": "^20.12.11",
13
13
  "typescript": "^5.4.5",
14
14
  "vite": "^5.2.11"
@@ -30,5 +30,5 @@
30
30
  "build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
31
31
  "clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
32
32
  },
33
- "gitHead": "ceeb7b89aac080a290671b5d4e4dbe72ea693c8c"
33
+ "gitHead": "e5d125d95a0c858bbcc9a57acc1adb3b61c64f23"
34
34
  }
@@ -21,7 +21,10 @@ import { extractEnumFromValues } from "./util";
21
21
 
22
22
  export type InferenceTypeBuilder = (value: any) => DataType;
23
23
 
24
- export async function buildEntityPropertiesFromData(data: object[], getType: InferenceTypeBuilder): Promise<Properties> {
24
+ export async function buildEntityPropertiesFromData(
25
+ data: object[],
26
+ getType: InferenceTypeBuilder
27
+ ): Promise<Properties> {
25
28
  const typesCount: TypesCountRecord = {};
26
29
  const valuesCount: ValuesCountRecord = {};
27
30
  if (data) {
@@ -30,15 +33,18 @@ export async function buildEntityPropertiesFromData(data: object[], getType: Inf
30
33
  Object.entries(entry).forEach(([key, value]) => {
31
34
  increaseMapTypeCount(typesCount, key, value, getType);
32
35
  increaseValuesCount(valuesCount, key, value, getType);
33
- })
36
+ });
34
37
  }
35
38
  });
36
39
  }
37
- // console.log(util.inspect({ typesCount }, { showHidden: false, depth: null, colors: true }));
38
40
  return buildPropertiesFromCount(data.length, typesCount, valuesCount);
39
41
  }
40
42
 
41
- export function buildPropertyFromData(data: any[], property: Property, getType: InferenceTypeBuilder): Property {
43
+ export function buildPropertyFromData(
44
+ data: any[],
45
+ property: Property,
46
+ getType: InferenceTypeBuilder
47
+ ): Property {
42
48
  const typesCount = {};
43
49
  const valuesCount: ValuesCountRecord = {};
44
50
  if (data) {
@@ -55,18 +61,26 @@ export function buildPropertyFromData(data: any[], property: Property, getType:
55
61
  enumValues: [...newEnumValues, ...enumValues]
56
62
  } as StringProperty;
57
63
  }
58
- const generatedProperty = buildPropertyFromCount("inferred_prop", data.length, property.dataType, typesCount, valuesCount["inferred_prop"]);
64
+ const generatedProperty = buildPropertyFromCount(
65
+ "inferred_prop",
66
+ data.length,
67
+ property.dataType,
68
+ typesCount,
69
+ valuesCount["inferred_prop"]
70
+ );
59
71
  return mergeDeep(generatedProperty, property);
60
72
  }
61
73
 
62
- export function buildPropertiesOrder(properties: Properties<any>, priorityKeys?: string[]): string [] {
74
+ export function buildPropertiesOrder(
75
+ properties: Properties<any>,
76
+ priorityKeys?: string[]
77
+ ): string[] {
63
78
  const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());
64
79
 
65
80
  function propOrder(s: string) {
66
81
  const k = s.toLowerCase();
67
82
  if (lowerCasePriorityKeys.includes(k)) return 4;
68
83
  if (k === "title" || k === "name") return 3;
69
- if (k === "title" || k === "name") return 3;
70
84
  if (k.includes("title") || k.includes("name")) return 2;
71
85
  if (k.includes("image") || k.includes("picture")) return 1;
72
86
  return 0;
@@ -86,7 +100,12 @@ export function buildPropertiesOrder(properties: Properties<any>, priorityKeys?:
86
100
  * @param fieldValue
87
101
  * @param getType
88
102
  */
89
- function increaseTypeCount(type: DataType, typesCount: TypesCount, fieldValue: any, getType: InferenceTypeBuilder) {
103
+ function increaseTypeCount(
104
+ type: DataType,
105
+ typesCount: TypesCount,
106
+ fieldValue: any,
107
+ getType: InferenceTypeBuilder
108
+ ) {
90
109
  if (type === "map") {
91
110
  if (fieldValue) {
92
111
  let mapTypesCount = typesCount[type];
@@ -96,7 +115,7 @@ function increaseTypeCount(type: DataType, typesCount: TypesCount, fieldValue: a
96
115
  }
97
116
  Object.entries(fieldValue).forEach(([key, value]) => {
98
117
  increaseMapTypeCount(mapTypesCount as TypesCountRecord, key, value, getType);
99
- })
118
+ });
100
119
  }
101
120
  } else if (type === "array") {
102
121
  let arrayTypesCount = typesCount[type];
@@ -105,9 +124,22 @@ function increaseTypeCount(type: DataType, typesCount: TypesCount, fieldValue: a
105
124
  typesCount[type] = arrayTypesCount;
106
125
  }
107
126
  if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {
108
- const arrayType = getMostProbableTypeInArray(fieldValue, getType); // get type of first element
109
- if (!arrayTypesCount[arrayType]) (arrayTypesCount[arrayType] as number) = 1;
110
- else (arrayTypesCount[arrayType] as number)++;
127
+ const arrayType = getMostProbableTypeInArray(fieldValue, getType);
128
+ if (arrayType === "map") {
129
+ let mapTypesCount = arrayTypesCount[arrayType];
130
+ if (!mapTypesCount) {
131
+ mapTypesCount = {};
132
+ }
133
+ fieldValue.forEach((value) => {
134
+ Object.entries(value).forEach(([key, v]) =>
135
+ increaseMapTypeCount(mapTypesCount, key, v, getType)
136
+ );
137
+ });
138
+ arrayTypesCount[arrayType] = mapTypesCount;
139
+ } else {
140
+ if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;
141
+ else (arrayTypesCount[arrayType] as number)++;
142
+ }
111
143
  }
112
144
  } else {
113
145
  if (!typesCount[type]) typesCount[type] = 1;
@@ -127,7 +159,8 @@ function increaseMapTypeCount(
127
159
  typesCountRecord[key] = typesCount;
128
160
  }
129
161
 
130
- if (fieldValue != null) { // Check that fieldValue is not null or undefined before proceeding
162
+ if (fieldValue != null) {
163
+ // Check that fieldValue is not null or undefined before proceeding
131
164
  const type = getType(fieldValue);
132
165
  increaseTypeCount(type, typesCount, fieldValue, getType);
133
166
  }
@@ -139,7 +172,6 @@ function increaseValuesCount(
139
172
  fieldValue: any,
140
173
  getType: InferenceTypeBuilder
141
174
  ) {
142
-
143
175
  const dataType = getType(fieldValue);
144
176
 
145
177
  let valuesRecord: {
@@ -163,13 +195,15 @@ function increaseValuesCount(
163
195
  valuesRecord.map = mapValuesRecord;
164
196
  }
165
197
  if (fieldValue)
166
- Object.entries(fieldValue).forEach(([key, value]) => increaseValuesCount(mapValuesRecord as ValuesCountRecord, key, value, getType))
198
+ Object.entries(fieldValue).forEach(([key, value]) =>
199
+ increaseValuesCount(mapValuesRecord as ValuesCountRecord, key, value, getType)
200
+ );
167
201
  } else if (dataType === "array") {
168
202
  if (Array.isArray(fieldValue)) {
169
203
  fieldValue.forEach((value) => {
170
204
  valuesRecord.values.push(value);
171
205
  valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);
172
- })
206
+ });
173
207
  }
174
208
  } else {
175
209
  if (fieldValue) {
@@ -177,7 +211,6 @@ function increaseValuesCount(
177
211
  valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);
178
212
  }
179
213
  }
180
-
181
214
  }
182
215
 
183
216
  function getHighestTypesCount(typesCount: TypesCount): number {
@@ -207,7 +240,7 @@ function getHighestRecordCount(record: TypesCountRecord): number {
207
240
 
208
241
  function getMostProbableType(typesCount: TypesCount): DataType {
209
242
  let highestCount = -1;
210
- let probableType: DataType = "string"; //default
243
+ let probableType: DataType = "string"; // default
211
244
  Object.entries(typesCount).forEach(([type, count]) => {
212
245
  let countValue;
213
246
  if (type === "map") {
@@ -225,7 +258,13 @@ function getMostProbableType(typesCount: TypesCount): DataType {
225
258
  return probableType;
226
259
  }
227
260
 
228
- function buildPropertyFromCount(key: string, totalDocsCount: number, mostProbableType: DataType, typesCount: TypesCount, valuesResult?: ValuesCountEntry): Property {
261
+ function buildPropertyFromCount(
262
+ key: string,
263
+ totalDocsCount: number,
264
+ mostProbableType: DataType,
265
+ typesCount: TypesCount,
266
+ valuesResult?: ValuesCountEntry
267
+ ): Property {
229
268
  let title: string | undefined;
230
269
 
231
270
  if (key) {
@@ -234,7 +273,6 @@ function buildPropertyFromCount(key: string, totalDocsCount: number, mostProbabl
234
273
 
235
274
  let result: Property | undefined = undefined;
236
275
  if (mostProbableType === "map") {
237
-
238
276
  const highVariability = checkTypesCountHighVariability(typesCount);
239
277
  if (highVariability) {
240
278
  result = {
@@ -244,7 +282,11 @@ function buildPropertyFromCount(key: string, totalDocsCount: number, mostProbabl
244
282
  properties: {}
245
283
  };
246
284
  }
247
- const properties = buildPropertiesFromCount(totalDocsCount, typesCount.map as TypesCountRecord, valuesResult ? valuesResult.mapValues : undefined);
285
+ const properties = buildPropertiesFromCount(
286
+ totalDocsCount,
287
+ typesCount.map as TypesCountRecord,
288
+ valuesResult ? valuesResult.mapValues : undefined
289
+ );
248
290
  result = {
249
291
  dataType: "map",
250
292
  name: title,
@@ -253,13 +295,20 @@ function buildPropertyFromCount(key: string, totalDocsCount: number, mostProbabl
253
295
  } else if (mostProbableType === "array") {
254
296
  const arrayTypesCount = typesCount.array as TypesCount;
255
297
  const arrayMostProbableType = getMostProbableType(arrayTypesCount);
256
- const of = buildPropertyFromCount(key, totalDocsCount, arrayMostProbableType, arrayTypesCount, valuesResult);
298
+ const of = buildPropertyFromCount(
299
+ key,
300
+ totalDocsCount,
301
+ arrayMostProbableType,
302
+ arrayTypesCount,
303
+ valuesResult
304
+ );
257
305
  result = {
258
306
  dataType: "array",
259
307
  name: title,
260
308
  of
261
309
  };
262
310
  }
311
+
263
312
  if (!result) {
264
313
  const propertyProps: InferencePropertyBuilderProps = {
265
314
  name: key,
@@ -292,19 +341,28 @@ function buildPropertyFromCount(key: string, totalDocsCount: number, mostProbabl
292
341
  };
293
342
  }
294
343
 
295
- function buildPropertiesFromCount(totalDocsCount: number, typesCountRecord: TypesCountRecord, valuesCountRecord?: ValuesCountRecord): Properties {
344
+ function buildPropertiesFromCount(
345
+ totalDocsCount: number,
346
+ typesCountRecord: TypesCountRecord,
347
+ valuesCountRecord?: ValuesCountRecord
348
+ ): Properties {
296
349
  const res: Properties = {};
297
350
  Object.entries(typesCountRecord).forEach(([key, typesCount]) => {
298
351
  const mostProbableType = getMostProbableType(typesCount);
299
- res[key] = buildPropertyFromCount(key, totalDocsCount, mostProbableType, typesCount, valuesCountRecord ? valuesCountRecord[key] : undefined);
300
- })
352
+ res[key] = buildPropertyFromCount(
353
+ key,
354
+ totalDocsCount,
355
+ mostProbableType,
356
+ typesCount,
357
+ valuesCountRecord ? valuesCountRecord[key] : undefined
358
+ );
359
+ });
301
360
  return res;
302
361
  }
303
362
 
304
363
  function countMaxDocumentsUnder(typesCount: TypesCount) {
305
364
  let count = 0;
306
365
  Object.entries(typesCount).forEach(([type, value]) => {
307
- // console.log(util.inspect({ type, value }, { showHidden: false, depth: null, colors: true }));
308
366
  if (typeof value === "object") {
309
367
  count = Math.max(count, countMaxDocumentsUnder(value as TypesCountRecord));
310
368
  } else {
@@ -314,7 +372,10 @@ function countMaxDocumentsUnder(typesCount: TypesCount) {
314
372
  return count;
315
373
  }
316
374
 
317
- function getMostProbableTypeInArray(array: any[], getType: InferenceTypeBuilder): DataType {
375
+ function getMostProbableTypeInArray(
376
+ array: any[],
377
+ getType: InferenceTypeBuilder
378
+ ): DataType {
318
379
  let typesCount: TypesCount = {};
319
380
  array.forEach((value) => {
320
381
  increaseTypeCount(getType(value), typesCount, value, getType);
@@ -325,13 +386,12 @@ function getMostProbableTypeInArray(array: any[], getType: InferenceTypeBuilder)
325
386
  function checkTypesCountHighVariability(typesCount: TypesCount) {
326
387
  const maxCount = countMaxDocumentsUnder(typesCount);
327
388
  let keysWithFewValues = 0;
328
- Object.entries(typesCount.map ?? {})
329
- .forEach(([key, value]) => {
330
- const count = countMaxDocumentsUnder(value);
331
- if (count < maxCount / 3) {
332
- keysWithFewValues++;
333
- }
334
- });
389
+ Object.entries(typesCount.map ?? {}).forEach(([key, value]) => {
390
+ const count = countMaxDocumentsUnder(value);
391
+ if (count < maxCount / 3) {
392
+ keysWithFewValues++;
393
+ }
394
+ });
335
395
  return keysWithFewValues / Object.entries(typesCount.map ?? {}).length > 0.5;
336
396
  }
337
397
 
@@ -346,7 +406,7 @@ function formatString(input: string): string {
346
406
 
347
407
  // Capitalize the first letter of each word and join them with a space
348
408
  const formatted = words
349
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
409
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
350
410
  .join(" ");
351
411
 
352
412
  return formatted;
@@ -360,4 +420,3 @@ export function inferTypeFromValue(value: any): DataType {
360
420
  if (typeof value === "object") return "map";
361
421
  return "string";
362
422
  }
363
-