@xano/developer-mcp 1.0.34 → 1.0.35
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/tools/index.d.ts +2 -15
- package/dist/tools/index.js +2 -2
- package/dist/tools/validate_xanoscript.d.ts +84 -9
- package/dist/tools/validate_xanoscript.js +345 -31
- package/dist/xanoscript_docs/README.md +14 -1
- package/dist/xanoscript_docs/database.md +14 -0
- package/dist/xanoscript_docs/functions.md +14 -0
- package/dist/xanoscript_docs/quickstart.md +326 -13
- package/dist/xanoscript_docs/syntax.md +22 -0
- package/dist/xanoscript_docs/types.md +14 -0
- package/package.json +1 -1
package/dist/tools/index.d.ts
CHANGED
|
@@ -29,33 +29,20 @@
|
|
|
29
29
|
* const docs = xanoscriptDocs({ topic: 'syntax' });
|
|
30
30
|
* ```
|
|
31
31
|
*/
|
|
32
|
-
import { validateXanoscript, validateXanoscriptTool, validateXanoscriptToolDefinition, type ValidateXanoscriptArgs, type ValidationResult, type ParserDiagnostic } from "./validate_xanoscript.js";
|
|
32
|
+
import { validateXanoscript, validateXanoscriptTool, validateXanoscriptToolDefinition, TYPE_ALIASES, RESERVED_VARIABLES, type ValidateXanoscriptArgs, type ValidationResult, type BatchValidationResult, type SingleFileValidationResult, type ParserDiagnostic } from "./validate_xanoscript.js";
|
|
33
33
|
import { xanoscriptDocs, xanoscriptDocsTool, xanoscriptDocsToolDefinition, getXanoscriptDocsPath, setXanoscriptDocsPath, type XanoscriptDocsArgs, type XanoscriptDocsResult } from "./xanoscript_docs.js";
|
|
34
34
|
import { mcpVersion, mcpVersionTool, mcpVersionToolDefinition, getServerVersion, setServerVersion, type McpVersionResult } from "./mcp_version.js";
|
|
35
35
|
import { metaApiDocs, metaApiDocsTool, metaApiDocsToolDefinition, metaApiTopics, getMetaApiTopicNames, getMetaApiTopicDescriptions, type MetaApiDocsArgs, type MetaApiDocsResult } from "./meta_api_docs.js";
|
|
36
36
|
import { runApiDocs, runApiDocsTool, runApiDocsToolDefinition, runApiTopics, getRunApiTopicNames, getRunApiTopicDescriptions, type RunApiDocsArgs, type RunApiDocsResult } from "./run_api_docs.js";
|
|
37
37
|
import { cliDocs, cliDocsTool, cliDocsToolDefinition, cliTopics, getCliTopicNames, getCliTopicDescriptions, type CliDocsArgs, type CliDocsResult } from "./cli_docs.js";
|
|
38
38
|
import { type ToolResult, toMcpResponse } from "./types.js";
|
|
39
|
-
export { validateXanoscript, type ValidateXanoscriptArgs, type ValidationResult, type ParserDiagnostic, xanoscriptDocs, getXanoscriptDocsPath, setXanoscriptDocsPath, type XanoscriptDocsArgs, type XanoscriptDocsResult, mcpVersion, getServerVersion, setServerVersion, type McpVersionResult, metaApiDocs, metaApiTopics, getMetaApiTopicNames, getMetaApiTopicDescriptions, type MetaApiDocsArgs, type MetaApiDocsResult, runApiDocs, runApiTopics, getRunApiTopicNames, getRunApiTopicDescriptions, type RunApiDocsArgs, type RunApiDocsResult, cliDocs, cliTopics, getCliTopicNames, getCliTopicDescriptions, type CliDocsArgs, type CliDocsResult, type ToolResult, toMcpResponse, };
|
|
39
|
+
export { validateXanoscript, TYPE_ALIASES, RESERVED_VARIABLES, type ValidateXanoscriptArgs, type ValidationResult, type BatchValidationResult, type SingleFileValidationResult, type ParserDiagnostic, xanoscriptDocs, getXanoscriptDocsPath, setXanoscriptDocsPath, type XanoscriptDocsArgs, type XanoscriptDocsResult, mcpVersion, getServerVersion, setServerVersion, type McpVersionResult, metaApiDocs, metaApiTopics, getMetaApiTopicNames, getMetaApiTopicDescriptions, type MetaApiDocsArgs, type MetaApiDocsResult, runApiDocs, runApiTopics, getRunApiTopicNames, getRunApiTopicDescriptions, type RunApiDocsArgs, type RunApiDocsResult, cliDocs, cliTopics, getCliTopicNames, getCliTopicDescriptions, type CliDocsArgs, type CliDocsResult, type ToolResult, toMcpResponse, };
|
|
40
40
|
export { validateXanoscriptTool, xanoscriptDocsTool, mcpVersionTool, metaApiDocsTool, runApiDocsTool, cliDocsTool, };
|
|
41
41
|
export { validateXanoscriptToolDefinition, xanoscriptDocsToolDefinition, mcpVersionToolDefinition, metaApiDocsToolDefinition, runApiDocsToolDefinition, cliDocsToolDefinition, };
|
|
42
42
|
/**
|
|
43
43
|
* All tool definitions for MCP server registration
|
|
44
44
|
*/
|
|
45
45
|
export declare const toolDefinitions: ({
|
|
46
|
-
name: string;
|
|
47
|
-
description: string;
|
|
48
|
-
inputSchema: {
|
|
49
|
-
type: string;
|
|
50
|
-
properties: {
|
|
51
|
-
code: {
|
|
52
|
-
type: string;
|
|
53
|
-
description: string;
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
required: string[];
|
|
57
|
-
};
|
|
58
|
-
} | {
|
|
59
46
|
name: string;
|
|
60
47
|
description: string;
|
|
61
48
|
inputSchema: {
|
package/dist/tools/index.js
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
// =============================================================================
|
|
33
33
|
// Tool Imports
|
|
34
34
|
// =============================================================================
|
|
35
|
-
import { validateXanoscript, validateXanoscriptTool, validateXanoscriptToolDefinition, } from "./validate_xanoscript.js";
|
|
35
|
+
import { validateXanoscript, validateXanoscriptTool, validateXanoscriptToolDefinition, TYPE_ALIASES, RESERVED_VARIABLES, } from "./validate_xanoscript.js";
|
|
36
36
|
import { xanoscriptDocs, xanoscriptDocsTool, xanoscriptDocsToolDefinition, getXanoscriptDocsPath, setXanoscriptDocsPath, } from "./xanoscript_docs.js";
|
|
37
37
|
import { mcpVersion, mcpVersionTool, mcpVersionToolDefinition, getServerVersion, setServerVersion, } from "./mcp_version.js";
|
|
38
38
|
import { metaApiDocs, metaApiDocsTool, metaApiDocsToolDefinition, metaApiTopics, getMetaApiTopicNames, getMetaApiTopicDescriptions, } from "./meta_api_docs.js";
|
|
@@ -44,7 +44,7 @@ import { toMcpResponse } from "./types.js";
|
|
|
44
44
|
// =============================================================================
|
|
45
45
|
export {
|
|
46
46
|
// Validation
|
|
47
|
-
validateXanoscript,
|
|
47
|
+
validateXanoscript, TYPE_ALIASES, RESERVED_VARIABLES,
|
|
48
48
|
// XanoScript Documentation
|
|
49
49
|
xanoscriptDocs, getXanoscriptDocsPath, setXanoscriptDocsPath,
|
|
50
50
|
// MCP Version
|
|
@@ -3,11 +3,25 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Validates XanoScript code for syntax errors using the XanoScript language server.
|
|
5
5
|
* Can be used standalone or within the MCP server.
|
|
6
|
+
*
|
|
7
|
+
* Supports multiple input methods:
|
|
8
|
+
* - code: Raw XanoScript code as a string
|
|
9
|
+
* - file_path: Path to a single .xs file
|
|
10
|
+
* - file_paths: Array of file paths for batch validation
|
|
11
|
+
* - directory: Directory path with optional glob pattern
|
|
6
12
|
*/
|
|
7
13
|
import type { ToolResult } from "./types.js";
|
|
8
14
|
export interface ValidateXanoscriptArgs {
|
|
9
|
-
/** The XanoScript code to validate */
|
|
10
|
-
code
|
|
15
|
+
/** The XanoScript code to validate (mutually exclusive with file_path/file_paths/directory) */
|
|
16
|
+
code?: string;
|
|
17
|
+
/** Path to a single XanoScript file to validate */
|
|
18
|
+
file_path?: string;
|
|
19
|
+
/** Array of file paths for batch validation */
|
|
20
|
+
file_paths?: string[];
|
|
21
|
+
/** Directory to validate (validates all .xs files recursively) */
|
|
22
|
+
directory?: string;
|
|
23
|
+
/** Glob pattern to filter files when using directory (default: "**\/*.xs") */
|
|
24
|
+
pattern?: string;
|
|
11
25
|
}
|
|
12
26
|
export interface ParserDiagnostic {
|
|
13
27
|
range: {
|
|
@@ -23,14 +37,42 @@ export interface ParserDiagnostic {
|
|
|
23
37
|
message: string;
|
|
24
38
|
source: string;
|
|
25
39
|
}
|
|
40
|
+
export interface SingleFileValidationResult {
|
|
41
|
+
valid: boolean;
|
|
42
|
+
errors: ParserDiagnostic[];
|
|
43
|
+
message: string;
|
|
44
|
+
file_path?: string;
|
|
45
|
+
}
|
|
26
46
|
export interface ValidationResult {
|
|
27
47
|
valid: boolean;
|
|
28
48
|
errors: ParserDiagnostic[];
|
|
29
49
|
message: string;
|
|
30
50
|
}
|
|
51
|
+
export interface BatchValidationResult {
|
|
52
|
+
valid: boolean;
|
|
53
|
+
total_files: number;
|
|
54
|
+
valid_files: number;
|
|
55
|
+
invalid_files: number;
|
|
56
|
+
results: SingleFileValidationResult[];
|
|
57
|
+
message: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Common type aliases that users might try
|
|
61
|
+
*/
|
|
62
|
+
declare const TYPE_ALIASES: Record<string, string>;
|
|
63
|
+
/**
|
|
64
|
+
* Reserved variable names that cannot be used
|
|
65
|
+
*/
|
|
66
|
+
declare const RESERVED_VARIABLES: string[];
|
|
31
67
|
/**
|
|
32
68
|
* Validate XanoScript code for syntax errors.
|
|
33
69
|
*
|
|
70
|
+
* Supports multiple input methods:
|
|
71
|
+
* - code: Raw XanoScript code as a string
|
|
72
|
+
* - file_path: Path to a single .xs file
|
|
73
|
+
* - file_paths: Array of file paths for batch validation
|
|
74
|
+
* - directory: Directory path with optional glob pattern
|
|
75
|
+
*
|
|
34
76
|
* @param args - The validation arguments
|
|
35
77
|
* @returns Validation result with errors if any
|
|
36
78
|
*
|
|
@@ -38,15 +80,28 @@ export interface ValidationResult {
|
|
|
38
80
|
* ```ts
|
|
39
81
|
* import { validateXanoscript } from '@xano/developer-mcp';
|
|
40
82
|
*
|
|
83
|
+
* // Validate code directly
|
|
41
84
|
* const result = validateXanoscript({ code: 'return 1 + 1' });
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
85
|
+
*
|
|
86
|
+
* // Validate a single file
|
|
87
|
+
* const fileResult = validateXanoscript({ file_path: './functions/utils.xs' });
|
|
88
|
+
*
|
|
89
|
+
* // Validate multiple files
|
|
90
|
+
* const batchResult = validateXanoscript({
|
|
91
|
+
* file_paths: ['./apis/users/get.xs', './apis/users/create.xs']
|
|
92
|
+
* });
|
|
93
|
+
*
|
|
94
|
+
* // Validate all .xs files in a directory
|
|
95
|
+
* const dirResult = validateXanoscript({ directory: './src' });
|
|
96
|
+
*
|
|
97
|
+
* // Validate with a specific pattern
|
|
98
|
+
* const patternResult = validateXanoscript({
|
|
99
|
+
* directory: './src',
|
|
100
|
+
* pattern: 'apis/**\/*.xs'
|
|
101
|
+
* });
|
|
47
102
|
* ```
|
|
48
103
|
*/
|
|
49
|
-
export declare function validateXanoscript(args: ValidateXanoscriptArgs): ValidationResult;
|
|
104
|
+
export declare function validateXanoscript(args: ValidateXanoscriptArgs): ValidationResult | BatchValidationResult;
|
|
50
105
|
/**
|
|
51
106
|
* Validate XanoScript and return a simplified result.
|
|
52
107
|
* Returns ToolResult format for consistent error handling.
|
|
@@ -62,7 +117,27 @@ export declare const validateXanoscriptToolDefinition: {
|
|
|
62
117
|
type: string;
|
|
63
118
|
description: string;
|
|
64
119
|
};
|
|
120
|
+
file_path: {
|
|
121
|
+
type: string;
|
|
122
|
+
description: string;
|
|
123
|
+
};
|
|
124
|
+
file_paths: {
|
|
125
|
+
type: string;
|
|
126
|
+
items: {
|
|
127
|
+
type: string;
|
|
128
|
+
};
|
|
129
|
+
description: string;
|
|
130
|
+
};
|
|
131
|
+
directory: {
|
|
132
|
+
type: string;
|
|
133
|
+
description: string;
|
|
134
|
+
};
|
|
135
|
+
pattern: {
|
|
136
|
+
type: string;
|
|
137
|
+
description: string;
|
|
138
|
+
};
|
|
65
139
|
};
|
|
66
|
-
required:
|
|
140
|
+
required: never[];
|
|
67
141
|
};
|
|
68
142
|
};
|
|
143
|
+
export { TYPE_ALIASES, RESERVED_VARIABLES };
|
|
@@ -3,47 +3,183 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Validates XanoScript code for syntax errors using the XanoScript language server.
|
|
5
5
|
* Can be used standalone or within the MCP server.
|
|
6
|
+
*
|
|
7
|
+
* Supports multiple input methods:
|
|
8
|
+
* - code: Raw XanoScript code as a string
|
|
9
|
+
* - file_path: Path to a single .xs file
|
|
10
|
+
* - file_paths: Array of file paths for batch validation
|
|
11
|
+
* - directory: Directory path with optional glob pattern
|
|
6
12
|
*/
|
|
7
13
|
import { xanoscriptParser } from "@xano/xanoscript-language-server/parser/parser.js";
|
|
8
14
|
import { getSchemeFromContent } from "@xano/xanoscript-language-server/utils.js";
|
|
15
|
+
import { readFileSync, existsSync, readdirSync } from "fs";
|
|
16
|
+
import { join, resolve, basename } from "path";
|
|
17
|
+
import { minimatch } from "minimatch";
|
|
9
18
|
// =============================================================================
|
|
10
|
-
//
|
|
19
|
+
// Error Message Improvements
|
|
11
20
|
// =============================================================================
|
|
12
21
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* @param args - The validation arguments
|
|
16
|
-
* @returns Validation result with errors if any
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```ts
|
|
20
|
-
* import { validateXanoscript } from '@xano/developer-mcp';
|
|
21
|
-
*
|
|
22
|
-
* const result = validateXanoscript({ code: 'return 1 + 1' });
|
|
23
|
-
* if (result.valid) {
|
|
24
|
-
* console.log('Code is valid!');
|
|
25
|
-
* } else {
|
|
26
|
-
* console.log('Errors:', result.errors);
|
|
27
|
-
* }
|
|
28
|
-
* ```
|
|
22
|
+
* Common type aliases that users might try
|
|
29
23
|
*/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
24
|
+
const TYPE_ALIASES = {
|
|
25
|
+
boolean: "bool",
|
|
26
|
+
integer: "int",
|
|
27
|
+
string: "text",
|
|
28
|
+
number: "decimal",
|
|
29
|
+
float: "decimal",
|
|
30
|
+
double: "decimal",
|
|
31
|
+
array: "type[]",
|
|
32
|
+
list: "type[]",
|
|
33
|
+
object: "json",
|
|
34
|
+
map: "json",
|
|
35
|
+
dict: "json",
|
|
36
|
+
dictionary: "json",
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Reserved variable names that cannot be used
|
|
40
|
+
*/
|
|
41
|
+
const RESERVED_VARIABLES = [
|
|
42
|
+
"$response",
|
|
43
|
+
"$output",
|
|
44
|
+
"$input",
|
|
45
|
+
"$auth",
|
|
46
|
+
"$env",
|
|
47
|
+
"$db",
|
|
48
|
+
"$this",
|
|
49
|
+
"$result",
|
|
50
|
+
];
|
|
51
|
+
/**
|
|
52
|
+
* Common syntax mistakes and their fixes
|
|
53
|
+
*/
|
|
54
|
+
const SYNTAX_SUGGESTIONS = [
|
|
55
|
+
{
|
|
56
|
+
pattern: /else\s+if/,
|
|
57
|
+
suggestion: 'Use "elseif" (one word) instead of "else if"',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
pattern: /body\s*=/,
|
|
61
|
+
suggestion: 'Use "params" instead of "body" for api.request request body',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
pattern: /\|default:/,
|
|
65
|
+
suggestion: 'There is no "default" filter. Use "first_notnull" or "??" operator instead',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
pattern: /boolean/,
|
|
69
|
+
suggestion: 'Use "bool" instead of "boolean" for type declaration',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
pattern: /integer(?!\s*\()/,
|
|
73
|
+
suggestion: 'Use "int" instead of "integer" for type declaration',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
pattern: /string(?!\s*\()/,
|
|
77
|
+
suggestion: 'Use "text" instead of "string" for type declaration',
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
/**
|
|
81
|
+
* Enhance error message with helpful suggestions
|
|
82
|
+
*/
|
|
83
|
+
function enhanceErrorMessage(message, code, lineNumber) {
|
|
84
|
+
let enhanced = message;
|
|
85
|
+
const lines = code.split("\n");
|
|
86
|
+
const errorLine = lines[lineNumber] || "";
|
|
87
|
+
// Check for type aliases
|
|
88
|
+
for (const [alias, correct] of Object.entries(TYPE_ALIASES)) {
|
|
89
|
+
const regex = new RegExp(`\\b${alias}\\b`, "i");
|
|
90
|
+
if (regex.test(errorLine)) {
|
|
91
|
+
enhanced += `\n\n💡 Suggestion: Use "${correct}" instead of "${alias}"`;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Check for reserved variables
|
|
96
|
+
for (const reserved of RESERVED_VARIABLES) {
|
|
97
|
+
if (errorLine.includes(`var ${reserved}`) ||
|
|
98
|
+
errorLine.includes(`var.update ${reserved}`)) {
|
|
99
|
+
enhanced += `\n\n💡 "${reserved}" is a reserved variable name. Try a different name like "${reserved.replace("$", "$my_")}"`;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Check for common syntax mistakes
|
|
104
|
+
for (const { pattern, suggestion } of SYNTAX_SUGGESTIONS) {
|
|
105
|
+
if (pattern.test(errorLine) || pattern.test(code)) {
|
|
106
|
+
enhanced += `\n\n💡 Suggestion: ${suggestion}`;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Add the actual line of code for context
|
|
111
|
+
if (errorLine.trim()) {
|
|
112
|
+
enhanced += `\n\nCode at line ${lineNumber + 1}:\n ${errorLine.trim()}`;
|
|
113
|
+
}
|
|
114
|
+
return enhanced;
|
|
115
|
+
}
|
|
116
|
+
// =============================================================================
|
|
117
|
+
// File Reading Utilities
|
|
118
|
+
// =============================================================================
|
|
119
|
+
/**
|
|
120
|
+
* Read a file and return its contents
|
|
121
|
+
*/
|
|
122
|
+
function readFile(filePath) {
|
|
123
|
+
try {
|
|
124
|
+
const absolutePath = resolve(filePath);
|
|
125
|
+
if (!existsSync(absolutePath)) {
|
|
126
|
+
return { content: "", error: `File not found: ${filePath}` };
|
|
127
|
+
}
|
|
128
|
+
const content = readFileSync(absolutePath, "utf-8");
|
|
129
|
+
return { content };
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
133
|
+
return { content: "", error: `Error reading file: ${errorMessage}` };
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Find all .xs files in a directory matching the pattern
|
|
138
|
+
*/
|
|
139
|
+
function findXsFiles(directory, pattern = "**/*.xs") {
|
|
140
|
+
const absoluteDir = resolve(directory);
|
|
141
|
+
if (!existsSync(absoluteDir)) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
const files = [];
|
|
145
|
+
function walkDir(dir, basePath = "") {
|
|
146
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
147
|
+
for (const entry of entries) {
|
|
148
|
+
const fullPath = join(dir, entry.name);
|
|
149
|
+
const relativePath = basePath ? join(basePath, entry.name) : entry.name;
|
|
150
|
+
if (entry.isDirectory()) {
|
|
151
|
+
walkDir(fullPath, relativePath);
|
|
152
|
+
}
|
|
153
|
+
else if (entry.isFile() && entry.name.endsWith(".xs")) {
|
|
154
|
+
if (minimatch(relativePath, pattern)) {
|
|
155
|
+
files.push(fullPath);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
37
159
|
}
|
|
160
|
+
walkDir(absoluteDir);
|
|
161
|
+
return files;
|
|
162
|
+
}
|
|
163
|
+
// =============================================================================
|
|
164
|
+
// Standalone Tool Function
|
|
165
|
+
// =============================================================================
|
|
166
|
+
/**
|
|
167
|
+
* Validate a single piece of XanoScript code.
|
|
168
|
+
* Internal function used by the public API.
|
|
169
|
+
*/
|
|
170
|
+
function validateCode(code, filePath) {
|
|
38
171
|
try {
|
|
39
|
-
const text =
|
|
172
|
+
const text = code;
|
|
40
173
|
const scheme = getSchemeFromContent(text);
|
|
41
174
|
const parser = xanoscriptParser(text, scheme);
|
|
42
175
|
if (parser.errors.length === 0) {
|
|
43
176
|
return {
|
|
44
177
|
valid: true,
|
|
45
178
|
errors: [],
|
|
46
|
-
message:
|
|
179
|
+
message: filePath
|
|
180
|
+
? `✓ ${basename(filePath)}: Valid`
|
|
181
|
+
: "XanoScript is valid. No syntax errors found.",
|
|
182
|
+
file_path: filePath,
|
|
47
183
|
};
|
|
48
184
|
}
|
|
49
185
|
const diagnostics = parser.errors.map((error) => {
|
|
@@ -55,12 +191,14 @@ export function validateXanoscript(args) {
|
|
|
55
191
|
const endLines = text.substring(0, endOffset + 1).split("\n");
|
|
56
192
|
const endLine = endLines.length - 1;
|
|
57
193
|
const endCharacter = endLines[endLines.length - 1].length;
|
|
194
|
+
// Enhance error message with suggestions
|
|
195
|
+
const enhancedMessage = enhanceErrorMessage(error.message, text, line);
|
|
58
196
|
return {
|
|
59
197
|
range: {
|
|
60
198
|
start: { line, character },
|
|
61
199
|
end: { line: endLine, character: endCharacter },
|
|
62
200
|
},
|
|
63
|
-
message:
|
|
201
|
+
message: enhancedMessage,
|
|
64
202
|
source: error.name || "XanoScript Parser",
|
|
65
203
|
};
|
|
66
204
|
});
|
|
@@ -68,10 +206,12 @@ export function validateXanoscript(args) {
|
|
|
68
206
|
const location = `Line ${d.range.start.line + 1}, Column ${d.range.start.character + 1}`;
|
|
69
207
|
return `${i + 1}. [${location}] ${d.message}`;
|
|
70
208
|
});
|
|
209
|
+
const prefix = filePath ? `✗ ${basename(filePath)}: ` : "";
|
|
71
210
|
return {
|
|
72
211
|
valid: false,
|
|
73
212
|
errors: diagnostics,
|
|
74
|
-
message:
|
|
213
|
+
message: `${prefix}Found ${diagnostics.length} error(s):\n\n${errorMessages.join("\n")}`,
|
|
214
|
+
file_path: filePath,
|
|
75
215
|
};
|
|
76
216
|
}
|
|
77
217
|
catch (error) {
|
|
@@ -80,9 +220,156 @@ export function validateXanoscript(args) {
|
|
|
80
220
|
valid: false,
|
|
81
221
|
errors: [],
|
|
82
222
|
message: `Validation error: ${errorMessage}`,
|
|
223
|
+
file_path: filePath,
|
|
83
224
|
};
|
|
84
225
|
}
|
|
85
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* Validate XanoScript code for syntax errors.
|
|
229
|
+
*
|
|
230
|
+
* Supports multiple input methods:
|
|
231
|
+
* - code: Raw XanoScript code as a string
|
|
232
|
+
* - file_path: Path to a single .xs file
|
|
233
|
+
* - file_paths: Array of file paths for batch validation
|
|
234
|
+
* - directory: Directory path with optional glob pattern
|
|
235
|
+
*
|
|
236
|
+
* @param args - The validation arguments
|
|
237
|
+
* @returns Validation result with errors if any
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```ts
|
|
241
|
+
* import { validateXanoscript } from '@xano/developer-mcp';
|
|
242
|
+
*
|
|
243
|
+
* // Validate code directly
|
|
244
|
+
* const result = validateXanoscript({ code: 'return 1 + 1' });
|
|
245
|
+
*
|
|
246
|
+
* // Validate a single file
|
|
247
|
+
* const fileResult = validateXanoscript({ file_path: './functions/utils.xs' });
|
|
248
|
+
*
|
|
249
|
+
* // Validate multiple files
|
|
250
|
+
* const batchResult = validateXanoscript({
|
|
251
|
+
* file_paths: ['./apis/users/get.xs', './apis/users/create.xs']
|
|
252
|
+
* });
|
|
253
|
+
*
|
|
254
|
+
* // Validate all .xs files in a directory
|
|
255
|
+
* const dirResult = validateXanoscript({ directory: './src' });
|
|
256
|
+
*
|
|
257
|
+
* // Validate with a specific pattern
|
|
258
|
+
* const patternResult = validateXanoscript({
|
|
259
|
+
* directory: './src',
|
|
260
|
+
* pattern: 'apis/**\/*.xs'
|
|
261
|
+
* });
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
export function validateXanoscript(args) {
|
|
265
|
+
// Validate that at least one input method is provided
|
|
266
|
+
if (!args?.code && !args?.file_path && !args?.file_paths && !args?.directory) {
|
|
267
|
+
return {
|
|
268
|
+
valid: false,
|
|
269
|
+
errors: [],
|
|
270
|
+
message: "Error: One of 'code', 'file_path', 'file_paths', or 'directory' parameter is required",
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// Handle direct code validation
|
|
274
|
+
if (args.code) {
|
|
275
|
+
const result = validateCode(args.code);
|
|
276
|
+
return {
|
|
277
|
+
valid: result.valid,
|
|
278
|
+
errors: result.errors,
|
|
279
|
+
message: result.message,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
// Handle single file validation
|
|
283
|
+
if (args.file_path) {
|
|
284
|
+
const { content, error } = readFile(args.file_path);
|
|
285
|
+
if (error) {
|
|
286
|
+
return {
|
|
287
|
+
valid: false,
|
|
288
|
+
errors: [],
|
|
289
|
+
message: error,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const result = validateCode(content, args.file_path);
|
|
293
|
+
return {
|
|
294
|
+
valid: result.valid,
|
|
295
|
+
errors: result.errors,
|
|
296
|
+
message: result.message,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
// Handle batch validation (file_paths or directory)
|
|
300
|
+
let filesToValidate = [];
|
|
301
|
+
if (args.file_paths) {
|
|
302
|
+
filesToValidate = args.file_paths;
|
|
303
|
+
}
|
|
304
|
+
else if (args.directory) {
|
|
305
|
+
filesToValidate = findXsFiles(args.directory, args.pattern || "**/*.xs");
|
|
306
|
+
if (filesToValidate.length === 0) {
|
|
307
|
+
return {
|
|
308
|
+
valid: true,
|
|
309
|
+
total_files: 0,
|
|
310
|
+
valid_files: 0,
|
|
311
|
+
invalid_files: 0,
|
|
312
|
+
results: [],
|
|
313
|
+
message: `No .xs files found in directory: ${args.directory}${args.pattern ? ` matching pattern: ${args.pattern}` : ""}`,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Validate all files
|
|
318
|
+
const results = [];
|
|
319
|
+
let validCount = 0;
|
|
320
|
+
let invalidCount = 0;
|
|
321
|
+
for (const filePath of filesToValidate) {
|
|
322
|
+
const { content, error } = readFile(filePath);
|
|
323
|
+
if (error) {
|
|
324
|
+
results.push({
|
|
325
|
+
valid: false,
|
|
326
|
+
errors: [],
|
|
327
|
+
message: error,
|
|
328
|
+
file_path: filePath,
|
|
329
|
+
});
|
|
330
|
+
invalidCount++;
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
const result = validateCode(content, filePath);
|
|
334
|
+
results.push(result);
|
|
335
|
+
if (result.valid) {
|
|
336
|
+
validCount++;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
invalidCount++;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// Build summary message
|
|
343
|
+
const allValid = invalidCount === 0;
|
|
344
|
+
const summaryLines = [
|
|
345
|
+
`Validated ${filesToValidate.length} file(s): ${validCount} valid, ${invalidCount} invalid`,
|
|
346
|
+
"",
|
|
347
|
+
];
|
|
348
|
+
// Show errors first, then valid files
|
|
349
|
+
const invalidResults = results.filter((r) => !r.valid);
|
|
350
|
+
const validResults = results.filter((r) => r.valid);
|
|
351
|
+
if (invalidResults.length > 0) {
|
|
352
|
+
summaryLines.push("❌ Files with errors:");
|
|
353
|
+
for (const result of invalidResults) {
|
|
354
|
+
summaryLines.push(`\n${result.message}`);
|
|
355
|
+
}
|
|
356
|
+
summaryLines.push("");
|
|
357
|
+
}
|
|
358
|
+
if (validResults.length > 0) {
|
|
359
|
+
summaryLines.push("✅ Valid files:");
|
|
360
|
+
for (const result of validResults) {
|
|
361
|
+
summaryLines.push(` ${result.file_path}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return {
|
|
365
|
+
valid: allValid,
|
|
366
|
+
total_files: filesToValidate.length,
|
|
367
|
+
valid_files: validCount,
|
|
368
|
+
invalid_files: invalidCount,
|
|
369
|
+
results,
|
|
370
|
+
message: summaryLines.join("\n"),
|
|
371
|
+
};
|
|
372
|
+
}
|
|
86
373
|
/**
|
|
87
374
|
* Validate XanoScript and return a simplified result.
|
|
88
375
|
* Returns ToolResult format for consistent error handling.
|
|
@@ -100,15 +387,42 @@ export function validateXanoscriptTool(args) {
|
|
|
100
387
|
// =============================================================================
|
|
101
388
|
export const validateXanoscriptToolDefinition = {
|
|
102
389
|
name: "validate_xanoscript",
|
|
103
|
-
description: "Validate XanoScript code for syntax errors.
|
|
390
|
+
description: "Validate XanoScript code for syntax errors. Supports multiple input methods:\n" +
|
|
391
|
+
"- code: Raw XanoScript code as a string\n" +
|
|
392
|
+
"- file_path: Path to a single .xs file (easier than escaping code!)\n" +
|
|
393
|
+
"- file_paths: Array of file paths for batch validation\n" +
|
|
394
|
+
"- directory: Validate all .xs files in a directory\n\n" +
|
|
395
|
+
"Returns errors with line/column positions and helpful suggestions for common mistakes. " +
|
|
396
|
+
"The language server auto-detects the object type from the code syntax.",
|
|
104
397
|
inputSchema: {
|
|
105
398
|
type: "object",
|
|
106
399
|
properties: {
|
|
107
400
|
code: {
|
|
108
401
|
type: "string",
|
|
109
|
-
description: "The XanoScript code to validate",
|
|
402
|
+
description: "The XanoScript code to validate as a string. Use file_path instead if the code contains special characters that are hard to escape.",
|
|
403
|
+
},
|
|
404
|
+
file_path: {
|
|
405
|
+
type: "string",
|
|
406
|
+
description: "Path to a single XanoScript file to validate. Easier than passing code directly - avoids escaping issues.",
|
|
407
|
+
},
|
|
408
|
+
file_paths: {
|
|
409
|
+
type: "array",
|
|
410
|
+
items: { type: "string" },
|
|
411
|
+
description: "Array of file paths for batch validation. Returns a summary with per-file results.",
|
|
412
|
+
},
|
|
413
|
+
directory: {
|
|
414
|
+
type: "string",
|
|
415
|
+
description: "Directory path to validate. Validates all .xs files recursively. Use with 'pattern' to filter.",
|
|
416
|
+
},
|
|
417
|
+
pattern: {
|
|
418
|
+
type: "string",
|
|
419
|
+
description: 'Glob pattern to filter files when using directory (default: "**/*.xs"). Example: "apis/**/*.xs"',
|
|
110
420
|
},
|
|
111
421
|
},
|
|
112
|
-
required: [
|
|
422
|
+
required: [],
|
|
113
423
|
},
|
|
114
424
|
};
|
|
425
|
+
// =============================================================================
|
|
426
|
+
// Utility Exports
|
|
427
|
+
// =============================================================================
|
|
428
|
+
export { TYPE_ALIASES, RESERVED_VARIABLES };
|
|
@@ -108,7 +108,20 @@ $db.table.field // Database field reference (in queries)
|
|
|
108
108
|
$this // Current item in loops/maps
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
**
|
|
111
|
+
**Reserved Variables:** The following cannot be used as variable names: `$response`, `$output`, `$input`, `$auth`, `$env`, `$db`, `$this`, `$result`.
|
|
112
|
+
|
|
113
|
+
### Type Names
|
|
114
|
+
|
|
115
|
+
XanoScript uses specific type names:
|
|
116
|
+
|
|
117
|
+
| Type | Description | Example |
|
|
118
|
+
|------|-------------|---------|
|
|
119
|
+
| `text` | String (not "string") | `text name` |
|
|
120
|
+
| `int` | Integer (not "integer") | `int count` |
|
|
121
|
+
| `bool` | Boolean (not "boolean") | `bool active` |
|
|
122
|
+
| `decimal` | Float/number | `decimal price` |
|
|
123
|
+
| `type[]` | Array (not "array" or "list") | `text[] tags` |
|
|
124
|
+
| `json` | Arbitrary JSON data | `json metadata` |
|
|
112
125
|
|
|
113
126
|
### Comments
|
|
114
127
|
|
|
@@ -612,3 +612,17 @@ try_catch {
|
|
|
612
612
|
5. **Use null-safe operators** - `==?` for optional filters
|
|
613
613
|
6. **Use bulk operations for batch processing** - More efficient than loops
|
|
614
614
|
7. **Handle deadlocks gracefully** - Implement retry logic for concurrent writes
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
## Related Topics
|
|
619
|
+
|
|
620
|
+
Explore more with `xanoscript_docs({ topic: "<topic>" })`:
|
|
621
|
+
|
|
622
|
+
| Topic | Description |
|
|
623
|
+
|-------|-------------|
|
|
624
|
+
| `tables` | Database schema definitions with indexes and relationships |
|
|
625
|
+
| `syntax` | Query filters, operators, and expressions |
|
|
626
|
+
| `quickstart` | Common CRUD patterns and examples |
|
|
627
|
+
| `addons` | Reusable subqueries for fetching related data |
|
|
628
|
+
| `performance` | Query optimization best practices |
|
|
@@ -465,3 +465,17 @@ foreach ($items) {
|
|
|
465
465
|
5. **Keep stacks shallow** - Avoid deeply nested conditionals
|
|
466
466
|
6. **Use group for organization** - Visually group related statements for readability
|
|
467
467
|
7. **Use remove sparingly** - Consider filtering arrays instead
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Related Topics
|
|
472
|
+
|
|
473
|
+
Explore more with `xanoscript_docs({ topic: "<topic>" })`:
|
|
474
|
+
|
|
475
|
+
| Topic | Description |
|
|
476
|
+
|-------|-------------|
|
|
477
|
+
| `types` | Input types, filters, and validation |
|
|
478
|
+
| `syntax` | Expressions, operators, and control flow |
|
|
479
|
+
| `quickstart` | Common patterns and examples |
|
|
480
|
+
| `database` | Database operations in function stacks |
|
|
481
|
+
| `testing` | Unit testing functions |
|
|
@@ -8,6 +8,62 @@ Essential patterns for XanoScript development. Use this as a quick reference for
|
|
|
8
8
|
|
|
9
9
|
## Quick Reference
|
|
10
10
|
|
|
11
|
+
### Reserved Variable Names
|
|
12
|
+
|
|
13
|
+
These variable names are reserved and cannot be used:
|
|
14
|
+
|
|
15
|
+
| Variable | Description |
|
|
16
|
+
|----------|-------------|
|
|
17
|
+
| `$response` | API/function response (auto-populated) |
|
|
18
|
+
| `$output` | Output value |
|
|
19
|
+
| `$input` | Input parameters from request/function call |
|
|
20
|
+
| `$auth` | Authenticated user context |
|
|
21
|
+
| `$env` | Environment variables and request context |
|
|
22
|
+
| `$db` | Database table reference for queries |
|
|
23
|
+
| `$this` | Current context reference |
|
|
24
|
+
| `$result` | Used in reduce operations |
|
|
25
|
+
|
|
26
|
+
```xs
|
|
27
|
+
// ❌ Wrong - using reserved variable name
|
|
28
|
+
var $response { value = "test" } // Error: $response is reserved
|
|
29
|
+
|
|
30
|
+
// ✅ Correct - use a different name
|
|
31
|
+
var $api_response { value = "test" }
|
|
32
|
+
var $my_result { value = "test" }
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Type Names (Common Aliases)
|
|
36
|
+
|
|
37
|
+
XanoScript uses specific type names. Common aliases from other languages won't work.
|
|
38
|
+
|
|
39
|
+
> **Full reference:** For complete type details and validation, see `xanoscript_docs({ topic: "types" })`.
|
|
40
|
+
|
|
41
|
+
| ❌ Wrong | ✅ Correct | Description |
|
|
42
|
+
|----------|------------|-------------|
|
|
43
|
+
| `boolean` | `bool` | Boolean true/false |
|
|
44
|
+
| `integer` | `int` | 32-bit integer |
|
|
45
|
+
| `string` | `text` | UTF-8 string |
|
|
46
|
+
| `number` | `decimal` | Floating-point number |
|
|
47
|
+
| `float` | `decimal` | Floating-point number |
|
|
48
|
+
| `array` | `type[]` | Array (e.g., `text[]`, `int[]`) |
|
|
49
|
+
| `list` | `type[]` | Array (e.g., `text[]`, `int[]`) |
|
|
50
|
+
|
|
51
|
+
```xs
|
|
52
|
+
// ❌ Wrong - invalid type names
|
|
53
|
+
input {
|
|
54
|
+
boolean is_active // Error: use "bool"
|
|
55
|
+
integer count // Error: use "int"
|
|
56
|
+
string name // Error: use "text"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ✅ Correct - proper XanoScript types
|
|
60
|
+
input {
|
|
61
|
+
bool is_active
|
|
62
|
+
int count
|
|
63
|
+
text name
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
11
67
|
### Variable Declaration
|
|
12
68
|
```xs
|
|
13
69
|
var $name { value = "initial value" }
|
|
@@ -35,7 +91,7 @@ conditional {
|
|
|
35
91
|
api.request {
|
|
36
92
|
url = "https://api.example.com/data"
|
|
37
93
|
method = "POST"
|
|
38
|
-
params = $payload
|
|
94
|
+
params = $payload // Note: "params" is used for request body, NOT "body"
|
|
39
95
|
headers = ["Content-Type: application/json", "Authorization: Bearer " ~ $env.API_KEY]
|
|
40
96
|
} as $api_result
|
|
41
97
|
|
|
@@ -47,6 +103,27 @@ precondition ($api_result.response.status == 200) {
|
|
|
47
103
|
var $data { value = $api_result.response.result }
|
|
48
104
|
```
|
|
49
105
|
|
|
106
|
+
### api.request Response Structure
|
|
107
|
+
The response object contains:
|
|
108
|
+
```xs
|
|
109
|
+
$result.response.status // HTTP status code (200, 404, 500, etc.)
|
|
110
|
+
$result.response.result // Parsed response body (JSON decoded)
|
|
111
|
+
$result.response.headers // Response headers object
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### While Loop
|
|
115
|
+
```xs
|
|
116
|
+
stack {
|
|
117
|
+
var $counter { value = 0 }
|
|
118
|
+
while ($counter < 10) {
|
|
119
|
+
each {
|
|
120
|
+
var.update $counter { value = $counter + 1 }
|
|
121
|
+
debug.log { value = "Iteration: " ~ ($counter|to_text) }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
50
127
|
### String Concatenation
|
|
51
128
|
```xs
|
|
52
129
|
var $greeting { value = "Hello, " ~ $input.name ~ "!" }
|
|
@@ -55,6 +132,116 @@ var $greeting { value = "Hello, " ~ $input.name ~ "!" }
|
|
|
55
132
|
var $message { value = "Status: " ~ ($status|to_text) ~ " - " ~ ($data|json_encode) }
|
|
56
133
|
```
|
|
57
134
|
|
|
135
|
+
### Input Block Syntax
|
|
136
|
+
|
|
137
|
+
> **Full reference:** For complete input types and validation options, see `xanoscript_docs({ topic: "types" })`.
|
|
138
|
+
|
|
139
|
+
```xs
|
|
140
|
+
input {
|
|
141
|
+
// Required input
|
|
142
|
+
text name
|
|
143
|
+
|
|
144
|
+
// Optional input (can be omitted)
|
|
145
|
+
text nickname?
|
|
146
|
+
|
|
147
|
+
// Optional with default value
|
|
148
|
+
text role?="user"
|
|
149
|
+
|
|
150
|
+
// With filters applied
|
|
151
|
+
email contact filters=trim|lower
|
|
152
|
+
|
|
153
|
+
// Optional with default AND filters
|
|
154
|
+
text search?="" filters=trim
|
|
155
|
+
|
|
156
|
+
// Array type
|
|
157
|
+
text[] tags filters=trim
|
|
158
|
+
|
|
159
|
+
// Nested object with schema
|
|
160
|
+
object address {
|
|
161
|
+
schema {
|
|
162
|
+
text street
|
|
163
|
+
text city
|
|
164
|
+
text country?="US"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Error Types Reference
|
|
171
|
+
|
|
172
|
+
> **Full reference:** For try-catch, throw, and preconditions, see `xanoscript_docs({ topic: "syntax" })`.
|
|
173
|
+
|
|
174
|
+
| Type | HTTP Status | Use Case |
|
|
175
|
+
|------|-------------|----------|
|
|
176
|
+
| `inputerror` | 400 Bad Request | Invalid input data |
|
|
177
|
+
| `accessdenied` | 403 Forbidden | Authorization failure |
|
|
178
|
+
| `notfound` | 404 Not Found | Resource doesn't exist |
|
|
179
|
+
| `standard` | 500 Internal Server Error | General errors |
|
|
180
|
+
|
|
181
|
+
### Quick Filter Reference
|
|
182
|
+
|
|
183
|
+
> **Full reference:** For the complete list of filters with examples, see `xanoscript_docs({ topic: "syntax" })`.
|
|
184
|
+
|
|
185
|
+
**String Filters:**
|
|
186
|
+
```xs
|
|
187
|
+
$s|trim // Remove whitespace
|
|
188
|
+
$s|to_lower // Lowercase
|
|
189
|
+
$s|to_upper // Uppercase
|
|
190
|
+
$s|substr:1:3 // Substring from index 1, length 3
|
|
191
|
+
$s|split:"," // Split by delimiter → array
|
|
192
|
+
$s|replace:"old":"new" // Replace text
|
|
193
|
+
$s|contains:"text" // Check if contains → bool
|
|
194
|
+
$s|strlen // String length
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Array Filters:**
|
|
198
|
+
```xs
|
|
199
|
+
$arr|first // First element
|
|
200
|
+
$arr|last // Last element
|
|
201
|
+
$arr|count // Array length
|
|
202
|
+
$arr|push:$item // Add to end
|
|
203
|
+
$arr|pop // Remove & return last
|
|
204
|
+
$arr|join:"," // Join to string
|
|
205
|
+
$arr|map:$$.name // Transform elements
|
|
206
|
+
$arr|filter:$$.active // Filter elements
|
|
207
|
+
$arr|find:$$.id == 5 // Find first match
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**Object Filters:**
|
|
211
|
+
```xs
|
|
212
|
+
$obj|get:"key" // Get property value
|
|
213
|
+
$obj|get:"key":"default" // With default if missing
|
|
214
|
+
$obj|set:"key":"value" // Set property
|
|
215
|
+
$obj|has:"key" // Check if key exists → bool
|
|
216
|
+
$obj|keys // Get all keys → array
|
|
217
|
+
$obj|values // Get all values → array
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Type Conversion:**
|
|
221
|
+
```xs
|
|
222
|
+
$val|to_text // Convert to string
|
|
223
|
+
$val|to_int // Convert to integer
|
|
224
|
+
$val|to_decimal // Convert to decimal
|
|
225
|
+
$val|to_bool // Convert to boolean
|
|
226
|
+
$val|json_encode // Object → JSON string
|
|
227
|
+
$str|json_decode // JSON string → object
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
**Null Handling:**
|
|
231
|
+
```xs
|
|
232
|
+
$val|first_notnull:"default" // Default if null
|
|
233
|
+
$val|first_notempty:"default" // Default if empty
|
|
234
|
+
$val ?? "default" // Nullish coalescing (same as first_notnull)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Encoding:**
|
|
238
|
+
```xs
|
|
239
|
+
$s|url_encode // URL encode
|
|
240
|
+
$s|url_decode // URL decode
|
|
241
|
+
$s|base64_encode // Base64 encode
|
|
242
|
+
$s|base64_decode // Base64 decode
|
|
243
|
+
```
|
|
244
|
+
|
|
58
245
|
---
|
|
59
246
|
|
|
60
247
|
## Common Patterns
|
|
@@ -77,6 +264,8 @@ precondition ($input.email|contains:"@") {
|
|
|
77
264
|
|
|
78
265
|
### 2. Database CRUD
|
|
79
266
|
|
|
267
|
+
> **Full reference:** For all db.* operations including transactions, see `xanoscript_docs({ topic: "database" })`.
|
|
268
|
+
|
|
80
269
|
```xs
|
|
81
270
|
// Create
|
|
82
271
|
db.add "user" {
|
|
@@ -142,6 +331,8 @@ var $active_items { value = $items|filter:$$.is_active == true }
|
|
|
142
331
|
|
|
143
332
|
### 5. Error Handling with Try-Catch
|
|
144
333
|
|
|
334
|
+
> **Full reference:** For all error handling patterns, see `xanoscript_docs({ topic: "syntax" })`.
|
|
335
|
+
|
|
145
336
|
```xs
|
|
146
337
|
try_catch {
|
|
147
338
|
try {
|
|
@@ -159,6 +350,8 @@ try_catch {
|
|
|
159
350
|
|
|
160
351
|
### 6. Authentication Check
|
|
161
352
|
|
|
353
|
+
> **Full reference:** For security best practices, see `xanoscript_docs({ topic: "security" })`.
|
|
354
|
+
|
|
162
355
|
```xs
|
|
163
356
|
// Require authenticated user
|
|
164
357
|
precondition ($auth.id != null) {
|
|
@@ -220,6 +413,8 @@ var $response {
|
|
|
220
413
|
|
|
221
414
|
### 9. Date/Time Operations
|
|
222
415
|
|
|
416
|
+
> **Full reference:** For all date/time filters, see `xanoscript_docs({ topic: "syntax" })`.
|
|
417
|
+
|
|
223
418
|
```xs
|
|
224
419
|
// Current timestamp
|
|
225
420
|
var $now { value = now }
|
|
@@ -239,6 +434,8 @@ db.query "event" {
|
|
|
239
434
|
|
|
240
435
|
### 10. JSON API Response
|
|
241
436
|
|
|
437
|
+
> **Full reference:** For external API patterns, see `xanoscript_docs({ topic: "integrations" })`.
|
|
438
|
+
|
|
242
439
|
```xs
|
|
243
440
|
api.request {
|
|
244
441
|
url = "https://api.openai.com/v1/chat/completions"
|
|
@@ -287,42 +484,104 @@ conditional {
|
|
|
287
484
|
|
|
288
485
|
### 2. Missing parentheses in filter concatenation
|
|
289
486
|
```xs
|
|
290
|
-
// ❌ Wrong
|
|
487
|
+
// ❌ Wrong - parse error
|
|
291
488
|
var $msg { value = $status|to_text ~ " - " ~ $data|json_encode }
|
|
292
489
|
|
|
293
|
-
// ✅ Correct
|
|
490
|
+
// ✅ Correct - wrap filtered expressions in parentheses
|
|
294
491
|
var $msg { value = ($status|to_text) ~ " - " ~ ($data|json_encode) }
|
|
295
492
|
```
|
|
296
493
|
|
|
297
|
-
### 3.
|
|
494
|
+
### 3. Missing parentheses in filter comparisons
|
|
298
495
|
```xs
|
|
299
|
-
// ❌ Wrong
|
|
496
|
+
// ❌ Wrong - parse error
|
|
497
|
+
if ($array|count > 0) { }
|
|
498
|
+
|
|
499
|
+
// ✅ Correct - wrap filter expression in parentheses
|
|
500
|
+
if (($array|count) > 0) { }
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### 4. Using `body` instead of `params` for api.request
|
|
504
|
+
```xs
|
|
505
|
+
// ❌ Wrong - "body" is not valid
|
|
300
506
|
api.request {
|
|
301
507
|
url = "..."
|
|
302
508
|
method = "POST"
|
|
303
|
-
body = $payload
|
|
509
|
+
body = $payload
|
|
304
510
|
}
|
|
305
511
|
|
|
306
|
-
// ✅ Correct
|
|
512
|
+
// ✅ Correct - use "params" for request body
|
|
307
513
|
api.request {
|
|
308
514
|
url = "..."
|
|
309
515
|
method = "POST"
|
|
310
|
-
params = $payload
|
|
516
|
+
params = $payload
|
|
311
517
|
}
|
|
312
518
|
```
|
|
313
519
|
|
|
314
|
-
###
|
|
520
|
+
### 5. Using `default` filter (doesn't exist)
|
|
315
521
|
```xs
|
|
316
|
-
// ❌ Wrong
|
|
522
|
+
// ❌ Wrong - no "default" filter exists
|
|
317
523
|
var $value { value = $input.optional|default:"fallback" }
|
|
318
524
|
|
|
319
|
-
// ✅ Correct
|
|
525
|
+
// ✅ Correct - use first_notnull or ?? operator
|
|
320
526
|
var $value { value = $input.optional|first_notnull:"fallback" }
|
|
321
527
|
// or
|
|
322
528
|
var $value { value = $input.optional ?? "fallback" }
|
|
529
|
+
|
|
530
|
+
// For object key access with default, use get with 3rd parameter
|
|
531
|
+
var $val { value = $obj|get:"key":"default_value" }
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### 6. Using reserved variable names
|
|
535
|
+
```xs
|
|
536
|
+
// ❌ Wrong - $response is reserved
|
|
537
|
+
var $response { value = "test" }
|
|
538
|
+
|
|
539
|
+
// ✅ Correct - use a different name
|
|
540
|
+
var $api_response { value = "test" }
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### 7. Wrong type names
|
|
544
|
+
```xs
|
|
545
|
+
// ❌ Wrong - invalid type names
|
|
546
|
+
input {
|
|
547
|
+
boolean active // Use "bool"
|
|
548
|
+
integer count // Use "int"
|
|
549
|
+
string name // Use "text"
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// ✅ Correct
|
|
553
|
+
input {
|
|
554
|
+
bool active
|
|
555
|
+
int count
|
|
556
|
+
text name
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### 8. Object literal syntax (using = instead of :)
|
|
561
|
+
```xs
|
|
562
|
+
// ❌ Wrong - object literals use : not =
|
|
563
|
+
var $data { value = { customer = $id } }
|
|
564
|
+
|
|
565
|
+
// ✅ Correct - use : for object properties
|
|
566
|
+
var $data { value = { customer: $id } }
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
### 9. Throw block with commas
|
|
570
|
+
```xs
|
|
571
|
+
// ❌ Wrong - throw blocks don't use commas
|
|
572
|
+
throw {
|
|
573
|
+
name = "Error",
|
|
574
|
+
value = "message"
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// ✅ Correct - no commas between properties
|
|
578
|
+
throw {
|
|
579
|
+
name = "Error"
|
|
580
|
+
value = "message"
|
|
581
|
+
}
|
|
323
582
|
```
|
|
324
583
|
|
|
325
|
-
###
|
|
584
|
+
### 10. Using $env in run.job input blocks
|
|
326
585
|
```xs
|
|
327
586
|
// ❌ Wrong - $env not allowed in input blocks
|
|
328
587
|
run.job "my_job" {
|
|
@@ -331,10 +590,64 @@ run.job "my_job" {
|
|
|
331
590
|
}
|
|
332
591
|
}
|
|
333
592
|
|
|
334
|
-
// ✅ Correct -
|
|
593
|
+
// ✅ Correct - access $env in the stack instead
|
|
335
594
|
run.job "my_job" {
|
|
336
595
|
stack {
|
|
337
596
|
var $api_key { value = $env.API_KEY }
|
|
338
597
|
}
|
|
339
598
|
}
|
|
340
599
|
```
|
|
600
|
+
|
|
601
|
+
### 11. Using `object` type without schema
|
|
602
|
+
```xs
|
|
603
|
+
// ❌ Wrong - object requires a schema
|
|
604
|
+
input {
|
|
605
|
+
object data // Error: needs schema
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// ✅ Correct - use json for arbitrary data
|
|
609
|
+
input {
|
|
610
|
+
json data // Accepts any JSON
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// ✅ Or define a schema for object
|
|
614
|
+
input {
|
|
615
|
+
object data {
|
|
616
|
+
schema {
|
|
617
|
+
text name
|
|
618
|
+
int id
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### 12. While loop outside of stack block
|
|
625
|
+
```xs
|
|
626
|
+
// ❌ Wrong - while must be inside stack
|
|
627
|
+
while (true) {
|
|
628
|
+
each { ... }
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// ✅ Correct - wrap in stack block
|
|
632
|
+
stack {
|
|
633
|
+
while (true) {
|
|
634
|
+
each { ... }
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
---
|
|
640
|
+
|
|
641
|
+
## Related Topics
|
|
642
|
+
|
|
643
|
+
Explore more with `xanoscript_docs({ topic: "<topic>" })`:
|
|
644
|
+
|
|
645
|
+
| Topic | Description |
|
|
646
|
+
|-------|-------------|
|
|
647
|
+
| `syntax` | Complete filter reference, operators, system variables |
|
|
648
|
+
| `types` | Data types, input validation, schema definitions |
|
|
649
|
+
| `database` | All db.* operations: query, get, add, edit, delete |
|
|
650
|
+
| `functions` | Reusable function stacks, async patterns, loops |
|
|
651
|
+
| `apis` | HTTP endpoints, authentication, CRUD patterns |
|
|
652
|
+
| `security` | Security best practices and authentication |
|
|
653
|
+
| `integrations` | External API patterns (OpenAI, Stripe, etc.) |
|
|
@@ -280,6 +280,8 @@ Generate numeric ranges with the `..` operator:
|
|
|
280
280
|
|
|
281
281
|
## Type Filters
|
|
282
282
|
|
|
283
|
+
> **Full reference:** For input types and validation, see `xanoscript_docs({ topic: "types" })`.
|
|
284
|
+
|
|
283
285
|
| Filter | Example | Result |
|
|
284
286
|
|--------|---------|--------|
|
|
285
287
|
| `to_int` | `"123"\|to_int` | `123` |
|
|
@@ -343,6 +345,8 @@ $ts|timestamp_day_of_week // Day (0=Sunday)
|
|
|
343
345
|
|
|
344
346
|
## Security Filters
|
|
345
347
|
|
|
348
|
+
> **Full reference:** For security best practices, see `xanoscript_docs({ topic: "security" })`.
|
|
349
|
+
|
|
346
350
|
| Filter | Example |
|
|
347
351
|
|--------|---------|
|
|
348
352
|
| `md5` | `"text"\|md5` |
|
|
@@ -359,6 +363,8 @@ $ts|timestamp_day_of_week // Day (0=Sunday)
|
|
|
359
363
|
|
|
360
364
|
## DB Query Filters
|
|
361
365
|
|
|
366
|
+
> **Full reference:** For complete database operations, see `xanoscript_docs({ topic: "database" })`.
|
|
367
|
+
|
|
362
368
|
Used in `db.query` where clauses:
|
|
363
369
|
|
|
364
370
|
| Filter | Example | Description |
|
|
@@ -731,6 +737,8 @@ $db.created_at|timestamp_epoch_ms // Milliseconds since epoch
|
|
|
731
737
|
|
|
732
738
|
### Vector Operations (AI/ML)
|
|
733
739
|
|
|
740
|
+
> **Full reference:** For AI agents and embeddings, see `xanoscript_docs({ topic: "agents" })`.
|
|
741
|
+
|
|
734
742
|
Additional vector similarity functions:
|
|
735
743
|
|
|
736
744
|
```xs
|
|
@@ -741,3 +749,17 @@ $db.embedding|inner_product:$input.vector // Inner product
|
|
|
741
749
|
// Geo covers (for polygon containment)
|
|
742
750
|
$db.boundary|covers:$input.point // Polygon covers point
|
|
743
751
|
```
|
|
752
|
+
|
|
753
|
+
---
|
|
754
|
+
|
|
755
|
+
## Related Topics
|
|
756
|
+
|
|
757
|
+
Explore more with `xanoscript_docs({ topic: "<topic>" })`:
|
|
758
|
+
|
|
759
|
+
| Topic | Description |
|
|
760
|
+
|-------|-------------|
|
|
761
|
+
| `quickstart` | Common patterns, examples, mistakes to avoid |
|
|
762
|
+
| `types` | Data types, input validation, schema definitions |
|
|
763
|
+
| `database` | All db.* operations with query examples |
|
|
764
|
+
| `functions` | Reusable function stacks, async patterns |
|
|
765
|
+
| `security` | Security best practices and authentication |
|
|
@@ -362,3 +362,17 @@ precondition ($input.start_date < $input.end_date) {
|
|
|
362
362
|
2. **Use filters first** - Prefer declarative filters over stack validation
|
|
363
363
|
3. **Mark sensitive data** - Use `sensitive = true` for PII/credentials
|
|
364
364
|
4. **Validate at boundaries** - Validate user input, trust internal calls
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Related Topics
|
|
369
|
+
|
|
370
|
+
Explore more with `xanoscript_docs({ topic: "<topic>" })`:
|
|
371
|
+
|
|
372
|
+
| Topic | Description |
|
|
373
|
+
|-------|-------------|
|
|
374
|
+
| `schema` | Runtime schema parsing and validation |
|
|
375
|
+
| `syntax` | All filters, operators, and error handling |
|
|
376
|
+
| `quickstart` | Common patterns and mistakes to avoid |
|
|
377
|
+
| `functions` | Using input blocks in functions |
|
|
378
|
+
| `apis` | Using input blocks in API endpoints |
|
package/package.json
CHANGED