@dereekb/dbx-components-mcp 13.11.7 → 13.11.8

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.7",
8
+ version: "13.11.8",
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.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",
23
+ "@dereekb/dbx-cli": "13.11.8",
24
+ "@dereekb/dbx-core": "13.11.8",
25
+ "@dereekb/dbx-firebase": "13.11.8",
26
+ "@dereekb/dbx-form": "13.11.8",
27
+ "@dereekb/dbx-web": "13.11.8",
28
+ "@dereekb/firebase": "13.11.8",
29
+ "@dereekb/firebase-server": "13.11.8",
30
+ "@dereekb/rxjs": "13.11.8",
31
+ "@dereekb/util": "13.11.8",
32
32
  "@uirouter/angular": "21.0.0",
33
33
  rxjs: "^7.8.2"
34
34
  },
35
35
  devDependencies: {
36
- "@dereekb/model": "13.11.7"
36
+ "@dereekb/model": "13.11.8"
37
37
  }
38
38
  };
39
39
 
@@ -3253,7 +3253,8 @@ var DbxMcpConfig = type16({
3253
3253
  version: "1",
3254
3254
  "modelValidate?": {
3255
3255
  "maxFieldNameLength?": "number>=1",
3256
- "ignoredFieldNames?": "string[]"
3256
+ "ignoredFieldNames?": "string[]",
3257
+ "ignoredExternalParents?": "string[]"
3257
3258
  },
3258
3259
  "semanticTypes?": ClusterSection,
3259
3260
  "uiComponents?": ClusterSection,
@@ -8066,7 +8067,9 @@ function assembleFile(input) {
8066
8067
  const fields = buildFields({
8067
8068
  converter,
8068
8069
  inheritedProps,
8069
- enumNames
8070
+ enumNames,
8071
+ subObjectConstIndex: input.subObjectConstIndex,
8072
+ subObjectInterfaceIndex: input.subObjectInterfaceIndex
8070
8073
  });
8071
8074
  const referencedEnums = new Set(fields.flatMap((f) => f.enumRef ? [f.enumRef] : []));
8072
8075
  const relevantEnums = input.enums.filter((e) => referencedEnums.has(e.name));
@@ -8119,6 +8122,12 @@ function buildFields(input) {
8119
8122
  const enumRef = enumFromType ?? enumFromConverter;
8120
8123
  const optional = prop?.optional ?? f.converter.startsWith("optionalFirestore");
8121
8124
  const longName = resolveLongName(f.key, prop?.longName);
8125
+ const subObject = resolveFieldSubObject({
8126
+ converter: f.converter,
8127
+ subObjectConstIndex: input.subObjectConstIndex,
8128
+ subObjectInterfaceIndex: input.subObjectInterfaceIndex,
8129
+ enumNames: input.enumNames
8130
+ });
8122
8131
  const field = {
8123
8132
  name: f.key,
8124
8133
  longName,
@@ -8127,12 +8136,126 @@ function buildFields(input) {
8127
8136
  optional,
8128
8137
  ...prop?.description ? { description: prop.description } : {},
8129
8138
  ...enumRef ? { enumRef } : {},
8130
- ...prop?.syncFlag ? { syncFlag: prop.syncFlag } : {}
8139
+ ...prop?.syncFlag ? { syncFlag: prop.syncFlag } : {},
8140
+ ...subObject ? { subObject } : {}
8131
8141
  };
8132
8142
  out.push(field);
8133
8143
  }
8134
8144
  return out;
8135
8145
  }
8146
+ function resolveFieldSubObject(input) {
8147
+ const { converter, subObjectConstIndex, subObjectInterfaceIndex, enumNames } = input;
8148
+ if (!subObjectConstIndex || !subObjectInterfaceIndex) {
8149
+ return void 0;
8150
+ }
8151
+ const resolved = resolveSubObjectReference(converter, subObjectConstIndex);
8152
+ if (!resolved) {
8153
+ return void 0;
8154
+ }
8155
+ const iface = subObjectInterfaceIndex.get(resolved.interfaceName);
8156
+ if (!iface) {
8157
+ return void 0;
8158
+ }
8159
+ const fields = buildSubObjectFields({ iface, subObjectConstIndex, subObjectInterfaceIndex, enumNames, visited: /* @__PURE__ */ new Set([resolved.interfaceName]) });
8160
+ return { interfaceName: resolved.interfaceName, factoryKind: resolved.factoryKind, fields };
8161
+ }
8162
+ var INLINE_SUB_OBJECT_RE = /^(firestoreSubObject|firestoreObjectArray|firestoreMap)\s*<\s*([A-Za-z_$][A-Za-z0-9_$]*)\s*>/;
8163
+ var WRAPPED_OBJECT_FIELD_RE = /^(firestoreObjectArray|firestoreMap)\s*\(\s*\{\s*objectField:\s*([A-Za-z_$][A-Za-z0-9_$]*)/;
8164
+ function resolveSubObjectReference(converter, index) {
8165
+ let result;
8166
+ const trimmed = converter.trim();
8167
+ const inline = INLINE_SUB_OBJECT_RE.exec(trimmed);
8168
+ if (inline) {
8169
+ result = { interfaceName: inline[2], factoryKind: FACTORY_KIND_BY_NAME[inline[1]] };
8170
+ } else {
8171
+ const wrapped = WRAPPED_OBJECT_FIELD_RE.exec(trimmed);
8172
+ if (wrapped) {
8173
+ const entry = index.get(wrapped[2]);
8174
+ if (entry) {
8175
+ const outerKind = FACTORY_KIND_BY_NAME[wrapped[1]];
8176
+ result = { interfaceName: entry.interfaceName, factoryKind: outerKind };
8177
+ }
8178
+ } else {
8179
+ const entry = index.get(trimmed);
8180
+ if (entry) {
8181
+ result = { interfaceName: entry.interfaceName, factoryKind: entry.factoryKind };
8182
+ }
8183
+ }
8184
+ }
8185
+ return result;
8186
+ }
8187
+ var FACTORY_KIND_BY_NAME = {
8188
+ firestoreSubObject: "object",
8189
+ firestoreObjectArray: "array",
8190
+ firestoreMap: "map"
8191
+ };
8192
+ function buildSubObjectFields(input) {
8193
+ const out = [];
8194
+ for (const prop of input.iface.props) {
8195
+ out.push(buildSubObjectField({ prop, ...input }));
8196
+ }
8197
+ return out;
8198
+ }
8199
+ function buildSubObjectField(input) {
8200
+ const { prop, subObjectConstIndex, subObjectInterfaceIndex, enumNames, visited } = input;
8201
+ const enumRef = prop.tsType ? findEnumInType(prop.tsType, enumNames) : void 0;
8202
+ const longName = resolveLongName(prop.name, prop.longName);
8203
+ const nested = resolveNestedSubObjectFromType({ tsType: prop.tsType, subObjectConstIndex, subObjectInterfaceIndex, enumNames, visited });
8204
+ const field = {
8205
+ name: prop.name,
8206
+ longName,
8207
+ converter: "",
8208
+ ...prop.tsType ? { tsType: prop.tsType } : {},
8209
+ optional: prop.optional,
8210
+ ...prop.description ? { description: prop.description } : {},
8211
+ ...enumRef ? { enumRef } : {},
8212
+ ...prop.syncFlag ? { syncFlag: prop.syncFlag } : {},
8213
+ ...nested ? { subObject: nested } : {}
8214
+ };
8215
+ return field;
8216
+ }
8217
+ function resolveNestedSubObjectFromType(input) {
8218
+ const { tsType, subObjectInterfaceIndex, visited } = input;
8219
+ if (!tsType) return void 0;
8220
+ const peeled = peelArrayAndMaybe(tsType.trim());
8221
+ if (!peeled) return void 0;
8222
+ if (visited.has(peeled.name)) return void 0;
8223
+ const iface = subObjectInterfaceIndex.get(peeled.name);
8224
+ if (!iface) return void 0;
8225
+ const nestedVisited = new Set(visited);
8226
+ nestedVisited.add(peeled.name);
8227
+ const fields = buildSubObjectFields({
8228
+ iface,
8229
+ subObjectConstIndex: input.subObjectConstIndex,
8230
+ subObjectInterfaceIndex,
8231
+ enumNames: input.enumNames,
8232
+ visited: nestedVisited
8233
+ });
8234
+ return { interfaceName: peeled.name, factoryKind: peeled.array ? "array" : "object", fields };
8235
+ }
8236
+ function peelArrayAndMaybe(raw) {
8237
+ let current = raw;
8238
+ let array = false;
8239
+ const maybeMatch = /^Maybe<\s*(.+)\s*>$/.exec(current);
8240
+ if (maybeMatch) {
8241
+ current = maybeMatch[1].trim();
8242
+ }
8243
+ const readonlyArrayMatch = /^ReadonlyArray<\s*(.+)\s*>$/.exec(current);
8244
+ if (readonlyArrayMatch) {
8245
+ current = readonlyArrayMatch[1].trim();
8246
+ array = true;
8247
+ } else {
8248
+ const arrayMatch = /^(?:readonly\s+)?(.+?)(\s*\[\s*\])$/.exec(current);
8249
+ if (arrayMatch) {
8250
+ current = arrayMatch[1].trim();
8251
+ array = true;
8252
+ }
8253
+ }
8254
+ if (!/^[A-Z][A-Za-z0-9_$]*$/.test(current)) {
8255
+ return void 0;
8256
+ }
8257
+ return { name: current, array };
8258
+ }
8136
8259
  function resolveLongName(fieldName, propLongName) {
8137
8260
  let result;
8138
8261
  if (propLongName && LONG_NAME_RE.test(propLongName)) {
@@ -8314,14 +8437,18 @@ function peelTypeNode(node) {
8314
8437
  }
8315
8438
  function readInterfaceTags(jsDocs) {
8316
8439
  let dbxModel = false;
8440
+ let dbxModelSubObject = false;
8317
8441
  for (const jsDoc of jsDocs) {
8318
8442
  for (const tag of jsDoc.getTags()) {
8319
- if (tag.getTagName() === "dbxModel") {
8443
+ const tagName = tag.getTagName();
8444
+ if (tagName === "dbxModel") {
8320
8445
  dbxModel = true;
8446
+ } else if (tagName === "dbxModelSubObject") {
8447
+ dbxModelSubObject = true;
8321
8448
  }
8322
8449
  }
8323
8450
  }
8324
- return { dbxModel };
8451
+ return { dbxModel, dbxModelSubObject };
8325
8452
  }
8326
8453
  function readPropertyTags2(jsDocs) {
8327
8454
  let dbxModelVariable;
@@ -8526,6 +8653,40 @@ function extractGroupModelNames(text) {
8526
8653
  return [...seen].sort((a, b) => a.localeCompare(b));
8527
8654
  }
8528
8655
 
8656
+ // packages/dbx-components-mcp/src/scan/extract-models/find-sub-object-consts.ts
8657
+ import { Node as Node11 } from "ts-morph";
8658
+ var SUB_OBJECT_FACTORY_NAMES = /* @__PURE__ */ new Set(["firestoreSubObject", "firestoreObjectArray", "firestoreMap"]);
8659
+ function findSubObjectConsts(sf) {
8660
+ const out = [];
8661
+ for (const statement of sf.getVariableStatements()) {
8662
+ for (const decl of statement.getDeclarations()) {
8663
+ const entry = readSubObjectConst(decl);
8664
+ if (entry) out.push(entry);
8665
+ }
8666
+ }
8667
+ return out;
8668
+ }
8669
+ function readSubObjectConst(decl) {
8670
+ const initializer = decl.getInitializer();
8671
+ if (!initializer || !Node11.isCallExpression(initializer)) return void 0;
8672
+ const expr = initializer.getExpression();
8673
+ if (!Node11.isIdentifier(expr)) return void 0;
8674
+ const factoryName = expr.getText();
8675
+ if (!SUB_OBJECT_FACTORY_NAMES.has(factoryName)) return void 0;
8676
+ const interfaceName = readInterfaceTypeArg2(initializer);
8677
+ if (!interfaceName) return void 0;
8678
+ return { constName: decl.getName(), interfaceName, factoryName };
8679
+ }
8680
+ function readInterfaceTypeArg2(call) {
8681
+ const typeArgs = call.getTypeArguments();
8682
+ if (typeArgs.length === 0) return void 0;
8683
+ const first = typeArgs[0];
8684
+ if (!Node11.isTypeReference(first)) return void 0;
8685
+ const nameNode = first.getTypeName();
8686
+ if (!Node11.isIdentifier(nameNode)) return void 0;
8687
+ return nameNode.getText();
8688
+ }
8689
+
8529
8690
  // packages/dbx-components-mcp/src/scan/extract-models/infer-collection-kind.ts
8530
8691
  var COLLECTION_CALL_RE = /\.(firestoreCollection|rootSingleItemFirestoreCollection|firestoreCollectionWithParent|singleItemFirestoreCollection)\s*\(/g;
8531
8692
  var KIND_BY_METHOD = {
@@ -8571,14 +8732,37 @@ async function extractModels(input) {
8571
8732
  const models = [];
8572
8733
  const modelGroups = [];
8573
8734
  const errors = [];
8735
+ const subObjectConstIndex = /* @__PURE__ */ new Map();
8736
+ const subObjectInterfaceIndex = /* @__PURE__ */ new Map();
8737
+ const parsedFiles = [];
8574
8738
  for (const filePath of files) {
8575
8739
  const sourceFileRel = relative3(baseDir, filePath).split(sep3).join(posix.sep);
8576
8740
  try {
8577
8741
  const text = await readFile2(filePath, "utf8");
8578
- if (!text.includes("firestoreModelIdentity(") && !text.includes("@dbxModelGroup")) {
8742
+ const hasModelMarker = text.includes("firestoreModelIdentity(") || text.includes("@dbxModelGroup");
8743
+ const hasSubObjectMarker = text.includes("@dbxModelSubObject") || text.includes("firestoreSubObject") || text.includes("firestoreObjectArray") || text.includes("firestoreMap");
8744
+ if (!hasModelMarker && !hasSubObjectMarker) {
8579
8745
  continue;
8580
8746
  }
8581
- const sf = project.createSourceFile(`/scan/${basename2(filePath)}-${models.length}-${modelGroups.length}.ts`, text, { overwrite: true });
8747
+ const sf = project.createSourceFile(`/scan/${basename2(filePath)}-${parsedFiles.length}.ts`, text, { overwrite: true });
8748
+ parsedFiles.push({ filePath, sourceFileRel, sf, hasModelMarker });
8749
+ for (const c of findSubObjectConsts(sf)) {
8750
+ if (!subObjectConstIndex.has(c.constName)) {
8751
+ subObjectConstIndex.set(c.constName, { interfaceName: c.interfaceName, factoryKind: c.factoryName === "firestoreSubObject" ? "object" : c.factoryName === "firestoreObjectArray" ? "array" : "map" });
8752
+ }
8753
+ }
8754
+ for (const iface of findInterfaces(sf)) {
8755
+ if (iface.tags.dbxModelSubObject && !subObjectInterfaceIndex.has(iface.name)) {
8756
+ subObjectInterfaceIndex.set(iface.name, iface);
8757
+ }
8758
+ }
8759
+ } catch (error) {
8760
+ errors.push({ sourceFile: sourceFileRel, message: error instanceof Error ? error.message : String(error) });
8761
+ }
8762
+ }
8763
+ for (const { sourceFileRel, sf, hasModelMarker } of parsedFiles) {
8764
+ if (!hasModelMarker) continue;
8765
+ try {
8582
8766
  const assembled = assembleFile({
8583
8767
  sourcePackage,
8584
8768
  sourceFile: sourceFileRel,
@@ -8587,7 +8771,9 @@ async function extractModels(input) {
8587
8771
  converters: findConverters(sf),
8588
8772
  enums: findEnums(sf),
8589
8773
  modelGroups: findModelGroups(sf),
8590
- factoryKinds: findCollectionFactoryCalls(sf)
8774
+ factoryKinds: findCollectionFactoryCalls(sf),
8775
+ subObjectConstIndex,
8776
+ subObjectInterfaceIndex
8591
8777
  });
8592
8778
  for (const m of assembled.models) models.push(m);
8593
8779
  for (const g of assembled.modelGroups) modelGroups.push(g);
@@ -13041,15 +13227,44 @@ function applyFieldsFilter(model, filter) {
13041
13227
  for (const field of model.fields) {
13042
13228
  const nameLower = field.name.toLowerCase();
13043
13229
  const longNameLower = field.longName.toLowerCase();
13044
- if (filterSet.has(nameLower) || filterSet.has(longNameLower)) {
13230
+ let keep = false;
13231
+ if (filterSet.has(nameLower)) {
13232
+ matched.add(nameLower);
13233
+ keep = true;
13234
+ }
13235
+ if (filterSet.has(longNameLower)) {
13236
+ matched.add(longNameLower);
13237
+ keep = true;
13238
+ }
13239
+ if (field.subObject !== void 0 && subObjectMatches(field.subObject, filterSet, matched)) {
13240
+ keep = true;
13241
+ }
13242
+ if (keep) {
13045
13243
  kept.push(field);
13046
- if (filterSet.has(nameLower)) matched.add(nameLower);
13047
- if (filterSet.has(longNameLower)) matched.add(longNameLower);
13048
13244
  }
13049
13245
  }
13050
13246
  const unmatchedFilters = filter.filter((entry) => !matched.has(entry));
13051
13247
  return { kept, unmatchedFilters };
13052
13248
  }
13249
+ function subObjectMatches(subObject, filterSet, matched) {
13250
+ let any = false;
13251
+ for (const field of subObject.fields) {
13252
+ const nameLower = field.name.toLowerCase();
13253
+ const longNameLower = field.longName.toLowerCase();
13254
+ if (filterSet.has(nameLower)) {
13255
+ matched.add(nameLower);
13256
+ any = true;
13257
+ }
13258
+ if (filterSet.has(longNameLower)) {
13259
+ matched.add(longNameLower);
13260
+ any = true;
13261
+ }
13262
+ if (field.subObject !== void 0 && subObjectMatches(field.subObject, filterSet, matched)) {
13263
+ any = true;
13264
+ }
13265
+ }
13266
+ return any;
13267
+ }
13053
13268
  function firebaseModelStoreShape(model) {
13054
13269
  const result = model.parentIdentityConst ? "sub-collection" : "root";
13055
13270
  return result;
@@ -13098,18 +13313,66 @@ function appendFieldsTable(lines, fields, depth) {
13098
13313
  lines.push("| Field | Description |", "|-------|-------------|");
13099
13314
  for (const field of fields) {
13100
13315
  const desc = describeField(field);
13101
- lines.push(`| \`${field.name}\` | ${desc} |`);
13316
+ lines.push(`| \`${formatFieldLabel(field)}\` | ${desc} |`);
13102
13317
  }
13103
13318
  } else {
13104
13319
  lines.push("| Field | Description | Type | Converter |", "|-------|-------------|------|-----------|");
13105
13320
  for (const field of fields) {
13106
13321
  const desc = describeField(field);
13107
13322
  const ts = field.tsType ? `\`${field.tsType}\`` : "\u2013";
13108
- const conv = `\`${field.converter}\``;
13109
- lines.push(`| \`${field.name}\` | ${desc} | ${ts} | ${conv} |`);
13323
+ const conv = field.converter.length > 0 ? `\`${field.converter}\`` : "\u2013";
13324
+ lines.push(`| \`${formatFieldLabel(field)}\` | ${desc} | ${ts} | ${conv} |`);
13325
+ }
13326
+ }
13327
+ appendSubObjectSections(lines, fields, depth);
13328
+ }
13329
+ function formatFieldLabel(field) {
13330
+ if (field.longName && field.longName !== field.name) {
13331
+ return `${field.name} (${field.longName})`;
13332
+ }
13333
+ return field.name;
13334
+ }
13335
+ function appendSubObjectSections(lines, fields, depth) {
13336
+ for (const field of fields) {
13337
+ if (field.subObject === void 0) continue;
13338
+ appendSubObjectSection({ lines, parentLabel: formatFieldLabel(field), subObject: field.subObject, depth, headingLevel: 3 });
13339
+ }
13340
+ }
13341
+ function appendSubObjectSection(input) {
13342
+ const { lines, parentLabel, subObject, depth, headingLevel } = input;
13343
+ const heading = "#".repeat(Math.min(Math.max(headingLevel, 2), 6));
13344
+ const kindLabel = SUB_OBJECT_KIND_LABEL[subObject.factoryKind];
13345
+ lines.push("", `${heading} Sub-object: \`${parentLabel}\` \u2192 \`${subObject.interfaceName}\` (${kindLabel})`, "");
13346
+ if (depth === "brief") {
13347
+ lines.push("| Field | Description |", "|-------|-------------|");
13348
+ for (const field of subObject.fields) {
13349
+ const desc = describeField(field);
13350
+ lines.push(`| \`${formatFieldLabel(field)}\` | ${desc} |`);
13351
+ }
13352
+ } else {
13353
+ lines.push("| Field | Description | Type |", "|-------|-------------|------|");
13354
+ for (const field of subObject.fields) {
13355
+ const desc = describeField(field);
13356
+ const ts = field.tsType ? `\`${field.tsType}\`` : "\u2013";
13357
+ lines.push(`| \`${formatFieldLabel(field)}\` | ${desc} | ${ts} |`);
13110
13358
  }
13111
13359
  }
13360
+ for (const field of subObject.fields) {
13361
+ if (field.subObject === void 0) continue;
13362
+ appendSubObjectSection({
13363
+ lines,
13364
+ parentLabel: `${parentLabel}.${formatFieldLabel(field)}`,
13365
+ subObject: field.subObject,
13366
+ depth,
13367
+ headingLevel: headingLevel + 1
13368
+ });
13369
+ }
13112
13370
  }
13371
+ var SUB_OBJECT_KIND_LABEL = {
13372
+ object: "embedded object",
13373
+ array: "embedded array",
13374
+ map: "embedded map"
13375
+ };
13113
13376
  function describeField(field) {
13114
13377
  return (field.description ?? "\u2013").replaceAll("|", String.raw`\|`).replaceAll("\n", " ");
13115
13378
  }
@@ -13407,7 +13670,7 @@ var DBX_MODEL_LOOKUP_TOOL = {
13407
13670
  "Optional inputs:",
13408
13671
  ' \u2022 `scope`: `"all"` (default), `"upstream"` (only `@dereekb/firebase`), or `"downstream"` (only component packages).',
13409
13672
  " \u2022 `componentDirs`: explicit downstream package directories \u2014 overrides the default `components/*-firebase` discovery.",
13410
- ' \u2022 `fields`: when the topic resolves to a single model, restrict the rendered fields table to those whose persisted name (e.g. `"fs"`) or longName (e.g. `"fileState"`) appears in the list (case-insensitive). Enums prune to only those referenced by the kept fields. Ignored on catalog/shapes/not-found responses.'
13673
+ ' \u2022 `fields`: when the topic resolves to a single model, restrict the rendered fields table to those whose persisted name (e.g. `"fs"`) or longName (e.g. `"fileState"`) appears in the list (case-insensitive). Filters also match against `@dbxModelSubObject` field names / longNames reachable through a parent field\'s `firestoreSubObject<T>` / `firestoreObjectArray<T>` / `firestoreMap<T>` converter \u2014 the parent field is kept whenever any of its nested sub-object fields match. Enums prune to only those referenced by the kept fields. Ignored on catalog/shapes/not-found responses.'
13411
13674
  ].join("\n"),
13412
13675
  inputSchema: {
13413
13676
  type: "object",
@@ -13950,29 +14213,35 @@ function matchPrefix(value, prefixes) {
13950
14213
  var DBX_MODEL_DECODE_TOOL = {
13951
14214
  name: "dbx_model_decode",
13952
14215
  description: [
13953
- "Decode a raw @dereekb/firebase Firestore document \u2014 identify the model, expand abbreviated field names to their descriptions, decode enum integer values, and surface foreign-key relationships to other models.",
14216
+ "Decode a @dereekb/firebase Firestore document or model key.",
14217
+ "",
14218
+ 'Document mode \u2014 pass `data` as a JSON string (copied straight from the Firestore console) or an already-parsed object to identify the model, expand abbreviated field names, decode enum integer values, and surface foreign-key relationships. Optionally pass `model` to skip detection and target a specific model by interface name (`"StorageFile"`), identity constant (`"storageFileIdentity"`), `modelType` (`"storageFile"`), or collection prefix (`"sf"`).',
13954
14219
  "",
13955
- 'Pass `data` as either a JSON string (copied straight from the Firestore console) or an already-parsed object. Pass `model` to skip detection and target a specific model by interface name (`"StorageFile"`), identity constant (`"storageFileIdentity"`), `modelType` (`"storageFile"`), or collection prefix (`"sf"`).',
14220
+ 'Key mode \u2014 pass just `key` (e.g. `"jwr/hkzQa9W6MpaP99RTlQJcImbWdZm2"`) to resolve the model identity and id from the collection prefix alone, no document required. Subcollection paths like `"nb/abc/nbn/def"` are walked end-to-end so the leaf model is reported alongside its parent chain.',
13956
14221
  "",
13957
- "Auto-detection uses the document's key field (if any), then falls back to scoring each registered model by how many of its distinctive fields are present."
14222
+ "At least one of `data` or `key` is required."
13958
14223
  ].join("\n"),
13959
14224
  inputSchema: {
13960
14225
  type: "object",
13961
14226
  properties: {
13962
14227
  data: {
13963
- description: "Raw Firestore document \u2014 JSON string or already-parsed object.",
14228
+ description: "Raw Firestore document \u2014 JSON string or already-parsed object. Required for document mode.",
13964
14229
  oneOf: [{ type: "string" }, { type: "object" }]
13965
14230
  },
14231
+ key: {
14232
+ type: "string",
14233
+ description: 'Firestore model key (e.g. `"sf/abc123"` or subcollection path `"nb/abc/nbn/def"`). Used as the sole input in key mode, or as an extra detection hint when paired with `data`.'
14234
+ },
13966
14235
  model: {
13967
14236
  type: "string",
13968
14237
  description: "Optional model hint \u2014 interface name, identity const, model type, or collection prefix."
13969
14238
  }
13970
- },
13971
- required: ["data"]
14239
+ }
13972
14240
  }
13973
14241
  };
13974
14242
  var DecodeArgsType = type36({
13975
- data: "string | object",
14243
+ "data?": "string | object",
14244
+ "key?": "string",
13976
14245
  "model?": "string"
13977
14246
  });
13978
14247
  function parseDecodeArgs(raw) {
@@ -13982,6 +14251,7 @@ function parseDecodeArgs(raw) {
13982
14251
  }
13983
14252
  const result = {
13984
14253
  data: parsed.data,
14254
+ key: parsed.key,
13985
14255
  model: parsed.model
13986
14256
  };
13987
14257
  return result;
@@ -14055,6 +14325,78 @@ function buildPrefixMap() {
14055
14325
  }
14056
14326
  return out;
14057
14327
  }
14328
+ function decodeKeyPath(key, hint) {
14329
+ const trimmed = key.trim();
14330
+ if (trimmed.length === 0) {
14331
+ return { error: "Key is empty. Provide a Firestore key like `sf/abc123`." };
14332
+ }
14333
+ const segments = trimmed.split("/").filter((s) => s.length > 0);
14334
+ if (segments.length < 2 || segments.length % 2 !== 0) {
14335
+ return {
14336
+ error: `Invalid Firestore key '${trimmed}'. Expected an even number of segments (\`prefix/id\` pairs). Got ${segments.length} segment(s).`
14337
+ };
14338
+ }
14339
+ const decoded = [];
14340
+ const unresolved = [];
14341
+ for (let i = 0; i < segments.length; i += 2) {
14342
+ const prefix = segments[i];
14343
+ const id = segments[i + 1];
14344
+ const model = getFirebaseModelByPrefix(prefix);
14345
+ if (!model) {
14346
+ unresolved.push(prefix);
14347
+ }
14348
+ decoded.push({ prefix, id, model });
14349
+ }
14350
+ let leaf = decoded[decoded.length - 1];
14351
+ if (!leaf.model && hint) {
14352
+ const fromHint = getFirebaseModel(hint) ?? getFirebaseModelByPrefix(hint);
14353
+ if (fromHint) {
14354
+ leaf = { prefix: leaf.prefix, id: leaf.id, model: fromHint };
14355
+ }
14356
+ }
14357
+ const ancestors2 = decoded.slice(0, -1);
14358
+ return { leaf, ancestors: ancestors2, unresolvedPrefixes: unresolved };
14359
+ }
14360
+ function formatKeyDecode(input, rawKey) {
14361
+ const lines = [];
14362
+ lines.push("_Model decoded from key prefix._", "");
14363
+ const leaf = input.leaf;
14364
+ if (leaf.model) {
14365
+ lines.push(`**Leaf:** ${leaf.model.name}`);
14366
+ lines.push(`- identityConst: \`${leaf.model.identityConst}\``);
14367
+ lines.push(`- modelType: \`${leaf.model.modelType}\``);
14368
+ lines.push(`- prefix: \`${leaf.prefix}\``);
14369
+ lines.push(`- id: \`${leaf.id}\``);
14370
+ if (leaf.model.modelGroup) {
14371
+ lines.push(`- modelGroup: ${leaf.model.modelGroup}`);
14372
+ }
14373
+ if (leaf.model.parentIdentityConst) {
14374
+ lines.push(`- parentIdentityConst: \`${leaf.model.parentIdentityConst}\``);
14375
+ }
14376
+ lines.push(`- source: \`${leaf.model.sourcePackage}\` (${leaf.model.sourceFile})`);
14377
+ } else {
14378
+ lines.push(`**Leaf:** _unknown_ \u2014 no model registered for prefix \`${leaf.prefix}\``);
14379
+ lines.push(`- prefix: \`${leaf.prefix}\``);
14380
+ lines.push(`- id: \`${leaf.id}\``);
14381
+ }
14382
+ if (input.ancestors.length > 0) {
14383
+ lines.push("", "**Parent chain:**");
14384
+ for (const ancestor of input.ancestors) {
14385
+ if (ancestor.model) {
14386
+ lines.push(`- ${ancestor.model.name} \u2014 prefix \`${ancestor.prefix}\`, id \`${ancestor.id}\``);
14387
+ } else {
14388
+ lines.push(`- _unknown_ \u2014 prefix \`${ancestor.prefix}\` (id \`${ancestor.id}\`)`);
14389
+ }
14390
+ }
14391
+ }
14392
+ if (input.unresolvedPrefixes.length > 0) {
14393
+ const label = input.unresolvedPrefixes.length === 1 ? "prefix" : "prefixes";
14394
+ const list = input.unresolvedPrefixes.map((p) => `\`${p}\``).join(", ");
14395
+ lines.push("", `_Unresolved ${label}: ${list}. Run \`dbx_model_lookup\` to browse known models._`);
14396
+ }
14397
+ lines.push("", `_Key:_ \`${rawKey}\``);
14398
+ return lines.join("\n");
14399
+ }
14058
14400
  function runModelDecode(rawArgs) {
14059
14401
  let args;
14060
14402
  try {
@@ -14063,6 +14405,18 @@ function runModelDecode(rawArgs) {
14063
14405
  const message = err instanceof Error ? err.message : String(err);
14064
14406
  return toolError(message);
14065
14407
  }
14408
+ if (args.data === void 0 && args.key === void 0) {
14409
+ return toolError("Provide either `data` (a Firestore document) or `key` (a Firestore model key).");
14410
+ }
14411
+ if (args.data === void 0 && typeof args.key === "string") {
14412
+ const decoded = decodeKeyPath(args.key, args.model);
14413
+ if ("error" in decoded) {
14414
+ return toolError(decoded.error);
14415
+ }
14416
+ const text2 = formatKeyDecode(decoded, args.key);
14417
+ const result2 = { content: [{ type: "text", text: text2 }] };
14418
+ return result2;
14419
+ }
14066
14420
  let document;
14067
14421
  try {
14068
14422
  document = coerceToDocument(args.data);
@@ -14070,15 +14424,16 @@ function runModelDecode(rawArgs) {
14070
14424
  const message = err instanceof Error ? err.message : String(err);
14071
14425
  return toolError(message);
14072
14426
  }
14073
- const detection = detectModel(document.doc, document.extraKey, args.model);
14427
+ const extraKey = args.key ?? document.extraKey;
14428
+ const detection = detectModel(document.doc, extraKey, args.model);
14074
14429
  if (!detection) {
14075
- const message = buildUnmatchedMessage(args.model, document);
14430
+ const message = buildUnmatchedMessage(args.model, { ...document, extraKey });
14076
14431
  const result2 = { content: [{ type: "text", text: message }] };
14077
14432
  return result2;
14078
14433
  }
14079
14434
  const prefixes = buildPrefixMap();
14080
14435
  const header = buildDetectionHeader(detection);
14081
- const body = formatDecode({ model: detection.model, doc: document.doc, prefixes, extraKey: document.extraKey });
14436
+ const body = formatDecode({ model: detection.model, doc: document.doc, prefixes, extraKey });
14082
14437
  const text = `${header}
14083
14438
 
14084
14439
  ${body}`;
@@ -14279,13 +14634,13 @@ function createListAppTool(config) {
14279
14634
  }
14280
14635
 
14281
14636
  // packages/dbx-components-mcp/src/tools/model-validate/extract.ts
14282
- import { Node as Node11, Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
14637
+ import { Node as Node12, Project as Project4, SyntaxKind as SyntaxKind4 } from "ts-morph";
14283
14638
 
14284
14639
  // packages/dbx-components-mcp/src/tools/model-validate/types.ts
14285
14640
  var MAX_FIELD_NAME_LENGTH = 5;
14286
14641
  var ROOT_MODEL_ORDER = ["identity", "interface", "rolesType", "documentClass", "converter", "referenceFn", "collectionType", "collectionFn"];
14287
14642
  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"];
14643
+ var SUB_OBJECT_FACTORY_NAMES2 = ["firestoreSubObject", "firestoreObjectArray", "firestoreMap"];
14289
14644
 
14290
14645
  // packages/dbx-components-mcp/src/tools/model-validate/extract.ts
14291
14646
  function extractFile(source) {
@@ -14311,10 +14666,10 @@ function extractFile(source) {
14311
14666
  }
14312
14667
  function findSubObjectFactoryCalls(sourceFile) {
14313
14668
  const out = [];
14314
- const factorySet = new Set(SUB_OBJECT_FACTORY_NAMES);
14669
+ const factorySet = new Set(SUB_OBJECT_FACTORY_NAMES2);
14315
14670
  for (const call of sourceFile.getDescendantsOfKind(SyntaxKind4.CallExpression)) {
14316
14671
  const expr = call.getExpression();
14317
- if (!Node11.isIdentifier(expr)) {
14672
+ if (!Node12.isIdentifier(expr)) {
14318
14673
  continue;
14319
14674
  }
14320
14675
  const factoryName = expr.getText();
@@ -14338,11 +14693,11 @@ function findSubObjectFactoryCalls(sourceFile) {
14338
14693
  return out;
14339
14694
  }
14340
14695
  function readTypeReferenceIdentifier(typeNode) {
14341
- if (!Node11.isTypeReference(typeNode)) {
14696
+ if (!Node12.isTypeReference(typeNode)) {
14342
14697
  return void 0;
14343
14698
  }
14344
14699
  const nameNode = typeNode.getTypeName();
14345
- if (!Node11.isIdentifier(nameNode)) {
14700
+ if (!Node12.isIdentifier(nameNode)) {
14346
14701
  return void 0;
14347
14702
  }
14348
14703
  return nameNode.getText();
@@ -14358,10 +14713,49 @@ function findDataInterfaces(sourceFile, groupInterface) {
14358
14713
  const fields = extractInterfaceFields(iface);
14359
14714
  const dbxModelTag = readDbxModelTag(iface.getJsDocs());
14360
14715
  const dbxModelSubObjectTag = readDbxModelSubObjectTag(iface.getJsDocs());
14361
- out.push({ name, line: iface.getStartLineNumber(), dbxModelTag, dbxModelSubObjectTag, fields });
14716
+ const extendsNames = readExtendsNames(iface);
14717
+ out.push({ name, line: iface.getStartLineNumber(), dbxModelTag, dbxModelSubObjectTag, extendsNames, fields });
14362
14718
  }
14363
14719
  return out;
14364
14720
  }
14721
+ function readExtendsNames(iface) {
14722
+ const out = [];
14723
+ for (const expr of iface.getExtends()) {
14724
+ const head = expr.getExpression().getText();
14725
+ let resolved = head;
14726
+ if (PASSTHROUGH_TYPE_WRAPPERS2.has(head)) {
14727
+ const typeArgs = expr.getTypeArguments();
14728
+ if (typeArgs.length > 0) {
14729
+ const peeled = peelExtendsTypeNode(typeArgs[0]);
14730
+ if (peeled !== void 0) {
14731
+ resolved = peeled;
14732
+ }
14733
+ }
14734
+ }
14735
+ out.push(resolved);
14736
+ }
14737
+ return out;
14738
+ }
14739
+ var PASSTHROUGH_TYPE_WRAPPERS2 = /* @__PURE__ */ new Set(["Partial", "Required", "Readonly", "NonNullable", "MaybeMap", "Pick", "Omit"]);
14740
+ function peelExtendsTypeNode(node) {
14741
+ let current = node;
14742
+ while (Node12.isParenthesizedTypeNode(current)) {
14743
+ current = current.getTypeNode();
14744
+ }
14745
+ let result;
14746
+ if (Node12.isTypeReference(current)) {
14747
+ const name = current.getTypeName().getText();
14748
+ if (PASSTHROUGH_TYPE_WRAPPERS2.has(name)) {
14749
+ const inner = current.getTypeArguments();
14750
+ if (inner.length > 0) {
14751
+ result = peelExtendsTypeNode(inner[0]);
14752
+ }
14753
+ } else {
14754
+ result = name;
14755
+ }
14756
+ }
14757
+ return result;
14758
+ }
14365
14759
  function extractInterfaceFields(iface) {
14366
14760
  const fields = [];
14367
14761
  for (const prop of iface.getProperties()) {
@@ -14478,7 +14872,7 @@ function extractIdentityRefs(alias) {
14478
14872
  if (!typeNode) {
14479
14873
  return refs;
14480
14874
  }
14481
- if (Node11.isTypeQuery(typeNode)) {
14875
+ if (Node12.isTypeQuery(typeNode)) {
14482
14876
  refs.push(typeNode.getExprName().getText());
14483
14877
  }
14484
14878
  const typeofNodes = typeNode.getDescendantsOfKind(SyntaxKind4.TypeQuery);
@@ -14492,7 +14886,7 @@ function findIdentities2(sourceFile) {
14492
14886
  for (const statement of sourceFile.getVariableStatements()) {
14493
14887
  for (const decl of statement.getDeclarations()) {
14494
14888
  const initializer = decl.getInitializer();
14495
- if (!initializer || !Node11.isCallExpression(initializer)) {
14889
+ if (!initializer || !Node12.isCallExpression(initializer)) {
14496
14890
  continue;
14497
14891
  }
14498
14892
  if (initializer.getExpression().getText() !== "firestoreModelIdentity") {
@@ -14528,7 +14922,7 @@ function parseIdentityArgs(args) {
14528
14922
  }
14529
14923
  if (args.length === 3) {
14530
14924
  const [parentNode, nameNode, prefixNode] = args;
14531
- const parentRef = Node11.isIdentifier(parentNode) ? parentNode.getText() : void 0;
14925
+ const parentRef = Node12.isIdentifier(parentNode) ? parentNode.getText() : void 0;
14532
14926
  const result2 = {
14533
14927
  parentIdentityRef: parentRef,
14534
14928
  collectionName: stringLiteralValue2(nameNode),
@@ -14543,7 +14937,7 @@ function stringLiteralValue2(node) {
14543
14937
  if (!node) {
14544
14938
  return void 0;
14545
14939
  }
14546
- if (Node11.isStringLiteral(node) || Node11.isNoSubstitutionTemplateLiteral(node)) {
14940
+ if (Node12.isStringLiteral(node) || Node12.isNoSubstitutionTemplateLiteral(node)) {
14547
14941
  return node.getLiteralText();
14548
14942
  }
14549
14943
  return void 0;
@@ -14604,7 +14998,7 @@ function detectFactoryCallKind(sourceFile, factoryFnName) {
14604
14998
  const calls = fn.getDescendantsOfKind(SyntaxKind4.CallExpression);
14605
14999
  for (const call of calls) {
14606
15000
  const expr = call.getExpression();
14607
- if (!Node11.isPropertyAccessExpression(expr)) {
15001
+ if (!Node12.isPropertyAccessExpression(expr)) {
14608
15002
  continue;
14609
15003
  }
14610
15004
  const name = expr.getName();
@@ -15425,6 +15819,22 @@ var RULE_CATALOG = [
15425
15819
  }
15426
15820
  ]
15427
15821
  },
15822
+ {
15823
+ code: "MODEL_SUBOBJECT_PARENT_NOT_TAGGED",
15824
+ source: "dbx_model_validate",
15825
+ severity: "warning",
15826
+ title: "A `@dbxModelSubObject` interface extends a parent interface that is not itself tagged with `@dbxModel` or `@dbxModelSubObject`. The parent's persisted fields flow through the sub-object's converter but never reach the workspace's `@dbxModelVariable` long-name checks. Whether the agent acts depends on whether the parent is owned by this package, but the validator surfaces both classifications so the consuming agent (or developer) can make an informed call",
15827
+ whatItFlags: "A `@dbxModelSubObject` interface extends a parent interface that is not itself tagged with `@dbxModel` or `@dbxModelSubObject`. The parent's persisted fields flow through the sub-object's converter but never reach the workspace's `@dbxModelVariable` long-name checks. Whether the agent acts depends on whether the parent is owned by this package, but the validator surfaces both classifications so the consuming agent (or developer) can make an informed call.",
15828
+ whenItApplies: "Every `@dbxModelSubObject` interface whose `extends` heritage names an untagged parent. The parent is classified `in-package` when its declaration is found in the validated source set, otherwise `external`. Anchored at the sub-object interface line so the caller sees both the child and the parent in one place.",
15829
+ whenItDoesNotApply: "Parents already tagged with `@dbxModel` or `@dbxModelSubObject`; parents whose names appear in `modelValidate.ignoredExternalParents` (suppresses external-only warnings \u2014 in-package parents are never suppressed). Generic parameters, inline types, and TS utility wrappers (`Partial<T>`, `Pick<T, K>`, `Omit<T, K>`, `Readonly<T>`, `MaybeMap<T>`) are unwrapped to the underlying parent name before resolution.",
15830
+ canonicalFix: "In-package parent: add `@dbxModelSubObject` to the parent interface's JSDoc and tag each persisted field with `@dbxModelVariable <longName>`. Alternative: redeclare the inherited fields directly on the child with their own JSDoc + tag (useful when the parent is a shared shape that shouldn't commit to a single longName). External parent: redeclare the inherited fields on the child with `@dbxModelVariable <longName>` tags when surface long-names are needed, or add the parent name to `modelValidate.ignoredExternalParents` in `dbx-mcp.config.json` when the inherited fields are framework plumbing (e.g. `IndexRef.i`, `DateRange.start/end`).",
15831
+ seeAlso: [
15832
+ {
15833
+ kind: "artifact",
15834
+ target: "firestore-model"
15835
+ }
15836
+ ]
15837
+ },
15428
15838
  {
15429
15839
  code: "MODEL_SUBOBJECT_TAG_CONFLICT",
15430
15840
  source: "dbx_model_validate",
@@ -17064,28 +17474,31 @@ function formatSeeAlso(ref) {
17064
17474
  // packages/dbx-components-mcp/src/tools/model-validate/rules.ts
17065
17475
  function runRules(file, options, context) {
17066
17476
  const violations = [];
17067
- if (file.models.length === 0) {
17068
- checkSubObjectFactoryCallSites(file, violations, context);
17069
- return violations;
17070
- }
17071
- checkFileLevel(file, violations);
17072
- for (const model of file.models) {
17073
- checkIdentity(file, model, violations);
17074
- checkCoreDeclarations(file, model, violations);
17075
- if (model.variant === "subcollection") {
17076
- checkSubcollectionExtras(file, model, violations);
17477
+ const hasModels = file.models.length > 0;
17478
+ if (hasModels) {
17479
+ checkFileLevel(file, violations);
17480
+ for (const model of file.models) {
17481
+ checkIdentity(file, model, violations);
17482
+ checkCoreDeclarations(file, model, violations);
17483
+ if (model.variant === "subcollection") {
17484
+ checkSubcollectionExtras(file, model, violations);
17485
+ }
17486
+ checkDeclarationOrder(file, model, violations);
17077
17487
  }
17078
- checkDeclarationOrder(file, model, violations);
17079
17488
  }
17080
- checkFieldNameLengths(file, violations, options);
17489
+ checkFieldNameLengths(file, violations, options, { restrictToTaggedInterfaces: !hasModels });
17081
17490
  checkSubObjectInterfaceTags(file, violations);
17082
17491
  checkSubObjectFactoryCallSites(file, violations, context);
17492
+ checkSubObjectParentNotTagged(file, violations, context, options);
17083
17493
  return violations;
17084
17494
  }
17085
- function checkFieldNameLengths(file, violations, options) {
17495
+ function checkFieldNameLengths(file, violations, options, scope) {
17086
17496
  const limit = options?.maxFieldNameLength ?? MAX_FIELD_NAME_LENGTH;
17087
17497
  const ignored = options?.ignoredFieldNames;
17088
17498
  for (const iface of file.dataInterfaces) {
17499
+ if (scope.restrictToTaggedInterfaces && !(iface.dbxModelTag || iface.dbxModelSubObjectTag)) {
17500
+ continue;
17501
+ }
17089
17502
  for (const field of iface.fields) {
17090
17503
  if (ignored?.has(field.name)) {
17091
17504
  continue;
@@ -17103,11 +17516,14 @@ function checkFieldNameLengths(file, violations, options) {
17103
17516
  });
17104
17517
  }
17105
17518
  }
17106
- checkFieldJsDocs(file, violations, options);
17519
+ checkFieldJsDocs(file, violations, options, scope);
17107
17520
  }
17108
- function checkFieldJsDocs(file, violations, options) {
17521
+ function checkFieldJsDocs(file, violations, options, scope) {
17109
17522
  const ignored = options?.ignoredFieldNames;
17110
17523
  for (const iface of file.dataInterfaces) {
17524
+ if (scope.restrictToTaggedInterfaces && !(iface.dbxModelTag || iface.dbxModelSubObjectTag)) {
17525
+ continue;
17526
+ }
17111
17527
  for (const field of iface.fields) {
17112
17528
  if (!field.jsDocFirstLine) {
17113
17529
  pushViolation(violations, {
@@ -17186,6 +17602,52 @@ function checkSubObjectFactoryCallSites(file, violations, context) {
17186
17602
  });
17187
17603
  }
17188
17604
  }
17605
+ function checkSubObjectParentNotTagged(file, violations, context, options) {
17606
+ if (!context) {
17607
+ return;
17608
+ }
17609
+ const ignoredExternal = options?.ignoredExternalParents;
17610
+ for (const iface of file.dataInterfaces) {
17611
+ if (!iface.dbxModelSubObjectTag) {
17612
+ continue;
17613
+ }
17614
+ for (const parentName of iface.extendsNames) {
17615
+ const dedupKey = `${iface.name}<-${parentName}`;
17616
+ if (context.emittedSubObjectInterfaces.has(dedupKey)) {
17617
+ continue;
17618
+ }
17619
+ const entry = context.interfacesByName.get(parentName);
17620
+ if (entry) {
17621
+ const parent = entry.iface;
17622
+ if (parent.dbxModelTag || parent.dbxModelSubObjectTag) {
17623
+ continue;
17624
+ }
17625
+ context.emittedSubObjectInterfaces.add(dedupKey);
17626
+ pushViolation(violations, {
17627
+ code: "MODEL_SUBOBJECT_PARENT_NOT_TAGGED",
17628
+ severity: "warning",
17629
+ message: `Interface \`${parentName}\` is extended by \`@dbxModelSubObject\` \`${iface.name}\`. \`${parentName}\` is declared in the same package (${entry.file}) and its fields are persisted via \`${iface.name}\`'s converter but are not validated. Fix (preferred): add \`@dbxModelSubObject\` to \`${parentName}\`'s JSDoc and tag each persisted field with \`@dbxModelVariable <longName>\`. Alternative: redeclare the inherited fields directly on \`${iface.name}\` with their own JSDoc + tag (useful when \`${parentName}\` is a shared shape that you do not want to commit to a single longName).`,
17630
+ file: entry.file,
17631
+ line: parent.line,
17632
+ model: parentName
17633
+ });
17634
+ } else {
17635
+ if (ignoredExternal?.has(parentName)) {
17636
+ continue;
17637
+ }
17638
+ context.emittedSubObjectInterfaces.add(dedupKey);
17639
+ pushViolation(violations, {
17640
+ code: "MODEL_SUBOBJECT_PARENT_NOT_TAGGED",
17641
+ severity: "warning",
17642
+ message: `Interface \`${parentName}\` is extended by \`@dbxModelSubObject\` \`${iface.name}\`, but \`${parentName}\` is declared outside this package (unresolved in the validated source set). Its persisted fields cannot be tagged from here. Decide: (1) if the inherited fields need explicit longNames in this catalog, redeclare them on \`${iface.name}\` with a JSDoc block carrying \`@dbxModelVariable <longName>\` (the redeclaration is structurally compatible \u2014 TypeScript treats it as a field narrowing, not a new property); (2) if the inherited fields are framework plumbing (e.g. \`IndexRef.i\`, \`DateRange.start/end\`) and surface longNames are not needed, suppress this specific warning by adding \`${parentName}\` to \`modelValidate.ignoredExternalParents\` in \`dbx-mcp.config.json\`.`,
17643
+ file: file.name,
17644
+ line: iface.line,
17645
+ model: iface.name
17646
+ });
17647
+ }
17648
+ }
17649
+ }
17650
+ }
17189
17651
  function checkFileLevel(file, violations) {
17190
17652
  const { groupInterface, groupTypes, firstModelLine, models, name } = file;
17191
17653
  if (groupInterface) {
@@ -17984,7 +18446,7 @@ var modelValidateTool = /* @__PURE__ */ createModelValidateTool();
17984
18446
  var runModelValidate = modelValidateTool.run;
17985
18447
 
17986
18448
  // packages/dbx-components-mcp/src/tools/model-validate-api/extract.ts
17987
- import { Node as Node12, Project as Project5, SyntaxKind as SyntaxKind5 } from "ts-morph";
18449
+ import { Node as Node13, Project as Project5, SyntaxKind as SyntaxKind5 } from "ts-morph";
17988
18450
  function extractFile2(source) {
17989
18451
  const project = new Project5({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
17990
18452
  const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
@@ -18150,7 +18612,7 @@ function findCrudConfigType(sourceFile) {
18150
18612
  continue;
18151
18613
  }
18152
18614
  const typeNode = alias.getTypeNode();
18153
- const summary = typeNode && Node12.isTypeLiteral(typeNode) ? summarizeCrudConfigType(typeNode) : { keys: [], nonNullKeys: [], bareLeafParamsNames: [] };
18615
+ const summary = typeNode && Node13.isTypeLiteral(typeNode) ? summarizeCrudConfigType(typeNode) : { keys: [], nonNullKeys: [], bareLeafParamsNames: [] };
18154
18616
  const result = {
18155
18617
  name: alias.getName(),
18156
18618
  exported: alias.isExported(),
@@ -18164,14 +18626,14 @@ function findCrudConfigType(sourceFile) {
18164
18626
  return void 0;
18165
18627
  }
18166
18628
  function summarizeCrudConfigType(typeLiteral) {
18167
- if (!Node12.isTypeLiteral(typeLiteral)) {
18629
+ if (!Node13.isTypeLiteral(typeLiteral)) {
18168
18630
  return { keys: [], nonNullKeys: [], bareLeafParamsNames: [] };
18169
18631
  }
18170
18632
  const keys = [];
18171
18633
  const nonNullKeys = [];
18172
18634
  const bareLeafParamsNames = [];
18173
18635
  for (const member of typeLiteral.getMembers()) {
18174
- if (!Node12.isPropertySignature(member)) {
18636
+ if (!Node13.isPropertySignature(member)) {
18175
18637
  continue;
18176
18638
  }
18177
18639
  const name = member.getName();
@@ -18189,18 +18651,18 @@ function summarizeCrudConfigType(typeLiteral) {
18189
18651
  return { keys, nonNullKeys, bareLeafParamsNames };
18190
18652
  }
18191
18653
  function isNullLiteralType(node) {
18192
- if (Node12.isLiteralTypeNode(node)) {
18654
+ if (Node13.isLiteralTypeNode(node)) {
18193
18655
  const literal = node.getLiteral();
18194
- if (Node12.isNullLiteral(literal)) {
18656
+ if (Node13.isNullLiteral(literal)) {
18195
18657
  return true;
18196
18658
  }
18197
18659
  }
18198
18660
  return false;
18199
18661
  }
18200
18662
  function collectBareParamsLeaves(node, out) {
18201
- if (Node12.isTypeLiteral(node)) {
18663
+ if (Node13.isTypeLiteral(node)) {
18202
18664
  for (const member of node.getMembers()) {
18203
- if (!Node12.isPropertySignature(member)) {
18665
+ if (!Node13.isPropertySignature(member)) {
18204
18666
  continue;
18205
18667
  }
18206
18668
  const valueNode = member.getTypeNode();
@@ -18210,10 +18672,10 @@ function collectBareParamsLeaves(node, out) {
18210
18672
  }
18211
18673
  return;
18212
18674
  }
18213
- if (Node12.isTupleTypeNode(node)) {
18675
+ if (Node13.isTupleTypeNode(node)) {
18214
18676
  return;
18215
18677
  }
18216
- if (Node12.isTypeReference(node)) {
18678
+ if (Node13.isTypeReference(node)) {
18217
18679
  const name = node.getTypeName().getText();
18218
18680
  if (name.endsWith("Params")) {
18219
18681
  out.push(name);
@@ -18230,12 +18692,12 @@ function findCrudConfigConst(sourceFile) {
18230
18692
  const typeNode = decl.getTypeNode();
18231
18693
  const initializer = decl.getInitializer();
18232
18694
  const runtimeKeys = [];
18233
- if (initializer && Node12.isAsExpression(initializer)) {
18695
+ if (initializer && Node13.isAsExpression(initializer)) {
18234
18696
  const inner = initializer.getExpression();
18235
- if (Node12.isObjectLiteralExpression(inner)) {
18697
+ if (Node13.isObjectLiteralExpression(inner)) {
18236
18698
  runtimeKeys.push(...collectObjectLiteralKeys(inner));
18237
18699
  }
18238
- } else if (initializer && Node12.isObjectLiteralExpression(initializer)) {
18700
+ } else if (initializer && Node13.isObjectLiteralExpression(initializer)) {
18239
18701
  runtimeKeys.push(...collectObjectLiteralKeys(initializer));
18240
18702
  }
18241
18703
  const result = {
@@ -18253,7 +18715,7 @@ function findCrudConfigConst(sourceFile) {
18253
18715
  function collectObjectLiteralKeys(obj) {
18254
18716
  const out = [];
18255
18717
  for (const prop of obj.getProperties()) {
18256
- if (Node12.isPropertyAssignment(prop) || Node12.isShorthandPropertyAssignment(prop)) {
18718
+ if (Node13.isPropertyAssignment(prop) || Node13.isShorthandPropertyAssignment(prop)) {
18257
18719
  out.push(prop.getName());
18258
18720
  }
18259
18721
  }
@@ -18269,7 +18731,7 @@ function findFunctionMap(sourceFile) {
18269
18731
  const initializer = decl.getInitializer();
18270
18732
  let callsFactory = false;
18271
18733
  const factoryArgs = [];
18272
- if (initializer && Node12.isCallExpression(initializer)) {
18734
+ if (initializer && Node13.isCallExpression(initializer)) {
18273
18735
  const exprText = initializer.getExpression().getText();
18274
18736
  if (exprText === "callModelFirebaseFunctionMapFactory") {
18275
18737
  callsFactory = true;
@@ -18407,18 +18869,18 @@ function extractCastTargetName(node) {
18407
18869
  return void 0;
18408
18870
  }
18409
18871
  let current = node;
18410
- while (current && Node12.isAsExpression(current)) {
18872
+ while (current && Node13.isAsExpression(current)) {
18411
18873
  const typeNode = current.getTypeNode();
18412
18874
  if (!typeNode) {
18413
18875
  break;
18414
18876
  }
18415
- if (Node12.isTypeReference(typeNode)) {
18877
+ if (Node13.isTypeReference(typeNode)) {
18416
18878
  const refName = typeNode.getTypeName().getText();
18417
18879
  if (refName === "Type") {
18418
18880
  const args = typeNode.getTypeArguments();
18419
18881
  if (args.length === 1) {
18420
18882
  const arg = args[0];
18421
- if (Node12.isTypeReference(arg)) {
18883
+ if (Node13.isTypeReference(arg)) {
18422
18884
  return arg.getTypeName().getText();
18423
18885
  }
18424
18886
  return arg.getText();
@@ -18437,7 +18899,7 @@ function extractValidatorProperties(initializer) {
18437
18899
  }
18438
18900
  const out = [];
18439
18901
  for (const prop of obj.getProperties()) {
18440
- if (!Node12.isPropertyAssignment(prop)) {
18902
+ if (!Node13.isPropertyAssignment(prop)) {
18441
18903
  continue;
18442
18904
  }
18443
18905
  const propAssignment = prop;
@@ -18447,7 +18909,7 @@ function extractValidatorProperties(initializer) {
18447
18909
  const clean = optional ? stripped.slice(0, -1) : stripped;
18448
18910
  const valueNode = propAssignment.getInitializer();
18449
18911
  let hasClearable = false;
18450
- if (valueNode && Node12.isCallExpression(valueNode)) {
18912
+ if (valueNode && Node13.isCallExpression(valueNode)) {
18451
18913
  const exprText = valueNode.getExpression().getText();
18452
18914
  if (exprText === "clearable") {
18453
18915
  hasClearable = true;
@@ -18459,25 +18921,25 @@ function extractValidatorProperties(initializer) {
18459
18921
  }
18460
18922
  function findArktypeObjectLiteral(initializer) {
18461
18923
  let current = initializer;
18462
- while (current && Node12.isAsExpression(current)) {
18924
+ while (current && Node13.isAsExpression(current)) {
18463
18925
  current = current.getExpression();
18464
18926
  }
18465
- if (!current || !Node12.isCallExpression(current)) {
18927
+ if (!current || !Node13.isCallExpression(current)) {
18466
18928
  return void 0;
18467
18929
  }
18468
18930
  const expr = current.getExpression();
18469
- if (Node12.isIdentifier(expr) && expr.getText() === "type") {
18931
+ if (Node13.isIdentifier(expr) && expr.getText() === "type") {
18470
18932
  const args = current.getArguments();
18471
18933
  const arg = args[0];
18472
- if (arg && Node12.isObjectLiteralExpression(arg)) {
18934
+ if (arg && Node13.isObjectLiteralExpression(arg)) {
18473
18935
  return arg;
18474
18936
  }
18475
18937
  return void 0;
18476
18938
  }
18477
- if (Node12.isPropertyAccessExpression(expr) && expr.getName() === "merge") {
18939
+ if (Node13.isPropertyAccessExpression(expr) && expr.getName() === "merge") {
18478
18940
  const args = current.getArguments();
18479
18941
  const arg = args[0];
18480
- if (arg && Node12.isObjectLiteralExpression(arg)) {
18942
+ if (arg && Node13.isObjectLiteralExpression(arg)) {
18481
18943
  return arg;
18482
18944
  }
18483
18945
  }
@@ -19162,7 +19624,7 @@ import { readdir as readdir2, readFile as readFile4, stat as stat4 } from "node:
19162
19624
  import { join as join4, relative as relative4, sep as sep5 } from "node:path";
19163
19625
 
19164
19626
  // packages/dbx-cli/manifest-extract/src/lib/extract-crud.ts
19165
- import { Node as Node13, Project as Project6 } from "ts-morph";
19627
+ import { Node as Node14, Project as Project6 } from "ts-morph";
19166
19628
  var SUPPORTED_VERBS = /* @__PURE__ */ new Set(["create", "read", "update", "delete", "query"]);
19167
19629
  function extractCrudEntries(source) {
19168
19630
  const project = new Project6({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
@@ -19188,9 +19650,9 @@ function extractCrudEntries(source) {
19188
19650
  };
19189
19651
  if (crudConfigType) {
19190
19652
  const literal = crudConfigType.getTypeNode();
19191
- if (literal && Node13.isTypeLiteral(literal)) {
19653
+ if (literal && Node14.isTypeLiteral(literal)) {
19192
19654
  for (const member of literal.getMembers()) {
19193
- if (!Node13.isPropertySignature(member)) {
19655
+ if (!Node14.isPropertySignature(member)) {
19194
19656
  continue;
19195
19657
  }
19196
19658
  const modelName = member.getName();
@@ -19202,9 +19664,9 @@ function extractCrudEntries(source) {
19202
19664
  if (isNullLiteralType2(valueNode)) {
19203
19665
  continue;
19204
19666
  }
19205
- if (Node13.isTypeLiteral(valueNode)) {
19667
+ if (Node14.isTypeLiteral(valueNode)) {
19206
19668
  for (const verbMember of valueNode.getMembers()) {
19207
- if (!Node13.isPropertySignature(verbMember)) {
19669
+ if (!Node14.isPropertySignature(verbMember)) {
19208
19670
  continue;
19209
19671
  }
19210
19672
  const verbName = verbMember.getName();
@@ -19225,9 +19687,9 @@ function extractCrudEntries(source) {
19225
19687
  const functionTypeMap = findTypeAliasByEnding(sourceFile, "FunctionTypeMap");
19226
19688
  if (functionTypeMap) {
19227
19689
  const literal = functionTypeMap.getTypeNode();
19228
- if (literal && Node13.isTypeLiteral(literal)) {
19690
+ if (literal && Node14.isTypeLiteral(literal)) {
19229
19691
  for (const member of literal.getMembers()) {
19230
- if (!Node13.isPropertySignature(member)) {
19692
+ if (!Node14.isPropertySignature(member)) {
19231
19693
  continue;
19232
19694
  }
19233
19695
  const key = member.getName();
@@ -19295,9 +19757,9 @@ function inferGroupName2(sourceFile) {
19295
19757
  return void 0;
19296
19758
  }
19297
19759
  function isNullLiteralType2(node) {
19298
- if (Node13.isLiteralTypeNode(node)) {
19760
+ if (Node14.isLiteralTypeNode(node)) {
19299
19761
  const literal = node.getLiteral();
19300
- if (Node13.isNullLiteral(literal)) {
19762
+ if (Node14.isNullLiteral(literal)) {
19301
19763
  return true;
19302
19764
  }
19303
19765
  }
@@ -19305,9 +19767,9 @@ function isNullLiteralType2(node) {
19305
19767
  }
19306
19768
  function collectVerbEntries(input) {
19307
19769
  const { modelName, verb, valueNode, entries, fallbackDescription, resolveTypeDocs } = input;
19308
- if (Node13.isTypeLiteral(valueNode)) {
19770
+ if (Node14.isTypeLiteral(valueNode)) {
19309
19771
  for (const specMember of valueNode.getMembers()) {
19310
- if (!Node13.isPropertySignature(specMember)) {
19772
+ if (!Node14.isPropertySignature(specMember)) {
19311
19773
  continue;
19312
19774
  }
19313
19775
  const specifier = specMember.getName();
@@ -19349,7 +19811,7 @@ function collectVerbEntries(input) {
19349
19811
  });
19350
19812
  }
19351
19813
  function readTupleParamsResult(node) {
19352
- if (!Node13.isTupleTypeNode(node)) {
19814
+ if (!Node14.isTupleTypeNode(node)) {
19353
19815
  return void 0;
19354
19816
  }
19355
19817
  const elements = node.getElements();
@@ -19368,7 +19830,7 @@ function readBareParams(node) {
19368
19830
  return { params, result: void 0 };
19369
19831
  }
19370
19832
  function typeNodeName(node) {
19371
- if (Node13.isTypeReference(node)) {
19833
+ if (Node14.isTypeReference(node)) {
19372
19834
  return node.getTypeName().getText();
19373
19835
  }
19374
19836
  const text = node.getText().trim();
@@ -20207,7 +20669,7 @@ async function collectApiFiles2(rootAbs) {
20207
20669
  // packages/dbx-components-mcp/src/tools/model-api-validate-app/extract-handlers.ts
20208
20670
  import { readFile as readFile8 } from "node:fs/promises";
20209
20671
  import { join as join8 } from "node:path";
20210
- import { Node as Node14, Project as Project8 } from "ts-morph";
20672
+ import { Node as Node15, Project as Project8 } from "ts-morph";
20211
20673
  var HANDLER_MAP_REL = "src/app/function/model/crud.functions.ts";
20212
20674
  var VERB_TOKENS = [
20213
20675
  { token: "Create", verb: "create" },
@@ -20235,7 +20697,7 @@ async function extractHandlerEntries(apiAbs, apiDir) {
20235
20697
  const verb = matchVerbFromConstName(name);
20236
20698
  if (!verb) continue;
20237
20699
  const initializer = decl.getInitializer();
20238
- if (!initializer || !Node14.isObjectLiteralExpression(initializer)) continue;
20700
+ if (!initializer || !Node15.isObjectLiteralExpression(initializer)) continue;
20239
20701
  verbsFound.push(verb);
20240
20702
  collectVerbMap({ verb, mapLiteral: initializer, sourceFileRel, entries });
20241
20703
  }
@@ -20253,7 +20715,7 @@ function matchVerbFromConstName(name) {
20253
20715
  function collectVerbMap(input) {
20254
20716
  const { verb, mapLiteral, sourceFileRel, entries } = input;
20255
20717
  for (const prop of mapLiteral.getProperties()) {
20256
- if (!Node14.isPropertyAssignment(prop)) continue;
20718
+ if (!Node15.isPropertyAssignment(prop)) continue;
20257
20719
  const model = prop.getName();
20258
20720
  const value = prop.getInitializer();
20259
20721
  if (!value) continue;
@@ -20272,25 +20734,25 @@ function collectVerbMap(input) {
20272
20734
  }
20273
20735
  }
20274
20736
  function readSpecifierHandler(node) {
20275
- if (!Node14.isCallExpression(node)) return void 0;
20737
+ if (!Node15.isCallExpression(node)) return void 0;
20276
20738
  const expr = node.getExpression();
20277
20739
  if (!expr.getText().endsWith("onCallSpecifierHandler")) return void 0;
20278
20740
  const args = node.getArguments();
20279
20741
  if (args.length === 0) return void 0;
20280
20742
  const firstArg = args[0];
20281
- if (!Node14.isObjectLiteralExpression(firstArg)) return void 0;
20743
+ if (!Node15.isObjectLiteralExpression(firstArg)) return void 0;
20282
20744
  const out = /* @__PURE__ */ new Map();
20283
20745
  for (const prop of firstArg.getProperties()) {
20284
- if (!Node14.isPropertyAssignment(prop) && !Node14.isShorthandPropertyAssignment(prop)) continue;
20746
+ if (!Node15.isPropertyAssignment(prop) && !Node15.isShorthandPropertyAssignment(prop)) continue;
20285
20747
  const specifier = prop.getName();
20286
- const handlerName = readBareHandlerName(Node14.isPropertyAssignment(prop) ? prop.getInitializerOrThrow() : prop) ?? "(unresolved)";
20748
+ const handlerName = readBareHandlerName(Node15.isPropertyAssignment(prop) ? prop.getInitializerOrThrow() : prop) ?? "(unresolved)";
20287
20749
  out.set(specifier, handlerName);
20288
20750
  }
20289
20751
  return out;
20290
20752
  }
20291
20753
  function readBareHandlerName(node) {
20292
- if (Node14.isIdentifier(node)) return node.getText();
20293
- if (Node14.isShorthandPropertyAssignment(node)) return node.getName();
20754
+ if (Node15.isIdentifier(node)) return node.getText();
20755
+ if (Node15.isShorthandPropertyAssignment(node)) return node.getName();
20294
20756
  const text = node.getText().split(/\s|\(/)[0];
20295
20757
  if (/^[A-Za-z_]\w*$/.test(text)) return text;
20296
20758
  return void 0;
@@ -20788,7 +21250,7 @@ async function readModelSources(folderPath, files) {
20788
21250
  }
20789
21251
 
20790
21252
  // packages/dbx-components-mcp/src/tools/model-validate-folder/rules.ts
20791
- function runRules3(inspection) {
21253
+ function runRules3(inspection, options) {
20792
21254
  const violations = [];
20793
21255
  if (inspection.status === "not-found") {
20794
21256
  pushViolation3(violations, {
@@ -20821,16 +21283,16 @@ function runRules3(inspection) {
20821
21283
  }
20822
21284
  checkRequiredFiles(inspection, violations);
20823
21285
  checkStrayFiles(inspection, violations);
20824
- checkSourceContents(inspection, violations);
21286
+ checkSourceContents(inspection, violations, options);
20825
21287
  return violations;
20826
21288
  }
20827
- function checkSourceContents(inspection, violations) {
21289
+ function checkSourceContents(inspection, violations, options) {
20828
21290
  const sources = inspection.sources;
20829
21291
  if (!sources || sources.length === 0) {
20830
21292
  return;
20831
21293
  }
20832
21294
  const validatorSources = sources.map((s) => ({ name: s.filename, text: s.text }));
20833
- const result = validateFirebaseModelSources(validatorSources);
21295
+ const result = validateFirebaseModelSources(validatorSources, options);
20834
21296
  for (const v of result.violations) {
20835
21297
  pushViolation3(violations, {
20836
21298
  code: v.code,
@@ -20891,8 +21353,8 @@ function pushViolation3(buffer, violation) {
20891
21353
  }
20892
21354
 
20893
21355
  // packages/dbx-components-mcp/src/tools/model-validate-folder/validate.ts
20894
- function validateModelFolders(inspections) {
20895
- return aggregateFolderRules({ inspections, runRules: runRules3 });
21356
+ function validateModelFolders(inspections, options) {
21357
+ return aggregateFolderRules({ inspections, runRules: (inspection) => runRules3(inspection, options) });
20896
21358
  }
20897
21359
 
20898
21360
  // packages/dbx-components-mcp/src/tools/model-validate-folder.tool.ts
@@ -20926,12 +21388,16 @@ var DBX_MODEL_VALIDATE_FOLDER_TOOL = {
20926
21388
  }
20927
21389
  }
20928
21390
  };
20929
- var modelValidateFolderTool = createFolderValidateTool({
20930
- definition: DBX_MODEL_VALIDATE_FOLDER_TOOL,
20931
- inspectFolder,
20932
- validate: validateModelFolders,
20933
- format: formatResult3
20934
- });
21391
+ // @__NO_SIDE_EFFECTS__
21392
+ function createModelValidateFolderTool(options = {}) {
21393
+ const { ruleOptions } = options;
21394
+ return createFolderValidateTool({
21395
+ definition: DBX_MODEL_VALIDATE_FOLDER_TOOL,
21396
+ inspectFolder,
21397
+ validate: (inspections) => validateModelFolders(inspections, ruleOptions),
21398
+ format: formatResult3
21399
+ });
21400
+ }
20935
21401
 
20936
21402
  // packages/dbx-components-mcp/src/tools/model-store-scaffold.tool.ts
20937
21403
  import { type as type41 } from "arktype";
@@ -21492,7 +21958,7 @@ function paramsHasFixtureDependencies(params) {
21492
21958
  }
21493
21959
 
21494
21960
  // packages/dbx-components-mcp/src/tools/model-fixture-shared/extract.ts
21495
- import { Node as Node15, Project as Project9, SyntaxKind as SyntaxKind7 } from "ts-morph";
21961
+ import { Node as Node16, Project as Project9, SyntaxKind as SyntaxKind7 } from "ts-morph";
21496
21962
 
21497
21963
  // packages/dbx-components-mcp/src/tools/model-fixture-shared/framework-fixtures.ts
21498
21964
  var KNOWN_NON_MODEL_FIXTURE_FAMILIES = [
@@ -21604,7 +22070,7 @@ function extendsByName(cls, baseName) {
21604
22070
  const extendsClause = cls.getExtends();
21605
22071
  if (!extendsClause) return false;
21606
22072
  const expr = extendsClause.getExpression();
21607
- if (Node15.isIdentifier(expr)) {
22073
+ if (Node16.isIdentifier(expr)) {
21608
22074
  return expr.getText() === baseName;
21609
22075
  }
21610
22076
  return extendsClause.getText().startsWith(baseName);
@@ -21732,14 +22198,14 @@ function readContextFactory(decl) {
21732
22198
  const initializer = decl.getInitializer();
21733
22199
  if (!initializer) return void 0;
21734
22200
  let bodyExpr;
21735
- if (Node15.isArrowFunction(initializer) || Node15.isFunctionExpression(initializer)) {
22201
+ if (Node16.isArrowFunction(initializer) || Node16.isFunctionExpression(initializer)) {
21736
22202
  bodyExpr = readSingleReturnExpression(initializer);
21737
22203
  } else {
21738
22204
  bodyExpr = initializer;
21739
22205
  }
21740
- if (!bodyExpr || !Node15.isCallExpression(bodyExpr)) return void 0;
22206
+ if (!bodyExpr || !Node16.isCallExpression(bodyExpr)) return void 0;
21741
22207
  const callee = bodyExpr.getExpression();
21742
- if (!Node15.isIdentifier(callee)) return void 0;
22208
+ if (!Node16.isIdentifier(callee)) return void 0;
21743
22209
  const calleeName = callee.getText();
21744
22210
  let family;
21745
22211
  if (calleeName !== MODEL_FACTORY_NAME) {
@@ -21754,9 +22220,9 @@ function readContextFactory(decl) {
21754
22220
  let parentFixtureFieldFromGetCollection;
21755
22221
  if (args.length > 0) {
21756
22222
  const first = args[0];
21757
- if (Node15.isObjectLiteralExpression(first)) {
22223
+ if (Node16.isObjectLiteralExpression(first)) {
21758
22224
  const getCollection = first.getProperty("getCollection");
21759
- if (getCollection && Node15.isPropertyAssignment(getCollection)) {
22225
+ if (getCollection && Node16.isPropertyAssignment(getCollection)) {
21760
22226
  const fnInit = getCollection.getInitializer();
21761
22227
  const arity = readArrowParameterCount(fnInit);
21762
22228
  if (arity >= 2) {
@@ -21807,7 +22273,7 @@ function familyFromExtends(cls) {
21807
22273
  if (!ext) return void 0;
21808
22274
  const expr = ext.getExpression();
21809
22275
  let baseName;
21810
- if (Node15.isIdentifier(expr)) {
22276
+ if (Node16.isIdentifier(expr)) {
21811
22277
  baseName = expr.getText();
21812
22278
  } else {
21813
22279
  const text = ext.getText();
@@ -21820,9 +22286,9 @@ function familyFromExtends(cls) {
21820
22286
  function readSingleReturnExpression(fn) {
21821
22287
  const body = fn.getBody();
21822
22288
  if (!body) return void 0;
21823
- if (Node15.isBlock(body)) {
22289
+ if (Node16.isBlock(body)) {
21824
22290
  for (const stmt of body.getStatements()) {
21825
- if (Node15.isReturnStatement(stmt)) {
22291
+ if (Node16.isReturnStatement(stmt)) {
21826
22292
  return stmt.getExpression();
21827
22293
  }
21828
22294
  }
@@ -21832,19 +22298,19 @@ function readSingleReturnExpression(fn) {
21832
22298
  }
21833
22299
  function readArrowParameterCount(fn) {
21834
22300
  if (!fn) return 0;
21835
- if (Node15.isArrowFunction(fn) || Node15.isFunctionExpression(fn) || Node15.isFunctionDeclaration(fn) || Node15.isMethodDeclaration(fn)) {
22301
+ if (Node16.isArrowFunction(fn) || Node16.isFunctionExpression(fn) || Node16.isFunctionDeclaration(fn) || Node16.isMethodDeclaration(fn)) {
21836
22302
  return fn.getParameters().length;
21837
22303
  }
21838
22304
  return 0;
21839
22305
  }
21840
22306
  function readParamsAccessFieldName(fn) {
21841
22307
  if (!fn) return void 0;
21842
- if (!Node15.isArrowFunction(fn) && !Node15.isFunctionExpression(fn)) return void 0;
22308
+ if (!Node16.isArrowFunction(fn) && !Node16.isFunctionExpression(fn)) return void 0;
21843
22309
  const body = fn.getBody();
21844
22310
  if (!body) return void 0;
21845
22311
  for (const access2 of body.getDescendantsOfKind(SyntaxKind7.PropertyAccessExpression)) {
21846
22312
  const expr = access2.getExpression();
21847
- if (Node15.isIdentifier(expr) && expr.getText() === "params") {
22313
+ if (Node16.isIdentifier(expr) && expr.getText() === "params") {
21848
22314
  return access2.getName();
21849
22315
  }
21850
22316
  }
@@ -21885,9 +22351,9 @@ function collectSingletonsByFactory(sourceFile) {
21885
22351
  for (const stmt of sourceFile.getVariableStatements()) {
21886
22352
  for (const decl of stmt.getDeclarations()) {
21887
22353
  const init = decl.getInitializer();
21888
- if (!init || !Node15.isCallExpression(init)) continue;
22354
+ if (!init || !Node16.isCallExpression(init)) continue;
21889
22355
  const callee = init.getExpression();
21890
- if (!Node15.isIdentifier(callee)) continue;
22356
+ if (!Node16.isIdentifier(callee)) continue;
21891
22357
  out.set(callee.getText(), decl.getName());
21892
22358
  }
21893
22359
  }
@@ -23135,7 +23601,7 @@ import { resolve as resolve32 } from "node:path";
23135
23601
  import { type as type47 } from "arktype";
23136
23602
 
23137
23603
  // packages/dbx-components-mcp/src/tools/model-test-shared/extract.ts
23138
- import { Node as Node16, Project as Project11, SyntaxKind as SyntaxKind8 } from "ts-morph";
23604
+ import { Node as Node17, Project as Project11, SyntaxKind as SyntaxKind8 } from "ts-morph";
23139
23605
  var SPEC_FILE_VIRTUAL_PATH = "__spec__/spec.ts";
23140
23606
  var FIXTURE_CONTEXT_SUFFIX = "Context";
23141
23607
  var FIXTURE_FACTORY_SUFFIX = "ContextFactory";
@@ -23156,9 +23622,9 @@ function extractSpecTreeFromText(input) {
23156
23622
  const counts = { describe: 0, it: 0, fixture: 0 };
23157
23623
  const rootChildren = [];
23158
23624
  for (const stmt of sourceFile.getStatements()) {
23159
- if (!Node16.isExpressionStatement(stmt)) continue;
23625
+ if (!Node17.isExpressionStatement(stmt)) continue;
23160
23626
  const expr = stmt.getExpression();
23161
- if (!Node16.isCallExpression(expr)) continue;
23627
+ if (!Node17.isCallExpression(expr)) continue;
23162
23628
  const node = walkCall(expr, { prefix, knownFixtureNames, helperNames, counts });
23163
23629
  if (node !== void 0) {
23164
23630
  rootChildren.push(node);
@@ -23324,7 +23790,7 @@ function fixtureNode(input) {
23324
23790
  const { call, calleeName, ctx, line, endLine } = input;
23325
23791
  const args = call.getArguments();
23326
23792
  const argsObject = args[0];
23327
- const parentVars = Node16.isObjectLiteralExpression(argsObject) ? readParentVars(argsObject) : [];
23793
+ const parentVars = Node17.isObjectLiteralExpression(argsObject) ? readParentVars(argsObject) : [];
23328
23794
  const callback = findCallback(call);
23329
23795
  const varName = callback === void 0 ? void 0 : readCallbackVarName(callback);
23330
23796
  const model = stripFixturePrefix(calleeName, ctx.prefix);
@@ -23362,11 +23828,11 @@ function stripFixturePrefix(name, prefix) {
23362
23828
  }
23363
23829
  function readTitle(arg) {
23364
23830
  if (arg === void 0) return { title: void 0, titleIsTemplate: false };
23365
- if (Node16.isStringLiteral(arg) || Node16.isNoSubstitutionTemplateLiteral(arg)) {
23831
+ if (Node17.isStringLiteral(arg) || Node17.isNoSubstitutionTemplateLiteral(arg)) {
23366
23832
  const result2 = { title: arg.getLiteralText(), titleIsTemplate: false };
23367
23833
  return result2;
23368
23834
  }
23369
- if (Node16.isTemplateExpression(arg)) {
23835
+ if (Node17.isTemplateExpression(arg)) {
23370
23836
  const result2 = { title: arg.getText(), titleIsTemplate: true };
23371
23837
  return result2;
23372
23838
  }
@@ -23377,7 +23843,7 @@ function findCallback(call) {
23377
23843
  const args = call.getArguments();
23378
23844
  for (let i = args.length - 1; i >= 0; i--) {
23379
23845
  const a = args[i];
23380
- if (Node16.isArrowFunction(a) || Node16.isFunctionExpression(a)) {
23846
+ if (Node17.isArrowFunction(a) || Node17.isFunctionExpression(a)) {
23381
23847
  return a;
23382
23848
  }
23383
23849
  }
@@ -23388,7 +23854,7 @@ function readCallbackVarName(callback) {
23388
23854
  if (params.length === 0) return void 0;
23389
23855
  const first = params[0];
23390
23856
  const nameNode = first.getNameNode();
23391
- if (Node16.isIdentifier(nameNode)) {
23857
+ if (Node17.isIdentifier(nameNode)) {
23392
23858
  return nameNode.getText();
23393
23859
  }
23394
23860
  return void 0;
@@ -23396,13 +23862,13 @@ function readCallbackVarName(callback) {
23396
23862
  function readParentVars(obj) {
23397
23863
  const out = [];
23398
23864
  for (const prop of obj.getProperties()) {
23399
- if (Node16.isShorthandPropertyAssignment(prop)) {
23865
+ if (Node17.isShorthandPropertyAssignment(prop)) {
23400
23866
  out.push(prop.getName());
23401
23867
  continue;
23402
23868
  }
23403
- if (Node16.isPropertyAssignment(prop)) {
23869
+ if (Node17.isPropertyAssignment(prop)) {
23404
23870
  const init = prop.getInitializer();
23405
- if (init !== void 0 && Node16.isIdentifier(init)) {
23871
+ if (init !== void 0 && Node17.isIdentifier(init)) {
23406
23872
  out.push(init.getText());
23407
23873
  }
23408
23874
  }
@@ -23411,10 +23877,10 @@ function readParentVars(obj) {
23411
23877
  }
23412
23878
  function walkCallbackBody(callback, ctx) {
23413
23879
  const body = callback.getBody();
23414
- if (Node16.isBlock(body)) {
23880
+ if (Node17.isBlock(body)) {
23415
23881
  return walkBlock(body, ctx);
23416
23882
  }
23417
- if (Node16.isCallExpression(body)) {
23883
+ if (Node17.isCallExpression(body)) {
23418
23884
  const child = walkCall(body, ctx);
23419
23885
  return child === void 0 ? [] : [child];
23420
23886
  }
@@ -23423,9 +23889,9 @@ function walkCallbackBody(callback, ctx) {
23423
23889
  function walkBlock(block, ctx) {
23424
23890
  const children = [];
23425
23891
  for (const stmt of block.getStatements()) {
23426
- if (!Node16.isExpressionStatement(stmt)) continue;
23892
+ if (!Node17.isExpressionStatement(stmt)) continue;
23427
23893
  const expr = stmt.getExpression();
23428
- if (!Node16.isCallExpression(expr)) continue;
23894
+ if (!Node17.isCallExpression(expr)) continue;
23429
23895
  const child = walkCall(expr, ctx);
23430
23896
  if (child !== void 0) {
23431
23897
  children.push(child);
@@ -23435,7 +23901,7 @@ function walkBlock(block, ctx) {
23435
23901
  }
23436
23902
  function getCalleeName(call) {
23437
23903
  const expr = call.getExpression();
23438
- if (Node16.isIdentifier(expr)) return expr.getText();
23904
+ if (Node17.isIdentifier(expr)) return expr.getText();
23439
23905
  return void 0;
23440
23906
  }
23441
23907
  function collectHelpers(sourceFile) {
@@ -23451,7 +23917,7 @@ function collectHelpers(sourceFile) {
23451
23917
  for (const decl of v.getDeclarations()) {
23452
23918
  const init = decl.getInitializer();
23453
23919
  if (init === void 0) continue;
23454
- if (!Node16.isArrowFunction(init) && !Node16.isFunctionExpression(init)) continue;
23920
+ if (!Node17.isArrowFunction(init) && !Node17.isFunctionExpression(init)) continue;
23455
23921
  const usage = scanForDescribeOrIt(init);
23456
23922
  if (!usage.emitsDescribe && !usage.emitsIt) continue;
23457
23923
  out.push({ name: decl.getName(), line: decl.getStartLineNumber(), endLine: decl.getEndLineNumber(), emitsDescribe: usage.emitsDescribe, emitsIt: usage.emitsIt });
@@ -23465,7 +23931,7 @@ function scanForDescribeOrIt(node) {
23465
23931
  if (descendant.getKind() !== SyntaxKind8.CallExpression) return;
23466
23932
  const call = descendant;
23467
23933
  const expr = call.getExpression();
23468
- if (!Node16.isIdentifier(expr)) return;
23934
+ if (!Node17.isIdentifier(expr)) return;
23469
23935
  const name = expr.getText();
23470
23936
  if (DESCRIBE_NAMES.has(name)) usage.emitsDescribe = true;
23471
23937
  if (isItName(name)) usage.emitsIt = true;
@@ -24238,10 +24704,10 @@ var modelHierarchyTool = {
24238
24704
  };
24239
24705
 
24240
24706
  // packages/dbx-components-mcp/src/tools/storagefile-m-validate-app/extract.ts
24241
- import { Node as Node18, SyntaxKind as SyntaxKind10 } from "ts-morph";
24707
+ import { Node as Node19, SyntaxKind as SyntaxKind10 } from "ts-morph";
24242
24708
 
24243
24709
  // packages/dbx-components-mcp/src/tools/_validate/ast.ts
24244
- import { Node as Node17, Project as Project12, SyntaxKind as SyntaxKind9 } from "ts-morph";
24710
+ import { Node as Node18, Project as Project12, SyntaxKind as SyntaxKind9 } from "ts-morph";
24245
24711
  var COMPONENT_VIRTUAL_PREFIX = "__component__/";
24246
24712
  var API_VIRTUAL_PREFIX = "__api__/";
24247
24713
  // @__NO_SIDE_EFFECTS__
@@ -24266,28 +24732,28 @@ function componentRelPath(sourceFile) {
24266
24732
  }
24267
24733
  function unwrapAsExpressions(node) {
24268
24734
  let current = node;
24269
- while (current && Node17.isAsExpression(current)) {
24735
+ while (current && Node18.isAsExpression(current)) {
24270
24736
  current = current.getExpression();
24271
24737
  }
24272
24738
  return current;
24273
24739
  }
24274
24740
  function asObjectLiteral(node) {
24275
24741
  const inner = unwrapAsExpressions(node);
24276
- if (inner && Node17.isObjectLiteralExpression(inner)) {
24742
+ if (inner && Node18.isObjectLiteralExpression(inner)) {
24277
24743
  return inner;
24278
24744
  }
24279
24745
  return void 0;
24280
24746
  }
24281
24747
  function asArrayLiteral(node) {
24282
24748
  const inner = unwrapAsExpressions(node);
24283
- if (inner && Node17.isArrayLiteralExpression(inner)) {
24749
+ if (inner && Node18.isArrayLiteralExpression(inner)) {
24284
24750
  return inner;
24285
24751
  }
24286
24752
  return void 0;
24287
24753
  }
24288
24754
  function readStringLiteralInitializer(decl) {
24289
24755
  const initializer = unwrapAsExpressions(decl.getInitializer());
24290
- if (initializer && Node17.isStringLiteral(initializer)) {
24756
+ if (initializer && Node18.isStringLiteral(initializer)) {
24291
24757
  return initializer.getLiteralText();
24292
24758
  }
24293
24759
  return void 0;
@@ -24299,37 +24765,37 @@ function typeAnnotationText(node) {
24299
24765
  function getPropertyInitializer(obj, name) {
24300
24766
  const prop = obj.getProperty(name);
24301
24767
  if (!prop) return void 0;
24302
- if (Node17.isPropertyAssignment(prop)) {
24768
+ if (Node18.isPropertyAssignment(prop)) {
24303
24769
  return prop.getInitializer();
24304
24770
  }
24305
- if (Node17.isShorthandPropertyAssignment(prop)) {
24771
+ if (Node18.isShorthandPropertyAssignment(prop)) {
24306
24772
  return prop.getNameNode();
24307
24773
  }
24308
24774
  return void 0;
24309
24775
  }
24310
24776
  function readStringProperty2(obj, name) {
24311
24777
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
24312
- if (init && Node17.isStringLiteral(init)) {
24778
+ if (init && Node18.isStringLiteral(init)) {
24313
24779
  return init.getLiteralText();
24314
24780
  }
24315
24781
  return void 0;
24316
24782
  }
24317
24783
  function readIdentifierProperty(obj, name) {
24318
24784
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
24319
- if (init && Node17.isIdentifier(init)) {
24785
+ if (init && Node18.isIdentifier(init)) {
24320
24786
  return init.getText();
24321
24787
  }
24322
24788
  return void 0;
24323
24789
  }
24324
24790
  function findReturnExpression(fn) {
24325
- if (!Node17.isArrowFunction(fn) && !Node17.isFunctionDeclaration(fn) && !Node17.isFunctionExpression(fn)) {
24791
+ if (!Node18.isArrowFunction(fn) && !Node18.isFunctionDeclaration(fn) && !Node18.isFunctionExpression(fn)) {
24326
24792
  return void 0;
24327
24793
  }
24328
24794
  const body = fn.getBody();
24329
24795
  if (!body) return void 0;
24330
- if (Node17.isBlock(body)) {
24796
+ if (Node18.isBlock(body)) {
24331
24797
  for (const stmt of body.getStatements()) {
24332
- if (Node17.isReturnStatement(stmt)) {
24798
+ if (Node18.isReturnStatement(stmt)) {
24333
24799
  return stmt.getExpression();
24334
24800
  }
24335
24801
  }
@@ -24349,7 +24815,7 @@ function findLocalVariable(sf, name) {
24349
24815
  return void 0;
24350
24816
  }
24351
24817
  function collectTypeofReferences(node, out) {
24352
- if (Node17.isTypeQuery(node)) {
24818
+ if (Node18.isTypeQuery(node)) {
24353
24819
  out.push(node.getExprName().getText());
24354
24820
  return;
24355
24821
  }
@@ -24551,7 +25017,7 @@ function buildApiFunctionIndex(sources) {
24551
25017
  for (const decl of stmt.getDeclarations()) {
24552
25018
  const initializer = unwrapAsExpressions(decl.getInitializer());
24553
25019
  if (!initializer) continue;
24554
- if (Node18.isArrowFunction(initializer) || Node18.isFunctionExpression(initializer)) {
25020
+ if (Node19.isArrowFunction(initializer) || Node19.isFunctionExpression(initializer)) {
24555
25021
  map.set(decl.getName(), { node: initializer, sourceFile: sf });
24556
25022
  }
24557
25023
  }
@@ -24564,34 +25030,34 @@ function collectInitializerBindingsFromValue(options) {
24564
25030
  const { node, sf, index, resolved, unresolved, visited } = options;
24565
25031
  const inner = unwrapAsExpressions(node);
24566
25032
  if (!inner) return false;
24567
- if (Node18.isArrayLiteralExpression(inner)) {
25033
+ if (Node19.isArrayLiteralExpression(inner)) {
24568
25034
  for (const el of inner.getElements()) {
24569
- if (Node18.isSpreadElement(el)) {
25035
+ if (Node19.isSpreadElement(el)) {
24570
25036
  const spreadInner = el.getExpression();
24571
- if (Node18.isIdentifier(spreadInner)) {
25037
+ if (Node19.isIdentifier(spreadInner)) {
24572
25038
  collectInitializerBindingsFromIdentifier({ name: spreadInner.getText(), sf, index, resolved, unresolved, visited });
24573
- } else if (Node18.isCallExpression(spreadInner)) {
25039
+ } else if (Node19.isCallExpression(spreadInner)) {
24574
25040
  const callee = spreadInner.getExpression();
24575
- if (Node18.isIdentifier(callee)) {
25041
+ if (Node19.isIdentifier(callee)) {
24576
25042
  collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
24577
25043
  }
24578
25044
  }
24579
25045
  continue;
24580
25046
  }
24581
25047
  const elementInner = unwrapAsExpressions(el);
24582
- if (elementInner && Node18.isIdentifier(elementInner)) {
25048
+ if (elementInner && Node19.isIdentifier(elementInner)) {
24583
25049
  resolved.push(elementInner.getText());
24584
25050
  }
24585
25051
  }
24586
25052
  return true;
24587
25053
  }
24588
- if (Node18.isCallExpression(inner)) {
25054
+ if (Node19.isCallExpression(inner)) {
24589
25055
  const callee = inner.getExpression();
24590
- if (Node18.isIdentifier(callee)) {
25056
+ if (Node19.isIdentifier(callee)) {
24591
25057
  return collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
24592
25058
  }
24593
25059
  }
24594
- if (Node18.isIdentifier(inner)) {
25060
+ if (Node19.isIdentifier(inner)) {
24595
25061
  return collectInitializerBindingsFromIdentifier({ name: inner.getText(), sf, index, resolved, unresolved, visited });
24596
25062
  }
24597
25063
  return false;
@@ -24630,15 +25096,15 @@ function collectUploadInitializerArray(options) {
24630
25096
  const { initializerArr, sf, index, direct, spreads, resolved, unresolved } = options;
24631
25097
  const visited = /* @__PURE__ */ new Set();
24632
25098
  for (const el of initializerArr.getElements()) {
24633
- if (Node18.isSpreadElement(el)) {
25099
+ if (Node19.isSpreadElement(el)) {
24634
25100
  const inner2 = el.getExpression();
24635
- if (Node18.isIdentifier(inner2)) {
25101
+ if (Node19.isIdentifier(inner2)) {
24636
25102
  const name = inner2.getText();
24637
25103
  spreads.push(name);
24638
25104
  collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
24639
- } else if (Node18.isCallExpression(inner2)) {
25105
+ } else if (Node19.isCallExpression(inner2)) {
24640
25106
  const callee = inner2.getExpression();
24641
- if (Node18.isIdentifier(callee)) {
25107
+ if (Node19.isIdentifier(callee)) {
24642
25108
  const name = callee.getText();
24643
25109
  spreads.push(name);
24644
25110
  collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
@@ -24647,7 +25113,7 @@ function collectUploadInitializerArray(options) {
24647
25113
  continue;
24648
25114
  }
24649
25115
  const inner = unwrapAsExpressions(el);
24650
- if (inner && Node18.isIdentifier(inner)) {
25116
+ if (inner && Node19.isIdentifier(inner)) {
24651
25117
  const name = inner.getText();
24652
25118
  direct.push(name);
24653
25119
  resolved.push(name);
@@ -24660,7 +25126,7 @@ function extractUploadServiceCalls(sources, index) {
24660
25126
  const rel = apiRelPath(sf);
24661
25127
  for (const call of sf.getDescendantsOfKind(SyntaxKind10.CallExpression)) {
24662
25128
  const expr = call.getExpression();
24663
- if (!Node18.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
25129
+ if (!Node19.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
24664
25130
  const args = call.getArguments();
24665
25131
  const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
24666
25132
  if (!first) continue;
@@ -24688,12 +25154,12 @@ function extractUploadServiceCalls(sources, index) {
24688
25154
  function resolveObjectArg(node, sf) {
24689
25155
  const inner = unwrapAsExpressions(node);
24690
25156
  if (!inner) return void 0;
24691
- if (Node18.isObjectLiteralExpression(inner)) return inner;
24692
- if (Node18.isIdentifier(inner)) {
25157
+ if (Node19.isObjectLiteralExpression(inner)) return inner;
25158
+ if (Node19.isIdentifier(inner)) {
24693
25159
  const declNode = findLocalVariable(sf, inner.getText());
24694
25160
  if (declNode) {
24695
25161
  const declInit = unwrapAsExpressions(declNode.getInitializer());
24696
- if (declInit && Node18.isObjectLiteralExpression(declInit)) {
25162
+ if (declInit && Node19.isObjectLiteralExpression(declInit)) {
24697
25163
  return declInit;
24698
25164
  }
24699
25165
  }
@@ -24703,12 +25169,12 @@ function resolveObjectArg(node, sf) {
24703
25169
  function resolveArrayFromProperty(obj, name, sf) {
24704
25170
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
24705
25171
  if (!init) return void 0;
24706
- if (Node18.isArrayLiteralExpression(init)) return init;
24707
- if (Node18.isIdentifier(init)) {
25172
+ if (Node19.isArrayLiteralExpression(init)) return init;
25173
+ if (Node19.isIdentifier(init)) {
24708
25174
  const declNode = findLocalVariable(sf, init.getText());
24709
25175
  if (declNode) {
24710
25176
  const declInit = unwrapAsExpressions(declNode.getInitializer());
24711
- if (declInit && Node18.isArrayLiteralExpression(declInit)) {
25177
+ if (declInit && Node19.isArrayLiteralExpression(declInit)) {
24712
25178
  return declInit;
24713
25179
  }
24714
25180
  }
@@ -24719,11 +25185,11 @@ function enclosingFactoryName(node) {
24719
25185
  let current = node.getParent();
24720
25186
  let result;
24721
25187
  while (current) {
24722
- if (Node18.isFunctionDeclaration(current)) {
25188
+ if (Node19.isFunctionDeclaration(current)) {
24723
25189
  result = current.getName() ?? void 0;
24724
25190
  break;
24725
25191
  }
24726
- if (Node18.isVariableDeclaration(current)) {
25192
+ if (Node19.isVariableDeclaration(current)) {
24727
25193
  result = current.getName();
24728
25194
  break;
24729
25195
  }
@@ -24777,10 +25243,10 @@ function extractProcessingConfigFromDecl(decl, rel) {
24777
25243
  function readFlowSubtasks(obj) {
24778
25244
  const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
24779
25245
  const subtasks = [];
24780
- if (flowInit && Node18.isArrayLiteralExpression(flowInit)) {
25246
+ if (flowInit && Node19.isArrayLiteralExpression(flowInit)) {
24781
25247
  for (const el of flowInit.getElements()) {
24782
25248
  const inner = unwrapAsExpressions(el);
24783
- if (inner && Node18.isObjectLiteralExpression(inner)) {
25249
+ if (inner && Node19.isObjectLiteralExpression(inner)) {
24784
25250
  const subtask = readIdentifierProperty(inner, "subtask");
24785
25251
  if (subtask) subtasks.push(subtask);
24786
25252
  }
@@ -24794,7 +25260,7 @@ function extractProcessingHandlerCalls(sources) {
24794
25260
  const rel = apiRelPath(sf);
24795
25261
  for (const call of sf.getDescendantsOfKind(SyntaxKind10.CallExpression)) {
24796
25262
  const expr = call.getExpression();
24797
- if (!Node18.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
25263
+ if (!Node19.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
24798
25264
  const args = call.getArguments();
24799
25265
  const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
24800
25266
  if (!first) continue;
@@ -24815,7 +25281,7 @@ function extractProcessingHandlerCalls(sources) {
24815
25281
  }
24816
25282
  function collectProcessorArrayElements(processorsArr, direct, spreads) {
24817
25283
  for (const el of processorsArr.getElements()) {
24818
- if (Node18.isSpreadElement(el)) {
25284
+ if (Node19.isSpreadElement(el)) {
24819
25285
  addProcessorIdentifierName(el.getExpression(), spreads);
24820
25286
  continue;
24821
25287
  }
@@ -24827,13 +25293,13 @@ function collectProcessorArrayElements(processorsArr, direct, spreads) {
24827
25293
  }
24828
25294
  function addProcessorIdentifierName(node, bucket) {
24829
25295
  if (!node) return;
24830
- if (Node18.isIdentifier(node)) {
25296
+ if (Node19.isIdentifier(node)) {
24831
25297
  bucket.push(node.getText());
24832
25298
  return;
24833
25299
  }
24834
- if (Node18.isCallExpression(node)) {
25300
+ if (Node19.isCallExpression(node)) {
24835
25301
  const callee = node.getExpression();
24836
- if (Node18.isIdentifier(callee)) {
25302
+ if (Node19.isIdentifier(callee)) {
24837
25303
  bucket.push(callee.getText());
24838
25304
  }
24839
25305
  }
@@ -25825,7 +26291,7 @@ var storageFileMValidateFolderTool = createTwoSideValidateTool({
25825
26291
  });
25826
26292
 
25827
26293
  // packages/dbx-components-mcp/src/tools/notification-m-validate-app/extract.ts
25828
- import { Node as Node19, SyntaxKind as SyntaxKind11 } from "ts-morph";
26294
+ import { Node as Node20, SyntaxKind as SyntaxKind11 } from "ts-morph";
25829
26295
  var NOTIF_TEMPLATE_TYPE = "NotificationTemplateType";
25830
26296
  var NOTIF_TEMPLATE_TYPE_INFO = "NotificationTemplateTypeInfo";
25831
26297
  var NOTIF_TEMPLATE_TYPE_INFO_ARRAY = "NotificationTemplateTypeInfo[]";
@@ -25946,7 +26412,7 @@ function extractTemplateInfoAggregates(sources) {
25946
26412
  const ids = [];
25947
26413
  for (const el of arr.getElements()) {
25948
26414
  const inner = unwrapAsExpressions(el);
25949
- if (inner && Node19.isIdentifier(inner)) {
26415
+ if (inner && Node20.isIdentifier(inner)) {
25950
26416
  ids.push(inner.getText());
25951
26417
  }
25952
26418
  }
@@ -25992,7 +26458,7 @@ function extractTaskAllTypesAggregates(sources) {
25992
26458
  const ids = [];
25993
26459
  for (const el of arr.getElements()) {
25994
26460
  const inner = unwrapAsExpressions(el);
25995
- if (inner && Node19.isIdentifier(inner)) {
26461
+ if (inner && Node20.isIdentifier(inner)) {
25996
26462
  ids.push(inner.getText());
25997
26463
  }
25998
26464
  }
@@ -26020,14 +26486,14 @@ function extractTaskCheckpointAliases(sources) {
26020
26486
  return out;
26021
26487
  }
26022
26488
  function collectStringLiterals(node, out) {
26023
- if (Node19.isLiteralTypeNode(node)) {
26489
+ if (Node20.isLiteralTypeNode(node)) {
26024
26490
  const lit = node.getLiteral();
26025
- if (Node19.isStringLiteral(lit)) {
26491
+ if (Node20.isStringLiteral(lit)) {
26026
26492
  out.push(lit.getLiteralText());
26027
26493
  }
26028
26494
  return;
26029
26495
  }
26030
- if (Node19.isUnionTypeNode(node)) {
26496
+ if (Node20.isUnionTypeNode(node)) {
26031
26497
  for (const child of node.getTypeNodes()) {
26032
26498
  collectStringLiterals(child, out);
26033
26499
  }
@@ -26081,7 +26547,7 @@ function extractTemplateInfoRecord(sources, index) {
26081
26547
  }
26082
26548
  function tryReadTemplateInfoRecord(decl, rel, index) {
26083
26549
  const initializer = unwrapAsExpressions(decl.getInitializer());
26084
- if (!initializer || !Node19.isCallExpression(initializer)) return void 0;
26550
+ if (!initializer || !Node20.isCallExpression(initializer)) return void 0;
26085
26551
  if (initializer.getExpression().getText() !== TEMPLATE_INFO_RECORD_FACTORY) return void 0;
26086
26552
  const args = initializer.getArguments();
26087
26553
  const arr = args[0] ? asArrayLiteral(args[0]) : void 0;
@@ -26102,15 +26568,15 @@ function tryReadTemplateInfoRecord(decl, rel, index) {
26102
26568
  }
26103
26569
  function classifyInfoRecordArrayElements(arr, direct, spreads) {
26104
26570
  for (const el of arr.getElements()) {
26105
- if (Node19.isSpreadElement(el)) {
26571
+ if (Node20.isSpreadElement(el)) {
26106
26572
  const inner2 = el.getExpression();
26107
- if (Node19.isIdentifier(inner2)) {
26573
+ if (Node20.isIdentifier(inner2)) {
26108
26574
  spreads.push(inner2.getText());
26109
26575
  }
26110
26576
  continue;
26111
26577
  }
26112
26578
  const inner = unwrapAsExpressions(el);
26113
- if (inner && Node19.isIdentifier(inner)) {
26579
+ if (inner && Node20.isIdentifier(inner)) {
26114
26580
  direct.push(inner.getText());
26115
26581
  }
26116
26582
  }
@@ -26137,7 +26603,7 @@ function extractTemplateInfoRecordWiring(sources) {
26137
26603
  const first = args[0];
26138
26604
  if (!first) continue;
26139
26605
  const inner = unwrapAsExpressions(first);
26140
- if (!inner || !Node19.isIdentifier(inner)) continue;
26606
+ if (!inner || !Node20.isIdentifier(inner)) continue;
26141
26607
  const result = {
26142
26608
  recordIdentifier: inner.getText(),
26143
26609
  sourceFile: rel
@@ -26175,7 +26641,7 @@ function buildApiFunctionIndex2(sources) {
26175
26641
  for (const decl of stmt.getDeclarations()) {
26176
26642
  const initializer = unwrapAsExpressions(decl.getInitializer());
26177
26643
  if (!initializer) continue;
26178
- if (Node19.isArrowFunction(initializer) || Node19.isFunctionExpression(initializer)) {
26644
+ if (Node20.isArrowFunction(initializer) || Node20.isFunctionExpression(initializer)) {
26179
26645
  map.set(decl.getName(), { node: initializer, sourceFile: sf, relPath: rel });
26180
26646
  }
26181
26647
  }
@@ -26211,11 +26677,11 @@ function extractTemplateConfigsArrayFactory(sources, index) {
26211
26677
  const arr = returnExpr ? asArrayLiteral(returnExpr) : void 0;
26212
26678
  if (arr) {
26213
26679
  for (const el of arr.getElements()) {
26214
- if (Node19.isSpreadElement(el)) {
26680
+ if (Node20.isSpreadElement(el)) {
26215
26681
  const inner2 = el.getExpression();
26216
- if (Node19.isCallExpression(inner2)) {
26682
+ if (Node20.isCallExpression(inner2)) {
26217
26683
  const callee = inner2.getExpression();
26218
- if (Node19.isIdentifier(callee)) {
26684
+ if (Node20.isIdentifier(callee)) {
26219
26685
  const callName = callee.getText();
26220
26686
  spreadCalls.push(callName);
26221
26687
  if (!index.functionsByName.has(callName)) {
@@ -26226,9 +26692,9 @@ function extractTemplateConfigsArrayFactory(sources, index) {
26226
26692
  continue;
26227
26693
  }
26228
26694
  const inner = unwrapAsExpressions(el);
26229
- if (inner && Node19.isCallExpression(inner)) {
26695
+ if (inner && Node20.isCallExpression(inner)) {
26230
26696
  const callee = inner.getExpression();
26231
- if (Node19.isIdentifier(callee)) {
26697
+ if (Node20.isIdentifier(callee)) {
26232
26698
  directCalls.push(callee.getText());
26233
26699
  }
26234
26700
  }
@@ -26277,11 +26743,11 @@ function collectFromArrayEntryFactory(name, out, index) {
26277
26743
  const arr = asArrayLiteral(returnExpr);
26278
26744
  if (!arr) return;
26279
26745
  for (const el of arr.getElements()) {
26280
- if (Node19.isSpreadElement(el)) {
26746
+ if (Node20.isSpreadElement(el)) {
26281
26747
  const inner2 = el.getExpression();
26282
- if (Node19.isCallExpression(inner2)) {
26748
+ if (Node20.isCallExpression(inner2)) {
26283
26749
  const callee = inner2.getExpression();
26284
- if (Node19.isIdentifier(callee)) {
26750
+ if (Node20.isIdentifier(callee)) {
26285
26751
  collectFromArrayEntryFactory(callee.getText(), out, index);
26286
26752
  }
26287
26753
  }
@@ -26289,9 +26755,9 @@ function collectFromArrayEntryFactory(name, out, index) {
26289
26755
  }
26290
26756
  const inner = unwrapAsExpressions(el);
26291
26757
  if (!inner) continue;
26292
- if (Node19.isCallExpression(inner)) {
26758
+ if (Node20.isCallExpression(inner)) {
26293
26759
  const callee = inner.getExpression();
26294
- if (Node19.isIdentifier(callee)) {
26760
+ if (Node20.isIdentifier(callee)) {
26295
26761
  collectFromSingleEntryFactory(callee.getText(), out, index);
26296
26762
  }
26297
26763
  continue;
@@ -26311,7 +26777,7 @@ function extractTaskServiceCalls(sources, index, trustedExternal) {
26311
26777
  const rel = apiRelPath(sf);
26312
26778
  for (const call of sf.getDescendantsOfKind(SyntaxKind11.CallExpression)) {
26313
26779
  const expr = call.getExpression();
26314
- if (!Node19.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
26780
+ if (!Node20.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
26315
26781
  const args = call.getArguments();
26316
26782
  const first = args[0] ? asObjectLiteral(args[0]) : void 0;
26317
26783
  if (!first) continue;
@@ -26337,13 +26803,13 @@ function collectValidateArrayElements(validateArr) {
26337
26803
  const spreads = [];
26338
26804
  if (!validateArr) return { ids, spreads };
26339
26805
  for (const el of validateArr.getElements()) {
26340
- if (Node19.isSpreadElement(el)) {
26806
+ if (Node20.isSpreadElement(el)) {
26341
26807
  const inner2 = el.getExpression();
26342
- if (Node19.isIdentifier(inner2)) spreads.push(inner2.getText());
26808
+ if (Node20.isIdentifier(inner2)) spreads.push(inner2.getText());
26343
26809
  continue;
26344
26810
  }
26345
26811
  const inner = unwrapAsExpressions(el);
26346
- if (inner && Node19.isIdentifier(inner)) ids.push(inner.getText());
26812
+ if (inner && Node20.isIdentifier(inner)) ids.push(inner.getText());
26347
26813
  }
26348
26814
  return { ids, spreads };
26349
26815
  }
@@ -26356,17 +26822,17 @@ function collectHandlersArrayElements(options) {
26356
26822
  if (!handlersArr) return { handlerTypes, unresolvedSpreads, resolvedBindings, unresolvedBindings };
26357
26823
  const visited = /* @__PURE__ */ new Set();
26358
26824
  for (const el of handlersArr.getElements()) {
26359
- if (Node19.isSpreadElement(el)) {
26825
+ if (Node20.isSpreadElement(el)) {
26360
26826
  consumeHandlersSpreadElement({ inner: el.getExpression(), sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited });
26361
26827
  continue;
26362
26828
  }
26363
26829
  const inner = unwrapAsExpressions(el);
26364
26830
  if (!inner) continue;
26365
- if (Node19.isIdentifier(inner)) {
26831
+ if (Node20.isIdentifier(inner)) {
26366
26832
  collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
26367
- } else if (Node19.isCallExpression(inner)) {
26833
+ } else if (Node20.isCallExpression(inner)) {
26368
26834
  const callee = inner.getExpression();
26369
- if (Node19.isIdentifier(callee)) {
26835
+ if (Node20.isIdentifier(callee)) {
26370
26836
  collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
26371
26837
  }
26372
26838
  }
@@ -26375,16 +26841,16 @@ function collectHandlersArrayElements(options) {
26375
26841
  }
26376
26842
  function consumeHandlersSpreadElement(options) {
26377
26843
  const { inner, sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited } = options;
26378
- if (Node19.isCallExpression(inner)) {
26844
+ if (Node20.isCallExpression(inner)) {
26379
26845
  const callee = inner.getExpression();
26380
- if (Node19.isIdentifier(callee)) {
26846
+ if (Node20.isIdentifier(callee)) {
26381
26847
  const name = callee.getText();
26382
26848
  unresolvedSpreads.push(name);
26383
26849
  collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
26384
26850
  }
26385
26851
  return;
26386
26852
  }
26387
- if (Node19.isIdentifier(inner)) {
26853
+ if (Node20.isIdentifier(inner)) {
26388
26854
  const name = inner.getText();
26389
26855
  unresolvedSpreads.push(name);
26390
26856
  collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
@@ -26394,20 +26860,20 @@ function collectHandlerBindingsFromValue(options) {
26394
26860
  const { node, sf, index, trustedExternal, resolved, unresolved, visited } = options;
26395
26861
  const inner = unwrapAsExpressions(node);
26396
26862
  if (!inner) return false;
26397
- if (Node19.isCallExpression(inner)) {
26863
+ if (Node20.isCallExpression(inner)) {
26398
26864
  const callee = inner.getExpression();
26399
- if (Node19.isIdentifier(callee)) {
26865
+ if (Node20.isIdentifier(callee)) {
26400
26866
  return collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
26401
26867
  }
26402
26868
  return false;
26403
26869
  }
26404
- if (Node19.isIdentifier(inner)) {
26870
+ if (Node20.isIdentifier(inner)) {
26405
26871
  return collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
26406
26872
  }
26407
- if (Node19.isArrayLiteralExpression(inner)) {
26873
+ if (Node20.isArrayLiteralExpression(inner)) {
26408
26874
  let any = false;
26409
26875
  for (const el of inner.getElements()) {
26410
- if (Node19.isSpreadElement(el)) {
26876
+ if (Node20.isSpreadElement(el)) {
26411
26877
  if (collectHandlerBindingsFromValue({ node: el.getExpression(), sf, index, trustedExternal, resolved, unresolved, visited })) {
26412
26878
  any = true;
26413
26879
  }
@@ -26433,7 +26899,7 @@ function collectHandlerBindingsFromIdentifier(options) {
26433
26899
  const typeText = typeNode ? typeNode.getText() : void 0;
26434
26900
  const isHandlerConfigTyped = typeText !== void 0 && (typeText === NOTIF_TASK_SERVICE_HANDLER_CONFIG || typeText.startsWith(`${NOTIF_TASK_SERVICE_HANDLER_CONFIG}<`));
26435
26901
  const declInit = unwrapAsExpressions(localDecl.getInitializer());
26436
- const isObjectLit = declInit !== void 0 && Node19.isObjectLiteralExpression(declInit);
26902
+ const isObjectLit = declInit !== void 0 && Node20.isObjectLiteralExpression(declInit);
26437
26903
  if (isHandlerConfigTyped && isObjectLit) {
26438
26904
  resolved.push(localDecl.getName());
26439
26905
  resolvedAny = true;
@@ -26464,12 +26930,12 @@ function collectHandlerBindingsFromIdentifier(options) {
26464
26930
  function resolveArrayFromProperty2(obj, name, sf) {
26465
26931
  const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
26466
26932
  if (!init) return void 0;
26467
- if (Node19.isArrayLiteralExpression(init)) return init;
26468
- if (Node19.isIdentifier(init)) {
26933
+ if (Node20.isArrayLiteralExpression(init)) return init;
26934
+ if (Node20.isIdentifier(init)) {
26469
26935
  const declNode = findLocalVariable(sf, init.getText());
26470
26936
  if (declNode) {
26471
26937
  const declInit = unwrapAsExpressions(declNode.getInitializer());
26472
- if (declInit && Node19.isArrayLiteralExpression(declInit)) {
26938
+ if (declInit && Node20.isArrayLiteralExpression(declInit)) {
26473
26939
  return declInit;
26474
26940
  }
26475
26941
  }
@@ -26490,12 +26956,12 @@ function extractTaskHandlerEntries(sources) {
26490
26956
  if (!typeIdent) return;
26491
26957
  const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
26492
26958
  let flowCount;
26493
- if (flowInit && Node19.isArrayLiteralExpression(flowInit)) {
26959
+ if (flowInit && Node20.isArrayLiteralExpression(flowInit)) {
26494
26960
  flowCount = flowInit.getElements().length;
26495
26961
  }
26496
26962
  let dataArg;
26497
26963
  let checkpointArg;
26498
- if (Node19.isTypeReference(typeNode)) {
26964
+ if (Node20.isTypeReference(typeNode)) {
26499
26965
  const tArgs = typeNode.getTypeArguments();
26500
26966
  if (tArgs.length >= 1) dataArg = tArgs[0].getText();
26501
26967
  if (tArgs.length >= 2) checkpointArg = tArgs[1].getText();
@@ -27388,7 +27854,7 @@ async function inspectFolder2(path) {
27388
27854
  }
27389
27855
 
27390
27856
  // packages/dbx-components-mcp/src/tools/system-m-validate-folder/extract.ts
27391
- import { Node as Node20, Project as Project13 } from "ts-morph";
27857
+ import { Node as Node21, Project as Project13 } from "ts-morph";
27392
27858
  var TYPE_CONSTANT_SUFFIX = "_SYSTEM_STATE_TYPE";
27393
27859
  var DATA_INTERFACE_SUFFIX = "SystemData";
27394
27860
  var CONVERTER_CONFIG_TYPE = "SystemStateStoredDataFieldConverterConfig";
@@ -27452,7 +27918,7 @@ function findDataInterfaces2(sourceFile) {
27452
27918
  return out;
27453
27919
  }
27454
27920
  function extendsSystemStateStoredData(iface) {
27455
- if (!Node20.isInterfaceDeclaration(iface)) return false;
27921
+ if (!Node21.isInterfaceDeclaration(iface)) return false;
27456
27922
  for (const clause of iface.getExtends()) {
27457
27923
  const text = clause.getText();
27458
27924
  if (text === SYSTEM_STATE_STORED_DATA || text.startsWith(`${SYSTEM_STATE_STORED_DATA}<`) || text === `${SYSTEM_STATE_STORED_DATA}, ${SYSTEM_STATE_STORED_DATA}`) {
@@ -27472,14 +27938,14 @@ function findConverters2(sourceFile) {
27472
27938
  for (const decl of stmt.getDeclarations()) {
27473
27939
  const typeNode = decl.getTypeNode();
27474
27940
  if (!typeNode) continue;
27475
- if (!Node20.isTypeReference(typeNode)) continue;
27941
+ if (!Node21.isTypeReference(typeNode)) continue;
27476
27942
  const typeName = typeNode.getTypeName().getText();
27477
27943
  if (typeName !== CONVERTER_CONFIG_TYPE) continue;
27478
27944
  const typeArgs = typeNode.getTypeArguments();
27479
27945
  let dataTypeArgument;
27480
27946
  if (typeArgs.length >= 1) {
27481
27947
  const arg = typeArgs[0];
27482
- if (Node20.isTypeReference(arg)) {
27948
+ if (Node21.isTypeReference(arg)) {
27483
27949
  dataTypeArgument = arg.getTypeName().getText();
27484
27950
  } else {
27485
27951
  dataTypeArgument = arg.getText();
@@ -27526,19 +27992,19 @@ function collectConverterMapKeys(decl) {
27526
27992
  if (!obj) return [];
27527
27993
  const out = [];
27528
27994
  for (const prop of obj.getProperties()) {
27529
- if (!Node20.isPropertyAssignment(prop)) continue;
27995
+ if (!Node21.isPropertyAssignment(prop)) continue;
27530
27996
  const nameNode = prop.getNameNode();
27531
27997
  const line = prop.getStartLineNumber();
27532
- if (Node20.isComputedPropertyName(nameNode)) {
27998
+ if (Node21.isComputedPropertyName(nameNode)) {
27533
27999
  const inner = nameNode.getExpression();
27534
28000
  out.push({ raw: inner.getText(), kind: "identifier", line });
27535
28001
  continue;
27536
28002
  }
27537
- if (Node20.isStringLiteral(nameNode)) {
28003
+ if (Node21.isStringLiteral(nameNode)) {
27538
28004
  out.push({ raw: nameNode.getLiteralText(), kind: "string", line });
27539
28005
  continue;
27540
28006
  }
27541
- if (Node20.isIdentifier(nameNode)) {
28007
+ if (Node21.isIdentifier(nameNode)) {
27542
28008
  out.push({ raw: nameNode.getText(), kind: "string", line });
27543
28009
  continue;
27544
28010
  }
@@ -27548,10 +28014,10 @@ function collectConverterMapKeys(decl) {
27548
28014
  }
27549
28015
  function unwrapObjectLiteral(node) {
27550
28016
  let current = node;
27551
- while (current && Node20.isAsExpression(current)) {
28017
+ while (current && Node21.isAsExpression(current)) {
27552
28018
  current = current.getExpression();
27553
28019
  }
27554
- if (current && Node20.isObjectLiteralExpression(current)) {
28020
+ if (current && Node21.isObjectLiteralExpression(current)) {
27555
28021
  return current;
27556
28022
  }
27557
28023
  return void 0;
@@ -27585,10 +28051,10 @@ function findLastTopLevelExportLine(sourceFile) {
27585
28051
  return last;
27586
28052
  }
27587
28053
  function isExportedTopLevel(stmt) {
27588
- if (Node20.isVariableStatement(stmt) || Node20.isFunctionDeclaration(stmt) || Node20.isClassDeclaration(stmt) || Node20.isInterfaceDeclaration(stmt) || Node20.isTypeAliasDeclaration(stmt) || Node20.isEnumDeclaration(stmt)) {
28054
+ if (Node21.isVariableStatement(stmt) || Node21.isFunctionDeclaration(stmt) || Node21.isClassDeclaration(stmt) || Node21.isInterfaceDeclaration(stmt) || Node21.isTypeAliasDeclaration(stmt) || Node21.isEnumDeclaration(stmt)) {
27589
28055
  return stmt.isExported();
27590
28056
  }
27591
- if (Node20.isExportDeclaration(stmt) || Node20.isExportAssignment(stmt)) {
28057
+ if (Node21.isExportDeclaration(stmt) || Node21.isExportAssignment(stmt)) {
27592
28058
  return true;
27593
28059
  }
27594
28060
  return false;
@@ -27899,7 +28365,7 @@ var systemMValidateFolderTool = createFolderValidateTool({
27899
28365
  });
27900
28366
 
27901
28367
  // packages/dbx-components-mcp/src/tools/dbx-asset-validate-app/extract.ts
27902
- import { Node as Node21, Project as Project14 } from "ts-morph";
28368
+ import { Node as Node22, Project as Project14 } from "ts-morph";
27903
28369
  var ASSETS_RELPATH = "src/lib/assets.ts";
27904
28370
  var BARREL_RELPATH = "src/lib/index.ts";
27905
28371
  var LOCAL_ASSET_BUILDER = "localAsset";
@@ -27958,11 +28424,11 @@ function extractFromAssetsSource(ctx, sf) {
27958
28424
  const initializer = unwrapAsExpressions(decl.getInitializer());
27959
28425
  if (!initializer) continue;
27960
28426
  const site = { isExported, symbolName: decl.getName(), line: decl.getStartLineNumber(), rel };
27961
- if (Node21.isCallExpression(initializer)) {
28427
+ if (Node22.isCallExpression(initializer)) {
27962
28428
  handleCallInitializer(ctx, site, initializer);
27963
28429
  continue;
27964
28430
  }
27965
- if (isExported && Node21.isArrayLiteralExpression(initializer) && typeAnnotationText(decl) === ASSET_PATH_REF_ARRAY_TYPE) {
28431
+ if (isExported && Node22.isArrayLiteralExpression(initializer) && typeAnnotationText(decl) === ASSET_PATH_REF_ARRAY_TYPE) {
27966
28432
  ctx.aggregatorExports.push({ symbolName: site.symbolName, memberNames: collectArrayIdentifiers(initializer.getElements()), sourceFile: rel, line: site.line });
27967
28433
  }
27968
28434
  }
@@ -27972,7 +28438,7 @@ function collectArrayIdentifiers(elements) {
27972
28438
  const out = [];
27973
28439
  for (const el of elements) {
27974
28440
  const inner = unwrapAsExpressions(el);
27975
- if (inner && Node21.isIdentifier(inner)) {
28441
+ if (inner && Node22.isIdentifier(inner)) {
27976
28442
  out.push(inner.getText());
27977
28443
  }
27978
28444
  }
@@ -27980,11 +28446,11 @@ function collectArrayIdentifiers(elements) {
27980
28446
  }
27981
28447
  function handleCallInitializer(ctx, site, callExpr) {
27982
28448
  const callee = callExpr.getExpression();
27983
- if (Node21.isIdentifier(callee)) {
28449
+ if (Node22.isIdentifier(callee)) {
27984
28450
  handleIdentifierCallee({ ctx, site, callExpr, calleeName: callee.getText() });
27985
28451
  return;
27986
28452
  }
27987
- if (Node21.isPropertyAccessExpression(callee)) {
28453
+ if (Node22.isPropertyAccessExpression(callee)) {
27988
28454
  handleFluentMemberCall(ctx, site, callExpr);
27989
28455
  }
27990
28456
  }
@@ -28042,9 +28508,9 @@ function handleRemoteBaseBuilder(ctx, site, arg) {
28042
28508
  }
28043
28509
  function handleFluentMemberCall(ctx, site, callExpr) {
28044
28510
  const callee = callExpr.getExpression();
28045
- if (!Node21.isPropertyAccessExpression(callee)) return;
28511
+ if (!Node22.isPropertyAccessExpression(callee)) return;
28046
28512
  const identNode = callee.getExpression();
28047
- if (!Node21.isIdentifier(identNode)) return;
28513
+ if (!Node22.isIdentifier(identNode)) return;
28048
28514
  const memberName = callee.getName();
28049
28515
  if (memberName !== "asset" && memberName !== "assets") return;
28050
28516
  const builderName = identNode.getText();
@@ -28069,7 +28535,7 @@ function handleFluentMemberCall(ctx, site, callExpr) {
28069
28535
  return;
28070
28536
  }
28071
28537
  const arrayInner = unwrapAsExpressions(args[0]);
28072
- if (!arrayInner || !Node21.isArrayLiteralExpression(arrayInner)) return;
28538
+ if (!arrayInner || !Node22.isArrayLiteralExpression(arrayInner)) return;
28073
28539
  const resolvedPaths = collectFluentArrayPaths({ elements: arrayInner.getElements(), sourceType, folder, remoteBase });
28074
28540
  if (site.isExported) {
28075
28541
  ctx.assetConstants.push({ symbolName: site.symbolName, sourceType, helper, resolved: void 0, resolvedPaths, sourceFile: site.rel, line: site.line });
@@ -28079,7 +28545,7 @@ function collectFluentArrayPaths(input) {
28079
28545
  const out = [];
28080
28546
  for (const el of input.elements) {
28081
28547
  const inner = unwrapAsExpressions(el);
28082
- if (inner && Node21.isStringLiteral(inner)) {
28548
+ if (inner && Node22.isStringLiteral(inner)) {
28083
28549
  const joined = joinFluent({ sourceType: input.sourceType, folder: input.folder, remoteBase: input.remoteBase, child: inner.getLiteralText() });
28084
28550
  if (joined !== void 0) out.push(joined);
28085
28551
  }
@@ -28112,7 +28578,7 @@ function readStringArg(call) {
28112
28578
  }
28113
28579
  function readStringArgFromNode(node) {
28114
28580
  const inner = unwrapAsExpressions(node);
28115
- if (inner && Node21.isStringLiteral(inner)) {
28581
+ if (inner && Node22.isStringLiteral(inner)) {
28116
28582
  return inner.getLiteralText();
28117
28583
  }
28118
28584
  return void 0;
@@ -30027,7 +30493,7 @@ import { glob as fsGlob5, readFile as readFile18, stat as stat14 } from "node:fs
30027
30493
  import { dirname as dirname13, isAbsolute as isAbsolute13, resolve as resolve34, sep as sep12 } from "node:path";
30028
30494
 
30029
30495
  // packages/dbx-components-mcp/src/tools/route/extract.ts
30030
- import { Node as Node22, Project as Project15, SyntaxKind as SyntaxKind12 } from "ts-morph";
30496
+ import { Node as Node23, Project as Project15, SyntaxKind as SyntaxKind12 } from "ts-morph";
30031
30497
  function extractFile3(source) {
30032
30498
  const project = new Project15({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
30033
30499
  const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
@@ -30042,9 +30508,9 @@ function extractFile3(source) {
30042
30508
  }
30043
30509
  for (const arrayLit of findStateArrayLiterals(sourceFile)) {
30044
30510
  for (const element of arrayLit.getElements()) {
30045
- if (Node22.isObjectLiteralExpression(element)) {
30511
+ if (Node23.isObjectLiteralExpression(element)) {
30046
30512
  addNode({ file: source.name, literal: element, fallbackConstName: void 0, into: collected, issues });
30047
- } else if (Node22.isIdentifier(element)) {
30513
+ } else if (Node23.isIdentifier(element)) {
30048
30514
  const ref = objectLiteralsByName.get(element.getText());
30049
30515
  if (ref) {
30050
30516
  addNode({ file: source.name, literal: ref.literal, fallbackConstName: element.getText(), into: collected, issues });
@@ -30065,7 +30531,7 @@ function collectStateConsts(sourceFile) {
30065
30531
  for (const stmt of sourceFile.getVariableStatements()) {
30066
30532
  for (const decl of stmt.getDeclarations()) {
30067
30533
  const initializer = decl.getInitializer();
30068
- if (!initializer || !Node22.isObjectLiteralExpression(initializer)) {
30534
+ if (!initializer || !Node23.isObjectLiteralExpression(initializer)) {
30069
30535
  continue;
30070
30536
  }
30071
30537
  const typeNode = decl.getTypeNode();
@@ -30080,7 +30546,7 @@ function findStateArrayLiterals(sourceFile) {
30080
30546
  for (const stmt of sourceFile.getVariableStatements()) {
30081
30547
  for (const decl of stmt.getDeclarations()) {
30082
30548
  const initializer = decl.getInitializer();
30083
- if (initializer && Node22.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
30549
+ if (initializer && Node23.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
30084
30550
  arrays.push(initializer);
30085
30551
  }
30086
30552
  }
@@ -30094,17 +30560,17 @@ function findStateArrayLiterals(sourceFile) {
30094
30560
  continue;
30095
30561
  }
30096
30562
  for (const arg of call.getArguments()) {
30097
- if (!Node22.isObjectLiteralExpression(arg)) {
30563
+ if (!Node23.isObjectLiteralExpression(arg)) {
30098
30564
  continue;
30099
30565
  }
30100
30566
  const statesProp = arg.getProperty("states");
30101
- if (!statesProp || !Node22.isPropertyAssignment(statesProp)) {
30567
+ if (!statesProp || !Node23.isPropertyAssignment(statesProp)) {
30102
30568
  continue;
30103
30569
  }
30104
30570
  const initializer = statesProp.getInitializer();
30105
- if (initializer && Node22.isArrayLiteralExpression(initializer)) {
30571
+ if (initializer && Node23.isArrayLiteralExpression(initializer)) {
30106
30572
  arrays.push(initializer);
30107
- } else if (initializer && Node22.isIdentifier(initializer)) {
30573
+ } else if (initializer && Node23.isIdentifier(initializer)) {
30108
30574
  const referenced = findArrayLiteralForIdentifier(sourceFile, initializer);
30109
30575
  if (referenced) {
30110
30576
  arrays.push(referenced);
@@ -30121,10 +30587,10 @@ function declarationIsStateArray(stmt, name, literal) {
30121
30587
  return true;
30122
30588
  }
30123
30589
  for (const element of literal.getElements()) {
30124
- if (Node22.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
30590
+ if (Node23.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
30125
30591
  return true;
30126
30592
  }
30127
- if (Node22.isIdentifier(element)) {
30593
+ if (Node23.isIdentifier(element)) {
30128
30594
  return true;
30129
30595
  }
30130
30596
  }
@@ -30132,11 +30598,11 @@ function declarationIsStateArray(stmt, name, literal) {
30132
30598
  }
30133
30599
  function hasStringNameProperty(literal) {
30134
30600
  const nameProp = literal.getProperty("name");
30135
- if (!nameProp || !Node22.isPropertyAssignment(nameProp)) {
30601
+ if (!nameProp || !Node23.isPropertyAssignment(nameProp)) {
30136
30602
  return false;
30137
30603
  }
30138
30604
  const initializer = nameProp.getInitializer();
30139
- return initializer !== void 0 && (Node22.isStringLiteral(initializer) || Node22.isNoSubstitutionTemplateLiteral(initializer));
30605
+ return initializer !== void 0 && (Node23.isStringLiteral(initializer) || Node23.isNoSubstitutionTemplateLiteral(initializer));
30140
30606
  }
30141
30607
  function findArrayLiteralForIdentifier(sourceFile, identifier) {
30142
30608
  const name = identifier.getText();
@@ -30146,7 +30612,7 @@ function findArrayLiteralForIdentifier(sourceFile, identifier) {
30146
30612
  continue;
30147
30613
  }
30148
30614
  const initializer = decl.getInitializer();
30149
- if (initializer && Node22.isArrayLiteralExpression(initializer)) {
30615
+ if (initializer && Node23.isArrayLiteralExpression(initializer)) {
30150
30616
  return initializer;
30151
30617
  }
30152
30618
  }
@@ -30196,21 +30662,21 @@ function addNode(options) {
30196
30662
  }
30197
30663
  function stringPropertyValue(literal, key) {
30198
30664
  const prop = literal.getProperty(key);
30199
- if (!prop || !Node22.isPropertyAssignment(prop)) {
30665
+ if (!prop || !Node23.isPropertyAssignment(prop)) {
30200
30666
  return void 0;
30201
30667
  }
30202
30668
  const initializer = prop.getInitializer();
30203
30669
  if (!initializer) {
30204
30670
  return void 0;
30205
30671
  }
30206
- if (Node22.isStringLiteral(initializer) || Node22.isNoSubstitutionTemplateLiteral(initializer)) {
30672
+ if (Node23.isStringLiteral(initializer) || Node23.isNoSubstitutionTemplateLiteral(initializer)) {
30207
30673
  return initializer.getLiteralText();
30208
30674
  }
30209
30675
  return void 0;
30210
30676
  }
30211
30677
  function booleanPropertyValue(literal, key) {
30212
30678
  const prop = literal.getProperty(key);
30213
- if (!prop || !Node22.isPropertyAssignment(prop)) {
30679
+ if (!prop || !Node23.isPropertyAssignment(prop)) {
30214
30680
  return void 0;
30215
30681
  }
30216
30682
  const initializer = prop.getInitializer();
@@ -30227,33 +30693,33 @@ function booleanPropertyValue(literal, key) {
30227
30693
  }
30228
30694
  function identifierPropertyValue(literal, key) {
30229
30695
  const prop = literal.getProperty(key);
30230
- if (!prop || !Node22.isPropertyAssignment(prop)) {
30696
+ if (!prop || !Node23.isPropertyAssignment(prop)) {
30231
30697
  return void 0;
30232
30698
  }
30233
30699
  const initializer = prop.getInitializer();
30234
30700
  if (!initializer) {
30235
30701
  return void 0;
30236
30702
  }
30237
- if (Node22.isIdentifier(initializer)) {
30703
+ if (Node23.isIdentifier(initializer)) {
30238
30704
  return initializer.getText();
30239
30705
  }
30240
- if (Node22.isPropertyAccessExpression(initializer)) {
30706
+ if (Node23.isPropertyAccessExpression(initializer)) {
30241
30707
  return initializer.getText();
30242
30708
  }
30243
30709
  return void 0;
30244
30710
  }
30245
30711
  function objectPropertyKeys(literal, key) {
30246
30712
  const prop = literal.getProperty(key);
30247
- if (!prop || !Node22.isPropertyAssignment(prop)) {
30713
+ if (!prop || !Node23.isPropertyAssignment(prop)) {
30248
30714
  return [];
30249
30715
  }
30250
30716
  const initializer = prop.getInitializer();
30251
- if (!initializer || !Node22.isObjectLiteralExpression(initializer)) {
30717
+ if (!initializer || !Node23.isObjectLiteralExpression(initializer)) {
30252
30718
  return [];
30253
30719
  }
30254
30720
  const out = [];
30255
30721
  for (const member of initializer.getProperties()) {
30256
- if (Node22.isPropertyAssignment(member) || Node22.isShorthandPropertyAssignment(member) || Node22.isMethodDeclaration(member)) {
30722
+ if (Node23.isPropertyAssignment(member) || Node23.isShorthandPropertyAssignment(member) || Node23.isMethodDeclaration(member)) {
30257
30723
  const nameNode = member.getNameNode();
30258
30724
  if (nameNode) {
30259
30725
  out.push(nameNode.getText());
@@ -30264,7 +30730,7 @@ function objectPropertyKeys(literal, key) {
30264
30730
  }
30265
30731
  function collectResolveKeys(literal) {
30266
30732
  const prop = literal.getProperty("resolve");
30267
- if (!prop || !Node22.isPropertyAssignment(prop)) {
30733
+ if (!prop || !Node23.isPropertyAssignment(prop)) {
30268
30734
  return [];
30269
30735
  }
30270
30736
  const initializer = prop.getInitializer();
@@ -30272,22 +30738,22 @@ function collectResolveKeys(literal) {
30272
30738
  return [];
30273
30739
  }
30274
30740
  const keys = [];
30275
- if (Node22.isObjectLiteralExpression(initializer)) {
30741
+ if (Node23.isObjectLiteralExpression(initializer)) {
30276
30742
  for (const member of initializer.getProperties()) {
30277
- if (Node22.isPropertyAssignment(member) || Node22.isShorthandPropertyAssignment(member) || Node22.isMethodDeclaration(member)) {
30743
+ if (Node23.isPropertyAssignment(member) || Node23.isShorthandPropertyAssignment(member) || Node23.isMethodDeclaration(member)) {
30278
30744
  const nameNode = member.getNameNode();
30279
30745
  if (nameNode) {
30280
30746
  keys.push(nameNode.getText());
30281
30747
  }
30282
30748
  }
30283
30749
  }
30284
- } else if (Node22.isArrayLiteralExpression(initializer)) {
30750
+ } else if (Node23.isArrayLiteralExpression(initializer)) {
30285
30751
  for (const element of initializer.getElements()) {
30286
- if (Node22.isObjectLiteralExpression(element)) {
30752
+ if (Node23.isObjectLiteralExpression(element)) {
30287
30753
  const tokenProp = element.getProperty("token");
30288
- if (tokenProp && Node22.isPropertyAssignment(tokenProp)) {
30754
+ if (tokenProp && Node23.isPropertyAssignment(tokenProp)) {
30289
30755
  const tokenInit = tokenProp.getInitializer();
30290
- if (tokenInit && (Node22.isStringLiteral(tokenInit) || Node22.isIdentifier(tokenInit))) {
30756
+ if (tokenInit && (Node23.isStringLiteral(tokenInit) || Node23.isIdentifier(tokenInit))) {
30291
30757
  keys.push(tokenInit.getText().replaceAll(/^['"]|['"]$/g, ""));
30292
30758
  }
30293
30759
  }
@@ -32356,7 +32822,7 @@ function createSearchModelSnapshotFieldTool(config) {
32356
32822
  import { glob, readFile as readFile19 } from "node:fs/promises";
32357
32823
  import { resolve as resolve35 } from "node:path";
32358
32824
  import { type as type59 } from "arktype";
32359
- import { Node as Node23, Project as Project16 } from "ts-morph";
32825
+ import { Node as Node24, Project as Project16 } from "ts-morph";
32360
32826
  var ListAppArgsType2 = type59({
32361
32827
  componentDir: "string",
32362
32828
  "apiDir?": "string",
@@ -32486,7 +32952,7 @@ async function buildListAppReport(input) {
32486
32952
  function findSnapshotConverterCalls(sourceFile) {
32487
32953
  const out = [];
32488
32954
  sourceFile.forEachDescendant((node) => {
32489
- if (Node23.isCallExpression(node)) {
32955
+ if (Node24.isCallExpression(node)) {
32490
32956
  const expr = node.getExpression();
32491
32957
  const exprText = expr.getText();
32492
32958
  const head = exprText.replace(/<[^>]*>$/, "");
@@ -32501,17 +32967,17 @@ function readFieldsObject(call) {
32501
32967
  const args = call.getArguments();
32502
32968
  if (args.length === 0) return void 0;
32503
32969
  const first = args[0];
32504
- if (!Node23.isObjectLiteralExpression(first)) return void 0;
32970
+ if (!Node24.isObjectLiteralExpression(first)) return void 0;
32505
32971
  const fieldsProp = first.getProperty("fields");
32506
- if (fieldsProp === void 0 || !Node23.isPropertyAssignment(fieldsProp)) return void 0;
32972
+ if (fieldsProp === void 0 || !Node24.isPropertyAssignment(fieldsProp)) return void 0;
32507
32973
  const initializer = fieldsProp.getInitializer();
32508
- if (initializer === void 0 || !Node23.isObjectLiteralExpression(initializer)) return void 0;
32974
+ if (initializer === void 0 || !Node24.isObjectLiteralExpression(initializer)) return void 0;
32509
32975
  return initializer;
32510
32976
  }
32511
32977
  function resolveModelName(call) {
32512
32978
  let current = call.getParent();
32513
32979
  while (current !== void 0) {
32514
- if (Node23.isVariableDeclaration(current)) {
32980
+ if (Node24.isVariableDeclaration(current)) {
32515
32981
  return current.getName();
32516
32982
  }
32517
32983
  current = current.getParent();
@@ -32521,10 +32987,10 @@ function resolveModelName(call) {
32521
32987
  function extractFieldUsages(fieldsObj, registry) {
32522
32988
  const out = [];
32523
32989
  for (const property of fieldsObj.getProperties()) {
32524
- if (!Node23.isPropertyAssignment(property) && !Node23.isShorthandPropertyAssignment(property)) continue;
32990
+ if (!Node24.isPropertyAssignment(property) && !Node24.isShorthandPropertyAssignment(property)) continue;
32525
32991
  const fieldName = property.getName();
32526
32992
  let converterText;
32527
- if (Node23.isShorthandPropertyAssignment(property)) {
32993
+ if (Node24.isShorthandPropertyAssignment(property)) {
32528
32994
  converterText = property.getName();
32529
32995
  } else {
32530
32996
  const initializer = property.getInitializer();
@@ -34047,7 +34513,7 @@ import { type as type64 } from "arktype";
34047
34513
  // packages/dbx-components-mcp/src/tools/model-list-component/extract.ts
34048
34514
  import { readdir as readdir12, readFile as readFile20, stat as stat16 } from "node:fs/promises";
34049
34515
  import { basename as basename6, join as join19, relative as relative11, sep as sep14 } from "node:path";
34050
- import { Node as Node24, Project as Project17 } from "ts-morph";
34516
+ import { Node as Node25, Project as Project17 } from "ts-morph";
34051
34517
  var MODEL_SUBPATH3 = "src/lib/model";
34052
34518
  var MODEL_SUBPATH_PREFIX = `${MODEL_SUBPATH3}/`;
34053
34519
  var RESERVED_NAMES = RESERVED_MODEL_FOLDERS.map((r) => r.name);
@@ -34188,7 +34654,7 @@ function findIdentityIn(sourceFile) {
34188
34654
  for (const statement of sourceFile.getVariableStatements()) {
34189
34655
  for (const decl of statement.getDeclarations()) {
34190
34656
  const initializer = decl.getInitializer();
34191
- if (!initializer || !Node24.isCallExpression(initializer)) continue;
34657
+ if (!initializer || !Node25.isCallExpression(initializer)) continue;
34192
34658
  if (initializer.getExpression().getText() !== "firestoreModelIdentity") continue;
34193
34659
  const args = initializer.getArguments();
34194
34660
  const parsed = parseIdentityArgs2(args);
@@ -34208,13 +34674,13 @@ function parseIdentityArgs2(args) {
34208
34674
  return { parentIdentityRef: void 0, collectionName: stringLiteralValue3(args[0]), collectionPrefix: stringLiteralValue3(args[1]) };
34209
34675
  }
34210
34676
  if (args.length === 3) {
34211
- const parent = Node24.isIdentifier(args[0]) ? args[0].getText() : void 0;
34677
+ const parent = Node25.isIdentifier(args[0]) ? args[0].getText() : void 0;
34212
34678
  return { parentIdentityRef: parent, collectionName: stringLiteralValue3(args[1]), collectionPrefix: stringLiteralValue3(args[2]) };
34213
34679
  }
34214
34680
  return { parentIdentityRef: void 0, collectionName: void 0, collectionPrefix: void 0 };
34215
34681
  }
34216
34682
  function stringLiteralValue3(node) {
34217
- if (Node24.isStringLiteral(node) || Node24.isNoSubstitutionTemplateLiteral(node)) {
34683
+ if (Node25.isStringLiteral(node) || Node25.isNoSubstitutionTemplateLiteral(node)) {
34218
34684
  return node.getLiteralText();
34219
34685
  }
34220
34686
  return void 0;
@@ -34376,7 +34842,7 @@ import { type as type65 } from "arktype";
34376
34842
  // packages/dbx-components-mcp/src/tools/server-actions-list-app/extract.ts
34377
34843
  import { readdir as readdir13, readFile as readFile21, stat as stat17 } from "node:fs/promises";
34378
34844
  import { dirname as dirname14, join as join20, relative as relative12, sep as sep15 } from "node:path";
34379
- import { Node as Node25, Project as Project18 } from "ts-morph";
34845
+ import { Node as Node26, Project as Project18 } from "ts-morph";
34380
34846
  var ACTION_SERVER_SUFFIX2 = ".action.server.ts";
34381
34847
  var COMMON_MODEL_SUBPATH2 = "src/app/common/model";
34382
34848
  var COMMON_BARREL_REL = "src/app/common/index.ts";
@@ -34513,7 +34979,7 @@ function inspectModuleText(input) {
34513
34979
  for (const decorator of cls.getDecorators()) {
34514
34980
  if (decorator.getName() !== "Module") continue;
34515
34981
  const args = decorator.getArguments();
34516
- if (args.length === 0 || !Node25.isObjectLiteralExpression(args[0])) continue;
34982
+ if (args.length === 0 || !Node26.isObjectLiteralExpression(args[0])) continue;
34517
34983
  const obj = args[0];
34518
34984
  providedByModule ||= moduleArrayContains(obj, "providers", input.className);
34519
34985
  exportedByModule ||= moduleArrayContains(obj, "exports", input.className);
@@ -34523,16 +34989,16 @@ function inspectModuleText(input) {
34523
34989
  }
34524
34990
  function moduleArrayContains(decoratorArg, propertyName, className) {
34525
34991
  const property = decoratorArg.getProperty(propertyName);
34526
- if (!property || !Node25.isPropertyAssignment(property)) return false;
34992
+ if (!property || !Node26.isPropertyAssignment(property)) return false;
34527
34993
  const initializer = property.getInitializer();
34528
- if (!initializer || !Node25.isArrayLiteralExpression(initializer)) return false;
34994
+ if (!initializer || !Node26.isArrayLiteralExpression(initializer)) return false;
34529
34995
  for (const element of initializer.getElements()) {
34530
- if (Node25.isIdentifier(element) && element.getText() === className) return true;
34531
- if (Node25.isObjectLiteralExpression(element)) {
34996
+ if (Node26.isIdentifier(element) && element.getText() === className) return true;
34997
+ if (Node26.isObjectLiteralExpression(element)) {
34532
34998
  const provideProp = element.getProperty("provide");
34533
- if (provideProp && Node25.isPropertyAssignment(provideProp)) {
34999
+ if (provideProp && Node26.isPropertyAssignment(provideProp)) {
34534
35000
  const provideInit = provideProp.getInitializer();
34535
- if (provideInit && Node25.isIdentifier(provideInit) && provideInit.getText() === className) return true;
35001
+ if (provideInit && Node26.isIdentifier(provideInit) && provideInit.getText() === className) return true;
34536
35002
  }
34537
35003
  }
34538
35004
  }
@@ -34586,11 +35052,11 @@ function collectInterfaceGetters(sourceFile) {
34586
35052
  const out = /* @__PURE__ */ new Map();
34587
35053
  for (const iface of sourceFile.getInterfaces()) {
34588
35054
  for (const member of iface.getMembers()) {
34589
- if (Node25.isGetAccessorDeclaration(member)) {
35055
+ if (Node26.isGetAccessorDeclaration(member)) {
34590
35056
  out.set(member.getName(), iface.getName());
34591
35057
  continue;
34592
35058
  }
34593
- if (Node25.isPropertySignature(member)) {
35059
+ if (Node26.isPropertySignature(member)) {
34594
35060
  out.set(member.getName(), iface.getName());
34595
35061
  }
34596
35062
  }
@@ -34602,7 +35068,7 @@ function collectClassGetters(sourceFile) {
34602
35068
  for (const cls of sourceFile.getClasses()) {
34603
35069
  const set = /* @__PURE__ */ new Set();
34604
35070
  for (const member of cls.getMembers()) {
34605
- if (Node25.isGetAccessorDeclaration(member)) set.add(member.getName());
35071
+ if (Node26.isGetAccessorDeclaration(member)) set.add(member.getName());
34606
35072
  }
34607
35073
  if (set.size > 0) out.set(cls.getName() ?? "<anon>", set);
34608
35074
  }
@@ -35114,7 +35580,7 @@ import { resolve as resolve43 } from "node:path";
35114
35580
  import { type as type67 } from "arktype";
35115
35581
 
35116
35582
  // packages/dbx-components-mcp/src/scan/actions-extract.ts
35117
- import { Node as Node26, SyntaxKind as SyntaxKind13 } from "ts-morph";
35583
+ import { Node as Node27, SyntaxKind as SyntaxKind13 } from "ts-morph";
35118
35584
  var ACTION_MARKER = "dbxAction";
35119
35585
  var ACTION_SLUG_TAG = "dbxActionSlug";
35120
35586
  var ACTION_ROLE_TAG = "dbxActionRole";
@@ -35322,7 +35788,7 @@ function filterStates(values) {
35322
35788
  }
35323
35789
  function readEnumMemberLiteral(member) {
35324
35790
  const initializer = member.getInitializer();
35325
- if (initializer !== void 0 && (Node26.isStringLiteral(initializer) || Node26.isNoSubstitutionTemplateLiteral(initializer))) {
35791
+ if (initializer !== void 0 && (Node27.isStringLiteral(initializer) || Node27.isNoSubstitutionTemplateLiteral(initializer))) {
35326
35792
  return initializer.getLiteralText();
35327
35793
  }
35328
35794
  return member.getName();
@@ -35942,7 +36408,7 @@ import { resolve as resolve45 } from "node:path";
35942
36408
  import { type as type71 } from "arktype";
35943
36409
 
35944
36410
  // packages/dbx-components-mcp/src/scan/pipes-extract.ts
35945
- import { Node as Node27 } from "ts-morph";
36411
+ import { Node as Node28 } from "ts-morph";
35946
36412
  var PIPE_MARKER = "dbxPipe";
35947
36413
  var PIPE_SLUG_TAG = "dbxPipeSlug";
35948
36414
  var PIPE_CATEGORY_TAG = "dbxPipeCategory";
@@ -36135,7 +36601,7 @@ function readPipeDecoratorConfig(decorator) {
36135
36601
  return void 0;
36136
36602
  }
36137
36603
  const firstArg = args[0];
36138
- if (!Node27.isObjectLiteralExpression(firstArg)) {
36604
+ if (!Node28.isObjectLiteralExpression(firstArg)) {
36139
36605
  return void 0;
36140
36606
  }
36141
36607
  const name = readStringProperty(firstArg, "name");
@@ -36148,7 +36614,7 @@ function readPipeDecoratorConfig(decorator) {
36148
36614
  }
36149
36615
  function readBooleanProperty(obj, propName) {
36150
36616
  const prop = obj.getProperty(propName);
36151
- if (prop === void 0 || !Node27.isPropertyAssignment(prop)) {
36617
+ if (prop === void 0 || !Node28.isPropertyAssignment(prop)) {
36152
36618
  return void 0;
36153
36619
  }
36154
36620
  const initializer = prop.getInitializer();
@@ -39946,7 +40412,6 @@ var DBX_TOOLS = [
39946
40412
  modelApiListAppTool,
39947
40413
  modelApiLookupTool,
39948
40414
  modelApiValidateAppTool,
39949
- modelValidateFolderTool,
39950
40415
  modelStoreScaffoldTool,
39951
40416
  modelFixtureListAppTool,
39952
40417
  modelFixtureLookupTool,
@@ -39998,7 +40463,7 @@ function createAuthClusterTools(registry) {
39998
40463
  function registerTools(server, options = {}) {
39999
40464
  const underlyingServer = server.server;
40000
40465
  const tools = [...DBX_TOOLS];
40001
- tools.push(createUiExamplesTool({ examplesRegistry: options.dbxDocsUiExamplesRegistry }), createModelValidateTool({ ruleOptions: options.modelValidateRuleOptions }), createModelFixtureValidateAppTool({ getRegistry: () => options.fixtureModelRegistry }));
40466
+ tools.push(createUiExamplesTool({ examplesRegistry: options.dbxDocsUiExamplesRegistry }), createModelValidateTool({ ruleOptions: options.modelValidateRuleOptions }), createModelValidateFolderTool({ ruleOptions: options.modelValidateRuleOptions }), createModelFixtureValidateAppTool({ getRegistry: () => options.fixtureModelRegistry }));
40002
40467
  if (options.forgeFieldRegistry !== void 0) {
40003
40468
  tools.push(createLookupFormTool({ registry: options.forgeFieldRegistry }), createSearchFormTool({ registry: options.forgeFieldRegistry }), createFormScaffoldTool({ registry: options.forgeFieldRegistry }));
40004
40469
  }
@@ -40323,9 +40788,11 @@ function resolveModelValidateRuleOptions(config) {
40323
40788
  return void 0;
40324
40789
  }
40325
40790
  const ignoredFieldNames = block.ignoredFieldNames === void 0 ? void 0 : new Set(block.ignoredFieldNames);
40791
+ const ignoredExternalParents = block.ignoredExternalParents === void 0 ? void 0 : new Set(block.ignoredExternalParents);
40326
40792
  const result = {
40327
40793
  maxFieldNameLength: block.maxFieldNameLength,
40328
- ignoredFieldNames
40794
+ ignoredFieldNames,
40795
+ ignoredExternalParents
40329
40796
  };
40330
40797
  return result;
40331
40798
  }