@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.
- package/dist/index.es.js +73 -41
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
- package/src/collection_builder.ts +95 -36
- package/src/test_schemas/pop_products.json +948 -0
- package/src/test_schemas/test_schema.ts +5 -1
package/dist/index.umd.js.map
CHANGED
@@ -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.
|
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.
|
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": "
|
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(
|
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(
|
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(
|
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(
|
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(
|
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);
|
109
|
-
if (
|
110
|
-
|
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) {
|
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]) =>
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
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
|
-
|