@dereekb/dbx-cli 13.11.14 → 13.11.16

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.
@@ -36,15 +36,21 @@ function collectGroupsFromConfig(initializer, importIdentToModule, sink) {
36
36
  }
37
37
  }
38
38
  function readGroupFromProperty(property, importIdentToModule) {
39
- if (!Node.isPropertyAssignment(property)) return void 0;
40
- const valueExpr = property.getInitializer();
41
- if (!valueExpr || !Node.isArrayLiteralExpression(valueExpr)) return void 0;
42
- const first = valueExpr.getElements()[0];
43
- if (!first || !Node.isIdentifier(first)) return void 0;
44
- const className = first.getText();
45
- const importedFromModule = importIdentToModule.get(className);
46
- if (!importedFromModule) return void 0;
47
- return { groupKey: property.getName(), className, importedFromModule };
39
+ let result;
40
+ if (Node.isPropertyAssignment(property)) {
41
+ const valueExpr = property.getInitializer();
42
+ if (valueExpr && Node.isArrayLiteralExpression(valueExpr)) {
43
+ const first = valueExpr.getElements()[0];
44
+ if (first && Node.isIdentifier(first)) {
45
+ const className = first.getText();
46
+ const importedFromModule = importIdentToModule.get(className);
47
+ if (importedFromModule) {
48
+ result = { groupKey: property.getName(), className, importedFromModule };
49
+ }
50
+ }
51
+ }
52
+ }
53
+ return result;
48
54
  }
49
55
  function isFunctionsConfigVariable(variable) {
50
56
  const name = variable.getName();
@@ -67,63 +73,80 @@ import { existsSync, readFileSync as readFileSync2 } from "node:fs";
67
73
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
68
74
  var _pathsCache;
69
75
  function loadTsconfigPaths(workspaceRoot) {
70
- if (_pathsCache) return _pathsCache;
71
- const tsconfigPath = join(workspaceRoot, "tsconfig.base.json");
72
- const raw = readFileSync2(tsconfigPath, "utf8");
73
- const cleaned = stripJsonComments(raw);
74
- const tsconfig = JSON.parse(cleaned);
75
- const paths = tsconfig.compilerOptions?.paths ?? {};
76
- const map = /* @__PURE__ */ new Map();
77
- for (const [key, value] of Object.entries(paths)) {
78
- if (Array.isArray(value) && value[0]) {
79
- map.set(key, resolve(workspaceRoot, value[0]));
76
+ let result;
77
+ if (_pathsCache) {
78
+ result = _pathsCache;
79
+ } else {
80
+ const tsconfigPath = join(workspaceRoot, "tsconfig.base.json");
81
+ const raw = readFileSync2(tsconfigPath, "utf8");
82
+ const cleaned = stripJsonComments(raw);
83
+ const tsconfig = JSON.parse(cleaned);
84
+ const paths = tsconfig.compilerOptions?.paths ?? {};
85
+ const map = /* @__PURE__ */ new Map();
86
+ for (const [key, value] of Object.entries(paths)) {
87
+ if (Array.isArray(value) && value[0]) {
88
+ map.set(key, resolve(workspaceRoot, value[0]));
89
+ }
80
90
  }
91
+ _pathsCache = map;
92
+ result = map;
81
93
  }
82
- _pathsCache = map;
83
- return map;
94
+ return result;
84
95
  }
85
96
  function resolveModuleToPackage(input) {
86
97
  const { workspaceRoot, importingFile, moduleSpecifier } = input;
98
+ let result;
87
99
  if (moduleSpecifier.startsWith(".")) {
88
100
  const importingDir = dirname(importingFile);
89
101
  const candidatePath = resolve(importingDir, moduleSpecifier);
90
- return locatePackageForPath(workspaceRoot, candidatePath);
102
+ result = locatePackageForPath(workspaceRoot, candidatePath);
103
+ } else {
104
+ const paths = loadTsconfigPaths(workspaceRoot);
105
+ const indexFile = paths.get(moduleSpecifier);
106
+ if (indexFile) {
107
+ result = locatePackageForPath(workspaceRoot, indexFile);
108
+ } else {
109
+ result = locatePackageInNodeModules({ workspaceRoot, importingFile, moduleSpecifier });
110
+ }
91
111
  }
92
- const paths = loadTsconfigPaths(workspaceRoot);
93
- const indexFile = paths.get(moduleSpecifier);
94
- if (indexFile) return locatePackageForPath(workspaceRoot, indexFile);
95
- return locatePackageInNodeModules({ workspaceRoot, importingFile, moduleSpecifier });
112
+ return result;
96
113
  }
97
114
  function locatePackageInNodeModules(input) {
98
115
  const { importingFile, moduleSpecifier } = input;
99
116
  let current = dirname(importingFile);
100
- while (current && current !== dirname(current)) {
117
+ let result;
118
+ while (!result && current && current !== dirname(current)) {
101
119
  const candidateRoot = join(current, "node_modules", moduleSpecifier);
102
120
  const pkgJson = join(candidateRoot, "package.json");
103
121
  if (existsSync(pkgJson)) {
104
122
  try {
105
123
  const pkg = JSON.parse(readFileSync2(pkgJson, "utf8"));
106
- if (pkg.name) return { packageName: pkg.name, packageRoot: candidateRoot };
124
+ if (pkg.name) {
125
+ result = { packageName: pkg.name, packageRoot: candidateRoot };
126
+ }
107
127
  } catch {
108
128
  }
109
129
  }
110
- current = dirname(current);
130
+ if (!result) current = dirname(current);
111
131
  }
112
- return void 0;
132
+ return result;
113
133
  }
114
134
  function locatePackageForPath(workspaceRoot, startPath) {
115
135
  let current = startPath;
116
- while (current && current !== workspaceRoot && current !== dirname(current)) {
136
+ let result;
137
+ while (!result && current && current !== workspaceRoot && current !== dirname(current)) {
117
138
  if (existsSync(join(current, "package.json"))) {
118
139
  try {
119
140
  const pkg = JSON.parse(readFileSync2(join(current, "package.json"), "utf8"));
120
- if (pkg.name) return { packageName: pkg.name, packageRoot: current };
141
+ if (pkg.name) {
142
+ result = { packageName: pkg.name, packageRoot: current };
143
+ }
121
144
  } catch {
122
145
  }
123
146
  }
124
- current = dirname(current);
147
+ if (!result) current = dirname(current);
125
148
  }
126
- return void 0;
149
+ return result;
127
150
  }
128
151
  function relPath(workspaceRoot, absolutePath) {
129
152
  return relative(workspaceRoot, absolutePath).split("\\").join("/");
@@ -149,17 +172,18 @@ function extractCrudEntries(source) {
149
172
  const functionsClassName = findFunctionsClassName(sourceFile);
150
173
  const typeDocsCache = /* @__PURE__ */ new Map();
151
174
  const resolveTypeDocs = (typeName) => {
152
- if (!typeName) {
153
- return void 0;
154
- }
155
- if (typeDocsCache.has(typeName)) {
156
- return typeDocsCache.get(typeName);
157
- }
158
- const docs = readTypeDocs(sourceFile, typeName);
159
- if (docs) {
160
- typeDocsCache.set(typeName, docs);
175
+ let result;
176
+ if (typeName) {
177
+ if (typeDocsCache.has(typeName)) {
178
+ result = typeDocsCache.get(typeName);
179
+ } else {
180
+ result = readTypeDocs(sourceFile, typeName);
181
+ if (result) {
182
+ typeDocsCache.set(typeName, result);
183
+ }
184
+ }
161
185
  }
162
- return docs;
186
+ return result;
163
187
  };
164
188
  if (crudConfigType) {
165
189
  const literal = crudConfigType.getTypeNode();
@@ -229,54 +253,64 @@ function extractCrudEntries(source) {
229
253
  return { groupName, modelKeys, entries, functionsClassName };
230
254
  }
231
255
  function findTypeAliasByEnding(sourceFile, ending) {
256
+ let result;
232
257
  for (const alias of sourceFile.getTypeAliases()) {
233
258
  if (alias.getName().endsWith(ending) && alias.getTypeNode()) {
234
- return alias;
259
+ result = alias;
260
+ break;
235
261
  }
236
262
  }
237
- return void 0;
263
+ return result;
238
264
  }
239
265
  function findFunctionsClassName(sourceFile) {
266
+ let result;
240
267
  for (const cls of sourceFile.getClasses()) {
241
268
  if (!cls.isAbstract()) {
242
269
  continue;
243
270
  }
244
271
  const name = cls.getName();
245
272
  if (name?.endsWith("Functions")) {
246
- return name;
273
+ result = name;
274
+ break;
247
275
  }
248
276
  }
249
- return void 0;
277
+ return result;
250
278
  }
251
279
  function inferGroupName(sourceFile) {
280
+ let result;
252
281
  for (const alias of sourceFile.getTypeAliases()) {
253
282
  const name = alias.getName();
254
283
  if (name.endsWith("ModelCrudFunctionsConfig")) {
255
284
  const stem = name.slice(0, -"ModelCrudFunctionsConfig".length);
256
285
  if (stem.length > 0) {
257
- return stem;
286
+ result = stem;
287
+ break;
258
288
  }
259
289
  }
260
290
  }
261
- for (const alias of sourceFile.getTypeAliases()) {
262
- const name = alias.getName();
263
- if (name.endsWith("FunctionTypeMap")) {
264
- const stem = name.slice(0, -"FunctionTypeMap".length);
265
- if (stem.length > 0) {
266
- return stem;
291
+ if (result === void 0) {
292
+ for (const alias of sourceFile.getTypeAliases()) {
293
+ const name = alias.getName();
294
+ if (name.endsWith("FunctionTypeMap")) {
295
+ const stem = name.slice(0, -"FunctionTypeMap".length);
296
+ if (stem.length > 0) {
297
+ result = stem;
298
+ break;
299
+ }
267
300
  }
268
301
  }
269
302
  }
270
- return void 0;
303
+ return result;
271
304
  }
272
305
  function isNullLiteralType(node) {
306
+ let result = false;
273
307
  if (Node2.isLiteralTypeNode(node)) {
274
308
  const literal = node.getLiteral();
275
309
  if (Node2.isNullLiteral(literal)) {
276
- return true;
310
+ result = true;
277
311
  }
278
312
  }
279
- return false;
313
+ return result;
280
314
  }
281
315
  function collectVerbEntries(input) {
282
316
  const { modelName, verb, valueNode, entries, fallbackDescription, resolveTypeDocs } = input;
@@ -324,32 +358,33 @@ function collectVerbEntries(input) {
324
358
  });
325
359
  }
326
360
  function readTupleParamsResult(node) {
327
- if (!Node2.isTupleTypeNode(node)) {
328
- return void 0;
329
- }
330
- const elements = node.getElements();
331
- if (elements.length === 0) {
332
- return void 0;
361
+ let pair;
362
+ if (Node2.isTupleTypeNode(node)) {
363
+ const elements = node.getElements();
364
+ if (elements.length > 0) {
365
+ const params = elements[0] ? typeNodeName(elements[0]) : void 0;
366
+ const result = elements[1] ? typeNodeName(elements[1]) : void 0;
367
+ pair = { params, result };
368
+ }
333
369
  }
334
- const params = elements[0] ? typeNodeName(elements[0]) : void 0;
335
- const result = elements[1] ? typeNodeName(elements[1]) : void 0;
336
- return { params, result };
370
+ return pair;
337
371
  }
338
372
  function readBareParams(node) {
339
373
  const params = typeNodeName(node);
340
- if (!params) {
341
- return void 0;
342
- }
343
- return { params, result: void 0 };
374
+ return params ? { params, result: void 0 } : void 0;
344
375
  }
345
376
  function typeNodeName(node) {
377
+ let result;
346
378
  if (Node2.isTypeReference(node)) {
347
- return node.getTypeName().getText();
379
+ result = node.getTypeName().getText();
380
+ } else {
381
+ const text = node.getText().trim();
382
+ result = text.length > 0 ? text : void 0;
348
383
  }
349
- const text = node.getText().trim();
350
- return text.length > 0 ? text : void 0;
384
+ return result;
351
385
  }
352
386
  function readTypeDocs(sourceFile, typeName) {
387
+ let result;
353
388
  const interfaceDecl = sourceFile.getInterface(typeName);
354
389
  if (interfaceDecl) {
355
390
  const typeDescription = readJsDocSummary(interfaceDecl);
@@ -362,26 +397,31 @@ function readTypeDocs(sourceFile, typeName) {
362
397
  const field = description ? { name: fieldName, typeText, description } : { name: fieldName, typeText };
363
398
  fields.push(field);
364
399
  }
365
- if (!typeDescription && fields.length === 0) {
366
- return void 0;
400
+ if (typeDescription || fields.length > 0) {
401
+ result = { typeDescription, fields: fields.length > 0 ? fields : void 0 };
402
+ }
403
+ } else {
404
+ const typeAlias = sourceFile.getTypeAlias(typeName);
405
+ if (typeAlias) {
406
+ const typeDescription = readJsDocSummary(typeAlias);
407
+ if (typeDescription) {
408
+ result = { typeDescription };
409
+ }
367
410
  }
368
- return { typeDescription, fields: fields.length > 0 ? fields : void 0 };
369
- }
370
- const typeAlias = sourceFile.getTypeAlias(typeName);
371
- if (typeAlias) {
372
- const typeDescription = readJsDocSummary(typeAlias);
373
- return typeDescription ? { typeDescription } : void 0;
374
411
  }
375
- return void 0;
412
+ return result;
376
413
  }
377
414
  function readJsDocSummary(node) {
415
+ let result;
378
416
  const docs = node.getJsDocs();
379
- if (docs.length === 0) {
380
- return void 0;
417
+ if (docs.length > 0) {
418
+ const last = docs[docs.length - 1];
419
+ const description = last.getDescription().trim();
420
+ if (description.length > 0) {
421
+ result = description;
422
+ }
381
423
  }
382
- const last = docs[docs.length - 1];
383
- const description = last.getDescription().trim();
384
- return description.length > 0 ? description : void 0;
424
+ return result;
385
425
  }
386
426
 
387
427
  // packages/dbx-cli/manifest-extract/src/lib/extract-models.ts
@@ -552,20 +592,25 @@ function readGenericInterfaceName(call) {
552
592
  function readConverterFields(call) {
553
593
  const fnName = call.getExpression().getText();
554
594
  const args = call.getArguments();
555
- if (args.length === 0) return void 0;
556
- const config = args[0];
557
- if (!Node3.isObjectLiteralExpression(config)) return void 0;
558
- let fieldsLiteral;
559
- if (fnName === SNAPSHOT_FN) {
560
- fieldsLiteral = readObjectProperty(config, FIELDS_LITERAL_KEY);
561
- } else {
562
- const objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
563
- if (objectField && Node3.isObjectLiteralExpression(objectField)) {
564
- fieldsLiteral = readObjectProperty(objectField, FIELDS_LITERAL_KEY);
595
+ let result;
596
+ if (args.length > 0) {
597
+ const config = args[0];
598
+ if (Node3.isObjectLiteralExpression(config)) {
599
+ let fieldsLiteral;
600
+ if (fnName === SNAPSHOT_FN) {
601
+ fieldsLiteral = readObjectProperty(config, FIELDS_LITERAL_KEY);
602
+ } else {
603
+ const objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
604
+ if (objectField && Node3.isObjectLiteralExpression(objectField)) {
605
+ fieldsLiteral = readObjectProperty(objectField, FIELDS_LITERAL_KEY);
606
+ }
607
+ }
608
+ if (fieldsLiteral) {
609
+ result = readFieldEntries(fieldsLiteral);
610
+ }
565
611
  }
566
612
  }
567
- if (!fieldsLiteral) return void 0;
568
- return readFieldEntries(fieldsLiteral);
613
+ return result;
569
614
  }
570
615
  function readFieldEntries(fields) {
571
616
  const out = [];
@@ -589,33 +634,38 @@ function readFieldEntries(fields) {
589
634
  return out;
590
635
  }
591
636
  function readNestedFromExpression(expr) {
592
- if (!Node3.isCallExpression(expr)) return void 0;
593
- const fnName = expr.getExpression().getText();
594
- if (fnName !== SUB_OBJECT_FN && fnName !== OBJECT_ARRAY_FN) return void 0;
595
- const args = expr.getArguments();
596
- if (args.length === 0) return void 0;
597
- const config = args[0];
598
- if (!Node3.isObjectLiteralExpression(config)) return void 0;
599
- const objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
600
- if (!objectField) return void 0;
601
- const isArray = fnName === OBJECT_ARRAY_FN;
602
637
  let result;
603
- if (Node3.isIdentifier(objectField)) {
604
- result = { ref: objectField.getText(), isArray };
605
- } else if (Node3.isObjectLiteralExpression(objectField)) {
606
- const fieldsLiteral = readObjectProperty(objectField, FIELDS_LITERAL_KEY);
607
- if (fieldsLiteral) {
608
- const inlineFields = readFieldEntries(fieldsLiteral);
609
- result = {
610
- inline: {
611
- converterConst: void 0,
612
- factory: fnName,
613
- interfaceName: readGenericInterfaceName(expr),
614
- fields: inlineFields,
615
- line: expr.getStartLineNumber()
616
- },
617
- isArray
618
- };
638
+ if (Node3.isCallExpression(expr)) {
639
+ const fnName = expr.getExpression().getText();
640
+ if (fnName === SUB_OBJECT_FN || fnName === OBJECT_ARRAY_FN) {
641
+ const args = expr.getArguments();
642
+ if (args.length > 0) {
643
+ const config = args[0];
644
+ if (Node3.isObjectLiteralExpression(config)) {
645
+ const objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
646
+ if (objectField) {
647
+ const isArray = fnName === OBJECT_ARRAY_FN;
648
+ if (Node3.isIdentifier(objectField)) {
649
+ result = { ref: objectField.getText(), isArray };
650
+ } else if (Node3.isObjectLiteralExpression(objectField)) {
651
+ const fieldsLiteral = readObjectProperty(objectField, FIELDS_LITERAL_KEY);
652
+ if (fieldsLiteral) {
653
+ const inlineFields = readFieldEntries(fieldsLiteral);
654
+ result = {
655
+ inline: {
656
+ converterConst: void 0,
657
+ factory: fnName,
658
+ interfaceName: readGenericInterfaceName(expr),
659
+ fields: inlineFields,
660
+ line: expr.getStartLineNumber()
661
+ },
662
+ isArray
663
+ };
664
+ }
665
+ }
666
+ }
667
+ }
668
+ }
619
669
  }
620
670
  }
621
671
  return result;
@@ -749,16 +799,17 @@ function identifierName(node) {
749
799
  // packages/dbx-cli/firebase-api-manifest/src/generate-api-manifest/find-api-files.ts
750
800
  function findApiFiles(packageRoot) {
751
801
  const libRoot = join2(packageRoot, "src", "lib");
752
- if (!safeIsDirectory(libRoot)) return [];
753
802
  const out = [];
754
- const seenClassNames = /* @__PURE__ */ new Set();
755
- for (const file of walkApiFiles(libRoot)) {
756
- const text = readFileSync3(file, "utf8");
757
- const extraction = extractCrudEntries({ name: file, text });
758
- if (!extraction.functionsClassName) continue;
759
- if (seenClassNames.has(extraction.functionsClassName)) continue;
760
- seenClassNames.add(extraction.functionsClassName);
761
- out.push({ filePath: file, className: extraction.functionsClassName, extraction });
803
+ if (safeIsDirectory(libRoot)) {
804
+ const seenClassNames = /* @__PURE__ */ new Set();
805
+ for (const file of walkApiFiles(libRoot)) {
806
+ const text = readFileSync3(file, "utf8");
807
+ const extraction = extractCrudEntries({ name: file, text });
808
+ if (!extraction.functionsClassName) continue;
809
+ if (seenClassNames.has(extraction.functionsClassName)) continue;
810
+ seenClassNames.add(extraction.functionsClassName);
811
+ out.push({ filePath: file, className: extraction.functionsClassName, extraction });
812
+ }
762
813
  }
763
814
  return out;
764
815
  }
@@ -775,15 +826,17 @@ function* walkApiFiles(dir) {
775
826
  }
776
827
  }
777
828
  function isApiFile(name) {
778
- if (name.endsWith(".spec.ts") || name.endsWith(".test.ts")) return false;
779
- return name.endsWith(".api.ts") || name.endsWith(".api.d.ts");
829
+ const isSpec = name.endsWith(".spec.ts") || name.endsWith(".test.ts");
830
+ return !isSpec && (name.endsWith(".api.ts") || name.endsWith(".api.d.ts"));
780
831
  }
781
832
  function safeIsDirectory(p) {
833
+ let result;
782
834
  try {
783
- return statSync(p).isDirectory();
835
+ result = statSync(p).isDirectory();
784
836
  } catch {
785
- return false;
837
+ result = false;
786
838
  }
839
+ return result;
787
840
  }
788
841
 
789
842
  // packages/dbx-cli/firebase-api-manifest/src/generate-api-manifest/find-model-files.ts
@@ -791,24 +844,20 @@ import { readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as
791
844
  import { join as join3 } from "node:path";
792
845
  function findModelFiles(packageRoot) {
793
846
  const libRoot = join3(packageRoot, "src", "lib");
794
- if (!safeIsDirectory2(libRoot)) return [];
795
847
  const out = [];
796
- for (const filePath of walkSourceFiles(libRoot)) {
797
- const text = readFileSync4(filePath, "utf8");
798
- if (!textHasModelMarker(text)) continue;
799
- const extraction = extractModelsFromSource({ name: filePath, text });
800
- if (extraction.identities.length === 0 && extraction.modelGroups.length === 0 && extraction.converters.length === 0) continue;
801
- out.push({ filePath, extraction });
848
+ if (safeIsDirectory2(libRoot)) {
849
+ for (const filePath of walkSourceFiles(libRoot)) {
850
+ const text = readFileSync4(filePath, "utf8");
851
+ if (!textHasModelMarker(text)) continue;
852
+ const extraction = extractModelsFromSource({ name: filePath, text });
853
+ if (extraction.identities.length === 0 && extraction.modelGroups.length === 0 && extraction.converters.length === 0) continue;
854
+ out.push({ filePath, extraction });
855
+ }
802
856
  }
803
857
  return out;
804
858
  }
805
859
  function textHasModelMarker(text) {
806
- if (text.includes("firestoreModelIdentity(")) return true;
807
- if (text.includes("@dbxModelGroup")) return true;
808
- if (text.includes("snapshotConverterFunctions")) return true;
809
- if (text.includes("firestoreSubObject")) return true;
810
- if (text.includes("firestoreObjectArray")) return true;
811
- return false;
860
+ return text.includes("firestoreModelIdentity(") || text.includes("@dbxModelGroup") || text.includes("snapshotConverterFunctions") || text.includes("firestoreSubObject") || text.includes("firestoreObjectArray");
812
861
  }
813
862
  function* walkSourceFiles(dir) {
814
863
  for (const entry of readdirSync2(dir).sort()) {
@@ -823,20 +872,16 @@ function* walkSourceFiles(dir) {
823
872
  }
824
873
  }
825
874
  function isCandidateSourceFile(name) {
826
- if (!name.endsWith(".ts")) return false;
827
- if (name.endsWith(".api.ts")) return false;
828
- if (name.endsWith(".spec.ts")) return false;
829
- if (name.endsWith(".test.ts")) return false;
830
- if (name.endsWith(".id.ts")) return false;
831
- if (name.endsWith(".d.ts")) return false;
832
- return true;
875
+ return name.endsWith(".ts") && !name.endsWith(".api.ts") && !name.endsWith(".spec.ts") && !name.endsWith(".test.ts") && !name.endsWith(".id.ts") && !name.endsWith(".d.ts");
833
876
  }
834
877
  function safeIsDirectory2(p) {
878
+ let result;
835
879
  try {
836
- return statSync2(p).isDirectory();
880
+ result = statSync2(p).isDirectory();
837
881
  } catch {
838
- return false;
882
+ result = false;
839
883
  }
884
+ return result;
840
885
  }
841
886
 
842
887
  // packages/dbx-cli/firebase-api-manifest/src/generate-api-manifest/assemble-models.ts
@@ -895,34 +940,39 @@ function appendEntriesFromSource(source, registries, accumulator) {
895
940
  }
896
941
  function buildEntryForIdentity(input) {
897
942
  const { identity, source, registries, enumNames } = input;
898
- if (identity.collectionPrefix === void 0) return void 0;
899
- const modelName = capitalize(identity.modelType);
900
- const iface = registries.interfaceRegistry.get(modelName);
901
- if (!iface?.hasDbxModelTag) return void 0;
902
- const converter = findConverterForInterface(source.extraction, modelName) ?? findConverterFromRegistry(registries.converterRegistry, modelName);
903
- if (!converter) return void 0;
904
- const fields = buildFields({
905
- converter,
906
- iface,
907
- interfaceRegistry: registries.interfaceRegistry,
908
- converterRegistry: registries.converterRegistry,
909
- enumNames,
910
- depth: 0,
911
- visitedConverters: /* @__PURE__ */ new Set()
912
- });
913
- const modelGroup = registries.groupByModelName.get(modelName);
914
- return {
915
- modelType: identity.modelType,
916
- modelName,
917
- ...modelGroup ? { modelGroup } : {},
918
- identityConst: identity.identityConst,
919
- collectionPrefix: identity.collectionPrefix,
920
- ...identity.parentIdentityConst ? { parentIdentityConst: identity.parentIdentityConst } : {},
921
- ...iface.description ? { description: iface.description } : {},
922
- sourcePackage: source.sourcePackage,
923
- sourceFile: source.sourceFile,
924
- fields
925
- };
943
+ let result;
944
+ if (identity.collectionPrefix !== void 0) {
945
+ const modelName = capitalize(identity.modelType);
946
+ const iface = registries.interfaceRegistry.get(modelName);
947
+ if (iface?.hasDbxModelTag) {
948
+ const converter = findConverterForInterface(source.extraction, modelName) ?? findConverterFromRegistry(registries.converterRegistry, modelName);
949
+ if (converter) {
950
+ const fields = buildFields({
951
+ converter,
952
+ iface,
953
+ interfaceRegistry: registries.interfaceRegistry,
954
+ converterRegistry: registries.converterRegistry,
955
+ enumNames,
956
+ depth: 0,
957
+ visitedConverters: /* @__PURE__ */ new Set()
958
+ });
959
+ const modelGroup = registries.groupByModelName.get(modelName);
960
+ result = {
961
+ modelType: identity.modelType,
962
+ modelName,
963
+ ...modelGroup ? { modelGroup } : {},
964
+ identityConst: identity.identityConst,
965
+ collectionPrefix: identity.collectionPrefix,
966
+ ...identity.parentIdentityConst ? { parentIdentityConst: identity.parentIdentityConst } : {},
967
+ ...iface.description ? { description: iface.description } : {},
968
+ sourcePackage: source.sourcePackage,
969
+ sourceFile: source.sourceFile,
970
+ fields
971
+ };
972
+ }
973
+ }
974
+ }
975
+ return result;
926
976
  }
927
977
  function findConverterForInterface(extraction, interfaceName) {
928
978
  return extraction.converters.find((c) => c.interfaceName === interfaceName);
@@ -975,28 +1025,36 @@ function buildField(input) {
975
1025
  }
976
1026
  function resolveNestedFields(input) {
977
1027
  const { field } = input;
978
- if (input.depth >= MAX_NESTED_DEPTH) return void 0;
979
- let nestedConverter;
980
- if (field.nestedConverterInline) {
981
- nestedConverter = field.nestedConverterInline;
982
- } else if (field.nestedConverterRef) {
983
- if (input.visitedConverters.has(field.nestedConverterRef)) return void 0;
984
- nestedConverter = input.converterRegistry.get(field.nestedConverterRef);
985
- }
986
- if (!nestedConverter) return void 0;
987
- const nextVisited = new Set(input.visitedConverters);
988
- if (nestedConverter.converterConst) nextVisited.add(nestedConverter.converterConst);
989
- const nestedIface = nestedConverter.interfaceName ? input.interfaceRegistry.get(nestedConverter.interfaceName) : void 0;
990
- const fields = buildFields({
991
- converter: nestedConverter,
992
- iface: nestedIface,
993
- interfaceRegistry: input.interfaceRegistry,
994
- converterRegistry: input.converterRegistry,
995
- enumNames: input.enumNames,
996
- depth: input.depth + 1,
997
- visitedConverters: nextVisited
998
- });
999
- return { fields, isArray: field.nestedIsArray ?? false };
1028
+ let result;
1029
+ if (input.depth < MAX_NESTED_DEPTH) {
1030
+ let nestedConverter;
1031
+ let aborted = false;
1032
+ if (field.nestedConverterInline) {
1033
+ nestedConverter = field.nestedConverterInline;
1034
+ } else if (field.nestedConverterRef) {
1035
+ if (input.visitedConverters.has(field.nestedConverterRef)) {
1036
+ aborted = true;
1037
+ } else {
1038
+ nestedConverter = input.converterRegistry.get(field.nestedConverterRef);
1039
+ }
1040
+ }
1041
+ if (!aborted && nestedConverter) {
1042
+ const nextVisited = new Set(input.visitedConverters);
1043
+ if (nestedConverter.converterConst) nextVisited.add(nestedConverter.converterConst);
1044
+ const nestedIface = nestedConverter.interfaceName ? input.interfaceRegistry.get(nestedConverter.interfaceName) : void 0;
1045
+ const fields = buildFields({
1046
+ converter: nestedConverter,
1047
+ iface: nestedIface,
1048
+ interfaceRegistry: input.interfaceRegistry,
1049
+ converterRegistry: input.converterRegistry,
1050
+ enumNames: input.enumNames,
1051
+ depth: input.depth + 1,
1052
+ visitedConverters: nextVisited
1053
+ });
1054
+ result = { fields, isArray: field.nestedIsArray ?? false };
1055
+ }
1056
+ }
1057
+ return result;
1000
1058
  }
1001
1059
  function collectAncestors(iface, registry) {
1002
1060
  const out = [];
@@ -1053,14 +1111,12 @@ function capitalize(s) {
1053
1111
  import { existsSync as existsSync2, readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync3 } from "node:fs";
1054
1112
  import { dirname as dirname2, isAbsolute as isAbsolute2, join as join4, resolve as resolve2 } from "node:path";
1055
1113
  function deriveValidatorName(paramsTypeName) {
1056
- if (!paramsTypeName) return "";
1057
- return paramsTypeName.charAt(0).toLowerCase() + paramsTypeName.slice(1) + "Type";
1114
+ return paramsTypeName ? paramsTypeName.charAt(0).toLowerCase() + paramsTypeName.slice(1) + "Type" : "";
1058
1115
  }
1059
1116
  function isExportedFromPackage(input) {
1060
1117
  const { packageRoot, identifier } = input;
1061
1118
  const indexPath = locateBarrelEntry(packageRoot);
1062
- if (!indexPath) return false;
1063
- return findIdentifierInBarrelChain(indexPath, identifier, /* @__PURE__ */ new Set());
1119
+ return indexPath ? findIdentifierInBarrelChain(indexPath, identifier, /* @__PURE__ */ new Set()) : false;
1064
1120
  }
1065
1121
  function locateBarrelEntry(packageRoot) {
1066
1122
  const candidates = [join4(packageRoot, "src", "index.ts"), join4(packageRoot, "src", "index.d.ts"), join4(packageRoot, "index.d.ts"), join4(packageRoot, "index.ts")];
@@ -1068,25 +1124,37 @@ function locateBarrelEntry(packageRoot) {
1068
1124
  }
1069
1125
  var EXPORT_DECL_PATTERNS = [/export\s+(?:declare\s+)?const\s+IDENT\b/, /export\s+(?:declare\s+)?function\s+IDENT\b/, /export\s*\{[^}]*\bIDENT\b[^}]*\}/];
1070
1126
  function findIdentifierInBarrelChain(filePath, identifier, visited) {
1071
- if (visited.has(filePath)) return false;
1072
- visited.add(filePath);
1073
- let text;
1074
- try {
1075
- text = readFileSync5(filePath, "utf8");
1076
- } catch {
1077
- return false;
1078
- }
1079
- for (const pattern of EXPORT_DECL_PATTERNS) {
1080
- const re = new RegExp(pattern.source.replace("IDENT", escapeRegExp(identifier)));
1081
- if (re.test(text)) return true;
1082
- }
1083
- const dir = dirname2(filePath);
1084
- for (const reExportTarget of collectReExportTargets(text)) {
1085
- const resolved = resolveReExport(dir, reExportTarget);
1086
- if (!resolved) continue;
1087
- if (findIdentifierInBarrelChain(resolved, identifier, visited)) return true;
1127
+ let result = false;
1128
+ if (!visited.has(filePath)) {
1129
+ visited.add(filePath);
1130
+ let text;
1131
+ try {
1132
+ text = readFileSync5(filePath, "utf8");
1133
+ } catch {
1134
+ text = void 0;
1135
+ }
1136
+ if (text !== void 0) {
1137
+ for (const pattern of EXPORT_DECL_PATTERNS) {
1138
+ const re = new RegExp(pattern.source.replace("IDENT", escapeRegExp(identifier)));
1139
+ if (re.test(text)) {
1140
+ result = true;
1141
+ break;
1142
+ }
1143
+ }
1144
+ if (!result) {
1145
+ const dir = dirname2(filePath);
1146
+ for (const reExportTarget of collectReExportTargets(text)) {
1147
+ const resolved = resolveReExport(dir, reExportTarget);
1148
+ if (!resolved) continue;
1149
+ if (findIdentifierInBarrelChain(resolved, identifier, visited)) {
1150
+ result = true;
1151
+ break;
1152
+ }
1153
+ }
1154
+ }
1155
+ }
1088
1156
  }
1089
- return false;
1157
+ return result;
1090
1158
  }
1091
1159
  function collectReExportTargets(text) {
1092
1160
  const out = [];
@@ -1098,15 +1166,16 @@ function collectReExportTargets(text) {
1098
1166
  return out;
1099
1167
  }
1100
1168
  function resolveReExport(fromDir, target) {
1101
- if (!target.startsWith(".")) return void 0;
1102
- const candidate = isAbsolute2(target) ? target : resolve2(fromDir, target);
1103
1169
  let result;
1104
- for (const ext of [".ts", ".mts", ".d.ts", "/index.ts", "/index.mts", "/index.d.ts"]) {
1105
- const probe = hasTsModuleExtension(candidate) ? candidate : candidate + ext;
1106
- const resolved = resolveExistingTsPath(probe);
1107
- if (resolved) {
1108
- result = resolved;
1109
- break;
1170
+ if (target.startsWith(".")) {
1171
+ const candidate = isAbsolute2(target) ? target : resolve2(fromDir, target);
1172
+ for (const ext of [".ts", ".mts", ".d.ts", "/index.ts", "/index.mts", "/index.d.ts"]) {
1173
+ const probe = hasTsModuleExtension(candidate) ? candidate : candidate + ext;
1174
+ const resolved = resolveExistingTsPath(probe);
1175
+ if (resolved) {
1176
+ result = resolved;
1177
+ break;
1178
+ }
1110
1179
  }
1111
1180
  }
1112
1181
  return result;
@@ -1115,14 +1184,24 @@ function hasTsModuleExtension(value) {
1115
1184
  return value.endsWith(".ts") || value.endsWith(".mts");
1116
1185
  }
1117
1186
  function resolveExistingTsPath(probe) {
1118
- if (!existsSync2(probe)) return void 0;
1119
- const stat = statSync3(probe);
1120
- if (stat.isFile()) return probe;
1121
- if (!stat.isDirectory()) return void 0;
1122
- const sourceIndex = join4(probe, "index.ts");
1123
- if (existsSync2(sourceIndex)) return sourceIndex;
1124
- const declarationIndex = join4(probe, "index.d.ts");
1125
- return existsSync2(declarationIndex) ? declarationIndex : void 0;
1187
+ let result;
1188
+ if (existsSync2(probe)) {
1189
+ const stat = statSync3(probe);
1190
+ if (stat.isFile()) {
1191
+ result = probe;
1192
+ } else if (stat.isDirectory()) {
1193
+ const sourceIndex = join4(probe, "index.ts");
1194
+ if (existsSync2(sourceIndex)) {
1195
+ result = sourceIndex;
1196
+ } else {
1197
+ const declarationIndex = join4(probe, "index.d.ts");
1198
+ if (existsSync2(declarationIndex)) {
1199
+ result = declarationIndex;
1200
+ }
1201
+ }
1202
+ }
1203
+ }
1204
+ return result;
1126
1205
  }
1127
1206
  function escapeRegExp(value) {
1128
1207
  return value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
@@ -1216,9 +1295,14 @@ function renderModelEntry(entry, emitConverters) {
1216
1295
  return ` { ${fields.filter((v) => Boolean(v)).join(", ")} }`;
1217
1296
  }
1218
1297
  function renderModelFields(fields, emitConverters) {
1219
- if (fields.length === 0) return "[]";
1220
- const items = fields.map((field) => renderModelField(field, emitConverters));
1221
- return `[${items.join(", ")}]`;
1298
+ let result;
1299
+ if (fields.length === 0) {
1300
+ result = "[]";
1301
+ } else {
1302
+ const items = fields.map((field) => renderModelField(field, emitConverters));
1303
+ result = `[${items.join(", ")}]`;
1304
+ }
1305
+ return result;
1222
1306
  }
1223
1307
  function renderModelField(field, emitConverters) {
1224
1308
  const nestedIsArrayLiteral = field.nestedIsArray ? "true" : "false";
@@ -1336,9 +1420,15 @@ async function main() {
1336
1420
  }
1337
1421
  }
1338
1422
  function compareEntries(a, b) {
1339
- if (a.entry.model !== b.entry.model) return a.entry.model.localeCompare(b.entry.model);
1340
- if (a.entry.verb !== b.entry.verb) return a.entry.verb.localeCompare(b.entry.verb);
1341
- return (a.entry.specifier ?? "").localeCompare(b.entry.specifier ?? "");
1423
+ let result;
1424
+ if (a.entry.model !== b.entry.model) {
1425
+ result = a.entry.model.localeCompare(b.entry.model);
1426
+ } else if (a.entry.verb === b.entry.verb) {
1427
+ result = (a.entry.specifier ?? "").localeCompare(b.entry.specifier ?? "");
1428
+ } else {
1429
+ result = a.entry.verb.localeCompare(b.entry.verb);
1430
+ }
1431
+ return result;
1342
1432
  }
1343
1433
  function ensureOutputDir(outputDir) {
1344
1434
  if (!existsSync3(outputDir)) mkdirSync(outputDir, { recursive: true });