@dereekb/dbx-cli 13.16.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 (44) 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 +177 -102
  13. package/firebase-api-manifest/package.json +3 -3
  14. package/generate-firestore-indexes/main.js +2 -2
  15. package/generate-firestore-indexes/package.json +2 -2
  16. package/generate-mcp-manifest/main.js +8 -2
  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 +4375 -1687
  21. package/index.esm.js +4355 -1688
  22. package/lint-cache/package.json +2 -2
  23. package/manifest-extract/index.cjs.js +54 -132
  24. package/manifest-extract/index.esm.js +53 -131
  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/package.json +9 -9
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli-lint-cache",
3
- "version": "13.16.0",
3
+ "version": "13.17.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "devDependencies": {
@@ -8,7 +8,7 @@
8
8
  "eslint": "10.4.0"
9
9
  },
10
10
  "peerDependencies": {
11
- "@dereekb/util": "13.16.0",
11
+ "@dereekb/util": "13.17.0",
12
12
  "yargs": "^18.0.0"
13
13
  }
14
14
  }
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var tsMorph = require('ts-morph');
4
+ var dbxCli = require('@dereekb/dbx-cli');
4
5
 
5
6
  function _define_property$1(obj, key, value) {
6
7
  if (key in obj) {
@@ -30,7 +31,7 @@ function _object_spread$1(target) {
30
31
  }
31
32
  return target;
32
33
  }
33
- function ownKeys(object, enumerableOnly) {
34
+ function ownKeys$1(object, enumerableOnly) {
34
35
  var keys = Object.keys(object);
35
36
  if (Object.getOwnPropertySymbols) {
36
37
  var symbols = Object.getOwnPropertySymbols(object);
@@ -38,12 +39,12 @@ function ownKeys(object, enumerableOnly) {
38
39
  }
39
40
  return keys;
40
41
  }
41
- function _object_spread_props(target, source) {
42
+ function _object_spread_props$1(target, source) {
42
43
  source = source != null ? source : {};
43
44
  if (Object.getOwnPropertyDescriptors) {
44
45
  Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
45
46
  } else {
46
- ownKeys(Object(source)).forEach(function(key) {
47
+ ownKeys$1(Object(source)).forEach(function(key) {
47
48
  Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
48
49
  });
49
50
  }
@@ -479,7 +480,7 @@ function readTypeDocs(sourceFile, typeName) {
479
480
  });
480
481
  var result;
481
482
  if (typeDescription || fields.length > 0 || hasApiParamsTag) {
482
- result = _object_spread_props(_object_spread$1({}, typeDescription ? {
483
+ result = _object_spread_props$1(_object_spread$1({}, typeDescription ? {
483
484
  typeDescription: typeDescription
484
485
  } : {}, fields.length > 0 ? {
485
486
  fields: fields
@@ -673,6 +674,25 @@ function _object_spread(target) {
673
674
  }
674
675
  return target;
675
676
  }
677
+ function ownKeys(object, enumerableOnly) {
678
+ var keys = Object.keys(object);
679
+ if (Object.getOwnPropertySymbols) {
680
+ var symbols = Object.getOwnPropertySymbols(object);
681
+ keys.push.apply(keys, symbols);
682
+ }
683
+ return keys;
684
+ }
685
+ function _object_spread_props(target, source) {
686
+ source = source != null ? source : {};
687
+ if (Object.getOwnPropertyDescriptors) {
688
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
689
+ } else {
690
+ ownKeys(Object(source)).forEach(function(key) {
691
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
692
+ });
693
+ }
694
+ return target;
695
+ }
676
696
  var READ_LEVEL_VALUES = new Set([
677
697
  'system',
678
698
  'owner',
@@ -683,25 +703,6 @@ var SERVICE_FACTORY_TAG = 'dbxModelServiceFactory';
683
703
  var MCP_TOOL_NAME_SEGMENT_TAG = 'dbxModelMcpToolNameSegment';
684
704
  var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
685
705
  var TOOL_NAME_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_$]*$/;
686
- /**
687
- * TS utility/structural wrappers that don't change the field surface for
688
- * inheritance walks — `Partial<T>`, `Required<T>`, `Readonly<T>`,
689
- * `NonNullable<T>` preserve every property, and `Pick<T, K>` / `Omit<T, K>`
690
- * leave the original `T` reachable for long-name resolution. `MaybeMap<T>` is
691
- * the workspace's own pass-through that decorates each prop with `Maybe<…>`
692
- * without renaming. `extends` walks need to see through these to find the
693
- * concrete ancestor interface — `getExpression()` alone returns just the
694
- * leftmost identifier (`Partial`, `Pick`, …) and silently drops the inner
695
- * model, leaving every inherited `@dbxModelVariable` tag unreachable.
696
- */ var PASSTHROUGH_TYPE_WRAPPERS = new Set([
697
- 'Partial',
698
- 'Required',
699
- 'Readonly',
700
- 'NonNullable',
701
- 'MaybeMap',
702
- 'Pick',
703
- 'Omit'
704
- ]);
705
706
  var IDENTITY_FN = 'firestoreModelIdentity';
706
707
  var CONVERTER_FN_NAMES = [
707
708
  'snapshotConverterFunctions',
@@ -713,6 +714,7 @@ var OBJECT_ARRAY_FN = 'firestoreObjectArray';
713
714
  var SNAPSHOT_FN = 'snapshotConverterFunctions';
714
715
  var FIELDS_LITERAL_KEY = 'fields';
715
716
  var OBJECT_FIELD_KEY = 'objectField';
717
+ var FIRESTORE_FIELD_KEY = 'firestoreField';
716
718
  /**
717
719
  * Walks a single source file and reports raw model-extraction artifacts.
718
720
  * Best-effort: a malformed call shape leaves the corresponding entry out
@@ -759,7 +761,7 @@ function readIdentities(sourceFile) {
759
761
  var initializer = decl.getInitializer();
760
762
  if (!initializer || !tsMorph.Node.isCallExpression(initializer)) continue;
761
763
  if (initializer.getExpression().getText() !== IDENTITY_FN) continue;
762
- var parsed = parseIdentityArgs(initializer);
764
+ var parsed = dbxCli.parseFirestoreModelIdentityArgs(initializer.getArguments());
763
765
  if (parsed) {
764
766
  out.push(_object_spread({
765
767
  identityConst: decl.getName()
@@ -797,48 +799,6 @@ function readIdentities(sourceFile) {
797
799
  }
798
800
  return out;
799
801
  }
800
- function parseIdentityArgs(call) {
801
- var args = call.getArguments();
802
- var result;
803
- if (args.length === 1) {
804
- var modelType = stringLiteralValue(args[0]);
805
- if (modelType !== undefined) {
806
- result = {
807
- modelType: modelType,
808
- collectionPrefix: undefined,
809
- parentIdentityConst: undefined
810
- };
811
- }
812
- } else if (args.length === 2) {
813
- var first = stringLiteralValue(args[0]);
814
- if (first === undefined) {
815
- var modelType1 = stringLiteralValue(args[1]);
816
- if (modelType1 !== undefined) {
817
- result = {
818
- modelType: modelType1,
819
- collectionPrefix: undefined,
820
- parentIdentityConst: identifierName(args[0])
821
- };
822
- }
823
- } else {
824
- result = {
825
- modelType: first,
826
- collectionPrefix: stringLiteralValue(args[1]),
827
- parentIdentityConst: undefined
828
- };
829
- }
830
- } else if (args.length >= 3) {
831
- var modelType2 = stringLiteralValue(args[1]);
832
- if (modelType2 !== undefined) {
833
- result = {
834
- modelType: modelType2,
835
- collectionPrefix: stringLiteralValue(args[2]),
836
- parentIdentityConst: identifierName(args[0])
837
- };
838
- }
839
- }
840
- return result;
841
- }
842
802
  function readInterfaces(sourceFile) {
843
803
  var out = [];
844
804
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -869,7 +829,7 @@ function buildInterface(decl) {
869
829
  var hasDbxModelTag = jsDocsHaveTag(jsDocs, 'dbxModel');
870
830
  var dbxModelRead = readDbxModelReadTag(jsDocs);
871
831
  var mcpToolNameSegment = readMcpToolNameSegmentTag(jsDocs);
872
- var extendsNames = decl.getExtends().map(resolveExtendsName);
832
+ var extendsNames = decl.getExtends().map(dbxCli.resolveExtendsName);
873
833
  var props = [];
874
834
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
875
835
  try {
@@ -1119,48 +1079,6 @@ function readServiceFactoryModelType(jsDocs) {
1119
1079
  }
1120
1080
  return result;
1121
1081
  }
1122
- /**
1123
- * Resolves an `extends` clause to the concrete ancestor interface name,
1124
- * peeling any leading {@link PASSTHROUGH_TYPE_WRAPPERS}. Returns the leftmost
1125
- * identifier of the unwrapped expression so the inheritance walker can chain
1126
- * through utility-wrapped declarations like
1127
- * `extends Partial<MaybeMap<Omit<Base, '…'>>>`.
1128
- *
1129
- * @param expr - The `ExpressionWithTypeArguments` produced by `getExtends()`
1130
- * @returns The resolved interface name, or the original leftmost identifier when no inner reference is reachable.
1131
- */ function resolveExtendsName(expr) {
1132
- var head = expr.getExpression().getText();
1133
- var result = head;
1134
- if (PASSTHROUGH_TYPE_WRAPPERS.has(head)) {
1135
- var typeArgs = expr.getTypeArguments();
1136
- if (typeArgs.length > 0) {
1137
- var peeled = peelTypeNode(typeArgs[0]);
1138
- if (peeled !== undefined) {
1139
- result = peeled;
1140
- }
1141
- }
1142
- }
1143
- return result;
1144
- }
1145
- function peelTypeNode(node) {
1146
- var current = node;
1147
- while(tsMorph.Node.isParenthesizedTypeNode(current)){
1148
- current = current.getTypeNode();
1149
- }
1150
- var result;
1151
- if (tsMorph.Node.isTypeReference(current)) {
1152
- var name = current.getTypeName().getText();
1153
- if (PASSTHROUGH_TYPE_WRAPPERS.has(name)) {
1154
- var inner = current.getTypeArguments();
1155
- if (inner.length > 0) {
1156
- result = peelTypeNode(inner[0]);
1157
- }
1158
- } else {
1159
- result = name;
1160
- }
1161
- }
1162
- return result;
1163
- }
1164
1082
  function readConverters(sourceFile) {
1165
1083
  var out = [];
1166
1084
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -1304,8 +1222,15 @@ function readNestedFromExpression(expr) {
1304
1222
  return result;
1305
1223
  }
1306
1224
  /**
1307
- * Reads the `objectField` argument of a `firestoreSubObject` /
1308
- * `firestoreObjectArray` call into a {@link NestedConverterMatch}.
1225
+ * Reads the `objectField` (or `firestoreField`) argument of a
1226
+ * `firestoreSubObject` / `firestoreObjectArray` call into a
1227
+ * {@link NestedConverterMatch}.
1228
+ *
1229
+ * `firestoreObjectArray`'s config is a union: `{ objectField }` describes the
1230
+ * element shape directly, while `{ firestoreField }` points the element decode
1231
+ * at another field converter (a sub-object const or an inline
1232
+ * `firestoreSubObject(...)`). Both carriers resolve through the same nested path
1233
+ * — the `firestoreField` variant is what the timesheet day-level form uses.
1309
1234
  *
1310
1235
  * @param call - The nested-converter call expression.
1311
1236
  * @param fnName - The resolved factory name (`firestoreSubObject` or `firestoreObjectArray`).
@@ -1316,10 +1241,11 @@ function readNestedFromExpression(expr) {
1316
1241
  if (args.length > 0) {
1317
1242
  var config = args[0];
1318
1243
  if (tsMorph.Node.isObjectLiteralExpression(config)) {
1319
- var objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
1320
- if (objectField) {
1244
+ var _readPropertyValue;
1245
+ var valueNode = (_readPropertyValue = readPropertyValue(config, OBJECT_FIELD_KEY)) !== null && _readPropertyValue !== void 0 ? _readPropertyValue : readPropertyValue(config, FIRESTORE_FIELD_KEY);
1246
+ if (valueNode) {
1321
1247
  result = buildNestedConverterMatch({
1322
- objectField: objectField,
1248
+ objectField: valueNode,
1323
1249
  call: call,
1324
1250
  fnName: fnName
1325
1251
  });
@@ -1329,12 +1255,15 @@ function readNestedFromExpression(expr) {
1329
1255
  return result;
1330
1256
  }
1331
1257
  /**
1332
- * Builds a {@link NestedConverterMatch} from a resolved `objectField` node:
1258
+ * Builds a {@link NestedConverterMatch} from a resolved value node:
1333
1259
  * an identifier yields a converter `ref`, an object literal yields an `inline`
1334
- * converter parsed from its `fields`.
1260
+ * converter parsed from its `fields`, and a nested
1261
+ * `firestoreSubObject(...)` / `firestoreObjectArray(...)` call (the inline
1262
+ * `firestoreField: firestoreSubObject<T>({...})` form) is resolved recursively —
1263
+ * the outer factory still decides array-ness.
1335
1264
  *
1336
- * @param input - The `objectField` node, owning call expression, and factory name.
1337
- * @returns The nested-converter match, or `undefined` when neither shape applies.
1265
+ * @param input - The resolved value node, owning call expression, and factory name.
1266
+ * @returns The nested-converter match, or `undefined` when no shape applies.
1338
1267
  */ function buildNestedConverterMatch(input) {
1339
1268
  var objectField = input.objectField, call = input.call, fnName = input.fnName;
1340
1269
  var isArray = fnName === OBJECT_ARRAY_FN;
@@ -1358,6 +1287,13 @@ function readNestedFromExpression(expr) {
1358
1287
  isArray: isArray
1359
1288
  };
1360
1289
  }
1290
+ } else if (tsMorph.Node.isCallExpression(objectField)) {
1291
+ var nested = readNestedFromExpression(objectField);
1292
+ if (nested) {
1293
+ result = _object_spread_props(_object_spread({}, nested), {
1294
+ isArray: isArray
1295
+ });
1296
+ }
1361
1297
  }
1362
1298
  return result;
1363
1299
  }
@@ -1651,20 +1587,6 @@ function firstParagraph(text) {
1651
1587
  }
1652
1588
  return collected.join(' ').trim();
1653
1589
  }
1654
- function stringLiteralValue(node) {
1655
- var result;
1656
- if (tsMorph.Node.isStringLiteral(node) || tsMorph.Node.isNoSubstitutionTemplateLiteral(node)) {
1657
- result = node.getLiteralText();
1658
- }
1659
- return result;
1660
- }
1661
- function identifierName(node) {
1662
- var result;
1663
- if (tsMorph.Node.isIdentifier(node)) {
1664
- result = node.getText();
1665
- }
1666
- return result;
1667
- }
1668
1590
 
1669
1591
  exports.extractCrudEntries = extractCrudEntries;
1670
1592
  exports.extractModelsFromSource = extractModelsFromSource;
@@ -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
  }
@@ -477,7 +478,7 @@ function readTypeDocs(sourceFile, typeName) {
477
478
  });
478
479
  var result;
479
480
  if (typeDescription || fields.length > 0 || hasApiParamsTag) {
480
- result = _object_spread_props(_object_spread$1({}, typeDescription ? {
481
+ result = _object_spread_props$1(_object_spread$1({}, typeDescription ? {
481
482
  typeDescription: typeDescription
482
483
  } : {}, fields.length > 0 ? {
483
484
  fields: fields
@@ -671,6 +672,25 @@ function _object_spread(target) {
671
672
  }
672
673
  return target;
673
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
+ }
674
694
  var READ_LEVEL_VALUES = new Set([
675
695
  'system',
676
696
  'owner',
@@ -681,25 +701,6 @@ var SERVICE_FACTORY_TAG = 'dbxModelServiceFactory';
681
701
  var MCP_TOOL_NAME_SEGMENT_TAG = 'dbxModelMcpToolNameSegment';
682
702
  var MODEL_TYPE_VALUE_PATTERN = /^[a-z][A-Za-z0-9_$]*$/;
683
703
  var TOOL_NAME_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_$]*$/;
684
- /**
685
- * TS utility/structural wrappers that don't change the field surface for
686
- * inheritance walks — `Partial<T>`, `Required<T>`, `Readonly<T>`,
687
- * `NonNullable<T>` preserve every property, and `Pick<T, K>` / `Omit<T, K>`
688
- * leave the original `T` reachable for long-name resolution. `MaybeMap<T>` is
689
- * the workspace's own pass-through that decorates each prop with `Maybe<…>`
690
- * without renaming. `extends` walks need to see through these to find the
691
- * concrete ancestor interface — `getExpression()` alone returns just the
692
- * leftmost identifier (`Partial`, `Pick`, …) and silently drops the inner
693
- * model, leaving every inherited `@dbxModelVariable` tag unreachable.
694
- */ var PASSTHROUGH_TYPE_WRAPPERS = new Set([
695
- 'Partial',
696
- 'Required',
697
- 'Readonly',
698
- 'NonNullable',
699
- 'MaybeMap',
700
- 'Pick',
701
- 'Omit'
702
- ]);
703
704
  var IDENTITY_FN = 'firestoreModelIdentity';
704
705
  var CONVERTER_FN_NAMES = [
705
706
  'snapshotConverterFunctions',
@@ -711,6 +712,7 @@ var OBJECT_ARRAY_FN = 'firestoreObjectArray';
711
712
  var SNAPSHOT_FN = 'snapshotConverterFunctions';
712
713
  var FIELDS_LITERAL_KEY = 'fields';
713
714
  var OBJECT_FIELD_KEY = 'objectField';
715
+ var FIRESTORE_FIELD_KEY = 'firestoreField';
714
716
  /**
715
717
  * Walks a single source file and reports raw model-extraction artifacts.
716
718
  * Best-effort: a malformed call shape leaves the corresponding entry out
@@ -757,7 +759,7 @@ function readIdentities(sourceFile) {
757
759
  var initializer = decl.getInitializer();
758
760
  if (!initializer || !Node.isCallExpression(initializer)) continue;
759
761
  if (initializer.getExpression().getText() !== IDENTITY_FN) continue;
760
- var parsed = parseIdentityArgs(initializer);
762
+ var parsed = parseFirestoreModelIdentityArgs(initializer.getArguments());
761
763
  if (parsed) {
762
764
  out.push(_object_spread({
763
765
  identityConst: decl.getName()
@@ -795,48 +797,6 @@ function readIdentities(sourceFile) {
795
797
  }
796
798
  return out;
797
799
  }
798
- function parseIdentityArgs(call) {
799
- var args = call.getArguments();
800
- var result;
801
- if (args.length === 1) {
802
- var modelType = stringLiteralValue(args[0]);
803
- if (modelType !== undefined) {
804
- result = {
805
- modelType: modelType,
806
- collectionPrefix: undefined,
807
- parentIdentityConst: undefined
808
- };
809
- }
810
- } else if (args.length === 2) {
811
- var first = stringLiteralValue(args[0]);
812
- if (first === undefined) {
813
- var modelType1 = stringLiteralValue(args[1]);
814
- if (modelType1 !== undefined) {
815
- result = {
816
- modelType: modelType1,
817
- collectionPrefix: undefined,
818
- parentIdentityConst: identifierName(args[0])
819
- };
820
- }
821
- } else {
822
- result = {
823
- modelType: first,
824
- collectionPrefix: stringLiteralValue(args[1]),
825
- parentIdentityConst: undefined
826
- };
827
- }
828
- } else if (args.length >= 3) {
829
- var modelType2 = stringLiteralValue(args[1]);
830
- if (modelType2 !== undefined) {
831
- result = {
832
- modelType: modelType2,
833
- collectionPrefix: stringLiteralValue(args[2]),
834
- parentIdentityConst: identifierName(args[0])
835
- };
836
- }
837
- }
838
- return result;
839
- }
840
800
  function readInterfaces(sourceFile) {
841
801
  var out = [];
842
802
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -1117,48 +1077,6 @@ function readServiceFactoryModelType(jsDocs) {
1117
1077
  }
1118
1078
  return result;
1119
1079
  }
1120
- /**
1121
- * Resolves an `extends` clause to the concrete ancestor interface name,
1122
- * peeling any leading {@link PASSTHROUGH_TYPE_WRAPPERS}. Returns the leftmost
1123
- * identifier of the unwrapped expression so the inheritance walker can chain
1124
- * through utility-wrapped declarations like
1125
- * `extends Partial<MaybeMap<Omit<Base, '…'>>>`.
1126
- *
1127
- * @param expr - The `ExpressionWithTypeArguments` produced by `getExtends()`
1128
- * @returns The resolved interface name, or the original leftmost identifier when no inner reference is reachable.
1129
- */ function resolveExtendsName(expr) {
1130
- var head = expr.getExpression().getText();
1131
- var result = head;
1132
- if (PASSTHROUGH_TYPE_WRAPPERS.has(head)) {
1133
- var typeArgs = expr.getTypeArguments();
1134
- if (typeArgs.length > 0) {
1135
- var peeled = peelTypeNode(typeArgs[0]);
1136
- if (peeled !== undefined) {
1137
- result = peeled;
1138
- }
1139
- }
1140
- }
1141
- return result;
1142
- }
1143
- function peelTypeNode(node) {
1144
- var current = node;
1145
- while(Node.isParenthesizedTypeNode(current)){
1146
- current = current.getTypeNode();
1147
- }
1148
- var result;
1149
- if (Node.isTypeReference(current)) {
1150
- var name = current.getTypeName().getText();
1151
- if (PASSTHROUGH_TYPE_WRAPPERS.has(name)) {
1152
- var inner = current.getTypeArguments();
1153
- if (inner.length > 0) {
1154
- result = peelTypeNode(inner[0]);
1155
- }
1156
- } else {
1157
- result = name;
1158
- }
1159
- }
1160
- return result;
1161
- }
1162
1080
  function readConverters(sourceFile) {
1163
1081
  var out = [];
1164
1082
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -1302,8 +1220,15 @@ function readNestedFromExpression(expr) {
1302
1220
  return result;
1303
1221
  }
1304
1222
  /**
1305
- * Reads the `objectField` argument of a `firestoreSubObject` /
1306
- * `firestoreObjectArray` call into a {@link NestedConverterMatch}.
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.
1307
1232
  *
1308
1233
  * @param call - The nested-converter call expression.
1309
1234
  * @param fnName - The resolved factory name (`firestoreSubObject` or `firestoreObjectArray`).
@@ -1314,10 +1239,11 @@ function readNestedFromExpression(expr) {
1314
1239
  if (args.length > 0) {
1315
1240
  var config = args[0];
1316
1241
  if (Node.isObjectLiteralExpression(config)) {
1317
- var objectField = readPropertyValue(config, OBJECT_FIELD_KEY);
1318
- if (objectField) {
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) {
1319
1245
  result = buildNestedConverterMatch({
1320
- objectField: objectField,
1246
+ objectField: valueNode,
1321
1247
  call: call,
1322
1248
  fnName: fnName
1323
1249
  });
@@ -1327,12 +1253,15 @@ function readNestedFromExpression(expr) {
1327
1253
  return result;
1328
1254
  }
1329
1255
  /**
1330
- * Builds a {@link NestedConverterMatch} from a resolved `objectField` node:
1256
+ * Builds a {@link NestedConverterMatch} from a resolved value node:
1331
1257
  * an identifier yields a converter `ref`, an object literal yields an `inline`
1332
- * converter parsed from its `fields`.
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.
1333
1262
  *
1334
- * @param input - The `objectField` node, owning call expression, and factory name.
1335
- * @returns The nested-converter match, or `undefined` when neither shape applies.
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.
1336
1265
  */ function buildNestedConverterMatch(input) {
1337
1266
  var objectField = input.objectField, call = input.call, fnName = input.fnName;
1338
1267
  var isArray = fnName === OBJECT_ARRAY_FN;
@@ -1356,6 +1285,13 @@ function readNestedFromExpression(expr) {
1356
1285
  isArray: isArray
1357
1286
  };
1358
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
+ }
1359
1295
  }
1360
1296
  return result;
1361
1297
  }
@@ -1649,19 +1585,5 @@ function firstParagraph(text) {
1649
1585
  }
1650
1586
  return collected.join(' ').trim();
1651
1587
  }
1652
- function stringLiteralValue(node) {
1653
- var result;
1654
- if (Node.isStringLiteral(node) || Node.isNoSubstitutionTemplateLiteral(node)) {
1655
- result = node.getLiteralText();
1656
- }
1657
- return result;
1658
- }
1659
- function identifierName(node) {
1660
- var result;
1661
- if (Node.isIdentifier(node)) {
1662
- result = node.getText();
1663
- }
1664
- return result;
1665
- }
1666
1588
 
1667
1589
  export { extractCrudEntries, extractModelsFromSource };
@@ -1,13 +1,18 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-cli/manifest-extract",
3
- "version": "13.16.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.16.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.16.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.16.0",
54
- "@dereekb/firebase": "13.16.0",
55
- "@dereekb/model": "13.16.0",
56
- "@dereekb/nestjs": "13.16.0",
57
- "@dereekb/util": "13.16.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';