@xano/xanoscript-language-server 11.11.0 → 11.12.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/xanoscript-language-server",
3
- "version": "11.11.0",
3
+ "version": "11.12.0",
4
4
  "description": "Language Server Protocol implementation for XanoScript",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -26,10 +26,11 @@ export function addonDeclaration($) {
26
26
  // Allow leading comments and newlines before the addon declaration
27
27
  $.SUBRULE($.optionalCommentBlockFn);
28
28
  const parent = $.CONSUME(AddonToken);
29
- $.OR([
29
+ const nameToken = $.OR([
30
30
  { ALT: () => $.CONSUME(StringLiteral) },
31
31
  { ALT: () => $.CONSUME(Identifier) },
32
32
  ]);
33
+ $.validateDeclarationName(nameToken, "addon");
33
34
  $.CONSUME(LCurly); // "{"
34
35
  $.MANY(() => {
35
36
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -21,10 +21,11 @@ export function agentDeclaration($) {
21
21
  // Allow leading comments and newlines before the agent declaration
22
22
  $.SUBRULE($.optionalCommentBlockFn);
23
23
  const parent = $.CONSUME(AgentToken); // agent
24
- $.OR([
24
+ const nameToken = $.OR([
25
25
  { ALT: () => $.CONSUME(StringLiteral) },
26
26
  { ALT: () => $.CONSUME(Identifier) },
27
27
  ]);
28
+ $.validateDeclarationName(nameToken, "agent");
28
29
  $.CONSUME(LCurly); // "{"
29
30
  $.MANY(() => {
30
31
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -26,10 +26,11 @@ export function agentTriggerDeclaration($) {
26
26
  // Allow leading comments and newlines before the agent_trigger declaration
27
27
  $.SUBRULE($.optionalCommentBlockFn);
28
28
  const parent = $.CONSUME(AgentTriggerToken); // agent_trigger
29
- $.OR([
29
+ const nameToken = $.OR([
30
30
  { ALT: () => $.CONSUME(StringLiteral) },
31
31
  { ALT: () => $.CONSUME(Identifier) },
32
32
  ]);
33
+ $.validateDeclarationName(nameToken, "agent_trigger");
33
34
  $.CONSUME(LCurly); // "{"
34
35
  $.MANY(() => {
35
36
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -27,10 +27,11 @@ export function apiGroupDeclaration($) {
27
27
  // Allow leading comments and newlines before the api_group declaration
28
28
  $.SUBRULE($.optionalCommentBlockFn);
29
29
  $.CONSUME(ApiGroupToken); // api_group
30
- $.OR([
30
+ const nameToken = $.OR([
31
31
  { ALT: () => $.CONSUME(StringLiteral) },
32
32
  { ALT: () => $.CONSUME(Identifier) },
33
33
  ]);
34
+ $.validateDeclarationName(nameToken, "api_group");
34
35
  $.CONSUME(LCurly); // "{"
35
36
  $.MANY(() => {
36
37
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken));
@@ -270,6 +270,17 @@ export class XanoBaseParser extends CstParser {
270
270
  this.SAVE_ERROR(new MismatchedTokenException(message, token));
271
271
  }
272
272
 
273
+ /**
274
+ * Validate that a declaration name token is not an empty string
275
+ * @param {import('chevrotain').IToken} nameToken
276
+ * @param {string} typeName the declaration type (e.g. "query", "function")
277
+ */
278
+ validateDeclarationName(nameToken, typeName) {
279
+ if (nameToken?.image === '""') {
280
+ this.addInvalidValueError(nameToken, `${typeName} name must not be empty`);
281
+ }
282
+ }
283
+
273
284
  /**
274
285
  * Setup all the required rules for the parser but without creating duplicates
275
286
  *
@@ -9,10 +9,11 @@ export function branchDeclaration($) {
9
9
  $.SUBRULE($.optionalCommentBlockFn);
10
10
 
11
11
  const parent = $.CONSUME(BranchToken); // branch
12
- $.OR([
12
+ const nameToken = $.OR([
13
13
  { ALT: () => $.CONSUME(StringLiteral) },
14
14
  { ALT: () => $.CONSUME(Identifier) },
15
15
  ]);
16
+ $.validateDeclarationName(nameToken, "branch");
16
17
 
17
18
  const middlewareSchema = {
18
19
  pre: [{ name: "[string]" }],
@@ -29,6 +29,7 @@ export function functionDeclaration($) {
29
29
  { ALT: () => $.CONSUME(StringLiteral) },
30
30
  ]);
31
31
 
32
+ $.validateDeclarationName(nameToken, "function");
32
33
  if (nameToken?.image && getVarName(nameToken).startsWith("/")) {
33
34
  $.addInvalidValueError(
34
35
  nameToken,
@@ -16,6 +16,20 @@ describe("function_parser", () => {
16
16
  expect(parser.errors).to.be.empty;
17
17
  });
18
18
 
19
+ it("should raise an error when a function name is empty", () => {
20
+ const parser = xanoscriptParser(`function "" {
21
+ input {
22
+ }
23
+
24
+ stack {
25
+ }
26
+
27
+ response = null
28
+ }`);
29
+ expect(parser.errors).to.not.be.empty;
30
+ expect(parser.errors[0].message).to.include("must not be empty");
31
+ });
32
+
19
33
  it("should raise an error when a function name starts with /", () => {
20
34
  const parser = xanoscriptParser(`function "/foo" {
21
35
  input {
@@ -24,10 +24,11 @@ export function mcpServerDeclaration($) {
24
24
  // Allow leading comments and newlines before the mcp_server declaration
25
25
  $.SUBRULE($.optionalCommentBlockFn);
26
26
  const parent = $.CONSUME(McpServerToken); // mcp_server
27
- $.OR([
27
+ const nameToken = $.OR([
28
28
  { ALT: () => $.CONSUME(StringLiteral) },
29
29
  { ALT: () => $.CONSUME(Identifier) },
30
30
  ]);
31
+ $.validateDeclarationName(nameToken, "mcp_server");
31
32
  $.CONSUME(LCurly); // "{"
32
33
  $.MANY(() => {
33
34
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -25,10 +25,11 @@ export function mcpServerTriggerDeclaration($) {
25
25
  $.SUBRULE($.optionalCommentBlockFn);
26
26
 
27
27
  const parent = $.CONSUME(McpServerTriggerToken); // mcp_server_trigger
28
- $.OR([
28
+ const nameToken = $.OR([
29
29
  { ALT: () => $.CONSUME(StringLiteral) },
30
30
  { ALT: () => $.CONSUME(Identifier) },
31
31
  ]);
32
+ $.validateDeclarationName(nameToken, "mcp_server_trigger");
32
33
  $.CONSUME(LCurly); // "{"
33
34
  $.MANY(() => {
34
35
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -28,10 +28,11 @@ export function middlewareDeclaration($) {
28
28
  $.SUBRULE($.optionalCommentBlockFn);
29
29
 
30
30
  const parent = $.CONSUME(MiddlewareToken);
31
- $.OR([
31
+ const nameToken = $.OR([
32
32
  { ALT: () => $.CONSUME(Identifier) },
33
33
  { ALT: () => $.CONSUME(StringLiteral) },
34
34
  ]);
35
+ $.validateDeclarationName(nameToken, "middleware");
35
36
  $.CONSUME(LCurly); // "{"
36
37
  $.MANY(() => {
37
38
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -43,6 +43,7 @@ export function queryDeclaration($) {
43
43
  { ALT: () => $.CONSUME(Identifier) }, // foo
44
44
  ]);
45
45
 
46
+ $.validateDeclarationName(nameToken, "query");
46
47
  if (nameToken?.image && getVarName(nameToken).startsWith("/")) {
47
48
  $.addInvalidValueError(nameToken, "query name must not start with '/'");
48
49
  }
@@ -16,6 +16,20 @@ describe("query_parser", () => {
16
16
  expect(parser.errors).to.be.empty;
17
17
  });
18
18
 
19
+ it("should raise an error when a query name is empty", () => {
20
+ const parser = xanoscriptParser(`query "" verb=GET {
21
+ input {
22
+ }
23
+
24
+ stack {
25
+ }
26
+
27
+ response = null
28
+ }`);
29
+ expect(parser.errors).to.not.be.empty;
30
+ expect(parser.errors[0].message).to.include("must not be empty");
31
+ });
32
+
19
33
  it("should raise an error when a query starts with /", () => {
20
34
  const parser = xanoscriptParser(`query "/foo" verb=GET {
21
35
  input {
@@ -9,10 +9,11 @@ export function realtimeChannelDeclaration($) {
9
9
  $.SUBRULE($.optionalCommentBlockFn);
10
10
 
11
11
  const parent = $.CONSUME(RealtimeChannelToken); // realtime_channel
12
- $.OR([
12
+ const nameToken = $.OR([
13
13
  { ALT: () => $.CONSUME(StringLiteral) },
14
14
  { ALT: () => $.CONSUME(Identifier) },
15
15
  ]);
16
+ $.validateDeclarationName(nameToken, "realtime_channel");
16
17
 
17
18
  $.SUBRULE($.schemaParseAttributeFn, {
18
19
  ARGS: [
@@ -25,10 +25,11 @@ export function realtimeTriggerDeclaration($) {
25
25
  $.SUBRULE($.optionalCommentBlockFn);
26
26
 
27
27
  const parent = $.CONSUME(RealtimeTriggerToken); // realtime_trigger
28
- $.OR([
28
+ const nameToken = $.OR([
29
29
  { ALT: () => $.CONSUME(StringLiteral) },
30
30
  { ALT: () => $.CONSUME(Identifier) },
31
31
  ]);
32
+ $.validateDeclarationName(nameToken, "realtime_trigger");
32
33
  $.CONSUME(LCurly); // "{"
33
34
  $.MANY(() => {
34
35
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -25,10 +25,11 @@ export function runJobClause($) {
25
25
  return () => {
26
26
  const parent = $.CONSUME(JobToken); // "job"
27
27
 
28
- $.OR([
28
+ const nameToken = $.OR([
29
29
  { ALT: () => $.CONSUME(StringLiteral) },
30
30
  { ALT: () => $.CONSUME(Identifier) },
31
31
  ]);
32
+ $.validateDeclarationName(nameToken, "job");
32
33
 
33
34
  $.SUBRULE($.schemaParseAttributeFn, {
34
35
  ARGS: [
@@ -49,10 +50,11 @@ export function runServiceClause($) {
49
50
  return () => {
50
51
  const parent = $.CONSUME(ServiceToken); // "service"
51
52
 
52
- $.OR([
53
+ const nameToken = $.OR([
53
54
  { ALT: () => $.CONSUME(StringLiteral) },
54
55
  { ALT: () => $.CONSUME(Identifier) },
55
56
  ]);
57
+ $.validateDeclarationName(nameToken, "service");
56
58
 
57
59
  $.SUBRULE($.schemaParseAttributeFn, {
58
60
  ARGS: [
@@ -25,7 +25,7 @@ export function tableDeclaration($) {
25
25
  $.SUBRULE($.optionalCommentBlockFn);
26
26
 
27
27
  $.CONSUME(TableToken); // "table"
28
- $.OR1([
28
+ const nameToken = $.OR1([
29
29
  {
30
30
  ALT: () =>
31
31
  $.CONSUME(StringLiteral, {
@@ -39,6 +39,7 @@ export function tableDeclaration($) {
39
39
  }),
40
40
  },
41
41
  ]);
42
+ $.validateDeclarationName(nameToken, "table");
42
43
 
43
44
  let hasSchema = false;
44
45
  let hasView = false;
@@ -30,10 +30,11 @@ export function tableTriggerDeclaration($) {
30
30
  $.SUBRULE($.optionalCommentBlockFn);
31
31
 
32
32
  const parent = $.CONSUME(TableTriggerToken); // table_trigger
33
- $.OR([
33
+ const nameToken = $.OR([
34
34
  { ALT: () => $.CONSUME(StringLiteral) },
35
35
  { ALT: () => $.CONSUME(Identifier) },
36
36
  ]);
37
+ $.validateDeclarationName(nameToken, "table_trigger");
37
38
  $.CONSUME(LCurly); // "{"
38
39
  $.MANY(() => {
39
40
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -25,10 +25,11 @@ export function taskDeclaration($) {
25
25
  $.SUBRULE($.optionalCommentBlockFn);
26
26
 
27
27
  $.CONSUME(TaskToken);
28
- $.OR([
28
+ const nameToken = $.OR([
29
29
  { ALT: () => $.CONSUME(StringLiteral) },
30
30
  { ALT: () => $.CONSUME(Identifier) },
31
31
  ]);
32
+ $.validateDeclarationName(nameToken, "task");
32
33
  $.CONSUME(LCurly); // "{"
33
34
  $.MANY(() => {
34
35
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -13,6 +13,17 @@ describe("task_parser", () => {
13
13
  expect(parser.errors).to.be.empty;
14
14
  });
15
15
 
16
+ it("should raise an error when a task name is empty", () => {
17
+ const parser = xanoscriptParser(`task "" {
18
+ stack {
19
+ }
20
+
21
+ schedule = []
22
+ }`);
23
+ expect(parser.errors).to.not.be.empty;
24
+ expect(parser.errors[0].message).to.include("must not be empty");
25
+ });
26
+
16
27
  it("should parse an active task", () => {
17
28
  const parser = xanoscriptParser(`task task_for_listing {
18
29
  active = true
@@ -21,10 +21,11 @@ export function toolDeclaration($) {
21
21
  $.SUBRULE($.optionalCommentBlockFn);
22
22
 
23
23
  const parent = $.CONSUME(ToolToken);
24
- $.OR([
24
+ const nameToken = $.OR([
25
25
  { ALT: () => $.CONSUME(StringLiteral) },
26
26
  { ALT: () => $.CONSUME(Identifier) },
27
27
  ]);
28
+ $.validateDeclarationName(nameToken, "tool");
28
29
  $.CONSUME(LCurly); // "{"
29
30
  $.MANY(() => {
30
31
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -16,10 +16,11 @@ export function workflowTestDeclaration($) {
16
16
  $.SUBRULE($.optionalCommentBlockFn);
17
17
 
18
18
  const parent = $.CONSUME(WorkflowTestToken);
19
- $.OR([
19
+ const nameToken = $.OR([
20
20
  { ALT: () => $.CONSUME(StringLiteral) },
21
21
  { ALT: () => $.CONSUME(Identifier) },
22
22
  ]);
23
+ $.validateDeclarationName(nameToken, "workflow_test");
23
24
  $.CONSUME(LCurly); // "{"
24
25
  $.MANY(() => {
25
26
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line
@@ -9,10 +9,11 @@ export function workspaceDeclaration($) {
9
9
  $.SUBRULE($.optionalCommentBlockFn);
10
10
 
11
11
  const parent = $.CONSUME(WorkspaceToken); // workspace
12
- $.OR([
12
+ const nameToken = $.OR([
13
13
  { ALT: () => $.CONSUME(StringLiteral) },
14
14
  { ALT: () => $.CONSUME(Identifier) },
15
15
  ]);
16
+ $.validateDeclarationName(nameToken, "workspace");
16
17
 
17
18
  $.SUBRULE($.schemaParseAttributeFn, {
18
19
  ARGS: [
@@ -23,10 +23,11 @@ export function workspaceTriggerDeclaration($) {
23
23
  $.SUBRULE($.optionalCommentBlockFn);
24
24
 
25
25
  const parent = $.CONSUME(WorkspaceTriggerToken); // workspace_trigger
26
- $.OR([
26
+ const nameToken = $.OR([
27
27
  { ALT: () => $.CONSUME(StringLiteral) },
28
28
  { ALT: () => $.CONSUME(Identifier) },
29
29
  ]);
30
+ $.validateDeclarationName(nameToken, "workspace_trigger");
30
31
  $.CONSUME(LCurly); // "{"
31
32
  $.MANY(() => {
32
33
  $.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // at least one new line