@xano/developer-mcp 1.0.52 → 1.0.54
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/dist/cli_docs/index.d.ts +6 -0
- package/dist/cli_docs/index.js +6 -0
- package/dist/meta_api_docs/index.d.ts +6 -0
- package/dist/meta_api_docs/index.js +6 -0
- package/dist/tools/index.d.ts +12 -0
- package/dist/tools/mcp_version.d.ts +6 -0
- package/dist/tools/mcp_version.js +6 -0
- package/dist/tools/validate_xanoscript.d.ts +6 -0
- package/dist/tools/validate_xanoscript.js +6 -0
- package/dist/tools/xanoscript_docs.d.ts +14 -0
- package/dist/tools/xanoscript_docs.js +18 -3
- package/dist/xanoscript.d.ts +1 -0
- package/dist/xanoscript.js +38 -41
- package/dist/xanoscript.test.js +47 -11
- package/dist/xanoscript_docs/cheatsheet.md +17 -15
- package/dist/xanoscript_docs/debugging.md +1 -1
- package/dist/xanoscript_docs/quickstart.md +6 -4
- package/dist/xanoscript_docs/security.md +2 -2
- package/dist/xanoscript_docs/unit-testing.md +12 -12
- package/package.json +1 -1
package/dist/cli_docs/index.d.ts
CHANGED
|
@@ -26,6 +26,12 @@ export declare function handleCliDocs(args: CliDocsArgs): string;
|
|
|
26
26
|
*/
|
|
27
27
|
export declare const cliDocsToolDefinition: {
|
|
28
28
|
name: string;
|
|
29
|
+
annotations: {
|
|
30
|
+
readOnlyHint: boolean;
|
|
31
|
+
destructiveHint: boolean;
|
|
32
|
+
idempotentHint: boolean;
|
|
33
|
+
openWorldHint: boolean;
|
|
34
|
+
};
|
|
29
35
|
description: string;
|
|
30
36
|
inputSchema: {
|
|
31
37
|
type: string;
|
package/dist/cli_docs/index.js
CHANGED
|
@@ -59,6 +59,12 @@ export function handleCliDocs(args) {
|
|
|
59
59
|
*/
|
|
60
60
|
export const cliDocsToolDefinition = {
|
|
61
61
|
name: "cli_docs",
|
|
62
|
+
annotations: {
|
|
63
|
+
readOnlyHint: true,
|
|
64
|
+
destructiveHint: false,
|
|
65
|
+
idempotentHint: true,
|
|
66
|
+
openWorldHint: false,
|
|
67
|
+
},
|
|
62
68
|
description: `Get documentation for the Xano CLI. Use this to understand how to use the CLI for local development, code sync, and XanoScript execution.
|
|
63
69
|
|
|
64
70
|
## Topics
|
|
@@ -26,6 +26,12 @@ export declare function handleMetaApiDocs(args: MetaApiDocsArgs): string;
|
|
|
26
26
|
*/
|
|
27
27
|
export declare const metaApiDocsToolDefinition: {
|
|
28
28
|
name: string;
|
|
29
|
+
annotations: {
|
|
30
|
+
readOnlyHint: boolean;
|
|
31
|
+
destructiveHint: boolean;
|
|
32
|
+
idempotentHint: boolean;
|
|
33
|
+
openWorldHint: boolean;
|
|
34
|
+
};
|
|
29
35
|
description: string;
|
|
30
36
|
inputSchema: {
|
|
31
37
|
type: string;
|
|
@@ -77,6 +77,12 @@ export function handleMetaApiDocs(args) {
|
|
|
77
77
|
*/
|
|
78
78
|
export const metaApiDocsToolDefinition = {
|
|
79
79
|
name: "meta_api_docs",
|
|
80
|
+
annotations: {
|
|
81
|
+
readOnlyHint: true,
|
|
82
|
+
destructiveHint: false,
|
|
83
|
+
idempotentHint: true,
|
|
84
|
+
openWorldHint: false,
|
|
85
|
+
},
|
|
80
86
|
description: `Get documentation for Xano's Meta API. Use this to understand how to programmatically manage Xano workspaces, databases, APIs, functions, agents, and more.
|
|
81
87
|
|
|
82
88
|
## Topics
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -42,6 +42,12 @@ export { validateXanoscriptToolDefinition, xanoscriptDocsToolDefinition, mcpVers
|
|
|
42
42
|
*/
|
|
43
43
|
export declare const toolDefinitions: ({
|
|
44
44
|
name: string;
|
|
45
|
+
annotations: {
|
|
46
|
+
readOnlyHint: boolean;
|
|
47
|
+
destructiveHint: boolean;
|
|
48
|
+
idempotentHint: boolean;
|
|
49
|
+
openWorldHint: boolean;
|
|
50
|
+
};
|
|
45
51
|
description: string;
|
|
46
52
|
inputSchema: {
|
|
47
53
|
type: string;
|
|
@@ -50,6 +56,12 @@ export declare const toolDefinitions: ({
|
|
|
50
56
|
};
|
|
51
57
|
} | {
|
|
52
58
|
name: string;
|
|
59
|
+
annotations: {
|
|
60
|
+
readOnlyHint: boolean;
|
|
61
|
+
destructiveHint: boolean;
|
|
62
|
+
idempotentHint: boolean;
|
|
63
|
+
openWorldHint: boolean;
|
|
64
|
+
};
|
|
53
65
|
description: string;
|
|
54
66
|
inputSchema: {
|
|
55
67
|
type: string;
|
|
@@ -36,6 +36,12 @@ export declare function mcpVersion(): McpVersionResult;
|
|
|
36
36
|
export declare function mcpVersionTool(): ToolResult;
|
|
37
37
|
export declare const mcpVersionToolDefinition: {
|
|
38
38
|
name: string;
|
|
39
|
+
annotations: {
|
|
40
|
+
readOnlyHint: boolean;
|
|
41
|
+
destructiveHint: boolean;
|
|
42
|
+
idempotentHint: boolean;
|
|
43
|
+
openWorldHint: boolean;
|
|
44
|
+
};
|
|
39
45
|
description: string;
|
|
40
46
|
inputSchema: {
|
|
41
47
|
type: string;
|
|
@@ -84,6 +84,12 @@ export function mcpVersionTool() {
|
|
|
84
84
|
// =============================================================================
|
|
85
85
|
export const mcpVersionToolDefinition = {
|
|
86
86
|
name: "mcp_version",
|
|
87
|
+
annotations: {
|
|
88
|
+
readOnlyHint: true,
|
|
89
|
+
destructiveHint: false,
|
|
90
|
+
idempotentHint: true,
|
|
91
|
+
openWorldHint: false,
|
|
92
|
+
},
|
|
87
93
|
description: "Get the current version of the Xano Developer MCP server. " +
|
|
88
94
|
"Returns the version string from package.json.",
|
|
89
95
|
inputSchema: {
|
|
@@ -109,6 +109,12 @@ export declare function validateXanoscript(args: ValidateXanoscriptArgs): Valida
|
|
|
109
109
|
export declare function validateXanoscriptTool(args: ValidateXanoscriptArgs): ToolResult;
|
|
110
110
|
export declare const validateXanoscriptToolDefinition: {
|
|
111
111
|
name: string;
|
|
112
|
+
annotations: {
|
|
113
|
+
readOnlyHint: boolean;
|
|
114
|
+
destructiveHint: boolean;
|
|
115
|
+
idempotentHint: boolean;
|
|
116
|
+
openWorldHint: boolean;
|
|
117
|
+
};
|
|
112
118
|
description: string;
|
|
113
119
|
inputSchema: {
|
|
114
120
|
type: string;
|
|
@@ -388,6 +388,12 @@ export function validateXanoscriptTool(args) {
|
|
|
388
388
|
// =============================================================================
|
|
389
389
|
export const validateXanoscriptToolDefinition = {
|
|
390
390
|
name: "validate_xanoscript",
|
|
391
|
+
annotations: {
|
|
392
|
+
readOnlyHint: true,
|
|
393
|
+
destructiveHint: false,
|
|
394
|
+
idempotentHint: true,
|
|
395
|
+
openWorldHint: false,
|
|
396
|
+
},
|
|
391
397
|
description: "Validate XanoScript code for syntax errors. Supports multiple input methods:\n" +
|
|
392
398
|
"- code: Raw XanoScript code as a string\n" +
|
|
393
399
|
"- file_path: Path to a single .xs file (easier than escaping code!)\n" +
|
|
@@ -50,11 +50,18 @@ export declare function xanoscriptDocsTool(args?: XanoscriptDocsArgs): ToolResul
|
|
|
50
50
|
export declare const xanoscriptDocsToolDefinition: {
|
|
51
51
|
name: string;
|
|
52
52
|
description: string;
|
|
53
|
+
annotations: {
|
|
54
|
+
readOnlyHint: boolean;
|
|
55
|
+
destructiveHint: boolean;
|
|
56
|
+
idempotentHint: boolean;
|
|
57
|
+
openWorldHint: boolean;
|
|
58
|
+
};
|
|
53
59
|
inputSchema: {
|
|
54
60
|
type: string;
|
|
55
61
|
properties: {
|
|
56
62
|
topic: {
|
|
57
63
|
type: string;
|
|
64
|
+
enum: string[];
|
|
58
65
|
description: string;
|
|
59
66
|
};
|
|
60
67
|
file_path: {
|
|
@@ -66,6 +73,13 @@ export declare const xanoscriptDocsToolDefinition: {
|
|
|
66
73
|
enum: string[];
|
|
67
74
|
description: string;
|
|
68
75
|
};
|
|
76
|
+
exclude_topics: {
|
|
77
|
+
type: string;
|
|
78
|
+
items: {
|
|
79
|
+
type: string;
|
|
80
|
+
};
|
|
81
|
+
description: string;
|
|
82
|
+
};
|
|
69
83
|
};
|
|
70
84
|
required: never[];
|
|
71
85
|
};
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { readFileSync } from "fs";
|
|
8
8
|
import { dirname, join } from "path";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
|
-
import { readXanoscriptDocsV2, getTopicDescriptions, } from "../xanoscript.js";
|
|
10
|
+
import { readXanoscriptDocsV2, getTopicNames, getTopicDescriptions, } from "../xanoscript.js";
|
|
11
11
|
// =============================================================================
|
|
12
12
|
// Path Resolution
|
|
13
13
|
// =============================================================================
|
|
@@ -104,12 +104,20 @@ export const xanoscriptDocsToolDefinition = {
|
|
|
104
104
|
description: "Get XanoScript programming language documentation for AI code generation. " +
|
|
105
105
|
"Call without parameters for overview (README). " +
|
|
106
106
|
"Use 'topic' for specific documentation, or 'file_path' for context-aware docs based on the file you're editing. " +
|
|
107
|
-
"Use mode='quick_reference' for compact syntax cheatsheet (recommended for context efficiency)."
|
|
107
|
+
"Use mode='quick_reference' for compact syntax cheatsheet (recommended for context efficiency). " +
|
|
108
|
+
"file_path mode defaults to 'quick_reference' to reduce context size; use mode='full' to get complete docs.",
|
|
109
|
+
annotations: {
|
|
110
|
+
readOnlyHint: true,
|
|
111
|
+
destructiveHint: false,
|
|
112
|
+
idempotentHint: true,
|
|
113
|
+
openWorldHint: false,
|
|
114
|
+
},
|
|
108
115
|
inputSchema: {
|
|
109
116
|
type: "object",
|
|
110
117
|
properties: {
|
|
111
118
|
topic: {
|
|
112
119
|
type: "string",
|
|
120
|
+
enum: getTopicNames(),
|
|
113
121
|
description: "Documentation topic to retrieve. Call without any parameters to get the README overview. " +
|
|
114
122
|
"Example: topic='syntax' for language syntax, topic='database' for database operations, topic='types' for type system.\n\n" +
|
|
115
123
|
"Available topics:\n" + getTopicDescriptions(),
|
|
@@ -127,7 +135,14 @@ export const xanoscriptDocsToolDefinition = {
|
|
|
127
135
|
description: "'full' = complete documentation with explanations and examples. " +
|
|
128
136
|
"'quick_reference' = compact cheatsheet with just syntax patterns and signatures. " +
|
|
129
137
|
"Use 'quick_reference' to save context window space when you just need a reminder. " +
|
|
130
|
-
"Default: 'full'.",
|
|
138
|
+
"Default: 'full' for topic mode, 'quick_reference' for file_path mode.",
|
|
139
|
+
},
|
|
140
|
+
exclude_topics: {
|
|
141
|
+
type: "array",
|
|
142
|
+
items: { type: "string" },
|
|
143
|
+
description: "List of topic names to exclude from file_path results. " +
|
|
144
|
+
"Use this to skip topics you've already loaded (e.g., exclude_topics: ['syntax', 'quickstart']). " +
|
|
145
|
+
"Only applies when using file_path parameter.",
|
|
131
146
|
},
|
|
132
147
|
},
|
|
133
148
|
required: [],
|
package/dist/xanoscript.d.ts
CHANGED
package/dist/xanoscript.js
CHANGED
|
@@ -93,7 +93,7 @@ export const XANOSCRIPT_DOCS_V2 = {
|
|
|
93
93
|
},
|
|
94
94
|
integrations: {
|
|
95
95
|
file: "integrations.md",
|
|
96
|
-
applyTo: [
|
|
96
|
+
applyTo: [],
|
|
97
97
|
description: "External service integrations index - see sub-topics for details",
|
|
98
98
|
},
|
|
99
99
|
"integrations/cloud-storage": {
|
|
@@ -133,7 +133,7 @@ export const XANOSCRIPT_DOCS_V2 = {
|
|
|
133
133
|
},
|
|
134
134
|
addons: {
|
|
135
135
|
file: "addons.md",
|
|
136
|
-
applyTo: ["addons/*.xs"
|
|
136
|
+
applyTo: ["addons/*.xs"],
|
|
137
137
|
description: "Reusable subqueries for fetching related data",
|
|
138
138
|
},
|
|
139
139
|
debugging: {
|
|
@@ -148,12 +148,12 @@ export const XANOSCRIPT_DOCS_V2 = {
|
|
|
148
148
|
},
|
|
149
149
|
realtime: {
|
|
150
150
|
file: "realtime.md",
|
|
151
|
-
applyTo: ["
|
|
151
|
+
applyTo: ["triggers/**/*.xs"],
|
|
152
152
|
description: "Real-time channels and events for push updates",
|
|
153
153
|
},
|
|
154
154
|
schema: {
|
|
155
155
|
file: "schema.md",
|
|
156
|
-
applyTo: [
|
|
156
|
+
applyTo: [],
|
|
157
157
|
description: "Runtime schema parsing and validation",
|
|
158
158
|
},
|
|
159
159
|
security: {
|
|
@@ -163,7 +163,7 @@ export const XANOSCRIPT_DOCS_V2 = {
|
|
|
163
163
|
},
|
|
164
164
|
streaming: {
|
|
165
165
|
file: "streaming.md",
|
|
166
|
-
applyTo: [
|
|
166
|
+
applyTo: [],
|
|
167
167
|
description: "Streaming data from files, requests, and responses",
|
|
168
168
|
},
|
|
169
169
|
middleware: {
|
|
@@ -241,49 +241,46 @@ export function getXanoscriptDocsVersion(docsPath) {
|
|
|
241
241
|
* Read XanoScript documentation with v2 structure
|
|
242
242
|
*/
|
|
243
243
|
export function readXanoscriptDocsV2(docsPath, args) {
|
|
244
|
-
|
|
244
|
+
// Default to quick_reference for file_path mode (loads many topics),
|
|
245
|
+
// full for topic mode (loads single topic)
|
|
246
|
+
const mode = args?.mode || (args?.file_path ? "quick_reference" : "full");
|
|
245
247
|
const version = getXanoscriptDocsVersion(docsPath);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
// Default: return README
|
|
249
|
+
if (!args?.topic && !args?.file_path) {
|
|
250
|
+
const readme = readFileSync(join(docsPath, "README.md"), "utf-8");
|
|
251
|
+
return `${readme}\n\n---\nDocumentation version: ${version}`;
|
|
252
|
+
}
|
|
253
|
+
// Context-aware: return docs matching file pattern
|
|
254
|
+
if (args?.file_path) {
|
|
255
|
+
let topics = getDocsForFilePath(args.file_path);
|
|
256
|
+
// Filter out excluded topics
|
|
257
|
+
if (args.exclude_topics && args.exclude_topics.length > 0) {
|
|
258
|
+
topics = topics.filter((t) => !args.exclude_topics.includes(t));
|
|
251
259
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const topics = getDocsForFilePath(args.file_path);
|
|
255
|
-
if (topics.length === 0) {
|
|
256
|
-
return `No documentation found for file pattern: ${args.file_path}\n\nAvailable topics: ${Object.keys(XANOSCRIPT_DOCS_V2).join(", ")}`;
|
|
257
|
-
}
|
|
258
|
-
const docs = topics.map((t) => {
|
|
259
|
-
const config = XANOSCRIPT_DOCS_V2[t];
|
|
260
|
-
const content = readFileSync(join(docsPath, config.file), "utf-8");
|
|
261
|
-
return mode === "quick_reference"
|
|
262
|
-
? extractQuickReference(content, t)
|
|
263
|
-
: content;
|
|
264
|
-
});
|
|
265
|
-
const header = `# XanoScript Documentation for: ${args.file_path}\n\nMatched topics: ${topics.join(", ")}\nMode: ${mode}\nVersion: ${version}\n\n---\n\n`;
|
|
266
|
-
return header + docs.join("\n\n---\n\n");
|
|
260
|
+
if (topics.length === 0) {
|
|
261
|
+
throw new Error(`No documentation found for file pattern: ${args.file_path}\n\nAvailable topics: ${Object.keys(XANOSCRIPT_DOCS_V2).join(", ")}`);
|
|
267
262
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const config = XANOSCRIPT_DOCS_V2[args.topic];
|
|
271
|
-
if (!config) {
|
|
272
|
-
const availableTopics = Object.keys(XANOSCRIPT_DOCS_V2).join(", ");
|
|
273
|
-
return `Error: Unknown topic "${args.topic}".\n\nAvailable topics: ${availableTopics}`;
|
|
274
|
-
}
|
|
263
|
+
const docs = topics.map((t) => {
|
|
264
|
+
const config = XANOSCRIPT_DOCS_V2[t];
|
|
275
265
|
const content = readFileSync(join(docsPath, config.file), "utf-8");
|
|
276
|
-
|
|
277
|
-
? extractQuickReference(content,
|
|
266
|
+
return mode === "quick_reference"
|
|
267
|
+
? extractQuickReference(content, t)
|
|
278
268
|
: content;
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
return
|
|
269
|
+
});
|
|
270
|
+
const header = `# XanoScript Documentation for: ${args.file_path}\n\nMatched topics: ${topics.join(", ")}\nMode: ${mode}\nVersion: ${version}\n\n---\n\n`;
|
|
271
|
+
return header + docs.join("\n\n---\n\n");
|
|
282
272
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
273
|
+
// Topic-based: return specific doc
|
|
274
|
+
const config = XANOSCRIPT_DOCS_V2[args.topic];
|
|
275
|
+
if (!config) {
|
|
276
|
+
const availableTopics = Object.keys(XANOSCRIPT_DOCS_V2).join(", ");
|
|
277
|
+
throw new Error(`Unknown topic "${args.topic}".\n\nAvailable topics: ${availableTopics}`);
|
|
286
278
|
}
|
|
279
|
+
const content = readFileSync(join(docsPath, config.file), "utf-8");
|
|
280
|
+
const doc = mode === "quick_reference"
|
|
281
|
+
? extractQuickReference(content, args.topic)
|
|
282
|
+
: content;
|
|
283
|
+
return `${doc}\n\n---\nDocumentation version: ${version}`;
|
|
287
284
|
}
|
|
288
285
|
/**
|
|
289
286
|
* Get available topic names
|
package/dist/xanoscript.test.js
CHANGED
|
@@ -70,7 +70,12 @@ describe("xanoscript module", () => {
|
|
|
70
70
|
expect(result).toContain("types");
|
|
71
71
|
expect(result).toContain("database");
|
|
72
72
|
expect(result).toContain("unit-testing");
|
|
73
|
-
|
|
73
|
+
// Niche topics should NOT be auto-included for apis
|
|
74
|
+
expect(result).not.toContain("addons");
|
|
75
|
+
expect(result).not.toContain("integrations");
|
|
76
|
+
expect(result).not.toContain("realtime");
|
|
77
|
+
expect(result).not.toContain("schema");
|
|
78
|
+
expect(result).not.toContain("streaming");
|
|
74
79
|
});
|
|
75
80
|
it("should match functions files", () => {
|
|
76
81
|
const result = getDocsForFilePath("functions/utils/format.xs");
|
|
@@ -78,6 +83,12 @@ describe("xanoscript module", () => {
|
|
|
78
83
|
expect(result).toContain("functions");
|
|
79
84
|
expect(result).toContain("types");
|
|
80
85
|
expect(result).toContain("database");
|
|
86
|
+
// Niche topics should NOT be auto-included for functions
|
|
87
|
+
expect(result).not.toContain("addons");
|
|
88
|
+
expect(result).not.toContain("integrations");
|
|
89
|
+
expect(result).not.toContain("realtime");
|
|
90
|
+
expect(result).not.toContain("schema");
|
|
91
|
+
expect(result).not.toContain("streaming");
|
|
81
92
|
});
|
|
82
93
|
it("should match tables files", () => {
|
|
83
94
|
const result = getDocsForFilePath("tables/users.xs");
|
|
@@ -89,7 +100,8 @@ describe("xanoscript module", () => {
|
|
|
89
100
|
expect(result).toContain("syntax");
|
|
90
101
|
expect(result).toContain("tasks");
|
|
91
102
|
expect(result).toContain("database");
|
|
92
|
-
|
|
103
|
+
// integrations is now topic-only (not auto-included)
|
|
104
|
+
expect(result).not.toContain("integrations");
|
|
93
105
|
});
|
|
94
106
|
it("should match triggers files", () => {
|
|
95
107
|
const result = getDocsForFilePath("triggers/table/users.xs");
|
|
@@ -126,7 +138,7 @@ describe("xanoscript module", () => {
|
|
|
126
138
|
expect(result).toContain("branch");
|
|
127
139
|
});
|
|
128
140
|
it("should match workspace.xs", () => {
|
|
129
|
-
const result = getDocsForFilePath("workspace.xs");
|
|
141
|
+
const result = getDocsForFilePath("workspace/workspace.xs");
|
|
130
142
|
expect(result).toContain("syntax");
|
|
131
143
|
expect(result).toContain("workspace");
|
|
132
144
|
});
|
|
@@ -236,10 +248,8 @@ Even more content.
|
|
|
236
248
|
const result = readXanoscriptDocsV2(DOCS_PATH, { topic: "syntax" });
|
|
237
249
|
expect(result).toContain("Documentation version:");
|
|
238
250
|
});
|
|
239
|
-
it("should
|
|
240
|
-
|
|
241
|
-
expect(result).toContain('Error: Unknown topic "nonexistent"');
|
|
242
|
-
expect(result).toContain("Available topics:");
|
|
251
|
+
it("should throw for unknown topic", () => {
|
|
252
|
+
expect(() => readXanoscriptDocsV2(DOCS_PATH, { topic: "nonexistent" })).toThrow('Unknown topic "nonexistent"');
|
|
243
253
|
});
|
|
244
254
|
it("should return context-aware docs for file_path", () => {
|
|
245
255
|
const result = readXanoscriptDocsV2(DOCS_PATH, {
|
|
@@ -272,11 +282,37 @@ Even more content.
|
|
|
272
282
|
});
|
|
273
283
|
expect(quickResult).toContain("Mode: quick_reference");
|
|
274
284
|
});
|
|
275
|
-
it("should
|
|
276
|
-
const result = readXanoscriptDocsV2(
|
|
277
|
-
|
|
285
|
+
it("should default to quick_reference mode for file_path", () => {
|
|
286
|
+
const result = readXanoscriptDocsV2(DOCS_PATH, {
|
|
287
|
+
file_path: "apis/test.xs",
|
|
288
|
+
});
|
|
289
|
+
expect(result).toContain("Mode: quick_reference");
|
|
290
|
+
});
|
|
291
|
+
it("should default to full mode for topic", () => {
|
|
292
|
+
const result = readXanoscriptDocsV2(DOCS_PATH, { topic: "syntax" });
|
|
293
|
+
// Full mode returns the complete doc content, not quick_reference
|
|
294
|
+
expect(result).not.toContain("Mode: quick_reference");
|
|
295
|
+
});
|
|
296
|
+
it("should support exclude_topics with file_path", () => {
|
|
297
|
+
const result = readXanoscriptDocsV2(DOCS_PATH, {
|
|
298
|
+
file_path: "apis/users/create.xs",
|
|
299
|
+
exclude_topics: ["syntax", "quickstart"],
|
|
278
300
|
});
|
|
279
|
-
expect(result).toContain("
|
|
301
|
+
expect(result).toContain("Matched topics:");
|
|
302
|
+
expect(result).not.toContain("Matched topics: syntax");
|
|
303
|
+
// Verify excluded topics are not in the matched list
|
|
304
|
+
const matchLine = result.split("\n").find((l) => l.startsWith("Matched topics:"));
|
|
305
|
+
expect(matchLine).not.toContain("syntax");
|
|
306
|
+
expect(matchLine).not.toContain("quickstart");
|
|
307
|
+
});
|
|
308
|
+
it("should throw when all topics are excluded via exclude_topics", () => {
|
|
309
|
+
expect(() => readXanoscriptDocsV2(DOCS_PATH, {
|
|
310
|
+
file_path: "branch.xs",
|
|
311
|
+
exclude_topics: ["syntax", "cheatsheet", "quickstart", "debugging", "branch"],
|
|
312
|
+
})).toThrow("No documentation found");
|
|
313
|
+
});
|
|
314
|
+
it("should throw for invalid docs path", () => {
|
|
315
|
+
expect(() => readXanoscriptDocsV2("/nonexistent/path", { topic: "syntax" })).toThrow();
|
|
280
316
|
});
|
|
281
317
|
});
|
|
282
318
|
describe("getTopicNames", () => {
|
|
@@ -6,7 +6,9 @@ applyTo: "**/*.xs"
|
|
|
6
6
|
|
|
7
7
|
> **Purpose:** Quick reference for the 20 most common XanoScript patterns. For detailed documentation, use `xanoscript_docs({ topic: "<topic>" })`.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Quick Reference
|
|
10
|
+
|
|
11
|
+
### Variable Declaration
|
|
10
12
|
|
|
11
13
|
```xs
|
|
12
14
|
var $name { value = "initial" }
|
|
@@ -15,7 +17,7 @@ var $items { value = [] }
|
|
|
15
17
|
var $data { value = { key: "value" } }
|
|
16
18
|
```
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
### Conditionals
|
|
19
21
|
|
|
20
22
|
```xs
|
|
21
23
|
conditional {
|
|
@@ -33,7 +35,7 @@ conditional {
|
|
|
33
35
|
|
|
34
36
|
> **Note:** Use `elseif` (one word), not `else if`.
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
### Switch
|
|
37
39
|
|
|
38
40
|
```xs
|
|
39
41
|
switch ($input.status) {
|
|
@@ -51,7 +53,7 @@ switch ($input.status) {
|
|
|
51
53
|
|
|
52
54
|
> **Note:** `break` goes **after** the closing `}` of each `case` block. The `default` case does not need `break`.
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
### Loops
|
|
55
57
|
|
|
56
58
|
```xs
|
|
57
59
|
// For each loop
|
|
@@ -81,7 +83,7 @@ var $names { value = $items|map:$$.name }
|
|
|
81
83
|
var $active { value = $items|filter:$$.is_active }
|
|
82
84
|
```
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
### Database CRUD
|
|
85
87
|
|
|
86
88
|
```xs
|
|
87
89
|
// Get single record by field
|
|
@@ -113,7 +115,7 @@ db.edit "user" {
|
|
|
113
115
|
db.del "user" { field_name = "id", field_value = $input.user_id }
|
|
114
116
|
```
|
|
115
117
|
|
|
116
|
-
|
|
118
|
+
### API Requests
|
|
117
119
|
|
|
118
120
|
```xs
|
|
119
121
|
api.request {
|
|
@@ -133,7 +135,7 @@ api.request {
|
|
|
133
135
|
// $api_result.response.headers → Response headers
|
|
134
136
|
```
|
|
135
137
|
|
|
136
|
-
|
|
138
|
+
### Error Handling
|
|
137
139
|
|
|
138
140
|
```xs
|
|
139
141
|
// Precondition (stops execution if false)
|
|
@@ -159,7 +161,7 @@ throw {
|
|
|
159
161
|
}
|
|
160
162
|
```
|
|
161
163
|
|
|
162
|
-
|
|
164
|
+
### Error Types
|
|
163
165
|
|
|
164
166
|
| Type | HTTP Status | Use Case |
|
|
165
167
|
|------|-------------|----------|
|
|
@@ -168,7 +170,7 @@ throw {
|
|
|
168
170
|
| `notfound` | 404 | Resource doesn't exist |
|
|
169
171
|
| `standard` | 500 | General errors |
|
|
170
172
|
|
|
171
|
-
|
|
173
|
+
### Common Filters
|
|
172
174
|
|
|
173
175
|
```xs
|
|
174
176
|
// String
|
|
@@ -210,7 +212,7 @@ $num|round:2 // Round to 2 decimals
|
|
|
210
212
|
$num|abs // Absolute value
|
|
211
213
|
```
|
|
212
214
|
|
|
213
|
-
|
|
215
|
+
### Authentication Check
|
|
214
216
|
|
|
215
217
|
```xs
|
|
216
218
|
precondition ($auth.id != null) {
|
|
@@ -219,7 +221,7 @@ precondition ($auth.id != null) {
|
|
|
219
221
|
}
|
|
220
222
|
```
|
|
221
223
|
|
|
222
|
-
|
|
224
|
+
### Function Call
|
|
223
225
|
|
|
224
226
|
```xs
|
|
225
227
|
function.run "my_function" {
|
|
@@ -227,7 +229,7 @@ function.run "my_function" {
|
|
|
227
229
|
} as $result
|
|
228
230
|
```
|
|
229
231
|
|
|
230
|
-
|
|
232
|
+
### String Concatenation
|
|
231
233
|
|
|
232
234
|
```xs
|
|
233
235
|
// Basic
|
|
@@ -237,7 +239,7 @@ var $msg { value = "Hello, " ~ $input.name ~ "!" }
|
|
|
237
239
|
var $msg { value = ($status|to_text) ~ ": " ~ ($data|json_encode) }
|
|
238
240
|
```
|
|
239
241
|
|
|
240
|
-
|
|
242
|
+
### Common Type Names
|
|
241
243
|
|
|
242
244
|
| Use This | Not This |
|
|
243
245
|
|----------|----------|
|
|
@@ -247,11 +249,11 @@ var $msg { value = ($status|to_text) ~ ": " ~ ($data|json_encode) }
|
|
|
247
249
|
| `decimal` | float, number |
|
|
248
250
|
| `type[]` | array, list |
|
|
249
251
|
|
|
250
|
-
|
|
252
|
+
### Reserved Variables (Cannot Use)
|
|
251
253
|
|
|
252
254
|
`$response`, `$output`, `$input`, `$auth`, `$env`, `$db`, `$this`, `$result`, `$index`
|
|
253
255
|
|
|
254
|
-
|
|
256
|
+
### Input Block Syntax
|
|
255
257
|
|
|
256
258
|
`?` after the **type** = nullable, `?` after the **variable name** = optional (not required).
|
|
257
259
|
|
|
@@ -298,7 +298,7 @@ precondition ($input.email|contains:"@") {
|
|
|
298
298
|
| `db.query` | Filtered list | `db.query "users" { where = $db.users.active == true } as $users` |
|
|
299
299
|
| `db.add` | Insert | `db.add "users" { data = { name: "John" } } as $new` |
|
|
300
300
|
| `db.edit` | Update | `db.edit "users" { field_name = "id" field_value = 1 data = { name: "Jane" } }` |
|
|
301
|
-
| `db.
|
|
301
|
+
| `db.del` | Delete | `db.del "users" { field_name = "id" field_value = 1 }` |
|
|
302
302
|
|
|
303
303
|
> **Full reference:** See `xanoscript_docs({ topic: "database" })` for joins, bulk operations, transactions, and more.
|
|
304
304
|
|
|
@@ -323,9 +323,11 @@ var $data {
|
|
|
323
323
|
### 4. Loop Through Array
|
|
324
324
|
|
|
325
325
|
```xs
|
|
326
|
-
// Using
|
|
327
|
-
|
|
328
|
-
|
|
326
|
+
// Using foreach
|
|
327
|
+
foreach ($items) {
|
|
328
|
+
each as $item {
|
|
329
|
+
debug.log { value = $item.name }
|
|
330
|
+
}
|
|
329
331
|
}
|
|
330
332
|
|
|
331
333
|
// Using map filter
|
|
@@ -96,7 +96,7 @@ function "refresh_auth" {
|
|
|
96
96
|
} as $new_token
|
|
97
97
|
|
|
98
98
|
// Rotate refresh token
|
|
99
|
-
|
|
99
|
+
security.create_uuid as $new_refresh
|
|
100
100
|
|
|
101
101
|
db.edit "refresh_token" {
|
|
102
102
|
field_name = "id"
|
|
@@ -120,7 +120,7 @@ function "refresh_auth" {
|
|
|
120
120
|
function "create_session" {
|
|
121
121
|
input { int user_id }
|
|
122
122
|
stack {
|
|
123
|
-
|
|
123
|
+
security.create_uuid as $session_id
|
|
124
124
|
|
|
125
125
|
db.add "session" {
|
|
126
126
|
data = {
|
|
@@ -107,34 +107,34 @@ function "add" {
|
|
|
107
107
|
### Value Assertions
|
|
108
108
|
|
|
109
109
|
```xs
|
|
110
|
-
|
|
110
|
+
// Equality
|
|
111
111
|
expect.to_equal ($response.status) { value = "active" }
|
|
112
112
|
expect.to_not_equal ($response.status) { value = "deleted" }
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
// Boolean
|
|
115
115
|
expect.to_be_true ($response.is_active)
|
|
116
116
|
expect.to_be_false ($response.is_deleted)
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
// Null
|
|
119
119
|
expect.to_be_null ($response.deleted_at)
|
|
120
120
|
expect.to_not_be_null ($response.created_at)
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
// Defined
|
|
123
123
|
expect.to_be_defined ($response.id)
|
|
124
124
|
expect.to_not_be_defined ($response.optional_field)
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
// Empty
|
|
127
127
|
expect.to_be_empty ($response.errors)
|
|
128
128
|
```
|
|
129
129
|
|
|
130
130
|
### Comparison Assertions
|
|
131
131
|
|
|
132
132
|
```xs
|
|
133
|
-
|
|
133
|
+
// Numeric comparisons
|
|
134
134
|
expect.to_be_greater_than ($response.total) { value = 100 }
|
|
135
135
|
expect.to_be_less_than ($response.stock) { value = 10 }
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
// Range
|
|
138
138
|
expect.to_be_within ($response.temperature) {
|
|
139
139
|
min = 20
|
|
140
140
|
max = 30
|
|
@@ -144,14 +144,14 @@ expect.to_be_within ($response.temperature) {
|
|
|
144
144
|
### String Assertions
|
|
145
145
|
|
|
146
146
|
```xs
|
|
147
|
-
|
|
147
|
+
// Starts/ends with
|
|
148
148
|
expect.to_start_with ($response.name) { value = "John" }
|
|
149
149
|
expect.to_end_with ($response.file) { value = ".pdf" }
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
// Contains
|
|
152
152
|
expect.to_contain ($response.tags) { value = "featured" }
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
// Regex match
|
|
155
155
|
expect.to_match ($response.phone) { value = "^\\+1\\d{10}$" }
|
|
156
156
|
```
|
|
157
157
|
|
|
@@ -165,13 +165,13 @@ expect.to_be_in_the_future ($response.expires_at)
|
|
|
165
165
|
### Error Assertions
|
|
166
166
|
|
|
167
167
|
```xs
|
|
168
|
-
|
|
168
|
+
// Expects any error
|
|
169
169
|
test "throws on invalid input" {
|
|
170
170
|
input = { amount: -1 }
|
|
171
171
|
expect.to_throw
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
// Expects specific error
|
|
175
175
|
test "throws validation error" {
|
|
176
176
|
input = { amount: -1 }
|
|
177
177
|
expect.to_throw { value = "InvalidInputError" }
|
package/package.json
CHANGED