@drzl/analyzer 1.9.0 → 1.10.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/dist/index.cjs +51 -2
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +48 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,7 +32,9 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
SchemaAnalyzer: () => SchemaAnalyzer,
|
|
34
34
|
default: () => index_default,
|
|
35
|
-
describeV1Column: () => describeV1Column
|
|
35
|
+
describeV1Column: () => describeV1Column,
|
|
36
|
+
isRelationsV2: () => isRelationsV2,
|
|
37
|
+
readRelationsV2: () => readRelationsV2
|
|
36
38
|
});
|
|
37
39
|
module.exports = __toCommonJS(index_exports);
|
|
38
40
|
var import_meta = {};
|
|
@@ -216,6 +218,47 @@ function declaredLength(column) {
|
|
|
216
218
|
const n = column?.length ?? column?.config?.length ?? column?.config?.dimensions;
|
|
217
219
|
return typeof n === "number" && Number.isFinite(n) && n > 0 ? n : void 0;
|
|
218
220
|
}
|
|
221
|
+
function getSymbolOf(target, key) {
|
|
222
|
+
if (!target) return void 0;
|
|
223
|
+
try {
|
|
224
|
+
for (const sym of Object.getOwnPropertySymbols(target)) {
|
|
225
|
+
if (sym.description === key) return target[sym];
|
|
226
|
+
}
|
|
227
|
+
} catch {
|
|
228
|
+
}
|
|
229
|
+
return target[Symbol.for(key)];
|
|
230
|
+
}
|
|
231
|
+
function isRelationsV2(val) {
|
|
232
|
+
if (!val || typeof val !== "object" || Array.isArray(val)) return false;
|
|
233
|
+
const entries = Object.values(val);
|
|
234
|
+
if (!entries.length) return false;
|
|
235
|
+
return entries.every(
|
|
236
|
+
(e) => !!e && typeof e === "object" && !!e.table && !!e.relations && typeof e.relations === "object" && Object.values(e.relations).every(
|
|
237
|
+
(r) => r?.relationType === "one" || r?.relationType === "many"
|
|
238
|
+
)
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
function readRelationsV2(val, issues = []) {
|
|
242
|
+
const out = [];
|
|
243
|
+
for (const [tableKey, entry] of Object.entries(val)) {
|
|
244
|
+
const from = getSymbolOf(entry.table, "drizzle:Name") ?? entry.name ?? tableKey;
|
|
245
|
+
for (const [fieldName, r] of Object.entries(entry.relations ?? {})) {
|
|
246
|
+
const to = r?.targetTableName;
|
|
247
|
+
if (typeof to !== "string" || !to) {
|
|
248
|
+
issues.push({
|
|
249
|
+
code: "DRZL_ANL_REL_V2",
|
|
250
|
+
level: "warn",
|
|
251
|
+
message: `Relation "${fieldName}" on "${from}" names no target table and was skipped.`
|
|
252
|
+
});
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const via = getSymbolOf(r.throughTable, "drizzle:Name") ?? getSymbolOf(r.through?.sourceTable, "drizzle:Name") ?? void 0;
|
|
256
|
+
if (via) out.push({ kind: "manyToMany", from, to, via });
|
|
257
|
+
else out.push({ kind: r.relationType === "many" ? "many" : "one", from, to });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return out;
|
|
261
|
+
}
|
|
219
262
|
var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
220
263
|
constructor(schemaPath) {
|
|
221
264
|
this.schemaPath = schemaPath;
|
|
@@ -769,6 +812,10 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
769
812
|
if (opts.includeRelations) {
|
|
770
813
|
relations.push(...this.readRelationsObject(val, name, issues));
|
|
771
814
|
}
|
|
815
|
+
} else if (isRelationsV2(val)) {
|
|
816
|
+
if (opts.includeRelations) {
|
|
817
|
+
relations.push(...readRelationsV2(val, issues));
|
|
818
|
+
}
|
|
772
819
|
} else {
|
|
773
820
|
const ev = val?.enumValues;
|
|
774
821
|
if (Array.isArray(ev) && ev.every((x) => typeof x === "string")) {
|
|
@@ -906,5 +953,7 @@ var index_default = SchemaAnalyzer;
|
|
|
906
953
|
// Annotate the CommonJS export names for ESM import in node:
|
|
907
954
|
0 && (module.exports = {
|
|
908
955
|
SchemaAnalyzer,
|
|
909
|
-
describeV1Column
|
|
956
|
+
describeV1Column,
|
|
957
|
+
isRelationsV2,
|
|
958
|
+
readRelationsV2
|
|
910
959
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -206,6 +206,25 @@ interface AnalyzeOptions {
|
|
|
206
206
|
* path below untouched.
|
|
207
207
|
*/
|
|
208
208
|
declare function describeV1Column(column: any): Partial<Column> | null;
|
|
209
|
+
/**
|
|
210
|
+
* Whether an export is a Relations v2 definition, from `defineRelations(schema, (r) => ...)`.
|
|
211
|
+
*
|
|
212
|
+
* v2 returns a plain object keyed by table name, each entry `{ table, name, relations }`, with
|
|
213
|
+
* no marker class or symbol to match on. So the shape is what identifies it: every value has a
|
|
214
|
+
* `relations` record whose entries carry a `relationType`. That is specific enough not to
|
|
215
|
+
* collide with a table or an enum, both of which are checked before this.
|
|
216
|
+
*/
|
|
217
|
+
declare function isRelationsV2(val: any): boolean;
|
|
218
|
+
/**
|
|
219
|
+
* Read the relations declared by `defineRelations`.
|
|
220
|
+
*
|
|
221
|
+
* Simpler than the v1 reader, which has to invoke a callback with a stand-in builder to find
|
|
222
|
+
* out what was declared. v2 has already resolved everything: each descriptor states its
|
|
223
|
+
* `relationType`, its `targetTableName`, and for a many-to-many its `through` table, so nothing
|
|
224
|
+
* has to be inferred and the join table is stated rather than guessed at by the heuristic that
|
|
225
|
+
* covers v1.
|
|
226
|
+
*/
|
|
227
|
+
declare function readRelationsV2(val: any, issues?: Issue[]): Relation[];
|
|
209
228
|
declare class SchemaAnalyzer {
|
|
210
229
|
private readonly schemaPath;
|
|
211
230
|
constructor(schemaPath: string);
|
|
@@ -310,4 +329,4 @@ declare class SchemaAnalyzer {
|
|
|
310
329
|
analyze(opts?: AnalyzeOptions): Promise<Analysis>;
|
|
311
330
|
}
|
|
312
331
|
|
|
313
|
-
export { type Analysis, type AnalyzeOptions, type Check, type Column, type ColumnRef, type ColumnShape, type Dialect, type Enum, type ForeignKey, type Index, type Issue, type Key, type Relation, SchemaAnalyzer, type Table, SchemaAnalyzer as default, describeV1Column };
|
|
332
|
+
export { type Analysis, type AnalyzeOptions, type Check, type Column, type ColumnRef, type ColumnShape, type Dialect, type Enum, type ForeignKey, type Index, type Issue, type Key, type Relation, SchemaAnalyzer, type Table, SchemaAnalyzer as default, describeV1Column, isRelationsV2, readRelationsV2 };
|
package/dist/index.d.ts
CHANGED
|
@@ -206,6 +206,25 @@ interface AnalyzeOptions {
|
|
|
206
206
|
* path below untouched.
|
|
207
207
|
*/
|
|
208
208
|
declare function describeV1Column(column: any): Partial<Column> | null;
|
|
209
|
+
/**
|
|
210
|
+
* Whether an export is a Relations v2 definition, from `defineRelations(schema, (r) => ...)`.
|
|
211
|
+
*
|
|
212
|
+
* v2 returns a plain object keyed by table name, each entry `{ table, name, relations }`, with
|
|
213
|
+
* no marker class or symbol to match on. So the shape is what identifies it: every value has a
|
|
214
|
+
* `relations` record whose entries carry a `relationType`. That is specific enough not to
|
|
215
|
+
* collide with a table or an enum, both of which are checked before this.
|
|
216
|
+
*/
|
|
217
|
+
declare function isRelationsV2(val: any): boolean;
|
|
218
|
+
/**
|
|
219
|
+
* Read the relations declared by `defineRelations`.
|
|
220
|
+
*
|
|
221
|
+
* Simpler than the v1 reader, which has to invoke a callback with a stand-in builder to find
|
|
222
|
+
* out what was declared. v2 has already resolved everything: each descriptor states its
|
|
223
|
+
* `relationType`, its `targetTableName`, and for a many-to-many its `through` table, so nothing
|
|
224
|
+
* has to be inferred and the join table is stated rather than guessed at by the heuristic that
|
|
225
|
+
* covers v1.
|
|
226
|
+
*/
|
|
227
|
+
declare function readRelationsV2(val: any, issues?: Issue[]): Relation[];
|
|
209
228
|
declare class SchemaAnalyzer {
|
|
210
229
|
private readonly schemaPath;
|
|
211
230
|
constructor(schemaPath: string);
|
|
@@ -310,4 +329,4 @@ declare class SchemaAnalyzer {
|
|
|
310
329
|
analyze(opts?: AnalyzeOptions): Promise<Analysis>;
|
|
311
330
|
}
|
|
312
331
|
|
|
313
|
-
export { type Analysis, type AnalyzeOptions, type Check, type Column, type ColumnRef, type ColumnShape, type Dialect, type Enum, type ForeignKey, type Index, type Issue, type Key, type Relation, SchemaAnalyzer, type Table, SchemaAnalyzer as default, describeV1Column };
|
|
332
|
+
export { type Analysis, type AnalyzeOptions, type Check, type Column, type ColumnRef, type ColumnShape, type Dialect, type Enum, type ForeignKey, type Index, type Issue, type Key, type Relation, SchemaAnalyzer, type Table, SchemaAnalyzer as default, describeV1Column, isRelationsV2, readRelationsV2 };
|
package/dist/index.js
CHANGED
|
@@ -179,6 +179,47 @@ function declaredLength(column) {
|
|
|
179
179
|
const n = column?.length ?? column?.config?.length ?? column?.config?.dimensions;
|
|
180
180
|
return typeof n === "number" && Number.isFinite(n) && n > 0 ? n : void 0;
|
|
181
181
|
}
|
|
182
|
+
function getSymbolOf(target, key) {
|
|
183
|
+
if (!target) return void 0;
|
|
184
|
+
try {
|
|
185
|
+
for (const sym of Object.getOwnPropertySymbols(target)) {
|
|
186
|
+
if (sym.description === key) return target[sym];
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
return target[Symbol.for(key)];
|
|
191
|
+
}
|
|
192
|
+
function isRelationsV2(val) {
|
|
193
|
+
if (!val || typeof val !== "object" || Array.isArray(val)) return false;
|
|
194
|
+
const entries = Object.values(val);
|
|
195
|
+
if (!entries.length) return false;
|
|
196
|
+
return entries.every(
|
|
197
|
+
(e) => !!e && typeof e === "object" && !!e.table && !!e.relations && typeof e.relations === "object" && Object.values(e.relations).every(
|
|
198
|
+
(r) => r?.relationType === "one" || r?.relationType === "many"
|
|
199
|
+
)
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
function readRelationsV2(val, issues = []) {
|
|
203
|
+
const out = [];
|
|
204
|
+
for (const [tableKey, entry] of Object.entries(val)) {
|
|
205
|
+
const from = getSymbolOf(entry.table, "drizzle:Name") ?? entry.name ?? tableKey;
|
|
206
|
+
for (const [fieldName, r] of Object.entries(entry.relations ?? {})) {
|
|
207
|
+
const to = r?.targetTableName;
|
|
208
|
+
if (typeof to !== "string" || !to) {
|
|
209
|
+
issues.push({
|
|
210
|
+
code: "DRZL_ANL_REL_V2",
|
|
211
|
+
level: "warn",
|
|
212
|
+
message: `Relation "${fieldName}" on "${from}" names no target table and was skipped.`
|
|
213
|
+
});
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
const via = getSymbolOf(r.throughTable, "drizzle:Name") ?? getSymbolOf(r.through?.sourceTable, "drizzle:Name") ?? void 0;
|
|
217
|
+
if (via) out.push({ kind: "manyToMany", from, to, via });
|
|
218
|
+
else out.push({ kind: r.relationType === "many" ? "many" : "one", from, to });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return out;
|
|
222
|
+
}
|
|
182
223
|
var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
183
224
|
constructor(schemaPath) {
|
|
184
225
|
this.schemaPath = schemaPath;
|
|
@@ -732,6 +773,10 @@ var _SchemaAnalyzer = class _SchemaAnalyzer {
|
|
|
732
773
|
if (opts.includeRelations) {
|
|
733
774
|
relations.push(...this.readRelationsObject(val, name, issues));
|
|
734
775
|
}
|
|
776
|
+
} else if (isRelationsV2(val)) {
|
|
777
|
+
if (opts.includeRelations) {
|
|
778
|
+
relations.push(...readRelationsV2(val, issues));
|
|
779
|
+
}
|
|
735
780
|
} else {
|
|
736
781
|
const ev = val?.enumValues;
|
|
737
782
|
if (Array.isArray(ev) && ev.every((x) => typeof x === "string")) {
|
|
@@ -869,5 +914,7 @@ var index_default = SchemaAnalyzer;
|
|
|
869
914
|
export {
|
|
870
915
|
SchemaAnalyzer,
|
|
871
916
|
index_default as default,
|
|
872
|
-
describeV1Column
|
|
917
|
+
describeV1Column,
|
|
918
|
+
isRelationsV2,
|
|
919
|
+
readRelationsV2
|
|
873
920
|
};
|