@firecms/schema_inference 3.0.0-beta.1 → 3.0.0-beta.10
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/LICENSE +114 -21
- package/dist/collection_builder.d.ts +3 -2
- package/dist/index.es.js +392 -202
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +433 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/util.d.ts +1 -1
- package/package.json +15 -7
- package/src/builders/string_property_builder.ts +1 -2
- package/src/collection_builder.ts +142 -49
- package/src/strings.ts +1 -1
- package/src/test_schemas/pop_products.json +948 -0
- package/src/test_schemas/test_schema.ts +5 -1
- package/src/util.ts +10 -2
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: string[]) {\n const enumValues = values\n .map((value) => ({ id: value, label: unslugify(value) }));\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\", \".png\", \".webp\", \".gif\"];\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\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 unslugify\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 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 // 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 data.forEach((entry) => {\n increaseTypeCount(property.dataType, typesCount, entry, getType);\n increaseValuesCount(valuesCount, \"inferred_prop\", entry, getType);\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>): string [] {\n function propOrder(s: string) {\n const k = s.toLowerCase();\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 = unslugify(key);\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\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","propOrder","k","keys","type","fieldValue","mapTypesCount","arrayTypesCount","arrayType","getMostProbableTypeInArray","typesCountRecord","typeValuesRecord","dataType","valuesRecord","mapValuesRecord","getHighestTypesCount","highestCount","count","countValue","getHighestRecordCount","record","getMostProbableType","probableType","mostProbableType","title","result","checkTypesCountHighVariability","arrayMostProbableType","of","propertyProps","validation","valuesCountRecord","res","countMaxDocumentsUnder","array","maxCount","keysWithFewValues"],"mappings":"kVAGO,SAASA,EAA8BC,EAAgC,CAE1E,GAAI,CAACA,EAAoB,OAEzB,SAASC,EAAQC,EAAY,CACzB,OAAI,OAAOA,GAAU,SAAiBA,EAC7BA,aAAiBC,EAAA,kBAA0BD,EAAM,KAC9C,MAChB,CAGM,MAAAE,EADoBJ,EAAY,OAAO,IAAKK,GAAMJ,EAAQI,CAAC,CAAC,EAAE,OAAYA,GAAA,CAAC,CAACA,CAAC,EACrD,KAAMC,GAAMA,EAAE,SAAS,GAAG,CAAC,EACzD,GAAI,CAACF,EACM,OAEX,MAAMG,EAAeH,EAAc,OAAO,EAAGA,EAAc,YAAY,GAAG,CAAC,EAS3E,OAPYJ,EAAY,OACnB,OAAQE,GAAU,CACT,MAAAM,EAAOP,EAAQC,CAAK,EAC1B,OAAKM,EACEA,EAAK,WAAWD,CAAY,EADjB,EACiB,CACtC,EAAE,OAASP,EAAY,OAAO,OAAS,EAAI,EAEnCO,EAAe,MAEhC,CC3BO,SAASE,EAAsBC,EAAkB,CACpD,MAAMC,EAAaD,EACd,IAAKR,IAAW,CAAE,GAAIA,EAAO,MAAOU,EAAA,UAAUV,CAAK,CAAA,EAAI,EACjD,OAAAS,EAAA,KAAK,CAACE,EAAGC,IAAMD,EAAE,MAAM,cAAcC,EAAE,KAAK,CAAC,EACjDH,CACX,CCFA,MAAMI,EAAmB,CAAC,OAAQ,OAAQ,QAAS,MAAM,EACnDC,EAAmB,CAAC,OAAQ,OAAQ,QAAS,MAAM,EACnDC,EAAmB,CAAC,OAAQ,MAAM,EAElCC,EAAa,uIAGZ,SAASC,EAAoB,CACI,eAAAC,EACA,aAAAC,CACJ,EAA4C,CAE5E,IAAIC,EAA2B,CAC3B,SAAU,QAAA,EAId,GAAID,EAAc,CAER,MAAAE,EAAoBF,EAAa,OAAO,OACxCG,EAAc,MAAM,KAAKH,EAAa,YAAY,KAAA,CAAM,EAAE,OAE1DI,EAAkC,CAAA,EAElCC,EAAeL,EAAa,OAC7B,OAAQnB,GAAU,OAAOA,GAAU,UAChCA,EAAM,WAAW,WAAW,MAAM,CAAC,EAAE,OAASkB,EAAiB,EAAI,EACvEM,IACAD,EAAO,IAAM,IAGjB,MAAME,EAAkBN,EAAa,OAChC,OAAQnB,GAAU,OAAOA,GAAU,UAChCgB,EAAW,KAAKhB,CAAK,CAAC,EAAE,OAASkB,EAAiB,EAAI,EAC1DO,IACAF,EAAO,MAAQ,IAGb,MAAAG,EAAkBP,EAAa,OAChC,OAAQnB,GAAU,OAAOA,GAAU,UAAYA,EAAM,SAAW,IAAM,CAACA,EAAM,SAAS,GAAG,CAAC,EAC1F,OAASkB,EAAiB,EAAI,EAI/B,GAHAQ,IACAH,EAAO,SAAW,IAElB,CAACE,GACD,CAACD,GACD,CAACE,GACD,CAACF,GACDF,EAAcD,EAAoB,EACpC,CACQ,MAAAZ,EAAaF,EAAsB,MAAM,KAAKY,EAAa,YAAY,KAAM,CAAA,CAAC,EAEhF,OAAO,KAAKV,CAAU,EAAE,OAAS,IACjCc,EAAO,WAAad,EAC5B,CAGI,GAAA,CAACgB,GACD,CAACD,GACD,CAACE,GACD,CAACF,GACD,CAACD,EAAO,WAAY,CACd,MAAAI,EAAWC,EAAiBT,EAAcD,CAAc,EAC1DS,IACAJ,EAAO,QAAU,CACb,cAAe,CAACI,CAAoB,EACpC,YAAa9B,EAA8BsB,CAAY,GAAK,GAAA,EAGxE,CAEI,OAAO,KAAKI,CAAM,EAAE,OAAS,IACZH,EAAA,CACb,GAAGA,EACH,GAAGG,EACH,SAAU,EAAA,EAEtB,CAEO,OAAAH,CACX,CAGA,SAASQ,EAAiB9B,EAA+BoB,EAA4C,CAC3F,MAAAW,EAAkB/B,EAAY,OAC/B,OAAQE,GAAU,OAAOA,GAAU,UAChCa,EAAiB,KAAMiB,GAAc9B,EAAM,WAAW,SAAS8B,CAAS,CAAC,CAAC,EAAE,OAASZ,EAAiB,EAAI,EAE5Ga,EAAgBjC,EAAY,OAC7B,OAAQE,GAAU,OAAOA,GAAU,UAChCc,EAAiB,KAAMgB,GAAc9B,EAAM,WAAW,SAAS8B,CAAS,CAAC,CAAC,EAAE,OAASZ,EAAiB,EAAI,EAE5Gc,EAAgBlC,EAAY,OAC7B,OAAQE,GAAU,OAAOA,GAAU,UAChCe,EAAiB,KAAMe,GAAc9B,EAAM,WAAW,SAAS8B,CAAS,CAAC,CAAC,EAAE,OAASZ,EAAiB,EAAI,EAO3G,OAL8BW,EAC/B,UACAE,EACI,UACAC,EAAgB,UAAY,EAE1C,CCxGO,SAASC,EAAgB,CACI,eAAAf,EACA,aAAAC,CACJ,EAAwE,CAEpG,GAAIA,EAAc,CACR,MAAAE,EAAoBF,EAAa,OAAO,OAC9C,GAAID,IAAmBG,EACZ,MAAA,CACH,SAAU,EAAA,CAEtB,CAGJ,CCbO,SAASa,EAAuB,CACC,eAAAhB,EACA,aAAAC,CACJ,EAA4C,CAQrE,MANoB,CACvB,SAAU,YACV,KAAMtB,EAA8BsB,CAAY,GAAK,eACrD,SAAU,EAAA,CAIlB,CCQsB,eAAAgB,EAA8BC,EAAgBC,EAAoD,CACpH,MAAMC,EAA+B,CAAA,EAC/BxC,EAAiC,CAAA,EAClC,OAAAsC,EAAA,QAASG,GAAU,CAChBA,GACO,OAAA,QAAQA,CAAK,EAAE,QAAQ,CAAC,CAACC,EAAKxC,CAAK,IAAM,CACvByC,EAAAH,EAAYE,EAAKxC,EAAOqC,CAAO,EAChCK,EAAA5C,EAAa0C,EAAKxC,EAAOqC,CAAO,CAAA,CACvD,CACL,CACH,EAEMM,EAAyBP,EAAK,OAAQE,EAAYxC,CAAW,CACxE,CAEgB,SAAA8C,EAAsBR,EAAaS,EAAoBR,EAAyC,CAC5G,MAAMC,EAAa,CAAA,EACbxC,EAAiC,CAAA,EAClCsC,EAAA,QAASG,GAAU,CACpBO,EAAkBD,EAAS,SAAUP,EAAYC,EAAOF,CAAO,EAC3CK,EAAA5C,EAAa,gBAAiByC,EAAOF,CAAO,CAAA,CACnE,EACD,MAAM5B,EAAa,eAAgBoC,EAAWE,EAAAA,kBAAkBF,EAAS,UAA2B,EAAI,OACxG,GAAIpC,EAAY,CACN,MAAAuC,EAAgBzC,EAAsB,MAAM,KAAKT,EAAY,cAAiB,YAAY,KAAM,CAAA,CAAC,EAChG,MAAA,CACH,GAAG+C,EACH,WAAY,CAAC,GAAGG,EAAe,GAAGvC,CAAU,CAAA,CAEpD,CACM,MAAAwC,EAAoBC,EAAuB,gBAAiBd,EAAK,OAAQS,EAAS,SAAUP,EAAYxC,EAAY,aAAgB,EACnI,OAAAqD,EAAA,UAAUF,EAAmBJ,CAAQ,CAChD,CAEO,SAASO,EAAqBC,EAAwC,CACzE,SAASC,EAAU,EAAW,CACpB,MAAAC,EAAI,EAAE,cACR,OAAAA,IAAM,SAAWA,IAAM,OAAe,EACtCA,EAAE,SAAS,OAAO,GAAKA,EAAE,SAAS,MAAM,EAAU,EAClDA,EAAE,SAAS,OAAO,GAAKA,EAAE,SAAS,SAAS,EAAU,EAClD,CACX,CAEM,MAAAC,EAAO,OAAO,KAAKH,CAAU,EACnC,OAAAG,EAAK,KAAK,EACLA,EAAA,KAAK,CAAC7C,EAAGC,IACH0C,EAAU1C,CAAC,EAAI0C,EAAU3C,CAAC,CACpC,EACM6C,CACX,CAQA,SAASV,EAAkBW,EAAgBnB,EAAwBoB,EAAiBrB,EAA+B,CAC/G,GAAIoB,IAAS,OACT,GAAIC,EAAY,CACR,IAAAC,EAAgBrB,EAAWmB,CAAI,EAC9BE,IACDA,EAAgB,CAAA,EAChBrB,EAAWmB,CAAI,EAAIE,GAEhB,OAAA,QAAQD,CAAU,EAAE,QAAQ,CAAC,CAAClB,EAAKxC,CAAK,IAAM,CAC5ByC,EAAAkB,EAAmCnB,EAAKxC,EAAOqC,CAAO,CAAA,CAC9E,CACL,UACOoB,IAAS,QAAS,CACrB,IAAAG,EAAkBtB,EAAWmB,CAAI,EAKrC,GAJKG,IACDA,EAAkB,CAAA,EAClBtB,EAAWmB,CAAI,EAAIG,GAEnBF,GAAc,MAAM,QAAQA,CAAU,GAAKA,EAAW,OAAS,EAAG,CAC5D,MAAAG,EAAYC,EAA2BJ,EAAYrB,CAAO,EAC3DuB,EAAgBC,CAAS,EACxBD,EAAgBC,CAAS,IADGD,EAAgBC,CAAS,EAAe,CAE9E,CAAA,MAEKvB,EAAWmB,CAAI,EACdnB,EAAWmB,CAAI,IADEnB,EAAWmB,CAAI,EAAI,CAGlD,CAEA,SAAShB,EACLsB,EACAvB,EACAkB,EACArB,EACF,CACM,IAAAC,EAAyByB,EAAiBvB,CAAG,EAMjD,GALKF,IACDA,EAAa,CAAA,EACbyB,EAAiBvB,CAAG,EAAIF,GAGxBoB,GAAc,KAAM,CACd,MAAAD,EAAOpB,EAAQqB,CAAU,EACbZ,EAAAW,EAAMnB,EAAYoB,EAAYrB,CAAO,CAC3D,CACJ,CAEA,SAASK,EACLsB,EACAxB,EACAkB,EACArB,EACF,CAEQ,MAAA4B,EAAW5B,EAAQqB,CAAU,EAE/B,IAAAQ,EAIAF,EAAiBxB,CAAG,EAUxB,GARK0B,IACcA,EAAA,CACX,OAAQ,CAAC,EACT,gBAAiB,GAAI,EAEzBF,EAAiBxB,CAAG,EAAI0B,GAGxBD,IAAa,MAAO,CACpB,IAAIE,EAAiDD,EAAa,IAC7DC,IACDA,EAAkB,CAAA,EAClBD,EAAa,IAAMC,GAEnBT,GACA,OAAO,QAAQA,CAAU,EAAE,QAAQ,CAAC,CAAClB,EAAKxC,CAAK,IAAM0C,EAAoByB,EAAsC3B,EAAKxC,EAAOqC,CAAO,CAAC,CAAA,MAChI4B,IAAa,QAChB,MAAM,QAAQP,CAAU,GACbA,EAAA,QAAS1D,GAAU,CACbkE,EAAA,OAAO,KAAKlE,CAAK,EACjBkE,EAAA,YAAY,IAAIlE,GAAQkE,EAAa,YAAY,IAAIlE,CAAK,GAAK,GAAK,CAAC,CAAA,CACrF,EAGD0D,IACaQ,EAAA,OAAO,KAAKR,CAAU,EACtBQ,EAAA,YAAY,IAAIR,GAAaQ,EAAa,YAAY,IAAIR,CAAU,GAAK,GAAK,CAAC,EAIxG,CAEA,SAASU,EAAqB9B,EAAgC,CAC1D,IAAI+B,EAAe,EACZ,cAAA,QAAQ/B,CAAU,EAAE,QAAQ,CAAC,CAACmB,EAAMa,CAAK,IAAM,CAClD,IAAIC,EAAa,EACbd,IAAS,MACTc,EAAaC,EAAsBF,CAAyB,EACrDb,IAAS,QAChBc,EAAaH,EAAqBE,CAAmB,EAExCC,EAAAD,EAEbC,EAAaF,IACEA,EAAAE,EACnB,CACH,EAEMF,CACX,CAEA,SAASG,EAAsBC,EAAkC,CACtD,OAAA,OAAO,QAAQA,CAAM,EACvB,IAAI,CAAC,CAACjC,EAAKF,CAAU,IAAM8B,EAAqB9B,CAAU,CAAC,EAC3D,OAAO,CAAC3B,EAAGC,IAAM,KAAK,IAAID,EAAGC,CAAC,EAAG,CAAC,CAC3C,CAEA,SAAS8D,EAAoBpC,EAAkC,CAC3D,IAAI+B,EAAe,GACfM,EAAyB,SACtB,cAAA,QAAQrC,CAAU,EAAE,QAAQ,CAAC,CAACmB,EAAMa,CAAK,IAAM,CAC9C,IAAAC,EACAd,IAAS,MACTc,EAAaC,EAAsBF,CAAyB,EACrDb,IAAS,QAChBc,EAAaH,EAAqBE,CAAmB,EAExCC,EAAAD,EAEbC,EAAaF,IACEA,EAAAE,EACAI,EAAAlB,EACnB,CACH,EACMkB,CACX,CAEA,SAASzB,EAAuBV,EAAatB,EAAwB0D,EAA4BtC,EAAwBnB,EAA2C,CAC5J,IAAA0D,EAEArC,IACAqC,EAAQnE,EAAAA,UAAU8B,CAAG,GAGzB,IAAIsC,EACJ,GAAIF,IAAqB,MAAO,CAEJG,EAA+BzC,CAAU,IAEpDwC,EAAA,CACL,SAAU,MACV,KAAMD,EACN,SAAU,GACV,WAAY,CAAC,CAAA,GAGf,MAAAxB,EAAaV,EAAyBzB,EAAgBoB,EAAW,IAAyBnB,EAAeA,EAAa,UAAY,MAAS,EACxI2D,EAAA,CACL,SAAU,MACV,KAAMD,EACN,WAAAxB,CAAA,CACJ,SACOuB,IAAqB,QAAS,CACrC,MAAMhB,EAAkBtB,EAAW,MAC7B0C,EAAwBN,EAAoBd,CAAe,EAC3DqB,EAAK/B,EAAuBV,EAAKtB,EAAgB8D,EAAuBpB,EAAiBzC,CAAY,EAClG2D,EAAA,CACL,SAAU,QACV,KAAMD,EACN,GAAAI,CAAA,CAER,CACA,GAAI,CAACH,EAAQ,CACT,MAAMI,EAA+C,CACjD,KAAM1C,EACN,eAAAtB,EACA,aAAAC,CAAA,EAEAyD,IAAqB,SACrBE,EAAS7D,EAAoBiE,CAAa,EACnCN,IAAqB,YAC5BE,EAAS5C,EAAuBgD,CAAa,EAEpCJ,EAAA,CACL,SAAUF,CAAA,EAIdC,IACAC,EAAO,KAAOD,GAGZ,MAAAM,EAAalD,EAAgBiD,CAAa,EAC5CC,IACAL,EAAO,WAAaK,EAE5B,CAEO,MAAA,CACH,GAAGL,EACH,SAAU,EAAA,CAElB,CAEA,SAASnC,EAAyBzB,EAAwB6C,EAAoCqB,EAAmD,CAC7I,MAAMC,EAAkB,CAAA,EACjB,cAAA,QAAQtB,CAAgB,EAAE,QAAQ,CAAC,CAACvB,EAAKF,CAAU,IAAM,CACtD,MAAAsC,EAAmBF,EAAoBpC,CAAU,EACnD+C,EAAA7C,CAAG,EAAIU,EAAuBV,EAAKtB,EAAgB0D,EAAkBtC,EAAY8C,EAAoBA,EAAkB5C,CAAG,EAAI,MAAS,CAAA,CAC9I,EACM6C,CACX,CAEA,SAASC,EAAuBhD,EAAwB,CACpD,IAAIgC,EAAQ,EACL,cAAA,QAAQhC,CAAU,EAAE,QAAQ,CAAC,CAACmB,EAAMzD,CAAK,IAAM,CAE9C,OAAOA,GAAU,SACjBsE,EAAQ,KAAK,IAAIA,EAAOgB,EAAuBtF,CAAyB,CAAC,EAEjEsE,EAAA,KAAK,IAAIA,EAAOtE,CAAe,CAC3C,CACH,EACMsE,CACX,CAEA,SAASR,EAA2ByB,EAAclD,EAAyC,CACvF,IAAIC,EAAyB,CAAA,EACvB,OAAAiD,EAAA,QAASvF,GAAU,CACrB8C,EAAkBT,EAAQrC,CAAK,EAAGsC,EAAYtC,EAAOqC,CAAO,CAAA,CAC/D,EACMqC,EAAoBpC,CAAU,CACzC,CAEA,SAASyC,EAA+BzC,EAAwB,CACtD,MAAAkD,EAAWF,EAAuBhD,CAAU,EAClD,IAAImD,EAAoB,EACjB,cAAA,QAAQnD,EAAW,KAAO,CAAA,CAAE,EAC9B,QAAQ,CAAC,CAACE,EAAKxC,CAAK,IAAM,CACTsF,EAAuBtF,CAAK,EAC9BwF,EAAW,GACnBC,GACJ,CACH,EACEA,EAAoB,OAAO,QAAQnD,EAAW,KAAO,CAAE,CAAA,EAAE,OAAS,EAC7E"}
|
|
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, PropertiesOrBuilders,\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: PropertiesOrBuilders,\n propertiesOrder?: string[],\n priorityKeys?: string[]\n): string[] {\n const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());\n\n function propOrder(s: string) {\n const k = s.toLowerCase();\n if (lowerCasePriorityKeys.includes(k)) return 4;\n if (k === \"title\" || k === \"name\") return 3;\n if (k.includes(\"title\") || k.includes(\"name\")) return 2;\n if (k.includes(\"image\") || k.includes(\"picture\")) return 1;\n return 0;\n }\n\n const keys = propertiesOrder ?? Object.keys(properties);\n keys.sort(); // alphabetically\n keys.sort((a, b) => {\n return propOrder(b) - propOrder(a);\n });\n return keys;\n}\n\n/**\n * @param type\n * @param typesCount\n * @param fieldValue\n * @param getType\n */\nfunction increaseTypeCount(\n type: DataType,\n typesCount: TypesCount,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n if (type === \"map\") {\n if (fieldValue) {\n let mapTypesCount = typesCount[type];\n if (!mapTypesCount) {\n mapTypesCount = {};\n typesCount[type] = mapTypesCount;\n }\n Object.entries(fieldValue).forEach(([key, value]) => {\n increaseMapTypeCount(mapTypesCount as TypesCountRecord, key, value, getType);\n });\n }\n } else if (type === \"array\") {\n let arrayTypesCount = typesCount[type];\n if (!arrayTypesCount) {\n arrayTypesCount = {};\n typesCount[type] = arrayTypesCount;\n }\n if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {\n const arrayType = getMostProbableTypeInArray(fieldValue, getType);\n if (arrayType === \"map\") {\n let mapTypesCount = arrayTypesCount[arrayType];\n if (!mapTypesCount) {\n mapTypesCount = {};\n }\n fieldValue.forEach((value) => {\n Object.entries(value).forEach(([key, v]) =>\n increaseMapTypeCount(mapTypesCount, key, v, getType)\n );\n });\n arrayTypesCount[arrayType] = mapTypesCount;\n } else {\n if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;\n else (arrayTypesCount[arrayType] as number)++;\n }\n }\n } else {\n if (!typesCount[type]) typesCount[type] = 1;\n else (typesCount[type] as number)++;\n }\n}\n\nfunction increaseMapTypeCount(\n typesCountRecord: TypesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n let typesCount: TypesCount = typesCountRecord[key];\n if (!typesCount) {\n typesCount = {};\n typesCountRecord[key] = typesCount;\n }\n\n if (fieldValue != null) {\n // Check that fieldValue is not null or undefined before proceeding\n const type = getType(fieldValue);\n increaseTypeCount(type, typesCount, fieldValue, getType);\n }\n}\n\nfunction increaseValuesCount(\n typeValuesRecord: ValuesCountRecord,\n key: string,\n fieldValue: any,\n getType: InferenceTypeBuilder\n) {\n const dataType = getType(fieldValue);\n\n let valuesRecord: {\n values: any[];\n valuesCount: Map<any, number>;\n map?: ValuesCountRecord;\n } = typeValuesRecord[key];\n\n if (!valuesRecord) {\n valuesRecord = {\n values: [],\n valuesCount: new Map()\n };\n typeValuesRecord[key] = valuesRecord;\n }\n\n if (dataType === \"map\") {\n let mapValuesRecord: ValuesCountRecord | undefined = valuesRecord.map;\n if (!mapValuesRecord) {\n mapValuesRecord = {};\n valuesRecord.map = mapValuesRecord;\n }\n if (fieldValue)\n Object.entries(fieldValue).forEach(([key, value]) =>\n increaseValuesCount(mapValuesRecord as ValuesCountRecord, key, value, getType)\n );\n } else if (dataType === \"array\") {\n if (Array.isArray(fieldValue)) {\n fieldValue.forEach((value) => {\n valuesRecord.values.push(value);\n valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);\n });\n }\n } else {\n if (fieldValue) {\n valuesRecord.values.push(fieldValue);\n valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);\n }\n }\n}\n\nfunction getHighestTypesCount(typesCount: TypesCount): number {\n let highestCount = 0;\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue = 0;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n }\n });\n\n return highestCount;\n}\n\nfunction getHighestRecordCount(record: TypesCountRecord): number {\n return Object.entries(record)\n .map(([key, typesCount]) => getHighestTypesCount(typesCount))\n .reduce((a, b) => Math.max(a, b), 0);\n}\n\nfunction getMostProbableType(typesCount: TypesCount): DataType {\n let highestCount = -1;\n let probableType: DataType = \"string\"; // default\n Object.entries(typesCount).forEach(([type, count]) => {\n let countValue;\n if (type === \"map\") {\n countValue = getHighestRecordCount(count as TypesCountRecord);\n } else if (type === \"array\") {\n countValue = getHighestTypesCount(count as TypesCount);\n } else {\n countValue = count as number;\n }\n if (countValue > highestCount) {\n highestCount = countValue;\n probableType = type as DataType;\n }\n });\n return probableType;\n}\n\nfunction buildPropertyFromCount(\n key: string,\n totalDocsCount: number,\n mostProbableType: DataType,\n typesCount: TypesCount,\n valuesResult?: ValuesCountEntry\n): Property {\n let title: string | undefined;\n\n if (key) {\n title = formatString(key.toLowerCase());\n }\n\n let result: Property | undefined = undefined;\n if (mostProbableType === \"map\") {\n const highVariability = checkTypesCountHighVariability(typesCount);\n if (highVariability) {\n result = {\n dataType: \"map\",\n name: title,\n keyValue: true,\n properties: {}\n };\n }\n const properties = buildPropertiesFromCount(\n totalDocsCount,\n typesCount.map as TypesCountRecord,\n valuesResult ? valuesResult.mapValues : undefined\n );\n result = {\n dataType: \"map\",\n name: title,\n properties\n };\n } else if (mostProbableType === \"array\") {\n const arrayTypesCount = typesCount.array as TypesCount;\n const arrayMostProbableType = getMostProbableType(arrayTypesCount);\n const of = buildPropertyFromCount(\n key,\n totalDocsCount,\n arrayMostProbableType,\n arrayTypesCount,\n valuesResult\n );\n result = {\n dataType: \"array\",\n name: title,\n of\n };\n }\n\n if (!result) {\n const propertyProps: InferencePropertyBuilderProps = {\n name: key,\n totalDocsCount,\n valuesResult\n };\n if (mostProbableType === \"string\") {\n result = buildStringProperty(propertyProps);\n } else if (mostProbableType === \"reference\") {\n result = buildReferenceProperty(propertyProps);\n } else {\n result = {\n dataType: mostProbableType\n } as Property;\n }\n\n if (title) {\n result.name = title;\n }\n\n const validation = buildValidation(propertyProps);\n if (validation) {\n result.validation = validation;\n }\n }\n\n return {\n ...result,\n editable: true\n };\n}\n\nfunction buildPropertiesFromCount(\n totalDocsCount: number,\n typesCountRecord: TypesCountRecord,\n valuesCountRecord?: ValuesCountRecord\n): Properties {\n const res: Properties = {};\n Object.entries(typesCountRecord).forEach(([key, typesCount]) => {\n const mostProbableType = getMostProbableType(typesCount);\n res[key] = buildPropertyFromCount(\n key,\n totalDocsCount,\n mostProbableType,\n typesCount,\n valuesCountRecord ? valuesCountRecord[key] : undefined\n );\n });\n return res;\n}\n\nfunction countMaxDocumentsUnder(typesCount: TypesCount) {\n let count = 0;\n Object.entries(typesCount).forEach(([type, value]) => {\n if (typeof value === \"object\") {\n count = Math.max(count, countMaxDocumentsUnder(value as TypesCountRecord));\n } else {\n count = Math.max(count, value as number);\n }\n });\n return count;\n}\n\nfunction getMostProbableTypeInArray(\n array: any[],\n getType: InferenceTypeBuilder\n): DataType {\n 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":["DocumentReference","unslugify","resolveEnumValues","mergeDeep","key"],"mappings":"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"}
|
package/dist/util.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "3.0.0-beta.
|
|
2
|
+
"version": "3.0.0-beta.10",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"name": "@firecms/schema_inference",
|
|
5
5
|
"access": "public",
|
|
6
|
-
"packageManager": "yarn@3.2.3",
|
|
7
6
|
"main": "./dist/index.umd.js",
|
|
8
7
|
"module": "./dist/index.es.js",
|
|
9
8
|
"types": "dist/index.d.ts",
|
|
10
9
|
"source": "src/index.ts",
|
|
11
|
-
"
|
|
12
|
-
"@firecms/core": "^3.0.0-beta.
|
|
13
|
-
"@types/node": "^20.
|
|
14
|
-
"typescript": "^5.
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@firecms/core": "^3.0.0-beta.10",
|
|
12
|
+
"@types/node": "^20.16.11",
|
|
13
|
+
"typescript": "^5.6.3",
|
|
14
|
+
"vite": "^5.4.8"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": "./dist/index.es.js",
|
|
19
|
+
"require": "./dist/index.umd.js",
|
|
20
|
+
"types": "./dist/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./package.json": "./package.json"
|
|
15
23
|
},
|
|
16
24
|
"files": [
|
|
17
25
|
"dist",
|
|
@@ -22,5 +30,5 @@
|
|
|
22
30
|
"build": "vite build && tsc --emitDeclarationOnly -p tsconfig.prod.json",
|
|
23
31
|
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f"
|
|
24
32
|
},
|
|
25
|
-
"gitHead": "
|
|
33
|
+
"gitHead": "f844c3f86094efec6c33313c3f106f30cdcd309f"
|
|
26
34
|
}
|
|
@@ -3,13 +3,12 @@ import { InferencePropertyBuilderProps, ValuesCountEntry } from "../types";
|
|
|
3
3
|
import { findCommonInitialStringInPath } from "../strings";
|
|
4
4
|
import { extractEnumFromValues } from "../util";
|
|
5
5
|
|
|
6
|
-
const IMAGE_EXTENSIONS = [".jpg", ".png", ".webp", ".gif"];
|
|
6
|
+
const IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".webp", ".gif", ".avif"];
|
|
7
7
|
const AUDIO_EXTENSIONS = [".mp3", ".ogg", ".opus", ".aac"];
|
|
8
8
|
const VIDEO_EXTENSIONS = [".avi", ".mp4"];
|
|
9
9
|
|
|
10
10
|
const emailRegEx = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
11
11
|
|
|
12
|
-
|
|
13
12
|
export function buildStringProperty({
|
|
14
13
|
totalDocsCount,
|
|
15
14
|
valuesResult
|
|
@@ -2,11 +2,10 @@ import {
|
|
|
2
2
|
DataType,
|
|
3
3
|
EnumValues,
|
|
4
4
|
mergeDeep,
|
|
5
|
-
Properties,
|
|
5
|
+
Properties, PropertiesOrBuilders,
|
|
6
6
|
Property,
|
|
7
7
|
resolveEnumValues,
|
|
8
|
-
StringProperty
|
|
9
|
-
unslugify
|
|
8
|
+
StringProperty
|
|
10
9
|
} from "@firecms/core";
|
|
11
10
|
import {
|
|
12
11
|
InferencePropertyBuilderProps,
|
|
@@ -22,28 +21,38 @@ import { extractEnumFromValues } from "./util";
|
|
|
22
21
|
|
|
23
22
|
export type InferenceTypeBuilder = (value: any) => DataType;
|
|
24
23
|
|
|
25
|
-
export async function buildEntityPropertiesFromData(
|
|
24
|
+
export async function buildEntityPropertiesFromData(
|
|
25
|
+
data: object[],
|
|
26
|
+
getType: InferenceTypeBuilder
|
|
27
|
+
): Promise<Properties> {
|
|
26
28
|
const typesCount: TypesCountRecord = {};
|
|
27
29
|
const valuesCount: ValuesCountRecord = {};
|
|
28
|
-
data
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
if (data) {
|
|
31
|
+
data.forEach((entry) => {
|
|
32
|
+
if (entry) {
|
|
33
|
+
Object.entries(entry).forEach(([key, value]) => {
|
|
34
|
+
increaseMapTypeCount(typesCount, key, value, getType);
|
|
35
|
+
increaseValuesCount(valuesCount, key, value, getType);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
37
40
|
return buildPropertiesFromCount(data.length, typesCount, valuesCount);
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
export function buildPropertyFromData(
|
|
43
|
+
export function buildPropertyFromData(
|
|
44
|
+
data: any[],
|
|
45
|
+
property: Property,
|
|
46
|
+
getType: InferenceTypeBuilder
|
|
47
|
+
): Property {
|
|
41
48
|
const typesCount = {};
|
|
42
49
|
const valuesCount: ValuesCountRecord = {};
|
|
43
|
-
data
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
if (data) {
|
|
51
|
+
data.forEach((entry) => {
|
|
52
|
+
increaseTypeCount(property.dataType, typesCount, entry, getType);
|
|
53
|
+
increaseValuesCount(valuesCount, "inferred_prop", entry, getType);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
47
56
|
const enumValues = "enumValues" in property ? resolveEnumValues(property["enumValues"] as EnumValues) : undefined;
|
|
48
57
|
if (enumValues) {
|
|
49
58
|
const newEnumValues = extractEnumFromValues(Array.from(valuesCount["inferred_prop"].valuesCount.keys()));
|
|
@@ -52,20 +61,33 @@ export function buildPropertyFromData(data: any[], property: Property, getType:
|
|
|
52
61
|
enumValues: [...newEnumValues, ...enumValues]
|
|
53
62
|
} as StringProperty;
|
|
54
63
|
}
|
|
55
|
-
const generatedProperty = buildPropertyFromCount(
|
|
64
|
+
const generatedProperty = buildPropertyFromCount(
|
|
65
|
+
"inferred_prop",
|
|
66
|
+
data.length,
|
|
67
|
+
property.dataType,
|
|
68
|
+
typesCount,
|
|
69
|
+
valuesCount["inferred_prop"]
|
|
70
|
+
);
|
|
56
71
|
return mergeDeep(generatedProperty, property);
|
|
57
72
|
}
|
|
58
73
|
|
|
59
|
-
export function buildPropertiesOrder(
|
|
74
|
+
export function buildPropertiesOrder(
|
|
75
|
+
properties: PropertiesOrBuilders,
|
|
76
|
+
propertiesOrder?: string[],
|
|
77
|
+
priorityKeys?: string[]
|
|
78
|
+
): string[] {
|
|
79
|
+
const lowerCasePriorityKeys = (priorityKeys ?? []).map((key) => key.toLowerCase());
|
|
80
|
+
|
|
60
81
|
function propOrder(s: string) {
|
|
61
82
|
const k = s.toLowerCase();
|
|
83
|
+
if (lowerCasePriorityKeys.includes(k)) return 4;
|
|
62
84
|
if (k === "title" || k === "name") return 3;
|
|
63
85
|
if (k.includes("title") || k.includes("name")) return 2;
|
|
64
86
|
if (k.includes("image") || k.includes("picture")) return 1;
|
|
65
87
|
return 0;
|
|
66
88
|
}
|
|
67
89
|
|
|
68
|
-
const keys = Object.keys(properties);
|
|
90
|
+
const keys = propertiesOrder ?? Object.keys(properties);
|
|
69
91
|
keys.sort(); // alphabetically
|
|
70
92
|
keys.sort((a, b) => {
|
|
71
93
|
return propOrder(b) - propOrder(a);
|
|
@@ -79,7 +101,12 @@ export function buildPropertiesOrder(properties: Properties<any>): string [] {
|
|
|
79
101
|
* @param fieldValue
|
|
80
102
|
* @param getType
|
|
81
103
|
*/
|
|
82
|
-
function increaseTypeCount(
|
|
104
|
+
function increaseTypeCount(
|
|
105
|
+
type: DataType,
|
|
106
|
+
typesCount: TypesCount,
|
|
107
|
+
fieldValue: any,
|
|
108
|
+
getType: InferenceTypeBuilder
|
|
109
|
+
) {
|
|
83
110
|
if (type === "map") {
|
|
84
111
|
if (fieldValue) {
|
|
85
112
|
let mapTypesCount = typesCount[type];
|
|
@@ -89,7 +116,7 @@ function increaseTypeCount(type: DataType, typesCount: TypesCount, fieldValue: a
|
|
|
89
116
|
}
|
|
90
117
|
Object.entries(fieldValue).forEach(([key, value]) => {
|
|
91
118
|
increaseMapTypeCount(mapTypesCount as TypesCountRecord, key, value, getType);
|
|
92
|
-
})
|
|
119
|
+
});
|
|
93
120
|
}
|
|
94
121
|
} else if (type === "array") {
|
|
95
122
|
let arrayTypesCount = typesCount[type];
|
|
@@ -98,9 +125,22 @@ function increaseTypeCount(type: DataType, typesCount: TypesCount, fieldValue: a
|
|
|
98
125
|
typesCount[type] = arrayTypesCount;
|
|
99
126
|
}
|
|
100
127
|
if (fieldValue && Array.isArray(fieldValue) && fieldValue.length > 0) {
|
|
101
|
-
const arrayType = getMostProbableTypeInArray(fieldValue, getType);
|
|
102
|
-
if (
|
|
103
|
-
|
|
128
|
+
const arrayType = getMostProbableTypeInArray(fieldValue, getType);
|
|
129
|
+
if (arrayType === "map") {
|
|
130
|
+
let mapTypesCount = arrayTypesCount[arrayType];
|
|
131
|
+
if (!mapTypesCount) {
|
|
132
|
+
mapTypesCount = {};
|
|
133
|
+
}
|
|
134
|
+
fieldValue.forEach((value) => {
|
|
135
|
+
Object.entries(value).forEach(([key, v]) =>
|
|
136
|
+
increaseMapTypeCount(mapTypesCount, key, v, getType)
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
arrayTypesCount[arrayType] = mapTypesCount;
|
|
140
|
+
} else {
|
|
141
|
+
if (!arrayTypesCount[arrayType]) arrayTypesCount[arrayType] = 1;
|
|
142
|
+
else (arrayTypesCount[arrayType] as number)++;
|
|
143
|
+
}
|
|
104
144
|
}
|
|
105
145
|
} else {
|
|
106
146
|
if (!typesCount[type]) typesCount[type] = 1;
|
|
@@ -120,7 +160,8 @@ function increaseMapTypeCount(
|
|
|
120
160
|
typesCountRecord[key] = typesCount;
|
|
121
161
|
}
|
|
122
162
|
|
|
123
|
-
if (fieldValue != null) {
|
|
163
|
+
if (fieldValue != null) {
|
|
164
|
+
// Check that fieldValue is not null or undefined before proceeding
|
|
124
165
|
const type = getType(fieldValue);
|
|
125
166
|
increaseTypeCount(type, typesCount, fieldValue, getType);
|
|
126
167
|
}
|
|
@@ -132,7 +173,6 @@ function increaseValuesCount(
|
|
|
132
173
|
fieldValue: any,
|
|
133
174
|
getType: InferenceTypeBuilder
|
|
134
175
|
) {
|
|
135
|
-
|
|
136
176
|
const dataType = getType(fieldValue);
|
|
137
177
|
|
|
138
178
|
let valuesRecord: {
|
|
@@ -156,13 +196,15 @@ function increaseValuesCount(
|
|
|
156
196
|
valuesRecord.map = mapValuesRecord;
|
|
157
197
|
}
|
|
158
198
|
if (fieldValue)
|
|
159
|
-
Object.entries(fieldValue).forEach(([key, value]) =>
|
|
199
|
+
Object.entries(fieldValue).forEach(([key, value]) =>
|
|
200
|
+
increaseValuesCount(mapValuesRecord as ValuesCountRecord, key, value, getType)
|
|
201
|
+
);
|
|
160
202
|
} else if (dataType === "array") {
|
|
161
203
|
if (Array.isArray(fieldValue)) {
|
|
162
204
|
fieldValue.forEach((value) => {
|
|
163
205
|
valuesRecord.values.push(value);
|
|
164
206
|
valuesRecord.valuesCount.set(value, (valuesRecord.valuesCount.get(value) ?? 0) + 1);
|
|
165
|
-
})
|
|
207
|
+
});
|
|
166
208
|
}
|
|
167
209
|
} else {
|
|
168
210
|
if (fieldValue) {
|
|
@@ -170,7 +212,6 @@ function increaseValuesCount(
|
|
|
170
212
|
valuesRecord.valuesCount.set(fieldValue, (valuesRecord.valuesCount.get(fieldValue) ?? 0) + 1);
|
|
171
213
|
}
|
|
172
214
|
}
|
|
173
|
-
|
|
174
215
|
}
|
|
175
216
|
|
|
176
217
|
function getHighestTypesCount(typesCount: TypesCount): number {
|
|
@@ -200,7 +241,7 @@ function getHighestRecordCount(record: TypesCountRecord): number {
|
|
|
200
241
|
|
|
201
242
|
function getMostProbableType(typesCount: TypesCount): DataType {
|
|
202
243
|
let highestCount = -1;
|
|
203
|
-
let probableType: DataType = "string"; //default
|
|
244
|
+
let probableType: DataType = "string"; // default
|
|
204
245
|
Object.entries(typesCount).forEach(([type, count]) => {
|
|
205
246
|
let countValue;
|
|
206
247
|
if (type === "map") {
|
|
@@ -218,16 +259,21 @@ function getMostProbableType(typesCount: TypesCount): DataType {
|
|
|
218
259
|
return probableType;
|
|
219
260
|
}
|
|
220
261
|
|
|
221
|
-
function buildPropertyFromCount(
|
|
262
|
+
function buildPropertyFromCount(
|
|
263
|
+
key: string,
|
|
264
|
+
totalDocsCount: number,
|
|
265
|
+
mostProbableType: DataType,
|
|
266
|
+
typesCount: TypesCount,
|
|
267
|
+
valuesResult?: ValuesCountEntry
|
|
268
|
+
): Property {
|
|
222
269
|
let title: string | undefined;
|
|
223
270
|
|
|
224
271
|
if (key) {
|
|
225
|
-
title =
|
|
272
|
+
title = formatString(key.toLowerCase());
|
|
226
273
|
}
|
|
227
274
|
|
|
228
275
|
let result: Property | undefined = undefined;
|
|
229
276
|
if (mostProbableType === "map") {
|
|
230
|
-
|
|
231
277
|
const highVariability = checkTypesCountHighVariability(typesCount);
|
|
232
278
|
if (highVariability) {
|
|
233
279
|
result = {
|
|
@@ -237,7 +283,11 @@ function buildPropertyFromCount(key: string, totalDocsCount: number, mostProbabl
|
|
|
237
283
|
properties: {}
|
|
238
284
|
};
|
|
239
285
|
}
|
|
240
|
-
const properties = buildPropertiesFromCount(
|
|
286
|
+
const properties = buildPropertiesFromCount(
|
|
287
|
+
totalDocsCount,
|
|
288
|
+
typesCount.map as TypesCountRecord,
|
|
289
|
+
valuesResult ? valuesResult.mapValues : undefined
|
|
290
|
+
);
|
|
241
291
|
result = {
|
|
242
292
|
dataType: "map",
|
|
243
293
|
name: title,
|
|
@@ -246,13 +296,20 @@ function buildPropertyFromCount(key: string, totalDocsCount: number, mostProbabl
|
|
|
246
296
|
} else if (mostProbableType === "array") {
|
|
247
297
|
const arrayTypesCount = typesCount.array as TypesCount;
|
|
248
298
|
const arrayMostProbableType = getMostProbableType(arrayTypesCount);
|
|
249
|
-
const of = buildPropertyFromCount(
|
|
299
|
+
const of = buildPropertyFromCount(
|
|
300
|
+
key,
|
|
301
|
+
totalDocsCount,
|
|
302
|
+
arrayMostProbableType,
|
|
303
|
+
arrayTypesCount,
|
|
304
|
+
valuesResult
|
|
305
|
+
);
|
|
250
306
|
result = {
|
|
251
307
|
dataType: "array",
|
|
252
308
|
name: title,
|
|
253
309
|
of
|
|
254
310
|
};
|
|
255
311
|
}
|
|
312
|
+
|
|
256
313
|
if (!result) {
|
|
257
314
|
const propertyProps: InferencePropertyBuilderProps = {
|
|
258
315
|
name: key,
|
|
@@ -285,19 +342,28 @@ function buildPropertyFromCount(key: string, totalDocsCount: number, mostProbabl
|
|
|
285
342
|
};
|
|
286
343
|
}
|
|
287
344
|
|
|
288
|
-
function buildPropertiesFromCount(
|
|
345
|
+
function buildPropertiesFromCount(
|
|
346
|
+
totalDocsCount: number,
|
|
347
|
+
typesCountRecord: TypesCountRecord,
|
|
348
|
+
valuesCountRecord?: ValuesCountRecord
|
|
349
|
+
): Properties {
|
|
289
350
|
const res: Properties = {};
|
|
290
351
|
Object.entries(typesCountRecord).forEach(([key, typesCount]) => {
|
|
291
352
|
const mostProbableType = getMostProbableType(typesCount);
|
|
292
|
-
res[key] = buildPropertyFromCount(
|
|
293
|
-
|
|
353
|
+
res[key] = buildPropertyFromCount(
|
|
354
|
+
key,
|
|
355
|
+
totalDocsCount,
|
|
356
|
+
mostProbableType,
|
|
357
|
+
typesCount,
|
|
358
|
+
valuesCountRecord ? valuesCountRecord[key] : undefined
|
|
359
|
+
);
|
|
360
|
+
});
|
|
294
361
|
return res;
|
|
295
362
|
}
|
|
296
363
|
|
|
297
364
|
function countMaxDocumentsUnder(typesCount: TypesCount) {
|
|
298
365
|
let count = 0;
|
|
299
366
|
Object.entries(typesCount).forEach(([type, value]) => {
|
|
300
|
-
// console.log(util.inspect({ type, value }, { showHidden: false, depth: null, colors: true }));
|
|
301
367
|
if (typeof value === "object") {
|
|
302
368
|
count = Math.max(count, countMaxDocumentsUnder(value as TypesCountRecord));
|
|
303
369
|
} else {
|
|
@@ -307,7 +373,10 @@ function countMaxDocumentsUnder(typesCount: TypesCount) {
|
|
|
307
373
|
return count;
|
|
308
374
|
}
|
|
309
375
|
|
|
310
|
-
function getMostProbableTypeInArray(
|
|
376
|
+
function getMostProbableTypeInArray(
|
|
377
|
+
array: any[],
|
|
378
|
+
getType: InferenceTypeBuilder
|
|
379
|
+
): DataType {
|
|
311
380
|
let typesCount: TypesCount = {};
|
|
312
381
|
array.forEach((value) => {
|
|
313
382
|
increaseTypeCount(getType(value), typesCount, value, getType);
|
|
@@ -318,13 +387,37 @@ function getMostProbableTypeInArray(array: any[], getType: InferenceTypeBuilder)
|
|
|
318
387
|
function checkTypesCountHighVariability(typesCount: TypesCount) {
|
|
319
388
|
const maxCount = countMaxDocumentsUnder(typesCount);
|
|
320
389
|
let keysWithFewValues = 0;
|
|
321
|
-
Object.entries(typesCount.map ?? {})
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
});
|
|
390
|
+
Object.entries(typesCount.map ?? {}).forEach(([key, value]) => {
|
|
391
|
+
const count = countMaxDocumentsUnder(value);
|
|
392
|
+
if (count < maxCount / 3) {
|
|
393
|
+
keysWithFewValues++;
|
|
394
|
+
}
|
|
395
|
+
});
|
|
328
396
|
return keysWithFewValues / Object.entries(typesCount.map ?? {}).length > 0.5;
|
|
329
397
|
}
|
|
330
398
|
|
|
399
|
+
function formatString(input: string): string {
|
|
400
|
+
const normalized = input
|
|
401
|
+
.replace(/[_\-]+/g, " ")
|
|
402
|
+
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
403
|
+
.toLowerCase();
|
|
404
|
+
|
|
405
|
+
// Split the normalized string into words
|
|
406
|
+
const words = normalized.split(" ");
|
|
407
|
+
|
|
408
|
+
// Capitalize the first letter of each word and join them with a space
|
|
409
|
+
const formatted = words
|
|
410
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
411
|
+
.join(" ");
|
|
412
|
+
|
|
413
|
+
return formatted;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export function inferTypeFromValue(value: any): DataType {
|
|
417
|
+
if (typeof value === "string") return "string";
|
|
418
|
+
if (typeof value === "number") return "number";
|
|
419
|
+
if (typeof value === "boolean") return "boolean";
|
|
420
|
+
if (Array.isArray(value)) return "array";
|
|
421
|
+
if (typeof value === "object") return "map";
|
|
422
|
+
return "string";
|
|
423
|
+
}
|
package/src/strings.ts
CHANGED