@dereekb/dbx-components-mcp 13.11.5 → 13.11.7

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.
@@ -5,7 +5,7 @@ const require = __createRequire(import.meta.url);
5
5
  // packages/dbx-components-mcp/package.json
6
6
  var package_default = {
7
7
  name: "@dereekb/dbx-components-mcp",
8
- version: "13.11.5",
8
+ version: "13.11.7",
9
9
  type: "module",
10
10
  bin: {
11
11
  "dbx-components-mcp": "dbx-components-mcp.js"
@@ -20,20 +20,20 @@ var package_default = {
20
20
  "@angular/core": "21.2.11",
21
21
  "@angular/forms": "21.2.11",
22
22
  "@angular/material": "^21.2.9",
23
- "@dereekb/dbx-cli": "13.11.5",
24
- "@dereekb/dbx-core": "13.11.5",
25
- "@dereekb/dbx-firebase": "13.11.5",
26
- "@dereekb/dbx-form": "13.11.5",
27
- "@dereekb/dbx-web": "13.11.5",
28
- "@dereekb/firebase": "13.11.5",
29
- "@dereekb/firebase-server": "13.11.5",
30
- "@dereekb/rxjs": "13.11.5",
31
- "@dereekb/util": "13.11.5",
23
+ "@dereekb/dbx-cli": "13.11.7",
24
+ "@dereekb/dbx-core": "13.11.7",
25
+ "@dereekb/dbx-firebase": "13.11.7",
26
+ "@dereekb/dbx-form": "13.11.7",
27
+ "@dereekb/dbx-web": "13.11.7",
28
+ "@dereekb/firebase": "13.11.7",
29
+ "@dereekb/firebase-server": "13.11.7",
30
+ "@dereekb/rxjs": "13.11.7",
31
+ "@dereekb/util": "13.11.7",
32
32
  "@uirouter/angular": "21.0.0",
33
33
  rxjs: "^7.8.2"
34
34
  },
35
35
  devDependencies: {
36
- "@dereekb/model": "13.11.5"
36
+ "@dereekb/model": "13.11.7"
37
37
  }
38
38
  };
39
39
 
@@ -8239,9 +8239,11 @@ function readFieldEntries(fields) {
8239
8239
  }
8240
8240
 
8241
8241
  // packages/dbx-components-mcp/src/scan/extract-models/find-enums.ts
8242
- import { Node as Node8, SyntaxKind as SyntaxKind3 } from "ts-morph";
8242
+ import { Node as Node9, SyntaxKind as SyntaxKind3 } from "ts-morph";
8243
8243
 
8244
8244
  // packages/dbx-components-mcp/src/scan/extract-models/find-interfaces.ts
8245
+ import { Node as Node8 } from "ts-morph";
8246
+ var PASSTHROUGH_TYPE_WRAPPERS = /* @__PURE__ */ new Set(["Partial", "Required", "Readonly", "NonNullable", "MaybeMap", "Pick", "Omit"]);
8245
8247
  function findInterfaces(sf) {
8246
8248
  const out = [];
8247
8249
  for (const decl of sf.getInterfaces()) {
@@ -8253,7 +8255,7 @@ function findInterfaces(sf) {
8253
8255
  function buildInterface(decl) {
8254
8256
  const tags = readInterfaceTags(decl.getJsDocs());
8255
8257
  const description = readDescription(decl.getJsDocs());
8256
- const extendsNames = decl.getExtends().map((e) => e.getExpression().getText());
8258
+ const extendsNames = decl.getExtends().map(resolveExtendsName);
8257
8259
  const props = [];
8258
8260
  for (const prop of decl.getProperties()) {
8259
8261
  const propJsDocs = prop.getJsDocs();
@@ -8277,6 +8279,39 @@ function buildInterface(decl) {
8277
8279
  props
8278
8280
  };
8279
8281
  }
8282
+ function resolveExtendsName(expr) {
8283
+ const head = expr.getExpression().getText();
8284
+ let result = head;
8285
+ if (PASSTHROUGH_TYPE_WRAPPERS.has(head)) {
8286
+ const typeArgs = expr.getTypeArguments();
8287
+ if (typeArgs.length > 0) {
8288
+ const peeled = peelTypeNode(typeArgs[0]);
8289
+ if (peeled !== void 0) {
8290
+ result = peeled;
8291
+ }
8292
+ }
8293
+ }
8294
+ return result;
8295
+ }
8296
+ function peelTypeNode(node) {
8297
+ let current = node;
8298
+ while (Node8.isParenthesizedTypeNode(current)) {
8299
+ current = current.getTypeNode();
8300
+ }
8301
+ let result;
8302
+ if (Node8.isTypeReference(current)) {
8303
+ const name = current.getTypeName().getText();
8304
+ if (PASSTHROUGH_TYPE_WRAPPERS.has(name)) {
8305
+ const inner = current.getTypeArguments();
8306
+ if (inner.length > 0) {
8307
+ result = peelTypeNode(inner[0]);
8308
+ }
8309
+ } else {
8310
+ result = name;
8311
+ }
8312
+ }
8313
+ return result;
8314
+ }
8280
8315
  function readInterfaceTags(jsDocs) {
8281
8316
  let dbxModel = false;
8282
8317
  for (const jsDoc of jsDocs) {
@@ -8354,14 +8389,14 @@ function buildEnum(decl) {
8354
8389
  if (initializer === void 0) {
8355
8390
  value = auto;
8356
8391
  auto = value + 1;
8357
- } else if (Node8.isStringLiteral(initializer) || Node8.isNoSubstitutionTemplateLiteral(initializer)) {
8392
+ } else if (Node9.isStringLiteral(initializer) || Node9.isNoSubstitutionTemplateLiteral(initializer)) {
8358
8393
  value = initializer.getLiteralText();
8359
- } else if (Node8.isNumericLiteral(initializer)) {
8394
+ } else if (Node9.isNumericLiteral(initializer)) {
8360
8395
  value = Number(initializer.getLiteralText());
8361
8396
  auto = value + 1;
8362
- } else if (Node8.isPrefixUnaryExpression(initializer)) {
8397
+ } else if (Node9.isPrefixUnaryExpression(initializer)) {
8363
8398
  const inner = initializer.getOperand();
8364
- if (Node8.isNumericLiteral(inner)) {
8399
+ if (Node9.isNumericLiteral(inner)) {
8365
8400
  const raw = Number(inner.getLiteralText());
8366
8401
  value = initializer.getOperatorToken() === SyntaxKind3.MinusToken ? -raw : raw;
8367
8402
  auto = value + 1;
@@ -8381,7 +8416,7 @@ function buildEnum(decl) {
8381
8416
  }
8382
8417
 
8383
8418
  // packages/dbx-components-mcp/src/scan/extract-models/find-identities.ts
8384
- import { Node as Node9 } from "ts-morph";
8419
+ import { Node as Node10 } from "ts-morph";
8385
8420
  var FUNCTION_NAME2 = "firestoreModelIdentity";
8386
8421
  function findIdentities(sf) {
8387
8422
  const out = [];
@@ -8389,7 +8424,7 @@ function findIdentities(sf) {
8389
8424
  if (!statement.isExported()) continue;
8390
8425
  for (const decl of statement.getDeclarations()) {
8391
8426
  const initializer = decl.getInitializer();
8392
- if (!initializer || !Node9.isCallExpression(initializer)) continue;
8427
+ if (!initializer || !Node10.isCallExpression(initializer)) continue;
8393
8428
  if (initializer.getExpression().getText() !== FUNCTION_NAME2) continue;
8394
8429
  const parsed = parseIdentityCall(initializer.getArguments());
8395
8430
  if (parsed) {
@@ -8426,14 +8461,14 @@ function parseIdentityCall(args) {
8426
8461
  }
8427
8462
  function stringLiteralValue(node) {
8428
8463
  let result;
8429
- if (Node9.isStringLiteral(node) || Node9.isNoSubstitutionTemplateLiteral(node)) {
8464
+ if (Node10.isStringLiteral(node) || Node10.isNoSubstitutionTemplateLiteral(node)) {
8430
8465
  result = node.getLiteralText();
8431
8466
  }
8432
8467
  return result;
8433
8468
  }
8434
8469
  function identifierName(node) {
8435
8470
  let result;
8436
- if (Node9.isIdentifier(node)) {
8471
+ if (Node10.isIdentifier(node)) {
8437
8472
  result = node.getText();
8438
8473
  }
8439
8474
  return result;
@@ -14244,7 +14279,15 @@ function createListAppTool(config) {
14244
14279
  }
14245
14280
 
14246
14281
  // packages/dbx-components-mcp/src/tools/model-validate/extract.ts
14247
- import { Node as Node10, Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
14282
+ import { Node as Node11, Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
14283
+
14284
+ // packages/dbx-components-mcp/src/tools/model-validate/types.ts
14285
+ var MAX_FIELD_NAME_LENGTH = 5;
14286
+ var ROOT_MODEL_ORDER = ["identity", "interface", "rolesType", "documentClass", "converter", "referenceFn", "collectionType", "collectionFn"];
14287
+ var SUBCOLLECTION_MODEL_ORDER = ["identity", "interface", "rolesType", "documentClass", "converter", "referenceFn", "collectionType", "collectionFactoryType", "collectionFn", "referenceGroupFn", "collectionGroupType", "collectionGroupFn"];
14288
+ var SUB_OBJECT_FACTORY_NAMES = ["firestoreSubObject", "firestoreObjectArray", "firestoreMap"];
14289
+
14290
+ // packages/dbx-components-mcp/src/tools/model-validate/extract.ts
14248
14291
  function extractFile(source) {
14249
14292
  const project = new Project4({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
14250
14293
  const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
@@ -14254,16 +14297,56 @@ function extractFile(source) {
14254
14297
  const firstModelLine = identities.length > 0 ? Math.min(...identities.map((i) => i.line)) : void 0;
14255
14298
  const models = identities.map((identity) => extractModel(sourceFile, identity));
14256
14299
  const dataInterfaces = findDataInterfaces(sourceFile, groupInterface);
14300
+ const subObjectCalls = findSubObjectFactoryCalls(sourceFile);
14257
14301
  const result = {
14258
14302
  name: source.name,
14259
14303
  groupInterface,
14260
14304
  groupTypes,
14261
14305
  firstModelLine,
14262
14306
  models,
14263
- dataInterfaces
14307
+ dataInterfaces,
14308
+ subObjectCalls
14264
14309
  };
14265
14310
  return result;
14266
14311
  }
14312
+ function findSubObjectFactoryCalls(sourceFile) {
14313
+ const out = [];
14314
+ const factorySet = new Set(SUB_OBJECT_FACTORY_NAMES);
14315
+ for (const call of sourceFile.getDescendantsOfKind(SyntaxKind4.CallExpression)) {
14316
+ const expr = call.getExpression();
14317
+ if (!Node11.isIdentifier(expr)) {
14318
+ continue;
14319
+ }
14320
+ const factoryName = expr.getText();
14321
+ if (!factorySet.has(factoryName)) {
14322
+ continue;
14323
+ }
14324
+ const typeArgs = call.getTypeArguments();
14325
+ if (typeArgs.length === 0) {
14326
+ continue;
14327
+ }
14328
+ const typeArgName = readTypeReferenceIdentifier(typeArgs[0]);
14329
+ if (!typeArgName) {
14330
+ continue;
14331
+ }
14332
+ out.push({
14333
+ factoryName,
14334
+ typeArgName,
14335
+ line: call.getStartLineNumber()
14336
+ });
14337
+ }
14338
+ return out;
14339
+ }
14340
+ function readTypeReferenceIdentifier(typeNode) {
14341
+ if (!Node11.isTypeReference(typeNode)) {
14342
+ return void 0;
14343
+ }
14344
+ const nameNode = typeNode.getTypeName();
14345
+ if (!Node11.isIdentifier(nameNode)) {
14346
+ return void 0;
14347
+ }
14348
+ return nameNode.getText();
14349
+ }
14267
14350
  function findDataInterfaces(sourceFile, groupInterface) {
14268
14351
  const out = [];
14269
14352
  const groupName = groupInterface?.name;
@@ -14274,7 +14357,8 @@ function findDataInterfaces(sourceFile, groupInterface) {
14274
14357
  }
14275
14358
  const fields = extractInterfaceFields(iface);
14276
14359
  const dbxModelTag = readDbxModelTag(iface.getJsDocs());
14277
- out.push({ name, line: iface.getStartLineNumber(), dbxModelTag, fields });
14360
+ const dbxModelSubObjectTag = readDbxModelSubObjectTag(iface.getJsDocs());
14361
+ out.push({ name, line: iface.getStartLineNumber(), dbxModelTag, dbxModelSubObjectTag, fields });
14278
14362
  }
14279
14363
  return out;
14280
14364
  }
@@ -14344,6 +14428,17 @@ function readDbxModelTag(jsDocs) {
14344
14428
  }
14345
14429
  return result;
14346
14430
  }
14431
+ function readDbxModelSubObjectTag(jsDocs) {
14432
+ let result = false;
14433
+ for (const jsDoc of jsDocs) {
14434
+ for (const tag of jsDoc.getTags()) {
14435
+ if (tag.getTagName() === "dbxModelSubObject") {
14436
+ result = true;
14437
+ }
14438
+ }
14439
+ }
14440
+ return result;
14441
+ }
14347
14442
  function readDbxModelVariableTag(jsDocs) {
14348
14443
  let result;
14349
14444
  for (const jsDoc of jsDocs) {
@@ -14383,7 +14478,7 @@ function extractIdentityRefs(alias) {
14383
14478
  if (!typeNode) {
14384
14479
  return refs;
14385
14480
  }
14386
- if (Node10.isTypeQuery(typeNode)) {
14481
+ if (Node11.isTypeQuery(typeNode)) {
14387
14482
  refs.push(typeNode.getExprName().getText());
14388
14483
  }
14389
14484
  const typeofNodes = typeNode.getDescendantsOfKind(SyntaxKind4.TypeQuery);
@@ -14397,7 +14492,7 @@ function findIdentities2(sourceFile) {
14397
14492
  for (const statement of sourceFile.getVariableStatements()) {
14398
14493
  for (const decl of statement.getDeclarations()) {
14399
14494
  const initializer = decl.getInitializer();
14400
- if (!initializer || !Node10.isCallExpression(initializer)) {
14495
+ if (!initializer || !Node11.isCallExpression(initializer)) {
14401
14496
  continue;
14402
14497
  }
14403
14498
  if (initializer.getExpression().getText() !== "firestoreModelIdentity") {
@@ -14433,7 +14528,7 @@ function parseIdentityArgs(args) {
14433
14528
  }
14434
14529
  if (args.length === 3) {
14435
14530
  const [parentNode, nameNode, prefixNode] = args;
14436
- const parentRef = Node10.isIdentifier(parentNode) ? parentNode.getText() : void 0;
14531
+ const parentRef = Node11.isIdentifier(parentNode) ? parentNode.getText() : void 0;
14437
14532
  const result2 = {
14438
14533
  parentIdentityRef: parentRef,
14439
14534
  collectionName: stringLiteralValue2(nameNode),
@@ -14448,7 +14543,7 @@ function stringLiteralValue2(node) {
14448
14543
  if (!node) {
14449
14544
  return void 0;
14450
14545
  }
14451
- if (Node10.isStringLiteral(node) || Node10.isNoSubstitutionTemplateLiteral(node)) {
14546
+ if (Node11.isStringLiteral(node) || Node11.isNoSubstitutionTemplateLiteral(node)) {
14452
14547
  return node.getLiteralText();
14453
14548
  }
14454
14549
  return void 0;
@@ -14509,7 +14604,7 @@ function detectFactoryCallKind(sourceFile, factoryFnName) {
14509
14604
  const calls = fn.getDescendantsOfKind(SyntaxKind4.CallExpression);
14510
14605
  for (const call of calls) {
14511
14606
  const expr = call.getExpression();
14512
- if (!Node10.isPropertyAccessExpression(expr)) {
14607
+ if (!Node11.isPropertyAccessExpression(expr)) {
14513
14608
  continue;
14514
14609
  }
14515
14610
  const name = expr.getName();
@@ -15100,6 +15195,16 @@ var RULE_CATALOG = [
15100
15195
  whenItDoesNotApply: "When the rename was intentional (rare \u2014 usually a copy-paste).",
15101
15196
  canonicalFix: "Update the getter body to return the matching identity constant."
15102
15197
  },
15198
+ {
15199
+ code: "MODEL_FIELD_LONG_NAME_EQUALS_NAME",
15200
+ source: "dbx_model_validate",
15201
+ severity: "warning",
15202
+ title: "A persisted field's `@dbxModelVariable <longName>` tag value matches the field's short name verbatim, defeating the tag's purpose (the long name should be the field's unabbreviated camelCase variable name)",
15203
+ whatItFlags: "A persisted field's `@dbxModelVariable <longName>` tag value matches the field's short name verbatim, defeating the tag's purpose (the long name should be the field's unabbreviated camelCase variable name).",
15204
+ whenItApplies: "Every field on a `@dbxModel` interface or on a `@dbxModelSubObject`-tagged embedded sub-object interface where `@dbxModelVariable` is present and its value equals the field's name (e.g. field `h` tagged `@dbxModelVariable h`, field `ub` tagged `@dbxModelVariable ub`). The tag must always carry the unabbreviated form so the catalog and decoder surface a meaningful long name.",
15205
+ whenItDoesNotApply: "Fields whose name is already the unabbreviated camelCase form (e.g. `name`, `email`, `id`, `at`) \u2014 add those to `dbx-mcp.config.json` `modelValidate.ignoredFieldNames` to silence the warning workspace-wide.",
15206
+ canonicalFix: "Replace the tag value with the field's unabbreviated camelCase variable name (e.g. `@dbxModelVariable h` \u2192 `@dbxModelVariable hours`, `@dbxModelVariable ub` \u2192 `@dbxModelVariable usedBudget`). To exempt fields whose long name legitimately equals the short name, add them to `modelValidate.ignoredFieldNames`."
15207
+ },
15103
15208
  {
15104
15209
  code: "MODEL_FIELD_MISSING_JSDOC",
15105
15210
  source: "dbx_model_validate",
@@ -15116,8 +15221,8 @@ var RULE_CATALOG = [
15116
15221
  severity: "warning",
15117
15222
  title: "A persisted field is missing its `@dbxModelVariable <name>` JSDoc tag",
15118
15223
  whatItFlags: "A persisted field is missing its `@dbxModelVariable <name>` JSDoc tag.",
15119
- whenItApplies: "Every field on a `@dbxModel` interface \u2014 the tag carries the human-readable long name the catalog and decoder use when surfacing the field to operators. The long name is the variable name the field would have unabbreviated, written in camelCase (e.g. `uid` \u2192 `userUid`, `n` \u2192 `name`, `crAt` \u2192 `createdAt`).",
15120
- whenItDoesNotApply: "Fields on embedded sub-object interfaces (no `@dbxModel` parent) and fields the project deliberately leaves untagged (rare).",
15224
+ whenItApplies: "Every field on a `@dbxModel` interface or on a `@dbxModelSubObject`-tagged embedded sub-object interface \u2014 the tag carries the human-readable long name the catalog and decoder use when surfacing the field to operators. The long name is the variable name the field would have unabbreviated, written in camelCase (e.g. `uid` \u2192 `userUid`, `n` \u2192 `name`, `crAt` \u2192 `createdAt`).",
15225
+ whenItDoesNotApply: "Fields on embedded sub-object interfaces that are not tagged with `@dbxModelSubObject` (the tag is opt-in) and fields the project deliberately leaves untagged (rare).",
15121
15226
  canonicalFix: "Append `@dbxModelVariable <longName>` to the field's JSDoc block, where `<longName>` is the field's unabbreviated camelCase variable name."
15122
15227
  },
15123
15228
  {
@@ -15304,6 +15409,32 @@ var RULE_CATALOG = [
15304
15409
  whenItDoesNotApply: "When intentionally module-private.",
15305
15410
  canonicalFix: "Add `export` to the alias."
15306
15411
  },
15412
+ {
15413
+ code: "MODEL_SUBOBJECT_NOT_TAGGED",
15414
+ source: "dbx_model_validate",
15415
+ severity: "warning",
15416
+ title: "An interface is referenced as the first generic type-argument of a sub-object factory call (`firestoreSubObject<T>(...)`, `firestoreObjectArray<T>(...)`, or `firestoreMap<T>(...)`) but its declaration carries neither `@dbxModel` nor `@dbxModelSubObject`. The interface therefore opts out of the workspace's `@dbxModelVariable` long-name conventions even though its fields are persisted to Firestore",
15417
+ whatItFlags: "An interface is referenced as the first generic type-argument of a sub-object factory call (`firestoreSubObject<T>(...)`, `firestoreObjectArray<T>(...)`, or `firestoreMap<T>(...)`) but its declaration carries neither `@dbxModel` nor `@dbxModelSubObject`. The interface therefore opts out of the workspace's `@dbxModelVariable` long-name conventions even though its fields are persisted to Firestore.",
15418
+ whenItApplies: "Any interface declared in the validated source set that is the type-arg of at least one sub-object factory call and lacks both `@dbxModel` and `@dbxModelSubObject`. The warning is emitted once per interface (de-duplicated across all call sites) and anchored at the interface declaration line. Unresolved type-args \u2014 interfaces declared outside the validated source set, generic parameters, inline types \u2014 are silently skipped to avoid false positives.",
15419
+ whenItDoesNotApply: "Interfaces already tagged with `@dbxModel` (top-level models) or `@dbxModelSubObject` (embedded sub-objects), and interfaces referenced only from outside the supplied source set (different package, etc.).",
15420
+ canonicalFix: "Add `@dbxModelSubObject` to the interface's JSDoc block so its fields are subject to `@dbxModelVariable` long-name checks. If the interface is actually a top-level Firestore model, declare a matching `firestoreModelIdentity` and tag it `@dbxModel` instead.",
15421
+ seeAlso: [
15422
+ {
15423
+ kind: "artifact",
15424
+ target: "firestore-model"
15425
+ }
15426
+ ]
15427
+ },
15428
+ {
15429
+ code: "MODEL_SUBOBJECT_TAG_CONFLICT",
15430
+ source: "dbx_model_validate",
15431
+ severity: "error",
15432
+ title: "An interface declaration carries both `@dbxModel` and `@dbxModelSubObject` JSDoc tags. The two tags model mutually exclusive concepts \u2014 `@dbxModel` marks a top-level Firestore model registered in the catalog via `firestoreModelIdentity`, while `@dbxModelSubObject` marks an embedded sub-object interface persisted only as part of a parent model's converter \u2014 so an interface must carry at most one",
15433
+ whatItFlags: "An interface declaration carries both `@dbxModel` and `@dbxModelSubObject` JSDoc tags. The two tags model mutually exclusive concepts \u2014 `@dbxModel` marks a top-level Firestore model registered in the catalog via `firestoreModelIdentity`, while `@dbxModelSubObject` marks an embedded sub-object interface persisted only as part of a parent model's converter \u2014 so an interface must carry at most one.",
15434
+ whenItApplies: "Any interface JSDoc block where both `@dbxModel` and `@dbxModelSubObject` are present.",
15435
+ whenItDoesNotApply: "Interfaces carrying only one of the two tags (or neither).",
15436
+ canonicalFix: "Remove whichever tag does not describe the interface. If the interface has a matching `firestoreModelIdentity` call, keep `@dbxModel`; if it is only embedded inside another model via `firestoreSubObject<T>()`, keep `@dbxModelSubObject`."
15437
+ },
15307
15438
  {
15308
15439
  code: "SUB_MISSING_COLLECTION_FACTORY_FN",
15309
15440
  source: "dbx_model_validate",
@@ -16930,15 +17061,11 @@ function formatSeeAlso(ref) {
16930
17061
  return `Doc: ${ref.target}${tail}`;
16931
17062
  }
16932
17063
 
16933
- // packages/dbx-components-mcp/src/tools/model-validate/types.ts
16934
- var MAX_FIELD_NAME_LENGTH = 5;
16935
- var ROOT_MODEL_ORDER = ["identity", "interface", "rolesType", "documentClass", "converter", "referenceFn", "collectionType", "collectionFn"];
16936
- var SUBCOLLECTION_MODEL_ORDER = ["identity", "interface", "rolesType", "documentClass", "converter", "referenceFn", "collectionType", "collectionFactoryType", "collectionFn", "referenceGroupFn", "collectionGroupType", "collectionGroupFn"];
16937
-
16938
17064
  // packages/dbx-components-mcp/src/tools/model-validate/rules.ts
16939
- function runRules(file, options) {
17065
+ function runRules(file, options, context) {
16940
17066
  const violations = [];
16941
17067
  if (file.models.length === 0) {
17068
+ checkSubObjectFactoryCallSites(file, violations, context);
16942
17069
  return violations;
16943
17070
  }
16944
17071
  checkFileLevel(file, violations);
@@ -16951,6 +17078,8 @@ function runRules(file, options) {
16951
17078
  checkDeclarationOrder(file, model, violations);
16952
17079
  }
16953
17080
  checkFieldNameLengths(file, violations, options);
17081
+ checkSubObjectInterfaceTags(file, violations);
17082
+ checkSubObjectFactoryCallSites(file, violations, context);
16954
17083
  return violations;
16955
17084
  }
16956
17085
  function checkFieldNameLengths(file, violations, options) {
@@ -16974,9 +17103,10 @@ function checkFieldNameLengths(file, violations, options) {
16974
17103
  });
16975
17104
  }
16976
17105
  }
16977
- checkFieldJsDocs(file, violations);
17106
+ checkFieldJsDocs(file, violations, options);
16978
17107
  }
16979
- function checkFieldJsDocs(file, violations) {
17108
+ function checkFieldJsDocs(file, violations, options) {
17109
+ const ignored = options?.ignoredFieldNames;
16980
17110
  for (const iface of file.dataInterfaces) {
16981
17111
  for (const field of iface.fields) {
16982
17112
  if (!field.jsDocFirstLine) {
@@ -16989,7 +17119,8 @@ function checkFieldJsDocs(file, violations) {
16989
17119
  model: iface.name
16990
17120
  });
16991
17121
  }
16992
- if (iface.dbxModelTag && field.dbxModelVariableTag === void 0) {
17122
+ const fieldRulesApply = iface.dbxModelTag || iface.dbxModelSubObjectTag;
17123
+ if (fieldRulesApply && field.dbxModelVariableTag === void 0) {
16993
17124
  pushViolation(violations, {
16994
17125
  code: "MODEL_FIELD_MISSING_VARIABLE_TAG",
16995
17126
  severity: "warning",
@@ -16999,7 +17130,60 @@ function checkFieldJsDocs(file, violations) {
16999
17130
  model: iface.name
17000
17131
  });
17001
17132
  }
17133
+ if (fieldRulesApply && field.dbxModelVariableTag !== void 0 && field.dbxModelVariableTag === field.name && !ignored?.has(field.name)) {
17134
+ pushViolation(violations, {
17135
+ code: "MODEL_FIELD_LONG_NAME_EQUALS_NAME",
17136
+ severity: "warning",
17137
+ message: `Field \`${field.name}\` in interface \`${iface.name}\` has \`@dbxModelVariable ${field.dbxModelVariableTag}\` matching its short name. The long name should be the field's unabbreviated camelCase variable name (e.g. \`h\` \u2192 \`hours\`, \`ub\` \u2192 \`usedBudget\`). If the short name is already the unabbreviated form, add \`${field.name}\` to \`modelValidate.ignoredFieldNames\` in \`dbx-mcp.config.json\`.`,
17138
+ file: file.name,
17139
+ line: field.line,
17140
+ model: iface.name
17141
+ });
17142
+ }
17143
+ }
17144
+ }
17145
+ }
17146
+ function checkSubObjectInterfaceTags(file, violations) {
17147
+ for (const iface of file.dataInterfaces) {
17148
+ if (iface.dbxModelTag && iface.dbxModelSubObjectTag) {
17149
+ pushViolation(violations, {
17150
+ code: "MODEL_SUBOBJECT_TAG_CONFLICT",
17151
+ message: `Interface \`${iface.name}\` carries both \`@dbxModel\` and \`@dbxModelSubObject\`. Use only \`@dbxModel\` for top-level Firestore models; use \`@dbxModelSubObject\` only for embedded sub-objects without a \`firestoreModelIdentity\`.`,
17152
+ file: file.name,
17153
+ line: iface.line,
17154
+ model: iface.name
17155
+ });
17156
+ }
17157
+ }
17158
+ }
17159
+ function checkSubObjectFactoryCallSites(file, violations, context) {
17160
+ if (!context) {
17161
+ return;
17162
+ }
17163
+ if (file.subObjectCalls.length === 0) {
17164
+ return;
17165
+ }
17166
+ for (const call of file.subObjectCalls) {
17167
+ const entry = context.interfacesByName.get(call.typeArgName);
17168
+ if (!entry) {
17169
+ continue;
17170
+ }
17171
+ const { iface, file: declFile } = entry;
17172
+ if (iface.dbxModelTag || iface.dbxModelSubObjectTag) {
17173
+ continue;
17174
+ }
17175
+ if (context.emittedSubObjectInterfaces.has(call.typeArgName)) {
17176
+ continue;
17002
17177
  }
17178
+ context.emittedSubObjectInterfaces.add(call.typeArgName);
17179
+ pushViolation(violations, {
17180
+ code: "MODEL_SUBOBJECT_NOT_TAGGED",
17181
+ severity: "warning",
17182
+ message: `Interface \`${iface.name}\` is referenced by \`${call.factoryName}<${iface.name}>(...)\` at ${file.name}:${call.line} but carries neither \`@dbxModel\` nor \`@dbxModelSubObject\`. Tag the interface with \`@dbxModelSubObject\` so its persisted fields are subject to the same \`@dbxModelVariable\` long-name checks as a top-level model.`,
17183
+ file: declFile,
17184
+ line: iface.line,
17185
+ model: iface.name
17186
+ });
17003
17187
  }
17004
17188
  }
17005
17189
  function checkFileLevel(file, violations) {
@@ -17703,10 +17887,15 @@ function validateFirebaseModelSources(sources, options) {
17703
17887
  let modelsChecked = 0;
17704
17888
  let errorCount = 0;
17705
17889
  let warningCount = 0;
17890
+ const extracteds = [];
17706
17891
  for (const source of sources) {
17707
17892
  const extracted = extractFile(source);
17893
+ extracteds.push(extracted);
17708
17894
  modelsChecked += extracted.models.length;
17709
- const fileViolations = runRules(extracted, options);
17895
+ }
17896
+ const context = buildCrossFileRuleContext(extracteds);
17897
+ for (const extracted of extracteds) {
17898
+ const fileViolations = runRules(extracted, options, context);
17710
17899
  for (const v of fileViolations) {
17711
17900
  violations.push(v);
17712
17901
  if (v.severity === "error") {
@@ -17725,6 +17914,22 @@ function validateFirebaseModelSources(sources, options) {
17725
17914
  };
17726
17915
  return result;
17727
17916
  }
17917
+ function buildCrossFileRuleContext(extracteds) {
17918
+ const interfacesByName = /* @__PURE__ */ new Map();
17919
+ for (const file of extracteds) {
17920
+ for (const iface of file.dataInterfaces) {
17921
+ if (interfacesByName.has(iface.name)) {
17922
+ continue;
17923
+ }
17924
+ interfacesByName.set(iface.name, { file: file.name, iface });
17925
+ }
17926
+ }
17927
+ const context = {
17928
+ interfacesByName,
17929
+ emittedSubObjectInterfaces: /* @__PURE__ */ new Set()
17930
+ };
17931
+ return context;
17932
+ }
17728
17933
 
17729
17934
  // packages/dbx-components-mcp/src/tools/model-validate.tool.ts
17730
17935
  var DBX_MODEL_VALIDATE_TOOL = {
@@ -17779,7 +17984,7 @@ var modelValidateTool = /* @__PURE__ */ createModelValidateTool();
17779
17984
  var runModelValidate = modelValidateTool.run;
17780
17985
 
17781
17986
  // packages/dbx-components-mcp/src/tools/model-validate-api/extract.ts
17782
- import { Node as Node11, Project as Project5, SyntaxKind as SyntaxKind5 } from "ts-morph";
17987
+ import { Node as Node12, Project as Project5, SyntaxKind as SyntaxKind5 } from "ts-morph";
17783
17988
  function extractFile2(source) {
17784
17989
  const project = new Project5({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
17785
17990
  const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
@@ -17945,7 +18150,7 @@ function findCrudConfigType(sourceFile) {
17945
18150
  continue;
17946
18151
  }
17947
18152
  const typeNode = alias.getTypeNode();
17948
- const summary = typeNode && Node11.isTypeLiteral(typeNode) ? summarizeCrudConfigType(typeNode) : { keys: [], nonNullKeys: [], bareLeafParamsNames: [] };
18153
+ const summary = typeNode && Node12.isTypeLiteral(typeNode) ? summarizeCrudConfigType(typeNode) : { keys: [], nonNullKeys: [], bareLeafParamsNames: [] };
17949
18154
  const result = {
17950
18155
  name: alias.getName(),
17951
18156
  exported: alias.isExported(),
@@ -17959,14 +18164,14 @@ function findCrudConfigType(sourceFile) {
17959
18164
  return void 0;
17960
18165
  }
17961
18166
  function summarizeCrudConfigType(typeLiteral) {
17962
- if (!Node11.isTypeLiteral(typeLiteral)) {
18167
+ if (!Node12.isTypeLiteral(typeLiteral)) {
17963
18168
  return { keys: [], nonNullKeys: [], bareLeafParamsNames: [] };
17964
18169
  }
17965
18170
  const keys = [];
17966
18171
  const nonNullKeys = [];
17967
18172
  const bareLeafParamsNames = [];
17968
18173
  for (const member of typeLiteral.getMembers()) {
17969
- if (!Node11.isPropertySignature(member)) {
18174
+ if (!Node12.isPropertySignature(member)) {
17970
18175
  continue;
17971
18176
  }
17972
18177
  const name = member.getName();
@@ -17984,18 +18189,18 @@ function summarizeCrudConfigType(typeLiteral) {
17984
18189
  return { keys, nonNullKeys, bareLeafParamsNames };
17985
18190
  }
17986
18191
  function isNullLiteralType(node) {
17987
- if (Node11.isLiteralTypeNode(node)) {
18192
+ if (Node12.isLiteralTypeNode(node)) {
17988
18193
  const literal = node.getLiteral();
17989
- if (Node11.isNullLiteral(literal)) {
18194
+ if (Node12.isNullLiteral(literal)) {
17990
18195
  return true;
17991
18196
  }
17992
18197
  }
17993
18198
  return false;
17994
18199
  }
17995
18200
  function collectBareParamsLeaves(node, out) {
17996
- if (Node11.isTypeLiteral(node)) {
18201
+ if (Node12.isTypeLiteral(node)) {
17997
18202
  for (const member of node.getMembers()) {
17998
- if (!Node11.isPropertySignature(member)) {
18203
+ if (!Node12.isPropertySignature(member)) {
17999
18204
  continue;
18000
18205
  }
18001
18206
  const valueNode = member.getTypeNode();
@@ -18005,10 +18210,10 @@ function collectBareParamsLeaves(node, out) {
18005
18210
  }
18006
18211
  return;
18007
18212
  }
18008
- if (Node11.isTupleTypeNode(node)) {
18213
+ if (Node12.isTupleTypeNode(node)) {
18009
18214
  return;
18010
18215
  }
18011
- if (Node11.isTypeReference(node)) {
18216
+ if (Node12.isTypeReference(node)) {
18012
18217
  const name = node.getTypeName().getText();
18013
18218
  if (name.endsWith("Params")) {
18014
18219
  out.push(name);
@@ -18025,12 +18230,12 @@ function findCrudConfigConst(sourceFile) {
18025
18230
  const typeNode = decl.getTypeNode();
18026
18231
  const initializer = decl.getInitializer();
18027
18232
  const runtimeKeys = [];
18028
- if (initializer && Node11.isAsExpression(initializer)) {
18233
+ if (initializer && Node12.isAsExpression(initializer)) {
18029
18234
  const inner = initializer.getExpression();
18030
- if (Node11.isObjectLiteralExpression(inner)) {
18235
+ if (Node12.isObjectLiteralExpression(inner)) {
18031
18236
  runtimeKeys.push(...collectObjectLiteralKeys(inner));
18032
18237
  }
18033
- } else if (initializer && Node11.isObjectLiteralExpression(initializer)) {
18238
+ } else if (initializer && Node12.isObjectLiteralExpression(initializer)) {
18034
18239
  runtimeKeys.push(...collectObjectLiteralKeys(initializer));
18035
18240
  }
18036
18241
  const result = {
@@ -18048,7 +18253,7 @@ function findCrudConfigConst(sourceFile) {
18048
18253
  function collectObjectLiteralKeys(obj) {
18049
18254
  const out = [];
18050
18255
  for (const prop of obj.getProperties()) {
18051
- if (Node11.isPropertyAssignment(prop) || Node11.isShorthandPropertyAssignment(prop)) {
18256
+ if (Node12.isPropertyAssignment(prop) || Node12.isShorthandPropertyAssignment(prop)) {
18052
18257
  out.push(prop.getName());
18053
18258
  }
18054
18259
  }
@@ -18064,7 +18269,7 @@ function findFunctionMap(sourceFile) {
18064
18269
  const initializer = decl.getInitializer();
18065
18270
  let callsFactory = false;
18066
18271
  const factoryArgs = [];
18067
- if (initializer && Node11.isCallExpression(initializer)) {
18272
+ if (initializer && Node12.isCallExpression(initializer)) {
18068
18273
  const exprText = initializer.getExpression().getText();
18069
18274
  if (exprText === "callModelFirebaseFunctionMapFactory") {
18070
18275
  callsFactory = true;
@@ -18202,18 +18407,18 @@ function extractCastTargetName(node) {
18202
18407
  return void 0;
18203
18408
  }
18204
18409
  let current = node;
18205
- while (current && Node11.isAsExpression(current)) {
18410
+ while (current && Node12.isAsExpression(current)) {
18206
18411
  const typeNode = current.getTypeNode();
18207
18412
  if (!typeNode) {
18208
18413
  break;
18209
18414
  }
18210
- if (Node11.isTypeReference(typeNode)) {
18415
+ if (Node12.isTypeReference(typeNode)) {
18211
18416
  const refName = typeNode.getTypeName().getText();
18212
18417
  if (refName === "Type") {
18213
18418
  const args = typeNode.getTypeArguments();
18214
18419
  if (args.length === 1) {
18215
18420
  const arg = args[0];
18216
- if (Node11.isTypeReference(arg)) {
18421
+ if (Node12.isTypeReference(arg)) {
18217
18422
  return arg.getTypeName().getText();
18218
18423
  }
18219
18424
  return arg.getText();
@@ -18232,7 +18437,7 @@ function extractValidatorProperties(initializer) {
18232
18437
  }
18233
18438
  const out = [];
18234
18439
  for (const prop of obj.getProperties()) {
18235
- if (!Node11.isPropertyAssignment(prop)) {
18440
+ if (!Node12.isPropertyAssignment(prop)) {
18236
18441
  continue;
18237
18442
  }
18238
18443
  const propAssignment = prop;
@@ -18242,7 +18447,7 @@ function extractValidatorProperties(initializer) {
18242
18447
  const clean = optional ? stripped.slice(0, -1) : stripped;
18243
18448
  const valueNode = propAssignment.getInitializer();
18244
18449
  let hasClearable = false;
18245
- if (valueNode && Node11.isCallExpression(valueNode)) {
18450
+ if (valueNode && Node12.isCallExpression(valueNode)) {
18246
18451
  const exprText = valueNode.getExpression().getText();
18247
18452
  if (exprText === "clearable") {
18248
18453
  hasClearable = true;
@@ -18254,25 +18459,25 @@ function extractValidatorProperties(initializer) {
18254
18459
  }
18255
18460
  function findArktypeObjectLiteral(initializer) {
18256
18461
  let current = initializer;
18257
- while (current && Node11.isAsExpression(current)) {
18462
+ while (current && Node12.isAsExpression(current)) {
18258
18463
  current = current.getExpression();
18259
18464
  }
18260
- if (!current || !Node11.isCallExpression(current)) {
18465
+ if (!current || !Node12.isCallExpression(current)) {
18261
18466
  return void 0;
18262
18467
  }
18263
18468
  const expr = current.getExpression();
18264
- if (Node11.isIdentifier(expr) && expr.getText() === "type") {
18469
+ if (Node12.isIdentifier(expr) && expr.getText() === "type") {
18265
18470
  const args = current.getArguments();
18266
18471
  const arg = args[0];
18267
- if (arg && Node11.isObjectLiteralExpression(arg)) {
18472
+ if (arg && Node12.isObjectLiteralExpression(arg)) {
18268
18473
  return arg;
18269
18474
  }
18270
18475
  return void 0;
18271
18476
  }
18272
- if (Node11.isPropertyAccessExpression(expr) && expr.getName() === "merge") {
18477
+ if (Node12.isPropertyAccessExpression(expr) && expr.getName() === "merge") {
18273
18478
  const args = current.getArguments();
18274
18479
  const arg = args[0];
18275
- if (arg && Node11.isObjectLiteralExpression(arg)) {
18480
+ if (arg && Node12.isObjectLiteralExpression(arg)) {
18276
18481
  return arg;
18277
18482
  }
18278
18483
  }
@@ -18957,7 +19162,7 @@ import { readdir as readdir2, readFile as readFile4, stat as stat4 } from "node:
18957
19162
  import { join as join4, relative as relative4, sep as sep5 } from "node:path";
18958
19163
 
18959
19164
  // packages/dbx-cli/manifest-extract/src/lib/extract-crud.ts
18960
- import { Node as Node12, Project as Project6 } from "ts-morph";
19165
+ import { Node as Node13, Project as Project6 } from "ts-morph";
18961
19166
  var SUPPORTED_VERBS = /* @__PURE__ */ new Set(["create", "read", "update", "delete", "query"]);
18962
19167
  function extractCrudEntries(source) {
18963
19168
  const project = new Project6({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
@@ -18983,9 +19188,9 @@ function extractCrudEntries(source) {
18983
19188
  };
18984
19189
  if (crudConfigType) {
18985
19190
  const literal = crudConfigType.getTypeNode();
18986
- if (literal && Node12.isTypeLiteral(literal)) {
19191
+ if (literal && Node13.isTypeLiteral(literal)) {
18987
19192
  for (const member of literal.getMembers()) {
18988
- if (!Node12.isPropertySignature(member)) {
19193
+ if (!Node13.isPropertySignature(member)) {
18989
19194
  continue;
18990
19195
  }
18991
19196
  const modelName = member.getName();
@@ -18997,9 +19202,9 @@ function extractCrudEntries(source) {
18997
19202
  if (isNullLiteralType2(valueNode)) {
18998
19203
  continue;
18999
19204
  }
19000
- if (Node12.isTypeLiteral(valueNode)) {
19205
+ if (Node13.isTypeLiteral(valueNode)) {
19001
19206
  for (const verbMember of valueNode.getMembers()) {
19002
- if (!Node12.isPropertySignature(verbMember)) {
19207
+ if (!Node13.isPropertySignature(verbMember)) {
19003
19208
  continue;
19004
19209
  }
19005
19210
  const verbName = verbMember.getName();
@@ -19020,9 +19225,9 @@ function extractCrudEntries(source) {
19020
19225
  const functionTypeMap = findTypeAliasByEnding(sourceFile, "FunctionTypeMap");
19021
19226
  if (functionTypeMap) {
19022
19227
  const literal = functionTypeMap.getTypeNode();
19023
- if (literal && Node12.isTypeLiteral(literal)) {
19228
+ if (literal && Node13.isTypeLiteral(literal)) {
19024
19229
  for (const member of literal.getMembers()) {
19025
- if (!Node12.isPropertySignature(member)) {
19230
+ if (!Node13.isPropertySignature(member)) {
19026
19231
  continue;
19027
19232
  }
19028
19233
  const key = member.getName();
@@ -19090,9 +19295,9 @@ function inferGroupName2(sourceFile) {
19090
19295
  return void 0;
19091
19296
  }
19092
19297
  function isNullLiteralType2(node) {
19093
- if (Node12.isLiteralTypeNode(node)) {
19298
+ if (Node13.isLiteralTypeNode(node)) {
19094
19299
  const literal = node.getLiteral();
19095
- if (Node12.isNullLiteral(literal)) {
19300
+ if (Node13.isNullLiteral(literal)) {
19096
19301
  return true;
19097
19302
  }
19098
19303
  }
@@ -19100,9 +19305,9 @@ function isNullLiteralType2(node) {
19100
19305
  }
19101
19306
  function collectVerbEntries(input) {
19102
19307
  const { modelName, verb, valueNode, entries, fallbackDescription, resolveTypeDocs } = input;
19103
- if (Node12.isTypeLiteral(valueNode)) {
19308
+ if (Node13.isTypeLiteral(valueNode)) {
19104
19309
  for (const specMember of valueNode.getMembers()) {
19105
- if (!Node12.isPropertySignature(specMember)) {
19310
+ if (!Node13.isPropertySignature(specMember)) {
19106
19311
  continue;
19107
19312
  }
19108
19313
  const specifier = specMember.getName();
@@ -19144,7 +19349,7 @@ function collectVerbEntries(input) {
19144
19349
  });
19145
19350
  }
19146
19351
  function readTupleParamsResult(node) {
19147
- if (!Node12.isTupleTypeNode(node)) {
19352
+ if (!Node13.isTupleTypeNode(node)) {
19148
19353
  return void 0;
19149
19354
  }
19150
19355
  const elements = node.getElements();
@@ -19163,7 +19368,7 @@ function readBareParams(node) {
19163
19368
  return { params, result: void 0 };
19164
19369
  }
19165
19370
  function typeNodeName(node) {
19166
- if (Node12.isTypeReference(node)) {
19371
+ if (Node13.isTypeReference(node)) {
19167
19372
  return node.getTypeName().getText();
19168
19373
  }
19169
19374
  const text = node.getText().trim();
@@ -20002,7 +20207,7 @@ async function collectApiFiles2(rootAbs) {
20002
20207
  // packages/dbx-components-mcp/src/tools/model-api-validate-app/extract-handlers.ts
20003
20208
  import { readFile as readFile8 } from "node:fs/promises";
20004
20209
  import { join as join8 } from "node:path";
20005
- import { Node as Node13, Project as Project8 } from "ts-morph";
20210
+ import { Node as Node14, Project as Project8 } from "ts-morph";
20006
20211
  var HANDLER_MAP_REL = "src/app/function/model/crud.functions.ts";
20007
20212
  var VERB_TOKENS = [
20008
20213
  { token: "Create", verb: "create" },
@@ -20030,7 +20235,7 @@ async function extractHandlerEntries(apiAbs, apiDir) {
20030
20235
  const verb = matchVerbFromConstName(name);
20031
20236
  if (!verb) continue;
20032
20237
  const initializer = decl.getInitializer();
20033
- if (!initializer || !Node13.isObjectLiteralExpression(initializer)) continue;
20238
+ if (!initializer || !Node14.isObjectLiteralExpression(initializer)) continue;
20034
20239
  verbsFound.push(verb);
20035
20240
  collectVerbMap({ verb, mapLiteral: initializer, sourceFileRel, entries });
20036
20241
  }
@@ -20048,7 +20253,7 @@ function matchVerbFromConstName(name) {
20048
20253
  function collectVerbMap(input) {
20049
20254
  const { verb, mapLiteral, sourceFileRel, entries } = input;
20050
20255
  for (const prop of mapLiteral.getProperties()) {
20051
- if (!Node13.isPropertyAssignment(prop)) continue;
20256
+ if (!Node14.isPropertyAssignment(prop)) continue;
20052
20257
  const model = prop.getName();
20053
20258
  const value = prop.getInitializer();
20054
20259
  if (!value) continue;
@@ -20067,25 +20272,25 @@ function collectVerbMap(input) {
20067
20272
  }
20068
20273
  }
20069
20274
  function readSpecifierHandler(node) {
20070
- if (!Node13.isCallExpression(node)) return void 0;
20275
+ if (!Node14.isCallExpression(node)) return void 0;
20071
20276
  const expr = node.getExpression();
20072
20277
  if (!expr.getText().endsWith("onCallSpecifierHandler")) return void 0;
20073
20278
  const args = node.getArguments();
20074
20279
  if (args.length === 0) return void 0;
20075
20280
  const firstArg = args[0];
20076
- if (!Node13.isObjectLiteralExpression(firstArg)) return void 0;
20281
+ if (!Node14.isObjectLiteralExpression(firstArg)) return void 0;
20077
20282
  const out = /* @__PURE__ */ new Map();
20078
20283
  for (const prop of firstArg.getProperties()) {
20079
- if (!Node13.isPropertyAssignment(prop) && !Node13.isShorthandPropertyAssignment(prop)) continue;
20284
+ if (!Node14.isPropertyAssignment(prop) && !Node14.isShorthandPropertyAssignment(prop)) continue;
20080
20285
  const specifier = prop.getName();
20081
- const handlerName = readBareHandlerName(Node13.isPropertyAssignment(prop) ? prop.getInitializerOrThrow() : prop) ?? "(unresolved)";
20286
+ const handlerName = readBareHandlerName(Node14.isPropertyAssignment(prop) ? prop.getInitializerOrThrow() : prop) ?? "(unresolved)";
20082
20287
  out.set(specifier, handlerName);
20083
20288
  }
20084
20289
  return out;
20085
20290
  }
20086
20291
  function readBareHandlerName(node) {
20087
- if (Node13.isIdentifier(node)) return node.getText();
20088
- if (Node13.isShorthandPropertyAssignment(node)) return node.getName();
20292
+ if (Node14.isIdentifier(node)) return node.getText();
20293
+ if (Node14.isShorthandPropertyAssignment(node)) return node.getName();
20089
20294
  const text = node.getText().split(/\s|\(/)[0];
20090
20295
  if (/^[A-Za-z_]\w*$/.test(text)) return text;
20091
20296
  return void 0;
@@ -21287,7 +21492,7 @@ function paramsHasFixtureDependencies(params) {
21287
21492
  }
21288
21493
 
21289
21494
  // packages/dbx-components-mcp/src/tools/model-fixture-shared/extract.ts
21290
- import { Node as Node14, Project as Project9, SyntaxKind as SyntaxKind7 } from "ts-morph";
21495
+ import { Node as Node15, Project as Project9, SyntaxKind as SyntaxKind7 } from "ts-morph";
21291
21496
 
21292
21497
  // packages/dbx-components-mcp/src/tools/model-fixture-shared/framework-fixtures.ts
21293
21498
  var KNOWN_NON_MODEL_FIXTURE_FAMILIES = [
@@ -21399,7 +21604,7 @@ function extendsByName(cls, baseName) {
21399
21604
  const extendsClause = cls.getExtends();
21400
21605
  if (!extendsClause) return false;
21401
21606
  const expr = extendsClause.getExpression();
21402
- if (Node14.isIdentifier(expr)) {
21607
+ if (Node15.isIdentifier(expr)) {
21403
21608
  return expr.getText() === baseName;
21404
21609
  }
21405
21610
  return extendsClause.getText().startsWith(baseName);
@@ -21527,14 +21732,14 @@ function readContextFactory(decl) {
21527
21732
  const initializer = decl.getInitializer();
21528
21733
  if (!initializer) return void 0;
21529
21734
  let bodyExpr;
21530
- if (Node14.isArrowFunction(initializer) || Node14.isFunctionExpression(initializer)) {
21735
+ if (Node15.isArrowFunction(initializer) || Node15.isFunctionExpression(initializer)) {
21531
21736
  bodyExpr = readSingleReturnExpression(initializer);
21532
21737
  } else {
21533
21738
  bodyExpr = initializer;
21534
21739
  }
21535
- if (!bodyExpr || !Node14.isCallExpression(bodyExpr)) return void 0;
21740
+ if (!bodyExpr || !Node15.isCallExpression(bodyExpr)) return void 0;
21536
21741
  const callee = bodyExpr.getExpression();
21537
- if (!Node14.isIdentifier(callee)) return void 0;
21742
+ if (!Node15.isIdentifier(callee)) return void 0;
21538
21743
  const calleeName = callee.getText();
21539
21744
  let family;
21540
21745
  if (calleeName !== MODEL_FACTORY_NAME) {
@@ -21549,9 +21754,9 @@ function readContextFactory(decl) {
21549
21754
  let parentFixtureFieldFromGetCollection;
21550
21755
  if (args.length > 0) {
21551
21756
  const first = args[0];
21552
- if (Node14.isObjectLiteralExpression(first)) {
21757
+ if (Node15.isObjectLiteralExpression(first)) {
21553
21758
  const getCollection = first.getProperty("getCollection");
21554
- if (getCollection && Node14.isPropertyAssignment(getCollection)) {
21759
+ if (getCollection && Node15.isPropertyAssignment(getCollection)) {
21555
21760
  const fnInit = getCollection.getInitializer();
21556
21761
  const arity = readArrowParameterCount(fnInit);
21557
21762
  if (arity >= 2) {
@@ -21602,7 +21807,7 @@ function familyFromExtends(cls) {
21602
21807
  if (!ext) return void 0;
21603
21808
  const expr = ext.getExpression();
21604
21809
  let baseName;
21605
- if (Node14.isIdentifier(expr)) {
21810
+ if (Node15.isIdentifier(expr)) {
21606
21811
  baseName = expr.getText();
21607
21812
  } else {
21608
21813
  const text = ext.getText();
@@ -21615,9 +21820,9 @@ function familyFromExtends(cls) {
21615
21820
  function readSingleReturnExpression(fn) {
21616
21821
  const body = fn.getBody();
21617
21822
  if (!body) return void 0;
21618
- if (Node14.isBlock(body)) {
21823
+ if (Node15.isBlock(body)) {
21619
21824
  for (const stmt of body.getStatements()) {
21620
- if (Node14.isReturnStatement(stmt)) {
21825
+ if (Node15.isReturnStatement(stmt)) {
21621
21826
  return stmt.getExpression();
21622
21827
  }
21623
21828
  }
@@ -21627,19 +21832,19 @@ function readSingleReturnExpression(fn) {
21627
21832
  }
21628
21833
  function readArrowParameterCount(fn) {
21629
21834
  if (!fn) return 0;
21630
- if (Node14.isArrowFunction(fn) || Node14.isFunctionExpression(fn) || Node14.isFunctionDeclaration(fn) || Node14.isMethodDeclaration(fn)) {
21835
+ if (Node15.isArrowFunction(fn) || Node15.isFunctionExpression(fn) || Node15.isFunctionDeclaration(fn) || Node15.isMethodDeclaration(fn)) {
21631
21836
  return fn.getParameters().length;
21632
21837
  }
21633
21838
  return 0;
21634
21839
  }
21635
21840
  function readParamsAccessFieldName(fn) {
21636
21841
  if (!fn) return void 0;
21637
- if (!Node14.isArrowFunction(fn) && !Node14.isFunctionExpression(fn)) return void 0;
21842
+ if (!Node15.isArrowFunction(fn) && !Node15.isFunctionExpression(fn)) return void 0;
21638
21843
  const body = fn.getBody();
21639
21844
  if (!body) return void 0;
21640
21845
  for (const access2 of body.getDescendantsOfKind(SyntaxKind7.PropertyAccessExpression)) {
21641
21846
  const expr = access2.getExpression();
21642
- if (Node14.isIdentifier(expr) && expr.getText() === "params") {
21847
+ if (Node15.isIdentifier(expr) && expr.getText() === "params") {
21643
21848
  return access2.getName();
21644
21849
  }
21645
21850
  }
@@ -21680,9 +21885,9 @@ function collectSingletonsByFactory(sourceFile) {
21680
21885
  for (const stmt of sourceFile.getVariableStatements()) {
21681
21886
  for (const decl of stmt.getDeclarations()) {
21682
21887
  const init = decl.getInitializer();
21683
- if (!init || !Node14.isCallExpression(init)) continue;
21888
+ if (!init || !Node15.isCallExpression(init)) continue;
21684
21889
  const callee = init.getExpression();
21685
- if (!Node14.isIdentifier(callee)) continue;
21890
+ if (!Node15.isIdentifier(callee)) continue;
21686
21891
  out.set(callee.getText(), decl.getName());
21687
21892
  }
21688
21893
  }
@@ -22930,7 +23135,7 @@ import { resolve as resolve32 } from "node:path";
22930
23135
  import { type as type47 } from "arktype";
22931
23136
 
22932
23137
  // packages/dbx-components-mcp/src/tools/model-test-shared/extract.ts
22933
- import { Node as Node15, Project as Project11, SyntaxKind as SyntaxKind8 } from "ts-morph";
23138
+ import { Node as Node16, Project as Project11, SyntaxKind as SyntaxKind8 } from "ts-morph";
22934
23139
  var SPEC_FILE_VIRTUAL_PATH = "__spec__/spec.ts";
22935
23140
  var FIXTURE_CONTEXT_SUFFIX = "Context";
22936
23141
  var FIXTURE_FACTORY_SUFFIX = "ContextFactory";
@@ -22951,9 +23156,9 @@ function extractSpecTreeFromText(input) {
22951
23156
  const counts = { describe: 0, it: 0, fixture: 0 };
22952
23157
  const rootChildren = [];
22953
23158
  for (const stmt of sourceFile.getStatements()) {
22954
- if (!Node15.isExpressionStatement(stmt)) continue;
23159
+ if (!Node16.isExpressionStatement(stmt)) continue;
22955
23160
  const expr = stmt.getExpression();
22956
- if (!Node15.isCallExpression(expr)) continue;
23161
+ if (!Node16.isCallExpression(expr)) continue;
22957
23162
  const node = walkCall(expr, { prefix, knownFixtureNames, helperNames, counts });
22958
23163
  if (node !== void 0) {
22959
23164
  rootChildren.push(node);
@@ -23119,7 +23324,7 @@ function fixtureNode(input) {
23119
23324
  const { call, calleeName, ctx, line, endLine } = input;
23120
23325
  const args = call.getArguments();
23121
23326
  const argsObject = args[0];
23122
- const parentVars = Node15.isObjectLiteralExpression(argsObject) ? readParentVars(argsObject) : [];
23327
+ const parentVars = Node16.isObjectLiteralExpression(argsObject) ? readParentVars(argsObject) : [];
23123
23328
  const callback = findCallback(call);
23124
23329
  const varName = callback === void 0 ? void 0 : readCallbackVarName(callback);
23125
23330
  const model = stripFixturePrefix(calleeName, ctx.prefix);
@@ -23157,11 +23362,11 @@ function stripFixturePrefix(name, prefix) {
23157
23362
  }
23158
23363
  function readTitle(arg) {
23159
23364
  if (arg === void 0) return { title: void 0, titleIsTemplate: false };
23160
- if (Node15.isStringLiteral(arg) || Node15.isNoSubstitutionTemplateLiteral(arg)) {
23365
+ if (Node16.isStringLiteral(arg) || Node16.isNoSubstitutionTemplateLiteral(arg)) {
23161
23366
  const result2 = { title: arg.getLiteralText(), titleIsTemplate: false };
23162
23367
  return result2;
23163
23368
  }
23164
- if (Node15.isTemplateExpression(arg)) {
23369
+ if (Node16.isTemplateExpression(arg)) {
23165
23370
  const result2 = { title: arg.getText(), titleIsTemplate: true };
23166
23371
  return result2;
23167
23372
  }
@@ -23172,7 +23377,7 @@ function findCallback(call) {
23172
23377
  const args = call.getArguments();
23173
23378
  for (let i = args.length - 1; i >= 0; i--) {
23174
23379
  const a = args[i];
23175
- if (Node15.isArrowFunction(a) || Node15.isFunctionExpression(a)) {
23380
+ if (Node16.isArrowFunction(a) || Node16.isFunctionExpression(a)) {
23176
23381
  return a;
23177
23382
  }
23178
23383
  }
@@ -23183,7 +23388,7 @@ function readCallbackVarName(callback) {
23183
23388
  if (params.length === 0) return void 0;
23184
23389
  const first = params[0];
23185
23390
  const nameNode = first.getNameNode();
23186
- if (Node15.isIdentifier(nameNode)) {
23391
+ if (Node16.isIdentifier(nameNode)) {
23187
23392
  return nameNode.getText();
23188
23393
  }
23189
23394
  return void 0;
@@ -23191,13 +23396,13 @@ function readCallbackVarName(callback) {
23191
23396
  function readParentVars(obj) {
23192
23397
  const out = [];
23193
23398
  for (const prop of obj.getProperties()) {
23194
- if (Node15.isShorthandPropertyAssignment(prop)) {
23399
+ if (Node16.isShorthandPropertyAssignment(prop)) {
23195
23400
  out.push(prop.getName());
23196
23401
  continue;
23197
23402
  }
23198
- if (Node15.isPropertyAssignment(prop)) {
23403
+ if (Node16.isPropertyAssignment(prop)) {
23199
23404
  const init = prop.getInitializer();
23200
- if (init !== void 0 && Node15.isIdentifier(init)) {
23405
+ if (init !== void 0 && Node16.isIdentifier(init)) {
23201
23406
  out.push(init.getText());
23202
23407
  }
23203
23408
  }
@@ -23206,10 +23411,10 @@ function readParentVars(obj) {
23206
23411
  }
23207
23412
  function walkCallbackBody(callback, ctx) {
23208
23413
  const body = callback.getBody();
23209
- if (Node15.isBlock(body)) {
23414
+ if (Node16.isBlock(body)) {
23210
23415
  return walkBlock(body, ctx);
23211
23416
  }
23212
- if (Node15.isCallExpression(body)) {
23417
+ if (Node16.isCallExpression(body)) {
23213
23418
  const child = walkCall(body, ctx);
23214
23419
  return child === void 0 ? [] : [child];
23215
23420
  }
@@ -23218,9 +23423,9 @@ function walkCallbackBody(callback, ctx) {
23218
23423
  function walkBlock(block, ctx) {
23219
23424
  const children = [];
23220
23425
  for (const stmt of block.getStatements()) {
23221
- if (!Node15.isExpressionStatement(stmt)) continue;
23426
+ if (!Node16.isExpressionStatement(stmt)) continue;
23222
23427
  const expr = stmt.getExpression();
23223
- if (!Node15.isCallExpression(expr)) continue;
23428
+ if (!Node16.isCallExpression(expr)) continue;
23224
23429
  const child = walkCall(expr, ctx);
23225
23430
  if (child !== void 0) {
23226
23431
  children.push(child);
@@ -23230,7 +23435,7 @@ function walkBlock(block, ctx) {
23230
23435
  }
23231
23436
  function getCalleeName(call) {
23232
23437
  const expr = call.getExpression();
23233
- if (Node15.isIdentifier(expr)) return expr.getText();
23438
+ if (Node16.isIdentifier(expr)) return expr.getText();
23234
23439
  return void 0;
23235
23440
  }
23236
23441
  function collectHelpers(sourceFile) {
@@ -23246,7 +23451,7 @@ function collectHelpers(sourceFile) {
23246
23451
  for (const decl of v.getDeclarations()) {
23247
23452
  const init = decl.getInitializer();
23248
23453
  if (init === void 0) continue;
23249
- if (!Node15.isArrowFunction(init) && !Node15.isFunctionExpression(init)) continue;
23454
+ if (!Node16.isArrowFunction(init) && !Node16.isFunctionExpression(init)) continue;
23250
23455
  const usage = scanForDescribeOrIt(init);
23251
23456
  if (!usage.emitsDescribe && !usage.emitsIt) continue;
23252
23457
  out.push({ name: decl.getName(), line: decl.getStartLineNumber(), endLine: decl.getEndLineNumber(), emitsDescribe: usage.emitsDescribe, emitsIt: usage.emitsIt });
@@ -23260,7 +23465,7 @@ function scanForDescribeOrIt(node) {
23260
23465
  if (descendant.getKind() !== SyntaxKind8.CallExpression) return;
23261
23466
  const call = descendant;
23262
23467
  const expr = call.getExpression();
23263
- if (!Node15.isIdentifier(expr)) return;
23468
+ if (!Node16.isIdentifier(expr)) return;
23264
23469
  const name = expr.getText();
23265
23470
  if (DESCRIBE_NAMES.has(name)) usage.emitsDescribe = true;
23266
23471
  if (isItName(name)) usage.emitsIt = true;
@@ -24033,10 +24238,10 @@ var modelHierarchyTool = {
24033
24238
  };
24034
24239
 
24035
24240
  // packages/dbx-components-mcp/src/tools/storagefile-m-validate-app/extract.ts
24036
- import { Node as Node17, SyntaxKind as SyntaxKind10 } from "ts-morph";
24241
+ import { Node as Node18, SyntaxKind as SyntaxKind10 } from "ts-morph";
24037
24242
 
24038
24243
  // packages/dbx-components-mcp/src/tools/_validate/ast.ts
24039
- import { Node as Node16, Project as Project12, SyntaxKind as SyntaxKind9 } from "ts-morph";
24244
+ import { Node as Node17, Project as Project12, SyntaxKind as SyntaxKind9 } from "ts-morph";
24040
24245
  var COMPONENT_VIRTUAL_PREFIX = "__component__/";
24041
24246
  var API_VIRTUAL_PREFIX = "__api__/";
24042
24247
  // @__NO_SIDE_EFFECTS__
@@ -24061,28 +24266,28 @@ function componentRelPath(sourceFile) {
24061
24266
  }
24062
24267
  function unwrapAsExpressions(node) {
24063
24268
  let current = node;
24064
- while (current && Node16.isAsExpression(current)) {
24269
+ while (current && Node17.isAsExpression(current)) {
24065
24270
  current = current.getExpression();
24066
24271
  }
24067
24272
  return current;
24068
24273
  }
24069
24274
  function asObjectLiteral(node) {
24070
24275
  const inner = unwrapAsExpressions(node);
24071
- if (inner && Node16.isObjectLiteralExpression(inner)) {
24276
+ if (inner && Node17.isObjectLiteralExpression(inner)) {
24072
24277
  return inner;
24073
24278
  }
24074
24279
  return void 0;
24075
24280
  }
24076
24281
  function asArrayLiteral(node) {
24077
24282
  const inner = unwrapAsExpressions(node);
24078
- if (inner && Node16.isArrayLiteralExpression(inner)) {
24283
+ if (inner && Node17.isArrayLiteralExpression(inner)) {
24079
24284
  return inner;
24080
24285
  }
24081
24286
  return void 0;
24082
24287
  }
24083
24288
  function readStringLiteralInitializer(decl) {
24084
24289
  const initializer = unwrapAsExpressions(decl.getInitializer());
24085
- if (initializer && Node16.isStringLiteral(initializer)) {
24290
+ if (initializer && Node17.isStringLiteral(initializer)) {
24086
24291
  return initializer.getLiteralText();
24087
24292
  }
24088
24293
  return void 0;
@@ -24094,37 +24299,37 @@ function typeAnnotationText(node) {
24094
24299
  function getPropertyInitializer(obj, name) {
24095
24300
  const prop = obj.getProperty(name);
24096
24301
  if (!prop) return void 0;
24097
- if (Node16.isPropertyAssignment(prop)) {
24302
+ if (Node17.isPropertyAssignment(prop)) {
24098
24303
  return prop.getInitializer();
24099
24304
  }
24100
- if (Node16.isShorthandPropertyAssignment(prop)) {
24305
+ if (Node17.isShorthandPropertyAssignment(prop)) {
24101
24306
  return prop.getNameNode();
24102
24307
  }
24103
24308
  return void 0;
24104
24309
  }
24105
24310
  function readStringProperty2(obj, name) {
24106
24311
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
24107
- if (init && Node16.isStringLiteral(init)) {
24312
+ if (init && Node17.isStringLiteral(init)) {
24108
24313
  return init.getLiteralText();
24109
24314
  }
24110
24315
  return void 0;
24111
24316
  }
24112
24317
  function readIdentifierProperty(obj, name) {
24113
24318
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
24114
- if (init && Node16.isIdentifier(init)) {
24319
+ if (init && Node17.isIdentifier(init)) {
24115
24320
  return init.getText();
24116
24321
  }
24117
24322
  return void 0;
24118
24323
  }
24119
24324
  function findReturnExpression(fn) {
24120
- if (!Node16.isArrowFunction(fn) && !Node16.isFunctionDeclaration(fn) && !Node16.isFunctionExpression(fn)) {
24325
+ if (!Node17.isArrowFunction(fn) && !Node17.isFunctionDeclaration(fn) && !Node17.isFunctionExpression(fn)) {
24121
24326
  return void 0;
24122
24327
  }
24123
24328
  const body = fn.getBody();
24124
24329
  if (!body) return void 0;
24125
- if (Node16.isBlock(body)) {
24330
+ if (Node17.isBlock(body)) {
24126
24331
  for (const stmt of body.getStatements()) {
24127
- if (Node16.isReturnStatement(stmt)) {
24332
+ if (Node17.isReturnStatement(stmt)) {
24128
24333
  return stmt.getExpression();
24129
24334
  }
24130
24335
  }
@@ -24144,7 +24349,7 @@ function findLocalVariable(sf, name) {
24144
24349
  return void 0;
24145
24350
  }
24146
24351
  function collectTypeofReferences(node, out) {
24147
- if (Node16.isTypeQuery(node)) {
24352
+ if (Node17.isTypeQuery(node)) {
24148
24353
  out.push(node.getExprName().getText());
24149
24354
  return;
24150
24355
  }
@@ -24346,7 +24551,7 @@ function buildApiFunctionIndex(sources) {
24346
24551
  for (const decl of stmt.getDeclarations()) {
24347
24552
  const initializer = unwrapAsExpressions(decl.getInitializer());
24348
24553
  if (!initializer) continue;
24349
- if (Node17.isArrowFunction(initializer) || Node17.isFunctionExpression(initializer)) {
24554
+ if (Node18.isArrowFunction(initializer) || Node18.isFunctionExpression(initializer)) {
24350
24555
  map.set(decl.getName(), { node: initializer, sourceFile: sf });
24351
24556
  }
24352
24557
  }
@@ -24359,34 +24564,34 @@ function collectInitializerBindingsFromValue(options) {
24359
24564
  const { node, sf, index, resolved, unresolved, visited } = options;
24360
24565
  const inner = unwrapAsExpressions(node);
24361
24566
  if (!inner) return false;
24362
- if (Node17.isArrayLiteralExpression(inner)) {
24567
+ if (Node18.isArrayLiteralExpression(inner)) {
24363
24568
  for (const el of inner.getElements()) {
24364
- if (Node17.isSpreadElement(el)) {
24569
+ if (Node18.isSpreadElement(el)) {
24365
24570
  const spreadInner = el.getExpression();
24366
- if (Node17.isIdentifier(spreadInner)) {
24571
+ if (Node18.isIdentifier(spreadInner)) {
24367
24572
  collectInitializerBindingsFromIdentifier({ name: spreadInner.getText(), sf, index, resolved, unresolved, visited });
24368
- } else if (Node17.isCallExpression(spreadInner)) {
24573
+ } else if (Node18.isCallExpression(spreadInner)) {
24369
24574
  const callee = spreadInner.getExpression();
24370
- if (Node17.isIdentifier(callee)) {
24575
+ if (Node18.isIdentifier(callee)) {
24371
24576
  collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
24372
24577
  }
24373
24578
  }
24374
24579
  continue;
24375
24580
  }
24376
24581
  const elementInner = unwrapAsExpressions(el);
24377
- if (elementInner && Node17.isIdentifier(elementInner)) {
24582
+ if (elementInner && Node18.isIdentifier(elementInner)) {
24378
24583
  resolved.push(elementInner.getText());
24379
24584
  }
24380
24585
  }
24381
24586
  return true;
24382
24587
  }
24383
- if (Node17.isCallExpression(inner)) {
24588
+ if (Node18.isCallExpression(inner)) {
24384
24589
  const callee = inner.getExpression();
24385
- if (Node17.isIdentifier(callee)) {
24590
+ if (Node18.isIdentifier(callee)) {
24386
24591
  return collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
24387
24592
  }
24388
24593
  }
24389
- if (Node17.isIdentifier(inner)) {
24594
+ if (Node18.isIdentifier(inner)) {
24390
24595
  return collectInitializerBindingsFromIdentifier({ name: inner.getText(), sf, index, resolved, unresolved, visited });
24391
24596
  }
24392
24597
  return false;
@@ -24425,15 +24630,15 @@ function collectUploadInitializerArray(options) {
24425
24630
  const { initializerArr, sf, index, direct, spreads, resolved, unresolved } = options;
24426
24631
  const visited = /* @__PURE__ */ new Set();
24427
24632
  for (const el of initializerArr.getElements()) {
24428
- if (Node17.isSpreadElement(el)) {
24633
+ if (Node18.isSpreadElement(el)) {
24429
24634
  const inner2 = el.getExpression();
24430
- if (Node17.isIdentifier(inner2)) {
24635
+ if (Node18.isIdentifier(inner2)) {
24431
24636
  const name = inner2.getText();
24432
24637
  spreads.push(name);
24433
24638
  collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
24434
- } else if (Node17.isCallExpression(inner2)) {
24639
+ } else if (Node18.isCallExpression(inner2)) {
24435
24640
  const callee = inner2.getExpression();
24436
- if (Node17.isIdentifier(callee)) {
24641
+ if (Node18.isIdentifier(callee)) {
24437
24642
  const name = callee.getText();
24438
24643
  spreads.push(name);
24439
24644
  collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
@@ -24442,7 +24647,7 @@ function collectUploadInitializerArray(options) {
24442
24647
  continue;
24443
24648
  }
24444
24649
  const inner = unwrapAsExpressions(el);
24445
- if (inner && Node17.isIdentifier(inner)) {
24650
+ if (inner && Node18.isIdentifier(inner)) {
24446
24651
  const name = inner.getText();
24447
24652
  direct.push(name);
24448
24653
  resolved.push(name);
@@ -24455,7 +24660,7 @@ function extractUploadServiceCalls(sources, index) {
24455
24660
  const rel = apiRelPath(sf);
24456
24661
  for (const call of sf.getDescendantsOfKind(SyntaxKind10.CallExpression)) {
24457
24662
  const expr = call.getExpression();
24458
- if (!Node17.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
24663
+ if (!Node18.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
24459
24664
  const args = call.getArguments();
24460
24665
  const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
24461
24666
  if (!first) continue;
@@ -24483,12 +24688,12 @@ function extractUploadServiceCalls(sources, index) {
24483
24688
  function resolveObjectArg(node, sf) {
24484
24689
  const inner = unwrapAsExpressions(node);
24485
24690
  if (!inner) return void 0;
24486
- if (Node17.isObjectLiteralExpression(inner)) return inner;
24487
- if (Node17.isIdentifier(inner)) {
24691
+ if (Node18.isObjectLiteralExpression(inner)) return inner;
24692
+ if (Node18.isIdentifier(inner)) {
24488
24693
  const declNode = findLocalVariable(sf, inner.getText());
24489
24694
  if (declNode) {
24490
24695
  const declInit = unwrapAsExpressions(declNode.getInitializer());
24491
- if (declInit && Node17.isObjectLiteralExpression(declInit)) {
24696
+ if (declInit && Node18.isObjectLiteralExpression(declInit)) {
24492
24697
  return declInit;
24493
24698
  }
24494
24699
  }
@@ -24498,12 +24703,12 @@ function resolveObjectArg(node, sf) {
24498
24703
  function resolveArrayFromProperty(obj, name, sf) {
24499
24704
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
24500
24705
  if (!init) return void 0;
24501
- if (Node17.isArrayLiteralExpression(init)) return init;
24502
- if (Node17.isIdentifier(init)) {
24706
+ if (Node18.isArrayLiteralExpression(init)) return init;
24707
+ if (Node18.isIdentifier(init)) {
24503
24708
  const declNode = findLocalVariable(sf, init.getText());
24504
24709
  if (declNode) {
24505
24710
  const declInit = unwrapAsExpressions(declNode.getInitializer());
24506
- if (declInit && Node17.isArrayLiteralExpression(declInit)) {
24711
+ if (declInit && Node18.isArrayLiteralExpression(declInit)) {
24507
24712
  return declInit;
24508
24713
  }
24509
24714
  }
@@ -24514,11 +24719,11 @@ function enclosingFactoryName(node) {
24514
24719
  let current = node.getParent();
24515
24720
  let result;
24516
24721
  while (current) {
24517
- if (Node17.isFunctionDeclaration(current)) {
24722
+ if (Node18.isFunctionDeclaration(current)) {
24518
24723
  result = current.getName() ?? void 0;
24519
24724
  break;
24520
24725
  }
24521
- if (Node17.isVariableDeclaration(current)) {
24726
+ if (Node18.isVariableDeclaration(current)) {
24522
24727
  result = current.getName();
24523
24728
  break;
24524
24729
  }
@@ -24572,10 +24777,10 @@ function extractProcessingConfigFromDecl(decl, rel) {
24572
24777
  function readFlowSubtasks(obj) {
24573
24778
  const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
24574
24779
  const subtasks = [];
24575
- if (flowInit && Node17.isArrayLiteralExpression(flowInit)) {
24780
+ if (flowInit && Node18.isArrayLiteralExpression(flowInit)) {
24576
24781
  for (const el of flowInit.getElements()) {
24577
24782
  const inner = unwrapAsExpressions(el);
24578
- if (inner && Node17.isObjectLiteralExpression(inner)) {
24783
+ if (inner && Node18.isObjectLiteralExpression(inner)) {
24579
24784
  const subtask = readIdentifierProperty(inner, "subtask");
24580
24785
  if (subtask) subtasks.push(subtask);
24581
24786
  }
@@ -24589,7 +24794,7 @@ function extractProcessingHandlerCalls(sources) {
24589
24794
  const rel = apiRelPath(sf);
24590
24795
  for (const call of sf.getDescendantsOfKind(SyntaxKind10.CallExpression)) {
24591
24796
  const expr = call.getExpression();
24592
- if (!Node17.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
24797
+ if (!Node18.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
24593
24798
  const args = call.getArguments();
24594
24799
  const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
24595
24800
  if (!first) continue;
@@ -24610,7 +24815,7 @@ function extractProcessingHandlerCalls(sources) {
24610
24815
  }
24611
24816
  function collectProcessorArrayElements(processorsArr, direct, spreads) {
24612
24817
  for (const el of processorsArr.getElements()) {
24613
- if (Node17.isSpreadElement(el)) {
24818
+ if (Node18.isSpreadElement(el)) {
24614
24819
  addProcessorIdentifierName(el.getExpression(), spreads);
24615
24820
  continue;
24616
24821
  }
@@ -24622,13 +24827,13 @@ function collectProcessorArrayElements(processorsArr, direct, spreads) {
24622
24827
  }
24623
24828
  function addProcessorIdentifierName(node, bucket) {
24624
24829
  if (!node) return;
24625
- if (Node17.isIdentifier(node)) {
24830
+ if (Node18.isIdentifier(node)) {
24626
24831
  bucket.push(node.getText());
24627
24832
  return;
24628
24833
  }
24629
- if (Node17.isCallExpression(node)) {
24834
+ if (Node18.isCallExpression(node)) {
24630
24835
  const callee = node.getExpression();
24631
- if (Node17.isIdentifier(callee)) {
24836
+ if (Node18.isIdentifier(callee)) {
24632
24837
  bucket.push(callee.getText());
24633
24838
  }
24634
24839
  }
@@ -25620,7 +25825,7 @@ var storageFileMValidateFolderTool = createTwoSideValidateTool({
25620
25825
  });
25621
25826
 
25622
25827
  // packages/dbx-components-mcp/src/tools/notification-m-validate-app/extract.ts
25623
- import { Node as Node18, SyntaxKind as SyntaxKind11 } from "ts-morph";
25828
+ import { Node as Node19, SyntaxKind as SyntaxKind11 } from "ts-morph";
25624
25829
  var NOTIF_TEMPLATE_TYPE = "NotificationTemplateType";
25625
25830
  var NOTIF_TEMPLATE_TYPE_INFO = "NotificationTemplateTypeInfo";
25626
25831
  var NOTIF_TEMPLATE_TYPE_INFO_ARRAY = "NotificationTemplateTypeInfo[]";
@@ -25741,7 +25946,7 @@ function extractTemplateInfoAggregates(sources) {
25741
25946
  const ids = [];
25742
25947
  for (const el of arr.getElements()) {
25743
25948
  const inner = unwrapAsExpressions(el);
25744
- if (inner && Node18.isIdentifier(inner)) {
25949
+ if (inner && Node19.isIdentifier(inner)) {
25745
25950
  ids.push(inner.getText());
25746
25951
  }
25747
25952
  }
@@ -25787,7 +25992,7 @@ function extractTaskAllTypesAggregates(sources) {
25787
25992
  const ids = [];
25788
25993
  for (const el of arr.getElements()) {
25789
25994
  const inner = unwrapAsExpressions(el);
25790
- if (inner && Node18.isIdentifier(inner)) {
25995
+ if (inner && Node19.isIdentifier(inner)) {
25791
25996
  ids.push(inner.getText());
25792
25997
  }
25793
25998
  }
@@ -25815,14 +26020,14 @@ function extractTaskCheckpointAliases(sources) {
25815
26020
  return out;
25816
26021
  }
25817
26022
  function collectStringLiterals(node, out) {
25818
- if (Node18.isLiteralTypeNode(node)) {
26023
+ if (Node19.isLiteralTypeNode(node)) {
25819
26024
  const lit = node.getLiteral();
25820
- if (Node18.isStringLiteral(lit)) {
26025
+ if (Node19.isStringLiteral(lit)) {
25821
26026
  out.push(lit.getLiteralText());
25822
26027
  }
25823
26028
  return;
25824
26029
  }
25825
- if (Node18.isUnionTypeNode(node)) {
26030
+ if (Node19.isUnionTypeNode(node)) {
25826
26031
  for (const child of node.getTypeNodes()) {
25827
26032
  collectStringLiterals(child, out);
25828
26033
  }
@@ -25876,7 +26081,7 @@ function extractTemplateInfoRecord(sources, index) {
25876
26081
  }
25877
26082
  function tryReadTemplateInfoRecord(decl, rel, index) {
25878
26083
  const initializer = unwrapAsExpressions(decl.getInitializer());
25879
- if (!initializer || !Node18.isCallExpression(initializer)) return void 0;
26084
+ if (!initializer || !Node19.isCallExpression(initializer)) return void 0;
25880
26085
  if (initializer.getExpression().getText() !== TEMPLATE_INFO_RECORD_FACTORY) return void 0;
25881
26086
  const args = initializer.getArguments();
25882
26087
  const arr = args[0] ? asArrayLiteral(args[0]) : void 0;
@@ -25897,15 +26102,15 @@ function tryReadTemplateInfoRecord(decl, rel, index) {
25897
26102
  }
25898
26103
  function classifyInfoRecordArrayElements(arr, direct, spreads) {
25899
26104
  for (const el of arr.getElements()) {
25900
- if (Node18.isSpreadElement(el)) {
26105
+ if (Node19.isSpreadElement(el)) {
25901
26106
  const inner2 = el.getExpression();
25902
- if (Node18.isIdentifier(inner2)) {
26107
+ if (Node19.isIdentifier(inner2)) {
25903
26108
  spreads.push(inner2.getText());
25904
26109
  }
25905
26110
  continue;
25906
26111
  }
25907
26112
  const inner = unwrapAsExpressions(el);
25908
- if (inner && Node18.isIdentifier(inner)) {
26113
+ if (inner && Node19.isIdentifier(inner)) {
25909
26114
  direct.push(inner.getText());
25910
26115
  }
25911
26116
  }
@@ -25932,7 +26137,7 @@ function extractTemplateInfoRecordWiring(sources) {
25932
26137
  const first = args[0];
25933
26138
  if (!first) continue;
25934
26139
  const inner = unwrapAsExpressions(first);
25935
- if (!inner || !Node18.isIdentifier(inner)) continue;
26140
+ if (!inner || !Node19.isIdentifier(inner)) continue;
25936
26141
  const result = {
25937
26142
  recordIdentifier: inner.getText(),
25938
26143
  sourceFile: rel
@@ -25970,7 +26175,7 @@ function buildApiFunctionIndex2(sources) {
25970
26175
  for (const decl of stmt.getDeclarations()) {
25971
26176
  const initializer = unwrapAsExpressions(decl.getInitializer());
25972
26177
  if (!initializer) continue;
25973
- if (Node18.isArrowFunction(initializer) || Node18.isFunctionExpression(initializer)) {
26178
+ if (Node19.isArrowFunction(initializer) || Node19.isFunctionExpression(initializer)) {
25974
26179
  map.set(decl.getName(), { node: initializer, sourceFile: sf, relPath: rel });
25975
26180
  }
25976
26181
  }
@@ -26006,11 +26211,11 @@ function extractTemplateConfigsArrayFactory(sources, index) {
26006
26211
  const arr = returnExpr ? asArrayLiteral(returnExpr) : void 0;
26007
26212
  if (arr) {
26008
26213
  for (const el of arr.getElements()) {
26009
- if (Node18.isSpreadElement(el)) {
26214
+ if (Node19.isSpreadElement(el)) {
26010
26215
  const inner2 = el.getExpression();
26011
- if (Node18.isCallExpression(inner2)) {
26216
+ if (Node19.isCallExpression(inner2)) {
26012
26217
  const callee = inner2.getExpression();
26013
- if (Node18.isIdentifier(callee)) {
26218
+ if (Node19.isIdentifier(callee)) {
26014
26219
  const callName = callee.getText();
26015
26220
  spreadCalls.push(callName);
26016
26221
  if (!index.functionsByName.has(callName)) {
@@ -26021,9 +26226,9 @@ function extractTemplateConfigsArrayFactory(sources, index) {
26021
26226
  continue;
26022
26227
  }
26023
26228
  const inner = unwrapAsExpressions(el);
26024
- if (inner && Node18.isCallExpression(inner)) {
26229
+ if (inner && Node19.isCallExpression(inner)) {
26025
26230
  const callee = inner.getExpression();
26026
- if (Node18.isIdentifier(callee)) {
26231
+ if (Node19.isIdentifier(callee)) {
26027
26232
  directCalls.push(callee.getText());
26028
26233
  }
26029
26234
  }
@@ -26072,11 +26277,11 @@ function collectFromArrayEntryFactory(name, out, index) {
26072
26277
  const arr = asArrayLiteral(returnExpr);
26073
26278
  if (!arr) return;
26074
26279
  for (const el of arr.getElements()) {
26075
- if (Node18.isSpreadElement(el)) {
26280
+ if (Node19.isSpreadElement(el)) {
26076
26281
  const inner2 = el.getExpression();
26077
- if (Node18.isCallExpression(inner2)) {
26282
+ if (Node19.isCallExpression(inner2)) {
26078
26283
  const callee = inner2.getExpression();
26079
- if (Node18.isIdentifier(callee)) {
26284
+ if (Node19.isIdentifier(callee)) {
26080
26285
  collectFromArrayEntryFactory(callee.getText(), out, index);
26081
26286
  }
26082
26287
  }
@@ -26084,9 +26289,9 @@ function collectFromArrayEntryFactory(name, out, index) {
26084
26289
  }
26085
26290
  const inner = unwrapAsExpressions(el);
26086
26291
  if (!inner) continue;
26087
- if (Node18.isCallExpression(inner)) {
26292
+ if (Node19.isCallExpression(inner)) {
26088
26293
  const callee = inner.getExpression();
26089
- if (Node18.isIdentifier(callee)) {
26294
+ if (Node19.isIdentifier(callee)) {
26090
26295
  collectFromSingleEntryFactory(callee.getText(), out, index);
26091
26296
  }
26092
26297
  continue;
@@ -26106,7 +26311,7 @@ function extractTaskServiceCalls(sources, index, trustedExternal) {
26106
26311
  const rel = apiRelPath(sf);
26107
26312
  for (const call of sf.getDescendantsOfKind(SyntaxKind11.CallExpression)) {
26108
26313
  const expr = call.getExpression();
26109
- if (!Node18.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
26314
+ if (!Node19.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
26110
26315
  const args = call.getArguments();
26111
26316
  const first = args[0] ? asObjectLiteral(args[0]) : void 0;
26112
26317
  if (!first) continue;
@@ -26132,13 +26337,13 @@ function collectValidateArrayElements(validateArr) {
26132
26337
  const spreads = [];
26133
26338
  if (!validateArr) return { ids, spreads };
26134
26339
  for (const el of validateArr.getElements()) {
26135
- if (Node18.isSpreadElement(el)) {
26340
+ if (Node19.isSpreadElement(el)) {
26136
26341
  const inner2 = el.getExpression();
26137
- if (Node18.isIdentifier(inner2)) spreads.push(inner2.getText());
26342
+ if (Node19.isIdentifier(inner2)) spreads.push(inner2.getText());
26138
26343
  continue;
26139
26344
  }
26140
26345
  const inner = unwrapAsExpressions(el);
26141
- if (inner && Node18.isIdentifier(inner)) ids.push(inner.getText());
26346
+ if (inner && Node19.isIdentifier(inner)) ids.push(inner.getText());
26142
26347
  }
26143
26348
  return { ids, spreads };
26144
26349
  }
@@ -26151,17 +26356,17 @@ function collectHandlersArrayElements(options) {
26151
26356
  if (!handlersArr) return { handlerTypes, unresolvedSpreads, resolvedBindings, unresolvedBindings };
26152
26357
  const visited = /* @__PURE__ */ new Set();
26153
26358
  for (const el of handlersArr.getElements()) {
26154
- if (Node18.isSpreadElement(el)) {
26359
+ if (Node19.isSpreadElement(el)) {
26155
26360
  consumeHandlersSpreadElement({ inner: el.getExpression(), sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited });
26156
26361
  continue;
26157
26362
  }
26158
26363
  const inner = unwrapAsExpressions(el);
26159
26364
  if (!inner) continue;
26160
- if (Node18.isIdentifier(inner)) {
26365
+ if (Node19.isIdentifier(inner)) {
26161
26366
  collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
26162
- } else if (Node18.isCallExpression(inner)) {
26367
+ } else if (Node19.isCallExpression(inner)) {
26163
26368
  const callee = inner.getExpression();
26164
- if (Node18.isIdentifier(callee)) {
26369
+ if (Node19.isIdentifier(callee)) {
26165
26370
  collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
26166
26371
  }
26167
26372
  }
@@ -26170,16 +26375,16 @@ function collectHandlersArrayElements(options) {
26170
26375
  }
26171
26376
  function consumeHandlersSpreadElement(options) {
26172
26377
  const { inner, sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited } = options;
26173
- if (Node18.isCallExpression(inner)) {
26378
+ if (Node19.isCallExpression(inner)) {
26174
26379
  const callee = inner.getExpression();
26175
- if (Node18.isIdentifier(callee)) {
26380
+ if (Node19.isIdentifier(callee)) {
26176
26381
  const name = callee.getText();
26177
26382
  unresolvedSpreads.push(name);
26178
26383
  collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
26179
26384
  }
26180
26385
  return;
26181
26386
  }
26182
- if (Node18.isIdentifier(inner)) {
26387
+ if (Node19.isIdentifier(inner)) {
26183
26388
  const name = inner.getText();
26184
26389
  unresolvedSpreads.push(name);
26185
26390
  collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
@@ -26189,15 +26394,31 @@ function collectHandlerBindingsFromValue(options) {
26189
26394
  const { node, sf, index, trustedExternal, resolved, unresolved, visited } = options;
26190
26395
  const inner = unwrapAsExpressions(node);
26191
26396
  if (!inner) return false;
26192
- if (Node18.isCallExpression(inner)) {
26397
+ if (Node19.isCallExpression(inner)) {
26193
26398
  const callee = inner.getExpression();
26194
- if (Node18.isIdentifier(callee)) {
26399
+ if (Node19.isIdentifier(callee)) {
26195
26400
  return collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
26196
26401
  }
26402
+ return false;
26197
26403
  }
26198
- if (Node18.isIdentifier(inner)) {
26404
+ if (Node19.isIdentifier(inner)) {
26199
26405
  return collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
26200
26406
  }
26407
+ if (Node19.isArrayLiteralExpression(inner)) {
26408
+ let any = false;
26409
+ for (const el of inner.getElements()) {
26410
+ if (Node19.isSpreadElement(el)) {
26411
+ if (collectHandlerBindingsFromValue({ node: el.getExpression(), sf, index, trustedExternal, resolved, unresolved, visited })) {
26412
+ any = true;
26413
+ }
26414
+ continue;
26415
+ }
26416
+ if (collectHandlerBindingsFromValue({ node: el, sf, index, trustedExternal, resolved, unresolved, visited })) {
26417
+ any = true;
26418
+ }
26419
+ }
26420
+ return any;
26421
+ }
26201
26422
  return false;
26202
26423
  }
26203
26424
  function collectHandlerBindingsFromIdentifier(options) {
@@ -26212,7 +26433,7 @@ function collectHandlerBindingsFromIdentifier(options) {
26212
26433
  const typeText = typeNode ? typeNode.getText() : void 0;
26213
26434
  const isHandlerConfigTyped = typeText !== void 0 && (typeText === NOTIF_TASK_SERVICE_HANDLER_CONFIG || typeText.startsWith(`${NOTIF_TASK_SERVICE_HANDLER_CONFIG}<`));
26214
26435
  const declInit = unwrapAsExpressions(localDecl.getInitializer());
26215
- const isObjectLit = declInit !== void 0 && Node18.isObjectLiteralExpression(declInit);
26436
+ const isObjectLit = declInit !== void 0 && Node19.isObjectLiteralExpression(declInit);
26216
26437
  if (isHandlerConfigTyped && isObjectLit) {
26217
26438
  resolved.push(localDecl.getName());
26218
26439
  resolvedAny = true;
@@ -26243,12 +26464,12 @@ function collectHandlerBindingsFromIdentifier(options) {
26243
26464
  function resolveArrayFromProperty2(obj, name, sf) {
26244
26465
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
26245
26466
  if (!init) return void 0;
26246
- if (Node18.isArrayLiteralExpression(init)) return init;
26247
- if (Node18.isIdentifier(init)) {
26467
+ if (Node19.isArrayLiteralExpression(init)) return init;
26468
+ if (Node19.isIdentifier(init)) {
26248
26469
  const declNode = findLocalVariable(sf, init.getText());
26249
26470
  if (declNode) {
26250
26471
  const declInit = unwrapAsExpressions(declNode.getInitializer());
26251
- if (declInit && Node18.isArrayLiteralExpression(declInit)) {
26472
+ if (declInit && Node19.isArrayLiteralExpression(declInit)) {
26252
26473
  return declInit;
26253
26474
  }
26254
26475
  }
@@ -26269,12 +26490,12 @@ function extractTaskHandlerEntries(sources) {
26269
26490
  if (!typeIdent) return;
26270
26491
  const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
26271
26492
  let flowCount;
26272
- if (flowInit && Node18.isArrayLiteralExpression(flowInit)) {
26493
+ if (flowInit && Node19.isArrayLiteralExpression(flowInit)) {
26273
26494
  flowCount = flowInit.getElements().length;
26274
26495
  }
26275
26496
  let dataArg;
26276
26497
  let checkpointArg;
26277
- if (Node18.isTypeReference(typeNode)) {
26498
+ if (Node19.isTypeReference(typeNode)) {
26278
26499
  const tArgs = typeNode.getTypeArguments();
26279
26500
  if (tArgs.length >= 1) dataArg = tArgs[0].getText();
26280
26501
  if (tArgs.length >= 2) checkpointArg = tArgs[1].getText();
@@ -27167,7 +27388,7 @@ async function inspectFolder2(path) {
27167
27388
  }
27168
27389
 
27169
27390
  // packages/dbx-components-mcp/src/tools/system-m-validate-folder/extract.ts
27170
- import { Node as Node19, Project as Project13 } from "ts-morph";
27391
+ import { Node as Node20, Project as Project13 } from "ts-morph";
27171
27392
  var TYPE_CONSTANT_SUFFIX = "_SYSTEM_STATE_TYPE";
27172
27393
  var DATA_INTERFACE_SUFFIX = "SystemData";
27173
27394
  var CONVERTER_CONFIG_TYPE = "SystemStateStoredDataFieldConverterConfig";
@@ -27231,7 +27452,7 @@ function findDataInterfaces2(sourceFile) {
27231
27452
  return out;
27232
27453
  }
27233
27454
  function extendsSystemStateStoredData(iface) {
27234
- if (!Node19.isInterfaceDeclaration(iface)) return false;
27455
+ if (!Node20.isInterfaceDeclaration(iface)) return false;
27235
27456
  for (const clause of iface.getExtends()) {
27236
27457
  const text = clause.getText();
27237
27458
  if (text === SYSTEM_STATE_STORED_DATA || text.startsWith(`${SYSTEM_STATE_STORED_DATA}<`) || text === `${SYSTEM_STATE_STORED_DATA}, ${SYSTEM_STATE_STORED_DATA}`) {
@@ -27251,14 +27472,14 @@ function findConverters2(sourceFile) {
27251
27472
  for (const decl of stmt.getDeclarations()) {
27252
27473
  const typeNode = decl.getTypeNode();
27253
27474
  if (!typeNode) continue;
27254
- if (!Node19.isTypeReference(typeNode)) continue;
27475
+ if (!Node20.isTypeReference(typeNode)) continue;
27255
27476
  const typeName = typeNode.getTypeName().getText();
27256
27477
  if (typeName !== CONVERTER_CONFIG_TYPE) continue;
27257
27478
  const typeArgs = typeNode.getTypeArguments();
27258
27479
  let dataTypeArgument;
27259
27480
  if (typeArgs.length >= 1) {
27260
27481
  const arg = typeArgs[0];
27261
- if (Node19.isTypeReference(arg)) {
27482
+ if (Node20.isTypeReference(arg)) {
27262
27483
  dataTypeArgument = arg.getTypeName().getText();
27263
27484
  } else {
27264
27485
  dataTypeArgument = arg.getText();
@@ -27305,19 +27526,19 @@ function collectConverterMapKeys(decl) {
27305
27526
  if (!obj) return [];
27306
27527
  const out = [];
27307
27528
  for (const prop of obj.getProperties()) {
27308
- if (!Node19.isPropertyAssignment(prop)) continue;
27529
+ if (!Node20.isPropertyAssignment(prop)) continue;
27309
27530
  const nameNode = prop.getNameNode();
27310
27531
  const line = prop.getStartLineNumber();
27311
- if (Node19.isComputedPropertyName(nameNode)) {
27532
+ if (Node20.isComputedPropertyName(nameNode)) {
27312
27533
  const inner = nameNode.getExpression();
27313
27534
  out.push({ raw: inner.getText(), kind: "identifier", line });
27314
27535
  continue;
27315
27536
  }
27316
- if (Node19.isStringLiteral(nameNode)) {
27537
+ if (Node20.isStringLiteral(nameNode)) {
27317
27538
  out.push({ raw: nameNode.getLiteralText(), kind: "string", line });
27318
27539
  continue;
27319
27540
  }
27320
- if (Node19.isIdentifier(nameNode)) {
27541
+ if (Node20.isIdentifier(nameNode)) {
27321
27542
  out.push({ raw: nameNode.getText(), kind: "string", line });
27322
27543
  continue;
27323
27544
  }
@@ -27327,10 +27548,10 @@ function collectConverterMapKeys(decl) {
27327
27548
  }
27328
27549
  function unwrapObjectLiteral(node) {
27329
27550
  let current = node;
27330
- while (current && Node19.isAsExpression(current)) {
27551
+ while (current && Node20.isAsExpression(current)) {
27331
27552
  current = current.getExpression();
27332
27553
  }
27333
- if (current && Node19.isObjectLiteralExpression(current)) {
27554
+ if (current && Node20.isObjectLiteralExpression(current)) {
27334
27555
  return current;
27335
27556
  }
27336
27557
  return void 0;
@@ -27364,10 +27585,10 @@ function findLastTopLevelExportLine(sourceFile) {
27364
27585
  return last;
27365
27586
  }
27366
27587
  function isExportedTopLevel(stmt) {
27367
- if (Node19.isVariableStatement(stmt) || Node19.isFunctionDeclaration(stmt) || Node19.isClassDeclaration(stmt) || Node19.isInterfaceDeclaration(stmt) || Node19.isTypeAliasDeclaration(stmt) || Node19.isEnumDeclaration(stmt)) {
27588
+ if (Node20.isVariableStatement(stmt) || Node20.isFunctionDeclaration(stmt) || Node20.isClassDeclaration(stmt) || Node20.isInterfaceDeclaration(stmt) || Node20.isTypeAliasDeclaration(stmt) || Node20.isEnumDeclaration(stmt)) {
27368
27589
  return stmt.isExported();
27369
27590
  }
27370
- if (Node19.isExportDeclaration(stmt) || Node19.isExportAssignment(stmt)) {
27591
+ if (Node20.isExportDeclaration(stmt) || Node20.isExportAssignment(stmt)) {
27371
27592
  return true;
27372
27593
  }
27373
27594
  return false;
@@ -27678,7 +27899,7 @@ var systemMValidateFolderTool = createFolderValidateTool({
27678
27899
  });
27679
27900
 
27680
27901
  // packages/dbx-components-mcp/src/tools/dbx-asset-validate-app/extract.ts
27681
- import { Node as Node20, Project as Project14 } from "ts-morph";
27902
+ import { Node as Node21, Project as Project14 } from "ts-morph";
27682
27903
  var ASSETS_RELPATH = "src/lib/assets.ts";
27683
27904
  var BARREL_RELPATH = "src/lib/index.ts";
27684
27905
  var LOCAL_ASSET_BUILDER = "localAsset";
@@ -27737,11 +27958,11 @@ function extractFromAssetsSource(ctx, sf) {
27737
27958
  const initializer = unwrapAsExpressions(decl.getInitializer());
27738
27959
  if (!initializer) continue;
27739
27960
  const site = { isExported, symbolName: decl.getName(), line: decl.getStartLineNumber(), rel };
27740
- if (Node20.isCallExpression(initializer)) {
27961
+ if (Node21.isCallExpression(initializer)) {
27741
27962
  handleCallInitializer(ctx, site, initializer);
27742
27963
  continue;
27743
27964
  }
27744
- if (isExported && Node20.isArrayLiteralExpression(initializer) && typeAnnotationText(decl) === ASSET_PATH_REF_ARRAY_TYPE) {
27965
+ if (isExported && Node21.isArrayLiteralExpression(initializer) && typeAnnotationText(decl) === ASSET_PATH_REF_ARRAY_TYPE) {
27745
27966
  ctx.aggregatorExports.push({ symbolName: site.symbolName, memberNames: collectArrayIdentifiers(initializer.getElements()), sourceFile: rel, line: site.line });
27746
27967
  }
27747
27968
  }
@@ -27751,7 +27972,7 @@ function collectArrayIdentifiers(elements) {
27751
27972
  const out = [];
27752
27973
  for (const el of elements) {
27753
27974
  const inner = unwrapAsExpressions(el);
27754
- if (inner && Node20.isIdentifier(inner)) {
27975
+ if (inner && Node21.isIdentifier(inner)) {
27755
27976
  out.push(inner.getText());
27756
27977
  }
27757
27978
  }
@@ -27759,11 +27980,11 @@ function collectArrayIdentifiers(elements) {
27759
27980
  }
27760
27981
  function handleCallInitializer(ctx, site, callExpr) {
27761
27982
  const callee = callExpr.getExpression();
27762
- if (Node20.isIdentifier(callee)) {
27983
+ if (Node21.isIdentifier(callee)) {
27763
27984
  handleIdentifierCallee({ ctx, site, callExpr, calleeName: callee.getText() });
27764
27985
  return;
27765
27986
  }
27766
- if (Node20.isPropertyAccessExpression(callee)) {
27987
+ if (Node21.isPropertyAccessExpression(callee)) {
27767
27988
  handleFluentMemberCall(ctx, site, callExpr);
27768
27989
  }
27769
27990
  }
@@ -27821,9 +28042,9 @@ function handleRemoteBaseBuilder(ctx, site, arg) {
27821
28042
  }
27822
28043
  function handleFluentMemberCall(ctx, site, callExpr) {
27823
28044
  const callee = callExpr.getExpression();
27824
- if (!Node20.isPropertyAccessExpression(callee)) return;
28045
+ if (!Node21.isPropertyAccessExpression(callee)) return;
27825
28046
  const identNode = callee.getExpression();
27826
- if (!Node20.isIdentifier(identNode)) return;
28047
+ if (!Node21.isIdentifier(identNode)) return;
27827
28048
  const memberName = callee.getName();
27828
28049
  if (memberName !== "asset" && memberName !== "assets") return;
27829
28050
  const builderName = identNode.getText();
@@ -27848,7 +28069,7 @@ function handleFluentMemberCall(ctx, site, callExpr) {
27848
28069
  return;
27849
28070
  }
27850
28071
  const arrayInner = unwrapAsExpressions(args[0]);
27851
- if (!arrayInner || !Node20.isArrayLiteralExpression(arrayInner)) return;
28072
+ if (!arrayInner || !Node21.isArrayLiteralExpression(arrayInner)) return;
27852
28073
  const resolvedPaths = collectFluentArrayPaths({ elements: arrayInner.getElements(), sourceType, folder, remoteBase });
27853
28074
  if (site.isExported) {
27854
28075
  ctx.assetConstants.push({ symbolName: site.symbolName, sourceType, helper, resolved: void 0, resolvedPaths, sourceFile: site.rel, line: site.line });
@@ -27858,7 +28079,7 @@ function collectFluentArrayPaths(input) {
27858
28079
  const out = [];
27859
28080
  for (const el of input.elements) {
27860
28081
  const inner = unwrapAsExpressions(el);
27861
- if (inner && Node20.isStringLiteral(inner)) {
28082
+ if (inner && Node21.isStringLiteral(inner)) {
27862
28083
  const joined = joinFluent({ sourceType: input.sourceType, folder: input.folder, remoteBase: input.remoteBase, child: inner.getLiteralText() });
27863
28084
  if (joined !== void 0) out.push(joined);
27864
28085
  }
@@ -27891,7 +28112,7 @@ function readStringArg(call) {
27891
28112
  }
27892
28113
  function readStringArgFromNode(node) {
27893
28114
  const inner = unwrapAsExpressions(node);
27894
- if (inner && Node20.isStringLiteral(inner)) {
28115
+ if (inner && Node21.isStringLiteral(inner)) {
27895
28116
  return inner.getLiteralText();
27896
28117
  }
27897
28118
  return void 0;
@@ -29260,6 +29481,83 @@ export class EditProfilePageComponent {
29260
29481
  notes: "`dbxActionForm` lives in `@dereekb/dbx-form` \u2014 it is the value provider in this composition. The form's `dbxFormSource` seeds the initial value and the form's modification status feeds `isModified` on the action store."
29261
29482
  };
29262
29483
 
29484
+ // packages/dbx-components-mcp/src/tools/data/patterns/actions/action.form-with-secondary.pattern.ts
29485
+ var ACTION_PATTERN_FORM_WITH_SECONDARY = {
29486
+ slug: "form-with-secondary",
29487
+ name: "Form submit with secondary action button",
29488
+ summary: "Outer `dbxAction` + `dbxActionForm` drives a primary (Approve) button; a nested `<ng-container dbxAction>` with `dbxActionValue` provides an independent secondary (Deny / Cancel) button that fires a void handler.",
29489
+ usesActionSlugs: ["action", "handler", "value", "button", "error-handler"],
29490
+ snippets: {
29491
+ minimal: `<div dbxAction [dbxActionHandler]="handleApprove">
29492
+ <my-form dbxActionForm></my-form>
29493
+ <dbx-button text="Approve" dbxActionButton></dbx-button>
29494
+ <ng-container dbxAction dbxActionValue [dbxActionHandler]="handleDeny">
29495
+ <dbx-button text="Deny" dbxActionButton></dbx-button>
29496
+ </ng-container>
29497
+ </div>`,
29498
+ brief: `<div dbxAction dbxActionSnackbarError [dbxActionHandler]="handleApprove">
29499
+ <my-form dbxActionForm [dbxFormSource]="data$"></my-form>
29500
+ <dbx-button [raised]="true" text="Approve" color="primary" dbxActionButton></dbx-button>
29501
+ <dbx-button-spacer></dbx-button-spacer>
29502
+ <ng-container dbxAction dbxActionSnackbarError dbxActionValue [dbxActionHandler]="handleDeny">
29503
+ <dbx-button [flat]="true" text="Deny" color="warn" dbxActionButton></dbx-button>
29504
+ </ng-container>
29505
+ </div>`,
29506
+ full: `import { Component, signal } from '@angular/core';
29507
+ import { type WorkUsingContext } from '@dereekb/rxjs';
29508
+
29509
+ type ConsentDecision = { readonly outcome: 'approved'; readonly value: ConsentFormValue } | { readonly outcome: 'denied' };
29510
+
29511
+ @Component({
29512
+ selector: 'app-consent-page',
29513
+ template: \`
29514
+ <!-- Outer context: form-driven Approve -->
29515
+ <div dbxAction dbxActionSnackbarError [dbxActionHandler]="handleApprove">
29516
+ <my-consent-form dbxActionForm [dbxFormSource]="defaults$"></my-consent-form>
29517
+
29518
+ <div class="dbx-pt3">
29519
+ <dbx-button [raised]="true" text="Approve" color="primary" dbxActionButton></dbx-button>
29520
+ <dbx-button-spacer></dbx-button-spacer>
29521
+
29522
+ <!-- Nested context: void Deny. dbxActionValue with no input -->
29523
+ <!-- supplies the empty payload that lets the button fire. -->
29524
+ <ng-container dbxAction dbxActionSnackbarError dbxActionValue [dbxActionHandler]="handleDeny">
29525
+ <dbx-button [flat]="true" text="Deny" color="warn" dbxActionButton></dbx-button>
29526
+ </ng-container>
29527
+ </div>
29528
+ </div>
29529
+
29530
+ @let decision = lastDecisionSignal();
29531
+ @if (decision) {
29532
+ <div class="dbx-pt3">
29533
+ @if (decision.outcome === 'approved') {
29534
+ <span>Approved with: <strong>{{ decision.value | json }}</strong></span>
29535
+ } @else {
29536
+ <span>Denied.</span>
29537
+ }
29538
+ </div>
29539
+ }
29540
+ \`,
29541
+ standalone: true
29542
+ })
29543
+ export class ConsentPageComponent {
29544
+ readonly defaults$ = this.store.defaults$;
29545
+ readonly lastDecisionSignal = signal<ConsentDecision | undefined>(undefined);
29546
+
29547
+ readonly handleApprove: WorkUsingContext<ConsentFormValue, ConsentResult> = (value, context) => {
29548
+ this.lastDecisionSignal.set({ outcome: 'approved', value });
29549
+ context.startWorkingWithLoadingStateObservable(this.store.approve(value));
29550
+ };
29551
+
29552
+ readonly handleDeny: WorkUsingContext<void, ConsentResult> = (_, context) => {
29553
+ this.lastDecisionSignal.set({ outcome: 'denied' });
29554
+ context.startWorkingWithLoadingStateObservable(this.store.deny());
29555
+ };
29556
+ }`
29557
+ },
29558
+ notes: 'Two non-obvious mechanics: (1) Each `dbxAction` creates its own `ActionContextStore`. `dbxActionButton` and other child directives inject the **nearest ancestor** store via Angular DI, so the inner button picks up the inner context \u2014 not the outer. (2) `dbxActionValue` with no input emits the empty-string sentinel, which `filterMaybe()` lets through, so `readyValue("")` fires immediately when the secondary button triggers; that satisfies `dbxActionButton` without needing a form on the secondary path. Each context can carry its own `dbxActionSnackbarError` so success/error feedback stays scoped per button. This is the canonical OIDC consent shape used in `@dereekb/dbx-firebase` (`oauth.consent.view.component.ts`).'
29559
+ };
29560
+
29263
29561
  // packages/dbx-components-mcp/src/tools/data/patterns/actions/action.provide-context-up.pattern.ts
29264
29562
  var ACTION_PATTERN_PROVIDE_CONTEXT_UP = {
29265
29563
  slug: "provide-context-up",
@@ -29369,7 +29667,7 @@ export class TagEditorComponent {
29369
29667
  };
29370
29668
 
29371
29669
  // packages/dbx-components-mcp/src/tools/data/patterns/action-patterns.ts
29372
- var ACTION_EXAMPLE_PATTERNS = [ACTION_PATTERN_BUTTON_CONFIRM_DELETE, ACTION_PATTERN_FORM_SUBMIT, ACTION_PATTERN_AUTO_TRIGGER_ON_MODIFY, ACTION_PATTERN_DISABLED_BY_KEY, ACTION_PATTERN_VALUE_GETTER_ON_TRIGGER, ACTION_PATTERN_PROVIDE_CONTEXT_UP];
29670
+ var ACTION_EXAMPLE_PATTERNS = [ACTION_PATTERN_BUTTON_CONFIRM_DELETE, ACTION_PATTERN_FORM_SUBMIT, ACTION_PATTERN_FORM_WITH_SECONDARY, ACTION_PATTERN_AUTO_TRIGGER_ON_MODIFY, ACTION_PATTERN_DISABLED_BY_KEY, ACTION_PATTERN_VALUE_GETTER_ON_TRIGGER, ACTION_PATTERN_PROVIDE_CONTEXT_UP];
29373
29671
  function getActionExamplePattern(slug) {
29374
29672
  const lowered = slug.trim().toLowerCase();
29375
29673
  return ACTION_EXAMPLE_PATTERNS.find((p) => p.slug === lowered);
@@ -29729,7 +30027,7 @@ import { glob as fsGlob5, readFile as readFile18, stat as stat14 } from "node:fs
29729
30027
  import { dirname as dirname13, isAbsolute as isAbsolute13, resolve as resolve34, sep as sep12 } from "node:path";
29730
30028
 
29731
30029
  // packages/dbx-components-mcp/src/tools/route/extract.ts
29732
- import { Node as Node21, Project as Project15, SyntaxKind as SyntaxKind12 } from "ts-morph";
30030
+ import { Node as Node22, Project as Project15, SyntaxKind as SyntaxKind12 } from "ts-morph";
29733
30031
  function extractFile3(source) {
29734
30032
  const project = new Project15({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
29735
30033
  const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
@@ -29744,9 +30042,9 @@ function extractFile3(source) {
29744
30042
  }
29745
30043
  for (const arrayLit of findStateArrayLiterals(sourceFile)) {
29746
30044
  for (const element of arrayLit.getElements()) {
29747
- if (Node21.isObjectLiteralExpression(element)) {
30045
+ if (Node22.isObjectLiteralExpression(element)) {
29748
30046
  addNode({ file: source.name, literal: element, fallbackConstName: void 0, into: collected, issues });
29749
- } else if (Node21.isIdentifier(element)) {
30047
+ } else if (Node22.isIdentifier(element)) {
29750
30048
  const ref = objectLiteralsByName.get(element.getText());
29751
30049
  if (ref) {
29752
30050
  addNode({ file: source.name, literal: ref.literal, fallbackConstName: element.getText(), into: collected, issues });
@@ -29767,7 +30065,7 @@ function collectStateConsts(sourceFile) {
29767
30065
  for (const stmt of sourceFile.getVariableStatements()) {
29768
30066
  for (const decl of stmt.getDeclarations()) {
29769
30067
  const initializer = decl.getInitializer();
29770
- if (!initializer || !Node21.isObjectLiteralExpression(initializer)) {
30068
+ if (!initializer || !Node22.isObjectLiteralExpression(initializer)) {
29771
30069
  continue;
29772
30070
  }
29773
30071
  const typeNode = decl.getTypeNode();
@@ -29782,7 +30080,7 @@ function findStateArrayLiterals(sourceFile) {
29782
30080
  for (const stmt of sourceFile.getVariableStatements()) {
29783
30081
  for (const decl of stmt.getDeclarations()) {
29784
30082
  const initializer = decl.getInitializer();
29785
- if (initializer && Node21.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
30083
+ if (initializer && Node22.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
29786
30084
  arrays.push(initializer);
29787
30085
  }
29788
30086
  }
@@ -29796,17 +30094,17 @@ function findStateArrayLiterals(sourceFile) {
29796
30094
  continue;
29797
30095
  }
29798
30096
  for (const arg of call.getArguments()) {
29799
- if (!Node21.isObjectLiteralExpression(arg)) {
30097
+ if (!Node22.isObjectLiteralExpression(arg)) {
29800
30098
  continue;
29801
30099
  }
29802
30100
  const statesProp = arg.getProperty("states");
29803
- if (!statesProp || !Node21.isPropertyAssignment(statesProp)) {
30101
+ if (!statesProp || !Node22.isPropertyAssignment(statesProp)) {
29804
30102
  continue;
29805
30103
  }
29806
30104
  const initializer = statesProp.getInitializer();
29807
- if (initializer && Node21.isArrayLiteralExpression(initializer)) {
30105
+ if (initializer && Node22.isArrayLiteralExpression(initializer)) {
29808
30106
  arrays.push(initializer);
29809
- } else if (initializer && Node21.isIdentifier(initializer)) {
30107
+ } else if (initializer && Node22.isIdentifier(initializer)) {
29810
30108
  const referenced = findArrayLiteralForIdentifier(sourceFile, initializer);
29811
30109
  if (referenced) {
29812
30110
  arrays.push(referenced);
@@ -29823,10 +30121,10 @@ function declarationIsStateArray(stmt, name, literal) {
29823
30121
  return true;
29824
30122
  }
29825
30123
  for (const element of literal.getElements()) {
29826
- if (Node21.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
30124
+ if (Node22.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
29827
30125
  return true;
29828
30126
  }
29829
- if (Node21.isIdentifier(element)) {
30127
+ if (Node22.isIdentifier(element)) {
29830
30128
  return true;
29831
30129
  }
29832
30130
  }
@@ -29834,11 +30132,11 @@ function declarationIsStateArray(stmt, name, literal) {
29834
30132
  }
29835
30133
  function hasStringNameProperty(literal) {
29836
30134
  const nameProp = literal.getProperty("name");
29837
- if (!nameProp || !Node21.isPropertyAssignment(nameProp)) {
30135
+ if (!nameProp || !Node22.isPropertyAssignment(nameProp)) {
29838
30136
  return false;
29839
30137
  }
29840
30138
  const initializer = nameProp.getInitializer();
29841
- return initializer !== void 0 && (Node21.isStringLiteral(initializer) || Node21.isNoSubstitutionTemplateLiteral(initializer));
30139
+ return initializer !== void 0 && (Node22.isStringLiteral(initializer) || Node22.isNoSubstitutionTemplateLiteral(initializer));
29842
30140
  }
29843
30141
  function findArrayLiteralForIdentifier(sourceFile, identifier) {
29844
30142
  const name = identifier.getText();
@@ -29848,7 +30146,7 @@ function findArrayLiteralForIdentifier(sourceFile, identifier) {
29848
30146
  continue;
29849
30147
  }
29850
30148
  const initializer = decl.getInitializer();
29851
- if (initializer && Node21.isArrayLiteralExpression(initializer)) {
30149
+ if (initializer && Node22.isArrayLiteralExpression(initializer)) {
29852
30150
  return initializer;
29853
30151
  }
29854
30152
  }
@@ -29898,21 +30196,21 @@ function addNode(options) {
29898
30196
  }
29899
30197
  function stringPropertyValue(literal, key) {
29900
30198
  const prop = literal.getProperty(key);
29901
- if (!prop || !Node21.isPropertyAssignment(prop)) {
30199
+ if (!prop || !Node22.isPropertyAssignment(prop)) {
29902
30200
  return void 0;
29903
30201
  }
29904
30202
  const initializer = prop.getInitializer();
29905
30203
  if (!initializer) {
29906
30204
  return void 0;
29907
30205
  }
29908
- if (Node21.isStringLiteral(initializer) || Node21.isNoSubstitutionTemplateLiteral(initializer)) {
30206
+ if (Node22.isStringLiteral(initializer) || Node22.isNoSubstitutionTemplateLiteral(initializer)) {
29909
30207
  return initializer.getLiteralText();
29910
30208
  }
29911
30209
  return void 0;
29912
30210
  }
29913
30211
  function booleanPropertyValue(literal, key) {
29914
30212
  const prop = literal.getProperty(key);
29915
- if (!prop || !Node21.isPropertyAssignment(prop)) {
30213
+ if (!prop || !Node22.isPropertyAssignment(prop)) {
29916
30214
  return void 0;
29917
30215
  }
29918
30216
  const initializer = prop.getInitializer();
@@ -29929,33 +30227,33 @@ function booleanPropertyValue(literal, key) {
29929
30227
  }
29930
30228
  function identifierPropertyValue(literal, key) {
29931
30229
  const prop = literal.getProperty(key);
29932
- if (!prop || !Node21.isPropertyAssignment(prop)) {
30230
+ if (!prop || !Node22.isPropertyAssignment(prop)) {
29933
30231
  return void 0;
29934
30232
  }
29935
30233
  const initializer = prop.getInitializer();
29936
30234
  if (!initializer) {
29937
30235
  return void 0;
29938
30236
  }
29939
- if (Node21.isIdentifier(initializer)) {
30237
+ if (Node22.isIdentifier(initializer)) {
29940
30238
  return initializer.getText();
29941
30239
  }
29942
- if (Node21.isPropertyAccessExpression(initializer)) {
30240
+ if (Node22.isPropertyAccessExpression(initializer)) {
29943
30241
  return initializer.getText();
29944
30242
  }
29945
30243
  return void 0;
29946
30244
  }
29947
30245
  function objectPropertyKeys(literal, key) {
29948
30246
  const prop = literal.getProperty(key);
29949
- if (!prop || !Node21.isPropertyAssignment(prop)) {
30247
+ if (!prop || !Node22.isPropertyAssignment(prop)) {
29950
30248
  return [];
29951
30249
  }
29952
30250
  const initializer = prop.getInitializer();
29953
- if (!initializer || !Node21.isObjectLiteralExpression(initializer)) {
30251
+ if (!initializer || !Node22.isObjectLiteralExpression(initializer)) {
29954
30252
  return [];
29955
30253
  }
29956
30254
  const out = [];
29957
30255
  for (const member of initializer.getProperties()) {
29958
- if (Node21.isPropertyAssignment(member) || Node21.isShorthandPropertyAssignment(member) || Node21.isMethodDeclaration(member)) {
30256
+ if (Node22.isPropertyAssignment(member) || Node22.isShorthandPropertyAssignment(member) || Node22.isMethodDeclaration(member)) {
29959
30257
  const nameNode = member.getNameNode();
29960
30258
  if (nameNode) {
29961
30259
  out.push(nameNode.getText());
@@ -29966,7 +30264,7 @@ function objectPropertyKeys(literal, key) {
29966
30264
  }
29967
30265
  function collectResolveKeys(literal) {
29968
30266
  const prop = literal.getProperty("resolve");
29969
- if (!prop || !Node21.isPropertyAssignment(prop)) {
30267
+ if (!prop || !Node22.isPropertyAssignment(prop)) {
29970
30268
  return [];
29971
30269
  }
29972
30270
  const initializer = prop.getInitializer();
@@ -29974,22 +30272,22 @@ function collectResolveKeys(literal) {
29974
30272
  return [];
29975
30273
  }
29976
30274
  const keys = [];
29977
- if (Node21.isObjectLiteralExpression(initializer)) {
30275
+ if (Node22.isObjectLiteralExpression(initializer)) {
29978
30276
  for (const member of initializer.getProperties()) {
29979
- if (Node21.isPropertyAssignment(member) || Node21.isShorthandPropertyAssignment(member) || Node21.isMethodDeclaration(member)) {
30277
+ if (Node22.isPropertyAssignment(member) || Node22.isShorthandPropertyAssignment(member) || Node22.isMethodDeclaration(member)) {
29980
30278
  const nameNode = member.getNameNode();
29981
30279
  if (nameNode) {
29982
30280
  keys.push(nameNode.getText());
29983
30281
  }
29984
30282
  }
29985
30283
  }
29986
- } else if (Node21.isArrayLiteralExpression(initializer)) {
30284
+ } else if (Node22.isArrayLiteralExpression(initializer)) {
29987
30285
  for (const element of initializer.getElements()) {
29988
- if (Node21.isObjectLiteralExpression(element)) {
30286
+ if (Node22.isObjectLiteralExpression(element)) {
29989
30287
  const tokenProp = element.getProperty("token");
29990
- if (tokenProp && Node21.isPropertyAssignment(tokenProp)) {
30288
+ if (tokenProp && Node22.isPropertyAssignment(tokenProp)) {
29991
30289
  const tokenInit = tokenProp.getInitializer();
29992
- if (tokenInit && (Node21.isStringLiteral(tokenInit) || Node21.isIdentifier(tokenInit))) {
30290
+ if (tokenInit && (Node22.isStringLiteral(tokenInit) || Node22.isIdentifier(tokenInit))) {
29993
30291
  keys.push(tokenInit.getText().replaceAll(/^['"]|['"]$/g, ""));
29994
30292
  }
29995
30293
  }
@@ -32058,7 +32356,7 @@ function createSearchModelSnapshotFieldTool(config) {
32058
32356
  import { glob, readFile as readFile19 } from "node:fs/promises";
32059
32357
  import { resolve as resolve35 } from "node:path";
32060
32358
  import { type as type59 } from "arktype";
32061
- import { Node as Node22, Project as Project16 } from "ts-morph";
32359
+ import { Node as Node23, Project as Project16 } from "ts-morph";
32062
32360
  var ListAppArgsType2 = type59({
32063
32361
  componentDir: "string",
32064
32362
  "apiDir?": "string",
@@ -32188,7 +32486,7 @@ async function buildListAppReport(input) {
32188
32486
  function findSnapshotConverterCalls(sourceFile) {
32189
32487
  const out = [];
32190
32488
  sourceFile.forEachDescendant((node) => {
32191
- if (Node22.isCallExpression(node)) {
32489
+ if (Node23.isCallExpression(node)) {
32192
32490
  const expr = node.getExpression();
32193
32491
  const exprText = expr.getText();
32194
32492
  const head = exprText.replace(/<[^>]*>$/, "");
@@ -32203,17 +32501,17 @@ function readFieldsObject(call) {
32203
32501
  const args = call.getArguments();
32204
32502
  if (args.length === 0) return void 0;
32205
32503
  const first = args[0];
32206
- if (!Node22.isObjectLiteralExpression(first)) return void 0;
32504
+ if (!Node23.isObjectLiteralExpression(first)) return void 0;
32207
32505
  const fieldsProp = first.getProperty("fields");
32208
- if (fieldsProp === void 0 || !Node22.isPropertyAssignment(fieldsProp)) return void 0;
32506
+ if (fieldsProp === void 0 || !Node23.isPropertyAssignment(fieldsProp)) return void 0;
32209
32507
  const initializer = fieldsProp.getInitializer();
32210
- if (initializer === void 0 || !Node22.isObjectLiteralExpression(initializer)) return void 0;
32508
+ if (initializer === void 0 || !Node23.isObjectLiteralExpression(initializer)) return void 0;
32211
32509
  return initializer;
32212
32510
  }
32213
32511
  function resolveModelName(call) {
32214
32512
  let current = call.getParent();
32215
32513
  while (current !== void 0) {
32216
- if (Node22.isVariableDeclaration(current)) {
32514
+ if (Node23.isVariableDeclaration(current)) {
32217
32515
  return current.getName();
32218
32516
  }
32219
32517
  current = current.getParent();
@@ -32223,10 +32521,10 @@ function resolveModelName(call) {
32223
32521
  function extractFieldUsages(fieldsObj, registry) {
32224
32522
  const out = [];
32225
32523
  for (const property of fieldsObj.getProperties()) {
32226
- if (!Node22.isPropertyAssignment(property) && !Node22.isShorthandPropertyAssignment(property)) continue;
32524
+ if (!Node23.isPropertyAssignment(property) && !Node23.isShorthandPropertyAssignment(property)) continue;
32227
32525
  const fieldName = property.getName();
32228
32526
  let converterText;
32229
- if (Node22.isShorthandPropertyAssignment(property)) {
32527
+ if (Node23.isShorthandPropertyAssignment(property)) {
32230
32528
  converterText = property.getName();
32231
32529
  } else {
32232
32530
  const initializer = property.getInitializer();
@@ -33749,7 +34047,7 @@ import { type as type64 } from "arktype";
33749
34047
  // packages/dbx-components-mcp/src/tools/model-list-component/extract.ts
33750
34048
  import { readdir as readdir12, readFile as readFile20, stat as stat16 } from "node:fs/promises";
33751
34049
  import { basename as basename6, join as join19, relative as relative11, sep as sep14 } from "node:path";
33752
- import { Node as Node23, Project as Project17 } from "ts-morph";
34050
+ import { Node as Node24, Project as Project17 } from "ts-morph";
33753
34051
  var MODEL_SUBPATH3 = "src/lib/model";
33754
34052
  var MODEL_SUBPATH_PREFIX = `${MODEL_SUBPATH3}/`;
33755
34053
  var RESERVED_NAMES = RESERVED_MODEL_FOLDERS.map((r) => r.name);
@@ -33890,7 +34188,7 @@ function findIdentityIn(sourceFile) {
33890
34188
  for (const statement of sourceFile.getVariableStatements()) {
33891
34189
  for (const decl of statement.getDeclarations()) {
33892
34190
  const initializer = decl.getInitializer();
33893
- if (!initializer || !Node23.isCallExpression(initializer)) continue;
34191
+ if (!initializer || !Node24.isCallExpression(initializer)) continue;
33894
34192
  if (initializer.getExpression().getText() !== "firestoreModelIdentity") continue;
33895
34193
  const args = initializer.getArguments();
33896
34194
  const parsed = parseIdentityArgs2(args);
@@ -33910,13 +34208,13 @@ function parseIdentityArgs2(args) {
33910
34208
  return { parentIdentityRef: void 0, collectionName: stringLiteralValue3(args[0]), collectionPrefix: stringLiteralValue3(args[1]) };
33911
34209
  }
33912
34210
  if (args.length === 3) {
33913
- const parent = Node23.isIdentifier(args[0]) ? args[0].getText() : void 0;
34211
+ const parent = Node24.isIdentifier(args[0]) ? args[0].getText() : void 0;
33914
34212
  return { parentIdentityRef: parent, collectionName: stringLiteralValue3(args[1]), collectionPrefix: stringLiteralValue3(args[2]) };
33915
34213
  }
33916
34214
  return { parentIdentityRef: void 0, collectionName: void 0, collectionPrefix: void 0 };
33917
34215
  }
33918
34216
  function stringLiteralValue3(node) {
33919
- if (Node23.isStringLiteral(node) || Node23.isNoSubstitutionTemplateLiteral(node)) {
34217
+ if (Node24.isStringLiteral(node) || Node24.isNoSubstitutionTemplateLiteral(node)) {
33920
34218
  return node.getLiteralText();
33921
34219
  }
33922
34220
  return void 0;
@@ -34078,7 +34376,7 @@ import { type as type65 } from "arktype";
34078
34376
  // packages/dbx-components-mcp/src/tools/server-actions-list-app/extract.ts
34079
34377
  import { readdir as readdir13, readFile as readFile21, stat as stat17 } from "node:fs/promises";
34080
34378
  import { dirname as dirname14, join as join20, relative as relative12, sep as sep15 } from "node:path";
34081
- import { Node as Node24, Project as Project18 } from "ts-morph";
34379
+ import { Node as Node25, Project as Project18 } from "ts-morph";
34082
34380
  var ACTION_SERVER_SUFFIX2 = ".action.server.ts";
34083
34381
  var COMMON_MODEL_SUBPATH2 = "src/app/common/model";
34084
34382
  var COMMON_BARREL_REL = "src/app/common/index.ts";
@@ -34215,7 +34513,7 @@ function inspectModuleText(input) {
34215
34513
  for (const decorator of cls.getDecorators()) {
34216
34514
  if (decorator.getName() !== "Module") continue;
34217
34515
  const args = decorator.getArguments();
34218
- if (args.length === 0 || !Node24.isObjectLiteralExpression(args[0])) continue;
34516
+ if (args.length === 0 || !Node25.isObjectLiteralExpression(args[0])) continue;
34219
34517
  const obj = args[0];
34220
34518
  providedByModule ||= moduleArrayContains(obj, "providers", input.className);
34221
34519
  exportedByModule ||= moduleArrayContains(obj, "exports", input.className);
@@ -34225,16 +34523,16 @@ function inspectModuleText(input) {
34225
34523
  }
34226
34524
  function moduleArrayContains(decoratorArg, propertyName, className) {
34227
34525
  const property = decoratorArg.getProperty(propertyName);
34228
- if (!property || !Node24.isPropertyAssignment(property)) return false;
34526
+ if (!property || !Node25.isPropertyAssignment(property)) return false;
34229
34527
  const initializer = property.getInitializer();
34230
- if (!initializer || !Node24.isArrayLiteralExpression(initializer)) return false;
34528
+ if (!initializer || !Node25.isArrayLiteralExpression(initializer)) return false;
34231
34529
  for (const element of initializer.getElements()) {
34232
- if (Node24.isIdentifier(element) && element.getText() === className) return true;
34233
- if (Node24.isObjectLiteralExpression(element)) {
34530
+ if (Node25.isIdentifier(element) && element.getText() === className) return true;
34531
+ if (Node25.isObjectLiteralExpression(element)) {
34234
34532
  const provideProp = element.getProperty("provide");
34235
- if (provideProp && Node24.isPropertyAssignment(provideProp)) {
34533
+ if (provideProp && Node25.isPropertyAssignment(provideProp)) {
34236
34534
  const provideInit = provideProp.getInitializer();
34237
- if (provideInit && Node24.isIdentifier(provideInit) && provideInit.getText() === className) return true;
34535
+ if (provideInit && Node25.isIdentifier(provideInit) && provideInit.getText() === className) return true;
34238
34536
  }
34239
34537
  }
34240
34538
  }
@@ -34288,11 +34586,11 @@ function collectInterfaceGetters(sourceFile) {
34288
34586
  const out = /* @__PURE__ */ new Map();
34289
34587
  for (const iface of sourceFile.getInterfaces()) {
34290
34588
  for (const member of iface.getMembers()) {
34291
- if (Node24.isGetAccessorDeclaration(member)) {
34589
+ if (Node25.isGetAccessorDeclaration(member)) {
34292
34590
  out.set(member.getName(), iface.getName());
34293
34591
  continue;
34294
34592
  }
34295
- if (Node24.isPropertySignature(member)) {
34593
+ if (Node25.isPropertySignature(member)) {
34296
34594
  out.set(member.getName(), iface.getName());
34297
34595
  }
34298
34596
  }
@@ -34304,7 +34602,7 @@ function collectClassGetters(sourceFile) {
34304
34602
  for (const cls of sourceFile.getClasses()) {
34305
34603
  const set = /* @__PURE__ */ new Set();
34306
34604
  for (const member of cls.getMembers()) {
34307
- if (Node24.isGetAccessorDeclaration(member)) set.add(member.getName());
34605
+ if (Node25.isGetAccessorDeclaration(member)) set.add(member.getName());
34308
34606
  }
34309
34607
  if (set.size > 0) out.set(cls.getName() ?? "<anon>", set);
34310
34608
  }
@@ -34816,7 +35114,7 @@ import { resolve as resolve43 } from "node:path";
34816
35114
  import { type as type67 } from "arktype";
34817
35115
 
34818
35116
  // packages/dbx-components-mcp/src/scan/actions-extract.ts
34819
- import { Node as Node25, SyntaxKind as SyntaxKind13 } from "ts-morph";
35117
+ import { Node as Node26, SyntaxKind as SyntaxKind13 } from "ts-morph";
34820
35118
  var ACTION_MARKER = "dbxAction";
34821
35119
  var ACTION_SLUG_TAG = "dbxActionSlug";
34822
35120
  var ACTION_ROLE_TAG = "dbxActionRole";
@@ -35024,7 +35322,7 @@ function filterStates(values) {
35024
35322
  }
35025
35323
  function readEnumMemberLiteral(member) {
35026
35324
  const initializer = member.getInitializer();
35027
- if (initializer !== void 0 && (Node25.isStringLiteral(initializer) || Node25.isNoSubstitutionTemplateLiteral(initializer))) {
35325
+ if (initializer !== void 0 && (Node26.isStringLiteral(initializer) || Node26.isNoSubstitutionTemplateLiteral(initializer))) {
35028
35326
  return initializer.getLiteralText();
35029
35327
  }
35030
35328
  return member.getName();
@@ -35644,7 +35942,7 @@ import { resolve as resolve45 } from "node:path";
35644
35942
  import { type as type71 } from "arktype";
35645
35943
 
35646
35944
  // packages/dbx-components-mcp/src/scan/pipes-extract.ts
35647
- import { Node as Node26 } from "ts-morph";
35945
+ import { Node as Node27 } from "ts-morph";
35648
35946
  var PIPE_MARKER = "dbxPipe";
35649
35947
  var PIPE_SLUG_TAG = "dbxPipeSlug";
35650
35948
  var PIPE_CATEGORY_TAG = "dbxPipeCategory";
@@ -35837,7 +36135,7 @@ function readPipeDecoratorConfig(decorator) {
35837
36135
  return void 0;
35838
36136
  }
35839
36137
  const firstArg = args[0];
35840
- if (!Node26.isObjectLiteralExpression(firstArg)) {
36138
+ if (!Node27.isObjectLiteralExpression(firstArg)) {
35841
36139
  return void 0;
35842
36140
  }
35843
36141
  const name = readStringProperty(firstArg, "name");
@@ -35850,7 +36148,7 @@ function readPipeDecoratorConfig(decorator) {
35850
36148
  }
35851
36149
  function readBooleanProperty(obj, propName) {
35852
36150
  const prop = obj.getProperty(propName);
35853
- if (prop === void 0 || !Node26.isPropertyAssignment(prop)) {
36151
+ if (prop === void 0 || !Node27.isPropertyAssignment(prop)) {
35854
36152
  return void 0;
35855
36153
  }
35856
36154
  const initializer = prop.getInitializer();