@dereekb/dbx-cli 13.15.0 → 13.17.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.
Files changed (46) hide show
  1. package/eslint/index.cjs.default.js +1 -0
  2. package/eslint/index.cjs.js +1050 -0
  3. package/eslint/index.cjs.mjs +2 -0
  4. package/eslint/index.d.ts +1 -0
  5. package/eslint/index.esm.js +1046 -0
  6. package/eslint/package.json +25 -0
  7. package/eslint/rollup.alias-internal.config.d.ts +11 -0
  8. package/eslint/src/index.d.ts +1 -0
  9. package/eslint/src/lib/index.d.ts +2 -0
  10. package/eslint/src/lib/plugin.d.ts +22 -0
  11. package/eslint/src/lib/valid-dbx-route-model-tags.rule.d.ts +59 -0
  12. package/firebase-api-manifest/main.js +318 -228
  13. package/firebase-api-manifest/package.json +3 -3
  14. package/generate-firestore-indexes/main.js +37 -24
  15. package/generate-firestore-indexes/package.json +2 -2
  16. package/generate-mcp-manifest/main.js +57 -39
  17. package/generate-mcp-manifest/package.json +3 -3
  18. package/generate-route-manifest/main.js +1137 -0
  19. package/generate-route-manifest/package.json +10 -0
  20. package/index.cjs.js +4847 -1953
  21. package/index.esm.js +4827 -1954
  22. package/lint-cache/package.json +2 -2
  23. package/manifest-extract/index.cjs.js +175 -240
  24. package/manifest-extract/index.esm.js +174 -239
  25. package/manifest-extract/package.json +9 -4
  26. package/package.json +16 -6
  27. package/src/lib/index.d.ts +2 -0
  28. package/src/lib/manifest/types.d.ts +53 -0
  29. package/src/lib/mcp-scan/manifest/package-root.d.ts +17 -0
  30. package/src/lib/mcp-scan/manifest/tokens-schema.d.ts +5 -4
  31. package/src/lib/mcp-scan/scan/extract-models/assemble.d.ts +17 -0
  32. package/src/lib/route/component-resolve.d.ts +48 -0
  33. package/src/lib/route/index.d.ts +18 -0
  34. package/src/lib/route/route-build-tree.d.ts +31 -0
  35. package/src/lib/route/route-extract.d.ts +46 -0
  36. package/src/lib/route/route-load-tree.d.ts +17 -0
  37. package/src/lib/route/route-manifest.d.ts +132 -0
  38. package/src/lib/route/route-model-tag.d.ts +89 -0
  39. package/src/lib/route/route-models-extract.d.ts +22 -0
  40. package/src/lib/route/route-resolve-sources.d.ts +39 -0
  41. package/src/lib/route/route-types.d.ts +136 -0
  42. package/src/lib/route/url-match.d.ts +116 -0
  43. package/src/lib/scan-helpers/firestore-model-extract-utils.d.ts +43 -0
  44. package/test/index.cjs.js +1 -1
  45. package/test/index.esm.js +1 -1
  46. package/test/package.json +9 -9
@@ -1,4 +1,5 @@
1
1
  import { Project, Node } from 'ts-morph';
2
+ import { parseFirestoreModelIdentityArgs, resolveExtendsName } from '@dereekb/dbx-cli';
2
3
 
3
4
  function _define_property$1(obj, key, value) {
4
5
  if (key in obj) {
@@ -28,7 +29,7 @@ function _object_spread$1(target) {
28
29
  }
29
30
  return target;
30
31
  }
31
- function ownKeys(object, enumerableOnly) {
32
+ function ownKeys$1(object, enumerableOnly) {
32
33
  var keys = Object.keys(object);
33
34
  if (Object.getOwnPropertySymbols) {
34
35
  var symbols = Object.getOwnPropertySymbols(object);
@@ -36,12 +37,12 @@ function ownKeys(object, enumerableOnly) {
36
37
  }
37
38
  return keys;
38
39
  }
39
- function _object_spread_props(target, source) {
40
+ function _object_spread_props$1(target, source) {
40
41
  source = source != null ? source : {};
41
42
  if (Object.getOwnPropertyDescriptors) {
42
43
  Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
43
44
  } else {
44
- ownKeys(Object(source)).forEach(function(key) {
45
+ ownKeys$1(Object(source)).forEach(function(key) {
45
46
  Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
46
47
  });
47
48
  }
@@ -293,14 +294,25 @@ function findFunctionsClassName(sourceFile) {
293
294
  return result;
294
295
  }
295
296
  function inferGroupName(sourceFile) {
297
+ var _findTypeAliasStem;
298
+ return (_findTypeAliasStem = findTypeAliasStem(sourceFile, 'ModelCrudFunctionsConfig')) !== null && _findTypeAliasStem !== void 0 ? _findTypeAliasStem : findTypeAliasStem(sourceFile, 'FunctionTypeMap');
299
+ }
300
+ /**
301
+ * Finds the first type alias whose name ends with `ending` and returns the
302
+ * non-empty stem (the name with `ending` stripped).
303
+ *
304
+ * @param sourceFile - The parsed `<model>.api.ts` source.
305
+ * @param ending - The type-alias name suffix to match.
306
+ * @returns The stem preceding `ending`, or `undefined` when no alias matches with a non-empty stem.
307
+ */ function findTypeAliasStem(sourceFile, ending) {
296
308
  var result;
297
309
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
298
310
  try {
299
311
  for(var _iterator = sourceFile.getTypeAliases()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
300
312
  var alias = _step.value;
301
313
  var name = alias.getName();
302
- if (name.endsWith('ModelCrudFunctionsConfig')) {
303
- var stem = name.slice(0, -'ModelCrudFunctionsConfig'.length);
314
+ if (name.endsWith(ending)) {
315
+ var stem = name.slice(0, -ending.length);
304
316
  if (stem.length > 0) {
305
317
  result = stem;
306
318
  break;
@@ -321,35 +333,6 @@ function inferGroupName(sourceFile) {
321
333
  }
322
334
  }
323
335
  }
324
- if (result === undefined) {
325
- var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
326
- try {
327
- for(var _iterator1 = sourceFile.getTypeAliases()[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
328
- var alias1 = _step1.value;
329
- var name1 = alias1.getName();
330
- if (name1.endsWith('FunctionTypeMap')) {
331
- var stem1 = name1.slice(0, -'FunctionTypeMap'.length);
332
- if (stem1.length > 0) {
333
- result = stem1;
334
- break;
335
- }
336
- }
337
- }
338
- } catch (err) {
339
- _didIteratorError1 = true;
340
- _iteratorError1 = err;
341
- } finally{
342
- try {
343
- if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
344
- _iterator1.return();
345
- }
346
- } finally{
347
- if (_didIteratorError1) {
348
- throw _iteratorError1;
349
- }
350
- }
351
- }
352
- }
353
336
  return result;
354
337
  }
355
338
  function isNullLiteralType(node) {
@@ -471,68 +454,71 @@ function typeNodeName(node) {
471
454
  return result;
472
455
  }
473
456
  function readTypeDocs(sourceFile, typeName) {
474
- var result;
475
457
  var interfaceDecl = sourceFile.getInterface(typeName);
458
+ var result;
476
459
  if (interfaceDecl) {
477
- var typeDescription = readJsDocSummary(interfaceDecl);
478
- var hasApiParamsTag = hasJsDocFlag(interfaceDecl, 'dbxModelApiParams');
479
- var fields = [];
480
- var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
481
- try {
482
- for(var _iterator = interfaceDecl.getProperties()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
483
- var property = _step.value;
484
- var _ref;
485
- var fieldName = property.getName();
486
- var description = readJsDocSummary(property);
487
- var typeNode = property.getTypeNode();
488
- var typeText = (_ref = typeNode === null || typeNode === void 0 ? void 0 : typeNode.getText().trim()) !== null && _ref !== void 0 ? _ref : '';
489
- var adminOnly = hasJsDocFlag(property, 'dbxModelApiAdminOnly');
490
- var field = _object_spread$1({
491
- name: fieldName,
492
- typeText: typeText
493
- }, description ? {
494
- description: description
495
- } : {}, adminOnly ? {
496
- accessLevel: 'adminOnly'
497
- } : {});
498
- fields.push(field);
499
- }
500
- } catch (err) {
501
- _didIteratorError = true;
502
- _iteratorError = err;
503
- } finally{
504
- try {
505
- if (!_iteratorNormalCompletion && _iterator.return != null) {
506
- _iterator.return();
507
- }
508
- } finally{
509
- if (_didIteratorError) {
510
- throw _iteratorError;
511
- }
512
- }
513
- }
514
- if (typeDescription || fields.length > 0 || hasApiParamsTag) {
515
- result = _object_spread_props(_object_spread$1({}, typeDescription ? {
516
- typeDescription: typeDescription
517
- } : {}, fields.length > 0 ? {
518
- fields: fields
519
- } : {}), {
520
- hasApiParamsTag: hasApiParamsTag
521
- });
522
- }
460
+ result = readInterfaceTypeDocs(interfaceDecl);
523
461
  } else {
524
462
  var typeAlias = sourceFile.getTypeAlias(typeName);
525
- if (typeAlias) {
526
- var typeDescription1 = readJsDocSummary(typeAlias);
527
- if (typeDescription1) {
528
- result = {
529
- typeDescription: typeDescription1
530
- };
531
- }
532
- }
463
+ result = typeAlias ? readTypeAliasDocs(typeAlias) : undefined;
464
+ }
465
+ return result;
466
+ }
467
+ /**
468
+ * Reads the type-level JSDoc (summary, fields, `@dbxModelApiParams` flag) of a
469
+ * resolved interface declaration.
470
+ *
471
+ * @param interfaceDecl - The interface naming a params/result type.
472
+ * @returns The collected docs, or `undefined` when the interface has no description, fields, or marker.
473
+ */ function readInterfaceTypeDocs(interfaceDecl) {
474
+ var typeDescription = readJsDocSummary(interfaceDecl);
475
+ var hasApiParamsTag = hasJsDocFlag(interfaceDecl, 'dbxModelApiParams');
476
+ var fields = interfaceDecl.getProperties().map(function(property) {
477
+ return readInterfaceField(property);
478
+ });
479
+ var result;
480
+ if (typeDescription || fields.length > 0 || hasApiParamsTag) {
481
+ result = _object_spread_props$1(_object_spread$1({}, typeDescription ? {
482
+ typeDescription: typeDescription
483
+ } : {}, fields.length > 0 ? {
484
+ fields: fields
485
+ } : {}), {
486
+ hasApiParamsTag: hasApiParamsTag
487
+ });
533
488
  }
534
489
  return result;
535
490
  }
491
+ /**
492
+ * Reads one interface property into a {@link CrudEntryDocField}, capturing its
493
+ * type text, JSDoc summary, and `@dbxModelApiAdminOnly` access level.
494
+ *
495
+ * @param property - The interface property signature.
496
+ * @returns The doc field for the property.
497
+ */ function readInterfaceField(property) {
498
+ var _ref;
499
+ var _property_getTypeNode;
500
+ var description = readJsDocSummary(property);
501
+ var adminOnly = hasJsDocFlag(property, 'dbxModelApiAdminOnly');
502
+ return _object_spread$1({
503
+ name: property.getName(),
504
+ typeText: (_ref = (_property_getTypeNode = property.getTypeNode()) === null || _property_getTypeNode === void 0 ? void 0 : _property_getTypeNode.getText().trim()) !== null && _ref !== void 0 ? _ref : ''
505
+ }, description ? {
506
+ description: description
507
+ } : {}, adminOnly ? {
508
+ accessLevel: 'adminOnly'
509
+ } : {});
510
+ }
511
+ /**
512
+ * Reads the type-level JSDoc summary of a resolved type alias.
513
+ *
514
+ * @param typeAlias - The type alias naming a params/result type.
515
+ * @returns The collected docs, or `undefined` when the alias has no description.
516
+ */ function readTypeAliasDocs(typeAlias) {
517
+ var typeDescription = readJsDocSummary(typeAlias);
518
+ return typeDescription ? {
519
+ typeDescription: typeDescription
520
+ } : undefined;
521
+ }
536
522
  /**
537
523
  * Returns `true` when any JSDoc block on `node` carries the bare `@<tagName>` flag.
538
524
  *
@@ -648,8 +634,8 @@ function readTypeDocs(sourceFile, typeName) {
648
634
  function readJsDocSummary(node) {
649
635
  var result;
650
636
  var docs = node.getJsDocs();
651
- if (docs.length > 0) {
652
- var last = docs[docs.length - 1];
637
+ var last = docs.at(-1);
638
+ if (last) {
653
639
  var description = last.getDescription().trim();
654
640
  if (description.length > 0) {
655
641
  result = description;
@@ -686,6 +672,25 @@ function _object_spread(target) {
686
672
  }
687
673
  return target;
688
674
  }
675
+ function ownKeys(object, enumerableOnly) {
676
+ var keys = Object.keys(object);
677
+ if (Object.getOwnPropertySymbols) {
678
+ var symbols = Object.getOwnPropertySymbols(object);
679
+ keys.push.apply(keys, symbols);
680
+ }
681
+ return keys;
682
+ }
683
+ function _object_spread_props(target, source) {
684
+ source = source != null ? source : {};
685
+ if (Object.getOwnPropertyDescriptors) {
686
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
687
+ } else {
688
+ ownKeys(Object(source)).forEach(function(key) {
689
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
690
+ });
691
+ }
692
+ return target;
693
+ }
689
694
  var READ_LEVEL_VALUES = new Set([
690
695
  'system',
691
696
  'owner',
@@ -696,25 +701,6 @@ var SERVICE_FACTORY_TAG = 'dbxModelServiceFactory';
696
701
  var MCP_TOOL_NAME_SEGMENT_TAG = 'dbxModelMcpToolNameSegment';
697
702
  var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
698
703
  var TOOL_NAME_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_$]*$/;
699
- /**
700
- * TS utility/structural wrappers that don't change the field surface for
701
- * inheritance walks — `Partial<T>`, `Required<T>`, `Readonly<T>`,
702
- * `NonNullable<T>` preserve every property, and `Pick<T, K>` / `Omit<T, K>`
703
- * leave the original `T` reachable for long-name resolution. `MaybeMap<T>` is
704
- * the workspace's own pass-through that decorates each prop with `Maybe<…>`
705
- * without renaming. `extends` walks need to see through these to find the
706
- * concrete ancestor interface — `getExpression()` alone returns just the
707
- * leftmost identifier (`Partial`, `Pick`, …) and silently drops the inner
708
- * model, leaving every inherited `@dbxModelVariable` tag unreachable.
709
- */ var PASSTHROUGH_TYPE_WRAPPERS = new Set([
710
- 'Partial',
711
- 'Required',
712
- 'Readonly',
713
- 'NonNullable',
714
- 'MaybeMap',
715
- 'Pick',
716
- 'Omit'
717
- ]);
718
704
  var IDENTITY_FN = 'firestoreModelIdentity';
719
705
  var CONVERTER_FN_NAMES = [
720
706
  'snapshotConverterFunctions',
@@ -726,6 +712,7 @@ var OBJECT_ARRAY_FN = 'firestoreObjectArray';
726
712
  var SNAPSHOT_FN = 'snapshotConverterFunctions';
727
713
  var FIELDS_LITERAL_KEY = 'fields';
728
714
  var OBJECT_FIELD_KEY = 'objectField';
715
+ var FIRESTORE_FIELD_KEY = 'firestoreField';
729
716
  /**
730
717
  * Walks a single source file and reports raw model-extraction artifacts.
731
718
  * Best-effort: a malformed call shape leaves the corresponding entry out
@@ -772,7 +759,7 @@ function readIdentities(sourceFile) {
772
759
  var initializer = decl.getInitializer();
773
760
  if (!initializer || !Node.isCallExpression(initializer)) continue;
774
761
  if (initializer.getExpression().getText() !== IDENTITY_FN) continue;
775
- var parsed = parseIdentityArgs(initializer);
762
+ var parsed = parseFirestoreModelIdentityArgs(initializer.getArguments());
776
763
  if (parsed) {
777
764
  out.push(_object_spread({
778
765
  identityConst: decl.getName()
@@ -810,48 +797,6 @@ function readIdentities(sourceFile) {
810
797
  }
811
798
  return out;
812
799
  }
813
- function parseIdentityArgs(call) {
814
- var args = call.getArguments();
815
- var result;
816
- if (args.length === 1) {
817
- var modelType = stringLiteralValue(args[0]);
818
- if (modelType !== undefined) {
819
- result = {
820
- modelType: modelType,
821
- collectionPrefix: undefined,
822
- parentIdentityConst: undefined
823
- };
824
- }
825
- } else if (args.length === 2) {
826
- var first = stringLiteralValue(args[0]);
827
- if (first === undefined) {
828
- var modelType1 = stringLiteralValue(args[1]);
829
- if (modelType1 !== undefined) {
830
- result = {
831
- modelType: modelType1,
832
- collectionPrefix: undefined,
833
- parentIdentityConst: identifierName(args[0])
834
- };
835
- }
836
- } else {
837
- result = {
838
- modelType: first,
839
- collectionPrefix: stringLiteralValue(args[1]),
840
- parentIdentityConst: undefined
841
- };
842
- }
843
- } else if (args.length >= 3) {
844
- var modelType2 = stringLiteralValue(args[1]);
845
- if (modelType2 !== undefined) {
846
- result = {
847
- modelType: modelType2,
848
- collectionPrefix: stringLiteralValue(args[2]),
849
- parentIdentityConst: identifierName(args[0])
850
- };
851
- }
852
- }
853
- return result;
854
- }
855
800
  function readInterfaces(sourceFile) {
856
801
  var out = [];
857
802
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -1132,48 +1077,6 @@ function readServiceFactoryModelType(jsDocs) {
1132
1077
  }
1133
1078
  return result;
1134
1079
  }
1135
- /**
1136
- * Resolves an `extends` clause to the concrete ancestor interface name,
1137
- * peeling any leading {@link PASSTHROUGH_TYPE_WRAPPERS}. Returns the leftmost
1138
- * identifier of the unwrapped expression so the inheritance walker can chain
1139
- * through utility-wrapped declarations like
1140
- * `extends Partial<MaybeMap<Omit<Base, '…'>>>`.
1141
- *
1142
- * @param expr - The `ExpressionWithTypeArguments` produced by `getExtends()`
1143
- * @returns The resolved interface name, or the original leftmost identifier when no inner reference is reachable.
1144
- */ function resolveExtendsName(expr) {
1145
- var head = expr.getExpression().getText();
1146
- var result = head;
1147
- if (PASSTHROUGH_TYPE_WRAPPERS.has(head)) {
1148
- var typeArgs = expr.getTypeArguments();
1149
- if (typeArgs.length > 0) {
1150
- var peeled = peelTypeNode(typeArgs[0]);
1151
- if (peeled !== undefined) {
1152
- result = peeled;
1153
- }
1154
- }
1155
- }
1156
- return result;
1157
- }
1158
- function peelTypeNode(node) {
1159
- var current = node;
1160
- while(Node.isParenthesizedTypeNode(current)){
1161
- current = current.getTypeNode();
1162
- }
1163
- var result;
1164
- if (Node.isTypeReference(current)) {
1165
- var name = current.getTypeName().getText();
1166
- if (PASSTHROUGH_TYPE_WRAPPERS.has(name)) {
1167
- var inner = current.getTypeArguments();
1168
- if (inner.length > 0) {
1169
- result = peelTypeNode(inner[0]);
1170
- }
1171
- } else {
1172
- result = name;
1173
- }
1174
- }
1175
- return result;
1176
- }
1177
1080
  function readConverters(sourceFile) {
1178
1081
  var out = [];
1179
1082
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -1311,41 +1214,87 @@ function readNestedFromExpression(expr) {
1311
1214
  if (Node.isCallExpression(expr)) {
1312
1215
  var fnName = expr.getExpression().getText();
1313
1216
  if (fnName === SUB_OBJECT_FN || fnName === OBJECT_ARRAY_FN) {
1314
- var args = expr.getArguments();
1315
- if (args.length > 0) {
1316
- var config = args[0];
1317
- if (Node.isObjectLiteralExpression(config)) {
1318
- var objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
1319
- if (objectField) {
1320
- var isArray = fnName === OBJECT_ARRAY_FN;
1321
- if (Node.isIdentifier(objectField)) {
1322
- result = {
1323
- ref: objectField.getText(),
1324
- isArray: isArray
1325
- };
1326
- } else if (Node.isObjectLiteralExpression(objectField)) {
1327
- var fieldsLiteral = readObjectProperty(objectField, FIELDS_LITERAL_KEY);
1328
- if (fieldsLiteral) {
1329
- var inlineFields = readFieldEntries(fieldsLiteral);
1330
- result = {
1331
- inline: {
1332
- converterConst: undefined,
1333
- factory: fnName,
1334
- interfaceName: readGenericInterfaceName(expr),
1335
- fields: inlineFields,
1336
- line: expr.getStartLineNumber()
1337
- },
1338
- isArray: isArray
1339
- };
1340
- }
1341
- }
1342
- }
1343
- }
1217
+ result = readNestedConverterCall(expr, fnName);
1218
+ }
1219
+ }
1220
+ return result;
1221
+ }
1222
+ /**
1223
+ * Reads the `objectField` (or `firestoreField`) argument of a
1224
+ * `firestoreSubObject` / `firestoreObjectArray` call into a
1225
+ * {@link NestedConverterMatch}.
1226
+ *
1227
+ * `firestoreObjectArray`'s config is a union: `{ objectField }` describes the
1228
+ * element shape directly, while `{ firestoreField }` points the element decode
1229
+ * at another field converter (a sub-object const or an inline
1230
+ * `firestoreSubObject(...)`). Both carriers resolve through the same nested path
1231
+ * — the `firestoreField` variant is what the timesheet day-level form uses.
1232
+ *
1233
+ * @param call - The nested-converter call expression.
1234
+ * @param fnName - The resolved factory name (`firestoreSubObject` or `firestoreObjectArray`).
1235
+ * @returns The nested-converter match, or `undefined` when the call shape is malformed.
1236
+ */ function readNestedConverterCall(call, fnName) {
1237
+ var result;
1238
+ var args = call.getArguments();
1239
+ if (args.length > 0) {
1240
+ var config = args[0];
1241
+ if (Node.isObjectLiteralExpression(config)) {
1242
+ var _readPropertyValue;
1243
+ var valueNode = (_readPropertyValue = readPropertyValue(config, OBJECT_FIELD_KEY)) !== null && _readPropertyValue !== void 0 ? _readPropertyValue : readPropertyValue(config, FIRESTORE_FIELD_KEY);
1244
+ if (valueNode) {
1245
+ result = buildNestedConverterMatch({
1246
+ objectField: valueNode,
1247
+ call: call,
1248
+ fnName: fnName
1249
+ });
1344
1250
  }
1345
1251
  }
1346
1252
  }
1347
1253
  return result;
1348
1254
  }
1255
+ /**
1256
+ * Builds a {@link NestedConverterMatch} from a resolved value node:
1257
+ * an identifier yields a converter `ref`, an object literal yields an `inline`
1258
+ * converter parsed from its `fields`, and a nested
1259
+ * `firestoreSubObject(...)` / `firestoreObjectArray(...)` call (the inline
1260
+ * `firestoreField: firestoreSubObject<T>({...})` form) is resolved recursively —
1261
+ * the outer factory still decides array-ness.
1262
+ *
1263
+ * @param input - The resolved value node, owning call expression, and factory name.
1264
+ * @returns The nested-converter match, or `undefined` when no shape applies.
1265
+ */ function buildNestedConverterMatch(input) {
1266
+ var objectField = input.objectField, call = input.call, fnName = input.fnName;
1267
+ var isArray = fnName === OBJECT_ARRAY_FN;
1268
+ var result;
1269
+ if (Node.isIdentifier(objectField)) {
1270
+ result = {
1271
+ ref: objectField.getText(),
1272
+ isArray: isArray
1273
+ };
1274
+ } else if (Node.isObjectLiteralExpression(objectField)) {
1275
+ var fieldsLiteral = readObjectProperty(objectField, FIELDS_LITERAL_KEY);
1276
+ if (fieldsLiteral) {
1277
+ result = {
1278
+ inline: {
1279
+ converterConst: undefined,
1280
+ factory: fnName,
1281
+ interfaceName: readGenericInterfaceName(call),
1282
+ fields: readFieldEntries(fieldsLiteral),
1283
+ line: call.getStartLineNumber()
1284
+ },
1285
+ isArray: isArray
1286
+ };
1287
+ }
1288
+ } else if (Node.isCallExpression(objectField)) {
1289
+ var nested = readNestedFromExpression(objectField);
1290
+ if (nested) {
1291
+ result = _object_spread_props(_object_spread({}, nested), {
1292
+ isArray: isArray
1293
+ });
1294
+ }
1295
+ }
1296
+ return result;
1297
+ }
1349
1298
  function readPropertyValue(literal, key) {
1350
1299
  var property = literal.getProperty(key);
1351
1300
  var result;
@@ -1636,19 +1585,5 @@ function firstParagraph(text) {
1636
1585
  }
1637
1586
  return collected.join(' ').trim();
1638
1587
  }
1639
- function stringLiteralValue(node) {
1640
- var result;
1641
- if (Node.isStringLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node)) {
1642
- result = node.getLiteralText();
1643
- }
1644
- return result;
1645
- }
1646
- function identifierName(node) {
1647
- var result;
1648
- if (Node.isIdentifier(node)) {
1649
- result = node.getText();
1650
- }
1651
- return result;
1652
- }
1653
1588
 
1654
1589
  export { extractCrudEntries, extractModelsFromSource };
@@ -1,13 +1,18 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli/manifest-extract",
3
- "version": "13.15.0",
3
+ "version": "13.17.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
+ "@dereekb/date": "13.15.0",
7
+ "@dereekb/dbx-cli": "13.17.0",
8
+ "@dereekb/firebase": "13.15.0",
9
+ "@dereekb/model": "13.15.0",
10
+ "@dereekb/nestjs": "13.15.0",
11
+ "@dereekb/rxjs": "13.15.0",
12
+ "@dereekb/util": "13.15.0",
13
+ "@dereekb/util-fetch": "13.15.0",
6
14
  "ts-morph": "^21.0.0"
7
15
  },
8
- "devDependencies": {
9
- "@dereekb/firebase": "13.15.0"
10
- },
11
16
  "exports": {
12
17
  "./package.json": "./package.json",
13
18
  ".": {
package/package.json CHANGED
@@ -1,15 +1,22 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli",
3
- "version": "13.15.0",
3
+ "version": "13.17.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "bin": {
7
7
  "dbx-cli-generate-firebase-api-manifest": "firebase-api-manifest/main.js",
8
8
  "dbx-cli-generate-firestore-indexes": "generate-firestore-indexes/main.js",
9
9
  "dbx-cli-generate-mcp-manifest": "generate-mcp-manifest/main.js",
10
+ "dbx-cli-generate-route-manifest": "generate-route-manifest/main.js",
10
11
  "dbx-cli-lint-cache": "lint-cache/main.js"
11
12
  },
12
13
  "exports": {
14
+ "./eslint": {
15
+ "module": "./eslint/index.esm.js",
16
+ "types": "./eslint/index.d.ts",
17
+ "import": "./eslint/index.cjs.mjs",
18
+ "default": "./eslint/index.cjs.js"
19
+ },
13
20
  "./firebase-api-manifest": {
14
21
  "default": "./firebase-api-manifest/main.js"
15
22
  },
@@ -19,6 +26,9 @@
19
26
  "./generate-mcp-manifest": {
20
27
  "default": "./generate-mcp-manifest/main.js"
21
28
  },
29
+ "./generate-route-manifest": {
30
+ "default": "./generate-route-manifest/main.js"
31
+ },
22
32
  "./lint-cache": {
23
33
  "default": "./lint-cache/main.js"
24
34
  },
@@ -50,11 +60,11 @@
50
60
  }
51
61
  },
52
62
  "peerDependencies": {
53
- "@dereekb/date": "13.15.0",
54
- "@dereekb/firebase": "13.15.0",
55
- "@dereekb/model": "13.15.0",
56
- "@dereekb/nestjs": "13.15.0",
57
- "@dereekb/util": "13.15.0",
63
+ "@dereekb/date": "13.17.0",
64
+ "@dereekb/firebase": "13.17.0",
65
+ "@dereekb/model": "13.17.0",
66
+ "@dereekb/nestjs": "13.17.0",
67
+ "@dereekb/util": "13.17.0",
58
68
  "@nestjs/common": "^11.1.19",
59
69
  "arktype": "^2.2.0",
60
70
  "jiti": "2.6.1",
@@ -10,6 +10,8 @@ export * from './mcp-scan';
10
10
  export * from './middleware';
11
11
  export * from './scan-helpers/scan-io.js';
12
12
  export * from './scan-helpers/scan-extract-utils.js';
13
+ export * from './scan-helpers/firestore-model-extract-utils.js';
13
14
  export * from './output';
15
+ export * from './route';
14
16
  export * from './runner';
15
17
  export * from './util';