@dereekb/dbx-components-mcp 13.10.1 → 13.10.2
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.
package/dbx-components-mcp.js
CHANGED
|
@@ -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.10.
|
|
8
|
+
version: "13.10.2",
|
|
9
9
|
type: "module",
|
|
10
10
|
bin: {
|
|
11
11
|
"dbx-components-mcp": "dbx-components-mcp.js"
|
|
@@ -799,10 +799,10 @@ var defaultGlobber = async (input) => {
|
|
|
799
799
|
}
|
|
800
800
|
return matches;
|
|
801
801
|
};
|
|
802
|
-
async function loadPackageName(packagePath,
|
|
802
|
+
async function loadPackageName(packagePath, readFile8) {
|
|
803
803
|
let raw = null;
|
|
804
804
|
try {
|
|
805
|
-
raw = await
|
|
805
|
+
raw = await readFile8(packagePath);
|
|
806
806
|
} catch {
|
|
807
807
|
raw = null;
|
|
808
808
|
}
|
|
@@ -862,15 +862,15 @@ function globToRegex(pattern) {
|
|
|
862
862
|
var DEFAULT_READ_FILE = defaultReadFile;
|
|
863
863
|
var DEFAULT_GLOBBER = defaultGlobber;
|
|
864
864
|
async function buildForgeFieldsManifest(input) {
|
|
865
|
-
const { projectRoot, generator, readFile:
|
|
865
|
+
const { projectRoot, generator, readFile: readFile8 = DEFAULT_READ_FILE, globber = DEFAULT_GLOBBER, now = () => /* @__PURE__ */ new Date() } = input;
|
|
866
866
|
const configPath = resolve(projectRoot, FORGE_FIELDS_SCAN_CONFIG_FILENAME);
|
|
867
867
|
const packagePath = resolve(projectRoot, "package.json");
|
|
868
|
-
const configOutcome = await loadScanConfig(configPath,
|
|
868
|
+
const configOutcome = await loadScanConfig(configPath, readFile8);
|
|
869
869
|
if (configOutcome.kind !== "ok") {
|
|
870
870
|
return configOutcome.outcome;
|
|
871
871
|
}
|
|
872
872
|
const scanSection = configOutcome.section;
|
|
873
|
-
const packageOutcome = await loadPackageName(packagePath,
|
|
873
|
+
const packageOutcome = await loadPackageName(packagePath, readFile8);
|
|
874
874
|
if (packageOutcome.kind !== "ok") {
|
|
875
875
|
return packageOutcome.outcome;
|
|
876
876
|
}
|
|
@@ -883,7 +883,7 @@ async function buildForgeFieldsManifest(input) {
|
|
|
883
883
|
const project = new Project({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
884
884
|
for (const relPath of filePaths) {
|
|
885
885
|
const absolute = resolve(projectRoot, relPath);
|
|
886
|
-
const text = await
|
|
886
|
+
const text = await readFile8(absolute);
|
|
887
887
|
project.createSourceFile(absolute, text, { overwrite: true });
|
|
888
888
|
}
|
|
889
889
|
const extractResult = extractForgeFieldEntries({ project });
|
|
@@ -914,10 +914,10 @@ async function buildForgeFieldsManifest(input) {
|
|
|
914
914
|
}
|
|
915
915
|
return outcome;
|
|
916
916
|
}
|
|
917
|
-
async function loadScanConfig(configPath,
|
|
917
|
+
async function loadScanConfig(configPath, readFile8) {
|
|
918
918
|
let raw = null;
|
|
919
919
|
try {
|
|
920
|
-
raw = await
|
|
920
|
+
raw = await readFile8(configPath);
|
|
921
921
|
} catch {
|
|
922
922
|
raw = null;
|
|
923
923
|
}
|
|
@@ -983,7 +983,7 @@ import { resolve as resolve2 } from "node:path";
|
|
|
983
983
|
var DEFAULT_READ_FILE2 = (path) => nodeReadFile2(path, "utf-8");
|
|
984
984
|
var DEFAULT_WRITE_FILE = (path, data) => nodeWriteFile(path, data, "utf-8");
|
|
985
985
|
async function runScanCliBase(input, config) {
|
|
986
|
-
const { argv, cwd, generator, readFile:
|
|
986
|
+
const { argv, cwd, generator, readFile: readFile8 = DEFAULT_READ_FILE2, writeFile: writeFile2 = DEFAULT_WRITE_FILE, globber, now, log = console.log, errorLog = console.error } = input;
|
|
987
987
|
let result;
|
|
988
988
|
const args = parseScanArgs(argv);
|
|
989
989
|
if (args.kind === "parse-error") {
|
|
@@ -999,8 +999,8 @@ async function runScanCliBase(input, config) {
|
|
|
999
999
|
result = { exitCode: 2 };
|
|
1000
1000
|
} else {
|
|
1001
1001
|
const projectRoot = resolve2(cwd, args.project);
|
|
1002
|
-
const outcome = await config.buildManifest({ projectRoot, generator, readFile:
|
|
1003
|
-
result = await handleOutcome({ outcome, args, projectArg: args.project, readFile:
|
|
1002
|
+
const outcome = await config.buildManifest({ projectRoot, generator, readFile: readFile8, globber, now });
|
|
1003
|
+
result = await handleOutcome({ outcome, args, projectArg: args.project, readFile: readFile8, writeFile: writeFile2, log, errorLog, config });
|
|
1004
1004
|
}
|
|
1005
1005
|
return result;
|
|
1006
1006
|
}
|
|
@@ -1054,7 +1054,7 @@ function parseScanArgs(argv) {
|
|
|
1054
1054
|
return result;
|
|
1055
1055
|
}
|
|
1056
1056
|
async function handleOutcome(input) {
|
|
1057
|
-
const { outcome, args, projectArg, readFile:
|
|
1057
|
+
const { outcome, args, projectArg, readFile: readFile8, writeFile: writeFile2, log, errorLog, config } = input;
|
|
1058
1058
|
let result;
|
|
1059
1059
|
if (outcome.kind === "success") {
|
|
1060
1060
|
const finalOutPath = args.out === void 0 ? outcome.outPath : resolve2(outcome.outPath, "..", args.out);
|
|
@@ -1062,7 +1062,7 @@ async function handleOutcome(input) {
|
|
|
1062
1062
|
if (args.check) {
|
|
1063
1063
|
let existing = null;
|
|
1064
1064
|
try {
|
|
1065
|
-
existing = await
|
|
1065
|
+
existing = await readFile8(finalOutPath);
|
|
1066
1066
|
} catch {
|
|
1067
1067
|
existing = null;
|
|
1068
1068
|
}
|
|
@@ -1076,7 +1076,7 @@ async function handleOutcome(input) {
|
|
|
1076
1076
|
result = { exitCode: 1 };
|
|
1077
1077
|
}
|
|
1078
1078
|
} else {
|
|
1079
|
-
await
|
|
1079
|
+
await writeFile2(finalOutPath, serialized);
|
|
1080
1080
|
log(`Wrote manifest: ${finalOutPath} (${outcome.manifest.entries.length} entries, ${outcome.scannedFileCount} files scanned)`);
|
|
1081
1081
|
for (const warning of outcome.extractWarnings) {
|
|
1082
1082
|
errorLog(`extract-warning: ${config.formatExtractWarning(warning)}`);
|
|
@@ -1334,8 +1334,8 @@ function parseExampleTag(text) {
|
|
|
1334
1334
|
let result;
|
|
1335
1335
|
if (fenceMatch) {
|
|
1336
1336
|
const caption = fenceMatch[1].trim();
|
|
1337
|
-
const
|
|
1338
|
-
result = caption.length > 0 ? { caption, code:
|
|
1337
|
+
const code11 = fenceMatch[2];
|
|
1338
|
+
result = caption.length > 0 ? { caption, code: code11 } : { code: code11 };
|
|
1339
1339
|
} else {
|
|
1340
1340
|
const standaloneFence = /^```[a-zA-Z]*\n([\s\S]*?)\n```\s*$/.exec(trimmed);
|
|
1341
1341
|
if (standaloneFence) {
|
|
@@ -1542,15 +1542,15 @@ var SCAN_CONFIG_FILENAME = "dbx-mcp.scan.json";
|
|
|
1542
1542
|
var DEFAULT_READ_FILE3 = defaultReadFile;
|
|
1543
1543
|
var DEFAULT_GLOBBER2 = defaultGlobber;
|
|
1544
1544
|
async function buildManifest(input) {
|
|
1545
|
-
const { projectRoot, generator, readFile:
|
|
1545
|
+
const { projectRoot, generator, readFile: readFile8 = DEFAULT_READ_FILE3, globber = DEFAULT_GLOBBER2, now = () => /* @__PURE__ */ new Date() } = input;
|
|
1546
1546
|
const configPath = resolve3(projectRoot, SCAN_CONFIG_FILENAME);
|
|
1547
1547
|
const packagePath = resolve3(projectRoot, "package.json");
|
|
1548
|
-
const configOutcome = await loadScanConfig2(configPath,
|
|
1548
|
+
const configOutcome = await loadScanConfig2(configPath, readFile8);
|
|
1549
1549
|
if (configOutcome.kind !== "ok") {
|
|
1550
1550
|
return configOutcome.outcome;
|
|
1551
1551
|
}
|
|
1552
1552
|
const scanConfig = configOutcome.config;
|
|
1553
|
-
const packageOutcome = await loadPackageName(packagePath,
|
|
1553
|
+
const packageOutcome = await loadPackageName(packagePath, readFile8);
|
|
1554
1554
|
if (packageOutcome.kind !== "ok") {
|
|
1555
1555
|
return packageOutcome.outcome;
|
|
1556
1556
|
}
|
|
@@ -1563,7 +1563,7 @@ async function buildManifest(input) {
|
|
|
1563
1563
|
const project = new Project2({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
1564
1564
|
for (const relPath of filePaths) {
|
|
1565
1565
|
const absolute = resolve3(projectRoot, relPath);
|
|
1566
|
-
const text = await
|
|
1566
|
+
const text = await readFile8(absolute);
|
|
1567
1567
|
project.createSourceFile(absolute, text, { overwrite: true });
|
|
1568
1568
|
}
|
|
1569
1569
|
const extracted = extractEntries({ project });
|
|
@@ -1592,10 +1592,10 @@ async function buildManifest(input) {
|
|
|
1592
1592
|
}
|
|
1593
1593
|
return outcome;
|
|
1594
1594
|
}
|
|
1595
|
-
async function loadScanConfig2(configPath,
|
|
1595
|
+
async function loadScanConfig2(configPath, readFile8) {
|
|
1596
1596
|
let raw = null;
|
|
1597
1597
|
try {
|
|
1598
|
-
raw = await
|
|
1598
|
+
raw = await readFile8(configPath);
|
|
1599
1599
|
} catch {
|
|
1600
1600
|
raw = null;
|
|
1601
1601
|
}
|
|
@@ -1667,7 +1667,7 @@ var USAGE2 = [
|
|
|
1667
1667
|
var DEFAULT_READ_FILE4 = (path) => nodeReadFile3(path, "utf-8");
|
|
1668
1668
|
var DEFAULT_WRITE_FILE2 = (path, data) => nodeWriteFile2(path, data, "utf-8");
|
|
1669
1669
|
async function runScanCli(input) {
|
|
1670
|
-
const { argv, cwd, generator, readFile:
|
|
1670
|
+
const { argv, cwd, generator, readFile: readFile8 = DEFAULT_READ_FILE4, writeFile: writeFile2 = DEFAULT_WRITE_FILE2, globber, now, log = console.log, errorLog = console.error } = input;
|
|
1671
1671
|
let result;
|
|
1672
1672
|
const args = parseArgs(argv);
|
|
1673
1673
|
if (args.kind === "parse-error") {
|
|
@@ -1683,8 +1683,8 @@ async function runScanCli(input) {
|
|
|
1683
1683
|
result = { exitCode: 2 };
|
|
1684
1684
|
} else {
|
|
1685
1685
|
const projectRoot = resolve4(cwd, args.project);
|
|
1686
|
-
const outcome = await buildManifest({ projectRoot, generator, readFile:
|
|
1687
|
-
result = await handleOutcome2({ outcome, args, projectArg: args.project, readFile:
|
|
1686
|
+
const outcome = await buildManifest({ projectRoot, generator, readFile: readFile8, globber, now });
|
|
1687
|
+
result = await handleOutcome2({ outcome, args, projectArg: args.project, readFile: readFile8, writeFile: writeFile2, log, errorLog });
|
|
1688
1688
|
}
|
|
1689
1689
|
return result;
|
|
1690
1690
|
}
|
|
@@ -1738,24 +1738,24 @@ function parseArgs(argv) {
|
|
|
1738
1738
|
return result;
|
|
1739
1739
|
}
|
|
1740
1740
|
async function handleSuccessOutcome(input) {
|
|
1741
|
-
const { outcome, args, projectArg, readFile:
|
|
1741
|
+
const { outcome, args, projectArg, readFile: readFile8, writeFile: writeFile2, log, errorLog } = input;
|
|
1742
1742
|
const finalOutPath = args.out === void 0 ? outcome.outPath : resolve4(outcome.outPath, "..", args.out);
|
|
1743
1743
|
const serialized = serializeManifest(outcome.manifest);
|
|
1744
1744
|
let result;
|
|
1745
1745
|
if (args.check) {
|
|
1746
|
-
result = await checkManifest({ finalOutPath, serialized, outcome, projectArg, readFile:
|
|
1746
|
+
result = await checkManifest({ finalOutPath, serialized, outcome, projectArg, readFile: readFile8, log, errorLog });
|
|
1747
1747
|
} else {
|
|
1748
|
-
await
|
|
1748
|
+
await writeFile2(finalOutPath, serialized);
|
|
1749
1749
|
log(`Wrote manifest: ${finalOutPath} (${outcome.manifest.entries.length} entries, ${outcome.scannedFileCount} files scanned)`);
|
|
1750
1750
|
result = { exitCode: 0 };
|
|
1751
1751
|
}
|
|
1752
1752
|
return result;
|
|
1753
1753
|
}
|
|
1754
1754
|
async function checkManifest(input) {
|
|
1755
|
-
const { finalOutPath, serialized, outcome, projectArg, readFile:
|
|
1755
|
+
const { finalOutPath, serialized, outcome, projectArg, readFile: readFile8, log, errorLog } = input;
|
|
1756
1756
|
let existing;
|
|
1757
1757
|
try {
|
|
1758
|
-
existing = await
|
|
1758
|
+
existing = await readFile8(finalOutPath);
|
|
1759
1759
|
} catch {
|
|
1760
1760
|
existing = null;
|
|
1761
1761
|
}
|
|
@@ -1950,13 +1950,13 @@ function parseDecoratorInput(property) {
|
|
|
1950
1950
|
}
|
|
1951
1951
|
}
|
|
1952
1952
|
const required = requiredFromDecorator ?? !property.hasQuestionToken();
|
|
1953
|
-
const
|
|
1953
|
+
const type48 = property.getTypeNode()?.getText() ?? "unknown";
|
|
1954
1954
|
const initializer = property.getInitializer();
|
|
1955
1955
|
const defaultValue = initializer === void 0 ? void 0 : initializer.getText();
|
|
1956
1956
|
return {
|
|
1957
1957
|
propertyName,
|
|
1958
1958
|
alias: alias ?? propertyName,
|
|
1959
|
-
type:
|
|
1959
|
+
type: type48,
|
|
1960
1960
|
required,
|
|
1961
1961
|
description: readPropertyDescription(property),
|
|
1962
1962
|
...defaultValue === void 0 ? {} : { defaultValue }
|
|
@@ -2022,22 +2022,22 @@ function parseDecoratorOutput(property) {
|
|
|
2022
2022
|
alias = decoratorArg.getLiteralText();
|
|
2023
2023
|
}
|
|
2024
2024
|
const initializer = property.getInitializer();
|
|
2025
|
-
let
|
|
2025
|
+
let type48 = "unknown";
|
|
2026
2026
|
if (initializer !== void 0 && Node4.isNewExpression(initializer)) {
|
|
2027
2027
|
const typeArgs = initializer.getTypeArguments();
|
|
2028
2028
|
if (typeArgs.length > 0) {
|
|
2029
|
-
|
|
2029
|
+
type48 = typeArgs[0].getText();
|
|
2030
2030
|
}
|
|
2031
2031
|
} else {
|
|
2032
2032
|
const explicit = property.getTypeNode()?.getText();
|
|
2033
2033
|
if (explicit !== void 0) {
|
|
2034
|
-
|
|
2034
|
+
type48 = explicit;
|
|
2035
2035
|
}
|
|
2036
2036
|
}
|
|
2037
2037
|
return {
|
|
2038
2038
|
propertyName,
|
|
2039
2039
|
name: alias ?? propertyName,
|
|
2040
|
-
type:
|
|
2040
|
+
type: type48,
|
|
2041
2041
|
description: readPropertyDescription(property)
|
|
2042
2042
|
};
|
|
2043
2043
|
}
|
|
@@ -2052,7 +2052,7 @@ function parseSignalOutput(property) {
|
|
|
2052
2052
|
}
|
|
2053
2053
|
const propertyName = property.getName();
|
|
2054
2054
|
const typeArgs = initializer.getTypeArguments();
|
|
2055
|
-
const
|
|
2055
|
+
const type48 = typeArgs.length > 0 ? typeArgs[0].getText() : "void";
|
|
2056
2056
|
const args = initializer.getArguments();
|
|
2057
2057
|
let alias;
|
|
2058
2058
|
if (args.length > 0 && Node4.isObjectLiteralExpression(args[0])) {
|
|
@@ -2061,7 +2061,7 @@ function parseSignalOutput(property) {
|
|
|
2061
2061
|
return {
|
|
2062
2062
|
propertyName,
|
|
2063
2063
|
name: alias ?? propertyName,
|
|
2064
|
-
type:
|
|
2064
|
+
type: type48,
|
|
2065
2065
|
description: readPropertyDescription(property)
|
|
2066
2066
|
};
|
|
2067
2067
|
}
|
|
@@ -2448,15 +2448,15 @@ var UI_COMPONENTS_SCAN_CONFIG_FILENAME = "dbx-mcp.scan.json";
|
|
|
2448
2448
|
var DEFAULT_READ_FILE5 = defaultReadFile;
|
|
2449
2449
|
var DEFAULT_GLOBBER3 = defaultGlobber;
|
|
2450
2450
|
async function buildUiComponentsManifest(input) {
|
|
2451
|
-
const { projectRoot, generator, readFile:
|
|
2451
|
+
const { projectRoot, generator, readFile: readFile8 = DEFAULT_READ_FILE5, globber = DEFAULT_GLOBBER3, now = () => /* @__PURE__ */ new Date() } = input;
|
|
2452
2452
|
const configPath = resolve5(projectRoot, UI_COMPONENTS_SCAN_CONFIG_FILENAME);
|
|
2453
2453
|
const packagePath = resolve5(projectRoot, "package.json");
|
|
2454
|
-
const configOutcome = await loadScanConfig3(configPath,
|
|
2454
|
+
const configOutcome = await loadScanConfig3(configPath, readFile8);
|
|
2455
2455
|
if (configOutcome.kind !== "ok") {
|
|
2456
2456
|
return configOutcome.outcome;
|
|
2457
2457
|
}
|
|
2458
2458
|
const scanSection = configOutcome.section;
|
|
2459
|
-
const packageOutcome = await loadPackageName(packagePath,
|
|
2459
|
+
const packageOutcome = await loadPackageName(packagePath, readFile8);
|
|
2460
2460
|
if (packageOutcome.kind !== "ok") {
|
|
2461
2461
|
return packageOutcome.outcome;
|
|
2462
2462
|
}
|
|
@@ -2469,7 +2469,7 @@ async function buildUiComponentsManifest(input) {
|
|
|
2469
2469
|
const project = new Project3({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
2470
2470
|
for (const relPath of filePaths) {
|
|
2471
2471
|
const absolute = resolve5(projectRoot, relPath);
|
|
2472
|
-
const text = await
|
|
2472
|
+
const text = await readFile8(absolute);
|
|
2473
2473
|
project.createSourceFile(absolute, text, { overwrite: true });
|
|
2474
2474
|
}
|
|
2475
2475
|
const extractResult = extractUiEntries({ project });
|
|
@@ -2500,10 +2500,10 @@ async function buildUiComponentsManifest(input) {
|
|
|
2500
2500
|
}
|
|
2501
2501
|
return outcome;
|
|
2502
2502
|
}
|
|
2503
|
-
async function loadScanConfig3(configPath,
|
|
2503
|
+
async function loadScanConfig3(configPath, readFile8) {
|
|
2504
2504
|
let raw = null;
|
|
2505
2505
|
try {
|
|
2506
|
-
raw = await
|
|
2506
|
+
raw = await readFile8(configPath);
|
|
2507
2507
|
} catch {
|
|
2508
2508
|
raw = null;
|
|
2509
2509
|
}
|
|
@@ -2642,11 +2642,11 @@ var DbxMcpConfig = type13({
|
|
|
2642
2642
|
var CONFIG_FILENAME = "dbx-mcp.config.json";
|
|
2643
2643
|
var DEFAULT_READ_FILE6 = (path) => nodeReadFile4(path, "utf-8");
|
|
2644
2644
|
async function findAndLoadConfig(input) {
|
|
2645
|
-
const { cwd, readFile:
|
|
2645
|
+
const { cwd, readFile: readFile8 = DEFAULT_READ_FILE6 } = input;
|
|
2646
2646
|
const configPath = resolve6(cwd, CONFIG_FILENAME);
|
|
2647
2647
|
let raw = null;
|
|
2648
2648
|
try {
|
|
2649
|
-
raw = await
|
|
2649
|
+
raw = await readFile8(configPath);
|
|
2650
2650
|
} catch {
|
|
2651
2651
|
raw = null;
|
|
2652
2652
|
}
|
|
@@ -2911,10 +2911,10 @@ import { readFile as nodeReadFile5 } from "node:fs/promises";
|
|
|
2911
2911
|
import { type as type16 } from "arktype";
|
|
2912
2912
|
var DEFAULT_READ_FILE7 = (path) => nodeReadFile5(path, "utf-8");
|
|
2913
2913
|
var SUPPORTED_VERSION = 1;
|
|
2914
|
-
async function loadFromSource(source,
|
|
2914
|
+
async function loadFromSource(source, readFile8, schema) {
|
|
2915
2915
|
let raw = null;
|
|
2916
2916
|
try {
|
|
2917
|
-
raw = await
|
|
2917
|
+
raw = await readFile8(source.path);
|
|
2918
2918
|
} catch {
|
|
2919
2919
|
raw = null;
|
|
2920
2920
|
}
|
|
@@ -2971,12 +2971,12 @@ function warningSortKey(warning) {
|
|
|
2971
2971
|
return key;
|
|
2972
2972
|
}
|
|
2973
2973
|
async function loadManifestsBase(input, config) {
|
|
2974
|
-
const { sources, readFile:
|
|
2974
|
+
const { sources, readFile: readFile8 = DEFAULT_READ_FILE7 } = input;
|
|
2975
2975
|
const { name, schema, extractIndexValue, buildEntryKey } = config;
|
|
2976
2976
|
const successes = [];
|
|
2977
2977
|
const warnings = [];
|
|
2978
2978
|
for (const source of sources) {
|
|
2979
|
-
const outcome = await loadFromSource(source,
|
|
2979
|
+
const outcome = await loadFromSource(source, readFile8, schema);
|
|
2980
2980
|
if (outcome.kind === "success") {
|
|
2981
2981
|
successes.push({ source, manifest: outcome.manifest });
|
|
2982
2982
|
} else if (isStrictSource(source)) {
|
|
@@ -3080,9 +3080,9 @@ var DEFAULT_BUNDLED_PATHS = () => {
|
|
|
3080
3080
|
return DEFAULT_BUNDLED_FILENAMES.map((name) => resolve7(packageRoot, "generated", name));
|
|
3081
3081
|
};
|
|
3082
3082
|
async function loadActionRegistry(input) {
|
|
3083
|
-
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS, readFile:
|
|
3083
|
+
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS, readFile: readFile8 } = input;
|
|
3084
3084
|
const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
|
|
3085
|
-
const configResult = await findAndLoadConfig({ cwd, readFile:
|
|
3085
|
+
const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
|
|
3086
3086
|
const externalSources = [];
|
|
3087
3087
|
if (configResult.config !== null && configResult.configPath !== null) {
|
|
3088
3088
|
const baseDir = dirname(configResult.configPath);
|
|
@@ -3096,7 +3096,7 @@ async function loadActionRegistry(input) {
|
|
|
3096
3096
|
let loaderWarnings = [];
|
|
3097
3097
|
const sources = [...bundledSources, ...externalSources];
|
|
3098
3098
|
if (sources.length > 0) {
|
|
3099
|
-
const loaded = await loadActionManifests({ sources, readFile:
|
|
3099
|
+
const loaded = await loadActionManifests({ sources, readFile: readFile8 });
|
|
3100
3100
|
registry = createActionRegistry(loaded);
|
|
3101
3101
|
loaderWarnings = loaded.warnings;
|
|
3102
3102
|
}
|
|
@@ -3296,9 +3296,9 @@ var DEFAULT_BUNDLED_PATHS2 = () => {
|
|
|
3296
3296
|
return DEFAULT_BUNDLED_FILENAMES2.map((name) => resolve8(packageRoot, "generated", name));
|
|
3297
3297
|
};
|
|
3298
3298
|
async function loadFilterRegistry(input) {
|
|
3299
|
-
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS2, readFile:
|
|
3299
|
+
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS2, readFile: readFile8 } = input;
|
|
3300
3300
|
const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
|
|
3301
|
-
const configResult = await findAndLoadConfig({ cwd, readFile:
|
|
3301
|
+
const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
|
|
3302
3302
|
const externalSources = [];
|
|
3303
3303
|
if (configResult.config !== null && configResult.configPath !== null) {
|
|
3304
3304
|
const baseDir = dirname2(configResult.configPath);
|
|
@@ -3312,7 +3312,7 @@ async function loadFilterRegistry(input) {
|
|
|
3312
3312
|
let loaderWarnings = [];
|
|
3313
3313
|
const sources = [...bundledSources, ...externalSources];
|
|
3314
3314
|
if (sources.length > 0) {
|
|
3315
|
-
const loaded = await loadFilterManifests({ sources, readFile:
|
|
3315
|
+
const loaded = await loadFilterManifests({ sources, readFile: readFile8 });
|
|
3316
3316
|
registry = createFilterRegistry(loaded);
|
|
3317
3317
|
loaderWarnings = loaded.warnings;
|
|
3318
3318
|
}
|
|
@@ -3543,9 +3543,9 @@ var DEFAULT_BUNDLED_PATHS3 = () => {
|
|
|
3543
3543
|
return DEFAULT_BUNDLED_FILENAMES3.map((name) => resolve9(packageRoot, "generated", name));
|
|
3544
3544
|
};
|
|
3545
3545
|
async function loadForgeFieldRegistry(input) {
|
|
3546
|
-
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS3, readFile:
|
|
3546
|
+
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS3, readFile: readFile8 } = input;
|
|
3547
3547
|
const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
|
|
3548
|
-
const configResult = await findAndLoadConfig({ cwd, readFile:
|
|
3548
|
+
const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
|
|
3549
3549
|
const externalSources = [];
|
|
3550
3550
|
if (configResult.config !== null && configResult.configPath !== null) {
|
|
3551
3551
|
const baseDir = dirname3(configResult.configPath);
|
|
@@ -3559,7 +3559,7 @@ async function loadForgeFieldRegistry(input) {
|
|
|
3559
3559
|
let loaderWarnings = [];
|
|
3560
3560
|
const sources = [...bundledSources, ...externalSources];
|
|
3561
3561
|
if (sources.length > 0) {
|
|
3562
|
-
const loaded = await loadForgeFieldManifests({ sources, readFile:
|
|
3562
|
+
const loaded = await loadForgeFieldManifests({ sources, readFile: readFile8 });
|
|
3563
3563
|
registry = createForgeFieldRegistry(loaded);
|
|
3564
3564
|
loaderWarnings = loaded.warnings;
|
|
3565
3565
|
}
|
|
@@ -3725,9 +3725,9 @@ var DEFAULT_BUNDLED_PATHS4 = () => {
|
|
|
3725
3725
|
return DEFAULT_BUNDLED_FILENAMES4.map((name) => resolve10(packageRoot, "generated", name));
|
|
3726
3726
|
};
|
|
3727
3727
|
async function loadPipeRegistry(input) {
|
|
3728
|
-
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS4, readFile:
|
|
3728
|
+
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS4, readFile: readFile8 } = input;
|
|
3729
3729
|
const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
|
|
3730
|
-
const configResult = await findAndLoadConfig({ cwd, readFile:
|
|
3730
|
+
const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
|
|
3731
3731
|
const externalSources = [];
|
|
3732
3732
|
if (configResult.config !== null && configResult.configPath !== null) {
|
|
3733
3733
|
const baseDir = dirname4(configResult.configPath);
|
|
@@ -3741,7 +3741,7 @@ async function loadPipeRegistry(input) {
|
|
|
3741
3741
|
let loaderWarnings = [];
|
|
3742
3742
|
const sources = [...bundledSources, ...externalSources];
|
|
3743
3743
|
if (sources.length > 0) {
|
|
3744
|
-
const loaded = await loadPipeManifests({ sources, readFile:
|
|
3744
|
+
const loaded = await loadPipeManifests({ sources, readFile: readFile8 });
|
|
3745
3745
|
registry = createPipeRegistry(loaded);
|
|
3746
3746
|
loaderWarnings = loaded.warnings;
|
|
3747
3747
|
}
|
|
@@ -3845,10 +3845,10 @@ function isCoreTopic(topic) {
|
|
|
3845
3845
|
// packages/dbx-components-mcp/src/manifest/loader.ts
|
|
3846
3846
|
var DEFAULT_READ_FILE8 = (path) => nodeReadFile6(path, "utf-8");
|
|
3847
3847
|
var SUPPORTED_VERSION2 = 1;
|
|
3848
|
-
async function loadFromSource2(source,
|
|
3848
|
+
async function loadFromSource2(source, readFile8) {
|
|
3849
3849
|
let raw = null;
|
|
3850
3850
|
try {
|
|
3851
|
-
raw = await
|
|
3851
|
+
raw = await readFile8(source.path);
|
|
3852
3852
|
} catch {
|
|
3853
3853
|
}
|
|
3854
3854
|
let result;
|
|
@@ -3935,11 +3935,11 @@ function warningSortKey2(warning) {
|
|
|
3935
3935
|
return key;
|
|
3936
3936
|
}
|
|
3937
3937
|
async function loadSemanticTypeManifests(input) {
|
|
3938
|
-
const { sources, readFile:
|
|
3938
|
+
const { sources, readFile: readFile8 = DEFAULT_READ_FILE8 } = input;
|
|
3939
3939
|
const successes = [];
|
|
3940
3940
|
const warnings = [];
|
|
3941
3941
|
for (const source of sources) {
|
|
3942
|
-
const outcome = await loadFromSource2(source,
|
|
3942
|
+
const outcome = await loadFromSource2(source, readFile8);
|
|
3943
3943
|
if (outcome.kind === "success") {
|
|
3944
3944
|
successes.push({ source, manifest: outcome.manifest });
|
|
3945
3945
|
} else if (isStrictSource2(source)) {
|
|
@@ -4036,9 +4036,9 @@ var DEFAULT_BUNDLED_PATHS5 = () => {
|
|
|
4036
4036
|
return DEFAULT_BUNDLED_FILENAMES5.map((name) => resolve11(packageRoot, "generated", name));
|
|
4037
4037
|
};
|
|
4038
4038
|
async function loadSemanticTypeRegistry(input) {
|
|
4039
|
-
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS5, readFile:
|
|
4039
|
+
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS5, readFile: readFile8 } = input;
|
|
4040
4040
|
const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
|
|
4041
|
-
const configResult = await findAndLoadConfig({ cwd, readFile:
|
|
4041
|
+
const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
|
|
4042
4042
|
const externalSources = [];
|
|
4043
4043
|
if (configResult.config !== null && configResult.configPath !== null) {
|
|
4044
4044
|
const baseDir = dirname5(configResult.configPath);
|
|
@@ -4052,7 +4052,7 @@ async function loadSemanticTypeRegistry(input) {
|
|
|
4052
4052
|
let loaderWarnings = [];
|
|
4053
4053
|
const sources = [...bundledSources, ...externalSources];
|
|
4054
4054
|
if (sources.length > 0) {
|
|
4055
|
-
const loaded = await loadSemanticTypeManifests({ sources, readFile:
|
|
4055
|
+
const loaded = await loadSemanticTypeManifests({ sources, readFile: readFile8 });
|
|
4056
4056
|
registry = createSemanticTypeRegistry(loaded);
|
|
4057
4057
|
loaderWarnings = loaded.warnings;
|
|
4058
4058
|
}
|
|
@@ -4197,9 +4197,9 @@ var DEFAULT_BUNDLED_PATHS6 = () => {
|
|
|
4197
4197
|
return DEFAULT_BUNDLED_FILENAMES6.map((name) => resolve12(packageRoot, "generated", name));
|
|
4198
4198
|
};
|
|
4199
4199
|
async function loadUiComponentRegistry(input) {
|
|
4200
|
-
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS6, readFile:
|
|
4200
|
+
const { cwd, bundledManifestPaths = DEFAULT_BUNDLED_PATHS6, readFile: readFile8 } = input;
|
|
4201
4201
|
const bundledSources = bundledManifestPaths().map((path) => ({ origin: "bundled", path }));
|
|
4202
|
-
const configResult = await findAndLoadConfig({ cwd, readFile:
|
|
4202
|
+
const configResult = await findAndLoadConfig({ cwd, readFile: readFile8 });
|
|
4203
4203
|
const externalSources = [];
|
|
4204
4204
|
if (configResult.config !== null && configResult.configPath !== null) {
|
|
4205
4205
|
const baseDir = dirname6(configResult.configPath);
|
|
@@ -4213,7 +4213,7 @@ async function loadUiComponentRegistry(input) {
|
|
|
4213
4213
|
let loaderWarnings = [];
|
|
4214
4214
|
const sources = [...bundledSources, ...externalSources];
|
|
4215
4215
|
if (sources.length > 0) {
|
|
4216
|
-
const loaded = await loadUiComponentManifests({ sources, readFile:
|
|
4216
|
+
const loaded = await loadUiComponentManifests({ sources, readFile: readFile8 });
|
|
4217
4217
|
registry = createUiComponentRegistry(loaded);
|
|
4218
4218
|
loaderWarnings = loaded.warnings;
|
|
4219
4219
|
}
|
|
@@ -4227,12 +4227,6 @@ async function loadUiComponentRegistry(input) {
|
|
|
4227
4227
|
return result;
|
|
4228
4228
|
}
|
|
4229
4229
|
|
|
4230
|
-
// packages/dbx-components-mcp/src/resources/form-fields.resource.ts
|
|
4231
|
-
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4232
|
-
|
|
4233
|
-
// packages/dbx-components-mcp/src/registry/form-fields.ts
|
|
4234
|
-
var FORM_TIER_ORDER = ["field-factory", "field-derivative", "composite-builder", "template-builder", "primitive"];
|
|
4235
|
-
|
|
4236
4230
|
// packages/dbx-components-mcp/generated/firebase-models.generated.ts
|
|
4237
4231
|
var FIREBASE_MODELS = [
|
|
4238
4232
|
{
|
|
@@ -4301,7 +4295,8 @@ var FIREBASE_MODELS = [
|
|
|
4301
4295
|
],
|
|
4302
4296
|
enums: [],
|
|
4303
4297
|
detectionHints: ["m", "r", "w"],
|
|
4304
|
-
modelGroup: "Notification"
|
|
4298
|
+
modelGroup: "Notification",
|
|
4299
|
+
collectionKind: "root"
|
|
4305
4300
|
},
|
|
4306
4301
|
{
|
|
4307
4302
|
name: "NotificationSummary",
|
|
@@ -4377,7 +4372,8 @@ var FIREBASE_MODELS = [
|
|
|
4377
4372
|
],
|
|
4378
4373
|
enums: [],
|
|
4379
4374
|
detectionHints: ["m", "n", "lat", "rat"],
|
|
4380
|
-
modelGroup: "Notification"
|
|
4375
|
+
modelGroup: "Notification",
|
|
4376
|
+
collectionKind: "root"
|
|
4381
4377
|
},
|
|
4382
4378
|
{
|
|
4383
4379
|
name: "NotificationUser",
|
|
@@ -4443,7 +4439,8 @@ var FIREBASE_MODELS = [
|
|
|
4443
4439
|
],
|
|
4444
4440
|
enums: [],
|
|
4445
4441
|
detectionHints: ["b", "x", "dc", "gc", "bc", "ns"],
|
|
4446
|
-
modelGroup: "Notification"
|
|
4442
|
+
modelGroup: "Notification",
|
|
4443
|
+
collectionKind: "root"
|
|
4447
4444
|
},
|
|
4448
4445
|
{
|
|
4449
4446
|
name: "OidcEntry",
|
|
@@ -4519,7 +4516,8 @@ var FIREBASE_MODELS = [
|
|
|
4519
4516
|
],
|
|
4520
4517
|
enums: [],
|
|
4521
4518
|
detectionHints: ["type", "payload", "grantId", "userCode", "consumed", "expiresAt"],
|
|
4522
|
-
modelGroup: "OidcModel"
|
|
4519
|
+
modelGroup: "OidcModel",
|
|
4520
|
+
collectionKind: "root"
|
|
4523
4521
|
},
|
|
4524
4522
|
{
|
|
4525
4523
|
name: "StorageFile",
|
|
@@ -4776,7 +4774,8 @@ var FIREBASE_MODELS = [
|
|
|
4776
4774
|
}
|
|
4777
4775
|
],
|
|
4778
4776
|
detectionHints: ["bucketId", "pathString", "n", "ct", "fs", "ps", "pn", "pat", "pcat", "uby", "p", "pg", "sdat", "g", "gs"],
|
|
4779
|
-
modelGroup: "StorageFile"
|
|
4777
|
+
modelGroup: "StorageFile",
|
|
4778
|
+
collectionKind: "root"
|
|
4780
4779
|
},
|
|
4781
4780
|
{
|
|
4782
4781
|
name: "StorageFileGroup",
|
|
@@ -4868,7 +4867,8 @@ var FIREBASE_MODELS = [
|
|
|
4868
4867
|
],
|
|
4869
4868
|
enums: [],
|
|
4870
4869
|
detectionHints: ["f", "z", "zsf", "zat", "re", "c"],
|
|
4871
|
-
modelGroup: "StorageFile"
|
|
4870
|
+
modelGroup: "StorageFile",
|
|
4871
|
+
collectionKind: "root"
|
|
4872
4872
|
},
|
|
4873
4873
|
{
|
|
4874
4874
|
name: "SystemState",
|
|
@@ -4888,7 +4888,8 @@ var FIREBASE_MODELS = [
|
|
|
4888
4888
|
],
|
|
4889
4889
|
enums: [],
|
|
4890
4890
|
detectionHints: ["data"],
|
|
4891
|
-
modelGroup: "SystemState"
|
|
4891
|
+
modelGroup: "SystemState",
|
|
4892
|
+
collectionKind: "root"
|
|
4892
4893
|
},
|
|
4893
4894
|
{
|
|
4894
4895
|
name: "Notification",
|
|
@@ -5168,7 +5169,8 @@ var FIREBASE_MODELS = [
|
|
|
5168
5169
|
],
|
|
5169
5170
|
detectionHints: ["st", "rf", "ts", "es", "ps", "ns", "n", "r", "ois", "ots", "sat", "a", "at", "tsr", "esr", "tpr", "ut"],
|
|
5170
5171
|
parentIdentityConst: "notificationBoxIdentity",
|
|
5171
|
-
modelGroup: "Notification"
|
|
5172
|
+
modelGroup: "Notification",
|
|
5173
|
+
collectionKind: "sub-collection"
|
|
5172
5174
|
},
|
|
5173
5175
|
{
|
|
5174
5176
|
name: "NotificationWeek",
|
|
@@ -5197,10 +5199,17 @@ var FIREBASE_MODELS = [
|
|
|
5197
5199
|
enums: [],
|
|
5198
5200
|
detectionHints: ["w", "n"],
|
|
5199
5201
|
parentIdentityConst: "notificationBoxIdentity",
|
|
5200
|
-
modelGroup: "Notification"
|
|
5202
|
+
modelGroup: "Notification",
|
|
5203
|
+
collectionKind: "sub-collection"
|
|
5201
5204
|
}
|
|
5202
5205
|
];
|
|
5203
5206
|
|
|
5207
|
+
// packages/dbx-components-mcp/src/resources/form-fields.resource.ts
|
|
5208
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5209
|
+
|
|
5210
|
+
// packages/dbx-components-mcp/src/registry/form-fields.ts
|
|
5211
|
+
var FORM_TIER_ORDER = ["field-factory", "field-derivative", "composite-builder", "template-builder", "primitive"];
|
|
5212
|
+
|
|
5204
5213
|
// packages/dbx-components-mcp/src/registry/index.ts
|
|
5205
5214
|
function getFirebaseModels() {
|
|
5206
5215
|
return FIREBASE_MODELS;
|
|
@@ -6491,7 +6500,7 @@ function createLookupFormTool(config) {
|
|
|
6491
6500
|
}
|
|
6492
6501
|
return lines.join("\n").trimEnd();
|
|
6493
6502
|
}
|
|
6494
|
-
function
|
|
6503
|
+
function run5(rawArgs) {
|
|
6495
6504
|
let args;
|
|
6496
6505
|
try {
|
|
6497
6506
|
args = parseLookupFormArgs(rawArgs);
|
|
@@ -6520,7 +6529,7 @@ function createLookupFormTool(config) {
|
|
|
6520
6529
|
}
|
|
6521
6530
|
const tool = {
|
|
6522
6531
|
definition: DBX_FORM_LOOKUP_TOOL,
|
|
6523
|
-
run
|
|
6532
|
+
run: run5
|
|
6524
6533
|
};
|
|
6525
6534
|
return tool;
|
|
6526
6535
|
}
|
|
@@ -6709,7 +6718,7 @@ function formatSearchResults(input) {
|
|
|
6709
6718
|
}
|
|
6710
6719
|
function createSearchFormTool(config) {
|
|
6711
6720
|
const { registry } = config;
|
|
6712
|
-
function
|
|
6721
|
+
function run5(rawArgs) {
|
|
6713
6722
|
return runSearchTool(
|
|
6714
6723
|
{
|
|
6715
6724
|
entries: registry.all,
|
|
@@ -6725,7 +6734,7 @@ function createSearchFormTool(config) {
|
|
|
6725
6734
|
}
|
|
6726
6735
|
const tool = {
|
|
6727
6736
|
definition: DBX_FORM_SEARCH_TOOL,
|
|
6728
|
-
run
|
|
6737
|
+
run: run5
|
|
6729
6738
|
};
|
|
6730
6739
|
return tool;
|
|
6731
6740
|
}
|
|
@@ -7248,7 +7257,7 @@ function renderScaffold(specs, valueTypeName, wrapInSection) {
|
|
|
7248
7257
|
}
|
|
7249
7258
|
function createFormScaffoldTool(config) {
|
|
7250
7259
|
const { registry } = config;
|
|
7251
|
-
function
|
|
7260
|
+
function run5(rawArgs) {
|
|
7252
7261
|
let args;
|
|
7253
7262
|
try {
|
|
7254
7263
|
args = parseScaffoldArgs(rawArgs);
|
|
@@ -7267,7 +7276,7 @@ function createFormScaffoldTool(config) {
|
|
|
7267
7276
|
return toolError(lines.join("\n"));
|
|
7268
7277
|
}
|
|
7269
7278
|
const specs = parsed;
|
|
7270
|
-
const
|
|
7279
|
+
const code11 = renderScaffold(specs, args.valueTypeName, args.wrapInSection);
|
|
7271
7280
|
const slugList = specs.map((s) => s.slug).join(", ");
|
|
7272
7281
|
const preamble = `# Scaffold
|
|
7273
7282
|
|
|
@@ -7275,14 +7284,14 @@ Generated from \`${slugList}\` (${specs.length} field${specs.length === 1 ? "" :
|
|
|
7275
7284
|
const text = `${preamble}
|
|
7276
7285
|
|
|
7277
7286
|
\`\`\`ts
|
|
7278
|
-
${
|
|
7287
|
+
${code11}
|
|
7279
7288
|
\`\`\``;
|
|
7280
7289
|
const result = { content: [{ type: "text", text }] };
|
|
7281
7290
|
return result;
|
|
7282
7291
|
}
|
|
7283
7292
|
const tool = {
|
|
7284
7293
|
definition: DBX_FORM_SCAFFOLD_TOOL,
|
|
7285
|
-
run
|
|
7294
|
+
run: run5
|
|
7286
7295
|
};
|
|
7287
7296
|
return tool;
|
|
7288
7297
|
}
|
|
@@ -7543,7 +7552,7 @@ function formatNotFound3(normalized, candidates) {
|
|
|
7543
7552
|
}
|
|
7544
7553
|
function createLookupUiTool(input) {
|
|
7545
7554
|
const { registry } = input;
|
|
7546
|
-
const
|
|
7555
|
+
const run5 = (rawArgs) => {
|
|
7547
7556
|
let args;
|
|
7548
7557
|
try {
|
|
7549
7558
|
args = parseLookupUiArgs(rawArgs);
|
|
@@ -7570,7 +7579,7 @@ function createLookupUiTool(input) {
|
|
|
7570
7579
|
const result = { content: [{ type: "text", text }] };
|
|
7571
7580
|
return result;
|
|
7572
7581
|
};
|
|
7573
|
-
return { definition: DBX_UI_LOOKUP_TOOL, run };
|
|
7582
|
+
return { definition: DBX_UI_LOOKUP_TOOL, run: run5 };
|
|
7574
7583
|
}
|
|
7575
7584
|
|
|
7576
7585
|
// packages/dbx-components-mcp/src/tools/search-ui.tool.ts
|
|
@@ -7752,7 +7761,7 @@ function formatSearchResults2(options) {
|
|
|
7752
7761
|
}
|
|
7753
7762
|
function createSearchUiTool(input) {
|
|
7754
7763
|
const { registry } = input;
|
|
7755
|
-
const
|
|
7764
|
+
const run5 = (rawArgs) => {
|
|
7756
7765
|
let args;
|
|
7757
7766
|
try {
|
|
7758
7767
|
args = parseSearchUiArgs(rawArgs);
|
|
@@ -7767,7 +7776,7 @@ function createSearchUiTool(input) {
|
|
|
7767
7776
|
const result = { content: [{ type: "text", text }] };
|
|
7768
7777
|
return result;
|
|
7769
7778
|
};
|
|
7770
|
-
return { definition: DBX_UI_SEARCH_TOOL, run };
|
|
7779
|
+
return { definition: DBX_UI_SEARCH_TOOL, run: run5 };
|
|
7771
7780
|
}
|
|
7772
7781
|
|
|
7773
7782
|
// packages/dbx-components-mcp/src/tools/ui-examples.tool.ts
|
|
@@ -8956,7 +8965,7 @@ var FolderValidateArgsType = type29({
|
|
|
8956
8965
|
});
|
|
8957
8966
|
function createFolderValidateTool(config) {
|
|
8958
8967
|
const { definition, inspectFolder: inspectFolder3, validate, format } = config;
|
|
8959
|
-
async function
|
|
8968
|
+
async function run5(rawArgs) {
|
|
8960
8969
|
const parsed = FolderValidateArgsType(rawArgs);
|
|
8961
8970
|
if (parsed instanceof type29.errors) {
|
|
8962
8971
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
@@ -8996,7 +9005,7 @@ function createFolderValidateTool(config) {
|
|
|
8996
9005
|
};
|
|
8997
9006
|
return toolResult;
|
|
8998
9007
|
}
|
|
8999
|
-
const tool = { definition, run };
|
|
9008
|
+
const tool = { definition, run: run5 };
|
|
9000
9009
|
return tool;
|
|
9001
9010
|
}
|
|
9002
9011
|
var SourceValidateArgsType = type29({
|
|
@@ -9006,7 +9015,7 @@ var SourceValidateArgsType = type29({
|
|
|
9006
9015
|
});
|
|
9007
9016
|
function createSourceValidateTool(config) {
|
|
9008
9017
|
const { definition, validate, format } = config;
|
|
9009
|
-
async function
|
|
9018
|
+
async function run5(rawArgs) {
|
|
9010
9019
|
const parsed = SourceValidateArgsType(rawArgs);
|
|
9011
9020
|
if (parsed instanceof type29.errors) {
|
|
9012
9021
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
@@ -9033,7 +9042,7 @@ function createSourceValidateTool(config) {
|
|
|
9033
9042
|
};
|
|
9034
9043
|
return toolResult;
|
|
9035
9044
|
}
|
|
9036
|
-
const tool = { definition, run };
|
|
9045
|
+
const tool = { definition, run: run5 };
|
|
9037
9046
|
return tool;
|
|
9038
9047
|
}
|
|
9039
9048
|
var TwoSideValidateArgsType = type29({
|
|
@@ -9060,7 +9069,7 @@ function resolveTwoSideInput(parsed) {
|
|
|
9060
9069
|
}
|
|
9061
9070
|
function createTwoSideValidateTool(config) {
|
|
9062
9071
|
const { definition, inspectAndValidate, format } = config;
|
|
9063
|
-
async function
|
|
9072
|
+
async function run5(rawArgs) {
|
|
9064
9073
|
const parsed = TwoSideValidateArgsType(rawArgs);
|
|
9065
9074
|
if (parsed instanceof type29.errors) {
|
|
9066
9075
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
@@ -9077,7 +9086,7 @@ function createTwoSideValidateTool(config) {
|
|
|
9077
9086
|
};
|
|
9078
9087
|
return toolResult;
|
|
9079
9088
|
}
|
|
9080
|
-
const tool = { definition, run };
|
|
9089
|
+
const tool = { definition, run: run5 };
|
|
9081
9090
|
return tool;
|
|
9082
9091
|
}
|
|
9083
9092
|
var ListAppArgsType = type29({
|
|
@@ -9087,7 +9096,7 @@ var ListAppArgsType = type29({
|
|
|
9087
9096
|
});
|
|
9088
9097
|
function createListAppTool(config) {
|
|
9089
9098
|
const { definition, inspectAndList, formatMarkdown, formatJson } = config;
|
|
9090
|
-
async function
|
|
9099
|
+
async function run5(rawArgs) {
|
|
9091
9100
|
const parsed = ListAppArgsType(rawArgs);
|
|
9092
9101
|
if (parsed instanceof type29.errors) {
|
|
9093
9102
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
@@ -9101,7 +9110,7 @@ function createListAppTool(config) {
|
|
|
9101
9110
|
const toolResult = { content: [{ type: "text", text }] };
|
|
9102
9111
|
return toolResult;
|
|
9103
9112
|
}
|
|
9104
|
-
const tool = { definition, run };
|
|
9113
|
+
const tool = { definition, run: run5 };
|
|
9105
9114
|
return tool;
|
|
9106
9115
|
}
|
|
9107
9116
|
|
|
@@ -9294,6 +9303,7 @@ function extractModel(sourceFile, identity) {
|
|
|
9294
9303
|
const collectionFnName = variant === "root" ? `${camelName}FirestoreCollection` : `${camelName}FirestoreCollectionFactory`;
|
|
9295
9304
|
const collectionFn = findFunction(sourceFile, collectionFnName);
|
|
9296
9305
|
const collectionGroupFn = variant === "subcollection" ? findFunction(sourceFile, `${camelName}FirestoreCollectionGroup`) : void 0;
|
|
9306
|
+
const factoryCallKind = detectFactoryCallKind(sourceFile, collectionFnName);
|
|
9297
9307
|
const extractedIdentity = {
|
|
9298
9308
|
constName: identity.constName,
|
|
9299
9309
|
exported: identity.exported,
|
|
@@ -9318,10 +9328,38 @@ function extractModel(sourceFile, identity) {
|
|
|
9318
9328
|
collectionFactoryType,
|
|
9319
9329
|
collectionGroupType,
|
|
9320
9330
|
collectionFn,
|
|
9321
|
-
collectionGroupFn
|
|
9331
|
+
collectionGroupFn,
|
|
9332
|
+
factoryCallKind
|
|
9322
9333
|
};
|
|
9323
9334
|
return result;
|
|
9324
9335
|
}
|
|
9336
|
+
function detectFactoryCallKind(sourceFile, factoryFnName) {
|
|
9337
|
+
const fn = sourceFile.getFunction(factoryFnName);
|
|
9338
|
+
if (!fn) {
|
|
9339
|
+
return void 0;
|
|
9340
|
+
}
|
|
9341
|
+
const calls = fn.getDescendantsOfKind(SyntaxKind3.CallExpression);
|
|
9342
|
+
for (const call of calls) {
|
|
9343
|
+
const expr = call.getExpression();
|
|
9344
|
+
if (!Node6.isPropertyAccessExpression(expr)) {
|
|
9345
|
+
continue;
|
|
9346
|
+
}
|
|
9347
|
+
const name = expr.getName();
|
|
9348
|
+
if (name === "firestoreCollection") {
|
|
9349
|
+
return "root";
|
|
9350
|
+
}
|
|
9351
|
+
if (name === "rootSingleItemFirestoreCollection") {
|
|
9352
|
+
return "root-singleton";
|
|
9353
|
+
}
|
|
9354
|
+
if (name === "firestoreCollectionWithParent") {
|
|
9355
|
+
return "sub-collection";
|
|
9356
|
+
}
|
|
9357
|
+
if (name === "singleItemFirestoreCollection") {
|
|
9358
|
+
return "singleton-sub";
|
|
9359
|
+
}
|
|
9360
|
+
}
|
|
9361
|
+
return void 0;
|
|
9362
|
+
}
|
|
9325
9363
|
function deriveCamelName(constName) {
|
|
9326
9364
|
const suffix = "Identity";
|
|
9327
9365
|
return constName.endsWith(suffix) ? constName.slice(0, -suffix.length) : constName;
|
|
@@ -9788,21 +9826,37 @@ function checkCollectionType(file, model, violations) {
|
|
|
9788
9826
|
return;
|
|
9789
9827
|
}
|
|
9790
9828
|
const typeText = model.collectionType.typeText ?? "";
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
}
|
|
9829
|
+
const allowedKinds = model.variant === "root" ? ["root", "root-singleton"] : ["sub-collection", "singleton-sub"];
|
|
9830
|
+
const aliasKind = detectAliasKind(typeText);
|
|
9831
|
+
const factoryKind = model.factoryCallKind;
|
|
9832
|
+
if (aliasKind && factoryKind && aliasKind !== factoryKind) {
|
|
9833
|
+
pushViolation(violations, {
|
|
9834
|
+
code: "MODEL_COLLECTION_FACTORY_TYPE_MISMATCH",
|
|
9835
|
+
message: `Type alias \`${model.name}FirestoreCollection\` is \`${COLLECTION_TYPE_NAME[aliasKind]}\` but factory \`${expectedCollectionFnName(model)}\` calls \`firestoreContext.${COLLECTION_FACTORY_FN_NAME[factoryKind]}({...})\`. Type alias and factory body must declare the same collection kind (\`${aliasKind}\` vs \`${factoryKind}\`).`,
|
|
9836
|
+
file: file.name,
|
|
9837
|
+
line: model.collectionType.line,
|
|
9838
|
+
model: model.name
|
|
9839
|
+
});
|
|
9802
9840
|
return;
|
|
9803
9841
|
}
|
|
9804
|
-
const
|
|
9805
|
-
|
|
9842
|
+
const isAllowed = (k) => k === void 0 || allowedKinds.includes(k);
|
|
9843
|
+
if (!isAllowed(aliasKind) || !isAllowed(factoryKind)) {
|
|
9844
|
+
const offender = !isAllowed(aliasKind) ? aliasKind : factoryKind;
|
|
9845
|
+
const offenderSite = !isAllowed(aliasKind) ? "type alias" : "factory body";
|
|
9846
|
+
const variantLabel = model.variant === "root" ? "root (no parent identity)" : "subcollection (parent identity declared)";
|
|
9847
|
+
const allowedList = allowedKinds.map((k) => `\`${k}\``).join(", ");
|
|
9848
|
+
pushViolation(violations, {
|
|
9849
|
+
code: "MODEL_COLLECTION_FACTORY_TYPE_MISMATCH",
|
|
9850
|
+
message: `Model \`${model.name}\` is a ${variantLabel} but its collection ${offenderSite} is \`${offender}\`. Allowed kinds for this variant: ${allowedList}.`,
|
|
9851
|
+
file: file.name,
|
|
9852
|
+
line: model.collectionType.line,
|
|
9853
|
+
model: model.name
|
|
9854
|
+
});
|
|
9855
|
+
return;
|
|
9856
|
+
}
|
|
9857
|
+
const defaultKind = model.variant === "root" ? "root" : "singleton-sub";
|
|
9858
|
+
const expectedKind = aliasKind ?? factoryKind ?? defaultKind;
|
|
9859
|
+
const expected = expectedCollectionTypeText(expectedKind, model);
|
|
9806
9860
|
if (typeText.replaceAll(/\s+/g, "") !== expected.replaceAll(/\s+/g, "")) {
|
|
9807
9861
|
pushViolation(violations, {
|
|
9808
9862
|
code: "MODEL_COLLECTION_TYPE_WRONG_GENERIC",
|
|
@@ -9813,6 +9867,45 @@ function checkCollectionType(file, model, violations) {
|
|
|
9813
9867
|
});
|
|
9814
9868
|
}
|
|
9815
9869
|
}
|
|
9870
|
+
var COLLECTION_TYPE_NAME = {
|
|
9871
|
+
root: "FirestoreCollection",
|
|
9872
|
+
"root-singleton": "RootSingleItemFirestoreCollection",
|
|
9873
|
+
"sub-collection": "FirestoreCollectionWithParent",
|
|
9874
|
+
"singleton-sub": "SingleItemFirestoreCollection"
|
|
9875
|
+
};
|
|
9876
|
+
var COLLECTION_FACTORY_FN_NAME = {
|
|
9877
|
+
root: "firestoreCollection",
|
|
9878
|
+
"root-singleton": "rootSingleItemFirestoreCollection",
|
|
9879
|
+
"sub-collection": "firestoreCollectionWithParent",
|
|
9880
|
+
"singleton-sub": "singleItemFirestoreCollection"
|
|
9881
|
+
};
|
|
9882
|
+
function detectAliasKind(typeText) {
|
|
9883
|
+
const normalized = typeText.replaceAll(/\s+/g, "");
|
|
9884
|
+
if (normalized.startsWith("RootSingleItemFirestoreCollection<")) {
|
|
9885
|
+
return "root-singleton";
|
|
9886
|
+
}
|
|
9887
|
+
if (normalized.startsWith("SingleItemFirestoreCollection<")) {
|
|
9888
|
+
return "singleton-sub";
|
|
9889
|
+
}
|
|
9890
|
+
if (normalized.startsWith("FirestoreCollectionWithParent<")) {
|
|
9891
|
+
return "sub-collection";
|
|
9892
|
+
}
|
|
9893
|
+
if (normalized.startsWith("FirestoreCollection<")) {
|
|
9894
|
+
return "root";
|
|
9895
|
+
}
|
|
9896
|
+
return void 0;
|
|
9897
|
+
}
|
|
9898
|
+
function expectedCollectionTypeText(kind, model) {
|
|
9899
|
+
const ctor = COLLECTION_TYPE_NAME[kind];
|
|
9900
|
+
if (kind === "root" || kind === "root-singleton") {
|
|
9901
|
+
return `${ctor}<${model.name}, ${model.name}Document>`;
|
|
9902
|
+
}
|
|
9903
|
+
const parentPascal = pascalCase2(deriveCamelName2(model.identity.parentIdentityRef ?? ""));
|
|
9904
|
+
return `${ctor}<${model.name}, ${parentPascal}, ${model.name}Document, ${parentPascal}Document>`;
|
|
9905
|
+
}
|
|
9906
|
+
function expectedCollectionFnName(model) {
|
|
9907
|
+
return model.variant === "root" ? `${model.camelName}FirestoreCollection` : `${model.camelName}FirestoreCollectionFactory`;
|
|
9908
|
+
}
|
|
9816
9909
|
function checkCollectionFn(file, model, violations) {
|
|
9817
9910
|
if (model.collectionFn) {
|
|
9818
9911
|
return;
|
|
@@ -11015,11 +11108,11 @@ function checkReadonlyFields(file, violations) {
|
|
|
11015
11108
|
}
|
|
11016
11109
|
}
|
|
11017
11110
|
function checkInterfaceReadonly(options) {
|
|
11018
|
-
const { file, decl, code:
|
|
11111
|
+
const { file, decl, code: code11, violations } = options;
|
|
11019
11112
|
for (const field of decl.fields) {
|
|
11020
11113
|
if (field.readonly) continue;
|
|
11021
11114
|
pushViolation2(violations, {
|
|
11022
|
-
code:
|
|
11115
|
+
code: code11,
|
|
11023
11116
|
severity: "warning",
|
|
11024
11117
|
message: `Field \`${field.name}\` on \`${decl.name}\` should be declared \`readonly\`.`,
|
|
11025
11118
|
file: file.name,
|
|
@@ -11351,8 +11444,8 @@ async function inspectFolder(path) {
|
|
|
11351
11444
|
status = "not-directory";
|
|
11352
11445
|
}
|
|
11353
11446
|
} catch (err) {
|
|
11354
|
-
const
|
|
11355
|
-
if (
|
|
11447
|
+
const code11 = err.code;
|
|
11448
|
+
if (code11 === "ENOENT" || code11 === "ENOTDIR") {
|
|
11356
11449
|
status = "not-found";
|
|
11357
11450
|
} else {
|
|
11358
11451
|
throw err;
|
|
@@ -11919,140 +12012,1700 @@ function systemStateAccessorBody(args) {
|
|
|
11919
12012
|
if (args.functionsClass !== void 0) {
|
|
11920
12013
|
lines.push(` readonly ${functionsFieldName(args.functionsClass)} = inject(${args.functionsClass});`, "");
|
|
11921
12014
|
}
|
|
11922
|
-
lines.push(` constructor() {`, ` super(${typeConst});`, ` }`);
|
|
11923
|
-
const crudLines = renderCrudLines(args, "this.systemStateDocumentStore");
|
|
11924
|
-
if (crudLines.length > 0) {
|
|
11925
|
-
lines.push("", ...crudLines);
|
|
12015
|
+
lines.push(` constructor() {`, ` super(${typeConst});`, ` }`);
|
|
12016
|
+
const crudLines = renderCrudLines(args, "this.systemStateDocumentStore");
|
|
12017
|
+
if (crudLines.length > 0) {
|
|
12018
|
+
lines.push("", ...crudLines);
|
|
12019
|
+
}
|
|
12020
|
+
lines.push(`}`);
|
|
12021
|
+
return { path: `${args.fileBaseName}.store.accessor.ts`, body: lines.join("\n") };
|
|
12022
|
+
}
|
|
12023
|
+
function documentDirectiveBody(args) {
|
|
12024
|
+
const docType = `${args.modelName}Document`;
|
|
12025
|
+
const storeClass = `${args.modelName}DocumentStore`;
|
|
12026
|
+
const directiveClass = `${args.appPrefixPascal}${args.modelName}DocumentStoreDirective`;
|
|
12027
|
+
const selector = `[${args.appPrefixCamel}${args.modelName}Document]`;
|
|
12028
|
+
const lines = [
|
|
12029
|
+
`import { Directive, inject } from '@angular/core';`,
|
|
12030
|
+
`import { DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';`,
|
|
12031
|
+
`import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
|
|
12032
|
+
`import { ${storeClass} } from './${args.fileBaseName}.document.store';`,
|
|
12033
|
+
"",
|
|
12034
|
+
`@Directive({`,
|
|
12035
|
+
` selector: '${selector}',`,
|
|
12036
|
+
` providers: provideDbxFirebaseDocumentStoreDirective(${directiveClass}, ${storeClass}),`,
|
|
12037
|
+
` standalone: true`,
|
|
12038
|
+
`})`,
|
|
12039
|
+
`export class ${directiveClass} extends DbxFirebaseDocumentStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
|
|
12040
|
+
` constructor() {`,
|
|
12041
|
+
` super(inject(${storeClass}));`,
|
|
12042
|
+
` }`,
|
|
12043
|
+
`}`
|
|
12044
|
+
];
|
|
12045
|
+
return { path: `${args.fileBaseName}.document.store.directive.ts`, body: lines.join("\n") };
|
|
12046
|
+
}
|
|
12047
|
+
function collectionDirectiveBody(args) {
|
|
12048
|
+
const docType = `${args.modelName}Document`;
|
|
12049
|
+
const storeClass = `${args.modelName}CollectionStore`;
|
|
12050
|
+
const directiveClass = `${args.appPrefixPascal}${args.modelName}CollectionStoreDirective`;
|
|
12051
|
+
const selector = `[${args.appPrefixCamel}${args.modelName}Collection]`;
|
|
12052
|
+
const lines = [
|
|
12053
|
+
`import { Directive, inject } from '@angular/core';`,
|
|
12054
|
+
`import { DbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionStoreDirective } from '@dereekb/dbx-firebase';`,
|
|
12055
|
+
`import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
|
|
12056
|
+
`import { ${storeClass} } from './${args.fileBaseName}.collection.store';`,
|
|
12057
|
+
"",
|
|
12058
|
+
`@Directive({`,
|
|
12059
|
+
` selector: '${selector}',`,
|
|
12060
|
+
` providers: provideDbxFirebaseCollectionStoreDirective(${directiveClass}, ${storeClass}),`,
|
|
12061
|
+
` standalone: true`,
|
|
12062
|
+
`})`,
|
|
12063
|
+
`export class ${directiveClass} extends DbxFirebaseCollectionStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
|
|
12064
|
+
` constructor() {`,
|
|
12065
|
+
` super(inject(${storeClass}));`,
|
|
12066
|
+
` }`,
|
|
12067
|
+
`}`
|
|
12068
|
+
];
|
|
12069
|
+
return { path: `${args.fileBaseName}.collection.store.directive.ts`, body: lines.join("\n") };
|
|
12070
|
+
}
|
|
12071
|
+
function buildBlocks(args) {
|
|
12072
|
+
const blocks = [];
|
|
12073
|
+
if (args.shape === "system-state") {
|
|
12074
|
+
blocks.push(systemStateAccessorBody(args));
|
|
12075
|
+
} else {
|
|
12076
|
+
for (const surface of args.surfaces) {
|
|
12077
|
+
if (surface === "document") {
|
|
12078
|
+
if (args.shape === "sub-collection" || args.shape === "singleton-sub") {
|
|
12079
|
+
blocks.push(subDocumentStoreBody(args));
|
|
12080
|
+
} else {
|
|
12081
|
+
blocks.push(rootDocumentStoreBody(args));
|
|
12082
|
+
}
|
|
12083
|
+
if (args.profile.emitsDirectives) {
|
|
12084
|
+
blocks.push(documentDirectiveBody(args));
|
|
12085
|
+
}
|
|
12086
|
+
} else {
|
|
12087
|
+
if (args.shape === "sub-collection") {
|
|
12088
|
+
blocks.push(subCollectionStoreBody(args));
|
|
12089
|
+
} else {
|
|
12090
|
+
blocks.push(rootCollectionStoreBody(args));
|
|
12091
|
+
}
|
|
12092
|
+
if (args.profile.emitsDirectives) {
|
|
12093
|
+
blocks.push(collectionDirectiveBody(args));
|
|
12094
|
+
}
|
|
12095
|
+
}
|
|
12096
|
+
}
|
|
12097
|
+
}
|
|
12098
|
+
return blocks;
|
|
12099
|
+
}
|
|
12100
|
+
function formatScaffold(args) {
|
|
12101
|
+
const blocks = buildBlocks(args);
|
|
12102
|
+
const surfaceLabel = args.shape === "system-state" ? "accessor" : args.surfaces.join(" + ");
|
|
12103
|
+
const functionsLabel = args.functionsClass ?? "none";
|
|
12104
|
+
const crudLabel = args.crudFunctions.length > 0 ? args.crudFunctions.map((c) => `${c.name} (${c.kind})`).join(", ") : "none";
|
|
12105
|
+
const parentLabel = args.parentModel === void 0 ? "n/a" : args.parentModel.name;
|
|
12106
|
+
const lines = [`# ${args.modelName} store scaffold`, "", `Shape: \`${args.shape}\` \xB7 Surfaces: ${surfaceLabel} \xB7 Parent: ${parentLabel} \xB7 Functions: ${functionsLabel} \xB7 Crud: ${crudLabel}`, "", `Drop into \`<app>/src/lib/modules/${args.fileBaseName.replaceAll(".", "/")}/store/\`.`, ""];
|
|
12107
|
+
for (const block of blocks) {
|
|
12108
|
+
lines.push(`## \`${block.path}\``, "", "```ts", block.body, "```", "");
|
|
12109
|
+
}
|
|
12110
|
+
lines.push("## Notes", "", "- Each store is `@Injectable()` with no `providedIn` \u2014 wire it in the consuming feature module / route providers, alongside its directive (when present).");
|
|
12111
|
+
if (args.shape === "sub-collection" || args.shape === "singleton-sub") {
|
|
12112
|
+
lines.push(`- The \`${args.parentModel?.name}DocumentStore\` parent is injected with \`{ optional: true }\` so the store works both as a standalone and as a child of a parent's document directive.`);
|
|
12113
|
+
}
|
|
12114
|
+
if (args.shape === "system-state") {
|
|
12115
|
+
lines.push(`- The accessor wraps a shared \`SystemStateDocumentStore\` keyed by \`${args.systemStateTypeConst}\`. CRUD function helpers reference \`this.systemStateDocumentStore\` (not \`this\`).`);
|
|
12116
|
+
}
|
|
12117
|
+
if (args.crudFunctions.length > 0) {
|
|
12118
|
+
lines.push(`- ${args.crudFunctions.length} CRUD helper line${args.crudFunctions.length === 1 ? "" : "s"} wired through \`firebaseDocumentStore{Create,Update,Crud}Function\`.`);
|
|
12119
|
+
}
|
|
12120
|
+
lines.push('- \u2192 See `dbx_model_lookup topic="shapes"` for the full store-shape taxonomy.', "- \u2192 Skill: `dbx__guide__angular-stores`.");
|
|
12121
|
+
return lines.join("\n");
|
|
12122
|
+
}
|
|
12123
|
+
function runModelStoreScaffold(rawArgs) {
|
|
12124
|
+
let args;
|
|
12125
|
+
try {
|
|
12126
|
+
args = parseArgs2(rawArgs);
|
|
12127
|
+
} catch (err) {
|
|
12128
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
12129
|
+
return toolError(message);
|
|
12130
|
+
}
|
|
12131
|
+
const text = formatScaffold(args);
|
|
12132
|
+
const result = { content: [{ type: "text", text }] };
|
|
12133
|
+
return result;
|
|
12134
|
+
}
|
|
12135
|
+
var modelStoreScaffoldTool = {
|
|
12136
|
+
definition: DBX_MODEL_STORE_SCAFFOLD_TOOL,
|
|
12137
|
+
run: runModelStoreScaffold
|
|
12138
|
+
};
|
|
12139
|
+
|
|
12140
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-list-app.tool.ts
|
|
12141
|
+
import { resolve as resolve15 } from "node:path";
|
|
12142
|
+
import { type as type31 } from "arktype";
|
|
12143
|
+
|
|
12144
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/archetype.ts
|
|
12145
|
+
function classifyFixtureArchetype(input) {
|
|
12146
|
+
const { factory, params } = input;
|
|
12147
|
+
const subCollection = isSubCollection(factory);
|
|
12148
|
+
let archetype;
|
|
12149
|
+
if (subCollection) {
|
|
12150
|
+
archetype = factory?.hasCollectionForDocument ? "sub-collection-traversal" : "sub-collection";
|
|
12151
|
+
} else if (paramsHasFixtureDependencies(params)) {
|
|
12152
|
+
archetype = "top-level-with-deps";
|
|
12153
|
+
} else {
|
|
12154
|
+
archetype = "top-level-simple";
|
|
12155
|
+
}
|
|
12156
|
+
return archetype;
|
|
12157
|
+
}
|
|
12158
|
+
function isSubCollection(factory) {
|
|
12159
|
+
if (factory === void 0) return false;
|
|
12160
|
+
return factory.hasParamsGetCollection || factory.hasCollectionForDocument;
|
|
12161
|
+
}
|
|
12162
|
+
function paramsHasFixtureDependencies(params) {
|
|
12163
|
+
if (params === void 0) return false;
|
|
12164
|
+
for (const field of params.fields) {
|
|
12165
|
+
if (field.fixtureModel !== void 0) return true;
|
|
12166
|
+
}
|
|
12167
|
+
return false;
|
|
12168
|
+
}
|
|
12169
|
+
|
|
12170
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/extract.ts
|
|
12171
|
+
import { Node as Node8, Project as Project6, SyntaxKind as SyntaxKind5 } from "ts-morph";
|
|
12172
|
+
var FIXTURE_SUFFIX = "TestContextFixture";
|
|
12173
|
+
var INSTANCE_SUFFIX = "TestContextInstance";
|
|
12174
|
+
var PARAMS_SUFFIX = "TestContextParams";
|
|
12175
|
+
var FIXTURE_FILE_VIRTUAL_PATH = "__fixture__/fixture.ts";
|
|
12176
|
+
var BASE_CONTEXT_FIXTURE_BASE = "FirebaseAdminNestTestContextFixture";
|
|
12177
|
+
var MODEL_FACTORY_NAME = "modelTestContextFactory";
|
|
12178
|
+
function extractAppFixturesFromText(input) {
|
|
12179
|
+
const { text, fixturePath } = input;
|
|
12180
|
+
const project = new Project6({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
12181
|
+
const sourceFile = project.createSourceFile(FIXTURE_FILE_VIRTUAL_PATH, text, { overwrite: true });
|
|
12182
|
+
const prefix = detectPrefix(sourceFile);
|
|
12183
|
+
const fixtureClasses = /* @__PURE__ */ new Map();
|
|
12184
|
+
const instanceClasses = /* @__PURE__ */ new Map();
|
|
12185
|
+
const unrecognized = [];
|
|
12186
|
+
collectClasses(sourceFile, prefix, { fixtures: fixtureClasses, instances: instanceClasses, unrecognized });
|
|
12187
|
+
const paramsTypes = collectParamsTypes(sourceFile, prefix);
|
|
12188
|
+
const factoriesByModel = collectFactories(sourceFile, prefix);
|
|
12189
|
+
const singletonsByFactory = collectSingletonsByFactory(sourceFile);
|
|
12190
|
+
const entries = [];
|
|
12191
|
+
const seenModels = /* @__PURE__ */ new Set();
|
|
12192
|
+
const sortedModels = collectAllModels(fixtureClasses, instanceClasses);
|
|
12193
|
+
for (const model of sortedModels) {
|
|
12194
|
+
if (seenModels.has(model)) continue;
|
|
12195
|
+
seenModels.add(model);
|
|
12196
|
+
const fixtureClass = fixtureClasses.get(model);
|
|
12197
|
+
const instanceClass = instanceClasses.get(model);
|
|
12198
|
+
if (fixtureClass === void 0 || instanceClass === void 0) {
|
|
12199
|
+
continue;
|
|
12200
|
+
}
|
|
12201
|
+
const params = paramsTypes.get(model);
|
|
12202
|
+
const factory = factoriesByModel.get(model);
|
|
12203
|
+
if (factory?.factoryName) {
|
|
12204
|
+
const singleton = singletonsByFactory.get(factory.factoryName);
|
|
12205
|
+
if (singleton !== void 0) {
|
|
12206
|
+
Object.assign(factory, { singletonName: singleton });
|
|
12207
|
+
}
|
|
12208
|
+
}
|
|
12209
|
+
const archetype = classifyFixtureArchetype({ factory, params });
|
|
12210
|
+
const fixtureMethods = readClassMethods(fixtureClass);
|
|
12211
|
+
const instanceMethods = readClassMethods(instanceClass);
|
|
12212
|
+
const entry = {
|
|
12213
|
+
model,
|
|
12214
|
+
prefix: prefix ?? "",
|
|
12215
|
+
archetype,
|
|
12216
|
+
fixtureClassName: fixtureClass.getName() ?? "",
|
|
12217
|
+
instanceClassName: instanceClass.getName() ?? "",
|
|
12218
|
+
paramsTypeName: params?.name ?? `${prefix ?? ""}${model}${PARAMS_SUFFIX}`,
|
|
12219
|
+
factoryName: factory?.factoryName,
|
|
12220
|
+
singletonName: factory?.singletonName,
|
|
12221
|
+
fixtureExtendsGenerics: readExtendsGenerics(fixtureClass),
|
|
12222
|
+
instanceExtendsGenerics: readExtendsGenerics(instanceClass),
|
|
12223
|
+
fixtureMethods,
|
|
12224
|
+
instanceMethods,
|
|
12225
|
+
params,
|
|
12226
|
+
factory,
|
|
12227
|
+
fixtureLine: fixtureClass.getStartLineNumber(),
|
|
12228
|
+
fixtureEndLine: fixtureClass.getEndLineNumber(),
|
|
12229
|
+
instanceLine: instanceClass.getStartLineNumber(),
|
|
12230
|
+
instanceEndLine: instanceClass.getEndLineNumber()
|
|
12231
|
+
};
|
|
12232
|
+
entries.push(entry);
|
|
12233
|
+
}
|
|
12234
|
+
const identityImports = collectIdentityImports(sourceFile);
|
|
12235
|
+
const result = {
|
|
12236
|
+
fixturePath,
|
|
12237
|
+
prefix,
|
|
12238
|
+
entries,
|
|
12239
|
+
unrecognizedClassNames: unrecognized,
|
|
12240
|
+
identityImports
|
|
12241
|
+
};
|
|
12242
|
+
return result;
|
|
12243
|
+
}
|
|
12244
|
+
function detectPrefix(sourceFile) {
|
|
12245
|
+
for (const cls of sourceFile.getClasses()) {
|
|
12246
|
+
const name = cls.getName();
|
|
12247
|
+
if (!name) continue;
|
|
12248
|
+
if (!name.endsWith("ContextFixture")) continue;
|
|
12249
|
+
if (name.endsWith(FIXTURE_SUFFIX)) continue;
|
|
12250
|
+
if (!extendsByName(cls, BASE_CONTEXT_FIXTURE_BASE)) continue;
|
|
12251
|
+
return name.slice(0, name.length - "ContextFixture".length);
|
|
12252
|
+
}
|
|
12253
|
+
return void 0;
|
|
12254
|
+
}
|
|
12255
|
+
function extendsByName(cls, baseName) {
|
|
12256
|
+
const extendsClause = cls.getExtends();
|
|
12257
|
+
if (!extendsClause) return false;
|
|
12258
|
+
const expr = extendsClause.getExpression();
|
|
12259
|
+
if (Node8.isIdentifier(expr)) {
|
|
12260
|
+
return expr.getText() === baseName;
|
|
12261
|
+
}
|
|
12262
|
+
return extendsClause.getText().startsWith(baseName);
|
|
12263
|
+
}
|
|
12264
|
+
function collectClasses(sourceFile, prefix, buckets) {
|
|
12265
|
+
for (const cls of sourceFile.getClasses()) {
|
|
12266
|
+
const name = cls.getName();
|
|
12267
|
+
if (!name) continue;
|
|
12268
|
+
const fixtureModel = bareModel(name, FIXTURE_SUFFIX, prefix);
|
|
12269
|
+
if (fixtureModel !== void 0) {
|
|
12270
|
+
buckets.fixtures.set(fixtureModel, cls);
|
|
12271
|
+
continue;
|
|
12272
|
+
}
|
|
12273
|
+
const instanceModel = bareModel(name, INSTANCE_SUFFIX, prefix);
|
|
12274
|
+
if (instanceModel !== void 0) {
|
|
12275
|
+
buckets.instances.set(instanceModel, cls);
|
|
12276
|
+
continue;
|
|
12277
|
+
}
|
|
12278
|
+
if (name.endsWith(FIXTURE_SUFFIX) || name.endsWith(INSTANCE_SUFFIX)) {
|
|
12279
|
+
buckets.unrecognized.push(name);
|
|
12280
|
+
}
|
|
12281
|
+
}
|
|
12282
|
+
}
|
|
12283
|
+
function bareModel(className, suffix, prefix) {
|
|
12284
|
+
if (!className.endsWith(suffix)) return void 0;
|
|
12285
|
+
const trimmed = className.slice(0, className.length - suffix.length);
|
|
12286
|
+
if (prefix === void 0 || prefix === "") {
|
|
12287
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
12288
|
+
}
|
|
12289
|
+
if (!trimmed.startsWith(prefix)) return void 0;
|
|
12290
|
+
const model = trimmed.slice(prefix.length);
|
|
12291
|
+
return model.length > 0 ? model : void 0;
|
|
12292
|
+
}
|
|
12293
|
+
function collectParamsTypes(sourceFile, prefix) {
|
|
12294
|
+
const out = /* @__PURE__ */ new Map();
|
|
12295
|
+
for (const i of sourceFile.getInterfaces()) {
|
|
12296
|
+
const name = i.getName();
|
|
12297
|
+
const model = bareModel(name, PARAMS_SUFFIX, prefix);
|
|
12298
|
+
if (model === void 0) continue;
|
|
12299
|
+
out.set(model, readParamsInterface(i, model, prefix));
|
|
12300
|
+
}
|
|
12301
|
+
for (const a of sourceFile.getTypeAliases()) {
|
|
12302
|
+
const name = a.getName();
|
|
12303
|
+
const model = bareModel(name, PARAMS_SUFFIX, prefix);
|
|
12304
|
+
if (model === void 0) continue;
|
|
12305
|
+
out.set(model, readParamsAlias(a, model));
|
|
12306
|
+
}
|
|
12307
|
+
return out;
|
|
12308
|
+
}
|
|
12309
|
+
function readParamsInterface(i, _model, prefix) {
|
|
12310
|
+
const extendsClauses = i.getExtends().map((e) => e.getText());
|
|
12311
|
+
const partialExtends = extendsClauses.find((t) => t.startsWith("Partial<"));
|
|
12312
|
+
const extendsPartial = partialExtends !== void 0;
|
|
12313
|
+
const modelName = partialExtends ? partialExtends.slice("Partial<".length, -1).trim() : void 0;
|
|
12314
|
+
const fields = [];
|
|
12315
|
+
for (const prop of i.getProperties()) {
|
|
12316
|
+
const propName = prop.getName();
|
|
12317
|
+
const typeNode = prop.getTypeNode();
|
|
12318
|
+
const typeText = typeNode ? typeNode.getText() : "";
|
|
12319
|
+
const optional = prop.hasQuestionToken();
|
|
12320
|
+
const fixtureModel = resolveFixtureFieldModel(typeText, prefix);
|
|
12321
|
+
const isArray = /\bArrayOrValue\b|\[\]\s*$|\bArray</.test(typeText);
|
|
12322
|
+
const field = {
|
|
12323
|
+
name: propName,
|
|
12324
|
+
typeText,
|
|
12325
|
+
optional,
|
|
12326
|
+
fixtureModel,
|
|
12327
|
+
array: isArray
|
|
12328
|
+
};
|
|
12329
|
+
fields.push(field);
|
|
12330
|
+
}
|
|
12331
|
+
const result = {
|
|
12332
|
+
name: i.getName(),
|
|
12333
|
+
kind: "interface",
|
|
12334
|
+
extendsPartial,
|
|
12335
|
+
aliasOfPartial: false,
|
|
12336
|
+
modelName,
|
|
12337
|
+
fields,
|
|
12338
|
+
line: i.getStartLineNumber()
|
|
12339
|
+
};
|
|
12340
|
+
return result;
|
|
12341
|
+
}
|
|
12342
|
+
function readParamsAlias(a, _model) {
|
|
12343
|
+
const typeText = a.getTypeNode()?.getText() ?? "";
|
|
12344
|
+
const aliasOfPartial = typeText.startsWith("Partial<");
|
|
12345
|
+
const modelName = aliasOfPartial ? typeText.slice("Partial<".length, -1).trim() : void 0;
|
|
12346
|
+
const result = {
|
|
12347
|
+
name: a.getName(),
|
|
12348
|
+
kind: "alias",
|
|
12349
|
+
extendsPartial: false,
|
|
12350
|
+
aliasOfPartial,
|
|
12351
|
+
modelName,
|
|
12352
|
+
fields: [],
|
|
12353
|
+
line: a.getStartLineNumber()
|
|
12354
|
+
};
|
|
12355
|
+
return result;
|
|
12356
|
+
}
|
|
12357
|
+
function resolveFixtureFieldModel(typeText, prefix) {
|
|
12358
|
+
const match = typeText.match(/([A-Z]\w*)TestContextFixture/);
|
|
12359
|
+
if (!match) return void 0;
|
|
12360
|
+
const before = match[1];
|
|
12361
|
+
if (prefix === void 0 || prefix === "") return before;
|
|
12362
|
+
if (!before.startsWith(prefix)) return void 0;
|
|
12363
|
+
const model = before.slice(prefix.length);
|
|
12364
|
+
return model.length > 0 ? model : void 0;
|
|
12365
|
+
}
|
|
12366
|
+
function collectFactories(sourceFile, prefix) {
|
|
12367
|
+
const out = /* @__PURE__ */ new Map();
|
|
12368
|
+
for (const stmt of sourceFile.getVariableStatements()) {
|
|
12369
|
+
for (const decl of stmt.getDeclarations()) {
|
|
12370
|
+
const factory = readModelTestContextFactory(decl, prefix);
|
|
12371
|
+
if (!factory) continue;
|
|
12372
|
+
const model = factoryNameToModel(factory.factoryName, prefix);
|
|
12373
|
+
if (model === void 0) continue;
|
|
12374
|
+
out.set(model, factory);
|
|
12375
|
+
}
|
|
12376
|
+
}
|
|
12377
|
+
return out;
|
|
12378
|
+
}
|
|
12379
|
+
function readModelTestContextFactory(decl, _prefix) {
|
|
12380
|
+
const initializer = decl.getInitializer();
|
|
12381
|
+
if (!initializer) return void 0;
|
|
12382
|
+
let bodyExpr;
|
|
12383
|
+
if (Node8.isArrowFunction(initializer) || Node8.isFunctionExpression(initializer)) {
|
|
12384
|
+
bodyExpr = readSingleReturnExpression(initializer);
|
|
12385
|
+
} else {
|
|
12386
|
+
bodyExpr = initializer;
|
|
12387
|
+
}
|
|
12388
|
+
if (!bodyExpr || !Node8.isCallExpression(bodyExpr)) return void 0;
|
|
12389
|
+
const callee = bodyExpr.getExpression();
|
|
12390
|
+
if (!Node8.isIdentifier(callee) || callee.getText() !== MODEL_FACTORY_NAME) return void 0;
|
|
12391
|
+
const generics = bodyExpr.getTypeArguments().map((t) => t.getText());
|
|
12392
|
+
const args = bodyExpr.getArguments();
|
|
12393
|
+
let hasParamsGetCollection = false;
|
|
12394
|
+
let hasCollectionForDocument = false;
|
|
12395
|
+
let hasInitDocument = false;
|
|
12396
|
+
let parentFixtureFieldFromGetCollection;
|
|
12397
|
+
if (args.length > 0) {
|
|
12398
|
+
const first = args[0];
|
|
12399
|
+
if (Node8.isObjectLiteralExpression(first)) {
|
|
12400
|
+
const getCollection = first.getProperty("getCollection");
|
|
12401
|
+
if (getCollection && Node8.isPropertyAssignment(getCollection)) {
|
|
12402
|
+
const fnInit = getCollection.getInitializer();
|
|
12403
|
+
const arity = readArrowParameterCount(fnInit);
|
|
12404
|
+
if (arity >= 2) {
|
|
12405
|
+
hasParamsGetCollection = true;
|
|
12406
|
+
parentFixtureFieldFromGetCollection = readParamsAccessFieldName(fnInit);
|
|
12407
|
+
}
|
|
12408
|
+
}
|
|
12409
|
+
if (first.getProperty("collectionForDocument") !== void 0) {
|
|
12410
|
+
hasCollectionForDocument = true;
|
|
12411
|
+
}
|
|
12412
|
+
if (first.getProperty("initDocument") !== void 0) {
|
|
12413
|
+
hasInitDocument = true;
|
|
12414
|
+
}
|
|
12415
|
+
}
|
|
12416
|
+
}
|
|
12417
|
+
const result = {
|
|
12418
|
+
factoryName: decl.getName(),
|
|
12419
|
+
genericArgs: generics,
|
|
12420
|
+
hasParamsGetCollection,
|
|
12421
|
+
hasCollectionForDocument,
|
|
12422
|
+
hasInitDocument,
|
|
12423
|
+
parentFixtureFieldFromGetCollection,
|
|
12424
|
+
line: decl.getStartLineNumber()
|
|
12425
|
+
};
|
|
12426
|
+
return result;
|
|
12427
|
+
}
|
|
12428
|
+
function readSingleReturnExpression(fn) {
|
|
12429
|
+
const body = fn.getBody();
|
|
12430
|
+
if (!body) return void 0;
|
|
12431
|
+
if (Node8.isBlock(body)) {
|
|
12432
|
+
for (const stmt of body.getStatements()) {
|
|
12433
|
+
if (Node8.isReturnStatement(stmt)) {
|
|
12434
|
+
return stmt.getExpression();
|
|
12435
|
+
}
|
|
12436
|
+
}
|
|
12437
|
+
return void 0;
|
|
12438
|
+
}
|
|
12439
|
+
return body;
|
|
12440
|
+
}
|
|
12441
|
+
function readArrowParameterCount(fn) {
|
|
12442
|
+
if (!fn) return 0;
|
|
12443
|
+
if (Node8.isArrowFunction(fn) || Node8.isFunctionExpression(fn) || Node8.isFunctionDeclaration(fn) || Node8.isMethodDeclaration(fn)) {
|
|
12444
|
+
return fn.getParameters().length;
|
|
12445
|
+
}
|
|
12446
|
+
return 0;
|
|
12447
|
+
}
|
|
12448
|
+
function readParamsAccessFieldName(fn) {
|
|
12449
|
+
if (!fn) return void 0;
|
|
12450
|
+
if (!Node8.isArrowFunction(fn) && !Node8.isFunctionExpression(fn)) return void 0;
|
|
12451
|
+
const body = fn.getBody();
|
|
12452
|
+
if (!body) return void 0;
|
|
12453
|
+
for (const access2 of body.getDescendantsOfKind(SyntaxKind5.PropertyAccessExpression)) {
|
|
12454
|
+
const expr = access2.getExpression();
|
|
12455
|
+
if (Node8.isIdentifier(expr) && expr.getText() === "params") {
|
|
12456
|
+
return access2.getName();
|
|
12457
|
+
}
|
|
12458
|
+
}
|
|
12459
|
+
return void 0;
|
|
12460
|
+
}
|
|
12461
|
+
function factoryNameToModel(factoryName, prefix) {
|
|
12462
|
+
const suffix = "ContextFactory";
|
|
12463
|
+
if (!factoryName.endsWith(suffix)) return void 0;
|
|
12464
|
+
const head = factoryName.slice(0, factoryName.length - suffix.length);
|
|
12465
|
+
if (prefix === void 0 || prefix === "") {
|
|
12466
|
+
if (head.length === 0) return void 0;
|
|
12467
|
+
return head.charAt(0).toUpperCase() + head.slice(1);
|
|
12468
|
+
}
|
|
12469
|
+
const factoryPrefixCandidates = factoryPrefixesFromWorkspacePrefix(prefix);
|
|
12470
|
+
for (const factoryPrefix of factoryPrefixCandidates) {
|
|
12471
|
+
if (head.startsWith(factoryPrefix)) {
|
|
12472
|
+
const remainder = head.slice(factoryPrefix.length);
|
|
12473
|
+
if (remainder.length === 0) continue;
|
|
12474
|
+
return remainder.charAt(0).toUpperCase() + remainder.slice(1);
|
|
12475
|
+
}
|
|
12476
|
+
}
|
|
12477
|
+
return void 0;
|
|
12478
|
+
}
|
|
12479
|
+
function factoryPrefixesFromWorkspacePrefix(prefix) {
|
|
12480
|
+
const lower = prefix.charAt(0).toLowerCase() + prefix.slice(1);
|
|
12481
|
+
const apiSuffix = "Api";
|
|
12482
|
+
if (prefix.endsWith(apiSuffix)) {
|
|
12483
|
+
const trimmed = prefix.slice(0, prefix.length - apiSuffix.length);
|
|
12484
|
+
if (trimmed.length > 0) {
|
|
12485
|
+
const lowerTrimmed = trimmed.charAt(0).toLowerCase() + trimmed.slice(1);
|
|
12486
|
+
return [lower, lowerTrimmed];
|
|
12487
|
+
}
|
|
12488
|
+
}
|
|
12489
|
+
return [lower];
|
|
12490
|
+
}
|
|
12491
|
+
function collectSingletonsByFactory(sourceFile) {
|
|
12492
|
+
const out = /* @__PURE__ */ new Map();
|
|
12493
|
+
for (const stmt of sourceFile.getVariableStatements()) {
|
|
12494
|
+
for (const decl of stmt.getDeclarations()) {
|
|
12495
|
+
const init = decl.getInitializer();
|
|
12496
|
+
if (!init || !Node8.isCallExpression(init)) continue;
|
|
12497
|
+
const callee = init.getExpression();
|
|
12498
|
+
if (!Node8.isIdentifier(callee)) continue;
|
|
12499
|
+
out.set(callee.getText(), decl.getName());
|
|
12500
|
+
}
|
|
12501
|
+
}
|
|
12502
|
+
return out;
|
|
12503
|
+
}
|
|
12504
|
+
function collectAllModels(fixtures, instances) {
|
|
12505
|
+
const all = /* @__PURE__ */ new Set();
|
|
12506
|
+
for (const k of fixtures.keys()) all.add(k);
|
|
12507
|
+
for (const k of instances.keys()) all.add(k);
|
|
12508
|
+
const list = [...all];
|
|
12509
|
+
list.sort((a, b) => {
|
|
12510
|
+
const aLine = (fixtures.get(a) ?? instances.get(a))?.getStartLineNumber() ?? 0;
|
|
12511
|
+
const bLine = (fixtures.get(b) ?? instances.get(b))?.getStartLineNumber() ?? 0;
|
|
12512
|
+
return aLine - bLine;
|
|
12513
|
+
});
|
|
12514
|
+
return list;
|
|
12515
|
+
}
|
|
12516
|
+
function readClassMethods(cls) {
|
|
12517
|
+
const out = [];
|
|
12518
|
+
for (const m of cls.getMethods()) {
|
|
12519
|
+
out.push(readMethod(m));
|
|
12520
|
+
}
|
|
12521
|
+
return out;
|
|
12522
|
+
}
|
|
12523
|
+
function readMethod(m) {
|
|
12524
|
+
const visibility = readVisibility(m);
|
|
12525
|
+
const isAsync = m.isAsync();
|
|
12526
|
+
const isStatic = m.isStatic();
|
|
12527
|
+
const params = m.getParameters().map((p) => p.getText()).join(", ");
|
|
12528
|
+
const returnTypeNode = m.getReturnTypeNode();
|
|
12529
|
+
const returnTypeText = returnTypeNode ? returnTypeNode.getText() : void 0;
|
|
12530
|
+
const result = {
|
|
12531
|
+
name: m.getName(),
|
|
12532
|
+
isStatic,
|
|
12533
|
+
isAsync,
|
|
12534
|
+
visibility,
|
|
12535
|
+
parameterText: params,
|
|
12536
|
+
returnTypeText,
|
|
12537
|
+
line: m.getStartLineNumber(),
|
|
12538
|
+
endLine: m.getEndLineNumber()
|
|
12539
|
+
};
|
|
12540
|
+
return result;
|
|
12541
|
+
}
|
|
12542
|
+
function readVisibility(m) {
|
|
12543
|
+
if (m.hasModifier(SyntaxKind5.PrivateKeyword)) return "private";
|
|
12544
|
+
if (m.hasModifier(SyntaxKind5.ProtectedKeyword)) return "protected";
|
|
12545
|
+
return "public";
|
|
12546
|
+
}
|
|
12547
|
+
function readExtendsGenerics(cls) {
|
|
12548
|
+
const ext = cls.getExtends();
|
|
12549
|
+
if (!ext) return [];
|
|
12550
|
+
return ext.getTypeArguments().map((t) => t.getText());
|
|
12551
|
+
}
|
|
12552
|
+
function collectIdentityImports(sourceFile) {
|
|
12553
|
+
const out = /* @__PURE__ */ new Set();
|
|
12554
|
+
for (const imp of sourceFile.getImportDeclarations()) {
|
|
12555
|
+
for (const named of imp.getNamedImports()) {
|
|
12556
|
+
const name = named.getNameNode().getText();
|
|
12557
|
+
if (name.endsWith("Identity")) {
|
|
12558
|
+
out.add(name);
|
|
12559
|
+
}
|
|
12560
|
+
}
|
|
12561
|
+
}
|
|
12562
|
+
const list = [...out];
|
|
12563
|
+
list.sort();
|
|
12564
|
+
return list;
|
|
12565
|
+
}
|
|
12566
|
+
|
|
12567
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/inspect.ts
|
|
12568
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
12569
|
+
import { join } from "node:path";
|
|
12570
|
+
var FIXTURE_RELATIVE_PATH = "src/test/fixture.ts";
|
|
12571
|
+
async function inspectAppFixtures(apiAbs, apiRel) {
|
|
12572
|
+
const absolutePath = join(apiAbs, FIXTURE_RELATIVE_PATH);
|
|
12573
|
+
const relativePath = `${apiRel}/${FIXTURE_RELATIVE_PATH}`;
|
|
12574
|
+
const text = await readFile2(absolutePath, "utf8");
|
|
12575
|
+
return extractAppFixturesFromText({ text, fixturePath: relativePath });
|
|
12576
|
+
}
|
|
12577
|
+
|
|
12578
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/validate.ts
|
|
12579
|
+
function validateAppFixtures(extraction, options = {}) {
|
|
12580
|
+
const diagnostics = [];
|
|
12581
|
+
for (const entry of extraction.entries) {
|
|
12582
|
+
pushTripletCompletenessDiagnostics(entry, diagnostics);
|
|
12583
|
+
pushForwardingDiagnostics(entry, diagnostics);
|
|
12584
|
+
pushGenericAlignmentDiagnostics(entry, diagnostics);
|
|
12585
|
+
pushArchetypeConsistencyDiagnostics(entry, diagnostics);
|
|
12586
|
+
pushParentFieldNamingDiagnostics(entry, options.registry, diagnostics);
|
|
12587
|
+
pushRegistryDiagnostics(entry, options.registry, diagnostics);
|
|
12588
|
+
}
|
|
12589
|
+
pushOrphanFixtureDiagnostics(extraction, diagnostics);
|
|
12590
|
+
pushModelsWithoutFixtureDiagnostics(extraction, options.registry, diagnostics);
|
|
12591
|
+
let errorCount = 0;
|
|
12592
|
+
let warningCount = 0;
|
|
12593
|
+
for (const d of diagnostics) {
|
|
12594
|
+
if (d.severity === "error") errorCount += 1;
|
|
12595
|
+
else warningCount += 1;
|
|
12596
|
+
}
|
|
12597
|
+
return {
|
|
12598
|
+
fixturePath: extraction.fixturePath,
|
|
12599
|
+
diagnostics,
|
|
12600
|
+
errorCount,
|
|
12601
|
+
warningCount
|
|
12602
|
+
};
|
|
12603
|
+
}
|
|
12604
|
+
function pushTripletCompletenessDiagnostics(entry, out) {
|
|
12605
|
+
if (!entry.factoryName) {
|
|
12606
|
+
out.push({
|
|
12607
|
+
code: "triplet-incomplete",
|
|
12608
|
+
severity: "error",
|
|
12609
|
+
model: entry.model,
|
|
12610
|
+
message: `Model \`${entry.model}\` has Fixture/Instance classes but no \`modelTestContextFactory\` registration.`,
|
|
12611
|
+
line: entry.fixtureLine
|
|
12612
|
+
});
|
|
12613
|
+
}
|
|
12614
|
+
if (entry.factoryName && !entry.singletonName) {
|
|
12615
|
+
out.push({
|
|
12616
|
+
code: "triplet-incomplete",
|
|
12617
|
+
severity: "warning",
|
|
12618
|
+
model: entry.model,
|
|
12619
|
+
message: `Factory \`${entry.factoryName}\` has no exported singleton (e.g. \`export const ${decapitalize(entry.prefix)}${entry.model}Context = ${entry.factoryName}();\`).`,
|
|
12620
|
+
line: entry.factory?.line
|
|
12621
|
+
});
|
|
12622
|
+
}
|
|
12623
|
+
if (!entry.params) {
|
|
12624
|
+
out.push({
|
|
12625
|
+
code: "triplet-incomplete",
|
|
12626
|
+
severity: "warning",
|
|
12627
|
+
model: entry.model,
|
|
12628
|
+
message: `Model \`${entry.model}\` has no \`${entry.prefix}${entry.model}TestContextParams\` interface or alias.`,
|
|
12629
|
+
line: entry.fixtureLine
|
|
12630
|
+
});
|
|
12631
|
+
}
|
|
12632
|
+
}
|
|
12633
|
+
function pushForwardingDiagnostics(entry, out) {
|
|
12634
|
+
const fixtureByName = new Map(entry.fixtureMethods.map((m) => [m.name, m]));
|
|
12635
|
+
for (const instanceMethod of entry.instanceMethods) {
|
|
12636
|
+
if (instanceMethod.visibility !== "public") continue;
|
|
12637
|
+
const fixtureMethod = fixtureByName.get(instanceMethod.name);
|
|
12638
|
+
if (!fixtureMethod) {
|
|
12639
|
+
out.push({
|
|
12640
|
+
code: "forwarder-missing",
|
|
12641
|
+
severity: "warning",
|
|
12642
|
+
model: entry.model,
|
|
12643
|
+
message: `Fixture \`${entry.fixtureClassName}\` is missing a forwarder for instance method \`${instanceMethod.name}\`.`,
|
|
12644
|
+
line: instanceMethod.line
|
|
12645
|
+
});
|
|
12646
|
+
continue;
|
|
12647
|
+
}
|
|
12648
|
+
if (!signaturesMatch(fixtureMethod, instanceMethod)) {
|
|
12649
|
+
out.push({
|
|
12650
|
+
code: "forwarder-divergent",
|
|
12651
|
+
severity: "warning",
|
|
12652
|
+
model: entry.model,
|
|
12653
|
+
message: `Fixture forwarder \`${fixtureMethod.name}\` signature differs from the instance method.`,
|
|
12654
|
+
line: fixtureMethod.line
|
|
12655
|
+
});
|
|
12656
|
+
}
|
|
12657
|
+
}
|
|
12658
|
+
}
|
|
12659
|
+
function pushGenericAlignmentDiagnostics(entry, out) {
|
|
12660
|
+
const fixGenerics = entry.fixtureExtendsGenerics;
|
|
12661
|
+
const instGenerics = entry.instanceExtendsGenerics;
|
|
12662
|
+
const factoryGenerics = entry.factory?.genericArgs ?? [];
|
|
12663
|
+
const fixModel = fixGenerics[0];
|
|
12664
|
+
const fixDoc = fixGenerics[1];
|
|
12665
|
+
const instModel = instGenerics[0];
|
|
12666
|
+
const instDoc = instGenerics[1];
|
|
12667
|
+
const factoryModel = factoryGenerics[0];
|
|
12668
|
+
const factoryDoc = factoryGenerics[1];
|
|
12669
|
+
if (fixModel !== void 0 && instModel !== void 0 && fixModel !== instModel) {
|
|
12670
|
+
out.push({
|
|
12671
|
+
code: "generics-misaligned",
|
|
12672
|
+
severity: "error",
|
|
12673
|
+
model: entry.model,
|
|
12674
|
+
message: `Model generic differs between Fixture (\`${fixModel}\`) and Instance (\`${instModel}\`).`,
|
|
12675
|
+
line: entry.fixtureLine
|
|
12676
|
+
});
|
|
12677
|
+
}
|
|
12678
|
+
if (fixDoc !== void 0 && instDoc !== void 0 && fixDoc !== instDoc) {
|
|
12679
|
+
out.push({
|
|
12680
|
+
code: "generics-misaligned",
|
|
12681
|
+
severity: "error",
|
|
12682
|
+
model: entry.model,
|
|
12683
|
+
message: `Document generic differs between Fixture (\`${fixDoc}\`) and Instance (\`${instDoc}\`).`,
|
|
12684
|
+
line: entry.fixtureLine
|
|
12685
|
+
});
|
|
12686
|
+
}
|
|
12687
|
+
if (factoryModel !== void 0 && fixModel !== void 0 && factoryModel !== fixModel) {
|
|
12688
|
+
out.push({
|
|
12689
|
+
code: "generics-misaligned",
|
|
12690
|
+
severity: "error",
|
|
12691
|
+
model: entry.model,
|
|
12692
|
+
message: `Model generic differs between factory (\`${factoryModel}\`) and Fixture (\`${fixModel}\`).`,
|
|
12693
|
+
line: entry.factory?.line
|
|
12694
|
+
});
|
|
12695
|
+
}
|
|
12696
|
+
if (factoryDoc !== void 0 && fixDoc !== void 0 && factoryDoc !== fixDoc) {
|
|
12697
|
+
out.push({
|
|
12698
|
+
code: "generics-misaligned",
|
|
12699
|
+
severity: "error",
|
|
12700
|
+
model: entry.model,
|
|
12701
|
+
message: `Document generic differs between factory (\`${factoryDoc}\`) and Fixture (\`${fixDoc}\`).`,
|
|
12702
|
+
line: entry.factory?.line
|
|
12703
|
+
});
|
|
12704
|
+
}
|
|
12705
|
+
}
|
|
12706
|
+
function pushArchetypeConsistencyDiagnostics(entry, out) {
|
|
12707
|
+
if (!entry.factory) return;
|
|
12708
|
+
const archetype = entry.archetype;
|
|
12709
|
+
if (archetype === "sub-collection" || archetype === "sub-collection-traversal") {
|
|
12710
|
+
const accessedField = entry.factory.parentFixtureFieldFromGetCollection;
|
|
12711
|
+
if (accessedField !== void 0) {
|
|
12712
|
+
const present = entry.params?.fields.some((f) => f.name === accessedField && f.fixtureModel !== void 0);
|
|
12713
|
+
if (!present) {
|
|
12714
|
+
out.push({
|
|
12715
|
+
code: "archetype-inconsistent",
|
|
12716
|
+
severity: "error",
|
|
12717
|
+
model: entry.model,
|
|
12718
|
+
message: `\`getCollection\` reads \`params.${accessedField}\` but the Params interface has no fixture-typed \`${accessedField}\` field.`,
|
|
12719
|
+
line: entry.factory.line
|
|
12720
|
+
});
|
|
12721
|
+
}
|
|
12722
|
+
}
|
|
12723
|
+
}
|
|
12724
|
+
}
|
|
12725
|
+
function pushParentFieldNamingDiagnostics(entry, registry, out) {
|
|
12726
|
+
if (!registry) return;
|
|
12727
|
+
if (!entry.params) return;
|
|
12728
|
+
for (const field of entry.params.fields) {
|
|
12729
|
+
if (field.fixtureModel === void 0) continue;
|
|
12730
|
+
const expected = lookupCollectionPrefix(registry, field.fixtureModel);
|
|
12731
|
+
if (expected === void 0) continue;
|
|
12732
|
+
if (field.name !== expected) {
|
|
12733
|
+
out.push({
|
|
12734
|
+
code: "params-field-naming",
|
|
12735
|
+
severity: "warning",
|
|
12736
|
+
model: entry.model,
|
|
12737
|
+
message: `Params field \`${field.name}: ${field.typeText}\` should be named \`${expected}\` to match \`${field.fixtureModel}\`'s firestoreModelIdentity short alias.`,
|
|
12738
|
+
line: entry.params.line
|
|
12739
|
+
});
|
|
12740
|
+
}
|
|
12741
|
+
}
|
|
12742
|
+
}
|
|
12743
|
+
function pushRegistryDiagnostics(entry, registry, out) {
|
|
12744
|
+
if (!registry) return;
|
|
12745
|
+
const known = registry.entries.find((m) => m.name === entry.model);
|
|
12746
|
+
if (!known) {
|
|
12747
|
+
out.push({
|
|
12748
|
+
code: "model-not-in-registry",
|
|
12749
|
+
severity: "warning",
|
|
12750
|
+
model: entry.model,
|
|
12751
|
+
message: `Model \`${entry.model}\` has a fixture but isn't in the supplied model registry.`,
|
|
12752
|
+
line: entry.fixtureLine
|
|
12753
|
+
});
|
|
12754
|
+
}
|
|
12755
|
+
}
|
|
12756
|
+
function pushOrphanFixtureDiagnostics(extraction, out) {
|
|
12757
|
+
for (const name of extraction.unrecognizedClassNames) {
|
|
12758
|
+
out.push({
|
|
12759
|
+
code: "triplet-incomplete",
|
|
12760
|
+
severity: "warning",
|
|
12761
|
+
message: `Class \`${name}\` ends in TestContextFixture/Instance but doesn't fit the \`<Prefix><Model><Suffix>\` convention.`
|
|
12762
|
+
});
|
|
12763
|
+
}
|
|
12764
|
+
}
|
|
12765
|
+
function pushModelsWithoutFixtureDiagnostics(extraction, registry, out) {
|
|
12766
|
+
if (!registry) return;
|
|
12767
|
+
const have = new Set(extraction.entries.map((e) => e.model));
|
|
12768
|
+
for (const m of registry.entries) {
|
|
12769
|
+
if (have.has(m.name)) continue;
|
|
12770
|
+
out.push({
|
|
12771
|
+
code: "model-without-fixture",
|
|
12772
|
+
severity: "warning",
|
|
12773
|
+
model: m.name,
|
|
12774
|
+
message: `Model \`${m.name}\` is in the registry but \`${extraction.fixturePath}\` doesn't declare a fixture for it.`
|
|
12775
|
+
});
|
|
12776
|
+
}
|
|
12777
|
+
}
|
|
12778
|
+
function signaturesMatch(a, b) {
|
|
12779
|
+
if (a.parameterText.replace(/\s+/g, "") !== b.parameterText.replace(/\s+/g, "")) return false;
|
|
12780
|
+
if (a.isAsync !== b.isAsync) return false;
|
|
12781
|
+
return true;
|
|
12782
|
+
}
|
|
12783
|
+
function decapitalize(s) {
|
|
12784
|
+
if (s.length === 0) return s;
|
|
12785
|
+
return s.charAt(0).toLowerCase() + s.slice(1);
|
|
12786
|
+
}
|
|
12787
|
+
function lookupCollectionPrefix(registry, modelName) {
|
|
12788
|
+
const entry = registry.entries.find((m) => m.name === modelName);
|
|
12789
|
+
return entry?.collectionPrefix;
|
|
12790
|
+
}
|
|
12791
|
+
|
|
12792
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/format.json.ts
|
|
12793
|
+
function formatListAsJson(extraction) {
|
|
12794
|
+
return stringify({
|
|
12795
|
+
fixturePath: extraction.fixturePath,
|
|
12796
|
+
prefix: extraction.prefix,
|
|
12797
|
+
identityImports: extraction.identityImports,
|
|
12798
|
+
unrecognizedClassNames: extraction.unrecognizedClassNames,
|
|
12799
|
+
entries: extraction.entries.map((e) => summarizeEntry(e))
|
|
12800
|
+
});
|
|
12801
|
+
}
|
|
12802
|
+
function formatLookupAsJson(extraction, entry) {
|
|
12803
|
+
return stringify({
|
|
12804
|
+
fixturePath: extraction.fixturePath,
|
|
12805
|
+
prefix: extraction.prefix,
|
|
12806
|
+
entry: summarizeEntry(entry, true)
|
|
12807
|
+
});
|
|
12808
|
+
}
|
|
12809
|
+
function formatValidationAsJson(result) {
|
|
12810
|
+
return stringify({
|
|
12811
|
+
fixturePath: result.fixturePath,
|
|
12812
|
+
errorCount: result.errorCount,
|
|
12813
|
+
warningCount: result.warningCount,
|
|
12814
|
+
diagnostics: result.diagnostics
|
|
12815
|
+
});
|
|
12816
|
+
}
|
|
12817
|
+
function summarizeEntry(entry, full = false) {
|
|
12818
|
+
const summary = {
|
|
12819
|
+
model: entry.model,
|
|
12820
|
+
prefix: entry.prefix,
|
|
12821
|
+
archetype: entry.archetype,
|
|
12822
|
+
fixtureClassName: entry.fixtureClassName,
|
|
12823
|
+
instanceClassName: entry.instanceClassName,
|
|
12824
|
+
paramsTypeName: entry.paramsTypeName,
|
|
12825
|
+
factoryName: entry.factoryName,
|
|
12826
|
+
singletonName: entry.singletonName,
|
|
12827
|
+
fixtureLine: entry.fixtureLine,
|
|
12828
|
+
fixtureEndLine: entry.fixtureEndLine,
|
|
12829
|
+
instanceLine: entry.instanceLine,
|
|
12830
|
+
instanceEndLine: entry.instanceEndLine,
|
|
12831
|
+
fixtureMethodNames: entry.fixtureMethods.map((m) => m.name),
|
|
12832
|
+
instanceMethodNames: entry.instanceMethods.map((m) => m.name)
|
|
12833
|
+
};
|
|
12834
|
+
if (full) {
|
|
12835
|
+
summary.fixtureExtendsGenerics = entry.fixtureExtendsGenerics;
|
|
12836
|
+
summary.instanceExtendsGenerics = entry.instanceExtendsGenerics;
|
|
12837
|
+
summary.factory = entry.factory;
|
|
12838
|
+
summary.params = entry.params;
|
|
12839
|
+
summary.fixtureMethods = entry.fixtureMethods;
|
|
12840
|
+
summary.instanceMethods = entry.instanceMethods;
|
|
12841
|
+
}
|
|
12842
|
+
return summary;
|
|
12843
|
+
}
|
|
12844
|
+
function stringify(value) {
|
|
12845
|
+
return JSON.stringify(value, null, 2);
|
|
12846
|
+
}
|
|
12847
|
+
|
|
12848
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/format.markdown.ts
|
|
12849
|
+
function formatListAsMarkdown(extraction) {
|
|
12850
|
+
const lines = [];
|
|
12851
|
+
lines.push(`# App fixtures \u2014 ${extraction.fixturePath}`);
|
|
12852
|
+
lines.push("");
|
|
12853
|
+
lines.push(`Detected workspace prefix: \`${extraction.prefix ?? "(none)"}\``);
|
|
12854
|
+
lines.push(`Identity imports: ${extraction.identityImports.length === 0 ? "_None._" : extraction.identityImports.map((s) => "`" + s + "`").join(", ")}`);
|
|
12855
|
+
lines.push("");
|
|
12856
|
+
lines.push(`## Fixtures (${extraction.entries.length})`);
|
|
12857
|
+
if (extraction.entries.length === 0) {
|
|
12858
|
+
lines.push("", "_No model fixtures found._");
|
|
12859
|
+
} else {
|
|
12860
|
+
lines.push("");
|
|
12861
|
+
lines.push("| Model | Archetype | Fixture | Instance | Params | Factory | Singleton | Methods (F/I) | Lines |");
|
|
12862
|
+
lines.push("|---|---|---|---|---|---|---|---|---|");
|
|
12863
|
+
for (const e of extraction.entries) {
|
|
12864
|
+
lines.push("| " + [e.model, e.archetype, code3(e.fixtureClassName), code3(e.instanceClassName), code3(e.paramsTypeName), code3(e.factoryName ?? "\u2014"), code3(e.singletonName ?? "\u2014"), `${e.fixtureMethods.length}/${e.instanceMethods.length}`, `${e.fixtureLine}-${e.instanceEndLine}`].join(" | ") + " |");
|
|
12865
|
+
}
|
|
12866
|
+
}
|
|
12867
|
+
if (extraction.unrecognizedClassNames.length > 0) {
|
|
12868
|
+
lines.push("", `## Unrecognized classes (${extraction.unrecognizedClassNames.length})`);
|
|
12869
|
+
for (const name of extraction.unrecognizedClassNames) {
|
|
12870
|
+
lines.push("", `- \`${name}\``);
|
|
12871
|
+
}
|
|
12872
|
+
}
|
|
12873
|
+
return lines.join("\n");
|
|
12874
|
+
}
|
|
12875
|
+
function formatLookupAsMarkdown(extraction, entry) {
|
|
12876
|
+
const lines = [];
|
|
12877
|
+
appendLookupHeader(lines, extraction, entry);
|
|
12878
|
+
appendLookupTriplet(lines, entry);
|
|
12879
|
+
appendLookupGenerics(lines, entry);
|
|
12880
|
+
appendLookupFactoryCallbacks(lines, entry);
|
|
12881
|
+
appendLookupParams(lines, entry);
|
|
12882
|
+
lines.push("", `## Methods \u2014 Fixture (${entry.fixtureMethods.length})`);
|
|
12883
|
+
appendMethodTable(lines, entry.fixtureMethods);
|
|
12884
|
+
lines.push("", `## Methods \u2014 Instance (${entry.instanceMethods.length})`);
|
|
12885
|
+
appendMethodTable(lines, entry.instanceMethods);
|
|
12886
|
+
lines.push("", "## Forwarding");
|
|
12887
|
+
appendForwardingTable(lines, entry);
|
|
12888
|
+
return lines.join("\n");
|
|
12889
|
+
}
|
|
12890
|
+
function appendLookupHeader(lines, extraction, entry) {
|
|
12891
|
+
lines.push(`# Fixture: \`${entry.prefix}${entry.model}\``, "", `Source: \`${extraction.fixturePath}\``, `Archetype: \`${entry.archetype}\``, "");
|
|
12892
|
+
}
|
|
12893
|
+
function appendLookupTriplet(lines, entry) {
|
|
12894
|
+
lines.push("## Triplet", "", `- Fixture: \`${entry.fixtureClassName}\` (lines ${entry.fixtureLine}-${entry.fixtureEndLine})`, `- Instance: \`${entry.instanceClassName}\` (lines ${entry.instanceLine}-${entry.instanceEndLine})`, `- Params: \`${entry.paramsTypeName}\``, `- Factory: \`${entry.factoryName ?? "\u2014"}\``, `- Singleton: \`${entry.singletonName ?? "\u2014"}\``);
|
|
12895
|
+
}
|
|
12896
|
+
function appendLookupGenerics(lines, entry) {
|
|
12897
|
+
if (entry.fixtureExtendsGenerics.length > 0) {
|
|
12898
|
+
lines.push("", `Fixture generics: \`${entry.fixtureExtendsGenerics.join(", ")}\``);
|
|
12899
|
+
}
|
|
12900
|
+
if (entry.instanceExtendsGenerics.length > 0) {
|
|
12901
|
+
lines.push(`Instance generics: \`${entry.instanceExtendsGenerics.join(", ")}\``);
|
|
12902
|
+
}
|
|
12903
|
+
if (entry.factory && entry.factory.genericArgs.length > 0) {
|
|
12904
|
+
lines.push(`Factory generics: \`${entry.factory.genericArgs.join(", ")}\``);
|
|
12905
|
+
}
|
|
12906
|
+
}
|
|
12907
|
+
function appendLookupFactoryCallbacks(lines, entry) {
|
|
12908
|
+
if (!entry.factory) return;
|
|
12909
|
+
const flags = [];
|
|
12910
|
+
flags.push(`getCollection: ${entry.factory.hasParamsGetCollection ? "`(fi, params) => \u2026`" : "`(fi) => \u2026`"}`);
|
|
12911
|
+
if (entry.factory.hasCollectionForDocument) flags.push("`collectionForDocument` present");
|
|
12912
|
+
if (entry.factory.hasInitDocument) flags.push("`initDocument` present");
|
|
12913
|
+
lines.push(`Factory callbacks: ${flags.join(", ")}`);
|
|
12914
|
+
if (entry.factory.parentFixtureFieldFromGetCollection) {
|
|
12915
|
+
lines.push(`Parent fixture field used in \`getCollection\`: \`params.${entry.factory.parentFixtureFieldFromGetCollection}\``);
|
|
12916
|
+
}
|
|
12917
|
+
}
|
|
12918
|
+
function appendLookupParams(lines, entry) {
|
|
12919
|
+
if (!entry.params) return;
|
|
12920
|
+
lines.push("", "## Params", "", `- Kind: ${entry.params.kind}`);
|
|
12921
|
+
if (entry.params.extendsPartial) lines.push(`- Extends \`Partial<${entry.params.modelName ?? "?"}>\``);
|
|
12922
|
+
if (entry.params.aliasOfPartial) lines.push(`- Alias of \`Partial<${entry.params.modelName ?? "?"}>\``);
|
|
12923
|
+
if (entry.params.fields.length === 0) return;
|
|
12924
|
+
lines.push("", "| Field | Type | Optional | Fixture dependency |", "|---|---|---|---|");
|
|
12925
|
+
for (const field of entry.params.fields) {
|
|
12926
|
+
lines.push("| " + [code3(field.name), code3(field.typeText), field.optional ? "yes" : "no", field.fixtureModel ? code3(field.fixtureModel) : "\u2014"].join(" | ") + " |");
|
|
12927
|
+
}
|
|
12928
|
+
}
|
|
12929
|
+
function formatValidationAsMarkdown(result) {
|
|
12930
|
+
const lines = [];
|
|
12931
|
+
lines.push(`# Fixture validation \u2014 ${result.fixturePath}`);
|
|
12932
|
+
lines.push("");
|
|
12933
|
+
lines.push(`Errors: ${result.errorCount}`);
|
|
12934
|
+
lines.push(`Warnings: ${result.warningCount}`);
|
|
12935
|
+
if (result.diagnostics.length === 0) {
|
|
12936
|
+
lines.push("", "_No diagnostics._");
|
|
12937
|
+
return lines.join("\n");
|
|
12938
|
+
}
|
|
12939
|
+
lines.push("", "## Diagnostics");
|
|
12940
|
+
for (const d of result.diagnostics) {
|
|
12941
|
+
const linePart = d.line !== void 0 ? ` (line ${d.line})` : "";
|
|
12942
|
+
const modelPart = d.model !== void 0 ? ` [${d.model}]` : "";
|
|
12943
|
+
lines.push("", `- **${d.severity.toUpperCase()}** \`${d.code}\`${modelPart}${linePart}: ${d.message}`);
|
|
12944
|
+
}
|
|
12945
|
+
return lines.join("\n");
|
|
12946
|
+
}
|
|
12947
|
+
function appendMethodTable(lines, methods) {
|
|
12948
|
+
if (methods.length === 0) {
|
|
12949
|
+
lines.push("", "_None._");
|
|
12950
|
+
return;
|
|
12951
|
+
}
|
|
12952
|
+
lines.push("", "| Method | Async | Returns | Line |");
|
|
12953
|
+
lines.push("|---|---|---|---|");
|
|
12954
|
+
for (const m of methods) {
|
|
12955
|
+
lines.push("| " + [code3(m.name + "(" + m.parameterText + ")"), m.isAsync ? "yes" : "no", code3(m.returnTypeText ?? "\u2014"), String(m.line)].join(" | ") + " |");
|
|
12956
|
+
}
|
|
12957
|
+
}
|
|
12958
|
+
function appendForwardingTable(lines, entry) {
|
|
12959
|
+
if (entry.instanceMethods.length === 0) {
|
|
12960
|
+
lines.push("", "_No instance methods to forward._");
|
|
12961
|
+
return;
|
|
12962
|
+
}
|
|
12963
|
+
const fixtureByName = new Map(entry.fixtureMethods.map((m) => [m.name, m]));
|
|
12964
|
+
lines.push("", "| Instance method | Forwarded? |");
|
|
12965
|
+
lines.push("|---|---|");
|
|
12966
|
+
for (const m of entry.instanceMethods) {
|
|
12967
|
+
const fixtureMethod = fixtureByName.get(m.name);
|
|
12968
|
+
let status;
|
|
12969
|
+
if (!fixtureMethod) {
|
|
12970
|
+
status = "missing";
|
|
12971
|
+
} else if (fixtureMethod.parameterText.replace(/\s+/g, "") !== m.parameterText.replace(/\s+/g, "")) {
|
|
12972
|
+
status = "forwarded \u2014 signature drifts";
|
|
12973
|
+
} else {
|
|
12974
|
+
status = "forwarded";
|
|
12975
|
+
}
|
|
12976
|
+
lines.push("| " + [code3(m.name), status].join(" | ") + " |");
|
|
12977
|
+
}
|
|
12978
|
+
}
|
|
12979
|
+
function code3(s) {
|
|
12980
|
+
return "`" + s + "`";
|
|
12981
|
+
}
|
|
12982
|
+
|
|
12983
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/scaffold.ts
|
|
12984
|
+
function renderFixtureScaffold(extraction, input) {
|
|
12985
|
+
const prefix = input.prefix;
|
|
12986
|
+
const factoryPrefix = input.factoryNamePrefix ?? defaultFactoryPrefix(prefix);
|
|
12987
|
+
const paramsTypeName = `${prefix}${input.model}TestContextParams`;
|
|
12988
|
+
const fixtureClassName = `${prefix}${input.model}TestContextFixture`;
|
|
12989
|
+
const instanceClassName = `${prefix}${input.model}TestContextInstance`;
|
|
12990
|
+
const factoryName = `${factoryPrefix}${input.model}ContextFactory`;
|
|
12991
|
+
const singletonName = `${factoryPrefix}${input.model}Context`;
|
|
12992
|
+
const modelDocumentTypeName = input.modelDocumentTypeName ?? `${input.model}Document`;
|
|
12993
|
+
const collectionGenericArg = input.collectionGenericArg;
|
|
12994
|
+
const todos = [];
|
|
12995
|
+
const paramsLines = renderParamsBlock(input, paramsTypeName, todos);
|
|
12996
|
+
const instanceBlock = renderInstanceBlock({ prefix, instanceClassName, modelDocumentTypeName, model: input.model, todos });
|
|
12997
|
+
const fixtureBlock = renderFixtureBlock({ prefix, fixtureClassName, instanceClassName, modelDocumentTypeName, model: input.model, todos });
|
|
12998
|
+
const factoryBlock = renderFactoryBlock({
|
|
12999
|
+
prefix,
|
|
13000
|
+
factoryName,
|
|
13001
|
+
fixtureClassName,
|
|
13002
|
+
instanceClassName,
|
|
13003
|
+
paramsTypeName,
|
|
13004
|
+
archetype: input.archetype,
|
|
13005
|
+
model: input.model,
|
|
13006
|
+
modelDocumentTypeName,
|
|
13007
|
+
collectionGenericArg,
|
|
13008
|
+
parentFixture: input.parentFixture,
|
|
13009
|
+
parentFixtureField: input.parentFixtureField,
|
|
13010
|
+
withInitDocument: input.withInitDocument === true,
|
|
13011
|
+
todos
|
|
13012
|
+
});
|
|
13013
|
+
const singletonBlock = `export const ${singletonName} = ${factoryName}();`;
|
|
13014
|
+
const snippet = [`// MARK: ${input.model}`, paramsLines.join("\n"), "", instanceBlock, "", fixtureBlock, "", factoryBlock, "", singletonBlock, ""].join("\n");
|
|
13015
|
+
const inserted = [
|
|
13016
|
+
{ kind: "params", name: paramsTypeName },
|
|
13017
|
+
{ kind: "instance", name: instanceClassName },
|
|
13018
|
+
{ kind: "fixture", name: fixtureClassName },
|
|
13019
|
+
{ kind: "factory", name: factoryName },
|
|
13020
|
+
{ kind: "singleton", name: singletonName }
|
|
13021
|
+
];
|
|
13022
|
+
if (!extraction.fixturePath) {
|
|
13023
|
+
todos.push("Confirm fixture path was parsed.");
|
|
13024
|
+
}
|
|
13025
|
+
todos.push(`Add named imports for \`${input.model}\` and \`${modelDocumentTypeName}\` if not already present.`);
|
|
13026
|
+
if (collectionGenericArg) {
|
|
13027
|
+
todos.push(`Add named import for \`${collectionGenericArg}\`.`);
|
|
13028
|
+
}
|
|
13029
|
+
if (input.archetype === "sub-collection" || input.archetype === "sub-collection-traversal") {
|
|
13030
|
+
todos.push("Wire `getCollection` to the correct collection factory accessor on `<prefix>FirestoreCollections`.");
|
|
13031
|
+
}
|
|
13032
|
+
todos.push("Replace TODOs in `makeRef` and instance methods with real logic.");
|
|
13033
|
+
return {
|
|
13034
|
+
snippet,
|
|
13035
|
+
todos,
|
|
13036
|
+
inserted,
|
|
13037
|
+
paramsTypeName,
|
|
13038
|
+
fixtureClassName,
|
|
13039
|
+
instanceClassName,
|
|
13040
|
+
factoryName,
|
|
13041
|
+
singletonName
|
|
13042
|
+
};
|
|
13043
|
+
}
|
|
13044
|
+
function defaultFactoryPrefix(prefix) {
|
|
13045
|
+
if (prefix.length === 0) return "app";
|
|
13046
|
+
const apiSuffix = "Api";
|
|
13047
|
+
if (prefix.endsWith(apiSuffix)) {
|
|
13048
|
+
const trimmed = prefix.slice(0, prefix.length - apiSuffix.length);
|
|
13049
|
+
if (trimmed.length === 0) return "app";
|
|
13050
|
+
return trimmed.charAt(0).toLowerCase() + trimmed.slice(1);
|
|
13051
|
+
}
|
|
13052
|
+
return prefix.charAt(0).toLowerCase() + prefix.slice(1);
|
|
13053
|
+
}
|
|
13054
|
+
function renderParamsBlock(input, paramsTypeName, todos) {
|
|
13055
|
+
const lines = [];
|
|
13056
|
+
const isSimplePartial = input.archetype === "top-level-simple" && (!input.paramsDependsOn || input.paramsDependsOn.length === 0);
|
|
13057
|
+
if (isSimplePartial) {
|
|
13058
|
+
lines.push(`export type ${paramsTypeName} = Partial<${input.model}>;`);
|
|
13059
|
+
return lines;
|
|
13060
|
+
}
|
|
13061
|
+
const extendsClause = input.archetype === "top-level-simple" || input.archetype === "top-level-with-deps" ? ` extends Partial<${input.model}>` : "";
|
|
13062
|
+
lines.push(`export interface ${paramsTypeName}${extendsClause} {`);
|
|
13063
|
+
if (input.archetype === "sub-collection" || input.archetype === "sub-collection-traversal") {
|
|
13064
|
+
if (input.parentFixture) {
|
|
13065
|
+
const field = input.parentFixtureField ?? defaultParentFieldName(input.parentFixture);
|
|
13066
|
+
lines.push(` readonly ${field}: ${input.prefix}${input.parentFixture}TestContextFixture;`);
|
|
13067
|
+
} else {
|
|
13068
|
+
todos.push("Add the required parent fixture field on the Params interface.");
|
|
13069
|
+
}
|
|
13070
|
+
}
|
|
13071
|
+
for (const dep of input.paramsDependsOn ?? []) {
|
|
13072
|
+
const optional = dep.optional ? "?" : "";
|
|
13073
|
+
const baseType = `${input.prefix}${dep.fixtureModel}TestContextFixture`;
|
|
13074
|
+
const typeText = dep.array ? `Maybe<ArrayOrValue<${baseType}>>` : baseType;
|
|
13075
|
+
lines.push(` readonly ${dep.field}${optional}: ${typeText};`);
|
|
13076
|
+
}
|
|
13077
|
+
lines.push("}");
|
|
13078
|
+
return lines;
|
|
13079
|
+
}
|
|
13080
|
+
function renderInstanceBlock(input) {
|
|
13081
|
+
input.todos.push(`Add instance methods to \`${input.instanceClassName}\`.`);
|
|
13082
|
+
return [`export class ${input.instanceClassName}<F extends FirebaseAdminFunctionTestContextInstance = FirebaseAdminFunctionTestContextInstance> extends ModelTestContextInstance<${input.model}, ${input.modelDocumentTypeName}, ${input.prefix}FunctionContextFixtureInstance<F>> {`, " // TODO: implement instance-side methods (these own the real logic).", "}"].join("\n");
|
|
13083
|
+
}
|
|
13084
|
+
function renderFixtureBlock(input) {
|
|
13085
|
+
input.todos.push(`Add forwarder methods to \`${input.fixtureClassName}\` after defining instance methods.`);
|
|
13086
|
+
return [`export class ${input.fixtureClassName}<F extends FirebaseAdminFunctionTestContextInstance = FirebaseAdminFunctionTestContextInstance> extends ModelTestContextFixture<${input.model}, ${input.modelDocumentTypeName}, ${input.prefix}FunctionContextFixtureInstance<F>, ${input.prefix}FunctionContextFixture<F>, ${input.instanceClassName}<F>> {`, " // TODO: forward instance methods. Run `dbx_model_fixture_forward` after adding instance methods.", "}"].join("\n");
|
|
13087
|
+
}
|
|
13088
|
+
function renderFactoryBlock(input) {
|
|
13089
|
+
const generics = renderFactoryGenerics(input);
|
|
13090
|
+
const callbacks = renderFactoryCallbacks(input);
|
|
13091
|
+
const lines = [];
|
|
13092
|
+
lines.push(`export const ${input.factoryName} = () =>`);
|
|
13093
|
+
lines.push(` modelTestContextFactory<`);
|
|
13094
|
+
for (let i = 0; i < generics.length; i += 1) {
|
|
13095
|
+
const isLast = i === generics.length - 1;
|
|
13096
|
+
lines.push(` ${generics[i]}${isLast ? "" : ","}`);
|
|
13097
|
+
}
|
|
13098
|
+
lines.push(" >({");
|
|
13099
|
+
for (let i = 0; i < callbacks.length; i += 1) {
|
|
13100
|
+
const isLast = i === callbacks.length - 1;
|
|
13101
|
+
lines.push(` ${callbacks[i]}${isLast ? "" : ","}`);
|
|
13102
|
+
}
|
|
13103
|
+
lines.push(" });");
|
|
13104
|
+
return lines.join("\n");
|
|
13105
|
+
}
|
|
13106
|
+
function renderFactoryGenerics(input) {
|
|
13107
|
+
const baseGenerics = [input.model, input.modelDocumentTypeName, input.paramsTypeName, `${input.prefix}FunctionContextFixtureInstance<FirebaseAdminFunctionTestContextInstance>`, `${input.prefix}FunctionContextFixture<FirebaseAdminFunctionTestContextInstance>`, `${input.instanceClassName}<FirebaseAdminFunctionTestContextInstance>`, `${input.fixtureClassName}<FirebaseAdminFunctionTestContextInstance>`];
|
|
13108
|
+
if (input.collectionGenericArg) {
|
|
13109
|
+
return [...baseGenerics, input.collectionGenericArg];
|
|
13110
|
+
}
|
|
13111
|
+
if (input.archetype === "sub-collection" || input.archetype === "sub-collection-traversal") {
|
|
13112
|
+
return [...baseGenerics, `${input.model}FirestoreCollection`];
|
|
13113
|
+
}
|
|
13114
|
+
return baseGenerics;
|
|
13115
|
+
}
|
|
13116
|
+
function renderFactoryCallbacks(input) {
|
|
13117
|
+
const callbacks = [];
|
|
13118
|
+
callbacks.push(`makeFixture: (f) => new ${input.fixtureClassName}(f)`);
|
|
13119
|
+
if (input.archetype === "sub-collection" || input.archetype === "sub-collection-traversal") {
|
|
13120
|
+
const field = input.parentFixtureField ?? (input.parentFixture ? defaultParentFieldName(input.parentFixture) : "parent");
|
|
13121
|
+
callbacks.push(`getCollection: (fi, params) => fi.${defaultCollectionsAccessor(input.prefix)}.${camelInitial(input.model)}CollectionFactory(params.${field}.document)`);
|
|
13122
|
+
if (input.archetype === "sub-collection-traversal") {
|
|
13123
|
+
callbacks.push(`collectionForDocument: (fi, doc) => fi.${defaultCollectionsAccessor(input.prefix)}.${camelInitial(input.model)}Collection`);
|
|
13124
|
+
input.todos.push("Verify `collectionForDocument` resolves to the correct collection accessor.");
|
|
13125
|
+
}
|
|
13126
|
+
} else {
|
|
13127
|
+
callbacks.push(`getCollection: (fi) => fi.${defaultCollectionsAccessor(input.prefix)}.${camelInitial(input.model)}Collection`);
|
|
13128
|
+
}
|
|
13129
|
+
callbacks.push(`makeInstance: (delegate, ref, testInstance) => new ${input.instanceClassName}(delegate, ref, testInstance)`);
|
|
13130
|
+
callbacks.push(`makeRef: async (collection, params, _p) => {
|
|
13131
|
+
// TODO: choose the correct ref strategy (auto id vs deterministic id).
|
|
13132
|
+
return collection.documentAccessor().newDocument().documentRef;
|
|
13133
|
+
}`);
|
|
13134
|
+
if (input.withInitDocument) {
|
|
13135
|
+
callbacks.push(`initDocument: async (instance, params) => {
|
|
13136
|
+
// TODO: seed the new document with sensible defaults from \`params\`.
|
|
13137
|
+
}`);
|
|
13138
|
+
}
|
|
13139
|
+
return callbacks;
|
|
13140
|
+
}
|
|
13141
|
+
function defaultCollectionsAccessor(prefix) {
|
|
13142
|
+
const base = prefix.length > 0 ? prefix.charAt(0).toLowerCase() + prefix.slice(1) : "app";
|
|
13143
|
+
if (base.endsWith("Api")) {
|
|
13144
|
+
return `${base.slice(0, -3)}FirestoreCollections`;
|
|
13145
|
+
}
|
|
13146
|
+
return `${base}FirestoreCollections`;
|
|
13147
|
+
}
|
|
13148
|
+
function camelInitial(name) {
|
|
13149
|
+
if (name.length === 0) return name;
|
|
13150
|
+
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
13151
|
+
}
|
|
13152
|
+
function defaultParentFieldName(parentModel) {
|
|
13153
|
+
const acronym = parentModel.match(/[A-Z]/g);
|
|
13154
|
+
if (!acronym || acronym.length === 0) return parentModel.toLowerCase();
|
|
13155
|
+
return acronym.join("").toLowerCase();
|
|
13156
|
+
}
|
|
13157
|
+
|
|
13158
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-shared/forward.ts
|
|
13159
|
+
function renderForwarders(input) {
|
|
13160
|
+
const { entry, methods } = input;
|
|
13161
|
+
const fixtureNames = new Set(entry.fixtureMethods.map((m) => m.name));
|
|
13162
|
+
const wanted = methods ? new Set(methods) : void 0;
|
|
13163
|
+
const added = [];
|
|
13164
|
+
const skipped = [];
|
|
13165
|
+
const missing = [];
|
|
13166
|
+
const instanceByName = new Map(entry.instanceMethods.map((m) => [m.name, m]));
|
|
13167
|
+
if (wanted) {
|
|
13168
|
+
for (const name of wanted) {
|
|
13169
|
+
if (!instanceByName.has(name)) {
|
|
13170
|
+
missing.push(name);
|
|
13171
|
+
}
|
|
13172
|
+
}
|
|
13173
|
+
}
|
|
13174
|
+
for (const m of entry.instanceMethods) {
|
|
13175
|
+
if (m.visibility !== "public") continue;
|
|
13176
|
+
if (wanted && !wanted.has(m.name)) continue;
|
|
13177
|
+
if (fixtureNames.has(m.name)) {
|
|
13178
|
+
skipped.push(m.name);
|
|
13179
|
+
continue;
|
|
13180
|
+
}
|
|
13181
|
+
added.push(renderOne(m));
|
|
13182
|
+
}
|
|
13183
|
+
return {
|
|
13184
|
+
added,
|
|
13185
|
+
skippedAlreadyForwarded: skipped,
|
|
13186
|
+
missingFromInstance: missing
|
|
13187
|
+
};
|
|
13188
|
+
}
|
|
13189
|
+
function renderOne(m) {
|
|
13190
|
+
const asyncKw = m.isAsync ? "async " : "";
|
|
13191
|
+
const returnType = m.returnTypeText ? `: ${m.returnTypeText}` : "";
|
|
13192
|
+
const args = parameterCallText(m.parameterText);
|
|
13193
|
+
const body = `return this.instance.${m.name}(${args});`;
|
|
13194
|
+
const source = ` ${asyncKw}${m.name}(${m.parameterText})${returnType} {
|
|
13195
|
+
${body}
|
|
13196
|
+
}`;
|
|
13197
|
+
return { method: m.name, source };
|
|
13198
|
+
}
|
|
13199
|
+
function parameterCallText(parameterText) {
|
|
13200
|
+
if (parameterText.trim().length === 0) return "";
|
|
13201
|
+
const params = splitParameters(parameterText);
|
|
13202
|
+
const out = [];
|
|
13203
|
+
for (const raw of params) {
|
|
13204
|
+
const trimmed = raw.trim();
|
|
13205
|
+
if (trimmed.length === 0) continue;
|
|
13206
|
+
const isRest = trimmed.startsWith("...");
|
|
13207
|
+
const stripped = isRest ? trimmed.slice(3) : trimmed;
|
|
13208
|
+
const equalsIdx = stripped.indexOf("=");
|
|
13209
|
+
const beforeEq = equalsIdx === -1 ? stripped : stripped.slice(0, equalsIdx);
|
|
13210
|
+
const colonIdx = topLevelColonIndex(beforeEq);
|
|
13211
|
+
const head = colonIdx === -1 ? beforeEq : beforeEq.slice(0, colonIdx);
|
|
13212
|
+
const cleaned = head.replace(/\?$/, "").trim();
|
|
13213
|
+
const name = cleaned.replace(/^public\s+|^private\s+|^protected\s+|^readonly\s+/, "").trim();
|
|
13214
|
+
if (name.length === 0) continue;
|
|
13215
|
+
out.push(isRest ? `...${name}` : name);
|
|
13216
|
+
}
|
|
13217
|
+
return out.join(", ");
|
|
13218
|
+
}
|
|
13219
|
+
function splitParameters(text) {
|
|
13220
|
+
const out = [];
|
|
13221
|
+
let depth = 0;
|
|
13222
|
+
let start = 0;
|
|
13223
|
+
for (let i = 0; i < text.length; i += 1) {
|
|
13224
|
+
const ch = text[i];
|
|
13225
|
+
if (ch === "<" || ch === "(" || ch === "[" || ch === "{") depth += 1;
|
|
13226
|
+
else if (ch === ">" || ch === ")" || ch === "]" || ch === "}") depth -= 1;
|
|
13227
|
+
else if (ch === "," && depth === 0) {
|
|
13228
|
+
out.push(text.slice(start, i));
|
|
13229
|
+
start = i + 1;
|
|
13230
|
+
}
|
|
13231
|
+
}
|
|
13232
|
+
out.push(text.slice(start));
|
|
13233
|
+
return out;
|
|
13234
|
+
}
|
|
13235
|
+
function topLevelColonIndex(text) {
|
|
13236
|
+
let depth = 0;
|
|
13237
|
+
let index = 0;
|
|
13238
|
+
for (const ch of text) {
|
|
13239
|
+
if (ch === "<" || ch === "(" || ch === "[" || ch === "{") depth += 1;
|
|
13240
|
+
else if (ch === ">" || ch === ")" || ch === "]" || ch === "}") depth -= 1;
|
|
13241
|
+
else if (ch === ":" && depth === 0) return index;
|
|
13242
|
+
index += 1;
|
|
13243
|
+
}
|
|
13244
|
+
return -1;
|
|
13245
|
+
}
|
|
13246
|
+
|
|
13247
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-list-app.tool.ts
|
|
13248
|
+
var ListArgsType = type31({
|
|
13249
|
+
apiDir: "string",
|
|
13250
|
+
"format?": "'markdown' | 'json'"
|
|
13251
|
+
});
|
|
13252
|
+
var TOOL = {
|
|
13253
|
+
name: "dbx_model_fixture_list_app",
|
|
13254
|
+
description: [
|
|
13255
|
+
"List every `<Prefix><Model>TestContext{Fixture,Instance,Params}` triplet declared in a downstream API app's `src/test/fixture.ts`.",
|
|
13256
|
+
"",
|
|
13257
|
+
"Each row reports the model name, archetype (`top-level-simple` / `top-level-with-deps` / `sub-collection` / `sub-collection-traversal`), Fixture and Instance class names, Params type, factory + singleton, fixture/instance method counts, and start/end lines.",
|
|
13258
|
+
"",
|
|
13259
|
+
"Provide:",
|
|
13260
|
+
"- `apiDir`: relative path to the API app (e.g. `apps/demo-api`).",
|
|
13261
|
+
"- `format` (optional): `markdown` (default) or `json`.",
|
|
13262
|
+
"",
|
|
13263
|
+
"Paths escaping the server cwd are rejected."
|
|
13264
|
+
].join("\n"),
|
|
13265
|
+
inputSchema: {
|
|
13266
|
+
type: "object",
|
|
13267
|
+
properties: {
|
|
13268
|
+
apiDir: { type: "string", description: "Relative path to the API app (e.g. `apps/demo-api`)." },
|
|
13269
|
+
format: { type: "string", enum: ["markdown", "json"], description: "Output format. Defaults to markdown." }
|
|
13270
|
+
},
|
|
13271
|
+
required: ["apiDir"]
|
|
13272
|
+
}
|
|
13273
|
+
};
|
|
13274
|
+
async function run(rawArgs) {
|
|
13275
|
+
const parsed = ListArgsType(rawArgs);
|
|
13276
|
+
if (parsed instanceof type31.errors) {
|
|
13277
|
+
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
13278
|
+
}
|
|
13279
|
+
const cwd = process.cwd();
|
|
13280
|
+
try {
|
|
13281
|
+
ensurePathInsideCwd(parsed.apiDir, cwd);
|
|
13282
|
+
} catch (err) {
|
|
13283
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
13284
|
+
}
|
|
13285
|
+
const apiAbs = resolve15(cwd, parsed.apiDir);
|
|
13286
|
+
let extraction;
|
|
13287
|
+
try {
|
|
13288
|
+
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
13289
|
+
} catch (err) {
|
|
13290
|
+
return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
|
|
13291
|
+
}
|
|
13292
|
+
const text = parsed.format === "json" ? formatListAsJson(extraction) : formatListAsMarkdown(extraction);
|
|
13293
|
+
const result = { content: [{ type: "text", text }] };
|
|
13294
|
+
return result;
|
|
13295
|
+
}
|
|
13296
|
+
var modelFixtureListAppTool = { definition: TOOL, run };
|
|
13297
|
+
|
|
13298
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-lookup.tool.ts
|
|
13299
|
+
import { resolve as resolve16 } from "node:path";
|
|
13300
|
+
import { type as type32 } from "arktype";
|
|
13301
|
+
var LookupArgsType = type32({
|
|
13302
|
+
apiDir: "string",
|
|
13303
|
+
model: "string",
|
|
13304
|
+
"format?": "'markdown' | 'json'"
|
|
13305
|
+
});
|
|
13306
|
+
var TOOL2 = {
|
|
13307
|
+
name: "dbx_model_fixture_lookup",
|
|
13308
|
+
description: [
|
|
13309
|
+
"Look up one fixture/instance triplet declared in `<apiDir>/src/test/fixture.ts`. Returns the archetype, generic args, Params shape with dependency edges, factory + singleton names, and full method tables for both Fixture and Instance with forwarding status.",
|
|
13310
|
+
"",
|
|
13311
|
+
"Provide:",
|
|
13312
|
+
"- `apiDir`: relative path to the API app (e.g. `apps/demo-api`).",
|
|
13313
|
+
"- `model`: bare model name with the workspace prefix stripped (e.g. `StorageFile`, `Profile`).",
|
|
13314
|
+
"- `format` (optional): `markdown` (default) or `json`."
|
|
13315
|
+
].join("\n"),
|
|
13316
|
+
inputSchema: {
|
|
13317
|
+
type: "object",
|
|
13318
|
+
properties: {
|
|
13319
|
+
apiDir: { type: "string", description: "Relative path to the API app." },
|
|
13320
|
+
model: { type: "string", description: "Bare model name (e.g. `StorageFile`)." },
|
|
13321
|
+
format: { type: "string", enum: ["markdown", "json"], description: "Output format. Defaults to markdown." }
|
|
13322
|
+
},
|
|
13323
|
+
required: ["apiDir", "model"]
|
|
13324
|
+
}
|
|
13325
|
+
};
|
|
13326
|
+
async function run2(rawArgs) {
|
|
13327
|
+
const parsed = LookupArgsType(rawArgs);
|
|
13328
|
+
if (parsed instanceof type32.errors) {
|
|
13329
|
+
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
13330
|
+
}
|
|
13331
|
+
const cwd = process.cwd();
|
|
13332
|
+
try {
|
|
13333
|
+
ensurePathInsideCwd(parsed.apiDir, cwd);
|
|
13334
|
+
} catch (err) {
|
|
13335
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
13336
|
+
}
|
|
13337
|
+
const apiAbs = resolve16(cwd, parsed.apiDir);
|
|
13338
|
+
let extraction;
|
|
13339
|
+
try {
|
|
13340
|
+
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
13341
|
+
} catch (err) {
|
|
13342
|
+
return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
|
|
13343
|
+
}
|
|
13344
|
+
const entry = extraction.entries.find((e) => e.model === parsed.model);
|
|
13345
|
+
if (!entry) {
|
|
13346
|
+
const known = extraction.entries.map((e) => e.model).join(", ") || "(none)";
|
|
13347
|
+
return toolError(`Model \`${parsed.model}\` not found in \`${extraction.fixturePath}\`. Known: ${known}.`);
|
|
13348
|
+
}
|
|
13349
|
+
const text = parsed.format === "json" ? formatLookupAsJson(extraction, entry) : formatLookupAsMarkdown(extraction, entry);
|
|
13350
|
+
const result = { content: [{ type: "text", text }] };
|
|
13351
|
+
return result;
|
|
13352
|
+
}
|
|
13353
|
+
var modelFixtureLookupTool = { definition: TOOL2, run: run2 };
|
|
13354
|
+
|
|
13355
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-validate-app.tool.ts
|
|
13356
|
+
import { resolve as resolve17 } from "node:path";
|
|
13357
|
+
import { type as type33 } from "arktype";
|
|
13358
|
+
var ValidateArgsType = type33({
|
|
13359
|
+
apiDir: "string",
|
|
13360
|
+
"format?": "'markdown' | 'json'"
|
|
13361
|
+
});
|
|
13362
|
+
var TOOL3 = {
|
|
13363
|
+
name: "dbx_model_fixture_validate_app",
|
|
13364
|
+
description: [
|
|
13365
|
+
"Validate every `<Prefix><Model>TestContext{Fixture,Instance,Params}` triplet in a downstream API app's `src/test/fixture.ts`.",
|
|
13366
|
+
"",
|
|
13367
|
+
"Diagnostics emitted:",
|
|
13368
|
+
"- `forwarder-missing` / `forwarder-divergent`: every public Instance method must have a Fixture forwarder with a matching signature.",
|
|
13369
|
+
"- `triplet-incomplete`: Fixture, Instance, Params, factory, and singleton must all be present per model.",
|
|
13370
|
+
"- `generics-misaligned`: Model and Document generics must agree across Fixture, Instance, and factory call.",
|
|
13371
|
+
"- `archetype-inconsistent`: sub-collection wiring requires a matching parent fixture field on the Params type.",
|
|
13372
|
+
"- `params-field-naming`: parent fixture field names must equal the parent model's firestoreModelIdentity short alias (when a model registry is configured).",
|
|
13373
|
+
"- `model-not-in-registry` / `model-without-fixture`: registry cross-reference (when a model registry is configured).",
|
|
13374
|
+
"",
|
|
13375
|
+
"Provide:",
|
|
13376
|
+
"- `apiDir`: relative path to the API app.",
|
|
13377
|
+
"- `format` (optional): `markdown` (default) or `json`."
|
|
13378
|
+
].join("\n"),
|
|
13379
|
+
inputSchema: {
|
|
13380
|
+
type: "object",
|
|
13381
|
+
properties: {
|
|
13382
|
+
apiDir: { type: "string", description: "Relative path to the API app." },
|
|
13383
|
+
format: { type: "string", enum: ["markdown", "json"], description: "Output format. Defaults to markdown." }
|
|
13384
|
+
},
|
|
13385
|
+
required: ["apiDir"]
|
|
13386
|
+
}
|
|
13387
|
+
};
|
|
13388
|
+
function createModelFixtureValidateAppTool(config = {}) {
|
|
13389
|
+
async function run5(rawArgs) {
|
|
13390
|
+
const parsed = ValidateArgsType(rawArgs);
|
|
13391
|
+
if (parsed instanceof type33.errors) {
|
|
13392
|
+
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
13393
|
+
}
|
|
13394
|
+
const cwd = process.cwd();
|
|
13395
|
+
try {
|
|
13396
|
+
ensurePathInsideCwd(parsed.apiDir, cwd);
|
|
13397
|
+
} catch (err) {
|
|
13398
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
13399
|
+
}
|
|
13400
|
+
const apiAbs = resolve17(cwd, parsed.apiDir);
|
|
13401
|
+
let extraction;
|
|
13402
|
+
try {
|
|
13403
|
+
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
13404
|
+
} catch (err) {
|
|
13405
|
+
return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
|
|
13406
|
+
}
|
|
13407
|
+
const registry = config.getRegistry ? config.getRegistry() : void 0;
|
|
13408
|
+
const result = validateAppFixtures(extraction, { registry });
|
|
13409
|
+
const text = parsed.format === "json" ? formatValidationAsJson(result) : formatValidationAsMarkdown(result);
|
|
13410
|
+
const toolResult = {
|
|
13411
|
+
content: [{ type: "text", text }],
|
|
13412
|
+
isError: result.errorCount > 0
|
|
13413
|
+
};
|
|
13414
|
+
return toolResult;
|
|
13415
|
+
}
|
|
13416
|
+
return { definition: TOOL3, run: run5 };
|
|
13417
|
+
}
|
|
13418
|
+
|
|
13419
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-scaffold.tool.ts
|
|
13420
|
+
import { readFile as readFile3, writeFile } from "node:fs/promises";
|
|
13421
|
+
import { join as join2, resolve as resolve18 } from "node:path";
|
|
13422
|
+
import { type as type34 } from "arktype";
|
|
13423
|
+
var ScaffoldArgsType3 = type34({
|
|
13424
|
+
apiDir: "string",
|
|
13425
|
+
model: "string",
|
|
13426
|
+
archetype: "'top-level-simple' | 'top-level-with-deps' | 'sub-collection' | 'sub-collection-traversal'",
|
|
13427
|
+
"prefix?": "string",
|
|
13428
|
+
"parentFixture?": "string",
|
|
13429
|
+
"parentFixtureField?": "string",
|
|
13430
|
+
"paramsDependsOn?": type34({
|
|
13431
|
+
field: "string",
|
|
13432
|
+
fixtureModel: "string",
|
|
13433
|
+
"optional?": "boolean",
|
|
13434
|
+
"array?": "boolean"
|
|
13435
|
+
}).array(),
|
|
13436
|
+
"withInitDocument?": "boolean",
|
|
13437
|
+
"collectionGenericArg?": "string",
|
|
13438
|
+
"modelDocumentTypeName?": "string",
|
|
13439
|
+
"factoryNamePrefix?": "string"
|
|
13440
|
+
});
|
|
13441
|
+
var TOOL4 = {
|
|
13442
|
+
name: "dbx_model_fixture_scaffold",
|
|
13443
|
+
description: [
|
|
13444
|
+
"Scaffold a new fixture/instance triplet directly into `<apiDir>/src/test/fixture.ts`. The tool appends a single block containing the Params interface (or `Partial<Model>` alias), Instance class, Fixture class, `modelTestContextFactory(...)` registration, and exported singleton. Every customizable callback body is left as a `TODO`.",
|
|
13445
|
+
"",
|
|
13446
|
+
"Refuses to mutate when any of the named entities already exist \u2014 review the conflict list and either rename or delete the existing entries before retrying.",
|
|
13447
|
+
"",
|
|
13448
|
+
"Use the four archetypes to control the factory dialect:",
|
|
13449
|
+
"- `top-level-simple`: 7 generics, single-arg `getCollection`, `Partial<Model>` Params alias.",
|
|
13450
|
+
"- `top-level-with-deps`: same shape but Params extends `Partial<Model>` and adds the listed fixture dependencies.",
|
|
13451
|
+
"- `sub-collection`: 8 generics, two-arg `getCollection(fi, params)` reading the parent fixture's document. Pass `parentFixture` to drive the parent ref.",
|
|
13452
|
+
"- `sub-collection-traversal`: same as `sub-collection` plus a `collectionForDocument` skeleton.",
|
|
13453
|
+
"",
|
|
13454
|
+
"When `parentFixture` is supplied without `parentFixtureField`, the field name defaults to lowercased initials of the parent model name (`SchoolGroup` \u2192 `sg`). Pass `parentFixtureField` to override.",
|
|
13455
|
+
"",
|
|
13456
|
+
"Returns a structured summary of the inserted entities and a TODO checklist for follow-up edits."
|
|
13457
|
+
].join("\n"),
|
|
13458
|
+
inputSchema: {
|
|
13459
|
+
type: "object",
|
|
13460
|
+
properties: {
|
|
13461
|
+
apiDir: { type: "string", description: "Relative path to the API app." },
|
|
13462
|
+
model: { type: "string", description: "Bare model name (e.g. `Widget`)." },
|
|
13463
|
+
archetype: { type: "string", enum: ["top-level-simple", "top-level-with-deps", "sub-collection", "sub-collection-traversal"], description: "Archetype that drives the factory shape." },
|
|
13464
|
+
prefix: { type: "string", description: "Workspace prefix override (e.g. `DemoApi`). Defaults to the prefix detected in the fixture file." },
|
|
13465
|
+
parentFixture: { type: "string", description: "Bare model name of the parent fixture for sub-collection archetypes." },
|
|
13466
|
+
parentFixtureField: { type: "string", description: "Override for the Params field that holds the parent fixture (defaults to lowercased initials of `parentFixture`, e.g. `sg`)." },
|
|
13467
|
+
paramsDependsOn: {
|
|
13468
|
+
type: "array",
|
|
13469
|
+
description: "Additional fixture refs to add to the Params interface.",
|
|
13470
|
+
items: {
|
|
13471
|
+
type: "object",
|
|
13472
|
+
properties: {
|
|
13473
|
+
field: { type: "string", description: "Params field name (e.g. `u`)." },
|
|
13474
|
+
fixtureModel: { type: "string", description: "Bare fixture model name (e.g. `AuthorizedUser`)." },
|
|
13475
|
+
optional: { type: "boolean", description: "When true the field is optional." },
|
|
13476
|
+
array: { type: "boolean", description: "When true the field type is wrapped in `Maybe<ArrayOrValue<...>>`." }
|
|
13477
|
+
},
|
|
13478
|
+
required: ["field", "fixtureModel"]
|
|
13479
|
+
}
|
|
13480
|
+
},
|
|
13481
|
+
withInitDocument: { type: "boolean", description: "When true an `initDocument` callback skeleton is emitted." },
|
|
13482
|
+
collectionGenericArg: { type: "string", description: "Explicit collection generic for 8-generic factories (e.g. `WidgetFirestoreCollection`)." },
|
|
13483
|
+
modelDocumentTypeName: { type: "string", description: "Override for the Document type name (defaults to `<Model>Document`)." },
|
|
13484
|
+
factoryNamePrefix: { type: "string", description: "Override for the factory name prefix (defaults to lowerCamel of the workspace prefix sans `Api` suffix)." }
|
|
13485
|
+
},
|
|
13486
|
+
required: ["apiDir", "model", "archetype"]
|
|
13487
|
+
}
|
|
13488
|
+
};
|
|
13489
|
+
async function run3(rawArgs) {
|
|
13490
|
+
const parsed = ScaffoldArgsType3(rawArgs);
|
|
13491
|
+
if (parsed instanceof type34.errors) {
|
|
13492
|
+
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
13493
|
+
}
|
|
13494
|
+
const cwd = process.cwd();
|
|
13495
|
+
try {
|
|
13496
|
+
ensurePathInsideCwd(parsed.apiDir, cwd);
|
|
13497
|
+
} catch (err) {
|
|
13498
|
+
return toolError(err instanceof Error ? err.message : String(err));
|
|
13499
|
+
}
|
|
13500
|
+
const apiAbs = resolve18(cwd, parsed.apiDir);
|
|
13501
|
+
let extraction;
|
|
13502
|
+
try {
|
|
13503
|
+
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
13504
|
+
} catch (err) {
|
|
13505
|
+
return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
|
|
13506
|
+
}
|
|
13507
|
+
const prefix = parsed.prefix ?? extraction.prefix;
|
|
13508
|
+
if (!prefix) {
|
|
13509
|
+
return toolError("Could not detect a workspace prefix from the fixture file. Pass `prefix` explicitly (e.g. `DemoApi`).");
|
|
13510
|
+
}
|
|
13511
|
+
if ((parsed.archetype === "sub-collection" || parsed.archetype === "sub-collection-traversal") && !parsed.parentFixture) {
|
|
13512
|
+
return toolError(`Archetype \`${parsed.archetype}\` requires \`parentFixture\` (the bare parent model name).`);
|
|
13513
|
+
}
|
|
13514
|
+
const paramsDependsOn = (parsed.paramsDependsOn ?? []).map((d) => {
|
|
13515
|
+
const dependency = {
|
|
13516
|
+
field: d.field,
|
|
13517
|
+
fixtureModel: d.fixtureModel,
|
|
13518
|
+
optional: d.optional,
|
|
13519
|
+
array: d.array
|
|
13520
|
+
};
|
|
13521
|
+
return dependency;
|
|
13522
|
+
});
|
|
13523
|
+
const rendered = renderFixtureScaffold(extraction, {
|
|
13524
|
+
model: parsed.model,
|
|
13525
|
+
prefix,
|
|
13526
|
+
archetype: parsed.archetype,
|
|
13527
|
+
parentFixture: parsed.parentFixture,
|
|
13528
|
+
parentFixtureField: parsed.parentFixtureField,
|
|
13529
|
+
paramsDependsOn,
|
|
13530
|
+
withInitDocument: parsed.withInitDocument,
|
|
13531
|
+
collectionGenericArg: parsed.collectionGenericArg,
|
|
13532
|
+
modelDocumentTypeName: parsed.modelDocumentTypeName,
|
|
13533
|
+
factoryNamePrefix: parsed.factoryNamePrefix
|
|
13534
|
+
});
|
|
13535
|
+
const conflicts = collectConflicts(extraction, rendered);
|
|
13536
|
+
if (conflicts.length > 0) {
|
|
13537
|
+
return toolError(["Refusing to scaffold \u2014 the following names already exist in `" + extraction.fixturePath + "`:", "", ...conflicts.map((c) => "- `" + c + "`"), "", "Rename, delete, or pick a different model name and retry."].join("\n"));
|
|
13538
|
+
}
|
|
13539
|
+
const absolutePath = join2(apiAbs, FIXTURE_RELATIVE_PATH);
|
|
13540
|
+
let original;
|
|
13541
|
+
try {
|
|
13542
|
+
original = await readFile3(absolutePath, "utf8");
|
|
13543
|
+
} catch (err) {
|
|
13544
|
+
return toolError(`Failed to read fixture file: ${err instanceof Error ? err.message : String(err)}`);
|
|
13545
|
+
}
|
|
13546
|
+
const newline = original.endsWith("\n") ? "" : "\n";
|
|
13547
|
+
const updated = `${original}${newline}
|
|
13548
|
+
${rendered.snippet}`;
|
|
13549
|
+
try {
|
|
13550
|
+
await writeFile(absolutePath, updated, "utf8");
|
|
13551
|
+
} catch (err) {
|
|
13552
|
+
return toolError(`Failed to write fixture file: ${err instanceof Error ? err.message : String(err)}`);
|
|
13553
|
+
}
|
|
13554
|
+
const reExtraction = extractAppFixturesFromText({ text: updated, fixturePath: extraction.fixturePath });
|
|
13555
|
+
const newEntry = reExtraction.entries.find((e) => e.fixtureClassName === rendered.fixtureClassName);
|
|
13556
|
+
const lines = [];
|
|
13557
|
+
lines.push(`# Scaffolded \`${rendered.fixtureClassName}\``);
|
|
13558
|
+
lines.push("");
|
|
13559
|
+
lines.push(`File: \`${extraction.fixturePath}\``);
|
|
13560
|
+
lines.push(`Archetype: \`${parsed.archetype}\``);
|
|
13561
|
+
lines.push("");
|
|
13562
|
+
lines.push("## Inserted");
|
|
13563
|
+
for (const ins of rendered.inserted) {
|
|
13564
|
+
lines.push(`- ${ins.kind}: \`${ins.name}\``);
|
|
13565
|
+
}
|
|
13566
|
+
if (newEntry) {
|
|
13567
|
+
lines.push("", `Fixture lines: ${newEntry.fixtureLine}-${newEntry.fixtureEndLine}`);
|
|
13568
|
+
lines.push(`Instance lines: ${newEntry.instanceLine}-${newEntry.instanceEndLine}`);
|
|
11926
13569
|
}
|
|
11927
|
-
lines.push(
|
|
11928
|
-
|
|
11929
|
-
}
|
|
11930
|
-
|
|
11931
|
-
const
|
|
11932
|
-
|
|
11933
|
-
const directiveClass = `${args.appPrefixPascal}${args.modelName}DocumentStoreDirective`;
|
|
11934
|
-
const selector = `[${args.appPrefixCamel}${args.modelName}Document]`;
|
|
11935
|
-
const lines = [
|
|
11936
|
-
`import { Directive, inject } from '@angular/core';`,
|
|
11937
|
-
`import { DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';`,
|
|
11938
|
-
`import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
|
|
11939
|
-
`import { ${storeClass} } from './${args.fileBaseName}.document.store';`,
|
|
11940
|
-
"",
|
|
11941
|
-
`@Directive({`,
|
|
11942
|
-
` selector: '${selector}',`,
|
|
11943
|
-
` providers: provideDbxFirebaseDocumentStoreDirective(${directiveClass}, ${storeClass}),`,
|
|
11944
|
-
` standalone: true`,
|
|
11945
|
-
`})`,
|
|
11946
|
-
`export class ${directiveClass} extends DbxFirebaseDocumentStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
|
|
11947
|
-
` constructor() {`,
|
|
11948
|
-
` super(inject(${storeClass}));`,
|
|
11949
|
-
` }`,
|
|
11950
|
-
`}`
|
|
11951
|
-
];
|
|
11952
|
-
return { path: `${args.fileBaseName}.document.store.directive.ts`, body: lines.join("\n") };
|
|
13570
|
+
lines.push("", "## Follow-up TODOs");
|
|
13571
|
+
for (const todo of rendered.todos) {
|
|
13572
|
+
lines.push(`- [ ] ${todo}`);
|
|
13573
|
+
}
|
|
13574
|
+
const result = { content: [{ type: "text", text: lines.join("\n") }] };
|
|
13575
|
+
return result;
|
|
11953
13576
|
}
|
|
11954
|
-
function
|
|
11955
|
-
const
|
|
11956
|
-
const
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
|
|
11961
|
-
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
"",
|
|
11965
|
-
`@Directive({`,
|
|
11966
|
-
` selector: '${selector}',`,
|
|
11967
|
-
` providers: provideDbxFirebaseCollectionStoreDirective(${directiveClass}, ${storeClass}),`,
|
|
11968
|
-
` standalone: true`,
|
|
11969
|
-
`})`,
|
|
11970
|
-
`export class ${directiveClass} extends DbxFirebaseCollectionStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
|
|
11971
|
-
` constructor() {`,
|
|
11972
|
-
` super(inject(${storeClass}));`,
|
|
11973
|
-
` }`,
|
|
11974
|
-
`}`
|
|
11975
|
-
];
|
|
11976
|
-
return { path: `${args.fileBaseName}.collection.store.directive.ts`, body: lines.join("\n") };
|
|
13577
|
+
function collectConflicts(extraction, rendered) {
|
|
13578
|
+
const out = [];
|
|
13579
|
+
for (const e of extraction.entries) {
|
|
13580
|
+
if (e.fixtureClassName === rendered.fixtureClassName) out.push(rendered.fixtureClassName);
|
|
13581
|
+
if (e.instanceClassName === rendered.instanceClassName) out.push(rendered.instanceClassName);
|
|
13582
|
+
if (e.paramsTypeName === rendered.paramsTypeName) out.push(rendered.paramsTypeName);
|
|
13583
|
+
if (e.factoryName === rendered.factoryName) out.push(rendered.factoryName);
|
|
13584
|
+
if (e.singletonName === rendered.singletonName) out.push(rendered.singletonName);
|
|
13585
|
+
}
|
|
13586
|
+
return [...new Set(out)];
|
|
11977
13587
|
}
|
|
11978
|
-
|
|
11979
|
-
|
|
11980
|
-
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
|
|
11984
|
-
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
11989
|
-
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
|
|
11997
|
-
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
|
|
12001
|
-
}
|
|
13588
|
+
var modelFixtureScaffoldTool = { definition: TOOL4, run: run3 };
|
|
13589
|
+
|
|
13590
|
+
// packages/dbx-components-mcp/src/tools/model-fixture-forward.tool.ts
|
|
13591
|
+
import { join as join3, resolve as resolve19 } from "node:path";
|
|
13592
|
+
import { type as type35 } from "arktype";
|
|
13593
|
+
import { Project as Project7 } from "ts-morph";
|
|
13594
|
+
var ForwardArgsType = type35({
|
|
13595
|
+
apiDir: "string",
|
|
13596
|
+
model: "string",
|
|
13597
|
+
"methods?": "string[]"
|
|
13598
|
+
});
|
|
13599
|
+
var TOOL5 = {
|
|
13600
|
+
name: "dbx_model_fixture_forward",
|
|
13601
|
+
description: ["Insert the missing Fixture forwarder methods for one model in `<apiDir>/src/test/fixture.ts`. Every public Instance method that lacks a Fixture method gains a thin wrapper:", "", "```ts", "async <name>(<paramText>): <returnType> {", " return this.instance.<name>(<args>);", "}", "```", "", "Existing forwarders are left untouched (idempotent). Pass `methods` to limit the run to specific method names; omit to forward everything that's missing."].join("\n"),
|
|
13602
|
+
inputSchema: {
|
|
13603
|
+
type: "object",
|
|
13604
|
+
properties: {
|
|
13605
|
+
apiDir: { type: "string", description: "Relative path to the API app." },
|
|
13606
|
+
model: { type: "string", description: "Bare model name (e.g. `StorageFile`)." },
|
|
13607
|
+
methods: {
|
|
13608
|
+
type: "array",
|
|
13609
|
+
items: { type: "string" },
|
|
13610
|
+
description: "Optional whitelist of instance method names to forward."
|
|
12002
13611
|
}
|
|
12003
|
-
}
|
|
13612
|
+
},
|
|
13613
|
+
required: ["apiDir", "model"]
|
|
12004
13614
|
}
|
|
12005
|
-
|
|
12006
|
-
|
|
12007
|
-
|
|
12008
|
-
|
|
12009
|
-
|
|
12010
|
-
const functionsLabel = args.functionsClass ?? "none";
|
|
12011
|
-
const crudLabel = args.crudFunctions.length > 0 ? args.crudFunctions.map((c) => `${c.name} (${c.kind})`).join(", ") : "none";
|
|
12012
|
-
const parentLabel = args.parentModel === void 0 ? "n/a" : args.parentModel.name;
|
|
12013
|
-
const lines = [`# ${args.modelName} store scaffold`, "", `Shape: \`${args.shape}\` \xB7 Surfaces: ${surfaceLabel} \xB7 Parent: ${parentLabel} \xB7 Functions: ${functionsLabel} \xB7 Crud: ${crudLabel}`, "", `Drop into \`<app>/src/lib/modules/${args.fileBaseName.replaceAll(".", "/")}/store/\`.`, ""];
|
|
12014
|
-
for (const block of blocks) {
|
|
12015
|
-
lines.push(`## \`${block.path}\``, "", "```ts", block.body, "```", "");
|
|
13615
|
+
};
|
|
13616
|
+
async function run4(rawArgs) {
|
|
13617
|
+
const parsed = ForwardArgsType(rawArgs);
|
|
13618
|
+
if (parsed instanceof type35.errors) {
|
|
13619
|
+
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
12016
13620
|
}
|
|
12017
|
-
|
|
12018
|
-
|
|
12019
|
-
|
|
13621
|
+
const cwd = process.cwd();
|
|
13622
|
+
try {
|
|
13623
|
+
ensurePathInsideCwd(parsed.apiDir, cwd);
|
|
13624
|
+
} catch (err) {
|
|
13625
|
+
return toolError(toErrorMessage(err));
|
|
12020
13626
|
}
|
|
12021
|
-
|
|
12022
|
-
|
|
13627
|
+
const apiAbs = resolve19(cwd, parsed.apiDir);
|
|
13628
|
+
let extraction;
|
|
13629
|
+
try {
|
|
13630
|
+
extraction = await inspectAppFixtures(apiAbs, parsed.apiDir);
|
|
13631
|
+
} catch (err) {
|
|
13632
|
+
return toolError(`Failed to read fixture file: ${toErrorMessage(err)}`);
|
|
12023
13633
|
}
|
|
12024
|
-
|
|
12025
|
-
|
|
13634
|
+
const entry = extraction.entries.find((e) => e.model === parsed.model);
|
|
13635
|
+
if (!entry) {
|
|
13636
|
+
const known = extraction.entries.map((e) => e.model).join(", ") || "(none)";
|
|
13637
|
+
return toolError(`Model \`${parsed.model}\` not found in \`${extraction.fixturePath}\`. Known: ${known}.`);
|
|
12026
13638
|
}
|
|
12027
|
-
|
|
12028
|
-
|
|
13639
|
+
const rendered = renderForwarders({ entry, methods: parsed.methods });
|
|
13640
|
+
if (rendered.added.length === 0) {
|
|
13641
|
+
return { content: [{ type: "text", text: renderNoOpReport(extraction.fixturePath, entry.fixtureClassName, rendered) }] };
|
|
13642
|
+
}
|
|
13643
|
+
const absolutePath = join3(apiAbs, FIXTURE_RELATIVE_PATH);
|
|
13644
|
+
const writeError = await applyForwardersToFile(absolutePath, entry.fixtureClassName, rendered);
|
|
13645
|
+
if (writeError) {
|
|
13646
|
+
return toolError(writeError);
|
|
13647
|
+
}
|
|
13648
|
+
return { content: [{ type: "text", text: renderSuccessReport(extraction.fixturePath, entry.fixtureClassName, rendered) }] };
|
|
12029
13649
|
}
|
|
12030
|
-
function
|
|
12031
|
-
|
|
13650
|
+
function toErrorMessage(err) {
|
|
13651
|
+
return err instanceof Error ? err.message : String(err);
|
|
13652
|
+
}
|
|
13653
|
+
async function applyForwardersToFile(absolutePath, fixtureClassName, rendered) {
|
|
13654
|
+
const project = new Project7({ skipAddingFilesFromTsConfig: true });
|
|
13655
|
+
let sourceFile;
|
|
12032
13656
|
try {
|
|
12033
|
-
|
|
13657
|
+
sourceFile = project.addSourceFileAtPath(absolutePath);
|
|
12034
13658
|
} catch (err) {
|
|
12035
|
-
|
|
12036
|
-
return toolError(message);
|
|
13659
|
+
return `Failed to load fixture file: ${toErrorMessage(err)}`;
|
|
12037
13660
|
}
|
|
12038
|
-
const
|
|
12039
|
-
|
|
12040
|
-
|
|
13661
|
+
const fixtureClass = sourceFile.getClass(fixtureClassName);
|
|
13662
|
+
if (!fixtureClass) {
|
|
13663
|
+
return `Could not locate class \`${fixtureClassName}\` for in-place edit. The fixture file may have been modified since parsing.`;
|
|
13664
|
+
}
|
|
13665
|
+
for (const forwarder of rendered.added) {
|
|
13666
|
+
fixtureClass.insertText(fixtureClass.getEnd() - 1, "\n" + forwarder.source + "\n");
|
|
13667
|
+
}
|
|
13668
|
+
sourceFile.formatText({ ensureNewLineAtEndOfFile: true });
|
|
13669
|
+
try {
|
|
13670
|
+
await sourceFile.save();
|
|
13671
|
+
} catch (err) {
|
|
13672
|
+
return `Failed to write fixture file: ${toErrorMessage(err)}`;
|
|
13673
|
+
}
|
|
13674
|
+
return void 0;
|
|
12041
13675
|
}
|
|
12042
|
-
|
|
12043
|
-
|
|
12044
|
-
|
|
12045
|
-
|
|
13676
|
+
function renderNoOpReport(fixturePath, fixtureClassName, rendered) {
|
|
13677
|
+
const lines = [`# No forwarders to add for \`${fixtureClassName}\``, "", `File: \`${fixturePath}\``];
|
|
13678
|
+
appendListSection(lines, "## Already forwarded", rendered.skippedAlreadyForwarded);
|
|
13679
|
+
appendListSection(lines, "## Whitelisted methods missing from Instance", rendered.missingFromInstance);
|
|
13680
|
+
return lines.join("\n");
|
|
13681
|
+
}
|
|
13682
|
+
function renderSuccessReport(fixturePath, fixtureClassName, rendered) {
|
|
13683
|
+
const lines = [`# Forwarded ${rendered.added.length} method${rendered.added.length === 1 ? "" : "s"} to \`${fixtureClassName}\``, "", `File: \`${fixturePath}\``, "", "## Added"];
|
|
13684
|
+
for (const f of rendered.added) {
|
|
13685
|
+
lines.push(`- \`${f.method}\``);
|
|
13686
|
+
}
|
|
13687
|
+
appendListSection(lines, "## Skipped (already forwarded)", rendered.skippedAlreadyForwarded);
|
|
13688
|
+
appendListSection(lines, "## Whitelisted methods missing from Instance", rendered.missingFromInstance);
|
|
13689
|
+
return lines.join("\n");
|
|
13690
|
+
}
|
|
13691
|
+
function appendListSection(lines, heading, names) {
|
|
13692
|
+
if (names.length === 0) return;
|
|
13693
|
+
lines.push("", heading);
|
|
13694
|
+
for (const name of names) {
|
|
13695
|
+
lines.push(`- \`${name}\``);
|
|
13696
|
+
}
|
|
13697
|
+
}
|
|
13698
|
+
var modelFixtureForwardTool = { definition: TOOL5, run: run4 };
|
|
12046
13699
|
|
|
12047
13700
|
// packages/dbx-components-mcp/src/tools/storagefile-m-validate-app/extract.ts
|
|
12048
|
-
import { Node as
|
|
13701
|
+
import { Node as Node10, SyntaxKind as SyntaxKind7 } from "ts-morph";
|
|
12049
13702
|
|
|
12050
13703
|
// packages/dbx-components-mcp/src/tools/_validate/ast.ts
|
|
12051
|
-
import { Node as
|
|
13704
|
+
import { Node as Node9, Project as Project8, SyntaxKind as SyntaxKind6 } from "ts-morph";
|
|
12052
13705
|
var COMPONENT_VIRTUAL_PREFIX = "__component__/";
|
|
12053
13706
|
var API_VIRTUAL_PREFIX = "__api__/";
|
|
12054
13707
|
function buildInMemoryProject(input) {
|
|
12055
|
-
const project = new
|
|
13708
|
+
const project = new Project8({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
12056
13709
|
const componentSources = [];
|
|
12057
13710
|
const apiSources = [];
|
|
12058
13711
|
for (const file of input.component.files) {
|
|
@@ -12072,28 +13725,28 @@ function componentRelPath(sourceFile) {
|
|
|
12072
13725
|
}
|
|
12073
13726
|
function unwrapAsExpressions(node) {
|
|
12074
13727
|
let current = node;
|
|
12075
|
-
while (current &&
|
|
13728
|
+
while (current && Node9.isAsExpression(current)) {
|
|
12076
13729
|
current = current.getExpression();
|
|
12077
13730
|
}
|
|
12078
13731
|
return current;
|
|
12079
13732
|
}
|
|
12080
13733
|
function asObjectLiteral(node) {
|
|
12081
13734
|
const inner = unwrapAsExpressions(node);
|
|
12082
|
-
if (inner &&
|
|
13735
|
+
if (inner && Node9.isObjectLiteralExpression(inner)) {
|
|
12083
13736
|
return inner;
|
|
12084
13737
|
}
|
|
12085
13738
|
return void 0;
|
|
12086
13739
|
}
|
|
12087
13740
|
function asArrayLiteral(node) {
|
|
12088
13741
|
const inner = unwrapAsExpressions(node);
|
|
12089
|
-
if (inner &&
|
|
13742
|
+
if (inner && Node9.isArrayLiteralExpression(inner)) {
|
|
12090
13743
|
return inner;
|
|
12091
13744
|
}
|
|
12092
13745
|
return void 0;
|
|
12093
13746
|
}
|
|
12094
13747
|
function readStringLiteralInitializer(decl) {
|
|
12095
13748
|
const initializer = unwrapAsExpressions(decl.getInitializer());
|
|
12096
|
-
if (initializer &&
|
|
13749
|
+
if (initializer && Node9.isStringLiteral(initializer)) {
|
|
12097
13750
|
return initializer.getLiteralText();
|
|
12098
13751
|
}
|
|
12099
13752
|
return void 0;
|
|
@@ -12105,37 +13758,37 @@ function typeAnnotationText(node) {
|
|
|
12105
13758
|
function getPropertyInitializer(obj, name) {
|
|
12106
13759
|
const prop = obj.getProperty(name);
|
|
12107
13760
|
if (!prop) return void 0;
|
|
12108
|
-
if (
|
|
13761
|
+
if (Node9.isPropertyAssignment(prop)) {
|
|
12109
13762
|
return prop.getInitializer();
|
|
12110
13763
|
}
|
|
12111
|
-
if (
|
|
13764
|
+
if (Node9.isShorthandPropertyAssignment(prop)) {
|
|
12112
13765
|
return prop.getNameNode();
|
|
12113
13766
|
}
|
|
12114
13767
|
return void 0;
|
|
12115
13768
|
}
|
|
12116
13769
|
function readStringProperty2(obj, name) {
|
|
12117
13770
|
const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
|
|
12118
|
-
if (init &&
|
|
13771
|
+
if (init && Node9.isStringLiteral(init)) {
|
|
12119
13772
|
return init.getLiteralText();
|
|
12120
13773
|
}
|
|
12121
13774
|
return void 0;
|
|
12122
13775
|
}
|
|
12123
13776
|
function readIdentifierProperty(obj, name) {
|
|
12124
13777
|
const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
|
|
12125
|
-
if (init &&
|
|
13778
|
+
if (init && Node9.isIdentifier(init)) {
|
|
12126
13779
|
return init.getText();
|
|
12127
13780
|
}
|
|
12128
13781
|
return void 0;
|
|
12129
13782
|
}
|
|
12130
13783
|
function findReturnExpression(fn) {
|
|
12131
|
-
if (!
|
|
13784
|
+
if (!Node9.isArrowFunction(fn) && !Node9.isFunctionDeclaration(fn) && !Node9.isFunctionExpression(fn)) {
|
|
12132
13785
|
return void 0;
|
|
12133
13786
|
}
|
|
12134
13787
|
const body = fn.getBody();
|
|
12135
13788
|
if (!body) return void 0;
|
|
12136
|
-
if (
|
|
13789
|
+
if (Node9.isBlock(body)) {
|
|
12137
13790
|
for (const stmt of body.getStatements()) {
|
|
12138
|
-
if (
|
|
13791
|
+
if (Node9.isReturnStatement(stmt)) {
|
|
12139
13792
|
return stmt.getExpression();
|
|
12140
13793
|
}
|
|
12141
13794
|
}
|
|
@@ -12149,17 +13802,17 @@ function findLocalVariable(sf, name) {
|
|
|
12149
13802
|
if (decl.getName() === name) return decl;
|
|
12150
13803
|
}
|
|
12151
13804
|
}
|
|
12152
|
-
for (const decl of sf.getDescendantsOfKind(
|
|
13805
|
+
for (const decl of sf.getDescendantsOfKind(SyntaxKind6.VariableDeclaration)) {
|
|
12153
13806
|
if (decl.getName() === name) return decl;
|
|
12154
13807
|
}
|
|
12155
13808
|
return void 0;
|
|
12156
13809
|
}
|
|
12157
13810
|
function collectTypeofReferences(node, out) {
|
|
12158
|
-
if (
|
|
13811
|
+
if (Node9.isTypeQuery(node)) {
|
|
12159
13812
|
out.push(node.getExprName().getText());
|
|
12160
13813
|
return;
|
|
12161
13814
|
}
|
|
12162
|
-
for (const tq of node.getDescendantsOfKind(
|
|
13815
|
+
for (const tq of node.getDescendantsOfKind(SyntaxKind6.TypeQuery)) {
|
|
12163
13816
|
out.push(tq.getExprName().getText());
|
|
12164
13817
|
}
|
|
12165
13818
|
}
|
|
@@ -12457,8 +14110,8 @@ function getFunctionType(x) {
|
|
|
12457
14110
|
return typeof x === "function" ? x.prototype ? Object.getOwnPropertyDescriptor(x, "prototype")?.writable ? "function" : "class" : x.constructor.name === "AsyncFunction" ? "function" : "arrow" : null;
|
|
12458
14111
|
}
|
|
12459
14112
|
function isNonClassFunction(x) {
|
|
12460
|
-
const
|
|
12461
|
-
return
|
|
14113
|
+
const type48 = getFunctionType(x);
|
|
14114
|
+
return type48 != null && type48 !== "class";
|
|
12462
14115
|
}
|
|
12463
14116
|
|
|
12464
14117
|
// packages/util/src/lib/getter/getter.ts
|
|
@@ -12535,9 +14188,9 @@ function asNumber(input) {
|
|
|
12535
14188
|
}
|
|
12536
14189
|
|
|
12537
14190
|
// packages/util/src/lib/number/round.ts
|
|
12538
|
-
function roundingFunction(
|
|
14191
|
+
function roundingFunction(type48) {
|
|
12539
14192
|
let fn;
|
|
12540
|
-
switch (
|
|
14193
|
+
switch (type48) {
|
|
12541
14194
|
case "floor":
|
|
12542
14195
|
fn = Math.floor;
|
|
12543
14196
|
break;
|
|
@@ -12790,9 +14443,9 @@ function filterKeyValueTuplesInputToFilter(input) {
|
|
|
12790
14443
|
}
|
|
12791
14444
|
function filterKeyValueTupleFunction(inputFilter) {
|
|
12792
14445
|
const filter = filterKeyValueTuplesInputToFilter(inputFilter);
|
|
12793
|
-
const { valueFilter:
|
|
14446
|
+
const { valueFilter: type48 = 1 /* UNDEFINED */, invertFilter: inverseFilter = false, keysFilter } = filter;
|
|
12794
14447
|
let filterFn;
|
|
12795
|
-
switch (
|
|
14448
|
+
switch (type48) {
|
|
12796
14449
|
case 1 /* UNDEFINED */:
|
|
12797
14450
|
filterFn = ([, x]) => x !== void 0;
|
|
12798
14451
|
break;
|
|
@@ -13051,7 +14704,7 @@ var NUMBER_STRING_DENCODER_64_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcd
|
|
|
13051
14704
|
var NUMBER_STRING_DENCODER_64_DEFAULT_NEGATIVE_PREFIX = "!";
|
|
13052
14705
|
function numberStringDencoder(config) {
|
|
13053
14706
|
const { negativePrefix, digits } = config;
|
|
13054
|
-
const
|
|
14707
|
+
const type48 = negativePrefix ? "integer" : "positive_integer";
|
|
13055
14708
|
const log2OfDigits = Math.min(6, Math.floor(Math.log2(digits.length)));
|
|
13056
14709
|
const bitDepth = Math.pow(2, log2OfDigits);
|
|
13057
14710
|
const bitMask = bitDepth - 1;
|
|
@@ -13088,7 +14741,7 @@ function numberStringDencoder(config) {
|
|
|
13088
14741
|
return result;
|
|
13089
14742
|
}
|
|
13090
14743
|
return {
|
|
13091
|
-
type:
|
|
14744
|
+
type: type48,
|
|
13092
14745
|
digits,
|
|
13093
14746
|
bitDepth,
|
|
13094
14747
|
negativePrefix,
|
|
@@ -13159,9 +14812,9 @@ function readableStreamToStringFunction(encoding) {
|
|
|
13159
14812
|
var readableStreamToBase64 = readableStreamToStringFunction("base64");
|
|
13160
14813
|
function readableStreamToBuffer(stream) {
|
|
13161
14814
|
const chunks = [];
|
|
13162
|
-
return new Promise((
|
|
14815
|
+
return new Promise((resolve22, reject) => {
|
|
13163
14816
|
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
13164
|
-
stream.on("end", () =>
|
|
14817
|
+
stream.on("end", () => resolve22(Buffer.concat(chunks)));
|
|
13165
14818
|
stream.on("error", reject);
|
|
13166
14819
|
});
|
|
13167
14820
|
}
|
|
@@ -13584,7 +15237,7 @@ function extractUploadInitializerEntries(sources) {
|
|
|
13584
15237
|
const out = [];
|
|
13585
15238
|
for (const sf of sources) {
|
|
13586
15239
|
const rel = apiRelPath(sf);
|
|
13587
|
-
for (const decl of sf.getDescendantsOfKind(
|
|
15240
|
+
for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
|
|
13588
15241
|
const typeText = typeAnnotationText(decl);
|
|
13589
15242
|
if (typeText !== UPLOAD_SERVICE_INITIALIZER_TYPE) continue;
|
|
13590
15243
|
const obj = asObjectLiteral(decl.getInitializer());
|
|
@@ -13614,7 +15267,7 @@ function buildApiFunctionIndex(sources) {
|
|
|
13614
15267
|
for (const decl of stmt.getDeclarations()) {
|
|
13615
15268
|
const initializer = unwrapAsExpressions(decl.getInitializer());
|
|
13616
15269
|
if (!initializer) continue;
|
|
13617
|
-
if (
|
|
15270
|
+
if (Node10.isArrowFunction(initializer) || Node10.isFunctionExpression(initializer)) {
|
|
13618
15271
|
map.set(decl.getName(), { node: initializer, sourceFile: sf });
|
|
13619
15272
|
}
|
|
13620
15273
|
}
|
|
@@ -13627,34 +15280,34 @@ function collectInitializerBindingsFromValue(options) {
|
|
|
13627
15280
|
const { node, sf, index, resolved, unresolved, visited } = options;
|
|
13628
15281
|
const inner = unwrapAsExpressions(node);
|
|
13629
15282
|
if (!inner) return false;
|
|
13630
|
-
if (
|
|
15283
|
+
if (Node10.isArrayLiteralExpression(inner)) {
|
|
13631
15284
|
for (const el of inner.getElements()) {
|
|
13632
|
-
if (
|
|
15285
|
+
if (Node10.isSpreadElement(el)) {
|
|
13633
15286
|
const spreadInner = el.getExpression();
|
|
13634
|
-
if (
|
|
15287
|
+
if (Node10.isIdentifier(spreadInner)) {
|
|
13635
15288
|
collectInitializerBindingsFromIdentifier({ name: spreadInner.getText(), sf, index, resolved, unresolved, visited });
|
|
13636
|
-
} else if (
|
|
15289
|
+
} else if (Node10.isCallExpression(spreadInner)) {
|
|
13637
15290
|
const callee = spreadInner.getExpression();
|
|
13638
|
-
if (
|
|
15291
|
+
if (Node10.isIdentifier(callee)) {
|
|
13639
15292
|
collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
|
|
13640
15293
|
}
|
|
13641
15294
|
}
|
|
13642
15295
|
continue;
|
|
13643
15296
|
}
|
|
13644
15297
|
const elementInner = unwrapAsExpressions(el);
|
|
13645
|
-
if (elementInner &&
|
|
15298
|
+
if (elementInner && Node10.isIdentifier(elementInner)) {
|
|
13646
15299
|
resolved.push(elementInner.getText());
|
|
13647
15300
|
}
|
|
13648
15301
|
}
|
|
13649
15302
|
return true;
|
|
13650
15303
|
}
|
|
13651
|
-
if (
|
|
15304
|
+
if (Node10.isCallExpression(inner)) {
|
|
13652
15305
|
const callee = inner.getExpression();
|
|
13653
|
-
if (
|
|
15306
|
+
if (Node10.isIdentifier(callee)) {
|
|
13654
15307
|
return collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
|
|
13655
15308
|
}
|
|
13656
15309
|
}
|
|
13657
|
-
if (
|
|
15310
|
+
if (Node10.isIdentifier(inner)) {
|
|
13658
15311
|
return collectInitializerBindingsFromIdentifier({ name: inner.getText(), sf, index, resolved, unresolved, visited });
|
|
13659
15312
|
}
|
|
13660
15313
|
return false;
|
|
@@ -13693,15 +15346,15 @@ function collectUploadInitializerArray(options) {
|
|
|
13693
15346
|
const { initializerArr, sf, index, direct, spreads, resolved, unresolved } = options;
|
|
13694
15347
|
const visited = /* @__PURE__ */ new Set();
|
|
13695
15348
|
for (const el of initializerArr.getElements()) {
|
|
13696
|
-
if (
|
|
15349
|
+
if (Node10.isSpreadElement(el)) {
|
|
13697
15350
|
const inner2 = el.getExpression();
|
|
13698
|
-
if (
|
|
15351
|
+
if (Node10.isIdentifier(inner2)) {
|
|
13699
15352
|
const name = inner2.getText();
|
|
13700
15353
|
spreads.push(name);
|
|
13701
15354
|
collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
|
|
13702
|
-
} else if (
|
|
15355
|
+
} else if (Node10.isCallExpression(inner2)) {
|
|
13703
15356
|
const callee = inner2.getExpression();
|
|
13704
|
-
if (
|
|
15357
|
+
if (Node10.isIdentifier(callee)) {
|
|
13705
15358
|
const name = callee.getText();
|
|
13706
15359
|
spreads.push(name);
|
|
13707
15360
|
collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
|
|
@@ -13710,7 +15363,7 @@ function collectUploadInitializerArray(options) {
|
|
|
13710
15363
|
continue;
|
|
13711
15364
|
}
|
|
13712
15365
|
const inner = unwrapAsExpressions(el);
|
|
13713
|
-
if (inner &&
|
|
15366
|
+
if (inner && Node10.isIdentifier(inner)) {
|
|
13714
15367
|
const name = inner.getText();
|
|
13715
15368
|
direct.push(name);
|
|
13716
15369
|
resolved.push(name);
|
|
@@ -13721,9 +15374,9 @@ function extractUploadServiceCalls(sources, index) {
|
|
|
13721
15374
|
const out = [];
|
|
13722
15375
|
for (const sf of sources) {
|
|
13723
15376
|
const rel = apiRelPath(sf);
|
|
13724
|
-
for (const call of sf.getDescendantsOfKind(
|
|
15377
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
|
|
13725
15378
|
const expr = call.getExpression();
|
|
13726
|
-
if (!
|
|
15379
|
+
if (!Node10.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
|
|
13727
15380
|
const args = call.getArguments();
|
|
13728
15381
|
const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
|
|
13729
15382
|
if (!first) continue;
|
|
@@ -13751,12 +15404,12 @@ function extractUploadServiceCalls(sources, index) {
|
|
|
13751
15404
|
function resolveObjectArg(node, sf) {
|
|
13752
15405
|
const inner = unwrapAsExpressions(node);
|
|
13753
15406
|
if (!inner) return void 0;
|
|
13754
|
-
if (
|
|
13755
|
-
if (
|
|
15407
|
+
if (Node10.isObjectLiteralExpression(inner)) return inner;
|
|
15408
|
+
if (Node10.isIdentifier(inner)) {
|
|
13756
15409
|
const declNode = findLocalVariable(sf, inner.getText());
|
|
13757
15410
|
if (declNode) {
|
|
13758
15411
|
const declInit = unwrapAsExpressions(declNode.getInitializer());
|
|
13759
|
-
if (declInit &&
|
|
15412
|
+
if (declInit && Node10.isObjectLiteralExpression(declInit)) {
|
|
13760
15413
|
return declInit;
|
|
13761
15414
|
}
|
|
13762
15415
|
}
|
|
@@ -13766,12 +15419,12 @@ function resolveObjectArg(node, sf) {
|
|
|
13766
15419
|
function resolveArrayFromProperty(obj, name, sf) {
|
|
13767
15420
|
const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
|
|
13768
15421
|
if (!init) return void 0;
|
|
13769
|
-
if (
|
|
13770
|
-
if (
|
|
15422
|
+
if (Node10.isArrayLiteralExpression(init)) return init;
|
|
15423
|
+
if (Node10.isIdentifier(init)) {
|
|
13771
15424
|
const declNode = findLocalVariable(sf, init.getText());
|
|
13772
15425
|
if (declNode) {
|
|
13773
15426
|
const declInit = unwrapAsExpressions(declNode.getInitializer());
|
|
13774
|
-
if (declInit &&
|
|
15427
|
+
if (declInit && Node10.isArrayLiteralExpression(declInit)) {
|
|
13775
15428
|
return declInit;
|
|
13776
15429
|
}
|
|
13777
15430
|
}
|
|
@@ -13782,11 +15435,11 @@ function enclosingFactoryName(node) {
|
|
|
13782
15435
|
let current = node.getParent();
|
|
13783
15436
|
let result;
|
|
13784
15437
|
while (current) {
|
|
13785
|
-
if (
|
|
15438
|
+
if (Node10.isFunctionDeclaration(current)) {
|
|
13786
15439
|
result = current.getName() ?? void 0;
|
|
13787
15440
|
break;
|
|
13788
15441
|
}
|
|
13789
|
-
if (
|
|
15442
|
+
if (Node10.isVariableDeclaration(current)) {
|
|
13790
15443
|
result = current.getName();
|
|
13791
15444
|
break;
|
|
13792
15445
|
}
|
|
@@ -13798,7 +15451,7 @@ function extractUploadServiceWirings(sources) {
|
|
|
13798
15451
|
const out = [];
|
|
13799
15452
|
for (const sf of sources) {
|
|
13800
15453
|
const rel = apiRelPath(sf);
|
|
13801
|
-
for (const obj of sf.getDescendantsOfKind(
|
|
15454
|
+
for (const obj of sf.getDescendantsOfKind(SyntaxKind7.ObjectLiteralExpression)) {
|
|
13802
15455
|
const provideIdent = readIdentifierProperty(obj, "provide");
|
|
13803
15456
|
if (provideIdent !== UPLOAD_SERVICE_PROVIDE_TOKEN) continue;
|
|
13804
15457
|
const useFactory = readIdentifierProperty(obj, "useFactory");
|
|
@@ -13811,7 +15464,7 @@ function extractProcessingConfigs(sources) {
|
|
|
13811
15464
|
const out = [];
|
|
13812
15465
|
for (const sf of sources) {
|
|
13813
15466
|
const rel = apiRelPath(sf);
|
|
13814
|
-
for (const decl of sf.getDescendantsOfKind(
|
|
15467
|
+
for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
|
|
13815
15468
|
const config = extractProcessingConfigFromDecl(decl, rel);
|
|
13816
15469
|
if (config) {
|
|
13817
15470
|
out.push(config);
|
|
@@ -13840,10 +15493,10 @@ function extractProcessingConfigFromDecl(decl, rel) {
|
|
|
13840
15493
|
function readFlowSubtasks(obj) {
|
|
13841
15494
|
const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
|
|
13842
15495
|
const subtasks = [];
|
|
13843
|
-
if (flowInit &&
|
|
15496
|
+
if (flowInit && Node10.isArrayLiteralExpression(flowInit)) {
|
|
13844
15497
|
for (const el of flowInit.getElements()) {
|
|
13845
15498
|
const inner = unwrapAsExpressions(el);
|
|
13846
|
-
if (inner &&
|
|
15499
|
+
if (inner && Node10.isObjectLiteralExpression(inner)) {
|
|
13847
15500
|
const subtask = readIdentifierProperty(inner, "subtask");
|
|
13848
15501
|
if (subtask) subtasks.push(subtask);
|
|
13849
15502
|
}
|
|
@@ -13855,9 +15508,9 @@ function extractProcessingHandlerCalls(sources) {
|
|
|
13855
15508
|
const out = [];
|
|
13856
15509
|
for (const sf of sources) {
|
|
13857
15510
|
const rel = apiRelPath(sf);
|
|
13858
|
-
for (const call of sf.getDescendantsOfKind(
|
|
15511
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
|
|
13859
15512
|
const expr = call.getExpression();
|
|
13860
|
-
if (!
|
|
15513
|
+
if (!Node10.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
|
|
13861
15514
|
const args = call.getArguments();
|
|
13862
15515
|
const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
|
|
13863
15516
|
if (!first) continue;
|
|
@@ -13878,7 +15531,7 @@ function extractProcessingHandlerCalls(sources) {
|
|
|
13878
15531
|
}
|
|
13879
15532
|
function collectProcessorArrayElements(processorsArr, direct, spreads) {
|
|
13880
15533
|
for (const el of processorsArr.getElements()) {
|
|
13881
|
-
if (
|
|
15534
|
+
if (Node10.isSpreadElement(el)) {
|
|
13882
15535
|
addProcessorIdentifierName(el.getExpression(), spreads);
|
|
13883
15536
|
continue;
|
|
13884
15537
|
}
|
|
@@ -13890,13 +15543,13 @@ function collectProcessorArrayElements(processorsArr, direct, spreads) {
|
|
|
13890
15543
|
}
|
|
13891
15544
|
function addProcessorIdentifierName(node, bucket) {
|
|
13892
15545
|
if (!node) return;
|
|
13893
|
-
if (
|
|
15546
|
+
if (Node10.isIdentifier(node)) {
|
|
13894
15547
|
bucket.push(node.getText());
|
|
13895
15548
|
return;
|
|
13896
15549
|
}
|
|
13897
|
-
if (
|
|
15550
|
+
if (Node10.isCallExpression(node)) {
|
|
13898
15551
|
const callee = node.getExpression();
|
|
13899
|
-
if (
|
|
15552
|
+
if (Node10.isIdentifier(callee)) {
|
|
13900
15553
|
bucket.push(callee.getText());
|
|
13901
15554
|
}
|
|
13902
15555
|
}
|
|
@@ -13938,7 +15591,7 @@ function runRules4(inspection, extracted) {
|
|
|
13938
15591
|
violations,
|
|
13939
15592
|
codes: IO_VIOLATION_CODES,
|
|
13940
15593
|
messages: IO_VIOLATION_MESSAGES,
|
|
13941
|
-
build: (
|
|
15594
|
+
build: (code11, message, side) => buildIoViolation(code11, message, side)
|
|
13942
15595
|
});
|
|
13943
15596
|
if (!proceed) {
|
|
13944
15597
|
return violations;
|
|
@@ -14170,18 +15823,18 @@ function checkDuplicates(extracted, violations) {
|
|
|
14170
15823
|
flagDuplicates({ entries: extracted.fileTypeIdentifierConstants.map(toCodeRef), code: "STORAGEFILE_FILE_TYPE_IDENTIFIER_DUPLICATE", label: "`UploadedFileTypeIdentifier`", violations });
|
|
14171
15824
|
}
|
|
14172
15825
|
function toCodeRef(entry) {
|
|
14173
|
-
const
|
|
14174
|
-
return { symbolName: entry.symbolName, code:
|
|
15826
|
+
const code11 = "purposeCode" in entry ? entry.purposeCode : entry.typeCode;
|
|
15827
|
+
return { symbolName: entry.symbolName, code: code11, sourceFile: entry.sourceFile };
|
|
14175
15828
|
}
|
|
14176
15829
|
function flagDuplicates(options) {
|
|
14177
|
-
const { entries, code:
|
|
15830
|
+
const { entries, code: code11, label, violations } = options;
|
|
14178
15831
|
const seen = /* @__PURE__ */ new Map();
|
|
14179
15832
|
for (const entry of entries) {
|
|
14180
15833
|
if (!entry.code) continue;
|
|
14181
15834
|
const previous = seen.get(entry.code);
|
|
14182
15835
|
if (previous) {
|
|
14183
15836
|
pushViolation4(violations, {
|
|
14184
|
-
code:
|
|
15837
|
+
code: code11,
|
|
14185
15838
|
severity: "warning",
|
|
14186
15839
|
message: `${label} value \`'${entry.code}'\` is shared by \`${previous}\` and \`${entry.symbolName}\`. Choose unique string literals.`,
|
|
14187
15840
|
side: "component",
|
|
@@ -14231,9 +15884,9 @@ function pushViolation4(buffer, violation) {
|
|
|
14231
15884
|
};
|
|
14232
15885
|
buffer.push(filled);
|
|
14233
15886
|
}
|
|
14234
|
-
function buildIoViolation(
|
|
15887
|
+
function buildIoViolation(code11, message, side) {
|
|
14235
15888
|
const result = {
|
|
14236
|
-
code:
|
|
15889
|
+
code: code11,
|
|
14237
15890
|
severity: "error",
|
|
14238
15891
|
message,
|
|
14239
15892
|
side,
|
|
@@ -14249,8 +15902,8 @@ function formatResult4(result) {
|
|
|
14249
15902
|
}
|
|
14250
15903
|
|
|
14251
15904
|
// packages/dbx-components-mcp/src/tools/_validate/inspect.ts
|
|
14252
|
-
import { readdir as readdir2, readFile as
|
|
14253
|
-
import { join, relative as relative4, sep as sep2 } from "node:path";
|
|
15905
|
+
import { readdir as readdir2, readFile as readFile4, stat as stat3 } from "node:fs/promises";
|
|
15906
|
+
import { join as join4, relative as relative4, sep as sep2 } from "node:path";
|
|
14254
15907
|
async function inspectSide(rootDir, subpaths) {
|
|
14255
15908
|
const rootStatus = await readRootStatus(rootDir);
|
|
14256
15909
|
if (rootStatus !== void 0) {
|
|
@@ -14260,7 +15913,7 @@ async function inspectSide(rootDir, subpaths) {
|
|
|
14260
15913
|
const presentFolders = [];
|
|
14261
15914
|
const collectedFiles = [];
|
|
14262
15915
|
for (const sub of subpaths) {
|
|
14263
|
-
const absFolder =
|
|
15916
|
+
const absFolder = join4(rootDir, sub);
|
|
14264
15917
|
const folderPresent = await isDirectory(absFolder);
|
|
14265
15918
|
if (!folderPresent) continue;
|
|
14266
15919
|
presentFolders.push(sub);
|
|
@@ -14279,8 +15932,8 @@ async function readRootStatus(rootDir) {
|
|
|
14279
15932
|
const stats = await stat3(rootDir);
|
|
14280
15933
|
return stats.isDirectory() ? void 0 : "dir-not-found";
|
|
14281
15934
|
} catch (err) {
|
|
14282
|
-
const
|
|
14283
|
-
if (
|
|
15935
|
+
const code11 = err.code;
|
|
15936
|
+
if (code11 === "ENOENT" || code11 === "ENOTDIR") {
|
|
14284
15937
|
return "dir-not-found";
|
|
14285
15938
|
}
|
|
14286
15939
|
throw err;
|
|
@@ -14306,7 +15959,7 @@ async function collectTsFiles(absFolder, rootDir) {
|
|
|
14306
15959
|
continue;
|
|
14307
15960
|
}
|
|
14308
15961
|
for (const entry of entries) {
|
|
14309
|
-
const full =
|
|
15962
|
+
const full = join4(current, entry.name);
|
|
14310
15963
|
if (entry.isDirectory()) {
|
|
14311
15964
|
stack.push(full);
|
|
14312
15965
|
continue;
|
|
@@ -14315,7 +15968,7 @@ async function collectTsFiles(absFolder, rootDir) {
|
|
|
14315
15968
|
if (!entry.name.endsWith(".ts")) continue;
|
|
14316
15969
|
if (entry.name.endsWith(".spec.ts")) continue;
|
|
14317
15970
|
if (entry.name.endsWith(".d.ts")) continue;
|
|
14318
|
-
const text = await
|
|
15971
|
+
const text = await readFile4(full, "utf8");
|
|
14319
15972
|
const rel = relative4(rootDir, full).split(sep2).join("/");
|
|
14320
15973
|
out.push({ relPath: rel, text });
|
|
14321
15974
|
}
|
|
@@ -14487,7 +16140,7 @@ function formatReportAsJson(report) {
|
|
|
14487
16140
|
// packages/dbx-components-mcp/src/tools/storagefile-m-list-app/format.markdown.ts
|
|
14488
16141
|
function formatReportAsMarkdown(report) {
|
|
14489
16142
|
const basename4 = report.componentDir.split("/").pop() ?? report.componentDir;
|
|
14490
|
-
const uploadServiceFactoryText = report.uploadServiceFactoryName ?
|
|
16143
|
+
const uploadServiceFactoryText = report.uploadServiceFactoryName ? code4(report.uploadServiceFactoryName) : "_Not defined._";
|
|
14491
16144
|
const lines = [`# App storagefiles \u2014 ${basename4}`, "", `Component: \`${report.componentDir}\``, `API: \`${report.apiDir}\``, "", `Upload service factory: ${uploadServiceFactoryText}`, `Wired via \`StorageFileInitializeFromUploadService\` provider: ${formatBool(report.uploadServiceWiredInApi)}`, `Processing handler call present: ${formatBool(report.processingHandlerWiredInApi)}`, "", `## Purposes (${report.purposes.length})`];
|
|
14492
16145
|
if (report.purposes.length === 0) {
|
|
14493
16146
|
lines.push("", "_None found._");
|
|
@@ -14503,15 +16156,15 @@ function formatPurposeBlock(p) {
|
|
|
14503
16156
|
const heading = p.purposeCode ? `### ${p.purposeCode} \u2014 \`${p.purposeSymbolName}\`` : `### \`${p.purposeSymbolName}\``;
|
|
14504
16157
|
parts.push(heading);
|
|
14505
16158
|
if (p.fileTypeIdentifierCode) {
|
|
14506
|
-
const codePart = p.fileTypeIdentifier ? ` (` +
|
|
16159
|
+
const codePart = p.fileTypeIdentifier ? ` (` + code4(`'${p.fileTypeIdentifier}'`) + `)` : "";
|
|
14507
16160
|
parts.push(`- Uploaded file type identifier: \`${p.fileTypeIdentifierCode}\`${codePart}`);
|
|
14508
16161
|
} else {
|
|
14509
16162
|
parts.push(`- Uploaded file type identifier: _Missing._`);
|
|
14510
16163
|
}
|
|
14511
|
-
const groupIdsText = p.fileGroupIdsFunctionName ?
|
|
16164
|
+
const groupIdsText = p.fileGroupIdsFunctionName ? code4(p.fileGroupIdsFunctionName) : "_Missing._";
|
|
14512
16165
|
parts.push(`- Group-ids helper: ${groupIdsText}`);
|
|
14513
16166
|
if (p.subtasks.length > 0) {
|
|
14514
|
-
const subtasksText = p.subtasks.map((s) =>
|
|
16167
|
+
const subtasksText = p.subtasks.map((s) => code4(s)).join(", ");
|
|
14515
16168
|
parts.push(`- Processing subtasks: ${subtasksText}`);
|
|
14516
16169
|
}
|
|
14517
16170
|
const uploadInitSuffix = p.uploadInitializerSourceFile ? ` _(${p.uploadInitializerSourceFile})_` : "";
|
|
@@ -14522,7 +16175,7 @@ function formatPurposeBlock(p) {
|
|
|
14522
16175
|
function formatBool(value) {
|
|
14523
16176
|
return value ? "yes" : "no";
|
|
14524
16177
|
}
|
|
14525
|
-
function
|
|
16178
|
+
function code4(value) {
|
|
14526
16179
|
return "`" + value + "`";
|
|
14527
16180
|
}
|
|
14528
16181
|
|
|
@@ -14568,8 +16221,8 @@ var storageFileMListAppTool = createListAppTool({
|
|
|
14568
16221
|
});
|
|
14569
16222
|
|
|
14570
16223
|
// packages/dbx-components-mcp/src/tools/validate-two-side-folder.ts
|
|
14571
|
-
import { readdir as readdir3, readFile as
|
|
14572
|
-
import { join as
|
|
16224
|
+
import { readdir as readdir3, readFile as readFile5, stat as stat4 } from "node:fs/promises";
|
|
16225
|
+
import { join as join5 } from "node:path";
|
|
14573
16226
|
var REEXPORT_PATTERN = /^\s*export\s+\*\s+from\s+['"]\.\/([^'"\n]+)['"]\s*;?\s*$/gm;
|
|
14574
16227
|
function createTwoSideFolderValidator(config) {
|
|
14575
16228
|
async function inspect(input) {
|
|
@@ -14613,7 +16266,7 @@ async function inspectSide2(input) {
|
|
|
14613
16266
|
let indexSource;
|
|
14614
16267
|
const rootStatOk = await isExistingDirectory(rootDir);
|
|
14615
16268
|
if (rootStatOk) {
|
|
14616
|
-
const absFolder =
|
|
16269
|
+
const absFolder = join5(rootDir, subPath);
|
|
14617
16270
|
const folderStatOk = await isExistingDirectory(absFolder);
|
|
14618
16271
|
if (folderStatOk) {
|
|
14619
16272
|
const folder = await readFolder(absFolder, indexFile);
|
|
@@ -14642,8 +16295,8 @@ async function isExistingDirectory(path) {
|
|
|
14642
16295
|
const stats = await stat4(path);
|
|
14643
16296
|
return stats.isDirectory();
|
|
14644
16297
|
} catch (err) {
|
|
14645
|
-
const
|
|
14646
|
-
if (
|
|
16298
|
+
const code11 = err.code;
|
|
16299
|
+
if (code11 !== "ENOENT" && code11 !== "ENOTDIR") {
|
|
14647
16300
|
throw err;
|
|
14648
16301
|
}
|
|
14649
16302
|
return false;
|
|
@@ -14665,7 +16318,7 @@ async function readFolder(absFolder, indexFile) {
|
|
|
14665
16318
|
let indexSource;
|
|
14666
16319
|
if (collectedFiles.includes(indexFile)) {
|
|
14667
16320
|
try {
|
|
14668
|
-
indexSource = await
|
|
16321
|
+
indexSource = await readFile5(join5(absFolder, indexFile), "utf8");
|
|
14669
16322
|
} catch {
|
|
14670
16323
|
indexSource = void 0;
|
|
14671
16324
|
}
|
|
@@ -14884,7 +16537,7 @@ var storageFileMValidateFolderTool = createTwoSideValidateTool({
|
|
|
14884
16537
|
});
|
|
14885
16538
|
|
|
14886
16539
|
// packages/dbx-components-mcp/src/tools/notification-m-validate-app/extract.ts
|
|
14887
|
-
import { Node as
|
|
16540
|
+
import { Node as Node11, SyntaxKind as SyntaxKind8 } from "ts-morph";
|
|
14888
16541
|
var NOTIF_TEMPLATE_TYPE = "NotificationTemplateType";
|
|
14889
16542
|
var NOTIF_TEMPLATE_TYPE_INFO = "NotificationTemplateTypeInfo";
|
|
14890
16543
|
var NOTIF_TEMPLATE_TYPE_INFO_ARRAY = "NotificationTemplateTypeInfo[]";
|
|
@@ -15005,7 +16658,7 @@ function extractTemplateInfoAggregates(sources) {
|
|
|
15005
16658
|
const ids = [];
|
|
15006
16659
|
for (const el of arr.getElements()) {
|
|
15007
16660
|
const inner = unwrapAsExpressions(el);
|
|
15008
|
-
if (inner &&
|
|
16661
|
+
if (inner && Node11.isIdentifier(inner)) {
|
|
15009
16662
|
ids.push(inner.getText());
|
|
15010
16663
|
}
|
|
15011
16664
|
}
|
|
@@ -15051,7 +16704,7 @@ function extractTaskAllTypesAggregates(sources) {
|
|
|
15051
16704
|
const ids = [];
|
|
15052
16705
|
for (const el of arr.getElements()) {
|
|
15053
16706
|
const inner = unwrapAsExpressions(el);
|
|
15054
|
-
if (inner &&
|
|
16707
|
+
if (inner && Node11.isIdentifier(inner)) {
|
|
15055
16708
|
ids.push(inner.getText());
|
|
15056
16709
|
}
|
|
15057
16710
|
}
|
|
@@ -15079,14 +16732,14 @@ function extractTaskCheckpointAliases(sources) {
|
|
|
15079
16732
|
return out;
|
|
15080
16733
|
}
|
|
15081
16734
|
function collectStringLiterals(node, out) {
|
|
15082
|
-
if (
|
|
16735
|
+
if (Node11.isLiteralTypeNode(node)) {
|
|
15083
16736
|
const lit = node.getLiteral();
|
|
15084
|
-
if (
|
|
16737
|
+
if (Node11.isStringLiteral(lit)) {
|
|
15085
16738
|
out.push(lit.getLiteralText());
|
|
15086
16739
|
}
|
|
15087
16740
|
return;
|
|
15088
16741
|
}
|
|
15089
|
-
if (
|
|
16742
|
+
if (Node11.isUnionTypeNode(node)) {
|
|
15090
16743
|
for (const child of node.getTypeNodes()) {
|
|
15091
16744
|
collectStringLiterals(child, out);
|
|
15092
16745
|
}
|
|
@@ -15140,7 +16793,7 @@ function extractTemplateInfoRecord(sources, index) {
|
|
|
15140
16793
|
}
|
|
15141
16794
|
function tryReadTemplateInfoRecord(decl, rel, index) {
|
|
15142
16795
|
const initializer = unwrapAsExpressions(decl.getInitializer());
|
|
15143
|
-
if (!initializer || !
|
|
16796
|
+
if (!initializer || !Node11.isCallExpression(initializer)) return void 0;
|
|
15144
16797
|
if (initializer.getExpression().getText() !== TEMPLATE_INFO_RECORD_FACTORY) return void 0;
|
|
15145
16798
|
const args = initializer.getArguments();
|
|
15146
16799
|
const arr = args[0] ? asArrayLiteral(args[0]) : void 0;
|
|
@@ -15161,15 +16814,15 @@ function tryReadTemplateInfoRecord(decl, rel, index) {
|
|
|
15161
16814
|
}
|
|
15162
16815
|
function classifyInfoRecordArrayElements(arr, direct, spreads) {
|
|
15163
16816
|
for (const el of arr.getElements()) {
|
|
15164
|
-
if (
|
|
16817
|
+
if (Node11.isSpreadElement(el)) {
|
|
15165
16818
|
const inner2 = el.getExpression();
|
|
15166
|
-
if (
|
|
16819
|
+
if (Node11.isIdentifier(inner2)) {
|
|
15167
16820
|
spreads.push(inner2.getText());
|
|
15168
16821
|
}
|
|
15169
16822
|
continue;
|
|
15170
16823
|
}
|
|
15171
16824
|
const inner = unwrapAsExpressions(el);
|
|
15172
|
-
if (inner &&
|
|
16825
|
+
if (inner && Node11.isIdentifier(inner)) {
|
|
15173
16826
|
direct.push(inner.getText());
|
|
15174
16827
|
}
|
|
15175
16828
|
}
|
|
@@ -15190,13 +16843,13 @@ function resolveTemplateInfoSpreads(direct, spreads, index) {
|
|
|
15190
16843
|
function extractTemplateInfoRecordWiring(sources) {
|
|
15191
16844
|
for (const sf of sources) {
|
|
15192
16845
|
const rel = apiRelPath(sf);
|
|
15193
|
-
for (const call of sf.getDescendantsOfKind(
|
|
16846
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
|
|
15194
16847
|
if (call.getExpression().getText() !== TEMPLATE_INFO_RECORD_SERVICE) continue;
|
|
15195
16848
|
const args = call.getArguments();
|
|
15196
16849
|
const first = args[0];
|
|
15197
16850
|
if (!first) continue;
|
|
15198
16851
|
const inner = unwrapAsExpressions(first);
|
|
15199
|
-
if (!inner || !
|
|
16852
|
+
if (!inner || !Node11.isIdentifier(inner)) continue;
|
|
15200
16853
|
const result = {
|
|
15201
16854
|
recordIdentifier: inner.getText(),
|
|
15202
16855
|
sourceFile: rel
|
|
@@ -15209,7 +16862,7 @@ function extractTemplateInfoRecordWiring(sources) {
|
|
|
15209
16862
|
function extractTemplateConfigsArrayWiring(sources) {
|
|
15210
16863
|
for (const sf of sources) {
|
|
15211
16864
|
const rel = apiRelPath(sf);
|
|
15212
|
-
for (const obj of sf.getDescendantsOfKind(
|
|
16865
|
+
for (const obj of sf.getDescendantsOfKind(SyntaxKind8.ObjectLiteralExpression)) {
|
|
15213
16866
|
const provideIdent = readIdentifierProperty(obj, "provide");
|
|
15214
16867
|
if (provideIdent !== TEMPLATE_CONFIGS_ARRAY_TOKEN) continue;
|
|
15215
16868
|
const useFactoryIdent = readIdentifierProperty(obj, "useFactory");
|
|
@@ -15234,7 +16887,7 @@ function buildApiFunctionIndex2(sources) {
|
|
|
15234
16887
|
for (const decl of stmt.getDeclarations()) {
|
|
15235
16888
|
const initializer = unwrapAsExpressions(decl.getInitializer());
|
|
15236
16889
|
if (!initializer) continue;
|
|
15237
|
-
if (
|
|
16890
|
+
if (Node11.isArrowFunction(initializer) || Node11.isFunctionExpression(initializer)) {
|
|
15238
16891
|
map.set(decl.getName(), { node: initializer, sourceFile: sf, relPath: rel });
|
|
15239
16892
|
}
|
|
15240
16893
|
}
|
|
@@ -15270,11 +16923,11 @@ function extractTemplateConfigsArrayFactory(sources, index) {
|
|
|
15270
16923
|
const arr = returnExpr ? asArrayLiteral(returnExpr) : void 0;
|
|
15271
16924
|
if (arr) {
|
|
15272
16925
|
for (const el of arr.getElements()) {
|
|
15273
|
-
if (
|
|
16926
|
+
if (Node11.isSpreadElement(el)) {
|
|
15274
16927
|
const inner2 = el.getExpression();
|
|
15275
|
-
if (
|
|
16928
|
+
if (Node11.isCallExpression(inner2)) {
|
|
15276
16929
|
const callee = inner2.getExpression();
|
|
15277
|
-
if (
|
|
16930
|
+
if (Node11.isIdentifier(callee)) {
|
|
15278
16931
|
const callName = callee.getText();
|
|
15279
16932
|
spreadCalls.push(callName);
|
|
15280
16933
|
if (!index.functionsByName.has(callName)) {
|
|
@@ -15285,9 +16938,9 @@ function extractTemplateConfigsArrayFactory(sources, index) {
|
|
|
15285
16938
|
continue;
|
|
15286
16939
|
}
|
|
15287
16940
|
const inner = unwrapAsExpressions(el);
|
|
15288
|
-
if (inner &&
|
|
16941
|
+
if (inner && Node11.isCallExpression(inner)) {
|
|
15289
16942
|
const callee = inner.getExpression();
|
|
15290
|
-
if (
|
|
16943
|
+
if (Node11.isIdentifier(callee)) {
|
|
15291
16944
|
directCalls.push(callee.getText());
|
|
15292
16945
|
}
|
|
15293
16946
|
}
|
|
@@ -15336,11 +16989,11 @@ function collectFromArrayEntryFactory(name, out, index) {
|
|
|
15336
16989
|
const arr = asArrayLiteral(returnExpr);
|
|
15337
16990
|
if (!arr) return;
|
|
15338
16991
|
for (const el of arr.getElements()) {
|
|
15339
|
-
if (
|
|
16992
|
+
if (Node11.isSpreadElement(el)) {
|
|
15340
16993
|
const inner2 = el.getExpression();
|
|
15341
|
-
if (
|
|
16994
|
+
if (Node11.isCallExpression(inner2)) {
|
|
15342
16995
|
const callee = inner2.getExpression();
|
|
15343
|
-
if (
|
|
16996
|
+
if (Node11.isIdentifier(callee)) {
|
|
15344
16997
|
collectFromArrayEntryFactory(callee.getText(), out, index);
|
|
15345
16998
|
}
|
|
15346
16999
|
}
|
|
@@ -15348,9 +17001,9 @@ function collectFromArrayEntryFactory(name, out, index) {
|
|
|
15348
17001
|
}
|
|
15349
17002
|
const inner = unwrapAsExpressions(el);
|
|
15350
17003
|
if (!inner) continue;
|
|
15351
|
-
if (
|
|
17004
|
+
if (Node11.isCallExpression(inner)) {
|
|
15352
17005
|
const callee = inner.getExpression();
|
|
15353
|
-
if (
|
|
17006
|
+
if (Node11.isIdentifier(callee)) {
|
|
15354
17007
|
collectFromSingleEntryFactory(callee.getText(), out, index);
|
|
15355
17008
|
}
|
|
15356
17009
|
continue;
|
|
@@ -15368,9 +17021,9 @@ function extractTaskServiceCalls(sources, index, trustedExternal) {
|
|
|
15368
17021
|
const out = [];
|
|
15369
17022
|
for (const sf of sources) {
|
|
15370
17023
|
const rel = apiRelPath(sf);
|
|
15371
|
-
for (const call of sf.getDescendantsOfKind(
|
|
17024
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
|
|
15372
17025
|
const expr = call.getExpression();
|
|
15373
|
-
if (!
|
|
17026
|
+
if (!Node11.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
|
|
15374
17027
|
const args = call.getArguments();
|
|
15375
17028
|
const first = args[0] ? asObjectLiteral(args[0]) : void 0;
|
|
15376
17029
|
if (!first) continue;
|
|
@@ -15396,13 +17049,13 @@ function collectValidateArrayElements(validateArr) {
|
|
|
15396
17049
|
const spreads = [];
|
|
15397
17050
|
if (!validateArr) return { ids, spreads };
|
|
15398
17051
|
for (const el of validateArr.getElements()) {
|
|
15399
|
-
if (
|
|
17052
|
+
if (Node11.isSpreadElement(el)) {
|
|
15400
17053
|
const inner2 = el.getExpression();
|
|
15401
|
-
if (
|
|
17054
|
+
if (Node11.isIdentifier(inner2)) spreads.push(inner2.getText());
|
|
15402
17055
|
continue;
|
|
15403
17056
|
}
|
|
15404
17057
|
const inner = unwrapAsExpressions(el);
|
|
15405
|
-
if (inner &&
|
|
17058
|
+
if (inner && Node11.isIdentifier(inner)) ids.push(inner.getText());
|
|
15406
17059
|
}
|
|
15407
17060
|
return { ids, spreads };
|
|
15408
17061
|
}
|
|
@@ -15415,17 +17068,17 @@ function collectHandlersArrayElements(options) {
|
|
|
15415
17068
|
if (!handlersArr) return { handlerTypes, unresolvedSpreads, resolvedBindings, unresolvedBindings };
|
|
15416
17069
|
const visited = /* @__PURE__ */ new Set();
|
|
15417
17070
|
for (const el of handlersArr.getElements()) {
|
|
15418
|
-
if (
|
|
17071
|
+
if (Node11.isSpreadElement(el)) {
|
|
15419
17072
|
consumeHandlersSpreadElement({ inner: el.getExpression(), sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited });
|
|
15420
17073
|
continue;
|
|
15421
17074
|
}
|
|
15422
17075
|
const inner = unwrapAsExpressions(el);
|
|
15423
17076
|
if (!inner) continue;
|
|
15424
|
-
if (
|
|
17077
|
+
if (Node11.isIdentifier(inner)) {
|
|
15425
17078
|
collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
|
|
15426
|
-
} else if (
|
|
17079
|
+
} else if (Node11.isCallExpression(inner)) {
|
|
15427
17080
|
const callee = inner.getExpression();
|
|
15428
|
-
if (
|
|
17081
|
+
if (Node11.isIdentifier(callee)) {
|
|
15429
17082
|
collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
|
|
15430
17083
|
}
|
|
15431
17084
|
}
|
|
@@ -15434,16 +17087,16 @@ function collectHandlersArrayElements(options) {
|
|
|
15434
17087
|
}
|
|
15435
17088
|
function consumeHandlersSpreadElement(options) {
|
|
15436
17089
|
const { inner, sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited } = options;
|
|
15437
|
-
if (
|
|
17090
|
+
if (Node11.isCallExpression(inner)) {
|
|
15438
17091
|
const callee = inner.getExpression();
|
|
15439
|
-
if (
|
|
17092
|
+
if (Node11.isIdentifier(callee)) {
|
|
15440
17093
|
const name = callee.getText();
|
|
15441
17094
|
unresolvedSpreads.push(name);
|
|
15442
17095
|
collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
|
|
15443
17096
|
}
|
|
15444
17097
|
return;
|
|
15445
17098
|
}
|
|
15446
|
-
if (
|
|
17099
|
+
if (Node11.isIdentifier(inner)) {
|
|
15447
17100
|
const name = inner.getText();
|
|
15448
17101
|
unresolvedSpreads.push(name);
|
|
15449
17102
|
collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
|
|
@@ -15453,13 +17106,13 @@ function collectHandlerBindingsFromValue(options) {
|
|
|
15453
17106
|
const { node, sf, index, trustedExternal, resolved, unresolved, visited } = options;
|
|
15454
17107
|
const inner = unwrapAsExpressions(node);
|
|
15455
17108
|
if (!inner) return false;
|
|
15456
|
-
if (
|
|
17109
|
+
if (Node11.isCallExpression(inner)) {
|
|
15457
17110
|
const callee = inner.getExpression();
|
|
15458
|
-
if (
|
|
17111
|
+
if (Node11.isIdentifier(callee)) {
|
|
15459
17112
|
return collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
|
|
15460
17113
|
}
|
|
15461
17114
|
}
|
|
15462
|
-
if (
|
|
17115
|
+
if (Node11.isIdentifier(inner)) {
|
|
15463
17116
|
return collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
|
|
15464
17117
|
}
|
|
15465
17118
|
return false;
|
|
@@ -15476,7 +17129,7 @@ function collectHandlerBindingsFromIdentifier(options) {
|
|
|
15476
17129
|
const typeText = typeNode ? typeNode.getText() : void 0;
|
|
15477
17130
|
const isHandlerConfigTyped = typeText !== void 0 && (typeText === NOTIF_TASK_SERVICE_HANDLER_CONFIG || typeText.startsWith(`${NOTIF_TASK_SERVICE_HANDLER_CONFIG}<`));
|
|
15478
17131
|
const declInit = unwrapAsExpressions(localDecl.getInitializer());
|
|
15479
|
-
const isObjectLit = declInit !== void 0 &&
|
|
17132
|
+
const isObjectLit = declInit !== void 0 && Node11.isObjectLiteralExpression(declInit);
|
|
15480
17133
|
if (isHandlerConfigTyped && isObjectLit) {
|
|
15481
17134
|
resolved.push(localDecl.getName());
|
|
15482
17135
|
resolvedAny = true;
|
|
@@ -15507,12 +17160,12 @@ function collectHandlerBindingsFromIdentifier(options) {
|
|
|
15507
17160
|
function resolveArrayFromProperty2(obj, name, sf) {
|
|
15508
17161
|
const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
|
|
15509
17162
|
if (!init) return void 0;
|
|
15510
|
-
if (
|
|
15511
|
-
if (
|
|
17163
|
+
if (Node11.isArrayLiteralExpression(init)) return init;
|
|
17164
|
+
if (Node11.isIdentifier(init)) {
|
|
15512
17165
|
const declNode = findLocalVariable(sf, init.getText());
|
|
15513
17166
|
if (declNode) {
|
|
15514
17167
|
const declInit = unwrapAsExpressions(declNode.getInitializer());
|
|
15515
|
-
if (declInit &&
|
|
17168
|
+
if (declInit && Node11.isArrayLiteralExpression(declInit)) {
|
|
15516
17169
|
return declInit;
|
|
15517
17170
|
}
|
|
15518
17171
|
}
|
|
@@ -15533,12 +17186,12 @@ function extractTaskHandlerEntries(sources) {
|
|
|
15533
17186
|
if (!typeIdent) return;
|
|
15534
17187
|
const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
|
|
15535
17188
|
let flowCount;
|
|
15536
|
-
if (flowInit &&
|
|
17189
|
+
if (flowInit && Node11.isArrayLiteralExpression(flowInit)) {
|
|
15537
17190
|
flowCount = flowInit.getElements().length;
|
|
15538
17191
|
}
|
|
15539
17192
|
let dataArg;
|
|
15540
17193
|
let checkpointArg;
|
|
15541
|
-
if (
|
|
17194
|
+
if (Node11.isTypeReference(typeNode)) {
|
|
15542
17195
|
const tArgs = typeNode.getTypeArguments();
|
|
15543
17196
|
if (tArgs.length >= 1) dataArg = tArgs[0].getText();
|
|
15544
17197
|
if (tArgs.length >= 2) checkpointArg = tArgs[1].getText();
|
|
@@ -15558,7 +17211,7 @@ function extractTaskHandlerEntries(sources) {
|
|
|
15558
17211
|
};
|
|
15559
17212
|
for (const sf of sources) {
|
|
15560
17213
|
const rel = apiRelPath(sf);
|
|
15561
|
-
for (const decl of sf.getDescendantsOfKind(
|
|
17214
|
+
for (const decl of sf.getDescendantsOfKind(SyntaxKind8.VariableDeclaration)) {
|
|
15562
17215
|
collectFromVariable(decl, rel);
|
|
15563
17216
|
}
|
|
15564
17217
|
}
|
|
@@ -15583,7 +17236,7 @@ function runRules6(inspection, extracted) {
|
|
|
15583
17236
|
violations,
|
|
15584
17237
|
codes: IO_VIOLATION_CODES2,
|
|
15585
17238
|
messages: IO_VIOLATION_MESSAGES2,
|
|
15586
|
-
build: (
|
|
17239
|
+
build: (code11, message, side) => buildIoViolation2(code11, message, side)
|
|
15587
17240
|
});
|
|
15588
17241
|
if (!proceed) {
|
|
15589
17242
|
return violations;
|
|
@@ -15936,14 +17589,14 @@ function flagUnusedInfoAggregates(extracted, violations) {
|
|
|
15936
17589
|
}
|
|
15937
17590
|
}
|
|
15938
17591
|
}
|
|
15939
|
-
function flagDuplicates2(entries,
|
|
17592
|
+
function flagDuplicates2(entries, code11, violations) {
|
|
15940
17593
|
const seen = /* @__PURE__ */ new Map();
|
|
15941
17594
|
for (const entry of entries) {
|
|
15942
17595
|
if (!entry.typeCode) continue;
|
|
15943
17596
|
const previous = seen.get(entry.typeCode);
|
|
15944
17597
|
if (previous) {
|
|
15945
17598
|
pushViolation6(violations, {
|
|
15946
|
-
code:
|
|
17599
|
+
code: code11,
|
|
15947
17600
|
severity: "warning",
|
|
15948
17601
|
message: `Type code \`'${entry.typeCode}'\` is shared by \`${previous}\` and \`${entry.symbolName}\`. Runtime aggregators reject duplicates \u2014 change one of the string literals.`,
|
|
15949
17602
|
side: "component",
|
|
@@ -15977,9 +17630,9 @@ function pushViolation6(buffer, violation) {
|
|
|
15977
17630
|
};
|
|
15978
17631
|
buffer.push(filled);
|
|
15979
17632
|
}
|
|
15980
|
-
function buildIoViolation2(
|
|
17633
|
+
function buildIoViolation2(code11, message, side) {
|
|
15981
17634
|
const result = {
|
|
15982
|
-
code:
|
|
17635
|
+
code: code11,
|
|
15983
17636
|
severity: "error",
|
|
15984
17637
|
message,
|
|
15985
17638
|
side,
|
|
@@ -16179,8 +17832,8 @@ function formatReportAsJson2(report) {
|
|
|
16179
17832
|
// packages/dbx-components-mcp/src/tools/notification-m-list-app/format.markdown.ts
|
|
16180
17833
|
function formatReportAsMarkdown2(report) {
|
|
16181
17834
|
const basename4 = report.componentDir.split("/").pop() ?? report.componentDir;
|
|
16182
|
-
const aggregatorRecordText = report.aggregatorRecordName ?
|
|
16183
|
-
const templateConfigsFactoryText = report.templateConfigsArrayFactoryName ?
|
|
17835
|
+
const aggregatorRecordText = report.aggregatorRecordName ? code5(report.aggregatorRecordName) : "_Not defined._";
|
|
17836
|
+
const templateConfigsFactoryText = report.templateConfigsArrayFactoryName ? code5(report.templateConfigsArrayFactoryName) : "_Not defined._";
|
|
16184
17837
|
const lines = [
|
|
16185
17838
|
`# App notifications \u2014 ${basename4}`,
|
|
16186
17839
|
"",
|
|
@@ -16220,8 +17873,8 @@ function formatTemplateBlock(t) {
|
|
|
16220
17873
|
if (t.description) parts.push(`- Description: ${t.description}`);
|
|
16221
17874
|
if (t.notificationMIdentity) parts.push(`- Notification model: \`${t.notificationMIdentity}\``);
|
|
16222
17875
|
if (t.targetModelIdentity) parts.push(`- Target model: \`${t.targetModelIdentity}\``);
|
|
16223
|
-
const infoText = t.infoSymbolName ?
|
|
16224
|
-
const factorySuffix = t.factoryFunctionName ? ` (${
|
|
17876
|
+
const infoText = t.infoSymbolName ? code5(t.infoSymbolName) : "_Missing._";
|
|
17877
|
+
const factorySuffix = t.factoryFunctionName ? ` (${code5(t.factoryFunctionName)})` : "";
|
|
16225
17878
|
parts.push(`- Info object: ${infoText}`, `- In info record: ${formatBool2(t.inInfoRecord)}`, `- Has factory: ${formatBool2(t.hasFactory)}${factorySuffix}`, `- Source: \`${t.sourceFile}\``);
|
|
16226
17879
|
return parts.join("\n");
|
|
16227
17880
|
}
|
|
@@ -16231,7 +17884,7 @@ function formatTaskBlock(t) {
|
|
|
16231
17884
|
parts.push(heading);
|
|
16232
17885
|
if (t.dataInterfaceName) parts.push(`- Data interface: \`${t.dataInterfaceName}\``);
|
|
16233
17886
|
if (t.checkpoints.length > 0) {
|
|
16234
|
-
const checkpointsText = t.checkpoints.map((c) =>
|
|
17887
|
+
const checkpointsText = t.checkpoints.map((c) => code5(c)).join(", ");
|
|
16235
17888
|
parts.push(`- Checkpoints: ${checkpointsText}`);
|
|
16236
17889
|
}
|
|
16237
17890
|
let handlerSuffix = "";
|
|
@@ -16245,7 +17898,7 @@ function formatTaskBlock(t) {
|
|
|
16245
17898
|
function formatBool2(value) {
|
|
16246
17899
|
return value ? "yes" : "no";
|
|
16247
17900
|
}
|
|
16248
|
-
function
|
|
17901
|
+
function code5(value) {
|
|
16249
17902
|
return "`" + value + "`";
|
|
16250
17903
|
}
|
|
16251
17904
|
|
|
@@ -16387,8 +18040,8 @@ function formatResult8(result) {
|
|
|
16387
18040
|
}
|
|
16388
18041
|
|
|
16389
18042
|
// packages/dbx-components-mcp/src/tools/system-m-validate-folder/inspect.ts
|
|
16390
|
-
import { readdir as readdir4, readFile as
|
|
16391
|
-
import { basename as basename3, join as
|
|
18043
|
+
import { readdir as readdir4, readFile as readFile6, stat as stat5 } from "node:fs/promises";
|
|
18044
|
+
import { basename as basename3, join as join6 } from "node:path";
|
|
16392
18045
|
async function inspectFolder2(path) {
|
|
16393
18046
|
const name = basename3(path);
|
|
16394
18047
|
let status;
|
|
@@ -16408,7 +18061,7 @@ async function inspectFolder2(path) {
|
|
|
16408
18061
|
files = collected;
|
|
16409
18062
|
if (collected.includes("system.ts")) {
|
|
16410
18063
|
try {
|
|
16411
|
-
systemSource = await
|
|
18064
|
+
systemSource = await readFile6(join6(path, "system.ts"), "utf8");
|
|
16412
18065
|
} catch {
|
|
16413
18066
|
systemSource = void 0;
|
|
16414
18067
|
}
|
|
@@ -16417,8 +18070,8 @@ async function inspectFolder2(path) {
|
|
|
16417
18070
|
status = "not-directory";
|
|
16418
18071
|
}
|
|
16419
18072
|
} catch (err) {
|
|
16420
|
-
const
|
|
16421
|
-
if (
|
|
18073
|
+
const code11 = err.code;
|
|
18074
|
+
if (code11 === "ENOENT" || code11 === "ENOTDIR") {
|
|
16422
18075
|
status = "not-found";
|
|
16423
18076
|
} else {
|
|
16424
18077
|
throw err;
|
|
@@ -16429,14 +18082,14 @@ async function inspectFolder2(path) {
|
|
|
16429
18082
|
}
|
|
16430
18083
|
|
|
16431
18084
|
// packages/dbx-components-mcp/src/tools/system-m-validate-folder/extract.ts
|
|
16432
|
-
import { Node as
|
|
18085
|
+
import { Node as Node12, Project as Project9 } from "ts-morph";
|
|
16433
18086
|
var TYPE_CONSTANT_SUFFIX = "_SYSTEM_STATE_TYPE";
|
|
16434
18087
|
var DATA_INTERFACE_SUFFIX = "SystemData";
|
|
16435
18088
|
var CONVERTER_CONFIG_TYPE = "SystemStateStoredDataFieldConverterConfig";
|
|
16436
18089
|
var CONVERTER_MAP_TYPE = "SystemStateStoredDataConverterMap";
|
|
16437
18090
|
var SYSTEM_STATE_STORED_DATA = "SystemStateStoredData";
|
|
16438
18091
|
function extractSystemFile(name, text) {
|
|
16439
|
-
const project = new
|
|
18092
|
+
const project = new Project9({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
16440
18093
|
const sourceFile = project.createSourceFile(name, text, { overwrite: true });
|
|
16441
18094
|
const typeConstants = findTypeConstants(sourceFile);
|
|
16442
18095
|
const dataInterfaces = findDataInterfaces2(sourceFile);
|
|
@@ -16493,7 +18146,7 @@ function findDataInterfaces2(sourceFile) {
|
|
|
16493
18146
|
return out;
|
|
16494
18147
|
}
|
|
16495
18148
|
function extendsSystemStateStoredData(iface) {
|
|
16496
|
-
if (!
|
|
18149
|
+
if (!Node12.isInterfaceDeclaration(iface)) return false;
|
|
16497
18150
|
for (const clause of iface.getExtends()) {
|
|
16498
18151
|
const text = clause.getText();
|
|
16499
18152
|
if (text === SYSTEM_STATE_STORED_DATA || text.startsWith(`${SYSTEM_STATE_STORED_DATA}<`) || text === `${SYSTEM_STATE_STORED_DATA}, ${SYSTEM_STATE_STORED_DATA}`) {
|
|
@@ -16513,14 +18166,14 @@ function findConverters(sourceFile) {
|
|
|
16513
18166
|
for (const decl of stmt.getDeclarations()) {
|
|
16514
18167
|
const typeNode = decl.getTypeNode();
|
|
16515
18168
|
if (!typeNode) continue;
|
|
16516
|
-
if (!
|
|
18169
|
+
if (!Node12.isTypeReference(typeNode)) continue;
|
|
16517
18170
|
const typeName = typeNode.getTypeName().getText();
|
|
16518
18171
|
if (typeName !== CONVERTER_CONFIG_TYPE) continue;
|
|
16519
18172
|
const typeArgs = typeNode.getTypeArguments();
|
|
16520
18173
|
let dataTypeArgument;
|
|
16521
18174
|
if (typeArgs.length >= 1) {
|
|
16522
18175
|
const arg = typeArgs[0];
|
|
16523
|
-
if (
|
|
18176
|
+
if (Node12.isTypeReference(arg)) {
|
|
16524
18177
|
dataTypeArgument = arg.getTypeName().getText();
|
|
16525
18178
|
} else {
|
|
16526
18179
|
dataTypeArgument = arg.getText();
|
|
@@ -16567,19 +18220,19 @@ function collectConverterMapKeys(decl) {
|
|
|
16567
18220
|
if (!obj) return [];
|
|
16568
18221
|
const out = [];
|
|
16569
18222
|
for (const prop of obj.getProperties()) {
|
|
16570
|
-
if (!
|
|
18223
|
+
if (!Node12.isPropertyAssignment(prop)) continue;
|
|
16571
18224
|
const nameNode = prop.getNameNode();
|
|
16572
18225
|
const line = prop.getStartLineNumber();
|
|
16573
|
-
if (
|
|
18226
|
+
if (Node12.isComputedPropertyName(nameNode)) {
|
|
16574
18227
|
const inner = nameNode.getExpression();
|
|
16575
18228
|
out.push({ raw: inner.getText(), kind: "identifier", line });
|
|
16576
18229
|
continue;
|
|
16577
18230
|
}
|
|
16578
|
-
if (
|
|
18231
|
+
if (Node12.isStringLiteral(nameNode)) {
|
|
16579
18232
|
out.push({ raw: nameNode.getLiteralText(), kind: "string", line });
|
|
16580
18233
|
continue;
|
|
16581
18234
|
}
|
|
16582
|
-
if (
|
|
18235
|
+
if (Node12.isIdentifier(nameNode)) {
|
|
16583
18236
|
out.push({ raw: nameNode.getText(), kind: "string", line });
|
|
16584
18237
|
continue;
|
|
16585
18238
|
}
|
|
@@ -16589,10 +18242,10 @@ function collectConverterMapKeys(decl) {
|
|
|
16589
18242
|
}
|
|
16590
18243
|
function unwrapObjectLiteral(node) {
|
|
16591
18244
|
let current = node;
|
|
16592
|
-
while (current &&
|
|
18245
|
+
while (current && Node12.isAsExpression(current)) {
|
|
16593
18246
|
current = current.getExpression();
|
|
16594
18247
|
}
|
|
16595
|
-
if (current &&
|
|
18248
|
+
if (current && Node12.isObjectLiteralExpression(current)) {
|
|
16596
18249
|
return current;
|
|
16597
18250
|
}
|
|
16598
18251
|
return void 0;
|
|
@@ -16626,10 +18279,10 @@ function findLastTopLevelExportLine(sourceFile) {
|
|
|
16626
18279
|
return last;
|
|
16627
18280
|
}
|
|
16628
18281
|
function isExportedTopLevel(stmt) {
|
|
16629
|
-
if (
|
|
18282
|
+
if (Node12.isVariableStatement(stmt) || Node12.isFunctionDeclaration(stmt) || Node12.isClassDeclaration(stmt) || Node12.isInterfaceDeclaration(stmt) || Node12.isTypeAliasDeclaration(stmt) || Node12.isEnumDeclaration(stmt)) {
|
|
16630
18283
|
return stmt.isExported();
|
|
16631
18284
|
}
|
|
16632
|
-
if (
|
|
18285
|
+
if (Node12.isExportDeclaration(stmt) || Node12.isExportAssignment(stmt)) {
|
|
16633
18286
|
return true;
|
|
16634
18287
|
}
|
|
16635
18288
|
return false;
|
|
@@ -16939,7 +18592,7 @@ var systemMValidateFolderTool = createFolderValidateTool({
|
|
|
16939
18592
|
});
|
|
16940
18593
|
|
|
16941
18594
|
// packages/dbx-components-mcp/src/tools/lookup-action.tool.ts
|
|
16942
|
-
import { type as
|
|
18595
|
+
import { type as type36 } from "arktype";
|
|
16943
18596
|
var DBX_ACTION_LOOKUP_TOOL = {
|
|
16944
18597
|
name: "dbx_action_lookup",
|
|
16945
18598
|
description: [
|
|
@@ -16972,13 +18625,13 @@ var DBX_ACTION_LOOKUP_TOOL = {
|
|
|
16972
18625
|
required: ["topic"]
|
|
16973
18626
|
}
|
|
16974
18627
|
};
|
|
16975
|
-
var LookupActionArgsType =
|
|
18628
|
+
var LookupActionArgsType = type36({
|
|
16976
18629
|
topic: "string",
|
|
16977
18630
|
"depth?": "'brief' | 'full'"
|
|
16978
18631
|
});
|
|
16979
18632
|
function parseLookupActionArgs(raw) {
|
|
16980
18633
|
const parsed = LookupActionArgsType(raw);
|
|
16981
|
-
if (parsed instanceof
|
|
18634
|
+
if (parsed instanceof type36.errors) {
|
|
16982
18635
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
16983
18636
|
}
|
|
16984
18637
|
const result = {
|
|
@@ -17102,7 +18755,7 @@ function formatDirectiveEntry(entry, depth) {
|
|
|
17102
18755
|
}
|
|
17103
18756
|
lines.push("## State interaction", "", formatStateInteraction(entry), "", "## Example", "", "```html", entry.example, "```");
|
|
17104
18757
|
if (entry.skillRefs.length > 0) {
|
|
17105
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
18758
|
+
const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
|
|
17106
18759
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
17107
18760
|
}
|
|
17108
18761
|
} else {
|
|
@@ -17136,7 +18789,7 @@ function formatStoreEntry(entry, depth) {
|
|
|
17136
18789
|
}
|
|
17137
18790
|
lines.push("## Example", "", "```ts", entry.example, "```");
|
|
17138
18791
|
if (entry.skillRefs.length > 0) {
|
|
17139
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
18792
|
+
const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
|
|
17140
18793
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
17141
18794
|
}
|
|
17142
18795
|
} else {
|
|
@@ -17161,7 +18814,7 @@ function formatStateDiagram(entry) {
|
|
|
17161
18814
|
function formatStateEntry(entry, depth) {
|
|
17162
18815
|
const lines = [`# DbxActionState.${entry.stateValue}`, "", entry.description, "", bullet("enum value", `\`'${entry.literal}'\``), bullet("slug", `\`${entry.slug}\``), "", "## Transitions", "", "```", formatStateDiagram(entry), "```"];
|
|
17163
18816
|
if (depth === "full" && entry.skillRefs.length > 0) {
|
|
17164
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
18817
|
+
const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
|
|
17165
18818
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
17166
18819
|
}
|
|
17167
18820
|
return lines.join("\n");
|
|
@@ -17240,12 +18893,12 @@ function formatNotFound6(normalized, candidates) {
|
|
|
17240
18893
|
}
|
|
17241
18894
|
return lines.join("\n");
|
|
17242
18895
|
}
|
|
17243
|
-
function
|
|
18896
|
+
function code6(value) {
|
|
17244
18897
|
return "`" + value + "`";
|
|
17245
18898
|
}
|
|
17246
18899
|
function createLookupActionTool(input) {
|
|
17247
18900
|
const { registry } = input;
|
|
17248
|
-
const
|
|
18901
|
+
const run5 = (rawArgs) => {
|
|
17249
18902
|
let args;
|
|
17250
18903
|
try {
|
|
17251
18904
|
args = parseLookupActionArgs(rawArgs);
|
|
@@ -17272,11 +18925,11 @@ function createLookupActionTool(input) {
|
|
|
17272
18925
|
const result = { content: [{ type: "text", text }] };
|
|
17273
18926
|
return result;
|
|
17274
18927
|
};
|
|
17275
|
-
return { definition: DBX_ACTION_LOOKUP_TOOL, run };
|
|
18928
|
+
return { definition: DBX_ACTION_LOOKUP_TOOL, run: run5 };
|
|
17276
18929
|
}
|
|
17277
18930
|
|
|
17278
18931
|
// packages/dbx-components-mcp/src/tools/action-examples.tool.ts
|
|
17279
|
-
import { type as
|
|
18932
|
+
import { type as type37 } from "arktype";
|
|
17280
18933
|
|
|
17281
18934
|
// packages/dbx-components-mcp/src/tools/data/patterns/actions/action.auto-trigger-on-modify.pattern.ts
|
|
17282
18935
|
var ACTION_PATTERN_AUTO_TRIGGER_ON_MODIFY = {
|
|
@@ -17636,13 +19289,13 @@ var DBX_ACTION_EXAMPLES_TOOL = {
|
|
|
17636
19289
|
required: ["pattern"]
|
|
17637
19290
|
}
|
|
17638
19291
|
};
|
|
17639
|
-
var ActionExamplesArgsType =
|
|
19292
|
+
var ActionExamplesArgsType = type37({
|
|
17640
19293
|
pattern: "string",
|
|
17641
19294
|
"depth?": "'minimal' | 'brief' | 'full'"
|
|
17642
19295
|
});
|
|
17643
19296
|
function parseActionExamplesArgs(raw) {
|
|
17644
19297
|
const parsed = ActionExamplesArgsType(raw);
|
|
17645
|
-
if (parsed instanceof
|
|
19298
|
+
if (parsed instanceof type37.errors) {
|
|
17646
19299
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
17647
19300
|
}
|
|
17648
19301
|
const result = {
|
|
@@ -17654,7 +19307,7 @@ function parseActionExamplesArgs(raw) {
|
|
|
17654
19307
|
function formatPatternCatalog3() {
|
|
17655
19308
|
const lines = [`# Action example patterns (${ACTION_EXAMPLE_PATTERNS.length})`, "", 'Call `dbx_action_examples pattern="<slug>"` for a full example.', ""];
|
|
17656
19309
|
for (const pattern of ACTION_EXAMPLE_PATTERNS) {
|
|
17657
|
-
const usesText = pattern.usesActionSlugs.map((s) =>
|
|
19310
|
+
const usesText = pattern.usesActionSlugs.map((s) => code7(s)).join(", ");
|
|
17658
19311
|
lines.push(`## ${pattern.name}`, "", `- **slug:** \`${pattern.slug}\``, `- **summary:** ${pattern.summary}`, `- **uses:** ${usesText}`, "");
|
|
17659
19312
|
}
|
|
17660
19313
|
return lines.join("\n").trimEnd();
|
|
@@ -17662,7 +19315,7 @@ function formatPatternCatalog3() {
|
|
|
17662
19315
|
function formatPattern3(pattern, depth) {
|
|
17663
19316
|
const snippet = pattern.snippets[depth];
|
|
17664
19317
|
const fence = depth === "full" ? "ts" : "html";
|
|
17665
|
-
const usesText = pattern.usesActionSlugs.map((s) =>
|
|
19318
|
+
const usesText = pattern.usesActionSlugs.map((s) => code7(s)).join(", ");
|
|
17666
19319
|
const sections = [`# ${pattern.name}`, "", pattern.summary, "", `**slug:** \`${pattern.slug}\` \xB7 **depth:** \`${depth}\` \xB7 **uses:** ${usesText}`, "", "```" + fence, snippet, "```"];
|
|
17667
19320
|
if (pattern.notes && depth === "full") {
|
|
17668
19321
|
sections.push("", "## Notes", "", pattern.notes);
|
|
@@ -17673,10 +19326,10 @@ function formatPattern3(pattern, depth) {
|
|
|
17673
19326
|
return sections.join("\n");
|
|
17674
19327
|
}
|
|
17675
19328
|
function formatNotFound7(slug) {
|
|
17676
|
-
const available = ACTION_EXAMPLE_PATTERNS.map((p) =>
|
|
19329
|
+
const available = ACTION_EXAMPLE_PATTERNS.map((p) => code7(p.slug)).join(", ");
|
|
17677
19330
|
return [`No action example pattern matched \`${slug}\`.`, "", `Available patterns: ${available}.`, "", 'Call `dbx_action_examples pattern="list"` for summaries.'].join("\n");
|
|
17678
19331
|
}
|
|
17679
|
-
function
|
|
19332
|
+
function code7(value) {
|
|
17680
19333
|
return "`" + value + "`";
|
|
17681
19334
|
}
|
|
17682
19335
|
function runActionExamples(rawArgs) {
|
|
@@ -17704,7 +19357,7 @@ var actionExamplesTool = {
|
|
|
17704
19357
|
};
|
|
17705
19358
|
|
|
17706
19359
|
// packages/dbx-components-mcp/src/tools/action-scaffold.tool.ts
|
|
17707
|
-
import { type as
|
|
19360
|
+
import { type as type38 } from "arktype";
|
|
17708
19361
|
var TRIGGER_VALUES = ["button", "form", "auto-modify"];
|
|
17709
19362
|
var SUCCESS_FEEDBACK_VALUES = ["snackbar", "redirect", "none"];
|
|
17710
19363
|
var CONTEXT_PROVIDER_VALUES = ["inline", "parent", "host-component"];
|
|
@@ -17738,7 +19391,7 @@ var DBX_ACTION_SCAFFOLD_TOOL = {
|
|
|
17738
19391
|
required: ["use_case", "trigger", "value_type"]
|
|
17739
19392
|
}
|
|
17740
19393
|
};
|
|
17741
|
-
var
|
|
19394
|
+
var ScaffoldArgsType4 = type38({
|
|
17742
19395
|
use_case: "string",
|
|
17743
19396
|
trigger: "'button' | 'form' | 'auto-modify'",
|
|
17744
19397
|
"confirm?": "boolean",
|
|
@@ -17748,8 +19401,8 @@ var ScaffoldArgsType3 = type33({
|
|
|
17748
19401
|
"result_type?": "string"
|
|
17749
19402
|
});
|
|
17750
19403
|
function parseScaffoldArgs2(raw) {
|
|
17751
|
-
const parsed =
|
|
17752
|
-
if (parsed instanceof
|
|
19404
|
+
const parsed = ScaffoldArgsType4(raw);
|
|
19405
|
+
if (parsed instanceof type38.errors) {
|
|
17753
19406
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
17754
19407
|
}
|
|
17755
19408
|
const useCase = parsed.use_case.trim();
|
|
@@ -17955,16 +19608,16 @@ var actionScaffoldTool = {
|
|
|
17955
19608
|
};
|
|
17956
19609
|
|
|
17957
19610
|
// packages/dbx-components-mcp/src/tools/route-tree.tool.ts
|
|
17958
|
-
import { type as
|
|
19611
|
+
import { type as type39 } from "arktype";
|
|
17959
19612
|
|
|
17960
19613
|
// packages/dbx-components-mcp/src/tools/route/load-sources.ts
|
|
17961
|
-
import { glob as fsGlob3, readFile as
|
|
17962
|
-
import { dirname as dirname7, isAbsolute as isAbsolute7, resolve as
|
|
19614
|
+
import { glob as fsGlob3, readFile as readFile7, stat as stat6 } from "node:fs/promises";
|
|
19615
|
+
import { dirname as dirname7, isAbsolute as isAbsolute7, resolve as resolve20, sep as sep3 } from "node:path";
|
|
17963
19616
|
|
|
17964
19617
|
// packages/dbx-components-mcp/src/tools/route/extract.ts
|
|
17965
|
-
import { Node as
|
|
19618
|
+
import { Node as Node13, Project as Project10, SyntaxKind as SyntaxKind9 } from "ts-morph";
|
|
17966
19619
|
function extractFile3(source) {
|
|
17967
|
-
const project = new
|
|
19620
|
+
const project = new Project10({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
17968
19621
|
const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
|
|
17969
19622
|
const issues = [];
|
|
17970
19623
|
const objectLiteralsByName = collectStateConsts(sourceFile);
|
|
@@ -17977,9 +19630,9 @@ function extractFile3(source) {
|
|
|
17977
19630
|
}
|
|
17978
19631
|
for (const arrayLit of findStateArrayLiterals(sourceFile)) {
|
|
17979
19632
|
for (const element of arrayLit.getElements()) {
|
|
17980
|
-
if (
|
|
19633
|
+
if (Node13.isObjectLiteralExpression(element)) {
|
|
17981
19634
|
addNode({ file: source.name, literal: element, fallbackConstName: void 0, into: collected, issues });
|
|
17982
|
-
} else if (
|
|
19635
|
+
} else if (Node13.isIdentifier(element)) {
|
|
17983
19636
|
const ref = objectLiteralsByName.get(element.getText());
|
|
17984
19637
|
if (ref) {
|
|
17985
19638
|
addNode({ file: source.name, literal: ref.literal, fallbackConstName: element.getText(), into: collected, issues });
|
|
@@ -18000,7 +19653,7 @@ function collectStateConsts(sourceFile) {
|
|
|
18000
19653
|
for (const stmt of sourceFile.getVariableStatements()) {
|
|
18001
19654
|
for (const decl of stmt.getDeclarations()) {
|
|
18002
19655
|
const initializer = decl.getInitializer();
|
|
18003
|
-
if (!initializer || !
|
|
19656
|
+
if (!initializer || !Node13.isObjectLiteralExpression(initializer)) {
|
|
18004
19657
|
continue;
|
|
18005
19658
|
}
|
|
18006
19659
|
const typeNode = decl.getTypeNode();
|
|
@@ -18015,12 +19668,12 @@ function findStateArrayLiterals(sourceFile) {
|
|
|
18015
19668
|
for (const stmt of sourceFile.getVariableStatements()) {
|
|
18016
19669
|
for (const decl of stmt.getDeclarations()) {
|
|
18017
19670
|
const initializer = decl.getInitializer();
|
|
18018
|
-
if (initializer &&
|
|
19671
|
+
if (initializer && Node13.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
|
|
18019
19672
|
arrays.push(initializer);
|
|
18020
19673
|
}
|
|
18021
19674
|
}
|
|
18022
19675
|
}
|
|
18023
|
-
for (const call of sourceFile.getDescendantsOfKind(
|
|
19676
|
+
for (const call of sourceFile.getDescendantsOfKind(SyntaxKind9.CallExpression)) {
|
|
18024
19677
|
const expr = call.getExpression();
|
|
18025
19678
|
const exprText = expr.getText();
|
|
18026
19679
|
const isProvide = exprText === "provideStates";
|
|
@@ -18029,17 +19682,17 @@ function findStateArrayLiterals(sourceFile) {
|
|
|
18029
19682
|
continue;
|
|
18030
19683
|
}
|
|
18031
19684
|
for (const arg of call.getArguments()) {
|
|
18032
|
-
if (!
|
|
19685
|
+
if (!Node13.isObjectLiteralExpression(arg)) {
|
|
18033
19686
|
continue;
|
|
18034
19687
|
}
|
|
18035
19688
|
const statesProp = arg.getProperty("states");
|
|
18036
|
-
if (!statesProp || !
|
|
19689
|
+
if (!statesProp || !Node13.isPropertyAssignment(statesProp)) {
|
|
18037
19690
|
continue;
|
|
18038
19691
|
}
|
|
18039
19692
|
const initializer = statesProp.getInitializer();
|
|
18040
|
-
if (initializer &&
|
|
19693
|
+
if (initializer && Node13.isArrayLiteralExpression(initializer)) {
|
|
18041
19694
|
arrays.push(initializer);
|
|
18042
|
-
} else if (initializer &&
|
|
19695
|
+
} else if (initializer && Node13.isIdentifier(initializer)) {
|
|
18043
19696
|
const referenced = findArrayLiteralForIdentifier(sourceFile, initializer);
|
|
18044
19697
|
if (referenced) {
|
|
18045
19698
|
arrays.push(referenced);
|
|
@@ -18056,10 +19709,10 @@ function declarationIsStateArray(stmt, name, literal) {
|
|
|
18056
19709
|
return true;
|
|
18057
19710
|
}
|
|
18058
19711
|
for (const element of literal.getElements()) {
|
|
18059
|
-
if (
|
|
19712
|
+
if (Node13.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
|
|
18060
19713
|
return true;
|
|
18061
19714
|
}
|
|
18062
|
-
if (
|
|
19715
|
+
if (Node13.isIdentifier(element)) {
|
|
18063
19716
|
return true;
|
|
18064
19717
|
}
|
|
18065
19718
|
}
|
|
@@ -18067,11 +19720,11 @@ function declarationIsStateArray(stmt, name, literal) {
|
|
|
18067
19720
|
}
|
|
18068
19721
|
function hasStringNameProperty(literal) {
|
|
18069
19722
|
const nameProp = literal.getProperty("name");
|
|
18070
|
-
if (!nameProp || !
|
|
19723
|
+
if (!nameProp || !Node13.isPropertyAssignment(nameProp)) {
|
|
18071
19724
|
return false;
|
|
18072
19725
|
}
|
|
18073
19726
|
const initializer = nameProp.getInitializer();
|
|
18074
|
-
return initializer !== void 0 && (
|
|
19727
|
+
return initializer !== void 0 && (Node13.isStringLiteral(initializer) || Node13.isNoSubstitutionTemplateLiteral(initializer));
|
|
18075
19728
|
}
|
|
18076
19729
|
function findArrayLiteralForIdentifier(sourceFile, identifier) {
|
|
18077
19730
|
const name = identifier.getText();
|
|
@@ -18081,7 +19734,7 @@ function findArrayLiteralForIdentifier(sourceFile, identifier) {
|
|
|
18081
19734
|
continue;
|
|
18082
19735
|
}
|
|
18083
19736
|
const initializer = decl.getInitializer();
|
|
18084
|
-
if (initializer &&
|
|
19737
|
+
if (initializer && Node13.isArrayLiteralExpression(initializer)) {
|
|
18085
19738
|
return initializer;
|
|
18086
19739
|
}
|
|
18087
19740
|
}
|
|
@@ -18131,64 +19784,64 @@ function addNode(options) {
|
|
|
18131
19784
|
}
|
|
18132
19785
|
function stringPropertyValue(literal, key) {
|
|
18133
19786
|
const prop = literal.getProperty(key);
|
|
18134
|
-
if (!prop || !
|
|
19787
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18135
19788
|
return void 0;
|
|
18136
19789
|
}
|
|
18137
19790
|
const initializer = prop.getInitializer();
|
|
18138
19791
|
if (!initializer) {
|
|
18139
19792
|
return void 0;
|
|
18140
19793
|
}
|
|
18141
|
-
if (
|
|
19794
|
+
if (Node13.isStringLiteral(initializer) || Node13.isNoSubstitutionTemplateLiteral(initializer)) {
|
|
18142
19795
|
return initializer.getLiteralText();
|
|
18143
19796
|
}
|
|
18144
19797
|
return void 0;
|
|
18145
19798
|
}
|
|
18146
19799
|
function booleanPropertyValue(literal, key) {
|
|
18147
19800
|
const prop = literal.getProperty(key);
|
|
18148
|
-
if (!prop || !
|
|
19801
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18149
19802
|
return void 0;
|
|
18150
19803
|
}
|
|
18151
19804
|
const initializer = prop.getInitializer();
|
|
18152
19805
|
if (!initializer) {
|
|
18153
19806
|
return void 0;
|
|
18154
19807
|
}
|
|
18155
|
-
if (initializer.getKind() ===
|
|
19808
|
+
if (initializer.getKind() === SyntaxKind9.TrueKeyword) {
|
|
18156
19809
|
return true;
|
|
18157
19810
|
}
|
|
18158
|
-
if (initializer.getKind() ===
|
|
19811
|
+
if (initializer.getKind() === SyntaxKind9.FalseKeyword) {
|
|
18159
19812
|
return false;
|
|
18160
19813
|
}
|
|
18161
19814
|
return void 0;
|
|
18162
19815
|
}
|
|
18163
19816
|
function identifierPropertyValue(literal, key) {
|
|
18164
19817
|
const prop = literal.getProperty(key);
|
|
18165
|
-
if (!prop || !
|
|
19818
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18166
19819
|
return void 0;
|
|
18167
19820
|
}
|
|
18168
19821
|
const initializer = prop.getInitializer();
|
|
18169
19822
|
if (!initializer) {
|
|
18170
19823
|
return void 0;
|
|
18171
19824
|
}
|
|
18172
|
-
if (
|
|
19825
|
+
if (Node13.isIdentifier(initializer)) {
|
|
18173
19826
|
return initializer.getText();
|
|
18174
19827
|
}
|
|
18175
|
-
if (
|
|
19828
|
+
if (Node13.isPropertyAccessExpression(initializer)) {
|
|
18176
19829
|
return initializer.getText();
|
|
18177
19830
|
}
|
|
18178
19831
|
return void 0;
|
|
18179
19832
|
}
|
|
18180
19833
|
function objectPropertyKeys(literal, key) {
|
|
18181
19834
|
const prop = literal.getProperty(key);
|
|
18182
|
-
if (!prop || !
|
|
19835
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18183
19836
|
return [];
|
|
18184
19837
|
}
|
|
18185
19838
|
const initializer = prop.getInitializer();
|
|
18186
|
-
if (!initializer || !
|
|
19839
|
+
if (!initializer || !Node13.isObjectLiteralExpression(initializer)) {
|
|
18187
19840
|
return [];
|
|
18188
19841
|
}
|
|
18189
19842
|
const out = [];
|
|
18190
19843
|
for (const member of initializer.getProperties()) {
|
|
18191
|
-
if (
|
|
19844
|
+
if (Node13.isPropertyAssignment(member) || Node13.isShorthandPropertyAssignment(member) || Node13.isMethodDeclaration(member)) {
|
|
18192
19845
|
const nameNode = member.getNameNode();
|
|
18193
19846
|
if (nameNode) {
|
|
18194
19847
|
out.push(nameNode.getText());
|
|
@@ -18199,7 +19852,7 @@ function objectPropertyKeys(literal, key) {
|
|
|
18199
19852
|
}
|
|
18200
19853
|
function collectResolveKeys(literal) {
|
|
18201
19854
|
const prop = literal.getProperty("resolve");
|
|
18202
|
-
if (!prop || !
|
|
19855
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18203
19856
|
return [];
|
|
18204
19857
|
}
|
|
18205
19858
|
const initializer = prop.getInitializer();
|
|
@@ -18207,22 +19860,22 @@ function collectResolveKeys(literal) {
|
|
|
18207
19860
|
return [];
|
|
18208
19861
|
}
|
|
18209
19862
|
const keys = [];
|
|
18210
|
-
if (
|
|
19863
|
+
if (Node13.isObjectLiteralExpression(initializer)) {
|
|
18211
19864
|
for (const member of initializer.getProperties()) {
|
|
18212
|
-
if (
|
|
19865
|
+
if (Node13.isPropertyAssignment(member) || Node13.isShorthandPropertyAssignment(member) || Node13.isMethodDeclaration(member)) {
|
|
18213
19866
|
const nameNode = member.getNameNode();
|
|
18214
19867
|
if (nameNode) {
|
|
18215
19868
|
keys.push(nameNode.getText());
|
|
18216
19869
|
}
|
|
18217
19870
|
}
|
|
18218
19871
|
}
|
|
18219
|
-
} else if (
|
|
19872
|
+
} else if (Node13.isArrayLiteralExpression(initializer)) {
|
|
18220
19873
|
for (const element of initializer.getElements()) {
|
|
18221
|
-
if (
|
|
19874
|
+
if (Node13.isObjectLiteralExpression(element)) {
|
|
18222
19875
|
const tokenProp = element.getProperty("token");
|
|
18223
|
-
if (tokenProp &&
|
|
19876
|
+
if (tokenProp && Node13.isPropertyAssignment(tokenProp)) {
|
|
18224
19877
|
const tokenInit = tokenProp.getInitializer();
|
|
18225
|
-
if (tokenInit && (
|
|
19878
|
+
if (tokenInit && (Node13.isStringLiteral(tokenInit) || Node13.isIdentifier(tokenInit))) {
|
|
18226
19879
|
keys.push(tokenInit.getText().replaceAll(/^['"]|['"]$/g, ""));
|
|
18227
19880
|
}
|
|
18228
19881
|
}
|
|
@@ -18274,7 +19927,7 @@ function computeRelativeSpecifiers(source) {
|
|
|
18274
19927
|
// packages/dbx-components-mcp/src/tools/route/load-sources.ts
|
|
18275
19928
|
var TRY_EXTENSIONS = [".ts", ".tsx", "/index.ts", "/index.tsx"];
|
|
18276
19929
|
async function loadRouteSources(args) {
|
|
18277
|
-
const cwdResolved = args.cwd ?
|
|
19930
|
+
const cwdResolved = args.cwd ? resolve20(process.cwd(), args.cwd) : process.cwd();
|
|
18278
19931
|
guardCwdInsideServer(args.cwd, cwdResolved);
|
|
18279
19932
|
const collected = /* @__PURE__ */ new Map();
|
|
18280
19933
|
if (args.sources) {
|
|
@@ -18346,21 +19999,21 @@ async function loadOne(relative5, cwd, into) {
|
|
|
18346
19999
|
if (into.has(relative5)) {
|
|
18347
20000
|
return;
|
|
18348
20001
|
}
|
|
18349
|
-
const absolute =
|
|
20002
|
+
const absolute = resolve20(cwd, relative5);
|
|
18350
20003
|
const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
|
|
18351
20004
|
if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
|
|
18352
20005
|
throw new Error(`Path \`${relative5}\` resolves outside the server cwd and is not allowed.`);
|
|
18353
20006
|
}
|
|
18354
|
-
const text = await
|
|
20007
|
+
const text = await readFile7(absolute, "utf8");
|
|
18355
20008
|
into.set(relative5, { name: relative5, text });
|
|
18356
20009
|
}
|
|
18357
20010
|
async function resolveRelativeImport(fromFile, specifier, cwd) {
|
|
18358
20011
|
if (!specifier.startsWith(".")) {
|
|
18359
20012
|
return void 0;
|
|
18360
20013
|
}
|
|
18361
|
-
const fromAbsolute = isAbsolute7(fromFile) ? fromFile :
|
|
20014
|
+
const fromAbsolute = isAbsolute7(fromFile) ? fromFile : resolve20(cwd, fromFile);
|
|
18362
20015
|
const fromDir = dirname7(fromAbsolute);
|
|
18363
|
-
const baseAbsolute =
|
|
20016
|
+
const baseAbsolute = resolve20(fromDir, specifier);
|
|
18364
20017
|
const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
|
|
18365
20018
|
for (const ext of TRY_EXTENSIONS) {
|
|
18366
20019
|
const candidateAbsolute = baseAbsolute + ext;
|
|
@@ -18371,7 +20024,7 @@ async function resolveRelativeImport(fromFile, specifier, cwd) {
|
|
|
18371
20024
|
if (!exists) {
|
|
18372
20025
|
continue;
|
|
18373
20026
|
}
|
|
18374
|
-
const text = await
|
|
20027
|
+
const text = await readFile7(candidateAbsolute, "utf8");
|
|
18375
20028
|
const relativeName = candidateAbsolute.startsWith(cwdPrefix) ? candidateAbsolute.slice(cwdPrefix.length) : candidateAbsolute;
|
|
18376
20029
|
const result = { name: relativeName, text };
|
|
18377
20030
|
return result;
|
|
@@ -18739,8 +20392,8 @@ var DBX_ROUTE_TREE_TOOL = {
|
|
|
18739
20392
|
}
|
|
18740
20393
|
}
|
|
18741
20394
|
};
|
|
18742
|
-
var TreeArgsType =
|
|
18743
|
-
"sources?":
|
|
20395
|
+
var TreeArgsType = type39({
|
|
20396
|
+
"sources?": type39({ name: "string", text: "string" }).array(),
|
|
18744
20397
|
"paths?": "string[]",
|
|
18745
20398
|
"glob?": "string",
|
|
18746
20399
|
"format?": "'markdown' | 'json' | 'flat'",
|
|
@@ -18749,7 +20402,7 @@ var TreeArgsType = type34({
|
|
|
18749
20402
|
});
|
|
18750
20403
|
function parseArgs3(raw) {
|
|
18751
20404
|
const parsed = TreeArgsType(raw);
|
|
18752
|
-
if (parsed instanceof
|
|
20405
|
+
if (parsed instanceof type39.errors) {
|
|
18753
20406
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
18754
20407
|
}
|
|
18755
20408
|
const result = {
|
|
@@ -18799,7 +20452,7 @@ var routeTreeTool = {
|
|
|
18799
20452
|
};
|
|
18800
20453
|
|
|
18801
20454
|
// packages/dbx-components-mcp/src/tools/route-lookup.tool.ts
|
|
18802
|
-
import { type as
|
|
20455
|
+
import { type as type40 } from "arktype";
|
|
18803
20456
|
var DBX_ROUTE_LOOKUP_TOOL = {
|
|
18804
20457
|
name: "dbx_route_lookup",
|
|
18805
20458
|
description: ["Look up a single UIRouter state by name, full URL, or component class name. Returns the state's URL, component, parent chain, params, resolves, siblings, and children.", "", "Provide at least one of `sources` / `paths` / `glob` to point the tool at the source set, plus a `topic`.", "", "Resolution order: exact state name \u2192 URL path \u2192 component class name \u2192 fuzzy substring (returns up to 5 candidates)."].join("\n"),
|
|
@@ -18824,17 +20477,17 @@ var DBX_ROUTE_LOOKUP_TOOL = {
|
|
|
18824
20477
|
required: ["topic"]
|
|
18825
20478
|
}
|
|
18826
20479
|
};
|
|
18827
|
-
var
|
|
20480
|
+
var LookupArgsType2 = type40({
|
|
18828
20481
|
topic: "string",
|
|
18829
|
-
"sources?":
|
|
20482
|
+
"sources?": type40({ name: "string", text: "string" }).array(),
|
|
18830
20483
|
"paths?": "string[]",
|
|
18831
20484
|
"glob?": "string",
|
|
18832
20485
|
"depth?": "'brief' | 'full'",
|
|
18833
20486
|
"cwd?": "string"
|
|
18834
20487
|
});
|
|
18835
20488
|
function parseArgs4(raw) {
|
|
18836
|
-
const parsed =
|
|
18837
|
-
if (parsed instanceof
|
|
20489
|
+
const parsed = LookupArgsType2(raw);
|
|
20490
|
+
if (parsed instanceof type40.errors) {
|
|
18838
20491
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
18839
20492
|
}
|
|
18840
20493
|
const result = {
|
|
@@ -18904,8 +20557,8 @@ function fuzzyCandidates3(query, byName) {
|
|
|
18904
20557
|
return scored.slice(0, 5).map((s) => s.node);
|
|
18905
20558
|
}
|
|
18906
20559
|
function formatSingle(node, depth, via) {
|
|
18907
|
-
const urlText = node.fullUrl === void 0 ? "_no url_" :
|
|
18908
|
-
const componentText = node.data.component === void 0 ? "_no component_" :
|
|
20560
|
+
const urlText = node.fullUrl === void 0 ? "_no url_" : code8(node.fullUrl);
|
|
20561
|
+
const componentText = node.data.component === void 0 ? "_no component_" : code8(node.data.component);
|
|
18909
20562
|
const lines = [`# ${node.data.name}`, "", `Matched via ${via}.`, "", `- **URL:** ${urlText}`, `- **Component:** ${componentText}`, `- **Defined in:** \`${node.data.file}:${node.data.line}\``];
|
|
18910
20563
|
if (node.data.redirectTo) {
|
|
18911
20564
|
lines.push(`- **Redirects to:** \`${node.data.redirectTo}\``);
|
|
@@ -18929,7 +20582,7 @@ function formatSingle(node, depth, via) {
|
|
|
18929
20582
|
}
|
|
18930
20583
|
function appendParentChainSection(lines, node) {
|
|
18931
20584
|
const chain = ancestors(node);
|
|
18932
|
-
const chainLine = chain.map((c) =>
|
|
20585
|
+
const chainLine = chain.map((c) => code8(c.data.name)).join(" \u2192 ");
|
|
18933
20586
|
lines.push("", "## Parent chain", chainLine.length > 0 ? chainLine : "_root_");
|
|
18934
20587
|
}
|
|
18935
20588
|
function appendKeyListSection(lines, title, keys) {
|
|
@@ -18949,8 +20602,8 @@ function appendRelatedNodesSection(lines, title, nodes) {
|
|
|
18949
20602
|
return;
|
|
18950
20603
|
}
|
|
18951
20604
|
for (const child of nodes) {
|
|
18952
|
-
const urlPart = child.fullUrl === void 0 ? "" :
|
|
18953
|
-
const componentPart = child.data.component ? ` \u2192 ${
|
|
20605
|
+
const urlPart = child.fullUrl === void 0 ? "" : code8(child.fullUrl);
|
|
20606
|
+
const componentPart = child.data.component ? ` \u2192 ${code8(child.data.component)}` : "";
|
|
18954
20607
|
lines.push(`- \`${child.data.name}\` ${urlPart}${componentPart}`);
|
|
18955
20608
|
}
|
|
18956
20609
|
}
|
|
@@ -18966,8 +20619,8 @@ function ancestors(node) {
|
|
|
18966
20619
|
function formatGroup2(title, nodes) {
|
|
18967
20620
|
const lines = [`# ${title}`, "", `${nodes.length} match(es).`, ""];
|
|
18968
20621
|
for (const node of nodes) {
|
|
18969
|
-
const urlPart = node.fullUrl === void 0 ? "" :
|
|
18970
|
-
const componentPart = node.data.component ? ` \u2192 ${
|
|
20622
|
+
const urlPart = node.fullUrl === void 0 ? "" : code8(node.fullUrl);
|
|
20623
|
+
const componentPart = node.data.component ? ` \u2192 ${code8(node.data.component)}` : "";
|
|
18971
20624
|
lines.push(`- \`${node.data.name}\` ${urlPart}${componentPart} _(${node.data.file}:${node.data.line})_`);
|
|
18972
20625
|
}
|
|
18973
20626
|
return lines.join("\n");
|
|
@@ -18977,8 +20630,8 @@ function formatNotFound8(query, candidates) {
|
|
|
18977
20630
|
if (candidates.length > 0) {
|
|
18978
20631
|
lines.push("Did you mean one of these?", "");
|
|
18979
20632
|
for (const node of candidates) {
|
|
18980
|
-
const urlPart = node.fullUrl === void 0 ? "" :
|
|
18981
|
-
const componentPart = node.data.component ? ` \u2192 ${
|
|
20633
|
+
const urlPart = node.fullUrl === void 0 ? "" : code8(node.fullUrl);
|
|
20634
|
+
const componentPart = node.data.component ? ` \u2192 ${code8(node.data.component)}` : "";
|
|
18982
20635
|
lines.push(`- \`${node.data.name}\` ${urlPart}${componentPart}`);
|
|
18983
20636
|
}
|
|
18984
20637
|
} else {
|
|
@@ -18986,7 +20639,7 @@ function formatNotFound8(query, candidates) {
|
|
|
18986
20639
|
}
|
|
18987
20640
|
return lines.join("\n");
|
|
18988
20641
|
}
|
|
18989
|
-
function
|
|
20642
|
+
function code8(value) {
|
|
18990
20643
|
return "`" + value + "`";
|
|
18991
20644
|
}
|
|
18992
20645
|
async function runRouteLookup(rawArgs) {
|
|
@@ -19027,7 +20680,7 @@ var routeLookupTool = {
|
|
|
19027
20680
|
};
|
|
19028
20681
|
|
|
19029
20682
|
// packages/dbx-components-mcp/src/tools/route-search.tool.ts
|
|
19030
|
-
import { type as
|
|
20683
|
+
import { type as type41 } from "arktype";
|
|
19031
20684
|
var DBX_ROUTE_SEARCH_TOOL = {
|
|
19032
20685
|
name: "dbx_route_search",
|
|
19033
20686
|
description: ["Search the UIRouter state tree of a dbx-components app. Matches against state names, full URLs, component class names, resolve keys, and source-file paths. Returns the top 10 results with state name, URL, component, and source location.", "", "Provide at least one of `sources` / `paths` / `glob` plus a `query`. `scope` narrows to a single axis (`name`, `url`, `component`, `resolve`)."].join("\n"),
|
|
@@ -19051,9 +20704,9 @@ var DBX_ROUTE_SEARCH_TOOL = {
|
|
|
19051
20704
|
required: ["query"]
|
|
19052
20705
|
}
|
|
19053
20706
|
};
|
|
19054
|
-
var SearchArgsType =
|
|
20707
|
+
var SearchArgsType = type41({
|
|
19055
20708
|
query: "string",
|
|
19056
|
-
"sources?":
|
|
20709
|
+
"sources?": type41({ name: "string", text: "string" }).array(),
|
|
19057
20710
|
"paths?": "string[]",
|
|
19058
20711
|
"glob?": "string",
|
|
19059
20712
|
"scope?": "'name' | 'url' | 'component' | 'resolve' | 'all'",
|
|
@@ -19061,7 +20714,7 @@ var SearchArgsType = type36({
|
|
|
19061
20714
|
});
|
|
19062
20715
|
function parseArgs5(raw) {
|
|
19063
20716
|
const parsed = SearchArgsType(raw);
|
|
19064
|
-
if (parsed instanceof
|
|
20717
|
+
if (parsed instanceof type41.errors) {
|
|
19065
20718
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
19066
20719
|
}
|
|
19067
20720
|
const result = {
|
|
@@ -19154,14 +20807,14 @@ var routeSearchTool = {
|
|
|
19154
20807
|
};
|
|
19155
20808
|
|
|
19156
20809
|
// packages/dbx-components-mcp/src/tools/_lookup.factory.ts
|
|
19157
|
-
import { type as
|
|
19158
|
-
var LOOKUP_ARGS_TYPE =
|
|
20810
|
+
import { type as type42 } from "arktype";
|
|
20811
|
+
var LOOKUP_ARGS_TYPE = type42({
|
|
19159
20812
|
topic: "string",
|
|
19160
20813
|
"depth?": "'brief' | 'full'"
|
|
19161
20814
|
});
|
|
19162
20815
|
function parseLookupArgs(raw) {
|
|
19163
20816
|
const parsed = LOOKUP_ARGS_TYPE(raw);
|
|
19164
|
-
if (parsed instanceof
|
|
20817
|
+
if (parsed instanceof type42.errors) {
|
|
19165
20818
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
19166
20819
|
}
|
|
19167
20820
|
const result = {
|
|
@@ -19310,11 +20963,11 @@ function formatEntry2(entry, depth) {
|
|
|
19310
20963
|
const fence = entry.kind === "pattern" ? "ts" : "html";
|
|
19311
20964
|
lines.push("## Example", "", "```" + fence, entry.example, "```");
|
|
19312
20965
|
if (entry.relatedSlugs.length > 0) {
|
|
19313
|
-
const relatedText = entry.relatedSlugs.map((s) =>
|
|
20966
|
+
const relatedText = entry.relatedSlugs.map((s) => code9(s)).join(", ");
|
|
19314
20967
|
lines.push("", `\u2192 Related: ${relatedText}`);
|
|
19315
20968
|
}
|
|
19316
20969
|
if (entry.skillRefs.length > 0) {
|
|
19317
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
20970
|
+
const skillsText = entry.skillRefs.map((s) => code9(s)).join(", ");
|
|
19318
20971
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
19319
20972
|
}
|
|
19320
20973
|
} else {
|
|
@@ -19343,7 +20996,7 @@ function formatNotFound9(normalized, candidates) {
|
|
|
19343
20996
|
}
|
|
19344
20997
|
return lines.join("\n");
|
|
19345
20998
|
}
|
|
19346
|
-
function
|
|
20999
|
+
function code9(value) {
|
|
19347
21000
|
return "`" + value + "`";
|
|
19348
21001
|
}
|
|
19349
21002
|
function createLookupFilterTool(input) {
|
|
@@ -19363,7 +21016,7 @@ function createLookupFilterTool(input) {
|
|
|
19363
21016
|
}
|
|
19364
21017
|
|
|
19365
21018
|
// packages/dbx-components-mcp/src/tools/filter-scaffold.tool.ts
|
|
19366
|
-
import { type as
|
|
21019
|
+
import { type as type43 } from "arktype";
|
|
19367
21020
|
var DBX_FILTER_SCAFFOLD_TOOL = {
|
|
19368
21021
|
name: "dbx_filter_scaffold",
|
|
19369
21022
|
description: [
|
|
@@ -19388,15 +21041,15 @@ var DBX_FILTER_SCAFFOLD_TOOL = {
|
|
|
19388
21041
|
required: ["model_name", "filter_type"]
|
|
19389
21042
|
}
|
|
19390
21043
|
};
|
|
19391
|
-
var
|
|
21044
|
+
var ScaffoldArgsType5 = type43({
|
|
19392
21045
|
model_name: "string",
|
|
19393
21046
|
filter_type: "string",
|
|
19394
21047
|
"preset_keys?": "string[]",
|
|
19395
21048
|
"uses_collection_store?": "boolean"
|
|
19396
21049
|
});
|
|
19397
21050
|
function parseArgs6(raw) {
|
|
19398
|
-
const parsed =
|
|
19399
|
-
if (parsed instanceof
|
|
21051
|
+
const parsed = ScaffoldArgsType5(raw);
|
|
21052
|
+
if (parsed instanceof type43.errors) {
|
|
19400
21053
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
19401
21054
|
}
|
|
19402
21055
|
const modelName = parsed.model_name.trim();
|
|
@@ -19579,11 +21232,11 @@ function formatEntry3(entry, depth) {
|
|
|
19579
21232
|
}
|
|
19580
21233
|
lines.push("## Example", "", "```html", entry.example, "```");
|
|
19581
21234
|
if (entry.relatedSlugs.length > 0) {
|
|
19582
|
-
const relatedText = entry.relatedSlugs.map((s) =>
|
|
21235
|
+
const relatedText = entry.relatedSlugs.map((s) => code10(s)).join(", ");
|
|
19583
21236
|
lines.push("", `\u2192 Related: ${relatedText}`);
|
|
19584
21237
|
}
|
|
19585
21238
|
if (entry.skillRefs.length > 0) {
|
|
19586
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
21239
|
+
const skillsText = entry.skillRefs.map((s) => code10(s)).join(", ");
|
|
19587
21240
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
19588
21241
|
}
|
|
19589
21242
|
} else {
|
|
@@ -19615,7 +21268,7 @@ function formatNotFound10(normalized, candidates) {
|
|
|
19615
21268
|
}
|
|
19616
21269
|
return lines.join("\n");
|
|
19617
21270
|
}
|
|
19618
|
-
function
|
|
21271
|
+
function code10(value) {
|
|
19619
21272
|
return "`" + value + "`";
|
|
19620
21273
|
}
|
|
19621
21274
|
function createLookupPipeTool(input) {
|
|
@@ -19636,8 +21289,8 @@ function createLookupPipeTool(input) {
|
|
|
19636
21289
|
|
|
19637
21290
|
// packages/dbx-components-mcp/src/tools/artifact-scaffold.tool.ts
|
|
19638
21291
|
import { access } from "node:fs/promises";
|
|
19639
|
-
import { resolve as
|
|
19640
|
-
import { type as
|
|
21292
|
+
import { resolve as resolve21, sep as sep4 } from "node:path";
|
|
21293
|
+
import { type as type44 } from "arktype";
|
|
19641
21294
|
|
|
19642
21295
|
// packages/dbx-components-mcp/src/tools/artifact-scaffold/templates.ts
|
|
19643
21296
|
function splitWords(input) {
|
|
@@ -20185,7 +21838,7 @@ var DBX_ARTIFACT_SCAFFOLD_TOOL = {
|
|
|
20185
21838
|
required: ["artifact", "name", "componentDir", "apiDir"]
|
|
20186
21839
|
}
|
|
20187
21840
|
};
|
|
20188
|
-
var ScaffoldArtifactArgsType =
|
|
21841
|
+
var ScaffoldArtifactArgsType = type44({
|
|
20189
21842
|
artifact: ARTIFACT_KIND_LITERAL_UNION,
|
|
20190
21843
|
name: "string",
|
|
20191
21844
|
componentDir: "string",
|
|
@@ -20198,7 +21851,7 @@ var ScaffoldArtifactArgsType = type39({
|
|
|
20198
21851
|
});
|
|
20199
21852
|
function parseArgs7(raw) {
|
|
20200
21853
|
const parsed = ScaffoldArtifactArgsType(raw);
|
|
20201
|
-
if (parsed instanceof
|
|
21854
|
+
if (parsed instanceof type44.errors) {
|
|
20202
21855
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
20203
21856
|
}
|
|
20204
21857
|
const result = {
|
|
@@ -20211,7 +21864,7 @@ function parseArgs7(raw) {
|
|
|
20211
21864
|
return result;
|
|
20212
21865
|
}
|
|
20213
21866
|
function ensureInsideCwd(relativePath, cwd) {
|
|
20214
|
-
const absolute =
|
|
21867
|
+
const absolute = resolve21(cwd, relativePath);
|
|
20215
21868
|
const cwdPrefix = cwd.endsWith(sep4) ? cwd : cwd + sep4;
|
|
20216
21869
|
if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
|
|
20217
21870
|
throw new Error(`Path \`${relativePath}\` resolves outside the server cwd and is not allowed.`);
|
|
@@ -20251,7 +21904,7 @@ async function runArtifactScaffold(rawArgs) {
|
|
|
20251
21904
|
const message = err instanceof Error ? err.message : String(err);
|
|
20252
21905
|
return toolError(`Scaffold failed: ${message}`);
|
|
20253
21906
|
}
|
|
20254
|
-
const checked = await applyIdempotency(raw, (relativePath) => fileExists2(
|
|
21907
|
+
const checked = await applyIdempotency(raw, (relativePath) => fileExists2(resolve21(cwd, relativePath)));
|
|
20255
21908
|
const text = formatResult9(checked);
|
|
20256
21909
|
const result = {
|
|
20257
21910
|
content: [{ type: "text", text }]
|
|
@@ -20264,7 +21917,7 @@ var artifactScaffoldTool = {
|
|
|
20264
21917
|
};
|
|
20265
21918
|
|
|
20266
21919
|
// packages/dbx-components-mcp/src/tools/artifact-file-convention.tool.ts
|
|
20267
|
-
import { type as
|
|
21920
|
+
import { type as type45 } from "arktype";
|
|
20268
21921
|
|
|
20269
21922
|
// packages/dbx-components-mcp/src/tools/artifact-file-convention/spec.ts
|
|
20270
21923
|
var FIRESTORE_MODEL = {
|
|
@@ -20700,7 +22353,7 @@ var DBX_ARTIFACT_FILE_CONVENTION_TOOL = {
|
|
|
20700
22353
|
required: ["artifact"]
|
|
20701
22354
|
}
|
|
20702
22355
|
};
|
|
20703
|
-
var FileConventionArgsType =
|
|
22356
|
+
var FileConventionArgsType = type45({
|
|
20704
22357
|
artifact: ARTIFACT_KIND_LITERAL_UNION2,
|
|
20705
22358
|
"componentDir?": "string",
|
|
20706
22359
|
"apiDir?": "string",
|
|
@@ -20708,7 +22361,7 @@ var FileConventionArgsType = type40({
|
|
|
20708
22361
|
});
|
|
20709
22362
|
function parseArgs8(raw) {
|
|
20710
22363
|
const parsed = FileConventionArgsType(raw);
|
|
20711
|
-
if (parsed instanceof
|
|
22364
|
+
if (parsed instanceof type45.errors) {
|
|
20712
22365
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
20713
22366
|
}
|
|
20714
22367
|
const result = {
|
|
@@ -20741,7 +22394,7 @@ var artifactFileConventionTool = {
|
|
|
20741
22394
|
};
|
|
20742
22395
|
|
|
20743
22396
|
// packages/dbx-components-mcp/src/tools/lookup-semantic-type.tool.ts
|
|
20744
|
-
import { type as
|
|
22397
|
+
import { type as type46 } from "arktype";
|
|
20745
22398
|
|
|
20746
22399
|
// packages/dbx-components-mcp/src/tools/semantic-type-lookup.formatter.ts
|
|
20747
22400
|
function formatSemanticTypeEntry(entry, depth) {
|
|
@@ -20922,13 +22575,13 @@ var DBX_SEMANTIC_TYPE_LOOKUP_TOOL = {
|
|
|
20922
22575
|
required: ["name"]
|
|
20923
22576
|
}
|
|
20924
22577
|
};
|
|
20925
|
-
var LookupSemanticTypeArgsType =
|
|
22578
|
+
var LookupSemanticTypeArgsType = type46({
|
|
20926
22579
|
name: "string",
|
|
20927
22580
|
"depth?": "'brief' | 'full'"
|
|
20928
22581
|
});
|
|
20929
22582
|
function parseLookupArgs2(raw) {
|
|
20930
22583
|
const parsed = LookupSemanticTypeArgsType(raw);
|
|
20931
|
-
if (parsed instanceof
|
|
22584
|
+
if (parsed instanceof type46.errors) {
|
|
20932
22585
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
20933
22586
|
}
|
|
20934
22587
|
const result = {
|
|
@@ -20939,7 +22592,7 @@ function parseLookupArgs2(raw) {
|
|
|
20939
22592
|
}
|
|
20940
22593
|
function createSemanticTypeLookupTool(config) {
|
|
20941
22594
|
const { registry } = config;
|
|
20942
|
-
function
|
|
22595
|
+
function run5(rawArgs) {
|
|
20943
22596
|
let args;
|
|
20944
22597
|
let result;
|
|
20945
22598
|
try {
|
|
@@ -20975,7 +22628,7 @@ function createSemanticTypeLookupTool(config) {
|
|
|
20975
22628
|
}
|
|
20976
22629
|
const tool = {
|
|
20977
22630
|
definition: DBX_SEMANTIC_TYPE_LOOKUP_TOOL,
|
|
20978
|
-
run
|
|
22631
|
+
run: run5
|
|
20979
22632
|
};
|
|
20980
22633
|
return tool;
|
|
20981
22634
|
}
|
|
@@ -20990,7 +22643,7 @@ function formatNotFound11(name, registry) {
|
|
|
20990
22643
|
}
|
|
20991
22644
|
|
|
20992
22645
|
// packages/dbx-components-mcp/src/tools/search-semantic-type.tool.ts
|
|
20993
|
-
import { type as
|
|
22646
|
+
import { type as type47 } from "arktype";
|
|
20994
22647
|
var DEFAULT_LIMIT4 = 25;
|
|
20995
22648
|
var MAX_LIMIT4 = 100;
|
|
20996
22649
|
var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
|
|
@@ -21023,7 +22676,7 @@ var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
|
|
|
21023
22676
|
}
|
|
21024
22677
|
}
|
|
21025
22678
|
};
|
|
21026
|
-
var SearchSemanticTypeArgsType =
|
|
22679
|
+
var SearchSemanticTypeArgsType = type47({
|
|
21027
22680
|
"topic?": "string",
|
|
21028
22681
|
"baseType?": "string",
|
|
21029
22682
|
"package?": "string",
|
|
@@ -21032,7 +22685,7 @@ var SearchSemanticTypeArgsType = type42({
|
|
|
21032
22685
|
});
|
|
21033
22686
|
function parseSearchArgs2(raw) {
|
|
21034
22687
|
const parsed = SearchSemanticTypeArgsType(raw);
|
|
21035
|
-
if (parsed instanceof
|
|
22688
|
+
if (parsed instanceof type47.errors) {
|
|
21036
22689
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
21037
22690
|
}
|
|
21038
22691
|
const rawLimit = parsed.limit ?? DEFAULT_LIMIT4;
|
|
@@ -21058,7 +22711,7 @@ function nonEmpty(value) {
|
|
|
21058
22711
|
}
|
|
21059
22712
|
function createSemanticTypeSearchTool(config) {
|
|
21060
22713
|
const { registry } = config;
|
|
21061
|
-
function
|
|
22714
|
+
function run5(rawArgs) {
|
|
21062
22715
|
let args;
|
|
21063
22716
|
let result;
|
|
21064
22717
|
try {
|
|
@@ -21083,7 +22736,7 @@ function createSemanticTypeSearchTool(config) {
|
|
|
21083
22736
|
}
|
|
21084
22737
|
const tool = {
|
|
21085
22738
|
definition: DBX_SEMANTIC_TYPE_SEARCH_TOOL,
|
|
21086
|
-
run
|
|
22739
|
+
run: run5
|
|
21087
22740
|
};
|
|
21088
22741
|
return tool;
|
|
21089
22742
|
}
|
|
@@ -21157,6 +22810,10 @@ var DBX_TOOLS = [
|
|
|
21157
22810
|
modelValidateApiTool,
|
|
21158
22811
|
modelValidateFolderTool,
|
|
21159
22812
|
modelStoreScaffoldTool,
|
|
22813
|
+
modelFixtureListAppTool,
|
|
22814
|
+
modelFixtureLookupTool,
|
|
22815
|
+
modelFixtureScaffoldTool,
|
|
22816
|
+
modelFixtureForwardTool,
|
|
21160
22817
|
// storagefile_m (model extension)
|
|
21161
22818
|
storageFileMValidateAppTool,
|
|
21162
22819
|
storageFileMListAppTool,
|
|
@@ -21183,6 +22840,7 @@ var DBX_TOOLS = [
|
|
|
21183
22840
|
function registerTools(server, options = {}) {
|
|
21184
22841
|
const underlyingServer = server.server;
|
|
21185
22842
|
const tools = [...DBX_TOOLS];
|
|
22843
|
+
tools.push(createModelFixtureValidateAppTool({ getRegistry: () => options.fixtureModelRegistry }));
|
|
21186
22844
|
if (options.forgeFieldRegistry !== void 0) {
|
|
21187
22845
|
tools.push(createLookupFormTool({ registry: options.forgeFieldRegistry }), createSearchFormTool({ registry: options.forgeFieldRegistry }), createFormScaffoldTool({ registry: options.forgeFieldRegistry }));
|
|
21188
22846
|
}
|
|
@@ -21232,6 +22890,7 @@ Tool clusters (each exposes lookup, search, examples, and/or scaffold/validate):
|
|
|
21232
22890
|
|
|
21233
22891
|
Model-extension validators (walk a downstream app to verify wiring):
|
|
21234
22892
|
- storagefile_m, notification_m, system_m \u2014 *_validate_app, *_list_app, *_validate_folder
|
|
22893
|
+
- model_fixture \u2014 list/lookup/validate/scaffold/forward an app's \`src/test/fixture.ts\` (TestContextFixture/Instance triplets)
|
|
21235
22894
|
|
|
21236
22895
|
Resource URIs are namespaced by domain:
|
|
21237
22896
|
- dbx://form/fields[/{slug}|/produces/{produces}|/tier/{tier}|/array-output/{arrayOutput}]
|
|
@@ -21354,8 +23013,11 @@ async function createServer(options = {}) {
|
|
|
21354
23013
|
filterRegistry = void 0;
|
|
21355
23014
|
}
|
|
21356
23015
|
}
|
|
23016
|
+
const fixtureModelRegistry = {
|
|
23017
|
+
entries: FIREBASE_MODELS.map((m) => ({ name: m.name, modelType: m.modelType, collectionPrefix: m.collectionPrefix }))
|
|
23018
|
+
};
|
|
21357
23019
|
registerResources(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
|
|
21358
|
-
registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
|
|
23020
|
+
registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry, fixtureModelRegistry });
|
|
21359
23021
|
return server;
|
|
21360
23022
|
}
|
|
21361
23023
|
async function runStdioServer() {
|