@adminiumjs/engine 0.1.0-rc.1

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.
Files changed (94) hide show
  1. package/LICENSE +661 -0
  2. package/dist/adapter-registry.d.ts +62 -0
  3. package/dist/adapter-registry.d.ts.map +1 -0
  4. package/dist/adapter-registry.js +75 -0
  5. package/dist/adapter-registry.js.map +1 -0
  6. package/dist/adapter.d.ts +384 -0
  7. package/dist/adapter.d.ts.map +1 -0
  8. package/dist/adapter.js +54 -0
  9. package/dist/adapter.js.map +1 -0
  10. package/dist/capabilities.d.ts +57 -0
  11. package/dist/capabilities.d.ts.map +1 -0
  12. package/dist/capabilities.js +131 -0
  13. package/dist/capabilities.js.map +1 -0
  14. package/dist/classify/columns.d.ts +57 -0
  15. package/dist/classify/columns.d.ts.map +1 -0
  16. package/dist/classify/columns.js +535 -0
  17. package/dist/classify/columns.js.map +1 -0
  18. package/dist/classify/index.d.ts +29 -0
  19. package/dist/classify/index.d.ts.map +1 -0
  20. package/dist/classify/index.js +44 -0
  21. package/dist/classify/index.js.map +1 -0
  22. package/dist/classify/names.d.ts +11 -0
  23. package/dist/classify/names.d.ts.map +1 -0
  24. package/dist/classify/names.js +19 -0
  25. package/dist/classify/names.js.map +1 -0
  26. package/dist/classify/pii.d.ts +29 -0
  27. package/dist/classify/pii.d.ts.map +1 -0
  28. package/dist/classify/pii.js +55 -0
  29. package/dist/classify/pii.js.map +1 -0
  30. package/dist/classify/tables.d.ts +64 -0
  31. package/dist/classify/tables.d.ts.map +1 -0
  32. package/dist/classify/tables.js +303 -0
  33. package/dist/classify/tables.js.map +1 -0
  34. package/dist/config-schema/envelope.d.ts +83 -0
  35. package/dist/config-schema/envelope.d.ts.map +1 -0
  36. package/dist/config-schema/envelope.js +87 -0
  37. package/dist/config-schema/envelope.js.map +1 -0
  38. package/dist/config-schema/index.d.ts +14 -0
  39. package/dist/config-schema/index.d.ts.map +1 -0
  40. package/dist/config-schema/index.js +15 -0
  41. package/dist/config-schema/index.js.map +1 -0
  42. package/dist/config-schema/migrations.d.ts +44 -0
  43. package/dist/config-schema/migrations.d.ts.map +1 -0
  44. package/dist/config-schema/migrations.js +62 -0
  45. package/dist/config-schema/migrations.js.map +1 -0
  46. package/dist/generate/archetype.d.ts +76 -0
  47. package/dist/generate/archetype.d.ts.map +1 -0
  48. package/dist/generate/archetype.js +250 -0
  49. package/dist/generate/archetype.js.map +1 -0
  50. package/dist/generate/crud.d.ts +36 -0
  51. package/dist/generate/crud.d.ts.map +1 -0
  52. package/dist/generate/crud.js +45 -0
  53. package/dist/generate/crud.js.map +1 -0
  54. package/dist/generate/dashboard.d.ts +43 -0
  55. package/dist/generate/dashboard.d.ts.map +1 -0
  56. package/dist/generate/dashboard.js +61 -0
  57. package/dist/generate/dashboard.js.map +1 -0
  58. package/dist/generate/domains.d.ts +29 -0
  59. package/dist/generate/domains.d.ts.map +1 -0
  60. package/dist/generate/domains.js +145 -0
  61. package/dist/generate/domains.js.map +1 -0
  62. package/dist/generate/index.d.ts +78 -0
  63. package/dist/generate/index.d.ts.map +1 -0
  64. package/dist/generate/index.js +301 -0
  65. package/dist/generate/index.js.map +1 -0
  66. package/dist/generate/util.d.ts +46 -0
  67. package/dist/generate/util.d.ts.map +1 -0
  68. package/dist/generate/util.js +123 -0
  69. package/dist/generate/util.js.map +1 -0
  70. package/dist/index.d.ts +8 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +8 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/schema-model.d.ts +1853 -0
  75. package/dist/schema-model.d.ts.map +1 -0
  76. package/dist/schema-model.js +463 -0
  77. package/dist/schema-model.js.map +1 -0
  78. package/dist/snapshot/diff.d.ts +258 -0
  79. package/dist/snapshot/diff.d.ts.map +1 -0
  80. package/dist/snapshot/diff.js +151 -0
  81. package/dist/snapshot/diff.js.map +1 -0
  82. package/dist/snapshot/hash.d.ts +23 -0
  83. package/dist/snapshot/hash.d.ts.map +1 -0
  84. package/dist/snapshot/hash.js +47 -0
  85. package/dist/snapshot/hash.js.map +1 -0
  86. package/dist/snapshot/index.d.ts +28 -0
  87. package/dist/snapshot/index.d.ts.map +1 -0
  88. package/dist/snapshot/index.js +26 -0
  89. package/dist/snapshot/index.js.map +1 -0
  90. package/dist/snapshot/sha256.d.ts +14 -0
  91. package/dist/snapshot/sha256.d.ts.map +1 -0
  92. package/dist/snapshot/sha256.js +99 -0
  93. package/dist/snapshot/sha256.js.map +1 -0
  94. package/package.json +37 -0
@@ -0,0 +1,535 @@
1
+ import { normalizeName } from './names.js';
2
+ import { detectPii } from './pii.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Shared vocab (verbatim from §7.1 unless commented)
5
+ // ---------------------------------------------------------------------------
6
+ const TEXTISH = new Set(['text', 'varchar']);
7
+ const NUMERIC = new Set(['integer', 'bigint', 'decimal', 'float']);
8
+ const TIMESTAMP_FAMILY = new Set(['date', 'timestamp', 'timestamptz']);
9
+ const SECRET_RE = /(password|passwd|secret|token|api_key|apikey|private_key|credential|salt|hash(ed)?_)/;
10
+ const PK_ID_NAME_RE = /^(id|uuid|guid)$/;
11
+ const MONEY_RE = /(^|_)(amount|price|cost|total|subtotal|balance|fee|mrr|arr|revenue|budget|salary|payout|refund|paid|owed)(_|$)/;
12
+ const PERCENT_RE = /(^|_)(percent|pct|rate|ratio|progress|completion|discount|utilization)(_|$)/;
13
+ const SCORE_RE = /(^|_)(score|rating|stars|nps|health)(_|$)/;
14
+ /** §7.1 row 7 — workflow value vocabulary (verbs/states → kanban trigger). */
15
+ export const WORKFLOW_VALUE_RE = /^(todo|to_do|backlog|open|new|pending|draft|queued|in_progress|inprogress|doing|review|in_review|approved|rejected|blocked|on_hold|done|completed?|closed|cancell?ed|archived|active|paused|failed|error|shipped|delivered|paid|overdue|refunded|trial|churned|q[1-4])$/i;
16
+ const CREATED_AT_RE = /^(created_at|created_on|created|creation_date|date_created|inserted_at)$/;
17
+ const UPDATED_AT_RE = /^(updated_at|updated_on|modified_at|last_modified|updatedat)$/;
18
+ const START_RE = /(^|_)(start|begin|from|opens?)(_date|_at|_time)?$/;
19
+ const END_RE = /(^|_)(end|finish|until|to|due|closes?)(_date|_at|_time)?$/;
20
+ const EVENT_TS_RE = /(_at|_date|_on|_time|_ts)$/;
21
+ /**
22
+ * §7.1 row 13 lists `_seconds|_secs|_ms|_minutes|_mins|_hours` inside the
23
+ * `(^|_)…(_|$)` envelope, which would require a double underscore; we read
24
+ * the intent as suffix alternatives and split the regex accordingly.
25
+ */
26
+ const DURATION_WORD_RE = /(^|_)(duration|elapsed|time_spent)(_|$)/;
27
+ const DURATION_SUFFIX_RE = /_(seconds|secs|ms|minutes|mins|hours)$/;
28
+ const LAT_RE = /^(lat|latitude)$/;
29
+ const LNG_RE = /^(lng|lon|long|longitude)$/;
30
+ const GEO_REGION_RE = /(^|_)(country|country_code|state|province|region|region_code|county)(_|$)/;
31
+ const PERSON_NAME_RE = /^(first_name|last_name|full_name|display_name|name|username)$/;
32
+ const EMAIL_RE = /(^|_)e?mail(_address)?(_|$)/;
33
+ const PHONE_RE = /(^|_)(phone|mobile|tele?phone|fax)(_number)?(_|$)/;
34
+ const IMAGE_RE = /(^|_)(avatar|image|img|photo|picture|logo|icon|thumbnail|cover)(_url|_path|_key)?(_|$)/;
35
+ const FILE_RE = /(^|_)(file|attachment|document|upload)(_url|_path|_key|_name)?(_|$)/;
36
+ const URL_RE = /(^|_)(url|link|website|href|homepage)(_|$)/;
37
+ const BOOL_PREFIX_RE = /^(is_|has_|can_|should_|allow_)/;
38
+ const BOOL_SUFFIX_RE = /(enabled|active|archived|deleted|read|seen|starred|verified|billable|public|featured|default)$/;
39
+ const COLOR_RE = /(^|_)(color|colour|hex)(_|$)/;
40
+ const TAGS_RE = /^(tags|labels|keywords)$/;
41
+ const SLUG_RE = /^(slug|handle|permalink)$/;
42
+ const IP_RE = /(^|_)ip(_address)?$/;
43
+ const EXTERNAL_ID_RE = /_(id|uuid|ref|number|no)$/;
44
+ const CENTS_RE = /_cents$/;
45
+ const CURRENCY_SIBLING_RE = /(^|_)(currency|curr(ency)?_code)(_|$)/;
46
+ /** §8 directory trigger vocabulary for "people-ish" tables (see tables.ts). */
47
+ export const PEOPLE_TABLE_RE = /(^|_)(users?|people|persons?|employees?|staff|members?|contacts?|customers?|profiles?|teachers?|students?|drivers?|agents?|authors?|patients?)(_|$)/;
48
+ // ---------------------------------------------------------------------------
49
+ // CHECK-constraint bounds (rules 5/6/22 use numeric bounds when present)
50
+ // ---------------------------------------------------------------------------
51
+ /** Min/max numeric literal in CHECK expressions mentioning the column. */
52
+ export function checkBounds(table, columnName) {
53
+ const columnRe = new RegExp(`(^|[^a-zA-Z0-9_"])"?${escapeRe(columnName)}"?([^a-zA-Z0-9_"]|$)`);
54
+ let min = Number.POSITIVE_INFINITY;
55
+ let max = Number.NEGATIVE_INFINITY;
56
+ let found = false;
57
+ for (const check of table.checks) {
58
+ if (!columnRe.test(check.expression))
59
+ continue;
60
+ for (const literal of check.expression.match(/\d+(\.\d+)?/g) ?? []) {
61
+ const value = Number(literal);
62
+ if (!Number.isFinite(value))
63
+ continue;
64
+ found = true;
65
+ min = Math.min(min, value);
66
+ max = Math.max(max, value);
67
+ }
68
+ }
69
+ return found ? { min, max } : null;
70
+ }
71
+ function escapeRe(text) {
72
+ return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Context builder (pair detection, FK set, people-ish flag)
76
+ // ---------------------------------------------------------------------------
77
+ /** Accepted-relation threshold (§6): ≥ 0.8 behaves like a declared FK. */
78
+ const ACCEPTED_RELATION_CONFIDENCE = 0.8;
79
+ export function buildColumnClassifyContext(model, table) {
80
+ const enumsById = new Map(model.enums.map((e) => [e.id, e]));
81
+ const fkColumns = new Set();
82
+ for (const column of table.columns) {
83
+ if (column.references !== null)
84
+ fkColumns.add(column.name);
85
+ }
86
+ for (const relation of model.relations) {
87
+ if (relation.from.tableId !== table.id)
88
+ continue;
89
+ if (relation.confidence < ACCEPTED_RELATION_CONFIDENCE)
90
+ continue;
91
+ for (const column of relation.from.columns)
92
+ fkColumns.add(column);
93
+ }
94
+ const names = table.columns.map((c) => normalizeName(c.name));
95
+ const hasEmail = table.columns.some((c, i) => TEXTISH.has(c.logicalType) && EMAIL_RE.test(names[i]));
96
+ const hasPersonName = names.some((n) => PERSON_NAME_RE.test(n));
97
+ const peopleish = PEOPLE_TABLE_RE.test(normalizeName(table.name)) || (hasEmail && hasPersonName);
98
+ return {
99
+ table,
100
+ enumsById,
101
+ fkColumns,
102
+ peopleish,
103
+ pairs: detectPairs(table),
104
+ };
105
+ }
106
+ /** §7.1 rows 11 (start/end) and 14 (lat/lng) are table-scoped pair rules. */
107
+ function detectPairs(table) {
108
+ const pairs = new Map();
109
+ // -- geo lat/lng (row 14): both present, float/decimal ------------------
110
+ const geoType = (c) => c.logicalType === 'float' || c.logicalType === 'decimal';
111
+ const lat = table.columns.find((c) => geoType(c) && LAT_RE.test(normalizeName(c.name)));
112
+ const lng = table.columns.find((c) => geoType(c) && LNG_RE.test(normalizeName(c.name)));
113
+ if (lat && lng) {
114
+ pairs.set(lat.name, { semantic: 'geo-point', role: 'lat', partner: lng.name });
115
+ pairs.set(lng.name, { semantic: 'geo-point', role: 'lng', partner: lat.name });
116
+ }
117
+ const stemOf = (name, re) => name.replace(re, '$1').replace(/^_|_$/g, '');
118
+ const starts = [];
119
+ const ends = [];
120
+ for (const column of table.columns) {
121
+ if (!TIMESTAMP_FAMILY.has(column.logicalType))
122
+ continue;
123
+ const name = normalizeName(column.name);
124
+ if (CREATED_AT_RE.test(name) || UPDATED_AT_RE.test(name))
125
+ continue;
126
+ if (START_RE.test(name))
127
+ starts.push({ column, stem: stemOf(name, START_RE) });
128
+ else if (END_RE.test(name))
129
+ ends.push({ column, stem: stemOf(name, END_RE) });
130
+ }
131
+ const taken = new Set();
132
+ const pairUp = (start, end) => {
133
+ taken.add(end.column.name);
134
+ pairs.set(start.column.name, {
135
+ semantic: 'date-range',
136
+ role: 'start',
137
+ partner: end.column.name,
138
+ });
139
+ pairs.set(end.column.name, {
140
+ semantic: 'date-range',
141
+ role: 'end',
142
+ partner: start.column.name,
143
+ });
144
+ };
145
+ for (const start of starts) {
146
+ const sameType = (e) => !taken.has(e.column.name) && e.column.logicalType === start.column.logicalType;
147
+ const byStem = ends.find((e) => sameType(e) && e.stem === start.stem);
148
+ if (byStem) {
149
+ pairUp(start, byStem);
150
+ continue;
151
+ }
152
+ // A single unambiguous start/end pair matches even without a shared stem.
153
+ if (starts.length === 1 && ends.filter(sameType).length === 1) {
154
+ pairUp(start, ends.find(sameType));
155
+ }
156
+ }
157
+ return pairs;
158
+ }
159
+ const hit = (tag, confidence, format, reasons, extra) => ({ tag, confidence, format, reasons, ...extra });
160
+ function enumValues(column, ctx) {
161
+ if (column.enumRef === null)
162
+ return null;
163
+ return ctx.enumsById.get(column.enumRef)?.values ?? null;
164
+ }
165
+ /** Ordered §7.1 pipeline; array index+1 = doc row number. */
166
+ const RULES = [
167
+ {
168
+ id: 'r01-secret',
169
+ rule: (_c, name) => SECRET_RE.test(name)
170
+ ? hit('secret', 0.95, null, ['name matches secret/credential vocabulary'], {
171
+ secret: true,
172
+ })
173
+ : null,
174
+ },
175
+ {
176
+ id: 'r02-pk-id',
177
+ rule: (c, name) => {
178
+ const typeOk = ['integer', 'bigint', 'uuid', 'varchar'].includes(c.logicalType);
179
+ if (!typeOk)
180
+ return null;
181
+ if (c.isPrimaryKey)
182
+ return hit('pk-id', 0.95, 'mono', ['column is a primary key']);
183
+ if (PK_ID_NAME_RE.test(name)) {
184
+ return hit('pk-id', 0.9, 'mono', ['name is a bare id/uuid/guid']);
185
+ }
186
+ return null;
187
+ },
188
+ },
189
+ {
190
+ id: 'r03-fk',
191
+ rule: (c, _name, ctx) => {
192
+ if (c.references !== null) {
193
+ return hit('fk', 1, null, [`declared FK → ${c.references.tableId}.${c.references.column}`]);
194
+ }
195
+ if (ctx.fkColumns.has(c.name)) {
196
+ return hit('fk', 0.85, null, ['accepted (≥ 0.8) inferred relation covers this column']);
197
+ }
198
+ return null;
199
+ },
200
+ },
201
+ {
202
+ id: 'r04-money',
203
+ rule: (c, name, ctx) => {
204
+ if (!NUMERIC.has(c.logicalType) || !MONEY_RE.test(name))
205
+ return null;
206
+ const reasons = ['name matches money vocabulary + numeric type'];
207
+ let format = 'currency';
208
+ if (c.logicalType === 'integer' || c.logicalType === 'bigint') {
209
+ if (CENTS_RE.test(name)) {
210
+ format = 'currency-cents';
211
+ reasons.push('integer with _cents suffix → divide-by-100 hint');
212
+ }
213
+ }
214
+ const sibling = ctx.table.columns.find((s) => CURRENCY_SIBLING_RE.test(normalizeName(s.name)));
215
+ if (sibling)
216
+ reasons.push(`sibling currency column "${sibling.name}" is the currency source`);
217
+ return hit('money', 0.85, format, reasons);
218
+ },
219
+ },
220
+ {
221
+ id: 'r05-percent',
222
+ rule: (c, name, ctx) => {
223
+ if (!NUMERIC.has(c.logicalType) || !PERCENT_RE.test(name))
224
+ return null;
225
+ const bounds = checkBounds(ctx.table, c.name);
226
+ const fraction = bounds !== null && bounds.max <= 1;
227
+ const reasons = ['name matches percent vocabulary + numeric type'];
228
+ if (bounds)
229
+ reasons.push(`CHECK bounds ${bounds.min}..${bounds.max} decide the scale`);
230
+ else
231
+ reasons.push('no CHECK bounds — assuming 0–100 scale');
232
+ return hit('percent', 0.8, fraction ? 'percent-fraction' : 'percent', reasons);
233
+ },
234
+ },
235
+ {
236
+ id: 'r06-score',
237
+ rule: (c, name, ctx) => {
238
+ if (!NUMERIC.has(c.logicalType) || !SCORE_RE.test(name))
239
+ return null;
240
+ const bounds = checkBounds(ctx.table, c.name);
241
+ const reasons = ['name matches score/rating vocabulary + numeric type'];
242
+ if (bounds)
243
+ reasons.push(`bounded by CHECK ${bounds.min}..${bounds.max}`);
244
+ return hit('score', 0.8, null, reasons);
245
+ },
246
+ },
247
+ {
248
+ id: 'r07-status-workflow',
249
+ rule: (c, _name, ctx) => {
250
+ const values = enumValues(c, ctx);
251
+ if (values === null || values.length > 8)
252
+ return null;
253
+ if (c.logicalType !== 'enum' && !(TEXTISH.has(c.logicalType) && (c.maxLength ?? 33) <= 32)) {
254
+ return null;
255
+ }
256
+ const workflowValues = values.filter((v) => WORKFLOW_VALUE_RE.test(v.trim()));
257
+ if (workflowValues.length < 2)
258
+ return null;
259
+ return hit('status-workflow', 0.85, 'status-pill', [
260
+ `${values.length} enum values, ${workflowValues.length} in workflow vocabulary (${workflowValues.join(', ')})`,
261
+ ]);
262
+ },
263
+ },
264
+ {
265
+ id: 'r08-category-enum',
266
+ rule: (c, _name, ctx) => {
267
+ const values = enumValues(c, ctx);
268
+ if (values === null || values.length > 24)
269
+ return null;
270
+ return hit('category-enum', 0.8, null, [
271
+ `enum with ${values.length} values, not a workflow vocabulary`,
272
+ ]);
273
+ },
274
+ },
275
+ {
276
+ id: 'r09-created-at',
277
+ rule: (c, name) => {
278
+ if (!TIMESTAMP_FAMILY.has(c.logicalType))
279
+ return null;
280
+ if (CREATED_AT_RE.test(name)) {
281
+ return hit('created-at', 0.95, 'relative-time', ['canonical created-at name']);
282
+ }
283
+ if (c.default?.kind === 'now' && !UPDATED_AT_RE.test(name)) {
284
+ return hit('created-at', 0.7, 'relative-time', [
285
+ 'non-canonical name but DEFAULT now() and no updated-at claim',
286
+ ]);
287
+ }
288
+ return null;
289
+ },
290
+ },
291
+ {
292
+ id: 'r10-updated-at',
293
+ rule: (c, name) => TIMESTAMP_FAMILY.has(c.logicalType) && UPDATED_AT_RE.test(name)
294
+ ? hit('updated-at', 0.95, 'relative-time', ['canonical updated-at name'])
295
+ : null,
296
+ },
297
+ {
298
+ id: 'r11-date-range',
299
+ rule: (c, _name, ctx) => {
300
+ const pair = ctx.pairs.get(c.name);
301
+ if (pair === undefined || pair.semantic !== 'date-range')
302
+ return null;
303
+ return hit('date-range', 0.75, null, [`${pair.role} of a start/end pair with "${pair.partner}"`], {
304
+ pair: { role: pair.role, partner: pair.partner },
305
+ });
306
+ },
307
+ },
308
+ {
309
+ id: 'r12-event-timestamp',
310
+ rule: (c, name) => TIMESTAMP_FAMILY.has(c.logicalType) && EVENT_TS_RE.test(name)
311
+ ? hit('event-timestamp', 0.7, null, ['timestamp-suffixed name outside created/updated/range'])
312
+ : null,
313
+ },
314
+ {
315
+ id: 'r13-duration',
316
+ rule: (c, name) => {
317
+ if (!NUMERIC.has(c.logicalType))
318
+ return null;
319
+ if (DURATION_WORD_RE.test(name)) {
320
+ const suffix = DURATION_SUFFIX_RE.exec(name)?.[1];
321
+ return hit('duration', 0.75, 'duration', [
322
+ `duration vocabulary; unit ${suffix ?? 'seconds (default)'}`,
323
+ ]);
324
+ }
325
+ const suffix = DURATION_SUFFIX_RE.exec(name)?.[1];
326
+ if (suffix !== undefined) {
327
+ return hit('duration', 0.75, 'duration', [`numeric with time-unit suffix _${suffix}`]);
328
+ }
329
+ return null;
330
+ },
331
+ },
332
+ {
333
+ id: 'r14-geo-point',
334
+ rule: (c, _name, ctx) => {
335
+ const pair = ctx.pairs.get(c.name);
336
+ if (pair === undefined || pair.semantic !== 'geo-point')
337
+ return null;
338
+ return hit('geo-point', 0.85, null, [`${pair.role} of a lat/lng pair with "${pair.partner}"`], {
339
+ pair: { role: pair.role, partner: pair.partner },
340
+ });
341
+ },
342
+ },
343
+ {
344
+ id: 'r15-geo-region',
345
+ rule: (c, name) => {
346
+ if (!TEXTISH.has(c.logicalType) || !GEO_REGION_RE.test(name))
347
+ return null;
348
+ if (c.maxLength !== null && c.maxLength > 64)
349
+ return null;
350
+ const short = c.maxLength !== null && c.maxLength <= 3;
351
+ const reasons = ['name matches region/country vocabulary'];
352
+ if (short)
353
+ reasons.push(`char(${c.maxLength}) strongly suggests a region code`);
354
+ return hit('geo-region', short ? 0.8 : 0.7, null, reasons);
355
+ },
356
+ },
357
+ {
358
+ id: 'r16-person-name',
359
+ rule: (c, name, ctx) => TEXTISH.has(c.logicalType) && PERSON_NAME_RE.test(name) && ctx.peopleish
360
+ ? hit('person-name', 0.8, null, ['name column on a people-shaped table'])
361
+ : null,
362
+ },
363
+ {
364
+ id: 'r17-email',
365
+ rule: (c, name) => TEXTISH.has(c.logicalType) && EMAIL_RE.test(name)
366
+ ? hit('email', 0.9, 'mono', ['name matches email pattern'])
367
+ : null,
368
+ },
369
+ {
370
+ id: 'r18-phone',
371
+ rule: (c, name) => TEXTISH.has(c.logicalType) && PHONE_RE.test(name)
372
+ ? hit('phone', 0.85, 'tel', ['name matches phone/fax pattern'])
373
+ : null,
374
+ },
375
+ {
376
+ id: 'r19-image-url',
377
+ rule: (c, name) => (TEXTISH.has(c.logicalType) || c.logicalType === 'binary') && IMAGE_RE.test(name)
378
+ ? hit('image-url', 0.8, null, ['name matches image/avatar vocabulary'])
379
+ : null,
380
+ },
381
+ {
382
+ id: 'r20-file-ref',
383
+ rule: (c, name) => {
384
+ if (TEXTISH.has(c.logicalType) && FILE_RE.test(name)) {
385
+ return hit('file-ref', 0.75, null, ['name matches file/attachment vocabulary']);
386
+ }
387
+ if (c.logicalType === 'binary') {
388
+ return hit('file-ref', 0.7, null, ['binary column without a more specific match']);
389
+ }
390
+ return null;
391
+ },
392
+ },
393
+ {
394
+ id: 'r21-url',
395
+ rule: (c, name) => TEXTISH.has(c.logicalType) && URL_RE.test(name)
396
+ ? hit('url', 0.8, null, ['name matches url/link vocabulary'])
397
+ : null,
398
+ },
399
+ {
400
+ id: 'r22-boolean-flag',
401
+ rule: (c, name, ctx) => {
402
+ const nameOk = BOOL_PREFIX_RE.test(name) || BOOL_SUFFIX_RE.test(name);
403
+ if (!nameOk)
404
+ return null;
405
+ if (c.logicalType === 'boolean') {
406
+ return hit('boolean-flag', 0.85, null, ['boolean type + flag vocabulary']);
407
+ }
408
+ if (/^tinyint\(1\)/i.test(c.dbType)) {
409
+ return hit('boolean-flag', 0.85, null, ['tinyint(1) + flag vocabulary']);
410
+ }
411
+ if (c.logicalType === 'integer') {
412
+ const bounds = checkBounds(ctx.table, c.name);
413
+ if (bounds !== null && bounds.min >= 0 && bounds.max <= 1) {
414
+ return hit('boolean-flag', 0.8, null, ['integer with 0–1 CHECK + flag vocabulary']);
415
+ }
416
+ }
417
+ return null;
418
+ },
419
+ },
420
+ {
421
+ id: 'r23-color',
422
+ rule: (c, name) => TEXTISH.has(c.logicalType) &&
423
+ COLOR_RE.test(name) &&
424
+ (c.maxLength === null || c.maxLength <= 9)
425
+ ? hit('color', 0.75, 'color-swatch', ['name matches color vocabulary (trusted at setup)'])
426
+ : null,
427
+ },
428
+ {
429
+ id: 'r24-tags',
430
+ rule: (c, name) => (c.isArray || TEXTISH.has(c.logicalType) || c.logicalType === 'json') && TAGS_RE.test(name)
431
+ ? hit('tags', 0.8, null, ['name matches tags/labels vocabulary'])
432
+ : null,
433
+ },
434
+ {
435
+ id: 'r25-slug',
436
+ rule: (c, name) => {
437
+ if (!TEXTISH.has(c.logicalType) || !SLUG_RE.test(name))
438
+ return null;
439
+ const reasons = ['name matches slug vocabulary'];
440
+ if (c.isUnique)
441
+ reasons.push('unique constraint confirms natural key');
442
+ return hit('slug', c.isUnique ? 0.85 : 0.7, 'mono', reasons);
443
+ },
444
+ },
445
+ {
446
+ id: 'r26-ip-address',
447
+ rule: (c, name) => {
448
+ if (c.logicalType === 'inet') {
449
+ return hit('ip-address', 0.95, 'mono', ['inet column type']);
450
+ }
451
+ if (TEXTISH.has(c.logicalType) && IP_RE.test(name)) {
452
+ return hit('ip-address', 0.85, 'mono', ['name matches ip pattern']);
453
+ }
454
+ return null;
455
+ },
456
+ },
457
+ {
458
+ id: 'r27-json-config',
459
+ rule: (c) => c.logicalType === 'json' ? hit('json-config', 0.9, null, ['json/jsonb column type']) : null,
460
+ },
461
+ {
462
+ id: 'r28-external-id',
463
+ rule: (c, name) => {
464
+ const typeOk = TEXTISH.has(c.logicalType) || NUMERIC.has(c.logicalType) || c.logicalType === 'uuid';
465
+ if (!typeOk || !EXTERNAL_ID_RE.test(name))
466
+ return null;
467
+ return hit('external-id', 0.6, 'mono', ['id-suffixed name unresolved by relation inference (§6)']);
468
+ },
469
+ },
470
+ {
471
+ id: 'r29-free-text',
472
+ rule: (c) => {
473
+ if (c.logicalType === 'text') {
474
+ return hit('free-text', 0.6, null, ['unbounded text type']);
475
+ }
476
+ if (c.logicalType === 'varchar' && c.maxLength !== null && c.maxLength >= 280) {
477
+ return hit('free-text', 0.6, null, [`varchar(${c.maxLength}) ≥ 280 treated as long text`]);
478
+ }
479
+ return null;
480
+ },
481
+ },
482
+ {
483
+ id: 'r30-plain',
484
+ rule: () => hit('plain', 0.5, null, ['no §7.1 rule matched — type-default rendering']),
485
+ },
486
+ ];
487
+ /** Every §7.1 rule id, in precedence order (exported for tests/docs). */
488
+ export const COLUMN_RULE_IDS = RULES.map((r) => r.id);
489
+ // ---------------------------------------------------------------------------
490
+ // Entry points
491
+ // ---------------------------------------------------------------------------
492
+ /** Classify one column within its table context. Pure and deterministic. */
493
+ export function classifyColumn(column, ctx) {
494
+ const name = normalizeName(column.name);
495
+ let ruleId = 'r30-plain';
496
+ let matched = RULES[RULES.length - 1].rule(column, name, ctx);
497
+ for (const { id, rule } of RULES) {
498
+ const result = rule(column, name, ctx);
499
+ if (result !== null) {
500
+ ruleId = id;
501
+ matched = result;
502
+ break;
503
+ }
504
+ }
505
+ const piiResult = detectPii(column, matched.tag, {
506
+ peopleish: ctx.peopleish,
507
+ isGeoPointPair: ctx.pairs.get(column.name)?.semantic === 'geo-point',
508
+ });
509
+ const secret = matched.secret === true;
510
+ const semantics = {
511
+ primary: matched.tag,
512
+ flags: {
513
+ secret,
514
+ pii: piiResult.pii,
515
+ maskedByDefault: secret || piiResult.maskedByDefault,
516
+ },
517
+ format: matched.format,
518
+ pair: matched.pair ?? null,
519
+ confidence: matched.confidence,
520
+ source: 'heuristic',
521
+ };
522
+ return {
523
+ tableId: ctx.table.id,
524
+ column: column.name,
525
+ ruleId,
526
+ reasons: [...matched.reasons, ...piiResult.reasons],
527
+ semantics,
528
+ };
529
+ }
530
+ /** Classify every column of a table (ordinal order preserved). */
531
+ export function classifyTableColumns(model, table) {
532
+ const ctx = buildColumnClassifyContext(model, table);
533
+ return table.columns.map((column) => classifyColumn(column, ctx));
534
+ }
535
+ //# sourceMappingURL=columns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"columns.js","sourceRoot":"","sources":["../../src/classify/columns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `@adminium/engine` classification entry point — 05-introspection-engine.md
3
+ * §§6–8 (05-T07 column semantics + PII layer, 05-T08 table shapes).
4
+ *
5
+ * Everything here is pure and deterministic: same model in, same
6
+ * classification out — a requirement inherited by `generate()` (05 §9).
7
+ */
8
+ import type { DatabaseModel } from '../schema-model.js';
9
+ import { type ClassifiedTable } from './tables.js';
10
+ export { nameTokens, normalizeName } from './names.js';
11
+ export { detectPii, type PiiContext, type PiiResult } from './pii.js';
12
+ export { buildColumnClassifyContext, checkBounds, classifyColumn, classifyTableColumns, COLUMN_RULE_IDS, PEOPLE_TABLE_RE, WORKFLOW_VALUE_RE, type ClassifiedColumn, type ColumnClassifyContext, type PairAssignment, } from './columns.js';
13
+ export { classifyTable, detectJoinTable, selectDisplayColumn, selectNaturalKey, TABLE_SHAPE_KINDS, type ClassifiedTable, type JoinTableResult, type TableShape, type TableShapeKind, } from './tables.js';
14
+ /** Full classification result for a model, sorted by tableId for stability. */
15
+ export interface ClassifiedModel {
16
+ /** `${schema}.${name}` of the source model, for traceability. */
17
+ modelName: string;
18
+ tables: ClassifiedTable[];
19
+ }
20
+ /** Classify every table + column of a model. Pure; does not mutate `model`. */
21
+ export declare function classifyModel(model: DatabaseModel): ClassifiedModel;
22
+ /**
23
+ * Return a NEW model with `ColumnModel.semantics` / `TableModel.semantics`
24
+ * filled from the classifier. Existing non-heuristic semantics (LLM or
25
+ * Studio overrides — `source: 'llm' | 'override'`) are preserved: overrides
26
+ * always win (05 §7).
27
+ */
28
+ export declare function applyClassification(model: DatabaseModel): DatabaseModel;
29
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/classify/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EACL,0BAA0B,EAC1B,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AAErB,+EAA+E;AAC/E,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,+EAA+E;AAC/E,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,eAAe,CAKnE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAuBvE"}
@@ -0,0 +1,44 @@
1
+ import { classifyTable } from './tables.js';
2
+ export { nameTokens, normalizeName } from './names.js';
3
+ export { detectPii } from './pii.js';
4
+ export { buildColumnClassifyContext, checkBounds, classifyColumn, classifyTableColumns, COLUMN_RULE_IDS, PEOPLE_TABLE_RE, WORKFLOW_VALUE_RE, } from './columns.js';
5
+ export { classifyTable, detectJoinTable, selectDisplayColumn, selectNaturalKey, TABLE_SHAPE_KINDS, } from './tables.js';
6
+ /** Classify every table + column of a model. Pure; does not mutate `model`. */
7
+ export function classifyModel(model) {
8
+ const tables = [...model.tables]
9
+ .sort((a, b) => a.id.localeCompare(b.id))
10
+ .map((table) => classifyTable(model, table));
11
+ return { modelName: model.name, tables };
12
+ }
13
+ /**
14
+ * Return a NEW model with `ColumnModel.semantics` / `TableModel.semantics`
15
+ * filled from the classifier. Existing non-heuristic semantics (LLM or
16
+ * Studio overrides — `source: 'llm' | 'override'`) are preserved: overrides
17
+ * always win (05 §7).
18
+ */
19
+ export function applyClassification(model) {
20
+ const classified = new Map(classifyModel(model).tables.map((t) => [t.tableId, t]));
21
+ return {
22
+ ...model,
23
+ tables: model.tables.map((table) => {
24
+ const result = classified.get(table.id);
25
+ if (result === undefined)
26
+ return table;
27
+ const byColumn = new Map(result.columns.map((c) => [c.column, c]));
28
+ return {
29
+ ...table,
30
+ semantics: table.semantics ?? result.semantics,
31
+ columns: table.columns.map((column) => {
32
+ if (column.semantics !== null && column.semantics.source !== 'heuristic') {
33
+ return column;
34
+ }
35
+ const columnResult = byColumn.get(column.name);
36
+ return columnResult === undefined
37
+ ? column
38
+ : { ...column, semantics: columnResult.semantics };
39
+ }),
40
+ };
41
+ }),
42
+ };
43
+ }
44
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/classify/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAwB,MAAM,aAAa,CAAC;AAElE,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,SAAS,EAAmC,MAAM,UAAU,CAAC;AACtE,OAAO,EACL,0BAA0B,EAC1B,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,iBAAiB,GAIlB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,GAKlB,MAAM,aAAa,CAAC;AASrB,+EAA+E;AAC/E,MAAM,UAAU,aAAa,CAAC,KAAoB;IAChD,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;SAC7B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;SACxC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAC/C,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAoB;IACtD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACnF,OAAO;QACL,GAAG,KAAK;QACR,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YACjC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACxC,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAC;YACvC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACnE,OAAO;gBACL,GAAG,KAAK;gBACR,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,MAAM,CAAC,SAAS;gBAC9C,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;oBACpC,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;wBACzE,OAAO,MAAM,CAAC;oBAChB,CAAC;oBACD,MAAM,YAAY,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;oBAC/C,OAAO,YAAY,KAAK,SAAS;wBAC/B,CAAC,CAAC,MAAM;wBACR,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,EAAE,CAAC;gBACvD,CAAC,CAAC;aACH,CAAC;QACJ,CAAC,CAAC;KACH,CAAC;AACJ,CAAC"}