@dereekb/dbx-components-mcp 13.10.0 → 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,10 +5,10 @@ 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
|
-
"dbx-components-mcp": "
|
|
11
|
+
"dbx-components-mcp": "dbx-components-mcp.js"
|
|
12
12
|
},
|
|
13
13
|
dependencies: {
|
|
14
14
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
@@ -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;
|
|
@@ -6317,7 +6326,11 @@ function formatConfigTable(field) {
|
|
|
6317
6326
|
const rows = keys.map((key) => {
|
|
6318
6327
|
const prop = field.config[key];
|
|
6319
6328
|
const required = prop.required ? "\u2713" : "";
|
|
6320
|
-
|
|
6329
|
+
let defaultCell = "";
|
|
6330
|
+
if (prop.default !== void 0) {
|
|
6331
|
+
const defaultText = typeof prop.default === "string" ? prop.default : JSON.stringify(prop.default);
|
|
6332
|
+
defaultCell = `\`${defaultText}\``;
|
|
6333
|
+
}
|
|
6321
6334
|
const desc = prop.description.replaceAll("|", String.raw`\|`);
|
|
6322
6335
|
const escapedType = prop.type.replaceAll("|", String.raw`\|`);
|
|
6323
6336
|
return `| \`${prop.name}\` | \`${escapedType}\` | ${required} | ${defaultCell} | ${desc} |`;
|
|
@@ -6487,7 +6500,7 @@ function createLookupFormTool(config) {
|
|
|
6487
6500
|
}
|
|
6488
6501
|
return lines.join("\n").trimEnd();
|
|
6489
6502
|
}
|
|
6490
|
-
function
|
|
6503
|
+
function run5(rawArgs) {
|
|
6491
6504
|
let args;
|
|
6492
6505
|
try {
|
|
6493
6506
|
args = parseLookupFormArgs(rawArgs);
|
|
@@ -6516,7 +6529,7 @@ function createLookupFormTool(config) {
|
|
|
6516
6529
|
}
|
|
6517
6530
|
const tool = {
|
|
6518
6531
|
definition: DBX_FORM_LOOKUP_TOOL,
|
|
6519
|
-
run
|
|
6532
|
+
run: run5
|
|
6520
6533
|
};
|
|
6521
6534
|
return tool;
|
|
6522
6535
|
}
|
|
@@ -6705,7 +6718,7 @@ function formatSearchResults(input) {
|
|
|
6705
6718
|
}
|
|
6706
6719
|
function createSearchFormTool(config) {
|
|
6707
6720
|
const { registry } = config;
|
|
6708
|
-
function
|
|
6721
|
+
function run5(rawArgs) {
|
|
6709
6722
|
return runSearchTool(
|
|
6710
6723
|
{
|
|
6711
6724
|
entries: registry.all,
|
|
@@ -6721,7 +6734,7 @@ function createSearchFormTool(config) {
|
|
|
6721
6734
|
}
|
|
6722
6735
|
const tool = {
|
|
6723
6736
|
definition: DBX_FORM_SEARCH_TOOL,
|
|
6724
|
-
run
|
|
6737
|
+
run: run5
|
|
6725
6738
|
};
|
|
6726
6739
|
return tool;
|
|
6727
6740
|
}
|
|
@@ -7244,7 +7257,7 @@ function renderScaffold(specs, valueTypeName, wrapInSection) {
|
|
|
7244
7257
|
}
|
|
7245
7258
|
function createFormScaffoldTool(config) {
|
|
7246
7259
|
const { registry } = config;
|
|
7247
|
-
function
|
|
7260
|
+
function run5(rawArgs) {
|
|
7248
7261
|
let args;
|
|
7249
7262
|
try {
|
|
7250
7263
|
args = parseScaffoldArgs(rawArgs);
|
|
@@ -7263,7 +7276,7 @@ function createFormScaffoldTool(config) {
|
|
|
7263
7276
|
return toolError(lines.join("\n"));
|
|
7264
7277
|
}
|
|
7265
7278
|
const specs = parsed;
|
|
7266
|
-
const
|
|
7279
|
+
const code11 = renderScaffold(specs, args.valueTypeName, args.wrapInSection);
|
|
7267
7280
|
const slugList = specs.map((s) => s.slug).join(", ");
|
|
7268
7281
|
const preamble = `# Scaffold
|
|
7269
7282
|
|
|
@@ -7271,14 +7284,14 @@ Generated from \`${slugList}\` (${specs.length} field${specs.length === 1 ? "" :
|
|
|
7271
7284
|
const text = `${preamble}
|
|
7272
7285
|
|
|
7273
7286
|
\`\`\`ts
|
|
7274
|
-
${
|
|
7287
|
+
${code11}
|
|
7275
7288
|
\`\`\``;
|
|
7276
7289
|
const result = { content: [{ type: "text", text }] };
|
|
7277
7290
|
return result;
|
|
7278
7291
|
}
|
|
7279
7292
|
const tool = {
|
|
7280
7293
|
definition: DBX_FORM_SCAFFOLD_TOOL,
|
|
7281
|
-
run
|
|
7294
|
+
run: run5
|
|
7282
7295
|
};
|
|
7283
7296
|
return tool;
|
|
7284
7297
|
}
|
|
@@ -7539,7 +7552,7 @@ function formatNotFound3(normalized, candidates) {
|
|
|
7539
7552
|
}
|
|
7540
7553
|
function createLookupUiTool(input) {
|
|
7541
7554
|
const { registry } = input;
|
|
7542
|
-
const
|
|
7555
|
+
const run5 = (rawArgs) => {
|
|
7543
7556
|
let args;
|
|
7544
7557
|
try {
|
|
7545
7558
|
args = parseLookupUiArgs(rawArgs);
|
|
@@ -7566,7 +7579,7 @@ function createLookupUiTool(input) {
|
|
|
7566
7579
|
const result = { content: [{ type: "text", text }] };
|
|
7567
7580
|
return result;
|
|
7568
7581
|
};
|
|
7569
|
-
return { definition: DBX_UI_LOOKUP_TOOL, run };
|
|
7582
|
+
return { definition: DBX_UI_LOOKUP_TOOL, run: run5 };
|
|
7570
7583
|
}
|
|
7571
7584
|
|
|
7572
7585
|
// packages/dbx-components-mcp/src/tools/search-ui.tool.ts
|
|
@@ -7748,7 +7761,7 @@ function formatSearchResults2(options) {
|
|
|
7748
7761
|
}
|
|
7749
7762
|
function createSearchUiTool(input) {
|
|
7750
7763
|
const { registry } = input;
|
|
7751
|
-
const
|
|
7764
|
+
const run5 = (rawArgs) => {
|
|
7752
7765
|
let args;
|
|
7753
7766
|
try {
|
|
7754
7767
|
args = parseSearchUiArgs(rawArgs);
|
|
@@ -7763,7 +7776,7 @@ function createSearchUiTool(input) {
|
|
|
7763
7776
|
const result = { content: [{ type: "text", text }] };
|
|
7764
7777
|
return result;
|
|
7765
7778
|
};
|
|
7766
|
-
return { definition: DBX_UI_SEARCH_TOOL, run };
|
|
7779
|
+
return { definition: DBX_UI_SEARCH_TOOL, run: run5 };
|
|
7767
7780
|
}
|
|
7768
7781
|
|
|
7769
7782
|
// packages/dbx-components-mcp/src/tools/ui-examples.tool.ts
|
|
@@ -8952,7 +8965,7 @@ var FolderValidateArgsType = type29({
|
|
|
8952
8965
|
});
|
|
8953
8966
|
function createFolderValidateTool(config) {
|
|
8954
8967
|
const { definition, inspectFolder: inspectFolder3, validate, format } = config;
|
|
8955
|
-
async function
|
|
8968
|
+
async function run5(rawArgs) {
|
|
8956
8969
|
const parsed = FolderValidateArgsType(rawArgs);
|
|
8957
8970
|
if (parsed instanceof type29.errors) {
|
|
8958
8971
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
@@ -8992,7 +9005,7 @@ function createFolderValidateTool(config) {
|
|
|
8992
9005
|
};
|
|
8993
9006
|
return toolResult;
|
|
8994
9007
|
}
|
|
8995
|
-
const tool = { definition, run };
|
|
9008
|
+
const tool = { definition, run: run5 };
|
|
8996
9009
|
return tool;
|
|
8997
9010
|
}
|
|
8998
9011
|
var SourceValidateArgsType = type29({
|
|
@@ -9002,7 +9015,7 @@ var SourceValidateArgsType = type29({
|
|
|
9002
9015
|
});
|
|
9003
9016
|
function createSourceValidateTool(config) {
|
|
9004
9017
|
const { definition, validate, format } = config;
|
|
9005
|
-
async function
|
|
9018
|
+
async function run5(rawArgs) {
|
|
9006
9019
|
const parsed = SourceValidateArgsType(rawArgs);
|
|
9007
9020
|
if (parsed instanceof type29.errors) {
|
|
9008
9021
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
@@ -9029,7 +9042,7 @@ function createSourceValidateTool(config) {
|
|
|
9029
9042
|
};
|
|
9030
9043
|
return toolResult;
|
|
9031
9044
|
}
|
|
9032
|
-
const tool = { definition, run };
|
|
9045
|
+
const tool = { definition, run: run5 };
|
|
9033
9046
|
return tool;
|
|
9034
9047
|
}
|
|
9035
9048
|
var TwoSideValidateArgsType = type29({
|
|
@@ -9056,7 +9069,7 @@ function resolveTwoSideInput(parsed) {
|
|
|
9056
9069
|
}
|
|
9057
9070
|
function createTwoSideValidateTool(config) {
|
|
9058
9071
|
const { definition, inspectAndValidate, format } = config;
|
|
9059
|
-
async function
|
|
9072
|
+
async function run5(rawArgs) {
|
|
9060
9073
|
const parsed = TwoSideValidateArgsType(rawArgs);
|
|
9061
9074
|
if (parsed instanceof type29.errors) {
|
|
9062
9075
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
@@ -9073,7 +9086,7 @@ function createTwoSideValidateTool(config) {
|
|
|
9073
9086
|
};
|
|
9074
9087
|
return toolResult;
|
|
9075
9088
|
}
|
|
9076
|
-
const tool = { definition, run };
|
|
9089
|
+
const tool = { definition, run: run5 };
|
|
9077
9090
|
return tool;
|
|
9078
9091
|
}
|
|
9079
9092
|
var ListAppArgsType = type29({
|
|
@@ -9083,7 +9096,7 @@ var ListAppArgsType = type29({
|
|
|
9083
9096
|
});
|
|
9084
9097
|
function createListAppTool(config) {
|
|
9085
9098
|
const { definition, inspectAndList, formatMarkdown, formatJson } = config;
|
|
9086
|
-
async function
|
|
9099
|
+
async function run5(rawArgs) {
|
|
9087
9100
|
const parsed = ListAppArgsType(rawArgs);
|
|
9088
9101
|
if (parsed instanceof type29.errors) {
|
|
9089
9102
|
return toolError(`Invalid arguments: ${parsed.summary}`);
|
|
@@ -9097,7 +9110,7 @@ function createListAppTool(config) {
|
|
|
9097
9110
|
const toolResult = { content: [{ type: "text", text }] };
|
|
9098
9111
|
return toolResult;
|
|
9099
9112
|
}
|
|
9100
|
-
const tool = { definition, run };
|
|
9113
|
+
const tool = { definition, run: run5 };
|
|
9101
9114
|
return tool;
|
|
9102
9115
|
}
|
|
9103
9116
|
|
|
@@ -9290,6 +9303,7 @@ function extractModel(sourceFile, identity) {
|
|
|
9290
9303
|
const collectionFnName = variant === "root" ? `${camelName}FirestoreCollection` : `${camelName}FirestoreCollectionFactory`;
|
|
9291
9304
|
const collectionFn = findFunction(sourceFile, collectionFnName);
|
|
9292
9305
|
const collectionGroupFn = variant === "subcollection" ? findFunction(sourceFile, `${camelName}FirestoreCollectionGroup`) : void 0;
|
|
9306
|
+
const factoryCallKind = detectFactoryCallKind(sourceFile, collectionFnName);
|
|
9293
9307
|
const extractedIdentity = {
|
|
9294
9308
|
constName: identity.constName,
|
|
9295
9309
|
exported: identity.exported,
|
|
@@ -9314,10 +9328,38 @@ function extractModel(sourceFile, identity) {
|
|
|
9314
9328
|
collectionFactoryType,
|
|
9315
9329
|
collectionGroupType,
|
|
9316
9330
|
collectionFn,
|
|
9317
|
-
collectionGroupFn
|
|
9331
|
+
collectionGroupFn,
|
|
9332
|
+
factoryCallKind
|
|
9318
9333
|
};
|
|
9319
9334
|
return result;
|
|
9320
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
|
+
}
|
|
9321
9363
|
function deriveCamelName(constName) {
|
|
9322
9364
|
const suffix = "Identity";
|
|
9323
9365
|
return constName.endsWith(suffix) ? constName.slice(0, -suffix.length) : constName;
|
|
@@ -9784,21 +9826,37 @@ function checkCollectionType(file, model, violations) {
|
|
|
9784
9826
|
return;
|
|
9785
9827
|
}
|
|
9786
9828
|
const typeText = model.collectionType.typeText ?? "";
|
|
9787
|
-
|
|
9788
|
-
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
}
|
|
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
|
+
});
|
|
9798
9840
|
return;
|
|
9799
9841
|
}
|
|
9800
|
-
const
|
|
9801
|
-
|
|
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);
|
|
9802
9860
|
if (typeText.replaceAll(/\s+/g, "") !== expected.replaceAll(/\s+/g, "")) {
|
|
9803
9861
|
pushViolation(violations, {
|
|
9804
9862
|
code: "MODEL_COLLECTION_TYPE_WRONG_GENERIC",
|
|
@@ -9809,6 +9867,45 @@ function checkCollectionType(file, model, violations) {
|
|
|
9809
9867
|
});
|
|
9810
9868
|
}
|
|
9811
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
|
+
}
|
|
9812
9909
|
function checkCollectionFn(file, model, violations) {
|
|
9813
9910
|
if (model.collectionFn) {
|
|
9814
9911
|
return;
|
|
@@ -11011,11 +11108,11 @@ function checkReadonlyFields(file, violations) {
|
|
|
11011
11108
|
}
|
|
11012
11109
|
}
|
|
11013
11110
|
function checkInterfaceReadonly(options) {
|
|
11014
|
-
const { file, decl, code:
|
|
11111
|
+
const { file, decl, code: code11, violations } = options;
|
|
11015
11112
|
for (const field of decl.fields) {
|
|
11016
11113
|
if (field.readonly) continue;
|
|
11017
11114
|
pushViolation2(violations, {
|
|
11018
|
-
code:
|
|
11115
|
+
code: code11,
|
|
11019
11116
|
severity: "warning",
|
|
11020
11117
|
message: `Field \`${field.name}\` on \`${decl.name}\` should be declared \`readonly\`.`,
|
|
11021
11118
|
file: file.name,
|
|
@@ -11347,8 +11444,8 @@ async function inspectFolder(path) {
|
|
|
11347
11444
|
status = "not-directory";
|
|
11348
11445
|
}
|
|
11349
11446
|
} catch (err) {
|
|
11350
|
-
const
|
|
11351
|
-
if (
|
|
11447
|
+
const code11 = err.code;
|
|
11448
|
+
if (code11 === "ENOENT" || code11 === "ENOTDIR") {
|
|
11352
11449
|
status = "not-found";
|
|
11353
11450
|
} else {
|
|
11354
11451
|
throw err;
|
|
@@ -11915,140 +12012,1700 @@ function systemStateAccessorBody(args) {
|
|
|
11915
12012
|
if (args.functionsClass !== void 0) {
|
|
11916
12013
|
lines.push(` readonly ${functionsFieldName(args.functionsClass)} = inject(${args.functionsClass});`, "");
|
|
11917
12014
|
}
|
|
11918
|
-
lines.push(` constructor() {`, ` super(${typeConst});`, ` }`);
|
|
11919
|
-
const crudLines = renderCrudLines(args, "this.systemStateDocumentStore");
|
|
11920
|
-
if (crudLines.length > 0) {
|
|
11921
|
-
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}`);
|
|
11922
13569
|
}
|
|
11923
|
-
lines.push(
|
|
11924
|
-
|
|
11925
|
-
}
|
|
11926
|
-
|
|
11927
|
-
const
|
|
11928
|
-
|
|
11929
|
-
const directiveClass = `${args.appPrefixPascal}${args.modelName}DocumentStoreDirective`;
|
|
11930
|
-
const selector = `[${args.appPrefixCamel}${args.modelName}Document]`;
|
|
11931
|
-
const lines = [
|
|
11932
|
-
`import { Directive, inject } from '@angular/core';`,
|
|
11933
|
-
`import { DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';`,
|
|
11934
|
-
`import { type ${args.modelName}, type ${docType} } from '${args.firebasePackage}';`,
|
|
11935
|
-
`import { ${storeClass} } from './${args.fileBaseName}.document.store';`,
|
|
11936
|
-
"",
|
|
11937
|
-
`@Directive({`,
|
|
11938
|
-
` selector: '${selector}',`,
|
|
11939
|
-
` providers: provideDbxFirebaseDocumentStoreDirective(${directiveClass}, ${storeClass}),`,
|
|
11940
|
-
` standalone: true`,
|
|
11941
|
-
`})`,
|
|
11942
|
-
`export class ${directiveClass} extends DbxFirebaseDocumentStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
|
|
11943
|
-
` constructor() {`,
|
|
11944
|
-
` super(inject(${storeClass}));`,
|
|
11945
|
-
` }`,
|
|
11946
|
-
`}`
|
|
11947
|
-
];
|
|
11948
|
-
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;
|
|
11949
13576
|
}
|
|
11950
|
-
function
|
|
11951
|
-
const
|
|
11952
|
-
const
|
|
11953
|
-
|
|
11954
|
-
|
|
11955
|
-
|
|
11956
|
-
|
|
11957
|
-
|
|
11958
|
-
|
|
11959
|
-
|
|
11960
|
-
"",
|
|
11961
|
-
`@Directive({`,
|
|
11962
|
-
` selector: '${selector}',`,
|
|
11963
|
-
` providers: provideDbxFirebaseCollectionStoreDirective(${directiveClass}, ${storeClass}),`,
|
|
11964
|
-
` standalone: true`,
|
|
11965
|
-
`})`,
|
|
11966
|
-
`export class ${directiveClass} extends DbxFirebaseCollectionStoreDirective<${args.modelName}, ${docType}, ${storeClass}> {`,
|
|
11967
|
-
` constructor() {`,
|
|
11968
|
-
` super(inject(${storeClass}));`,
|
|
11969
|
-
` }`,
|
|
11970
|
-
`}`
|
|
11971
|
-
];
|
|
11972
|
-
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)];
|
|
11973
13587
|
}
|
|
11974
|
-
|
|
11975
|
-
|
|
11976
|
-
|
|
11977
|
-
|
|
11978
|
-
|
|
11979
|
-
|
|
11980
|
-
|
|
11981
|
-
|
|
11982
|
-
|
|
11983
|
-
|
|
11984
|
-
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
11989
|
-
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
|
|
11997
|
-
}
|
|
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."
|
|
11998
13611
|
}
|
|
11999
|
-
}
|
|
13612
|
+
},
|
|
13613
|
+
required: ["apiDir", "model"]
|
|
12000
13614
|
}
|
|
12001
|
-
|
|
12002
|
-
|
|
12003
|
-
|
|
12004
|
-
|
|
12005
|
-
|
|
12006
|
-
const functionsLabel = args.functionsClass ?? "none";
|
|
12007
|
-
const crudLabel = args.crudFunctions.length > 0 ? args.crudFunctions.map((c) => `${c.name} (${c.kind})`).join(", ") : "none";
|
|
12008
|
-
const parentLabel = args.parentModel === void 0 ? "n/a" : args.parentModel.name;
|
|
12009
|
-
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/\`.`, ""];
|
|
12010
|
-
for (const block of blocks) {
|
|
12011
|
-
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}`);
|
|
12012
13620
|
}
|
|
12013
|
-
|
|
12014
|
-
|
|
12015
|
-
|
|
13621
|
+
const cwd = process.cwd();
|
|
13622
|
+
try {
|
|
13623
|
+
ensurePathInsideCwd(parsed.apiDir, cwd);
|
|
13624
|
+
} catch (err) {
|
|
13625
|
+
return toolError(toErrorMessage(err));
|
|
12016
13626
|
}
|
|
12017
|
-
|
|
12018
|
-
|
|
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)}`);
|
|
12019
13633
|
}
|
|
12020
|
-
|
|
12021
|
-
|
|
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}.`);
|
|
12022
13638
|
}
|
|
12023
|
-
|
|
12024
|
-
|
|
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) }] };
|
|
12025
13649
|
}
|
|
12026
|
-
function
|
|
12027
|
-
|
|
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;
|
|
12028
13656
|
try {
|
|
12029
|
-
|
|
13657
|
+
sourceFile = project.addSourceFileAtPath(absolutePath);
|
|
12030
13658
|
} catch (err) {
|
|
12031
|
-
|
|
12032
|
-
return toolError(message);
|
|
13659
|
+
return `Failed to load fixture file: ${toErrorMessage(err)}`;
|
|
12033
13660
|
}
|
|
12034
|
-
const
|
|
12035
|
-
|
|
12036
|
-
|
|
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;
|
|
12037
13675
|
}
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
|
|
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 };
|
|
12042
13699
|
|
|
12043
13700
|
// packages/dbx-components-mcp/src/tools/storagefile-m-validate-app/extract.ts
|
|
12044
|
-
import { Node as
|
|
13701
|
+
import { Node as Node10, SyntaxKind as SyntaxKind7 } from "ts-morph";
|
|
12045
13702
|
|
|
12046
13703
|
// packages/dbx-components-mcp/src/tools/_validate/ast.ts
|
|
12047
|
-
import { Node as
|
|
13704
|
+
import { Node as Node9, Project as Project8, SyntaxKind as SyntaxKind6 } from "ts-morph";
|
|
12048
13705
|
var COMPONENT_VIRTUAL_PREFIX = "__component__/";
|
|
12049
13706
|
var API_VIRTUAL_PREFIX = "__api__/";
|
|
12050
13707
|
function buildInMemoryProject(input) {
|
|
12051
|
-
const project = new
|
|
13708
|
+
const project = new Project8({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
12052
13709
|
const componentSources = [];
|
|
12053
13710
|
const apiSources = [];
|
|
12054
13711
|
for (const file of input.component.files) {
|
|
@@ -12068,28 +13725,28 @@ function componentRelPath(sourceFile) {
|
|
|
12068
13725
|
}
|
|
12069
13726
|
function unwrapAsExpressions(node) {
|
|
12070
13727
|
let current = node;
|
|
12071
|
-
while (current &&
|
|
13728
|
+
while (current && Node9.isAsExpression(current)) {
|
|
12072
13729
|
current = current.getExpression();
|
|
12073
13730
|
}
|
|
12074
13731
|
return current;
|
|
12075
13732
|
}
|
|
12076
13733
|
function asObjectLiteral(node) {
|
|
12077
13734
|
const inner = unwrapAsExpressions(node);
|
|
12078
|
-
if (inner &&
|
|
13735
|
+
if (inner && Node9.isObjectLiteralExpression(inner)) {
|
|
12079
13736
|
return inner;
|
|
12080
13737
|
}
|
|
12081
13738
|
return void 0;
|
|
12082
13739
|
}
|
|
12083
13740
|
function asArrayLiteral(node) {
|
|
12084
13741
|
const inner = unwrapAsExpressions(node);
|
|
12085
|
-
if (inner &&
|
|
13742
|
+
if (inner && Node9.isArrayLiteralExpression(inner)) {
|
|
12086
13743
|
return inner;
|
|
12087
13744
|
}
|
|
12088
13745
|
return void 0;
|
|
12089
13746
|
}
|
|
12090
13747
|
function readStringLiteralInitializer(decl) {
|
|
12091
13748
|
const initializer = unwrapAsExpressions(decl.getInitializer());
|
|
12092
|
-
if (initializer &&
|
|
13749
|
+
if (initializer && Node9.isStringLiteral(initializer)) {
|
|
12093
13750
|
return initializer.getLiteralText();
|
|
12094
13751
|
}
|
|
12095
13752
|
return void 0;
|
|
@@ -12101,37 +13758,37 @@ function typeAnnotationText(node) {
|
|
|
12101
13758
|
function getPropertyInitializer(obj, name) {
|
|
12102
13759
|
const prop = obj.getProperty(name);
|
|
12103
13760
|
if (!prop) return void 0;
|
|
12104
|
-
if (
|
|
13761
|
+
if (Node9.isPropertyAssignment(prop)) {
|
|
12105
13762
|
return prop.getInitializer();
|
|
12106
13763
|
}
|
|
12107
|
-
if (
|
|
13764
|
+
if (Node9.isShorthandPropertyAssignment(prop)) {
|
|
12108
13765
|
return prop.getNameNode();
|
|
12109
13766
|
}
|
|
12110
13767
|
return void 0;
|
|
12111
13768
|
}
|
|
12112
13769
|
function readStringProperty2(obj, name) {
|
|
12113
13770
|
const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
|
|
12114
|
-
if (init &&
|
|
13771
|
+
if (init && Node9.isStringLiteral(init)) {
|
|
12115
13772
|
return init.getLiteralText();
|
|
12116
13773
|
}
|
|
12117
13774
|
return void 0;
|
|
12118
13775
|
}
|
|
12119
13776
|
function readIdentifierProperty(obj, name) {
|
|
12120
13777
|
const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
|
|
12121
|
-
if (init &&
|
|
13778
|
+
if (init && Node9.isIdentifier(init)) {
|
|
12122
13779
|
return init.getText();
|
|
12123
13780
|
}
|
|
12124
13781
|
return void 0;
|
|
12125
13782
|
}
|
|
12126
13783
|
function findReturnExpression(fn) {
|
|
12127
|
-
if (!
|
|
13784
|
+
if (!Node9.isArrowFunction(fn) && !Node9.isFunctionDeclaration(fn) && !Node9.isFunctionExpression(fn)) {
|
|
12128
13785
|
return void 0;
|
|
12129
13786
|
}
|
|
12130
13787
|
const body = fn.getBody();
|
|
12131
13788
|
if (!body) return void 0;
|
|
12132
|
-
if (
|
|
13789
|
+
if (Node9.isBlock(body)) {
|
|
12133
13790
|
for (const stmt of body.getStatements()) {
|
|
12134
|
-
if (
|
|
13791
|
+
if (Node9.isReturnStatement(stmt)) {
|
|
12135
13792
|
return stmt.getExpression();
|
|
12136
13793
|
}
|
|
12137
13794
|
}
|
|
@@ -12145,17 +13802,17 @@ function findLocalVariable(sf, name) {
|
|
|
12145
13802
|
if (decl.getName() === name) return decl;
|
|
12146
13803
|
}
|
|
12147
13804
|
}
|
|
12148
|
-
for (const decl of sf.getDescendantsOfKind(
|
|
13805
|
+
for (const decl of sf.getDescendantsOfKind(SyntaxKind6.VariableDeclaration)) {
|
|
12149
13806
|
if (decl.getName() === name) return decl;
|
|
12150
13807
|
}
|
|
12151
13808
|
return void 0;
|
|
12152
13809
|
}
|
|
12153
13810
|
function collectTypeofReferences(node, out) {
|
|
12154
|
-
if (
|
|
13811
|
+
if (Node9.isTypeQuery(node)) {
|
|
12155
13812
|
out.push(node.getExprName().getText());
|
|
12156
13813
|
return;
|
|
12157
13814
|
}
|
|
12158
|
-
for (const tq of node.getDescendantsOfKind(
|
|
13815
|
+
for (const tq of node.getDescendantsOfKind(SyntaxKind6.TypeQuery)) {
|
|
12159
13816
|
out.push(tq.getExprName().getText());
|
|
12160
13817
|
}
|
|
12161
13818
|
}
|
|
@@ -12308,7 +13965,7 @@ function filterMaybeArrayFunction(filterFn) {
|
|
|
12308
13965
|
return ((values) => {
|
|
12309
13966
|
let result;
|
|
12310
13967
|
if (values != null) {
|
|
12311
|
-
result = values.filter(filterFn);
|
|
13968
|
+
result = values.filter((v, i, arr) => filterFn(v, i, arr));
|
|
12312
13969
|
} else {
|
|
12313
13970
|
result = [];
|
|
12314
13971
|
}
|
|
@@ -12419,7 +14076,7 @@ function booleanKeyArrayUtility(readKey) {
|
|
|
12419
14076
|
removeByKey
|
|
12420
14077
|
};
|
|
12421
14078
|
}
|
|
12422
|
-
var BooleanStringKeyArrayUtility = booleanKeyArrayUtility((x) => x
|
|
14079
|
+
var BooleanStringKeyArrayUtility = booleanKeyArrayUtility((x) => x || void 0);
|
|
12423
14080
|
|
|
12424
14081
|
// packages/util/src/lib/set/set.selection.ts
|
|
12425
14082
|
function isSelectedDecisionFunctionFactory(config) {
|
|
@@ -12453,8 +14110,8 @@ function getFunctionType(x) {
|
|
|
12453
14110
|
return typeof x === "function" ? x.prototype ? Object.getOwnPropertyDescriptor(x, "prototype")?.writable ? "function" : "class" : x.constructor.name === "AsyncFunction" ? "function" : "arrow" : null;
|
|
12454
14111
|
}
|
|
12455
14112
|
function isNonClassFunction(x) {
|
|
12456
|
-
const
|
|
12457
|
-
return
|
|
14113
|
+
const type48 = getFunctionType(x);
|
|
14114
|
+
return type48 != null && type48 !== "class";
|
|
12458
14115
|
}
|
|
12459
14116
|
|
|
12460
14117
|
// packages/util/src/lib/getter/getter.ts
|
|
@@ -12531,9 +14188,9 @@ function asNumber(input) {
|
|
|
12531
14188
|
}
|
|
12532
14189
|
|
|
12533
14190
|
// packages/util/src/lib/number/round.ts
|
|
12534
|
-
function roundingFunction(
|
|
14191
|
+
function roundingFunction(type48) {
|
|
12535
14192
|
let fn;
|
|
12536
|
-
switch (
|
|
14193
|
+
switch (type48) {
|
|
12537
14194
|
case "floor":
|
|
12538
14195
|
fn = Math.floor;
|
|
12539
14196
|
break;
|
|
@@ -12771,7 +14428,7 @@ function filterKeyValueTuplesFunction(filter) {
|
|
|
12771
14428
|
if (filter != null) {
|
|
12772
14429
|
const filterFn = filterKeyValueTupleFunction(filter);
|
|
12773
14430
|
result = (obj) => {
|
|
12774
|
-
return allKeyValueTuples(obj).filter(filterFn);
|
|
14431
|
+
return allKeyValueTuples(obj).filter((kv, i) => filterFn(kv, i));
|
|
12775
14432
|
};
|
|
12776
14433
|
} else {
|
|
12777
14434
|
result = allKeyValueTuples;
|
|
@@ -12786,9 +14443,9 @@ function filterKeyValueTuplesInputToFilter(input) {
|
|
|
12786
14443
|
}
|
|
12787
14444
|
function filterKeyValueTupleFunction(inputFilter) {
|
|
12788
14445
|
const filter = filterKeyValueTuplesInputToFilter(inputFilter);
|
|
12789
|
-
const { valueFilter:
|
|
14446
|
+
const { valueFilter: type48 = 1 /* UNDEFINED */, invertFilter: inverseFilter = false, keysFilter } = filter;
|
|
12790
14447
|
let filterFn;
|
|
12791
|
-
switch (
|
|
14448
|
+
switch (type48) {
|
|
12792
14449
|
case 1 /* UNDEFINED */:
|
|
12793
14450
|
filterFn = ([, x]) => x !== void 0;
|
|
12794
14451
|
break;
|
|
@@ -13047,7 +14704,7 @@ var NUMBER_STRING_DENCODER_64_DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcd
|
|
|
13047
14704
|
var NUMBER_STRING_DENCODER_64_DEFAULT_NEGATIVE_PREFIX = "!";
|
|
13048
14705
|
function numberStringDencoder(config) {
|
|
13049
14706
|
const { negativePrefix, digits } = config;
|
|
13050
|
-
const
|
|
14707
|
+
const type48 = negativePrefix ? "integer" : "positive_integer";
|
|
13051
14708
|
const log2OfDigits = Math.min(6, Math.floor(Math.log2(digits.length)));
|
|
13052
14709
|
const bitDepth = Math.pow(2, log2OfDigits);
|
|
13053
14710
|
const bitMask = bitDepth - 1;
|
|
@@ -13084,7 +14741,7 @@ function numberStringDencoder(config) {
|
|
|
13084
14741
|
return result;
|
|
13085
14742
|
}
|
|
13086
14743
|
return {
|
|
13087
|
-
type:
|
|
14744
|
+
type: type48,
|
|
13088
14745
|
digits,
|
|
13089
14746
|
bitDepth,
|
|
13090
14747
|
negativePrefix,
|
|
@@ -13155,9 +14812,9 @@ function readableStreamToStringFunction(encoding) {
|
|
|
13155
14812
|
var readableStreamToBase64 = readableStreamToStringFunction("base64");
|
|
13156
14813
|
function readableStreamToBuffer(stream) {
|
|
13157
14814
|
const chunks = [];
|
|
13158
|
-
return new Promise((
|
|
14815
|
+
return new Promise((resolve22, reject) => {
|
|
13159
14816
|
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
13160
|
-
stream.on("end", () =>
|
|
14817
|
+
stream.on("end", () => resolve22(Buffer.concat(chunks)));
|
|
13161
14818
|
stream.on("error", reject);
|
|
13162
14819
|
});
|
|
13163
14820
|
}
|
|
@@ -13580,7 +15237,7 @@ function extractUploadInitializerEntries(sources) {
|
|
|
13580
15237
|
const out = [];
|
|
13581
15238
|
for (const sf of sources) {
|
|
13582
15239
|
const rel = apiRelPath(sf);
|
|
13583
|
-
for (const decl of sf.getDescendantsOfKind(
|
|
15240
|
+
for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
|
|
13584
15241
|
const typeText = typeAnnotationText(decl);
|
|
13585
15242
|
if (typeText !== UPLOAD_SERVICE_INITIALIZER_TYPE) continue;
|
|
13586
15243
|
const obj = asObjectLiteral(decl.getInitializer());
|
|
@@ -13610,7 +15267,7 @@ function buildApiFunctionIndex(sources) {
|
|
|
13610
15267
|
for (const decl of stmt.getDeclarations()) {
|
|
13611
15268
|
const initializer = unwrapAsExpressions(decl.getInitializer());
|
|
13612
15269
|
if (!initializer) continue;
|
|
13613
|
-
if (
|
|
15270
|
+
if (Node10.isArrowFunction(initializer) || Node10.isFunctionExpression(initializer)) {
|
|
13614
15271
|
map.set(decl.getName(), { node: initializer, sourceFile: sf });
|
|
13615
15272
|
}
|
|
13616
15273
|
}
|
|
@@ -13623,34 +15280,34 @@ function collectInitializerBindingsFromValue(options) {
|
|
|
13623
15280
|
const { node, sf, index, resolved, unresolved, visited } = options;
|
|
13624
15281
|
const inner = unwrapAsExpressions(node);
|
|
13625
15282
|
if (!inner) return false;
|
|
13626
|
-
if (
|
|
15283
|
+
if (Node10.isArrayLiteralExpression(inner)) {
|
|
13627
15284
|
for (const el of inner.getElements()) {
|
|
13628
|
-
if (
|
|
15285
|
+
if (Node10.isSpreadElement(el)) {
|
|
13629
15286
|
const spreadInner = el.getExpression();
|
|
13630
|
-
if (
|
|
15287
|
+
if (Node10.isIdentifier(spreadInner)) {
|
|
13631
15288
|
collectInitializerBindingsFromIdentifier({ name: spreadInner.getText(), sf, index, resolved, unresolved, visited });
|
|
13632
|
-
} else if (
|
|
15289
|
+
} else if (Node10.isCallExpression(spreadInner)) {
|
|
13633
15290
|
const callee = spreadInner.getExpression();
|
|
13634
|
-
if (
|
|
15291
|
+
if (Node10.isIdentifier(callee)) {
|
|
13635
15292
|
collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
|
|
13636
15293
|
}
|
|
13637
15294
|
}
|
|
13638
15295
|
continue;
|
|
13639
15296
|
}
|
|
13640
15297
|
const elementInner = unwrapAsExpressions(el);
|
|
13641
|
-
if (elementInner &&
|
|
15298
|
+
if (elementInner && Node10.isIdentifier(elementInner)) {
|
|
13642
15299
|
resolved.push(elementInner.getText());
|
|
13643
15300
|
}
|
|
13644
15301
|
}
|
|
13645
15302
|
return true;
|
|
13646
15303
|
}
|
|
13647
|
-
if (
|
|
15304
|
+
if (Node10.isCallExpression(inner)) {
|
|
13648
15305
|
const callee = inner.getExpression();
|
|
13649
|
-
if (
|
|
15306
|
+
if (Node10.isIdentifier(callee)) {
|
|
13650
15307
|
return collectInitializerBindingsFromIdentifier({ name: callee.getText(), sf, index, resolved, unresolved, visited });
|
|
13651
15308
|
}
|
|
13652
15309
|
}
|
|
13653
|
-
if (
|
|
15310
|
+
if (Node10.isIdentifier(inner)) {
|
|
13654
15311
|
return collectInitializerBindingsFromIdentifier({ name: inner.getText(), sf, index, resolved, unresolved, visited });
|
|
13655
15312
|
}
|
|
13656
15313
|
return false;
|
|
@@ -13689,15 +15346,15 @@ function collectUploadInitializerArray(options) {
|
|
|
13689
15346
|
const { initializerArr, sf, index, direct, spreads, resolved, unresolved } = options;
|
|
13690
15347
|
const visited = /* @__PURE__ */ new Set();
|
|
13691
15348
|
for (const el of initializerArr.getElements()) {
|
|
13692
|
-
if (
|
|
15349
|
+
if (Node10.isSpreadElement(el)) {
|
|
13693
15350
|
const inner2 = el.getExpression();
|
|
13694
|
-
if (
|
|
15351
|
+
if (Node10.isIdentifier(inner2)) {
|
|
13695
15352
|
const name = inner2.getText();
|
|
13696
15353
|
spreads.push(name);
|
|
13697
15354
|
collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
|
|
13698
|
-
} else if (
|
|
15355
|
+
} else if (Node10.isCallExpression(inner2)) {
|
|
13699
15356
|
const callee = inner2.getExpression();
|
|
13700
|
-
if (
|
|
15357
|
+
if (Node10.isIdentifier(callee)) {
|
|
13701
15358
|
const name = callee.getText();
|
|
13702
15359
|
spreads.push(name);
|
|
13703
15360
|
collectInitializerBindingsFromIdentifier({ name, sf, index, resolved, unresolved, visited });
|
|
@@ -13706,7 +15363,7 @@ function collectUploadInitializerArray(options) {
|
|
|
13706
15363
|
continue;
|
|
13707
15364
|
}
|
|
13708
15365
|
const inner = unwrapAsExpressions(el);
|
|
13709
|
-
if (inner &&
|
|
15366
|
+
if (inner && Node10.isIdentifier(inner)) {
|
|
13710
15367
|
const name = inner.getText();
|
|
13711
15368
|
direct.push(name);
|
|
13712
15369
|
resolved.push(name);
|
|
@@ -13717,9 +15374,9 @@ function extractUploadServiceCalls(sources, index) {
|
|
|
13717
15374
|
const out = [];
|
|
13718
15375
|
for (const sf of sources) {
|
|
13719
15376
|
const rel = apiRelPath(sf);
|
|
13720
|
-
for (const call of sf.getDescendantsOfKind(
|
|
15377
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
|
|
13721
15378
|
const expr = call.getExpression();
|
|
13722
|
-
if (!
|
|
15379
|
+
if (!Node10.isIdentifier(expr) || expr.getText() !== UPLOAD_SERVICE_FACTORY) continue;
|
|
13723
15380
|
const args = call.getArguments();
|
|
13724
15381
|
const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
|
|
13725
15382
|
if (!first) continue;
|
|
@@ -13747,12 +15404,12 @@ function extractUploadServiceCalls(sources, index) {
|
|
|
13747
15404
|
function resolveObjectArg(node, sf) {
|
|
13748
15405
|
const inner = unwrapAsExpressions(node);
|
|
13749
15406
|
if (!inner) return void 0;
|
|
13750
|
-
if (
|
|
13751
|
-
if (
|
|
15407
|
+
if (Node10.isObjectLiteralExpression(inner)) return inner;
|
|
15408
|
+
if (Node10.isIdentifier(inner)) {
|
|
13752
15409
|
const declNode = findLocalVariable(sf, inner.getText());
|
|
13753
15410
|
if (declNode) {
|
|
13754
15411
|
const declInit = unwrapAsExpressions(declNode.getInitializer());
|
|
13755
|
-
if (declInit &&
|
|
15412
|
+
if (declInit && Node10.isObjectLiteralExpression(declInit)) {
|
|
13756
15413
|
return declInit;
|
|
13757
15414
|
}
|
|
13758
15415
|
}
|
|
@@ -13762,12 +15419,12 @@ function resolveObjectArg(node, sf) {
|
|
|
13762
15419
|
function resolveArrayFromProperty(obj, name, sf) {
|
|
13763
15420
|
const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
|
|
13764
15421
|
if (!init) return void 0;
|
|
13765
|
-
if (
|
|
13766
|
-
if (
|
|
15422
|
+
if (Node10.isArrayLiteralExpression(init)) return init;
|
|
15423
|
+
if (Node10.isIdentifier(init)) {
|
|
13767
15424
|
const declNode = findLocalVariable(sf, init.getText());
|
|
13768
15425
|
if (declNode) {
|
|
13769
15426
|
const declInit = unwrapAsExpressions(declNode.getInitializer());
|
|
13770
|
-
if (declInit &&
|
|
15427
|
+
if (declInit && Node10.isArrayLiteralExpression(declInit)) {
|
|
13771
15428
|
return declInit;
|
|
13772
15429
|
}
|
|
13773
15430
|
}
|
|
@@ -13778,11 +15435,11 @@ function enclosingFactoryName(node) {
|
|
|
13778
15435
|
let current = node.getParent();
|
|
13779
15436
|
let result;
|
|
13780
15437
|
while (current) {
|
|
13781
|
-
if (
|
|
15438
|
+
if (Node10.isFunctionDeclaration(current)) {
|
|
13782
15439
|
result = current.getName() ?? void 0;
|
|
13783
15440
|
break;
|
|
13784
15441
|
}
|
|
13785
|
-
if (
|
|
15442
|
+
if (Node10.isVariableDeclaration(current)) {
|
|
13786
15443
|
result = current.getName();
|
|
13787
15444
|
break;
|
|
13788
15445
|
}
|
|
@@ -13794,7 +15451,7 @@ function extractUploadServiceWirings(sources) {
|
|
|
13794
15451
|
const out = [];
|
|
13795
15452
|
for (const sf of sources) {
|
|
13796
15453
|
const rel = apiRelPath(sf);
|
|
13797
|
-
for (const obj of sf.getDescendantsOfKind(
|
|
15454
|
+
for (const obj of sf.getDescendantsOfKind(SyntaxKind7.ObjectLiteralExpression)) {
|
|
13798
15455
|
const provideIdent = readIdentifierProperty(obj, "provide");
|
|
13799
15456
|
if (provideIdent !== UPLOAD_SERVICE_PROVIDE_TOKEN) continue;
|
|
13800
15457
|
const useFactory = readIdentifierProperty(obj, "useFactory");
|
|
@@ -13807,7 +15464,7 @@ function extractProcessingConfigs(sources) {
|
|
|
13807
15464
|
const out = [];
|
|
13808
15465
|
for (const sf of sources) {
|
|
13809
15466
|
const rel = apiRelPath(sf);
|
|
13810
|
-
for (const decl of sf.getDescendantsOfKind(
|
|
15467
|
+
for (const decl of sf.getDescendantsOfKind(SyntaxKind7.VariableDeclaration)) {
|
|
13811
15468
|
const config = extractProcessingConfigFromDecl(decl, rel);
|
|
13812
15469
|
if (config) {
|
|
13813
15470
|
out.push(config);
|
|
@@ -13836,10 +15493,10 @@ function extractProcessingConfigFromDecl(decl, rel) {
|
|
|
13836
15493
|
function readFlowSubtasks(obj) {
|
|
13837
15494
|
const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
|
|
13838
15495
|
const subtasks = [];
|
|
13839
|
-
if (flowInit &&
|
|
15496
|
+
if (flowInit && Node10.isArrayLiteralExpression(flowInit)) {
|
|
13840
15497
|
for (const el of flowInit.getElements()) {
|
|
13841
15498
|
const inner = unwrapAsExpressions(el);
|
|
13842
|
-
if (inner &&
|
|
15499
|
+
if (inner && Node10.isObjectLiteralExpression(inner)) {
|
|
13843
15500
|
const subtask = readIdentifierProperty(inner, "subtask");
|
|
13844
15501
|
if (subtask) subtasks.push(subtask);
|
|
13845
15502
|
}
|
|
@@ -13851,9 +15508,9 @@ function extractProcessingHandlerCalls(sources) {
|
|
|
13851
15508
|
const out = [];
|
|
13852
15509
|
for (const sf of sources) {
|
|
13853
15510
|
const rel = apiRelPath(sf);
|
|
13854
|
-
for (const call of sf.getDescendantsOfKind(
|
|
15511
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind7.CallExpression)) {
|
|
13855
15512
|
const expr = call.getExpression();
|
|
13856
|
-
if (!
|
|
15513
|
+
if (!Node10.isIdentifier(expr) || expr.getText() !== PROCESSING_HANDLER_FACTORY) continue;
|
|
13857
15514
|
const args = call.getArguments();
|
|
13858
15515
|
const first = args[0] ? resolveObjectArg(args[0], sf) : void 0;
|
|
13859
15516
|
if (!first) continue;
|
|
@@ -13874,7 +15531,7 @@ function extractProcessingHandlerCalls(sources) {
|
|
|
13874
15531
|
}
|
|
13875
15532
|
function collectProcessorArrayElements(processorsArr, direct, spreads) {
|
|
13876
15533
|
for (const el of processorsArr.getElements()) {
|
|
13877
|
-
if (
|
|
15534
|
+
if (Node10.isSpreadElement(el)) {
|
|
13878
15535
|
addProcessorIdentifierName(el.getExpression(), spreads);
|
|
13879
15536
|
continue;
|
|
13880
15537
|
}
|
|
@@ -13886,13 +15543,13 @@ function collectProcessorArrayElements(processorsArr, direct, spreads) {
|
|
|
13886
15543
|
}
|
|
13887
15544
|
function addProcessorIdentifierName(node, bucket) {
|
|
13888
15545
|
if (!node) return;
|
|
13889
|
-
if (
|
|
15546
|
+
if (Node10.isIdentifier(node)) {
|
|
13890
15547
|
bucket.push(node.getText());
|
|
13891
15548
|
return;
|
|
13892
15549
|
}
|
|
13893
|
-
if (
|
|
15550
|
+
if (Node10.isCallExpression(node)) {
|
|
13894
15551
|
const callee = node.getExpression();
|
|
13895
|
-
if (
|
|
15552
|
+
if (Node10.isIdentifier(callee)) {
|
|
13896
15553
|
bucket.push(callee.getText());
|
|
13897
15554
|
}
|
|
13898
15555
|
}
|
|
@@ -13934,7 +15591,7 @@ function runRules4(inspection, extracted) {
|
|
|
13934
15591
|
violations,
|
|
13935
15592
|
codes: IO_VIOLATION_CODES,
|
|
13936
15593
|
messages: IO_VIOLATION_MESSAGES,
|
|
13937
|
-
build: (
|
|
15594
|
+
build: (code11, message, side) => buildIoViolation(code11, message, side)
|
|
13938
15595
|
});
|
|
13939
15596
|
if (!proceed) {
|
|
13940
15597
|
return violations;
|
|
@@ -14166,18 +15823,18 @@ function checkDuplicates(extracted, violations) {
|
|
|
14166
15823
|
flagDuplicates({ entries: extracted.fileTypeIdentifierConstants.map(toCodeRef), code: "STORAGEFILE_FILE_TYPE_IDENTIFIER_DUPLICATE", label: "`UploadedFileTypeIdentifier`", violations });
|
|
14167
15824
|
}
|
|
14168
15825
|
function toCodeRef(entry) {
|
|
14169
|
-
const
|
|
14170
|
-
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 };
|
|
14171
15828
|
}
|
|
14172
15829
|
function flagDuplicates(options) {
|
|
14173
|
-
const { entries, code:
|
|
15830
|
+
const { entries, code: code11, label, violations } = options;
|
|
14174
15831
|
const seen = /* @__PURE__ */ new Map();
|
|
14175
15832
|
for (const entry of entries) {
|
|
14176
15833
|
if (!entry.code) continue;
|
|
14177
15834
|
const previous = seen.get(entry.code);
|
|
14178
15835
|
if (previous) {
|
|
14179
15836
|
pushViolation4(violations, {
|
|
14180
|
-
code:
|
|
15837
|
+
code: code11,
|
|
14181
15838
|
severity: "warning",
|
|
14182
15839
|
message: `${label} value \`'${entry.code}'\` is shared by \`${previous}\` and \`${entry.symbolName}\`. Choose unique string literals.`,
|
|
14183
15840
|
side: "component",
|
|
@@ -14227,9 +15884,9 @@ function pushViolation4(buffer, violation) {
|
|
|
14227
15884
|
};
|
|
14228
15885
|
buffer.push(filled);
|
|
14229
15886
|
}
|
|
14230
|
-
function buildIoViolation(
|
|
15887
|
+
function buildIoViolation(code11, message, side) {
|
|
14231
15888
|
const result = {
|
|
14232
|
-
code:
|
|
15889
|
+
code: code11,
|
|
14233
15890
|
severity: "error",
|
|
14234
15891
|
message,
|
|
14235
15892
|
side,
|
|
@@ -14245,8 +15902,8 @@ function formatResult4(result) {
|
|
|
14245
15902
|
}
|
|
14246
15903
|
|
|
14247
15904
|
// packages/dbx-components-mcp/src/tools/_validate/inspect.ts
|
|
14248
|
-
import { readdir as readdir2, readFile as
|
|
14249
|
-
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";
|
|
14250
15907
|
async function inspectSide(rootDir, subpaths) {
|
|
14251
15908
|
const rootStatus = await readRootStatus(rootDir);
|
|
14252
15909
|
if (rootStatus !== void 0) {
|
|
@@ -14256,7 +15913,7 @@ async function inspectSide(rootDir, subpaths) {
|
|
|
14256
15913
|
const presentFolders = [];
|
|
14257
15914
|
const collectedFiles = [];
|
|
14258
15915
|
for (const sub of subpaths) {
|
|
14259
|
-
const absFolder =
|
|
15916
|
+
const absFolder = join4(rootDir, sub);
|
|
14260
15917
|
const folderPresent = await isDirectory(absFolder);
|
|
14261
15918
|
if (!folderPresent) continue;
|
|
14262
15919
|
presentFolders.push(sub);
|
|
@@ -14275,8 +15932,8 @@ async function readRootStatus(rootDir) {
|
|
|
14275
15932
|
const stats = await stat3(rootDir);
|
|
14276
15933
|
return stats.isDirectory() ? void 0 : "dir-not-found";
|
|
14277
15934
|
} catch (err) {
|
|
14278
|
-
const
|
|
14279
|
-
if (
|
|
15935
|
+
const code11 = err.code;
|
|
15936
|
+
if (code11 === "ENOENT" || code11 === "ENOTDIR") {
|
|
14280
15937
|
return "dir-not-found";
|
|
14281
15938
|
}
|
|
14282
15939
|
throw err;
|
|
@@ -14302,7 +15959,7 @@ async function collectTsFiles(absFolder, rootDir) {
|
|
|
14302
15959
|
continue;
|
|
14303
15960
|
}
|
|
14304
15961
|
for (const entry of entries) {
|
|
14305
|
-
const full =
|
|
15962
|
+
const full = join4(current, entry.name);
|
|
14306
15963
|
if (entry.isDirectory()) {
|
|
14307
15964
|
stack.push(full);
|
|
14308
15965
|
continue;
|
|
@@ -14311,7 +15968,7 @@ async function collectTsFiles(absFolder, rootDir) {
|
|
|
14311
15968
|
if (!entry.name.endsWith(".ts")) continue;
|
|
14312
15969
|
if (entry.name.endsWith(".spec.ts")) continue;
|
|
14313
15970
|
if (entry.name.endsWith(".d.ts")) continue;
|
|
14314
|
-
const text = await
|
|
15971
|
+
const text = await readFile4(full, "utf8");
|
|
14315
15972
|
const rel = relative4(rootDir, full).split(sep2).join("/");
|
|
14316
15973
|
out.push({ relPath: rel, text });
|
|
14317
15974
|
}
|
|
@@ -14483,7 +16140,7 @@ function formatReportAsJson(report) {
|
|
|
14483
16140
|
// packages/dbx-components-mcp/src/tools/storagefile-m-list-app/format.markdown.ts
|
|
14484
16141
|
function formatReportAsMarkdown(report) {
|
|
14485
16142
|
const basename4 = report.componentDir.split("/").pop() ?? report.componentDir;
|
|
14486
|
-
const uploadServiceFactoryText = report.uploadServiceFactoryName ?
|
|
16143
|
+
const uploadServiceFactoryText = report.uploadServiceFactoryName ? code4(report.uploadServiceFactoryName) : "_Not defined._";
|
|
14487
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})`];
|
|
14488
16145
|
if (report.purposes.length === 0) {
|
|
14489
16146
|
lines.push("", "_None found._");
|
|
@@ -14499,15 +16156,15 @@ function formatPurposeBlock(p) {
|
|
|
14499
16156
|
const heading = p.purposeCode ? `### ${p.purposeCode} \u2014 \`${p.purposeSymbolName}\`` : `### \`${p.purposeSymbolName}\``;
|
|
14500
16157
|
parts.push(heading);
|
|
14501
16158
|
if (p.fileTypeIdentifierCode) {
|
|
14502
|
-
const codePart = p.fileTypeIdentifier ? ` (` +
|
|
16159
|
+
const codePart = p.fileTypeIdentifier ? ` (` + code4(`'${p.fileTypeIdentifier}'`) + `)` : "";
|
|
14503
16160
|
parts.push(`- Uploaded file type identifier: \`${p.fileTypeIdentifierCode}\`${codePart}`);
|
|
14504
16161
|
} else {
|
|
14505
16162
|
parts.push(`- Uploaded file type identifier: _Missing._`);
|
|
14506
16163
|
}
|
|
14507
|
-
const groupIdsText = p.fileGroupIdsFunctionName ?
|
|
16164
|
+
const groupIdsText = p.fileGroupIdsFunctionName ? code4(p.fileGroupIdsFunctionName) : "_Missing._";
|
|
14508
16165
|
parts.push(`- Group-ids helper: ${groupIdsText}`);
|
|
14509
16166
|
if (p.subtasks.length > 0) {
|
|
14510
|
-
const subtasksText = p.subtasks.map((s) =>
|
|
16167
|
+
const subtasksText = p.subtasks.map((s) => code4(s)).join(", ");
|
|
14511
16168
|
parts.push(`- Processing subtasks: ${subtasksText}`);
|
|
14512
16169
|
}
|
|
14513
16170
|
const uploadInitSuffix = p.uploadInitializerSourceFile ? ` _(${p.uploadInitializerSourceFile})_` : "";
|
|
@@ -14518,7 +16175,7 @@ function formatPurposeBlock(p) {
|
|
|
14518
16175
|
function formatBool(value) {
|
|
14519
16176
|
return value ? "yes" : "no";
|
|
14520
16177
|
}
|
|
14521
|
-
function
|
|
16178
|
+
function code4(value) {
|
|
14522
16179
|
return "`" + value + "`";
|
|
14523
16180
|
}
|
|
14524
16181
|
|
|
@@ -14564,8 +16221,8 @@ var storageFileMListAppTool = createListAppTool({
|
|
|
14564
16221
|
});
|
|
14565
16222
|
|
|
14566
16223
|
// packages/dbx-components-mcp/src/tools/validate-two-side-folder.ts
|
|
14567
|
-
import { readdir as readdir3, readFile as
|
|
14568
|
-
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";
|
|
14569
16226
|
var REEXPORT_PATTERN = /^\s*export\s+\*\s+from\s+['"]\.\/([^'"\n]+)['"]\s*;?\s*$/gm;
|
|
14570
16227
|
function createTwoSideFolderValidator(config) {
|
|
14571
16228
|
async function inspect(input) {
|
|
@@ -14609,7 +16266,7 @@ async function inspectSide2(input) {
|
|
|
14609
16266
|
let indexSource;
|
|
14610
16267
|
const rootStatOk = await isExistingDirectory(rootDir);
|
|
14611
16268
|
if (rootStatOk) {
|
|
14612
|
-
const absFolder =
|
|
16269
|
+
const absFolder = join5(rootDir, subPath);
|
|
14613
16270
|
const folderStatOk = await isExistingDirectory(absFolder);
|
|
14614
16271
|
if (folderStatOk) {
|
|
14615
16272
|
const folder = await readFolder(absFolder, indexFile);
|
|
@@ -14638,8 +16295,8 @@ async function isExistingDirectory(path) {
|
|
|
14638
16295
|
const stats = await stat4(path);
|
|
14639
16296
|
return stats.isDirectory();
|
|
14640
16297
|
} catch (err) {
|
|
14641
|
-
const
|
|
14642
|
-
if (
|
|
16298
|
+
const code11 = err.code;
|
|
16299
|
+
if (code11 !== "ENOENT" && code11 !== "ENOTDIR") {
|
|
14643
16300
|
throw err;
|
|
14644
16301
|
}
|
|
14645
16302
|
return false;
|
|
@@ -14661,7 +16318,7 @@ async function readFolder(absFolder, indexFile) {
|
|
|
14661
16318
|
let indexSource;
|
|
14662
16319
|
if (collectedFiles.includes(indexFile)) {
|
|
14663
16320
|
try {
|
|
14664
|
-
indexSource = await
|
|
16321
|
+
indexSource = await readFile5(join5(absFolder, indexFile), "utf8");
|
|
14665
16322
|
} catch {
|
|
14666
16323
|
indexSource = void 0;
|
|
14667
16324
|
}
|
|
@@ -14880,7 +16537,7 @@ var storageFileMValidateFolderTool = createTwoSideValidateTool({
|
|
|
14880
16537
|
});
|
|
14881
16538
|
|
|
14882
16539
|
// packages/dbx-components-mcp/src/tools/notification-m-validate-app/extract.ts
|
|
14883
|
-
import { Node as
|
|
16540
|
+
import { Node as Node11, SyntaxKind as SyntaxKind8 } from "ts-morph";
|
|
14884
16541
|
var NOTIF_TEMPLATE_TYPE = "NotificationTemplateType";
|
|
14885
16542
|
var NOTIF_TEMPLATE_TYPE_INFO = "NotificationTemplateTypeInfo";
|
|
14886
16543
|
var NOTIF_TEMPLATE_TYPE_INFO_ARRAY = "NotificationTemplateTypeInfo[]";
|
|
@@ -15001,7 +16658,7 @@ function extractTemplateInfoAggregates(sources) {
|
|
|
15001
16658
|
const ids = [];
|
|
15002
16659
|
for (const el of arr.getElements()) {
|
|
15003
16660
|
const inner = unwrapAsExpressions(el);
|
|
15004
|
-
if (inner &&
|
|
16661
|
+
if (inner && Node11.isIdentifier(inner)) {
|
|
15005
16662
|
ids.push(inner.getText());
|
|
15006
16663
|
}
|
|
15007
16664
|
}
|
|
@@ -15047,7 +16704,7 @@ function extractTaskAllTypesAggregates(sources) {
|
|
|
15047
16704
|
const ids = [];
|
|
15048
16705
|
for (const el of arr.getElements()) {
|
|
15049
16706
|
const inner = unwrapAsExpressions(el);
|
|
15050
|
-
if (inner &&
|
|
16707
|
+
if (inner && Node11.isIdentifier(inner)) {
|
|
15051
16708
|
ids.push(inner.getText());
|
|
15052
16709
|
}
|
|
15053
16710
|
}
|
|
@@ -15075,14 +16732,14 @@ function extractTaskCheckpointAliases(sources) {
|
|
|
15075
16732
|
return out;
|
|
15076
16733
|
}
|
|
15077
16734
|
function collectStringLiterals(node, out) {
|
|
15078
|
-
if (
|
|
16735
|
+
if (Node11.isLiteralTypeNode(node)) {
|
|
15079
16736
|
const lit = node.getLiteral();
|
|
15080
|
-
if (
|
|
16737
|
+
if (Node11.isStringLiteral(lit)) {
|
|
15081
16738
|
out.push(lit.getLiteralText());
|
|
15082
16739
|
}
|
|
15083
16740
|
return;
|
|
15084
16741
|
}
|
|
15085
|
-
if (
|
|
16742
|
+
if (Node11.isUnionTypeNode(node)) {
|
|
15086
16743
|
for (const child of node.getTypeNodes()) {
|
|
15087
16744
|
collectStringLiterals(child, out);
|
|
15088
16745
|
}
|
|
@@ -15136,7 +16793,7 @@ function extractTemplateInfoRecord(sources, index) {
|
|
|
15136
16793
|
}
|
|
15137
16794
|
function tryReadTemplateInfoRecord(decl, rel, index) {
|
|
15138
16795
|
const initializer = unwrapAsExpressions(decl.getInitializer());
|
|
15139
|
-
if (!initializer || !
|
|
16796
|
+
if (!initializer || !Node11.isCallExpression(initializer)) return void 0;
|
|
15140
16797
|
if (initializer.getExpression().getText() !== TEMPLATE_INFO_RECORD_FACTORY) return void 0;
|
|
15141
16798
|
const args = initializer.getArguments();
|
|
15142
16799
|
const arr = args[0] ? asArrayLiteral(args[0]) : void 0;
|
|
@@ -15157,15 +16814,15 @@ function tryReadTemplateInfoRecord(decl, rel, index) {
|
|
|
15157
16814
|
}
|
|
15158
16815
|
function classifyInfoRecordArrayElements(arr, direct, spreads) {
|
|
15159
16816
|
for (const el of arr.getElements()) {
|
|
15160
|
-
if (
|
|
16817
|
+
if (Node11.isSpreadElement(el)) {
|
|
15161
16818
|
const inner2 = el.getExpression();
|
|
15162
|
-
if (
|
|
16819
|
+
if (Node11.isIdentifier(inner2)) {
|
|
15163
16820
|
spreads.push(inner2.getText());
|
|
15164
16821
|
}
|
|
15165
16822
|
continue;
|
|
15166
16823
|
}
|
|
15167
16824
|
const inner = unwrapAsExpressions(el);
|
|
15168
|
-
if (inner &&
|
|
16825
|
+
if (inner && Node11.isIdentifier(inner)) {
|
|
15169
16826
|
direct.push(inner.getText());
|
|
15170
16827
|
}
|
|
15171
16828
|
}
|
|
@@ -15186,13 +16843,13 @@ function resolveTemplateInfoSpreads(direct, spreads, index) {
|
|
|
15186
16843
|
function extractTemplateInfoRecordWiring(sources) {
|
|
15187
16844
|
for (const sf of sources) {
|
|
15188
16845
|
const rel = apiRelPath(sf);
|
|
15189
|
-
for (const call of sf.getDescendantsOfKind(
|
|
16846
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
|
|
15190
16847
|
if (call.getExpression().getText() !== TEMPLATE_INFO_RECORD_SERVICE) continue;
|
|
15191
16848
|
const args = call.getArguments();
|
|
15192
16849
|
const first = args[0];
|
|
15193
16850
|
if (!first) continue;
|
|
15194
16851
|
const inner = unwrapAsExpressions(first);
|
|
15195
|
-
if (!inner || !
|
|
16852
|
+
if (!inner || !Node11.isIdentifier(inner)) continue;
|
|
15196
16853
|
const result = {
|
|
15197
16854
|
recordIdentifier: inner.getText(),
|
|
15198
16855
|
sourceFile: rel
|
|
@@ -15205,7 +16862,7 @@ function extractTemplateInfoRecordWiring(sources) {
|
|
|
15205
16862
|
function extractTemplateConfigsArrayWiring(sources) {
|
|
15206
16863
|
for (const sf of sources) {
|
|
15207
16864
|
const rel = apiRelPath(sf);
|
|
15208
|
-
for (const obj of sf.getDescendantsOfKind(
|
|
16865
|
+
for (const obj of sf.getDescendantsOfKind(SyntaxKind8.ObjectLiteralExpression)) {
|
|
15209
16866
|
const provideIdent = readIdentifierProperty(obj, "provide");
|
|
15210
16867
|
if (provideIdent !== TEMPLATE_CONFIGS_ARRAY_TOKEN) continue;
|
|
15211
16868
|
const useFactoryIdent = readIdentifierProperty(obj, "useFactory");
|
|
@@ -15230,7 +16887,7 @@ function buildApiFunctionIndex2(sources) {
|
|
|
15230
16887
|
for (const decl of stmt.getDeclarations()) {
|
|
15231
16888
|
const initializer = unwrapAsExpressions(decl.getInitializer());
|
|
15232
16889
|
if (!initializer) continue;
|
|
15233
|
-
if (
|
|
16890
|
+
if (Node11.isArrowFunction(initializer) || Node11.isFunctionExpression(initializer)) {
|
|
15234
16891
|
map.set(decl.getName(), { node: initializer, sourceFile: sf, relPath: rel });
|
|
15235
16892
|
}
|
|
15236
16893
|
}
|
|
@@ -15266,11 +16923,11 @@ function extractTemplateConfigsArrayFactory(sources, index) {
|
|
|
15266
16923
|
const arr = returnExpr ? asArrayLiteral(returnExpr) : void 0;
|
|
15267
16924
|
if (arr) {
|
|
15268
16925
|
for (const el of arr.getElements()) {
|
|
15269
|
-
if (
|
|
16926
|
+
if (Node11.isSpreadElement(el)) {
|
|
15270
16927
|
const inner2 = el.getExpression();
|
|
15271
|
-
if (
|
|
16928
|
+
if (Node11.isCallExpression(inner2)) {
|
|
15272
16929
|
const callee = inner2.getExpression();
|
|
15273
|
-
if (
|
|
16930
|
+
if (Node11.isIdentifier(callee)) {
|
|
15274
16931
|
const callName = callee.getText();
|
|
15275
16932
|
spreadCalls.push(callName);
|
|
15276
16933
|
if (!index.functionsByName.has(callName)) {
|
|
@@ -15281,9 +16938,9 @@ function extractTemplateConfigsArrayFactory(sources, index) {
|
|
|
15281
16938
|
continue;
|
|
15282
16939
|
}
|
|
15283
16940
|
const inner = unwrapAsExpressions(el);
|
|
15284
|
-
if (inner &&
|
|
16941
|
+
if (inner && Node11.isCallExpression(inner)) {
|
|
15285
16942
|
const callee = inner.getExpression();
|
|
15286
|
-
if (
|
|
16943
|
+
if (Node11.isIdentifier(callee)) {
|
|
15287
16944
|
directCalls.push(callee.getText());
|
|
15288
16945
|
}
|
|
15289
16946
|
}
|
|
@@ -15332,11 +16989,11 @@ function collectFromArrayEntryFactory(name, out, index) {
|
|
|
15332
16989
|
const arr = asArrayLiteral(returnExpr);
|
|
15333
16990
|
if (!arr) return;
|
|
15334
16991
|
for (const el of arr.getElements()) {
|
|
15335
|
-
if (
|
|
16992
|
+
if (Node11.isSpreadElement(el)) {
|
|
15336
16993
|
const inner2 = el.getExpression();
|
|
15337
|
-
if (
|
|
16994
|
+
if (Node11.isCallExpression(inner2)) {
|
|
15338
16995
|
const callee = inner2.getExpression();
|
|
15339
|
-
if (
|
|
16996
|
+
if (Node11.isIdentifier(callee)) {
|
|
15340
16997
|
collectFromArrayEntryFactory(callee.getText(), out, index);
|
|
15341
16998
|
}
|
|
15342
16999
|
}
|
|
@@ -15344,9 +17001,9 @@ function collectFromArrayEntryFactory(name, out, index) {
|
|
|
15344
17001
|
}
|
|
15345
17002
|
const inner = unwrapAsExpressions(el);
|
|
15346
17003
|
if (!inner) continue;
|
|
15347
|
-
if (
|
|
17004
|
+
if (Node11.isCallExpression(inner)) {
|
|
15348
17005
|
const callee = inner.getExpression();
|
|
15349
|
-
if (
|
|
17006
|
+
if (Node11.isIdentifier(callee)) {
|
|
15350
17007
|
collectFromSingleEntryFactory(callee.getText(), out, index);
|
|
15351
17008
|
}
|
|
15352
17009
|
continue;
|
|
@@ -15364,9 +17021,9 @@ function extractTaskServiceCalls(sources, index, trustedExternal) {
|
|
|
15364
17021
|
const out = [];
|
|
15365
17022
|
for (const sf of sources) {
|
|
15366
17023
|
const rel = apiRelPath(sf);
|
|
15367
|
-
for (const call of sf.getDescendantsOfKind(
|
|
17024
|
+
for (const call of sf.getDescendantsOfKind(SyntaxKind8.CallExpression)) {
|
|
15368
17025
|
const expr = call.getExpression();
|
|
15369
|
-
if (!
|
|
17026
|
+
if (!Node11.isIdentifier(expr) || expr.getText() !== TASK_SERVICE_FACTORY) continue;
|
|
15370
17027
|
const args = call.getArguments();
|
|
15371
17028
|
const first = args[0] ? asObjectLiteral(args[0]) : void 0;
|
|
15372
17029
|
if (!first) continue;
|
|
@@ -15392,13 +17049,13 @@ function collectValidateArrayElements(validateArr) {
|
|
|
15392
17049
|
const spreads = [];
|
|
15393
17050
|
if (!validateArr) return { ids, spreads };
|
|
15394
17051
|
for (const el of validateArr.getElements()) {
|
|
15395
|
-
if (
|
|
17052
|
+
if (Node11.isSpreadElement(el)) {
|
|
15396
17053
|
const inner2 = el.getExpression();
|
|
15397
|
-
if (
|
|
17054
|
+
if (Node11.isIdentifier(inner2)) spreads.push(inner2.getText());
|
|
15398
17055
|
continue;
|
|
15399
17056
|
}
|
|
15400
17057
|
const inner = unwrapAsExpressions(el);
|
|
15401
|
-
if (inner &&
|
|
17058
|
+
if (inner && Node11.isIdentifier(inner)) ids.push(inner.getText());
|
|
15402
17059
|
}
|
|
15403
17060
|
return { ids, spreads };
|
|
15404
17061
|
}
|
|
@@ -15411,17 +17068,17 @@ function collectHandlersArrayElements(options) {
|
|
|
15411
17068
|
if (!handlersArr) return { handlerTypes, unresolvedSpreads, resolvedBindings, unresolvedBindings };
|
|
15412
17069
|
const visited = /* @__PURE__ */ new Set();
|
|
15413
17070
|
for (const el of handlersArr.getElements()) {
|
|
15414
|
-
if (
|
|
17071
|
+
if (Node11.isSpreadElement(el)) {
|
|
15415
17072
|
consumeHandlersSpreadElement({ inner: el.getExpression(), sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited });
|
|
15416
17073
|
continue;
|
|
15417
17074
|
}
|
|
15418
17075
|
const inner = unwrapAsExpressions(el);
|
|
15419
17076
|
if (!inner) continue;
|
|
15420
|
-
if (
|
|
17077
|
+
if (Node11.isIdentifier(inner)) {
|
|
15421
17078
|
collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
|
|
15422
|
-
} else if (
|
|
17079
|
+
} else if (Node11.isCallExpression(inner)) {
|
|
15423
17080
|
const callee = inner.getExpression();
|
|
15424
|
-
if (
|
|
17081
|
+
if (Node11.isIdentifier(callee)) {
|
|
15425
17082
|
collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
|
|
15426
17083
|
}
|
|
15427
17084
|
}
|
|
@@ -15430,16 +17087,16 @@ function collectHandlersArrayElements(options) {
|
|
|
15430
17087
|
}
|
|
15431
17088
|
function consumeHandlersSpreadElement(options) {
|
|
15432
17089
|
const { inner, sf, index, trustedExternal, unresolvedSpreads, resolvedBindings, unresolvedBindings, visited } = options;
|
|
15433
|
-
if (
|
|
17090
|
+
if (Node11.isCallExpression(inner)) {
|
|
15434
17091
|
const callee = inner.getExpression();
|
|
15435
|
-
if (
|
|
17092
|
+
if (Node11.isIdentifier(callee)) {
|
|
15436
17093
|
const name = callee.getText();
|
|
15437
17094
|
unresolvedSpreads.push(name);
|
|
15438
17095
|
collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
|
|
15439
17096
|
}
|
|
15440
17097
|
return;
|
|
15441
17098
|
}
|
|
15442
|
-
if (
|
|
17099
|
+
if (Node11.isIdentifier(inner)) {
|
|
15443
17100
|
const name = inner.getText();
|
|
15444
17101
|
unresolvedSpreads.push(name);
|
|
15445
17102
|
collectHandlerBindingsFromIdentifier({ name, sf, index, trustedExternal, resolved: resolvedBindings, unresolved: unresolvedBindings, visited });
|
|
@@ -15449,13 +17106,13 @@ function collectHandlerBindingsFromValue(options) {
|
|
|
15449
17106
|
const { node, sf, index, trustedExternal, resolved, unresolved, visited } = options;
|
|
15450
17107
|
const inner = unwrapAsExpressions(node);
|
|
15451
17108
|
if (!inner) return false;
|
|
15452
|
-
if (
|
|
17109
|
+
if (Node11.isCallExpression(inner)) {
|
|
15453
17110
|
const callee = inner.getExpression();
|
|
15454
|
-
if (
|
|
17111
|
+
if (Node11.isIdentifier(callee)) {
|
|
15455
17112
|
return collectHandlerBindingsFromIdentifier({ name: callee.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
|
|
15456
17113
|
}
|
|
15457
17114
|
}
|
|
15458
|
-
if (
|
|
17115
|
+
if (Node11.isIdentifier(inner)) {
|
|
15459
17116
|
return collectHandlerBindingsFromIdentifier({ name: inner.getText(), sf, index, trustedExternal, resolved, unresolved, visited });
|
|
15460
17117
|
}
|
|
15461
17118
|
return false;
|
|
@@ -15472,7 +17129,7 @@ function collectHandlerBindingsFromIdentifier(options) {
|
|
|
15472
17129
|
const typeText = typeNode ? typeNode.getText() : void 0;
|
|
15473
17130
|
const isHandlerConfigTyped = typeText !== void 0 && (typeText === NOTIF_TASK_SERVICE_HANDLER_CONFIG || typeText.startsWith(`${NOTIF_TASK_SERVICE_HANDLER_CONFIG}<`));
|
|
15474
17131
|
const declInit = unwrapAsExpressions(localDecl.getInitializer());
|
|
15475
|
-
const isObjectLit = declInit !== void 0 &&
|
|
17132
|
+
const isObjectLit = declInit !== void 0 && Node11.isObjectLiteralExpression(declInit);
|
|
15476
17133
|
if (isHandlerConfigTyped && isObjectLit) {
|
|
15477
17134
|
resolved.push(localDecl.getName());
|
|
15478
17135
|
resolvedAny = true;
|
|
@@ -15503,12 +17160,12 @@ function collectHandlerBindingsFromIdentifier(options) {
|
|
|
15503
17160
|
function resolveArrayFromProperty2(obj, name, sf) {
|
|
15504
17161
|
const init = unwrapAsExpressions(getPropertyInitializer(obj, name));
|
|
15505
17162
|
if (!init) return void 0;
|
|
15506
|
-
if (
|
|
15507
|
-
if (
|
|
17163
|
+
if (Node11.isArrayLiteralExpression(init)) return init;
|
|
17164
|
+
if (Node11.isIdentifier(init)) {
|
|
15508
17165
|
const declNode = findLocalVariable(sf, init.getText());
|
|
15509
17166
|
if (declNode) {
|
|
15510
17167
|
const declInit = unwrapAsExpressions(declNode.getInitializer());
|
|
15511
|
-
if (declInit &&
|
|
17168
|
+
if (declInit && Node11.isArrayLiteralExpression(declInit)) {
|
|
15512
17169
|
return declInit;
|
|
15513
17170
|
}
|
|
15514
17171
|
}
|
|
@@ -15529,12 +17186,12 @@ function extractTaskHandlerEntries(sources) {
|
|
|
15529
17186
|
if (!typeIdent) return;
|
|
15530
17187
|
const flowInit = unwrapAsExpressions(getPropertyInitializer(obj, "flow"));
|
|
15531
17188
|
let flowCount;
|
|
15532
|
-
if (flowInit &&
|
|
17189
|
+
if (flowInit && Node11.isArrayLiteralExpression(flowInit)) {
|
|
15533
17190
|
flowCount = flowInit.getElements().length;
|
|
15534
17191
|
}
|
|
15535
17192
|
let dataArg;
|
|
15536
17193
|
let checkpointArg;
|
|
15537
|
-
if (
|
|
17194
|
+
if (Node11.isTypeReference(typeNode)) {
|
|
15538
17195
|
const tArgs = typeNode.getTypeArguments();
|
|
15539
17196
|
if (tArgs.length >= 1) dataArg = tArgs[0].getText();
|
|
15540
17197
|
if (tArgs.length >= 2) checkpointArg = tArgs[1].getText();
|
|
@@ -15554,7 +17211,7 @@ function extractTaskHandlerEntries(sources) {
|
|
|
15554
17211
|
};
|
|
15555
17212
|
for (const sf of sources) {
|
|
15556
17213
|
const rel = apiRelPath(sf);
|
|
15557
|
-
for (const decl of sf.getDescendantsOfKind(
|
|
17214
|
+
for (const decl of sf.getDescendantsOfKind(SyntaxKind8.VariableDeclaration)) {
|
|
15558
17215
|
collectFromVariable(decl, rel);
|
|
15559
17216
|
}
|
|
15560
17217
|
}
|
|
@@ -15579,7 +17236,7 @@ function runRules6(inspection, extracted) {
|
|
|
15579
17236
|
violations,
|
|
15580
17237
|
codes: IO_VIOLATION_CODES2,
|
|
15581
17238
|
messages: IO_VIOLATION_MESSAGES2,
|
|
15582
|
-
build: (
|
|
17239
|
+
build: (code11, message, side) => buildIoViolation2(code11, message, side)
|
|
15583
17240
|
});
|
|
15584
17241
|
if (!proceed) {
|
|
15585
17242
|
return violations;
|
|
@@ -15932,14 +17589,14 @@ function flagUnusedInfoAggregates(extracted, violations) {
|
|
|
15932
17589
|
}
|
|
15933
17590
|
}
|
|
15934
17591
|
}
|
|
15935
|
-
function flagDuplicates2(entries,
|
|
17592
|
+
function flagDuplicates2(entries, code11, violations) {
|
|
15936
17593
|
const seen = /* @__PURE__ */ new Map();
|
|
15937
17594
|
for (const entry of entries) {
|
|
15938
17595
|
if (!entry.typeCode) continue;
|
|
15939
17596
|
const previous = seen.get(entry.typeCode);
|
|
15940
17597
|
if (previous) {
|
|
15941
17598
|
pushViolation6(violations, {
|
|
15942
|
-
code:
|
|
17599
|
+
code: code11,
|
|
15943
17600
|
severity: "warning",
|
|
15944
17601
|
message: `Type code \`'${entry.typeCode}'\` is shared by \`${previous}\` and \`${entry.symbolName}\`. Runtime aggregators reject duplicates \u2014 change one of the string literals.`,
|
|
15945
17602
|
side: "component",
|
|
@@ -15973,9 +17630,9 @@ function pushViolation6(buffer, violation) {
|
|
|
15973
17630
|
};
|
|
15974
17631
|
buffer.push(filled);
|
|
15975
17632
|
}
|
|
15976
|
-
function buildIoViolation2(
|
|
17633
|
+
function buildIoViolation2(code11, message, side) {
|
|
15977
17634
|
const result = {
|
|
15978
|
-
code:
|
|
17635
|
+
code: code11,
|
|
15979
17636
|
severity: "error",
|
|
15980
17637
|
message,
|
|
15981
17638
|
side,
|
|
@@ -16175,8 +17832,8 @@ function formatReportAsJson2(report) {
|
|
|
16175
17832
|
// packages/dbx-components-mcp/src/tools/notification-m-list-app/format.markdown.ts
|
|
16176
17833
|
function formatReportAsMarkdown2(report) {
|
|
16177
17834
|
const basename4 = report.componentDir.split("/").pop() ?? report.componentDir;
|
|
16178
|
-
const aggregatorRecordText = report.aggregatorRecordName ?
|
|
16179
|
-
const templateConfigsFactoryText = report.templateConfigsArrayFactoryName ?
|
|
17835
|
+
const aggregatorRecordText = report.aggregatorRecordName ? code5(report.aggregatorRecordName) : "_Not defined._";
|
|
17836
|
+
const templateConfigsFactoryText = report.templateConfigsArrayFactoryName ? code5(report.templateConfigsArrayFactoryName) : "_Not defined._";
|
|
16180
17837
|
const lines = [
|
|
16181
17838
|
`# App notifications \u2014 ${basename4}`,
|
|
16182
17839
|
"",
|
|
@@ -16216,8 +17873,8 @@ function formatTemplateBlock(t) {
|
|
|
16216
17873
|
if (t.description) parts.push(`- Description: ${t.description}`);
|
|
16217
17874
|
if (t.notificationMIdentity) parts.push(`- Notification model: \`${t.notificationMIdentity}\``);
|
|
16218
17875
|
if (t.targetModelIdentity) parts.push(`- Target model: \`${t.targetModelIdentity}\``);
|
|
16219
|
-
const infoText = t.infoSymbolName ?
|
|
16220
|
-
const factorySuffix = t.factoryFunctionName ? ` (${
|
|
17876
|
+
const infoText = t.infoSymbolName ? code5(t.infoSymbolName) : "_Missing._";
|
|
17877
|
+
const factorySuffix = t.factoryFunctionName ? ` (${code5(t.factoryFunctionName)})` : "";
|
|
16221
17878
|
parts.push(`- Info object: ${infoText}`, `- In info record: ${formatBool2(t.inInfoRecord)}`, `- Has factory: ${formatBool2(t.hasFactory)}${factorySuffix}`, `- Source: \`${t.sourceFile}\``);
|
|
16222
17879
|
return parts.join("\n");
|
|
16223
17880
|
}
|
|
@@ -16227,7 +17884,7 @@ function formatTaskBlock(t) {
|
|
|
16227
17884
|
parts.push(heading);
|
|
16228
17885
|
if (t.dataInterfaceName) parts.push(`- Data interface: \`${t.dataInterfaceName}\``);
|
|
16229
17886
|
if (t.checkpoints.length > 0) {
|
|
16230
|
-
const checkpointsText = t.checkpoints.map((c) =>
|
|
17887
|
+
const checkpointsText = t.checkpoints.map((c) => code5(c)).join(", ");
|
|
16231
17888
|
parts.push(`- Checkpoints: ${checkpointsText}`);
|
|
16232
17889
|
}
|
|
16233
17890
|
let handlerSuffix = "";
|
|
@@ -16241,7 +17898,7 @@ function formatTaskBlock(t) {
|
|
|
16241
17898
|
function formatBool2(value) {
|
|
16242
17899
|
return value ? "yes" : "no";
|
|
16243
17900
|
}
|
|
16244
|
-
function
|
|
17901
|
+
function code5(value) {
|
|
16245
17902
|
return "`" + value + "`";
|
|
16246
17903
|
}
|
|
16247
17904
|
|
|
@@ -16383,8 +18040,8 @@ function formatResult8(result) {
|
|
|
16383
18040
|
}
|
|
16384
18041
|
|
|
16385
18042
|
// packages/dbx-components-mcp/src/tools/system-m-validate-folder/inspect.ts
|
|
16386
|
-
import { readdir as readdir4, readFile as
|
|
16387
|
-
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";
|
|
16388
18045
|
async function inspectFolder2(path) {
|
|
16389
18046
|
const name = basename3(path);
|
|
16390
18047
|
let status;
|
|
@@ -16404,7 +18061,7 @@ async function inspectFolder2(path) {
|
|
|
16404
18061
|
files = collected;
|
|
16405
18062
|
if (collected.includes("system.ts")) {
|
|
16406
18063
|
try {
|
|
16407
|
-
systemSource = await
|
|
18064
|
+
systemSource = await readFile6(join6(path, "system.ts"), "utf8");
|
|
16408
18065
|
} catch {
|
|
16409
18066
|
systemSource = void 0;
|
|
16410
18067
|
}
|
|
@@ -16413,8 +18070,8 @@ async function inspectFolder2(path) {
|
|
|
16413
18070
|
status = "not-directory";
|
|
16414
18071
|
}
|
|
16415
18072
|
} catch (err) {
|
|
16416
|
-
const
|
|
16417
|
-
if (
|
|
18073
|
+
const code11 = err.code;
|
|
18074
|
+
if (code11 === "ENOENT" || code11 === "ENOTDIR") {
|
|
16418
18075
|
status = "not-found";
|
|
16419
18076
|
} else {
|
|
16420
18077
|
throw err;
|
|
@@ -16425,14 +18082,14 @@ async function inspectFolder2(path) {
|
|
|
16425
18082
|
}
|
|
16426
18083
|
|
|
16427
18084
|
// packages/dbx-components-mcp/src/tools/system-m-validate-folder/extract.ts
|
|
16428
|
-
import { Node as
|
|
18085
|
+
import { Node as Node12, Project as Project9 } from "ts-morph";
|
|
16429
18086
|
var TYPE_CONSTANT_SUFFIX = "_SYSTEM_STATE_TYPE";
|
|
16430
18087
|
var DATA_INTERFACE_SUFFIX = "SystemData";
|
|
16431
18088
|
var CONVERTER_CONFIG_TYPE = "SystemStateStoredDataFieldConverterConfig";
|
|
16432
18089
|
var CONVERTER_MAP_TYPE = "SystemStateStoredDataConverterMap";
|
|
16433
18090
|
var SYSTEM_STATE_STORED_DATA = "SystemStateStoredData";
|
|
16434
18091
|
function extractSystemFile(name, text) {
|
|
16435
|
-
const project = new
|
|
18092
|
+
const project = new Project9({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
16436
18093
|
const sourceFile = project.createSourceFile(name, text, { overwrite: true });
|
|
16437
18094
|
const typeConstants = findTypeConstants(sourceFile);
|
|
16438
18095
|
const dataInterfaces = findDataInterfaces2(sourceFile);
|
|
@@ -16489,7 +18146,7 @@ function findDataInterfaces2(sourceFile) {
|
|
|
16489
18146
|
return out;
|
|
16490
18147
|
}
|
|
16491
18148
|
function extendsSystemStateStoredData(iface) {
|
|
16492
|
-
if (!
|
|
18149
|
+
if (!Node12.isInterfaceDeclaration(iface)) return false;
|
|
16493
18150
|
for (const clause of iface.getExtends()) {
|
|
16494
18151
|
const text = clause.getText();
|
|
16495
18152
|
if (text === SYSTEM_STATE_STORED_DATA || text.startsWith(`${SYSTEM_STATE_STORED_DATA}<`) || text === `${SYSTEM_STATE_STORED_DATA}, ${SYSTEM_STATE_STORED_DATA}`) {
|
|
@@ -16509,14 +18166,14 @@ function findConverters(sourceFile) {
|
|
|
16509
18166
|
for (const decl of stmt.getDeclarations()) {
|
|
16510
18167
|
const typeNode = decl.getTypeNode();
|
|
16511
18168
|
if (!typeNode) continue;
|
|
16512
|
-
if (!
|
|
18169
|
+
if (!Node12.isTypeReference(typeNode)) continue;
|
|
16513
18170
|
const typeName = typeNode.getTypeName().getText();
|
|
16514
18171
|
if (typeName !== CONVERTER_CONFIG_TYPE) continue;
|
|
16515
18172
|
const typeArgs = typeNode.getTypeArguments();
|
|
16516
18173
|
let dataTypeArgument;
|
|
16517
18174
|
if (typeArgs.length >= 1) {
|
|
16518
18175
|
const arg = typeArgs[0];
|
|
16519
|
-
if (
|
|
18176
|
+
if (Node12.isTypeReference(arg)) {
|
|
16520
18177
|
dataTypeArgument = arg.getTypeName().getText();
|
|
16521
18178
|
} else {
|
|
16522
18179
|
dataTypeArgument = arg.getText();
|
|
@@ -16563,19 +18220,19 @@ function collectConverterMapKeys(decl) {
|
|
|
16563
18220
|
if (!obj) return [];
|
|
16564
18221
|
const out = [];
|
|
16565
18222
|
for (const prop of obj.getProperties()) {
|
|
16566
|
-
if (!
|
|
18223
|
+
if (!Node12.isPropertyAssignment(prop)) continue;
|
|
16567
18224
|
const nameNode = prop.getNameNode();
|
|
16568
18225
|
const line = prop.getStartLineNumber();
|
|
16569
|
-
if (
|
|
18226
|
+
if (Node12.isComputedPropertyName(nameNode)) {
|
|
16570
18227
|
const inner = nameNode.getExpression();
|
|
16571
18228
|
out.push({ raw: inner.getText(), kind: "identifier", line });
|
|
16572
18229
|
continue;
|
|
16573
18230
|
}
|
|
16574
|
-
if (
|
|
18231
|
+
if (Node12.isStringLiteral(nameNode)) {
|
|
16575
18232
|
out.push({ raw: nameNode.getLiteralText(), kind: "string", line });
|
|
16576
18233
|
continue;
|
|
16577
18234
|
}
|
|
16578
|
-
if (
|
|
18235
|
+
if (Node12.isIdentifier(nameNode)) {
|
|
16579
18236
|
out.push({ raw: nameNode.getText(), kind: "string", line });
|
|
16580
18237
|
continue;
|
|
16581
18238
|
}
|
|
@@ -16585,10 +18242,10 @@ function collectConverterMapKeys(decl) {
|
|
|
16585
18242
|
}
|
|
16586
18243
|
function unwrapObjectLiteral(node) {
|
|
16587
18244
|
let current = node;
|
|
16588
|
-
while (current &&
|
|
18245
|
+
while (current && Node12.isAsExpression(current)) {
|
|
16589
18246
|
current = current.getExpression();
|
|
16590
18247
|
}
|
|
16591
|
-
if (current &&
|
|
18248
|
+
if (current && Node12.isObjectLiteralExpression(current)) {
|
|
16592
18249
|
return current;
|
|
16593
18250
|
}
|
|
16594
18251
|
return void 0;
|
|
@@ -16622,10 +18279,10 @@ function findLastTopLevelExportLine(sourceFile) {
|
|
|
16622
18279
|
return last;
|
|
16623
18280
|
}
|
|
16624
18281
|
function isExportedTopLevel(stmt) {
|
|
16625
|
-
if (
|
|
18282
|
+
if (Node12.isVariableStatement(stmt) || Node12.isFunctionDeclaration(stmt) || Node12.isClassDeclaration(stmt) || Node12.isInterfaceDeclaration(stmt) || Node12.isTypeAliasDeclaration(stmt) || Node12.isEnumDeclaration(stmt)) {
|
|
16626
18283
|
return stmt.isExported();
|
|
16627
18284
|
}
|
|
16628
|
-
if (
|
|
18285
|
+
if (Node12.isExportDeclaration(stmt) || Node12.isExportAssignment(stmt)) {
|
|
16629
18286
|
return true;
|
|
16630
18287
|
}
|
|
16631
18288
|
return false;
|
|
@@ -16935,7 +18592,7 @@ var systemMValidateFolderTool = createFolderValidateTool({
|
|
|
16935
18592
|
});
|
|
16936
18593
|
|
|
16937
18594
|
// packages/dbx-components-mcp/src/tools/lookup-action.tool.ts
|
|
16938
|
-
import { type as
|
|
18595
|
+
import { type as type36 } from "arktype";
|
|
16939
18596
|
var DBX_ACTION_LOOKUP_TOOL = {
|
|
16940
18597
|
name: "dbx_action_lookup",
|
|
16941
18598
|
description: [
|
|
@@ -16968,13 +18625,13 @@ var DBX_ACTION_LOOKUP_TOOL = {
|
|
|
16968
18625
|
required: ["topic"]
|
|
16969
18626
|
}
|
|
16970
18627
|
};
|
|
16971
|
-
var LookupActionArgsType =
|
|
18628
|
+
var LookupActionArgsType = type36({
|
|
16972
18629
|
topic: "string",
|
|
16973
18630
|
"depth?": "'brief' | 'full'"
|
|
16974
18631
|
});
|
|
16975
18632
|
function parseLookupActionArgs(raw) {
|
|
16976
18633
|
const parsed = LookupActionArgsType(raw);
|
|
16977
|
-
if (parsed instanceof
|
|
18634
|
+
if (parsed instanceof type36.errors) {
|
|
16978
18635
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
16979
18636
|
}
|
|
16980
18637
|
const result = {
|
|
@@ -17098,7 +18755,7 @@ function formatDirectiveEntry(entry, depth) {
|
|
|
17098
18755
|
}
|
|
17099
18756
|
lines.push("## State interaction", "", formatStateInteraction(entry), "", "## Example", "", "```html", entry.example, "```");
|
|
17100
18757
|
if (entry.skillRefs.length > 0) {
|
|
17101
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
18758
|
+
const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
|
|
17102
18759
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
17103
18760
|
}
|
|
17104
18761
|
} else {
|
|
@@ -17132,7 +18789,7 @@ function formatStoreEntry(entry, depth) {
|
|
|
17132
18789
|
}
|
|
17133
18790
|
lines.push("## Example", "", "```ts", entry.example, "```");
|
|
17134
18791
|
if (entry.skillRefs.length > 0) {
|
|
17135
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
18792
|
+
const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
|
|
17136
18793
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
17137
18794
|
}
|
|
17138
18795
|
} else {
|
|
@@ -17157,7 +18814,7 @@ function formatStateDiagram(entry) {
|
|
|
17157
18814
|
function formatStateEntry(entry, depth) {
|
|
17158
18815
|
const lines = [`# DbxActionState.${entry.stateValue}`, "", entry.description, "", bullet("enum value", `\`'${entry.literal}'\``), bullet("slug", `\`${entry.slug}\``), "", "## Transitions", "", "```", formatStateDiagram(entry), "```"];
|
|
17159
18816
|
if (depth === "full" && entry.skillRefs.length > 0) {
|
|
17160
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
18817
|
+
const skillsText = entry.skillRefs.map((s) => code6(s)).join(", ");
|
|
17161
18818
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
17162
18819
|
}
|
|
17163
18820
|
return lines.join("\n");
|
|
@@ -17236,12 +18893,12 @@ function formatNotFound6(normalized, candidates) {
|
|
|
17236
18893
|
}
|
|
17237
18894
|
return lines.join("\n");
|
|
17238
18895
|
}
|
|
17239
|
-
function
|
|
18896
|
+
function code6(value) {
|
|
17240
18897
|
return "`" + value + "`";
|
|
17241
18898
|
}
|
|
17242
18899
|
function createLookupActionTool(input) {
|
|
17243
18900
|
const { registry } = input;
|
|
17244
|
-
const
|
|
18901
|
+
const run5 = (rawArgs) => {
|
|
17245
18902
|
let args;
|
|
17246
18903
|
try {
|
|
17247
18904
|
args = parseLookupActionArgs(rawArgs);
|
|
@@ -17268,11 +18925,11 @@ function createLookupActionTool(input) {
|
|
|
17268
18925
|
const result = { content: [{ type: "text", text }] };
|
|
17269
18926
|
return result;
|
|
17270
18927
|
};
|
|
17271
|
-
return { definition: DBX_ACTION_LOOKUP_TOOL, run };
|
|
18928
|
+
return { definition: DBX_ACTION_LOOKUP_TOOL, run: run5 };
|
|
17272
18929
|
}
|
|
17273
18930
|
|
|
17274
18931
|
// packages/dbx-components-mcp/src/tools/action-examples.tool.ts
|
|
17275
|
-
import { type as
|
|
18932
|
+
import { type as type37 } from "arktype";
|
|
17276
18933
|
|
|
17277
18934
|
// packages/dbx-components-mcp/src/tools/data/patterns/actions/action.auto-trigger-on-modify.pattern.ts
|
|
17278
18935
|
var ACTION_PATTERN_AUTO_TRIGGER_ON_MODIFY = {
|
|
@@ -17632,13 +19289,13 @@ var DBX_ACTION_EXAMPLES_TOOL = {
|
|
|
17632
19289
|
required: ["pattern"]
|
|
17633
19290
|
}
|
|
17634
19291
|
};
|
|
17635
|
-
var ActionExamplesArgsType =
|
|
19292
|
+
var ActionExamplesArgsType = type37({
|
|
17636
19293
|
pattern: "string",
|
|
17637
19294
|
"depth?": "'minimal' | 'brief' | 'full'"
|
|
17638
19295
|
});
|
|
17639
19296
|
function parseActionExamplesArgs(raw) {
|
|
17640
19297
|
const parsed = ActionExamplesArgsType(raw);
|
|
17641
|
-
if (parsed instanceof
|
|
19298
|
+
if (parsed instanceof type37.errors) {
|
|
17642
19299
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
17643
19300
|
}
|
|
17644
19301
|
const result = {
|
|
@@ -17650,7 +19307,7 @@ function parseActionExamplesArgs(raw) {
|
|
|
17650
19307
|
function formatPatternCatalog3() {
|
|
17651
19308
|
const lines = [`# Action example patterns (${ACTION_EXAMPLE_PATTERNS.length})`, "", 'Call `dbx_action_examples pattern="<slug>"` for a full example.', ""];
|
|
17652
19309
|
for (const pattern of ACTION_EXAMPLE_PATTERNS) {
|
|
17653
|
-
const usesText = pattern.usesActionSlugs.map((s) =>
|
|
19310
|
+
const usesText = pattern.usesActionSlugs.map((s) => code7(s)).join(", ");
|
|
17654
19311
|
lines.push(`## ${pattern.name}`, "", `- **slug:** \`${pattern.slug}\``, `- **summary:** ${pattern.summary}`, `- **uses:** ${usesText}`, "");
|
|
17655
19312
|
}
|
|
17656
19313
|
return lines.join("\n").trimEnd();
|
|
@@ -17658,7 +19315,7 @@ function formatPatternCatalog3() {
|
|
|
17658
19315
|
function formatPattern3(pattern, depth) {
|
|
17659
19316
|
const snippet = pattern.snippets[depth];
|
|
17660
19317
|
const fence = depth === "full" ? "ts" : "html";
|
|
17661
|
-
const usesText = pattern.usesActionSlugs.map((s) =>
|
|
19318
|
+
const usesText = pattern.usesActionSlugs.map((s) => code7(s)).join(", ");
|
|
17662
19319
|
const sections = [`# ${pattern.name}`, "", pattern.summary, "", `**slug:** \`${pattern.slug}\` \xB7 **depth:** \`${depth}\` \xB7 **uses:** ${usesText}`, "", "```" + fence, snippet, "```"];
|
|
17663
19320
|
if (pattern.notes && depth === "full") {
|
|
17664
19321
|
sections.push("", "## Notes", "", pattern.notes);
|
|
@@ -17669,10 +19326,10 @@ function formatPattern3(pattern, depth) {
|
|
|
17669
19326
|
return sections.join("\n");
|
|
17670
19327
|
}
|
|
17671
19328
|
function formatNotFound7(slug) {
|
|
17672
|
-
const available = ACTION_EXAMPLE_PATTERNS.map((p) =>
|
|
19329
|
+
const available = ACTION_EXAMPLE_PATTERNS.map((p) => code7(p.slug)).join(", ");
|
|
17673
19330
|
return [`No action example pattern matched \`${slug}\`.`, "", `Available patterns: ${available}.`, "", 'Call `dbx_action_examples pattern="list"` for summaries.'].join("\n");
|
|
17674
19331
|
}
|
|
17675
|
-
function
|
|
19332
|
+
function code7(value) {
|
|
17676
19333
|
return "`" + value + "`";
|
|
17677
19334
|
}
|
|
17678
19335
|
function runActionExamples(rawArgs) {
|
|
@@ -17700,7 +19357,7 @@ var actionExamplesTool = {
|
|
|
17700
19357
|
};
|
|
17701
19358
|
|
|
17702
19359
|
// packages/dbx-components-mcp/src/tools/action-scaffold.tool.ts
|
|
17703
|
-
import { type as
|
|
19360
|
+
import { type as type38 } from "arktype";
|
|
17704
19361
|
var TRIGGER_VALUES = ["button", "form", "auto-modify"];
|
|
17705
19362
|
var SUCCESS_FEEDBACK_VALUES = ["snackbar", "redirect", "none"];
|
|
17706
19363
|
var CONTEXT_PROVIDER_VALUES = ["inline", "parent", "host-component"];
|
|
@@ -17734,7 +19391,7 @@ var DBX_ACTION_SCAFFOLD_TOOL = {
|
|
|
17734
19391
|
required: ["use_case", "trigger", "value_type"]
|
|
17735
19392
|
}
|
|
17736
19393
|
};
|
|
17737
|
-
var
|
|
19394
|
+
var ScaffoldArgsType4 = type38({
|
|
17738
19395
|
use_case: "string",
|
|
17739
19396
|
trigger: "'button' | 'form' | 'auto-modify'",
|
|
17740
19397
|
"confirm?": "boolean",
|
|
@@ -17744,8 +19401,8 @@ var ScaffoldArgsType3 = type33({
|
|
|
17744
19401
|
"result_type?": "string"
|
|
17745
19402
|
});
|
|
17746
19403
|
function parseScaffoldArgs2(raw) {
|
|
17747
|
-
const parsed =
|
|
17748
|
-
if (parsed instanceof
|
|
19404
|
+
const parsed = ScaffoldArgsType4(raw);
|
|
19405
|
+
if (parsed instanceof type38.errors) {
|
|
17749
19406
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
17750
19407
|
}
|
|
17751
19408
|
const useCase = parsed.use_case.trim();
|
|
@@ -17951,16 +19608,16 @@ var actionScaffoldTool = {
|
|
|
17951
19608
|
};
|
|
17952
19609
|
|
|
17953
19610
|
// packages/dbx-components-mcp/src/tools/route-tree.tool.ts
|
|
17954
|
-
import { type as
|
|
19611
|
+
import { type as type39 } from "arktype";
|
|
17955
19612
|
|
|
17956
19613
|
// packages/dbx-components-mcp/src/tools/route/load-sources.ts
|
|
17957
|
-
import { glob as fsGlob3, readFile as
|
|
17958
|
-
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";
|
|
17959
19616
|
|
|
17960
19617
|
// packages/dbx-components-mcp/src/tools/route/extract.ts
|
|
17961
|
-
import { Node as
|
|
19618
|
+
import { Node as Node13, Project as Project10, SyntaxKind as SyntaxKind9 } from "ts-morph";
|
|
17962
19619
|
function extractFile3(source) {
|
|
17963
|
-
const project = new
|
|
19620
|
+
const project = new Project10({ useInMemoryFileSystem: true, skipAddingFilesFromTsConfig: true });
|
|
17964
19621
|
const sourceFile = project.createSourceFile(source.name, source.text, { overwrite: true });
|
|
17965
19622
|
const issues = [];
|
|
17966
19623
|
const objectLiteralsByName = collectStateConsts(sourceFile);
|
|
@@ -17973,9 +19630,9 @@ function extractFile3(source) {
|
|
|
17973
19630
|
}
|
|
17974
19631
|
for (const arrayLit of findStateArrayLiterals(sourceFile)) {
|
|
17975
19632
|
for (const element of arrayLit.getElements()) {
|
|
17976
|
-
if (
|
|
19633
|
+
if (Node13.isObjectLiteralExpression(element)) {
|
|
17977
19634
|
addNode({ file: source.name, literal: element, fallbackConstName: void 0, into: collected, issues });
|
|
17978
|
-
} else if (
|
|
19635
|
+
} else if (Node13.isIdentifier(element)) {
|
|
17979
19636
|
const ref = objectLiteralsByName.get(element.getText());
|
|
17980
19637
|
if (ref) {
|
|
17981
19638
|
addNode({ file: source.name, literal: ref.literal, fallbackConstName: element.getText(), into: collected, issues });
|
|
@@ -17996,7 +19653,7 @@ function collectStateConsts(sourceFile) {
|
|
|
17996
19653
|
for (const stmt of sourceFile.getVariableStatements()) {
|
|
17997
19654
|
for (const decl of stmt.getDeclarations()) {
|
|
17998
19655
|
const initializer = decl.getInitializer();
|
|
17999
|
-
if (!initializer || !
|
|
19656
|
+
if (!initializer || !Node13.isObjectLiteralExpression(initializer)) {
|
|
18000
19657
|
continue;
|
|
18001
19658
|
}
|
|
18002
19659
|
const typeNode = decl.getTypeNode();
|
|
@@ -18011,12 +19668,12 @@ function findStateArrayLiterals(sourceFile) {
|
|
|
18011
19668
|
for (const stmt of sourceFile.getVariableStatements()) {
|
|
18012
19669
|
for (const decl of stmt.getDeclarations()) {
|
|
18013
19670
|
const initializer = decl.getInitializer();
|
|
18014
|
-
if (initializer &&
|
|
19671
|
+
if (initializer && Node13.isArrayLiteralExpression(initializer) && declarationIsStateArray(stmt, decl.getName(), initializer)) {
|
|
18015
19672
|
arrays.push(initializer);
|
|
18016
19673
|
}
|
|
18017
19674
|
}
|
|
18018
19675
|
}
|
|
18019
|
-
for (const call of sourceFile.getDescendantsOfKind(
|
|
19676
|
+
for (const call of sourceFile.getDescendantsOfKind(SyntaxKind9.CallExpression)) {
|
|
18020
19677
|
const expr = call.getExpression();
|
|
18021
19678
|
const exprText = expr.getText();
|
|
18022
19679
|
const isProvide = exprText === "provideStates";
|
|
@@ -18025,17 +19682,17 @@ function findStateArrayLiterals(sourceFile) {
|
|
|
18025
19682
|
continue;
|
|
18026
19683
|
}
|
|
18027
19684
|
for (const arg of call.getArguments()) {
|
|
18028
|
-
if (!
|
|
19685
|
+
if (!Node13.isObjectLiteralExpression(arg)) {
|
|
18029
19686
|
continue;
|
|
18030
19687
|
}
|
|
18031
19688
|
const statesProp = arg.getProperty("states");
|
|
18032
|
-
if (!statesProp || !
|
|
19689
|
+
if (!statesProp || !Node13.isPropertyAssignment(statesProp)) {
|
|
18033
19690
|
continue;
|
|
18034
19691
|
}
|
|
18035
19692
|
const initializer = statesProp.getInitializer();
|
|
18036
|
-
if (initializer &&
|
|
19693
|
+
if (initializer && Node13.isArrayLiteralExpression(initializer)) {
|
|
18037
19694
|
arrays.push(initializer);
|
|
18038
|
-
} else if (initializer &&
|
|
19695
|
+
} else if (initializer && Node13.isIdentifier(initializer)) {
|
|
18039
19696
|
const referenced = findArrayLiteralForIdentifier(sourceFile, initializer);
|
|
18040
19697
|
if (referenced) {
|
|
18041
19698
|
arrays.push(referenced);
|
|
@@ -18052,10 +19709,10 @@ function declarationIsStateArray(stmt, name, literal) {
|
|
|
18052
19709
|
return true;
|
|
18053
19710
|
}
|
|
18054
19711
|
for (const element of literal.getElements()) {
|
|
18055
|
-
if (
|
|
19712
|
+
if (Node13.isObjectLiteralExpression(element) && hasStringNameProperty(element)) {
|
|
18056
19713
|
return true;
|
|
18057
19714
|
}
|
|
18058
|
-
if (
|
|
19715
|
+
if (Node13.isIdentifier(element)) {
|
|
18059
19716
|
return true;
|
|
18060
19717
|
}
|
|
18061
19718
|
}
|
|
@@ -18063,11 +19720,11 @@ function declarationIsStateArray(stmt, name, literal) {
|
|
|
18063
19720
|
}
|
|
18064
19721
|
function hasStringNameProperty(literal) {
|
|
18065
19722
|
const nameProp = literal.getProperty("name");
|
|
18066
|
-
if (!nameProp || !
|
|
19723
|
+
if (!nameProp || !Node13.isPropertyAssignment(nameProp)) {
|
|
18067
19724
|
return false;
|
|
18068
19725
|
}
|
|
18069
19726
|
const initializer = nameProp.getInitializer();
|
|
18070
|
-
return initializer !== void 0 && (
|
|
19727
|
+
return initializer !== void 0 && (Node13.isStringLiteral(initializer) || Node13.isNoSubstitutionTemplateLiteral(initializer));
|
|
18071
19728
|
}
|
|
18072
19729
|
function findArrayLiteralForIdentifier(sourceFile, identifier) {
|
|
18073
19730
|
const name = identifier.getText();
|
|
@@ -18077,7 +19734,7 @@ function findArrayLiteralForIdentifier(sourceFile, identifier) {
|
|
|
18077
19734
|
continue;
|
|
18078
19735
|
}
|
|
18079
19736
|
const initializer = decl.getInitializer();
|
|
18080
|
-
if (initializer &&
|
|
19737
|
+
if (initializer && Node13.isArrayLiteralExpression(initializer)) {
|
|
18081
19738
|
return initializer;
|
|
18082
19739
|
}
|
|
18083
19740
|
}
|
|
@@ -18127,64 +19784,64 @@ function addNode(options) {
|
|
|
18127
19784
|
}
|
|
18128
19785
|
function stringPropertyValue(literal, key) {
|
|
18129
19786
|
const prop = literal.getProperty(key);
|
|
18130
|
-
if (!prop || !
|
|
19787
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18131
19788
|
return void 0;
|
|
18132
19789
|
}
|
|
18133
19790
|
const initializer = prop.getInitializer();
|
|
18134
19791
|
if (!initializer) {
|
|
18135
19792
|
return void 0;
|
|
18136
19793
|
}
|
|
18137
|
-
if (
|
|
19794
|
+
if (Node13.isStringLiteral(initializer) || Node13.isNoSubstitutionTemplateLiteral(initializer)) {
|
|
18138
19795
|
return initializer.getLiteralText();
|
|
18139
19796
|
}
|
|
18140
19797
|
return void 0;
|
|
18141
19798
|
}
|
|
18142
19799
|
function booleanPropertyValue(literal, key) {
|
|
18143
19800
|
const prop = literal.getProperty(key);
|
|
18144
|
-
if (!prop || !
|
|
19801
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18145
19802
|
return void 0;
|
|
18146
19803
|
}
|
|
18147
19804
|
const initializer = prop.getInitializer();
|
|
18148
19805
|
if (!initializer) {
|
|
18149
19806
|
return void 0;
|
|
18150
19807
|
}
|
|
18151
|
-
if (initializer.getKind() ===
|
|
19808
|
+
if (initializer.getKind() === SyntaxKind9.TrueKeyword) {
|
|
18152
19809
|
return true;
|
|
18153
19810
|
}
|
|
18154
|
-
if (initializer.getKind() ===
|
|
19811
|
+
if (initializer.getKind() === SyntaxKind9.FalseKeyword) {
|
|
18155
19812
|
return false;
|
|
18156
19813
|
}
|
|
18157
19814
|
return void 0;
|
|
18158
19815
|
}
|
|
18159
19816
|
function identifierPropertyValue(literal, key) {
|
|
18160
19817
|
const prop = literal.getProperty(key);
|
|
18161
|
-
if (!prop || !
|
|
19818
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18162
19819
|
return void 0;
|
|
18163
19820
|
}
|
|
18164
19821
|
const initializer = prop.getInitializer();
|
|
18165
19822
|
if (!initializer) {
|
|
18166
19823
|
return void 0;
|
|
18167
19824
|
}
|
|
18168
|
-
if (
|
|
19825
|
+
if (Node13.isIdentifier(initializer)) {
|
|
18169
19826
|
return initializer.getText();
|
|
18170
19827
|
}
|
|
18171
|
-
if (
|
|
19828
|
+
if (Node13.isPropertyAccessExpression(initializer)) {
|
|
18172
19829
|
return initializer.getText();
|
|
18173
19830
|
}
|
|
18174
19831
|
return void 0;
|
|
18175
19832
|
}
|
|
18176
19833
|
function objectPropertyKeys(literal, key) {
|
|
18177
19834
|
const prop = literal.getProperty(key);
|
|
18178
|
-
if (!prop || !
|
|
19835
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18179
19836
|
return [];
|
|
18180
19837
|
}
|
|
18181
19838
|
const initializer = prop.getInitializer();
|
|
18182
|
-
if (!initializer || !
|
|
19839
|
+
if (!initializer || !Node13.isObjectLiteralExpression(initializer)) {
|
|
18183
19840
|
return [];
|
|
18184
19841
|
}
|
|
18185
19842
|
const out = [];
|
|
18186
19843
|
for (const member of initializer.getProperties()) {
|
|
18187
|
-
if (
|
|
19844
|
+
if (Node13.isPropertyAssignment(member) || Node13.isShorthandPropertyAssignment(member) || Node13.isMethodDeclaration(member)) {
|
|
18188
19845
|
const nameNode = member.getNameNode();
|
|
18189
19846
|
if (nameNode) {
|
|
18190
19847
|
out.push(nameNode.getText());
|
|
@@ -18195,7 +19852,7 @@ function objectPropertyKeys(literal, key) {
|
|
|
18195
19852
|
}
|
|
18196
19853
|
function collectResolveKeys(literal) {
|
|
18197
19854
|
const prop = literal.getProperty("resolve");
|
|
18198
|
-
if (!prop || !
|
|
19855
|
+
if (!prop || !Node13.isPropertyAssignment(prop)) {
|
|
18199
19856
|
return [];
|
|
18200
19857
|
}
|
|
18201
19858
|
const initializer = prop.getInitializer();
|
|
@@ -18203,22 +19860,22 @@ function collectResolveKeys(literal) {
|
|
|
18203
19860
|
return [];
|
|
18204
19861
|
}
|
|
18205
19862
|
const keys = [];
|
|
18206
|
-
if (
|
|
19863
|
+
if (Node13.isObjectLiteralExpression(initializer)) {
|
|
18207
19864
|
for (const member of initializer.getProperties()) {
|
|
18208
|
-
if (
|
|
19865
|
+
if (Node13.isPropertyAssignment(member) || Node13.isShorthandPropertyAssignment(member) || Node13.isMethodDeclaration(member)) {
|
|
18209
19866
|
const nameNode = member.getNameNode();
|
|
18210
19867
|
if (nameNode) {
|
|
18211
19868
|
keys.push(nameNode.getText());
|
|
18212
19869
|
}
|
|
18213
19870
|
}
|
|
18214
19871
|
}
|
|
18215
|
-
} else if (
|
|
19872
|
+
} else if (Node13.isArrayLiteralExpression(initializer)) {
|
|
18216
19873
|
for (const element of initializer.getElements()) {
|
|
18217
|
-
if (
|
|
19874
|
+
if (Node13.isObjectLiteralExpression(element)) {
|
|
18218
19875
|
const tokenProp = element.getProperty("token");
|
|
18219
|
-
if (tokenProp &&
|
|
19876
|
+
if (tokenProp && Node13.isPropertyAssignment(tokenProp)) {
|
|
18220
19877
|
const tokenInit = tokenProp.getInitializer();
|
|
18221
|
-
if (tokenInit && (
|
|
19878
|
+
if (tokenInit && (Node13.isStringLiteral(tokenInit) || Node13.isIdentifier(tokenInit))) {
|
|
18222
19879
|
keys.push(tokenInit.getText().replaceAll(/^['"]|['"]$/g, ""));
|
|
18223
19880
|
}
|
|
18224
19881
|
}
|
|
@@ -18270,7 +19927,7 @@ function computeRelativeSpecifiers(source) {
|
|
|
18270
19927
|
// packages/dbx-components-mcp/src/tools/route/load-sources.ts
|
|
18271
19928
|
var TRY_EXTENSIONS = [".ts", ".tsx", "/index.ts", "/index.tsx"];
|
|
18272
19929
|
async function loadRouteSources(args) {
|
|
18273
|
-
const cwdResolved = args.cwd ?
|
|
19930
|
+
const cwdResolved = args.cwd ? resolve20(process.cwd(), args.cwd) : process.cwd();
|
|
18274
19931
|
guardCwdInsideServer(args.cwd, cwdResolved);
|
|
18275
19932
|
const collected = /* @__PURE__ */ new Map();
|
|
18276
19933
|
if (args.sources) {
|
|
@@ -18342,21 +19999,21 @@ async function loadOne(relative5, cwd, into) {
|
|
|
18342
19999
|
if (into.has(relative5)) {
|
|
18343
20000
|
return;
|
|
18344
20001
|
}
|
|
18345
|
-
const absolute =
|
|
20002
|
+
const absolute = resolve20(cwd, relative5);
|
|
18346
20003
|
const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
|
|
18347
20004
|
if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
|
|
18348
20005
|
throw new Error(`Path \`${relative5}\` resolves outside the server cwd and is not allowed.`);
|
|
18349
20006
|
}
|
|
18350
|
-
const text = await
|
|
20007
|
+
const text = await readFile7(absolute, "utf8");
|
|
18351
20008
|
into.set(relative5, { name: relative5, text });
|
|
18352
20009
|
}
|
|
18353
20010
|
async function resolveRelativeImport(fromFile, specifier, cwd) {
|
|
18354
20011
|
if (!specifier.startsWith(".")) {
|
|
18355
20012
|
return void 0;
|
|
18356
20013
|
}
|
|
18357
|
-
const fromAbsolute = isAbsolute7(fromFile) ? fromFile :
|
|
20014
|
+
const fromAbsolute = isAbsolute7(fromFile) ? fromFile : resolve20(cwd, fromFile);
|
|
18358
20015
|
const fromDir = dirname7(fromAbsolute);
|
|
18359
|
-
const baseAbsolute =
|
|
20016
|
+
const baseAbsolute = resolve20(fromDir, specifier);
|
|
18360
20017
|
const cwdPrefix = cwd.endsWith(sep3) ? cwd : cwd + sep3;
|
|
18361
20018
|
for (const ext of TRY_EXTENSIONS) {
|
|
18362
20019
|
const candidateAbsolute = baseAbsolute + ext;
|
|
@@ -18367,7 +20024,7 @@ async function resolveRelativeImport(fromFile, specifier, cwd) {
|
|
|
18367
20024
|
if (!exists) {
|
|
18368
20025
|
continue;
|
|
18369
20026
|
}
|
|
18370
|
-
const text = await
|
|
20027
|
+
const text = await readFile7(candidateAbsolute, "utf8");
|
|
18371
20028
|
const relativeName = candidateAbsolute.startsWith(cwdPrefix) ? candidateAbsolute.slice(cwdPrefix.length) : candidateAbsolute;
|
|
18372
20029
|
const result = { name: relativeName, text };
|
|
18373
20030
|
return result;
|
|
@@ -18735,8 +20392,8 @@ var DBX_ROUTE_TREE_TOOL = {
|
|
|
18735
20392
|
}
|
|
18736
20393
|
}
|
|
18737
20394
|
};
|
|
18738
|
-
var TreeArgsType =
|
|
18739
|
-
"sources?":
|
|
20395
|
+
var TreeArgsType = type39({
|
|
20396
|
+
"sources?": type39({ name: "string", text: "string" }).array(),
|
|
18740
20397
|
"paths?": "string[]",
|
|
18741
20398
|
"glob?": "string",
|
|
18742
20399
|
"format?": "'markdown' | 'json' | 'flat'",
|
|
@@ -18745,7 +20402,7 @@ var TreeArgsType = type34({
|
|
|
18745
20402
|
});
|
|
18746
20403
|
function parseArgs3(raw) {
|
|
18747
20404
|
const parsed = TreeArgsType(raw);
|
|
18748
|
-
if (parsed instanceof
|
|
20405
|
+
if (parsed instanceof type39.errors) {
|
|
18749
20406
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
18750
20407
|
}
|
|
18751
20408
|
const result = {
|
|
@@ -18795,7 +20452,7 @@ var routeTreeTool = {
|
|
|
18795
20452
|
};
|
|
18796
20453
|
|
|
18797
20454
|
// packages/dbx-components-mcp/src/tools/route-lookup.tool.ts
|
|
18798
|
-
import { type as
|
|
20455
|
+
import { type as type40 } from "arktype";
|
|
18799
20456
|
var DBX_ROUTE_LOOKUP_TOOL = {
|
|
18800
20457
|
name: "dbx_route_lookup",
|
|
18801
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"),
|
|
@@ -18820,17 +20477,17 @@ var DBX_ROUTE_LOOKUP_TOOL = {
|
|
|
18820
20477
|
required: ["topic"]
|
|
18821
20478
|
}
|
|
18822
20479
|
};
|
|
18823
|
-
var
|
|
20480
|
+
var LookupArgsType2 = type40({
|
|
18824
20481
|
topic: "string",
|
|
18825
|
-
"sources?":
|
|
20482
|
+
"sources?": type40({ name: "string", text: "string" }).array(),
|
|
18826
20483
|
"paths?": "string[]",
|
|
18827
20484
|
"glob?": "string",
|
|
18828
20485
|
"depth?": "'brief' | 'full'",
|
|
18829
20486
|
"cwd?": "string"
|
|
18830
20487
|
});
|
|
18831
20488
|
function parseArgs4(raw) {
|
|
18832
|
-
const parsed =
|
|
18833
|
-
if (parsed instanceof
|
|
20489
|
+
const parsed = LookupArgsType2(raw);
|
|
20490
|
+
if (parsed instanceof type40.errors) {
|
|
18834
20491
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
18835
20492
|
}
|
|
18836
20493
|
const result = {
|
|
@@ -18900,8 +20557,8 @@ function fuzzyCandidates3(query, byName) {
|
|
|
18900
20557
|
return scored.slice(0, 5).map((s) => s.node);
|
|
18901
20558
|
}
|
|
18902
20559
|
function formatSingle(node, depth, via) {
|
|
18903
|
-
const urlText = node.fullUrl === void 0 ? "_no url_" :
|
|
18904
|
-
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);
|
|
18905
20562
|
const lines = [`# ${node.data.name}`, "", `Matched via ${via}.`, "", `- **URL:** ${urlText}`, `- **Component:** ${componentText}`, `- **Defined in:** \`${node.data.file}:${node.data.line}\``];
|
|
18906
20563
|
if (node.data.redirectTo) {
|
|
18907
20564
|
lines.push(`- **Redirects to:** \`${node.data.redirectTo}\``);
|
|
@@ -18925,7 +20582,7 @@ function formatSingle(node, depth, via) {
|
|
|
18925
20582
|
}
|
|
18926
20583
|
function appendParentChainSection(lines, node) {
|
|
18927
20584
|
const chain = ancestors(node);
|
|
18928
|
-
const chainLine = chain.map((c) =>
|
|
20585
|
+
const chainLine = chain.map((c) => code8(c.data.name)).join(" \u2192 ");
|
|
18929
20586
|
lines.push("", "## Parent chain", chainLine.length > 0 ? chainLine : "_root_");
|
|
18930
20587
|
}
|
|
18931
20588
|
function appendKeyListSection(lines, title, keys) {
|
|
@@ -18945,8 +20602,8 @@ function appendRelatedNodesSection(lines, title, nodes) {
|
|
|
18945
20602
|
return;
|
|
18946
20603
|
}
|
|
18947
20604
|
for (const child of nodes) {
|
|
18948
|
-
const urlPart = child.fullUrl === void 0 ? "" :
|
|
18949
|
-
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)}` : "";
|
|
18950
20607
|
lines.push(`- \`${child.data.name}\` ${urlPart}${componentPart}`);
|
|
18951
20608
|
}
|
|
18952
20609
|
}
|
|
@@ -18962,8 +20619,8 @@ function ancestors(node) {
|
|
|
18962
20619
|
function formatGroup2(title, nodes) {
|
|
18963
20620
|
const lines = [`# ${title}`, "", `${nodes.length} match(es).`, ""];
|
|
18964
20621
|
for (const node of nodes) {
|
|
18965
|
-
const urlPart = node.fullUrl === void 0 ? "" :
|
|
18966
|
-
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)}` : "";
|
|
18967
20624
|
lines.push(`- \`${node.data.name}\` ${urlPart}${componentPart} _(${node.data.file}:${node.data.line})_`);
|
|
18968
20625
|
}
|
|
18969
20626
|
return lines.join("\n");
|
|
@@ -18973,8 +20630,8 @@ function formatNotFound8(query, candidates) {
|
|
|
18973
20630
|
if (candidates.length > 0) {
|
|
18974
20631
|
lines.push("Did you mean one of these?", "");
|
|
18975
20632
|
for (const node of candidates) {
|
|
18976
|
-
const urlPart = node.fullUrl === void 0 ? "" :
|
|
18977
|
-
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)}` : "";
|
|
18978
20635
|
lines.push(`- \`${node.data.name}\` ${urlPart}${componentPart}`);
|
|
18979
20636
|
}
|
|
18980
20637
|
} else {
|
|
@@ -18982,7 +20639,7 @@ function formatNotFound8(query, candidates) {
|
|
|
18982
20639
|
}
|
|
18983
20640
|
return lines.join("\n");
|
|
18984
20641
|
}
|
|
18985
|
-
function
|
|
20642
|
+
function code8(value) {
|
|
18986
20643
|
return "`" + value + "`";
|
|
18987
20644
|
}
|
|
18988
20645
|
async function runRouteLookup(rawArgs) {
|
|
@@ -19023,7 +20680,7 @@ var routeLookupTool = {
|
|
|
19023
20680
|
};
|
|
19024
20681
|
|
|
19025
20682
|
// packages/dbx-components-mcp/src/tools/route-search.tool.ts
|
|
19026
|
-
import { type as
|
|
20683
|
+
import { type as type41 } from "arktype";
|
|
19027
20684
|
var DBX_ROUTE_SEARCH_TOOL = {
|
|
19028
20685
|
name: "dbx_route_search",
|
|
19029
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"),
|
|
@@ -19047,9 +20704,9 @@ var DBX_ROUTE_SEARCH_TOOL = {
|
|
|
19047
20704
|
required: ["query"]
|
|
19048
20705
|
}
|
|
19049
20706
|
};
|
|
19050
|
-
var SearchArgsType =
|
|
20707
|
+
var SearchArgsType = type41({
|
|
19051
20708
|
query: "string",
|
|
19052
|
-
"sources?":
|
|
20709
|
+
"sources?": type41({ name: "string", text: "string" }).array(),
|
|
19053
20710
|
"paths?": "string[]",
|
|
19054
20711
|
"glob?": "string",
|
|
19055
20712
|
"scope?": "'name' | 'url' | 'component' | 'resolve' | 'all'",
|
|
@@ -19057,7 +20714,7 @@ var SearchArgsType = type36({
|
|
|
19057
20714
|
});
|
|
19058
20715
|
function parseArgs5(raw) {
|
|
19059
20716
|
const parsed = SearchArgsType(raw);
|
|
19060
|
-
if (parsed instanceof
|
|
20717
|
+
if (parsed instanceof type41.errors) {
|
|
19061
20718
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
19062
20719
|
}
|
|
19063
20720
|
const result = {
|
|
@@ -19150,14 +20807,14 @@ var routeSearchTool = {
|
|
|
19150
20807
|
};
|
|
19151
20808
|
|
|
19152
20809
|
// packages/dbx-components-mcp/src/tools/_lookup.factory.ts
|
|
19153
|
-
import { type as
|
|
19154
|
-
var LOOKUP_ARGS_TYPE =
|
|
20810
|
+
import { type as type42 } from "arktype";
|
|
20811
|
+
var LOOKUP_ARGS_TYPE = type42({
|
|
19155
20812
|
topic: "string",
|
|
19156
20813
|
"depth?": "'brief' | 'full'"
|
|
19157
20814
|
});
|
|
19158
20815
|
function parseLookupArgs(raw) {
|
|
19159
20816
|
const parsed = LOOKUP_ARGS_TYPE(raw);
|
|
19160
|
-
if (parsed instanceof
|
|
20817
|
+
if (parsed instanceof type42.errors) {
|
|
19161
20818
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
19162
20819
|
}
|
|
19163
20820
|
const result = {
|
|
@@ -19306,11 +20963,11 @@ function formatEntry2(entry, depth) {
|
|
|
19306
20963
|
const fence = entry.kind === "pattern" ? "ts" : "html";
|
|
19307
20964
|
lines.push("## Example", "", "```" + fence, entry.example, "```");
|
|
19308
20965
|
if (entry.relatedSlugs.length > 0) {
|
|
19309
|
-
const relatedText = entry.relatedSlugs.map((s) =>
|
|
20966
|
+
const relatedText = entry.relatedSlugs.map((s) => code9(s)).join(", ");
|
|
19310
20967
|
lines.push("", `\u2192 Related: ${relatedText}`);
|
|
19311
20968
|
}
|
|
19312
20969
|
if (entry.skillRefs.length > 0) {
|
|
19313
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
20970
|
+
const skillsText = entry.skillRefs.map((s) => code9(s)).join(", ");
|
|
19314
20971
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
19315
20972
|
}
|
|
19316
20973
|
} else {
|
|
@@ -19339,7 +20996,7 @@ function formatNotFound9(normalized, candidates) {
|
|
|
19339
20996
|
}
|
|
19340
20997
|
return lines.join("\n");
|
|
19341
20998
|
}
|
|
19342
|
-
function
|
|
20999
|
+
function code9(value) {
|
|
19343
21000
|
return "`" + value + "`";
|
|
19344
21001
|
}
|
|
19345
21002
|
function createLookupFilterTool(input) {
|
|
@@ -19359,7 +21016,7 @@ function createLookupFilterTool(input) {
|
|
|
19359
21016
|
}
|
|
19360
21017
|
|
|
19361
21018
|
// packages/dbx-components-mcp/src/tools/filter-scaffold.tool.ts
|
|
19362
|
-
import { type as
|
|
21019
|
+
import { type as type43 } from "arktype";
|
|
19363
21020
|
var DBX_FILTER_SCAFFOLD_TOOL = {
|
|
19364
21021
|
name: "dbx_filter_scaffold",
|
|
19365
21022
|
description: [
|
|
@@ -19384,15 +21041,15 @@ var DBX_FILTER_SCAFFOLD_TOOL = {
|
|
|
19384
21041
|
required: ["model_name", "filter_type"]
|
|
19385
21042
|
}
|
|
19386
21043
|
};
|
|
19387
|
-
var
|
|
21044
|
+
var ScaffoldArgsType5 = type43({
|
|
19388
21045
|
model_name: "string",
|
|
19389
21046
|
filter_type: "string",
|
|
19390
21047
|
"preset_keys?": "string[]",
|
|
19391
21048
|
"uses_collection_store?": "boolean"
|
|
19392
21049
|
});
|
|
19393
21050
|
function parseArgs6(raw) {
|
|
19394
|
-
const parsed =
|
|
19395
|
-
if (parsed instanceof
|
|
21051
|
+
const parsed = ScaffoldArgsType5(raw);
|
|
21052
|
+
if (parsed instanceof type43.errors) {
|
|
19396
21053
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
19397
21054
|
}
|
|
19398
21055
|
const modelName = parsed.model_name.trim();
|
|
@@ -19575,11 +21232,11 @@ function formatEntry3(entry, depth) {
|
|
|
19575
21232
|
}
|
|
19576
21233
|
lines.push("## Example", "", "```html", entry.example, "```");
|
|
19577
21234
|
if (entry.relatedSlugs.length > 0) {
|
|
19578
|
-
const relatedText = entry.relatedSlugs.map((s) =>
|
|
21235
|
+
const relatedText = entry.relatedSlugs.map((s) => code10(s)).join(", ");
|
|
19579
21236
|
lines.push("", `\u2192 Related: ${relatedText}`);
|
|
19580
21237
|
}
|
|
19581
21238
|
if (entry.skillRefs.length > 0) {
|
|
19582
|
-
const skillsText = entry.skillRefs.map((s) =>
|
|
21239
|
+
const skillsText = entry.skillRefs.map((s) => code10(s)).join(", ");
|
|
19583
21240
|
lines.push("", `\u2192 Skills: ${skillsText}`);
|
|
19584
21241
|
}
|
|
19585
21242
|
} else {
|
|
@@ -19611,7 +21268,7 @@ function formatNotFound10(normalized, candidates) {
|
|
|
19611
21268
|
}
|
|
19612
21269
|
return lines.join("\n");
|
|
19613
21270
|
}
|
|
19614
|
-
function
|
|
21271
|
+
function code10(value) {
|
|
19615
21272
|
return "`" + value + "`";
|
|
19616
21273
|
}
|
|
19617
21274
|
function createLookupPipeTool(input) {
|
|
@@ -19632,8 +21289,8 @@ function createLookupPipeTool(input) {
|
|
|
19632
21289
|
|
|
19633
21290
|
// packages/dbx-components-mcp/src/tools/artifact-scaffold.tool.ts
|
|
19634
21291
|
import { access } from "node:fs/promises";
|
|
19635
|
-
import { resolve as
|
|
19636
|
-
import { type as
|
|
21292
|
+
import { resolve as resolve21, sep as sep4 } from "node:path";
|
|
21293
|
+
import { type as type44 } from "arktype";
|
|
19637
21294
|
|
|
19638
21295
|
// packages/dbx-components-mcp/src/tools/artifact-scaffold/templates.ts
|
|
19639
21296
|
function splitWords(input) {
|
|
@@ -20181,7 +21838,7 @@ var DBX_ARTIFACT_SCAFFOLD_TOOL = {
|
|
|
20181
21838
|
required: ["artifact", "name", "componentDir", "apiDir"]
|
|
20182
21839
|
}
|
|
20183
21840
|
};
|
|
20184
|
-
var ScaffoldArtifactArgsType =
|
|
21841
|
+
var ScaffoldArtifactArgsType = type44({
|
|
20185
21842
|
artifact: ARTIFACT_KIND_LITERAL_UNION,
|
|
20186
21843
|
name: "string",
|
|
20187
21844
|
componentDir: "string",
|
|
@@ -20194,7 +21851,7 @@ var ScaffoldArtifactArgsType = type39({
|
|
|
20194
21851
|
});
|
|
20195
21852
|
function parseArgs7(raw) {
|
|
20196
21853
|
const parsed = ScaffoldArtifactArgsType(raw);
|
|
20197
|
-
if (parsed instanceof
|
|
21854
|
+
if (parsed instanceof type44.errors) {
|
|
20198
21855
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
20199
21856
|
}
|
|
20200
21857
|
const result = {
|
|
@@ -20207,7 +21864,7 @@ function parseArgs7(raw) {
|
|
|
20207
21864
|
return result;
|
|
20208
21865
|
}
|
|
20209
21866
|
function ensureInsideCwd(relativePath, cwd) {
|
|
20210
|
-
const absolute =
|
|
21867
|
+
const absolute = resolve21(cwd, relativePath);
|
|
20211
21868
|
const cwdPrefix = cwd.endsWith(sep4) ? cwd : cwd + sep4;
|
|
20212
21869
|
if (!absolute.startsWith(cwdPrefix) && absolute !== cwd) {
|
|
20213
21870
|
throw new Error(`Path \`${relativePath}\` resolves outside the server cwd and is not allowed.`);
|
|
@@ -20247,7 +21904,7 @@ async function runArtifactScaffold(rawArgs) {
|
|
|
20247
21904
|
const message = err instanceof Error ? err.message : String(err);
|
|
20248
21905
|
return toolError(`Scaffold failed: ${message}`);
|
|
20249
21906
|
}
|
|
20250
|
-
const checked = await applyIdempotency(raw, (relativePath) => fileExists2(
|
|
21907
|
+
const checked = await applyIdempotency(raw, (relativePath) => fileExists2(resolve21(cwd, relativePath)));
|
|
20251
21908
|
const text = formatResult9(checked);
|
|
20252
21909
|
const result = {
|
|
20253
21910
|
content: [{ type: "text", text }]
|
|
@@ -20260,7 +21917,7 @@ var artifactScaffoldTool = {
|
|
|
20260
21917
|
};
|
|
20261
21918
|
|
|
20262
21919
|
// packages/dbx-components-mcp/src/tools/artifact-file-convention.tool.ts
|
|
20263
|
-
import { type as
|
|
21920
|
+
import { type as type45 } from "arktype";
|
|
20264
21921
|
|
|
20265
21922
|
// packages/dbx-components-mcp/src/tools/artifact-file-convention/spec.ts
|
|
20266
21923
|
var FIRESTORE_MODEL = {
|
|
@@ -20696,7 +22353,7 @@ var DBX_ARTIFACT_FILE_CONVENTION_TOOL = {
|
|
|
20696
22353
|
required: ["artifact"]
|
|
20697
22354
|
}
|
|
20698
22355
|
};
|
|
20699
|
-
var FileConventionArgsType =
|
|
22356
|
+
var FileConventionArgsType = type45({
|
|
20700
22357
|
artifact: ARTIFACT_KIND_LITERAL_UNION2,
|
|
20701
22358
|
"componentDir?": "string",
|
|
20702
22359
|
"apiDir?": "string",
|
|
@@ -20704,7 +22361,7 @@ var FileConventionArgsType = type40({
|
|
|
20704
22361
|
});
|
|
20705
22362
|
function parseArgs8(raw) {
|
|
20706
22363
|
const parsed = FileConventionArgsType(raw);
|
|
20707
|
-
if (parsed instanceof
|
|
22364
|
+
if (parsed instanceof type45.errors) {
|
|
20708
22365
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
20709
22366
|
}
|
|
20710
22367
|
const result = {
|
|
@@ -20737,7 +22394,7 @@ var artifactFileConventionTool = {
|
|
|
20737
22394
|
};
|
|
20738
22395
|
|
|
20739
22396
|
// packages/dbx-components-mcp/src/tools/lookup-semantic-type.tool.ts
|
|
20740
|
-
import { type as
|
|
22397
|
+
import { type as type46 } from "arktype";
|
|
20741
22398
|
|
|
20742
22399
|
// packages/dbx-components-mcp/src/tools/semantic-type-lookup.formatter.ts
|
|
20743
22400
|
function formatSemanticTypeEntry(entry, depth) {
|
|
@@ -20918,13 +22575,13 @@ var DBX_SEMANTIC_TYPE_LOOKUP_TOOL = {
|
|
|
20918
22575
|
required: ["name"]
|
|
20919
22576
|
}
|
|
20920
22577
|
};
|
|
20921
|
-
var LookupSemanticTypeArgsType =
|
|
22578
|
+
var LookupSemanticTypeArgsType = type46({
|
|
20922
22579
|
name: "string",
|
|
20923
22580
|
"depth?": "'brief' | 'full'"
|
|
20924
22581
|
});
|
|
20925
22582
|
function parseLookupArgs2(raw) {
|
|
20926
22583
|
const parsed = LookupSemanticTypeArgsType(raw);
|
|
20927
|
-
if (parsed instanceof
|
|
22584
|
+
if (parsed instanceof type46.errors) {
|
|
20928
22585
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
20929
22586
|
}
|
|
20930
22587
|
const result = {
|
|
@@ -20935,7 +22592,7 @@ function parseLookupArgs2(raw) {
|
|
|
20935
22592
|
}
|
|
20936
22593
|
function createSemanticTypeLookupTool(config) {
|
|
20937
22594
|
const { registry } = config;
|
|
20938
|
-
function
|
|
22595
|
+
function run5(rawArgs) {
|
|
20939
22596
|
let args;
|
|
20940
22597
|
let result;
|
|
20941
22598
|
try {
|
|
@@ -20971,7 +22628,7 @@ function createSemanticTypeLookupTool(config) {
|
|
|
20971
22628
|
}
|
|
20972
22629
|
const tool = {
|
|
20973
22630
|
definition: DBX_SEMANTIC_TYPE_LOOKUP_TOOL,
|
|
20974
|
-
run
|
|
22631
|
+
run: run5
|
|
20975
22632
|
};
|
|
20976
22633
|
return tool;
|
|
20977
22634
|
}
|
|
@@ -20986,7 +22643,7 @@ function formatNotFound11(name, registry) {
|
|
|
20986
22643
|
}
|
|
20987
22644
|
|
|
20988
22645
|
// packages/dbx-components-mcp/src/tools/search-semantic-type.tool.ts
|
|
20989
|
-
import { type as
|
|
22646
|
+
import { type as type47 } from "arktype";
|
|
20990
22647
|
var DEFAULT_LIMIT4 = 25;
|
|
20991
22648
|
var MAX_LIMIT4 = 100;
|
|
20992
22649
|
var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
|
|
@@ -21019,7 +22676,7 @@ var DBX_SEMANTIC_TYPE_SEARCH_TOOL = {
|
|
|
21019
22676
|
}
|
|
21020
22677
|
}
|
|
21021
22678
|
};
|
|
21022
|
-
var SearchSemanticTypeArgsType =
|
|
22679
|
+
var SearchSemanticTypeArgsType = type47({
|
|
21023
22680
|
"topic?": "string",
|
|
21024
22681
|
"baseType?": "string",
|
|
21025
22682
|
"package?": "string",
|
|
@@ -21028,7 +22685,7 @@ var SearchSemanticTypeArgsType = type42({
|
|
|
21028
22685
|
});
|
|
21029
22686
|
function parseSearchArgs2(raw) {
|
|
21030
22687
|
const parsed = SearchSemanticTypeArgsType(raw);
|
|
21031
|
-
if (parsed instanceof
|
|
22688
|
+
if (parsed instanceof type47.errors) {
|
|
21032
22689
|
throw new TypeError(`Invalid arguments: ${parsed.summary}`);
|
|
21033
22690
|
}
|
|
21034
22691
|
const rawLimit = parsed.limit ?? DEFAULT_LIMIT4;
|
|
@@ -21054,7 +22711,7 @@ function nonEmpty(value) {
|
|
|
21054
22711
|
}
|
|
21055
22712
|
function createSemanticTypeSearchTool(config) {
|
|
21056
22713
|
const { registry } = config;
|
|
21057
|
-
function
|
|
22714
|
+
function run5(rawArgs) {
|
|
21058
22715
|
let args;
|
|
21059
22716
|
let result;
|
|
21060
22717
|
try {
|
|
@@ -21079,7 +22736,7 @@ function createSemanticTypeSearchTool(config) {
|
|
|
21079
22736
|
}
|
|
21080
22737
|
const tool = {
|
|
21081
22738
|
definition: DBX_SEMANTIC_TYPE_SEARCH_TOOL,
|
|
21082
|
-
run
|
|
22739
|
+
run: run5
|
|
21083
22740
|
};
|
|
21084
22741
|
return tool;
|
|
21085
22742
|
}
|
|
@@ -21153,6 +22810,10 @@ var DBX_TOOLS = [
|
|
|
21153
22810
|
modelValidateApiTool,
|
|
21154
22811
|
modelValidateFolderTool,
|
|
21155
22812
|
modelStoreScaffoldTool,
|
|
22813
|
+
modelFixtureListAppTool,
|
|
22814
|
+
modelFixtureLookupTool,
|
|
22815
|
+
modelFixtureScaffoldTool,
|
|
22816
|
+
modelFixtureForwardTool,
|
|
21156
22817
|
// storagefile_m (model extension)
|
|
21157
22818
|
storageFileMValidateAppTool,
|
|
21158
22819
|
storageFileMListAppTool,
|
|
@@ -21179,6 +22840,7 @@ var DBX_TOOLS = [
|
|
|
21179
22840
|
function registerTools(server, options = {}) {
|
|
21180
22841
|
const underlyingServer = server.server;
|
|
21181
22842
|
const tools = [...DBX_TOOLS];
|
|
22843
|
+
tools.push(createModelFixtureValidateAppTool({ getRegistry: () => options.fixtureModelRegistry }));
|
|
21182
22844
|
if (options.forgeFieldRegistry !== void 0) {
|
|
21183
22845
|
tools.push(createLookupFormTool({ registry: options.forgeFieldRegistry }), createSearchFormTool({ registry: options.forgeFieldRegistry }), createFormScaffoldTool({ registry: options.forgeFieldRegistry }));
|
|
21184
22846
|
}
|
|
@@ -21228,6 +22890,7 @@ Tool clusters (each exposes lookup, search, examples, and/or scaffold/validate):
|
|
|
21228
22890
|
|
|
21229
22891
|
Model-extension validators (walk a downstream app to verify wiring):
|
|
21230
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)
|
|
21231
22894
|
|
|
21232
22895
|
Resource URIs are namespaced by domain:
|
|
21233
22896
|
- dbx://form/fields[/{slug}|/produces/{produces}|/tier/{tier}|/array-output/{arrayOutput}]
|
|
@@ -21350,8 +23013,11 @@ async function createServer(options = {}) {
|
|
|
21350
23013
|
filterRegistry = void 0;
|
|
21351
23014
|
}
|
|
21352
23015
|
}
|
|
23016
|
+
const fixtureModelRegistry = {
|
|
23017
|
+
entries: FIREBASE_MODELS.map((m) => ({ name: m.name, modelType: m.modelType, collectionPrefix: m.collectionPrefix }))
|
|
23018
|
+
};
|
|
21353
23019
|
registerResources(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
|
|
21354
|
-
registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry });
|
|
23020
|
+
registerTools(server, { semanticTypeRegistry: registry, forgeFieldRegistry: forgeRegistry, pipeRegistry, uiComponentRegistry: uiRegistry, actionRegistry, filterRegistry, fixtureModelRegistry });
|
|
21355
23021
|
return server;
|
|
21356
23022
|
}
|
|
21357
23023
|
async function runStdioServer() {
|