@svadmin/core 0.59.0 → 0.60.0
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/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/inferencer.ts +82 -1
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -304,7 +304,7 @@ export {
|
|
|
304
304
|
generateComponentCode,
|
|
305
305
|
generateResourceBundle,
|
|
306
306
|
} from './inferencer';
|
|
307
|
-
export type { InferResult } from './inferencer';
|
|
307
|
+
export type { InferResult, InferReview, InferReviewWarning, InferReviewWarningCode } from './inferencer';
|
|
308
308
|
export { createWebSocketLiveProvider } from './live-websocket';
|
|
309
309
|
export type { WebSocketLiveProviderOptions } from './live-websocket';
|
|
310
310
|
export { createSSELiveProvider } from './live-sse';
|
package/src/inferencer.ts
CHANGED
|
@@ -84,6 +84,7 @@ export interface InferResult {
|
|
|
84
84
|
resource: ResourceDefinition;
|
|
85
85
|
code: string;
|
|
86
86
|
typeboxCode: string;
|
|
87
|
+
review: InferReview;
|
|
87
88
|
componentCode: {
|
|
88
89
|
list: string;
|
|
89
90
|
create: string;
|
|
@@ -92,6 +93,26 @@ export interface InferResult {
|
|
|
92
93
|
};
|
|
93
94
|
}
|
|
94
95
|
|
|
96
|
+
export type InferReviewWarningCode =
|
|
97
|
+
| 'empty-sample'
|
|
98
|
+
| 'nullable-field'
|
|
99
|
+
| 'mixed-types'
|
|
100
|
+
| 'heuristic-relation'
|
|
101
|
+
| 'heuristic-select';
|
|
102
|
+
|
|
103
|
+
export interface InferReviewWarning {
|
|
104
|
+
code: InferReviewWarningCode;
|
|
105
|
+
field?: string;
|
|
106
|
+
message: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface InferReview {
|
|
110
|
+
needsReview: boolean;
|
|
111
|
+
confidence: 'high' | 'medium' | 'low';
|
|
112
|
+
sampleSize: number;
|
|
113
|
+
warnings: InferReviewWarning[];
|
|
114
|
+
}
|
|
115
|
+
|
|
95
116
|
/**
|
|
96
117
|
* Analyze a sample data array and produce a ResourceDefinition.
|
|
97
118
|
* @param resourceName - Name of the resource (e.g. "posts")
|
|
@@ -116,6 +137,15 @@ export function inferResource(
|
|
|
116
137
|
resource: emptyResource,
|
|
117
138
|
code: `// No data available to infer fields for "${resourceName}".`,
|
|
118
139
|
typeboxCode: generateTypeBoxSchemaCode(emptyResource),
|
|
140
|
+
review: {
|
|
141
|
+
needsReview: true,
|
|
142
|
+
confidence: 'low',
|
|
143
|
+
sampleSize: 0,
|
|
144
|
+
warnings: [{
|
|
145
|
+
code: 'empty-sample',
|
|
146
|
+
message: `No sample records were available for "${resourceName}".`,
|
|
147
|
+
}],
|
|
148
|
+
},
|
|
119
149
|
componentCode: {
|
|
120
150
|
list: generateListPageCode(emptyResource),
|
|
121
151
|
create: generateCreatePageCode(emptyResource),
|
|
@@ -133,6 +163,7 @@ export function inferResource(
|
|
|
133
163
|
|
|
134
164
|
// For each key, infer from all non-null values
|
|
135
165
|
const fields: FieldDefinition[] = [];
|
|
166
|
+
const warnings: InferReviewWarning[] = [];
|
|
136
167
|
for (const key of keySet) {
|
|
137
168
|
// Collect non-null values
|
|
138
169
|
const values = sampleData
|
|
@@ -141,6 +172,13 @@ export function inferResource(
|
|
|
141
172
|
|
|
142
173
|
const sampleValue = values[0];
|
|
143
174
|
let inferredType = inferFieldType(key, sampleValue);
|
|
175
|
+
if (values.length === 0) {
|
|
176
|
+
warnings.push({
|
|
177
|
+
code: 'nullable-field',
|
|
178
|
+
field: key,
|
|
179
|
+
message: `Field "${key}" contains only null or undefined values in the sample.`,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
144
182
|
|
|
145
183
|
// Cross-validate: if most values for this key are of a different type, use majority
|
|
146
184
|
const typeCounts = new Map<InferredType, number>();
|
|
@@ -155,13 +193,34 @@ export function inferResource(
|
|
|
155
193
|
inferredType = t;
|
|
156
194
|
}
|
|
157
195
|
}
|
|
196
|
+
if (typeCounts.size > 1) {
|
|
197
|
+
warnings.push({
|
|
198
|
+
code: 'mixed-types',
|
|
199
|
+
field: key,
|
|
200
|
+
message: `Field "${key}" contains multiple inferred types; the majority type was selected.`,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
158
203
|
|
|
159
204
|
// Check for relation
|
|
160
205
|
const relatedResource = isLikelyRelation(key);
|
|
206
|
+
if (relatedResource) {
|
|
207
|
+
warnings.push({
|
|
208
|
+
code: 'heuristic-relation',
|
|
209
|
+
field: key,
|
|
210
|
+
message: `Relation "${key}" was inferred from its field name.`,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
161
213
|
|
|
162
214
|
// Check if it looks like a select (few unique string values)
|
|
163
215
|
const uniqueStrings = new Set(values.filter(v => typeof v === 'string') as string[]);
|
|
164
216
|
const isSelect = inferredType === 'text' && uniqueStrings.size > 1 && uniqueStrings.size <= 10 && values.length >= 5;
|
|
217
|
+
if (isSelect) {
|
|
218
|
+
warnings.push({
|
|
219
|
+
code: 'heuristic-select',
|
|
220
|
+
field: key,
|
|
221
|
+
message: `Select options for "${key}" were inferred from repeated sample values.`,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
165
224
|
|
|
166
225
|
const field: FieldDefinition = {
|
|
167
226
|
key,
|
|
@@ -213,7 +272,23 @@ export function inferResource(
|
|
|
213
272
|
show: generateShowPageCode(resource),
|
|
214
273
|
};
|
|
215
274
|
|
|
216
|
-
return {
|
|
275
|
+
return {
|
|
276
|
+
fields,
|
|
277
|
+
resource,
|
|
278
|
+
code,
|
|
279
|
+
typeboxCode,
|
|
280
|
+
review: {
|
|
281
|
+
needsReview: warnings.length > 0,
|
|
282
|
+
confidence: warnings.some((warning) => warning.code === 'mixed-types' || warning.code === 'nullable-field')
|
|
283
|
+
? 'low'
|
|
284
|
+
: warnings.length > 0
|
|
285
|
+
? 'medium'
|
|
286
|
+
: 'high',
|
|
287
|
+
sampleSize: sampleData.length,
|
|
288
|
+
warnings,
|
|
289
|
+
},
|
|
290
|
+
componentCode,
|
|
291
|
+
};
|
|
217
292
|
}
|
|
218
293
|
|
|
219
294
|
// ─── Code Generation ─────────────────────────────────────────
|
|
@@ -462,6 +537,12 @@ export function generateResourceBundle(resource: ResourceDefinition): InferResul
|
|
|
462
537
|
resource,
|
|
463
538
|
code: generateResourceCode(resource),
|
|
464
539
|
typeboxCode: generateTypeBoxSchemaCode(resource),
|
|
540
|
+
review: {
|
|
541
|
+
needsReview: false,
|
|
542
|
+
confidence: 'high',
|
|
543
|
+
sampleSize: 0,
|
|
544
|
+
warnings: [],
|
|
545
|
+
},
|
|
465
546
|
componentCode: {
|
|
466
547
|
list: generateListPageCode(resource),
|
|
467
548
|
create: generateCreatePageCode(resource),
|