@rebasepro/schema-inference 0.0.1-canary.4d4fb3e

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.
@@ -0,0 +1,32 @@
1
+ import { buildEntityPropertiesFromData } from "../collection_builder";
2
+
3
+ // import usage from "./usage.json" assert {
4
+ // type: "json",
5
+ // integrity: "sha384-ABC123"
6
+ // };
7
+ import usage from "./pop_products.json" assert {
8
+ type: "json",
9
+ integrity: "sha384-ABC123"
10
+ };
11
+ import * as util from "util";
12
+ import { DataType } from "@rebasepro/types";
13
+
14
+ buildEntityPropertiesFromData(usage, getType)
15
+ .then((res) => console.log(util.inspect(res, { showHidden: false, depth: null, colors: true })));
16
+
17
+
18
+ function getType(value: any): DataType {
19
+ if (typeof value === "number")
20
+ return "number";
21
+ else if (typeof value === "string")
22
+ return "string";
23
+ else if (typeof value === "boolean")
24
+ return "boolean";
25
+ else if (Array.isArray(value))
26
+ return "array";
27
+ else if (value && "_seconds" in value && "_nanoseconds" in value)
28
+ return "date";
29
+ else if (value && "id" in value && "path" in value)
30
+ return "reference";
31
+ return "map";
32
+ }
package/src/types.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { DataType } from "@rebasepro/types";
2
+
3
+ export type TypesCount = {
4
+ number?: number,
5
+ string?: number,
6
+ boolean?: number,
7
+ map?: TypesCountRecord,
8
+ array?: TypesCount,
9
+ date?: number,
10
+ geopoint?: number,
11
+ reference?: number,
12
+ relation?: number,
13
+ };
14
+
15
+ export type TypesCountRecord<K extends keyof DataType = any> = {
16
+ [P in K]: TypesCount
17
+ };
18
+
19
+ export type ValuesCountEntry = {
20
+ values: any[];
21
+ valuesCount: Map<any, number>;
22
+ mapValues?: ValuesCountRecord;
23
+ };
24
+
25
+ export type ValuesCountRecord = Record<string, ValuesCountEntry>;
26
+
27
+ export type InferencePropertyBuilderProps = {
28
+
29
+ /**
30
+ * Name of the property
31
+ */
32
+ name: string;
33
+
34
+ /**
35
+ * Total documents this props are built from
36
+ */
37
+ totalDocsCount: number;
38
+
39
+ /**
40
+ * How many times does each value show up
41
+ */
42
+ valuesResult?: ValuesCountEntry;
43
+ };
package/src/util.ts ADDED
@@ -0,0 +1,116 @@
1
+ import { EnumValueConfig, EnumValues } from "@rebasepro/types";
2
+
3
+ export function extractEnumFromValues(values: unknown[]) {
4
+ if (!Array.isArray(values)) {
5
+ return [];
6
+ }
7
+ const enumValues = values
8
+ .map((value) => {
9
+ if (typeof value === "string") {
10
+ return ({
11
+ id: value,
12
+ label: unslugify(value)
13
+ });
14
+ } else
15
+ return null;
16
+ }).filter(Boolean) as Array<{ id: string, label: string }>;
17
+ enumValues.sort((a, b) => a.label.localeCompare(b.label));
18
+ return enumValues;
19
+ }
20
+
21
+ export function prettifyIdentifier(input: string) {
22
+ if (!input) return "";
23
+
24
+ let text = input;
25
+
26
+ // 1. Handle camelCase and Acronyms
27
+ // Group 1 ($1 $2): Lowercase followed by Uppercase (e.g., imageURL -> image URL)
28
+ // Group 2 ($3 $4): Uppercase followed by Uppercase+lowercase (e.g., XMLParser -> XML Parser)
29
+ text = text.replace(/([a-z])([A-Z])|([A-Z])([A-Z][a-z])/g, "$1$3 $2$4");
30
+
31
+ // 2. Replace hyphens/underscores with spaces
32
+ text = text.replace(/[_-]+/g, " ");
33
+
34
+ // 3. Capitalize first letter of each word (Title Case)
35
+ const s = text
36
+ .trim()
37
+ .replace(/\b\w/g, (char) => char.toUpperCase());
38
+ console.log("Prettified identifier:", {
39
+ input,
40
+ s
41
+ });
42
+ return s;
43
+ }
44
+
45
+ export function unslugify(slug?: string): string {
46
+ if (!slug) return "";
47
+ if (slug.includes("-") || slug.includes("_") || !slug.includes(" ")) {
48
+ const result = slug.replace(/[-_]/g, " ");
49
+ return result.replace(/\w\S*/g, function (txt) {
50
+ return txt.charAt(0).toUpperCase() + txt.substring(1);
51
+ }).trim();
52
+ } else {
53
+ return slug.trim();
54
+ }
55
+ }
56
+
57
+ export function resolveEnumValues(input: EnumValues): EnumValueConfig[] | undefined {
58
+ // Check Array.isArray first since typeof [] === "object" is true in JavaScript
59
+ if (Array.isArray(input)) {
60
+ return input as EnumValueConfig[];
61
+ } else if (typeof input === "object" && input !== null) {
62
+ return Object.entries(input).map(([id, value]) =>
63
+ (typeof value === "string"
64
+ ? {
65
+ id,
66
+ label: value
67
+ }
68
+ : value));
69
+ } else {
70
+ return undefined;
71
+ }
72
+ }
73
+
74
+ export function mergeDeep<T extends Record<any, any>, U extends Record<any, any>>(target: T, source: U, ignoreUndefined: boolean = false): T & U {
75
+ const targetIsObject = isObject(target);
76
+ const output = targetIsObject ? { ...target } : target;
77
+ if (targetIsObject && isObject(source)) {
78
+ Object.keys(source).forEach(key => {
79
+ const sourceElement = source[key];
80
+ // Skip undefined values when ignoreUndefined is true
81
+ if (ignoreUndefined && sourceElement === undefined) {
82
+ return;
83
+ }
84
+ if (sourceElement instanceof Date) {
85
+ // Assign a new Date instance with the same time value
86
+ Object.assign(output, { [key]: new Date(sourceElement.getTime()) });
87
+ } else if (isPlainObject(sourceElement)) {
88
+ // Only recursively merge plain objects, not class instances
89
+ if (!(key in target))
90
+ Object.assign(output, { [key]: sourceElement });
91
+ else if (isPlainObject((target as Record<string, unknown>)[key]))
92
+ (output as Record<string, unknown>)[key] = mergeDeep((target as Record<string, unknown>)[key] as Record<string, unknown>, sourceElement);
93
+ else
94
+ Object.assign(output, { [key]: sourceElement });
95
+ } else if (isObject(sourceElement)) {
96
+ // For class instances (EntityReference, GeoPoint, etc.), assign directly to preserve prototype
97
+ Object.assign(output, { [key]: sourceElement });
98
+ } else {
99
+ Object.assign(output, { [key]: sourceElement });
100
+ }
101
+ });
102
+ }
103
+ return output as T;
104
+ }
105
+
106
+ export function isObject(item: any) {
107
+ return item && typeof item === "object" && !Array.isArray(item);
108
+ }
109
+
110
+ export function isPlainObject(obj: any) {
111
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
112
+ return false;
113
+ }
114
+ return Object.getPrototypeOf(obj) === Object.prototype;
115
+ }
116
+