@xano/xanoscript-language-server 11.7.1 → 11.8.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.
@@ -12,7 +12,14 @@
12
12
  "Bash(find:*)",
13
13
  "Read(//tmp/**)",
14
14
  "Bash(git stash:*)",
15
- "Bash(node:*)"
15
+ "Bash(node:*)",
16
+ "Bash(for:*)",
17
+ "Bash(do)",
18
+ "Bash(if ! grep -q \"guidFieldAttribute\" \"$f\")",
19
+ "Bash(then)",
20
+ "Bash(echo:*)",
21
+ "Bash(fi)",
22
+ "Bash(done)"
16
23
  ]
17
24
  }
18
25
  }
package/lexer/tokens.js CHANGED
@@ -284,6 +284,12 @@ export const SensitiveToken = createTokenByName("sensitive", {
284
284
  categories: [Identifier], // could also be an identifier
285
285
  });
286
286
 
287
+ // define the sensitivity of a column
288
+ export const TriggerToken = createTokenByName("trigger", {
289
+ longer_alt: Identifier,
290
+ categories: [Identifier], // could also be an identifier
291
+ });
292
+
287
293
  export const DescriptionToken = createTokenByName("description", {
288
294
  longer_alt: Identifier,
289
295
  categories: [Identifier], // could also be an identifier
@@ -350,6 +356,7 @@ export const allTokens = uniq([
350
356
  AuthToken,
351
357
  GuidToken,
352
358
  SensitiveToken,
359
+ TriggerToken,
353
360
  TagsToken,
354
361
  DescriptionToken,
355
362
  DocsToken,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/xanoscript-language-server",
3
- "version": "11.7.1",
3
+ "version": "11.8.0",
4
4
  "description": "Language Server Protocol implementation for XanoScript",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -17,6 +17,7 @@ import {
17
17
  export function addonDeclaration($) {
18
18
  return () => {
19
19
  let hasDescription = false;
20
+ let hasGuid = false;
20
21
  let hasInput = false;
21
22
  let hasStack = false;
22
23
  let hasTags = false;
@@ -41,6 +42,13 @@ export function addonDeclaration($) {
41
42
  $.SUBRULE($.descriptionFieldAttribute);
42
43
  },
43
44
  },
45
+ {
46
+ GATE: () => !hasGuid,
47
+ ALT: () => {
48
+ hasGuid = true;
49
+ $.SUBRULE($.guidFieldAttribute);
50
+ },
51
+ },
44
52
  {
45
53
  GATE: () => !hasInput,
46
54
  ALT: () => {
@@ -9,6 +9,7 @@ export function agentDeclaration($) {
9
9
  return () => {
10
10
  let hasCanonical = false;
11
11
  let hasDescription = false;
12
+ let hasGuid = false;
12
13
  let hasDocs = false;
13
14
  let hasHistory = false;
14
15
  let hasLLM = false;
@@ -48,6 +49,13 @@ export function agentDeclaration($) {
48
49
  $.SUBRULE($.descriptionFieldAttribute);
49
50
  },
50
51
  },
52
+ {
53
+ GATE: () => !hasGuid,
54
+ ALT: () => {
55
+ hasGuid = true;
56
+ $.SUBRULE($.guidFieldAttribute);
57
+ },
58
+ },
51
59
  {
52
60
  GATE: () => !hasDocs,
53
61
  ALT: () => {
@@ -14,6 +14,7 @@ export function agentTriggerDeclaration($) {
14
14
  let hasActive = false;
15
15
  let hasAgent = false;
16
16
  let hasDescription = false;
17
+ let hasGuid = false;
17
18
  let hasDocs = false;
18
19
  let hasHistory = false;
19
20
  let hasInput = false;
@@ -69,6 +70,13 @@ export function agentTriggerDeclaration($) {
69
70
  $.SUBRULE($.descriptionFieldAttribute);
70
71
  },
71
72
  },
73
+ {
74
+ GATE: () => !hasGuid,
75
+ ALT: () => {
76
+ hasGuid = true;
77
+ $.SUBRULE($.guidFieldAttribute);
78
+ },
79
+ },
72
80
  {
73
81
  GATE: () => !hasDocs,
74
82
  ALT: () => {
@@ -16,10 +16,12 @@ export function apiGroupDeclaration($) {
16
16
  let hasCanonical = false;
17
17
  let hasCors = false;
18
18
  let hasDescription = false;
19
+ let hasGuid = false;
19
20
  let hasDocs = false;
20
21
  let hasHistory = false;
21
22
  let hasSwagger = false;
22
23
  let hasTags = false;
24
+ let hasMiddleware = false;
23
25
 
24
26
  $.sectionStack.push("apiGroupDeclaration");
25
27
  // Allow leading comments and newlines before the api_group declaration
@@ -43,6 +45,13 @@ export function apiGroupDeclaration($) {
43
45
  $.SUBRULE($.booleanValue);
44
46
  },
45
47
  },
48
+ {
49
+ GATE: () => !hasMiddleware,
50
+ ALT: () => {
51
+ hasMiddleware = true;
52
+ $.SUBRULE($.middlewareClause);
53
+ },
54
+ },
46
55
  {
47
56
  GATE: () => !hasCanonical,
48
57
  ALT: () => {
@@ -81,6 +90,13 @@ export function apiGroupDeclaration($) {
81
90
  $.SUBRULE($.descriptionFieldAttribute);
82
91
  },
83
92
  },
93
+ {
94
+ GATE: () => !hasGuid,
95
+ ALT: () => {
96
+ hasGuid = true;
97
+ $.SUBRULE($.guidFieldAttribute);
98
+ },
99
+ },
84
100
  {
85
101
  GATE: () => !hasDocs,
86
102
  ALT: () => {
@@ -39,6 +39,16 @@ describe("api_group", () => {
39
39
  expect(parser.errors).to.be.empty;
40
40
  });
41
41
 
42
+ it("should accept a middleware", () => {
43
+ const parser = xanoscriptParser(`api_group "some name" {
44
+ description = "Some description"
45
+ active = false
46
+ canonical = "HZ4jLtdc"
47
+ middleware = {pre: [{name: "M1"}], post: [{name: "M1"}]}
48
+ }`);
49
+ expect(parser.errors).to.be.empty;
50
+ });
51
+
42
52
  it("should parse a disable swagger api_group", () => {
43
53
  const parser = xanoscriptParser(`api_group Authentication {
44
54
  active = false
@@ -0,0 +1,16 @@
1
+ import { EqualToken } from "../../lexer/control.js";
2
+ import { StringLiteral } from "../../lexer/literal.js";
3
+ import { GuidToken } from "../../lexer/tokens.js";
4
+
5
+ /**
6
+ * @param {import('../base_parser.js').XanoBaseParser} $
7
+ */
8
+ export function guidFieldAttribute($) {
9
+ return () => {
10
+ $.sectionStack.push("guidFieldAttribute");
11
+ $.CONSUME(GuidToken); // "guid"
12
+ $.CONSUME(EqualToken); // "="
13
+ $.CONSUME(StringLiteral); // e.g., "tgGYuUFKbBz4_6DIkDR5hUUCRno"
14
+ $.sectionStack.pop();
15
+ };
16
+ }
@@ -0,0 +1,93 @@
1
+ import { expect } from "chai";
2
+ import { describe, it } from "mocha";
3
+ import { xanoscriptParser } from "../parser.js";
4
+
5
+ describe("guidFieldAttribute", () => {
6
+ it("should parse guid in a table", () => {
7
+ const parser = xanoscriptParser(`table "foo" {
8
+ guid = "tgGYuUFKbBz4_6DIkDR5hUUCRno"
9
+ auth = false
10
+ schema {
11
+ int id
12
+ }
13
+ }`);
14
+ expect(parser.errors).to.be.empty;
15
+ });
16
+
17
+ it("should parse guid in a function", () => {
18
+ const parser = xanoscriptParser(`function "my/function" {
19
+ guid = "dg4egGY_sadclkj231af32"
20
+ input {
21
+ }
22
+ stack {
23
+ }
24
+ response = null
25
+ }`);
26
+ expect(parser.errors).to.be.empty;
27
+ });
28
+
29
+ it("should parse guid in a query", () => {
30
+ const parser = xanoscriptParser(`query "test" verb = GET {
31
+ guid = "abc123def456"
32
+ api_group = "default"
33
+ input {
34
+ }
35
+ stack {
36
+ }
37
+ response = null
38
+ }`);
39
+ expect(parser.errors).to.be.empty;
40
+ });
41
+
42
+ it("should parse guid in a task", () => {
43
+ const parser = xanoscriptParser(`task "my_task" {
44
+ guid = "task_guid_123"
45
+ stack {
46
+ }
47
+ }`);
48
+ expect(parser.errors).to.be.empty;
49
+ });
50
+
51
+ it("should parse guid in an api_group", () => {
52
+ const parser = xanoscriptParser(`api_group "my_group" {
53
+ guid = "api_group_guid_123"
54
+ }`);
55
+ expect(parser.errors).to.be.empty;
56
+ });
57
+
58
+ it("should parse guid in a middleware", () => {
59
+ const parser = xanoscriptParser(`middleware "my_mw" {
60
+ guid = "mw_guid_123"
61
+ input {
62
+ }
63
+ stack {
64
+ }
65
+ response = null
66
+ }`);
67
+ expect(parser.errors).to.be.empty;
68
+ });
69
+
70
+ it("should not allow duplicate guid", () => {
71
+ const parser = xanoscriptParser(`function "test" {
72
+ guid = "first"
73
+ guid = "second"
74
+ input {
75
+ }
76
+ stack {
77
+ }
78
+ response = null
79
+ }`);
80
+ expect(parser.errors).to.not.be.empty;
81
+ });
82
+
83
+ it("should work without guid (optional)", () => {
84
+ const parser = xanoscriptParser(`function "test" {
85
+ input {
86
+ }
87
+ stack {
88
+ }
89
+ response = null
90
+ }`);
91
+ expect(parser.errors).to.be.empty;
92
+ });
93
+ });
@@ -2,6 +2,7 @@ import { columnDefaultValueAttribute } from "./columnDefaultValueAttribute.js";
2
2
  import { descriptionFieldAttribute } from "./descriptionFieldAttribute.js";
3
3
  import { disabledFieldAttribute } from "./disabledFieldAttribute.js";
4
4
  import { docsFieldAttribute } from "./docsFieldAttribute.js"
5
+ import { guidFieldAttribute } from "./guidFieldAttribute.js";
5
6
  import { inputFilterFn } from "./inputFilterFn.js";
6
7
  import { sensitiveFieldAttribute } from "./sensitiveFieldAttribute.js";
7
8
  import { valueFieldAttribute } from "./valueFieldAttribute.js";
@@ -28,6 +29,10 @@ export const register = ($) => {
28
29
  "docsFieldAttribute",
29
30
  docsFieldAttribute($)
30
31
  );
32
+ $.guidFieldAttribute = $.RULE(
33
+ "guidFieldAttribute",
34
+ guidFieldAttribute($)
35
+ );
31
36
  $.inputFilterFn = $.RULE("inputFilterFn", inputFilterFn($));
32
37
  $.sensitiveFieldAttribute = $.RULE(
33
38
  "sensitiveFieldAttribute",
@@ -55,6 +55,10 @@ export function nakedStackFn($) {
55
55
  GATE: () => options.allowCallStatements,
56
56
  ALT: () => $.SUBRULE($.middlewareCallFn),
57
57
  },
58
+ {
59
+ GATE: () => options.allowCallStatements,
60
+ ALT: () => $.SUBRULE($.triggerCallFn),
61
+ },
58
62
  { ALT: () => $.SUBRULE($.workflowExpectFn) },
59
63
  ]);
60
64
  });
@@ -36,10 +36,12 @@ export function viewClause($) {
36
36
 
37
37
  // each key is the view name, ensure either search or hide is present
38
38
  for (const viewName in captured) {
39
- if (!captured[viewName].search && !captured[viewName].hide) {
39
+ const hasSearch = !!captured[viewName].search;
40
+ const hasSort = !!captured[viewName].sort;
41
+ if (!hasSearch && !hasSort && !captured[viewName].hide) {
40
42
  $.addMissingError(
41
43
  parent,
42
- `view ${viewName} must have either a search or hide criteria`
44
+ `view ${viewName} must have either a search, sort or hide criteria`,
43
45
  );
44
46
  }
45
47
  }
@@ -109,13 +109,22 @@ describe("viewClause", () => {
109
109
  expect(parser.errors).to.be.empty;
110
110
  });
111
111
 
112
- it("viewClause requires either a search or hide criteria", () => {
112
+ it("viewClause accept either a sort criteria", () => {
113
113
  const parser = parse(`view = {
114
114
  "no search criteria": {
115
115
  sort : {id: "asc"}
116
116
  id : "9ed7daad-682f-455e-bf02-ca53444cd429"
117
117
  }
118
118
  }`);
119
+ expect(parser.errors).to.be.empty;
120
+ });
121
+
122
+ it("viewClause requires either a search, sort or hide criteria", () => {
123
+ const parser = parse(`view = {
124
+ "no criteria": {
125
+ id : "9ed7daad-682f-455e-bf02-ca53444cd429"
126
+ }
127
+ }`);
119
128
  expect(parser.errors).to.not.be.empty;
120
129
  });
121
130
 
@@ -9,6 +9,7 @@ export function functionDeclaration($) {
9
9
  return () => {
10
10
  let hasCache = false;
11
11
  let hasDescription = false;
12
+ let hasGuid = false;
12
13
  let hasDocs = false;
13
14
  let hasHistory = false;
14
15
  let hasInput = false;
@@ -54,6 +55,13 @@ export function functionDeclaration($) {
54
55
  $.SUBRULE($.descriptionFieldAttribute);
55
56
  },
56
57
  },
58
+ {
59
+ GATE: () => !hasGuid,
60
+ ALT: () => {
61
+ hasGuid = true;
62
+ $.SUBRULE($.guidFieldAttribute);
63
+ },
64
+ },
57
65
  {
58
66
  GATE: () => !hasDocs,
59
67
  ALT: () => {
@@ -32,6 +32,7 @@ import { streamFn } from "./streamFn.js";
32
32
  import { register as register_text } from "./text/register.js";
33
33
  import { textFn } from "./textFn.js";
34
34
  import { toolCallFn } from "./toolCallFn.js";
35
+ import { triggerCallFn } from "./triggerCallFn.js";
35
36
  import { unitExpectFn } from "./unitExpectFn.js";
36
37
  import { register as register_util } from "./util/register.js";
37
38
  import { utilFn } from "./utilFn.js";
@@ -70,6 +71,7 @@ export const register = ($) => {
70
71
  $.unitExpectFn = $.RULE("unitExpectFn", unitExpectFn($));
71
72
  $.workflowExpectFn = $.RULE("workflowExpectFn", workflowExpectFn($));
72
73
  $.toolCallFn = $.RULE("toolCallFn", toolCallFn($));
74
+ $.triggerCallFn = $.RULE("triggerCallFn", triggerCallFn($));
73
75
  register_ai($);
74
76
  register_schema($);
75
77
  register_api($);
@@ -0,0 +1,48 @@
1
+ import { CallToken } from "../../lexer/function.js";
2
+ import { StringLiteral } from "../../lexer/literal.js";
3
+ import { Identifier } from "../../lexer/tokens.js";
4
+ import { DotToken, TriggerToken } from "../../lexer/tokens.js";
5
+
6
+ /**
7
+ * @param {import('../../base_parser.js').XanoBaseParser} $
8
+ */
9
+ export function triggerCallFn($) {
10
+ return () => {
11
+ $.sectionStack.push("triggerCallFn");
12
+
13
+ $.CONSUME(TriggerToken); // "trigger"
14
+ $.CONSUME(DotToken); // "."
15
+ const fnToken = $.CONSUME(CallToken); // "call"
16
+
17
+ // Validate that trigger.call is only used in allowed contexts
18
+ const validContexts = ["workflowTestDeclaration"];
19
+ const isInValidContext = validContexts.some((context) =>
20
+ $.sectionStack.includes(context),
21
+ );
22
+
23
+ if (!isInValidContext) {
24
+ $.addInvalidValueError(
25
+ fnToken,
26
+ "trigger.call can only be used within workflow_test contexts",
27
+ );
28
+ }
29
+
30
+ $.OR([
31
+ { ALT: () => $.CONSUME(StringLiteral) }, // "foo/bar"
32
+ { ALT: () => $.CONSUME(Identifier) }, // foo
33
+ ]);
34
+
35
+ $.SUBRULE($.schemaParseAttributeFn, {
36
+ ARGS: [
37
+ fnToken,
38
+ {
39
+ "description?": "[string]",
40
+ "disabled?": "[boolean]",
41
+ "input?": { "[string]": "[expression]" },
42
+ },
43
+ ],
44
+ });
45
+ $.SUBRULE($.asVariable, { ARGS: [fnToken] });
46
+ $.sectionStack.pop();
47
+ };
48
+ }
@@ -0,0 +1,51 @@
1
+ import { expect } from "chai";
2
+ import { describe, it } from "mocha";
3
+ import { lexDocument } from "../../lexer/lexer.js";
4
+ import { parser } from "../test_parser.js";
5
+
6
+ function parse(inputText, context = null) {
7
+ parser.reset();
8
+ const lexResult = lexDocument(inputText);
9
+ parser.input = lexResult.tokens;
10
+
11
+ if (context) {
12
+ parser.sectionStack.push(context);
13
+ parser.triggerCallFn();
14
+ parser.sectionStack.pop();
15
+ } else {
16
+ parser.triggerCallFn();
17
+ }
18
+
19
+ return parser;
20
+ }
21
+
22
+ describe("triggerCallFn", () => {
23
+ it("should parse trigger.call statement", () => {
24
+ const parser = parse(
25
+ `trigger.call my_agent {
26
+ input = {
27
+ "key": "value"
28
+ }
29
+ } as $result`,
30
+ "workflowTestDeclaration",
31
+ );
32
+ expect(parser.errors).to.be.empty;
33
+ });
34
+
35
+ it("trigger.call can be one liner without a body", () => {
36
+ const parser = parse(
37
+ `trigger.call my_agent as $result`,
38
+ "workflowTestDeclaration",
39
+ );
40
+ expect(parser.errors).to.be.empty;
41
+ });
42
+
43
+ it("should not allow trigger.call statement outside of workflowTestDeclaration", () => {
44
+ const parser = parse(`trigger.call my_agent {
45
+ input = {
46
+ "key": "value"
47
+ }
48
+ } as $result`);
49
+ expect(parser.errors).to.not.be.empty;
50
+ });
51
+ });
@@ -13,6 +13,7 @@ export function mcpServerDeclaration($) {
13
13
  let hasActive = false;
14
14
  let hasCanonical = false;
15
15
  let hasDescription = false;
16
+ let hasGuid = false;
16
17
  let hasDocs = false;
17
18
  let hasHistory = false;
18
19
  let hasInstructions = false;
@@ -58,6 +59,13 @@ export function mcpServerDeclaration($) {
58
59
  $.SUBRULE($.descriptionFieldAttribute);
59
60
  },
60
61
  },
62
+ {
63
+ GATE: () => !hasGuid,
64
+ ALT: () => {
65
+ hasGuid = true;
66
+ $.SUBRULE($.guidFieldAttribute);
67
+ },
68
+ },
61
69
  {
62
70
  GATE: () => !hasDocs,
63
71
  ALT: () => {
@@ -12,6 +12,7 @@ export function mcpServerTriggerDeclaration($) {
12
12
  let hasActions = false;
13
13
  let hasActive = false;
14
14
  let hasDescription = false;
15
+ let hasGuid = false;
15
16
  let hasHistory = false;
16
17
  let hasInput = false;
17
18
  let hasMcpServer = false;
@@ -69,6 +70,13 @@ export function mcpServerTriggerDeclaration($) {
69
70
  $.SUBRULE($.descriptionFieldAttribute);
70
71
  },
71
72
  },
73
+ {
74
+ GATE: () => !hasGuid,
75
+ ALT: () => {
76
+ hasGuid = true;
77
+ $.SUBRULE($.guidFieldAttribute);
78
+ },
79
+ },
72
80
  {
73
81
  GATE: () => !hasHistory,
74
82
  ALT: () => {
@@ -11,6 +11,7 @@ import { Identifier, NewlineToken } from "../lexer/tokens.js";
11
11
  export function middlewareDeclaration($) {
12
12
  return () => {
13
13
  let hasDescription = false;
14
+ let hasGuid = false;
14
15
  let hasDocs = false;
15
16
  let hasExceptionPolicy = false;
16
17
  let hasHistory = false;
@@ -43,6 +44,13 @@ export function middlewareDeclaration($) {
43
44
  $.SUBRULE($.descriptionFieldAttribute);
44
45
  },
45
46
  },
47
+ {
48
+ GATE: () => !hasGuid,
49
+ ALT: () => {
50
+ hasGuid = true;
51
+ $.SUBRULE($.guidFieldAttribute);
52
+ },
53
+ },
46
54
  {
47
55
  GATE: () => !hasDocs,
48
56
  ALT: () => {
@@ -20,6 +20,7 @@ export function queryDeclaration($) {
20
20
  let hasAuth = false;
21
21
  let hasCache = false;
22
22
  let hasDescription = false;
23
+ let hasGuid = false;
23
24
  let hasDocs = false;
24
25
  let hasHistory = false;
25
26
  let hasInput = false;
@@ -101,6 +102,13 @@ export function queryDeclaration($) {
101
102
  $.SUBRULE($.descriptionFieldAttribute);
102
103
  },
103
104
  },
105
+ {
106
+ GATE: () => !hasGuid,
107
+ ALT: () => {
108
+ hasGuid = true;
109
+ $.SUBRULE($.guidFieldAttribute);
110
+ },
111
+ },
104
112
  {
105
113
  GATE: () => !hasApiGroup,
106
114
  ALT: () => {
@@ -114,6 +114,22 @@ describe("query_parser", () => {
114
114
  expect(parser.errors).to.be.empty;
115
115
  });
116
116
 
117
+ it("should accept a middleware clause", () => {
118
+ const parser = xanoscriptParser(`query foo verb=GET {
119
+ input {
120
+ text user_id filters=trim
121
+ }
122
+
123
+ stack {
124
+ }
125
+
126
+ response = null
127
+
128
+ middleware = {pre: [{name: "M1"}], post: [{name: "M1"}]}
129
+ }`);
130
+ expect(parser.errors).to.be.empty;
131
+ });
132
+
117
133
  it("should accept a test", () => {
118
134
  const parser = xanoscriptParser(`query test_expect verb=GET {
119
135
  input {
@@ -13,6 +13,7 @@ export function realtimeTriggerDeclaration($) {
13
13
  let hasActive = false;
14
14
  let hasChannel = false;
15
15
  let hasDescription = false;
16
+ let hasGuid = false;
16
17
  let hasHistory = false;
17
18
  let hasInput = false;
18
19
  let hasResponse = false;
@@ -75,6 +76,13 @@ export function realtimeTriggerDeclaration($) {
75
76
  $.SUBRULE($.descriptionFieldAttribute);
76
77
  },
77
78
  },
79
+ {
80
+ GATE: () => !hasGuid,
81
+ ALT: () => {
82
+ hasGuid = true;
83
+ $.SUBRULE($.guidFieldAttribute);
84
+ },
85
+ },
78
86
  {
79
87
  GATE: () => !hasHistory,
80
88
  ALT: () => {
@@ -44,6 +44,7 @@ export function tableDeclaration($) {
44
44
  let hasView = false;
45
45
  let hasAuth = false;
46
46
  let hasDescription = false;
47
+ let hasGuid = false;
47
48
  let hasTags = false;
48
49
  let hasAutoComplete = false;
49
50
  let hasIndex = false;
@@ -62,6 +63,10 @@ export function tableDeclaration($) {
62
63
  GATE: () => !hasDescription,
63
64
  ALT: () => $.SUBRULE($.descriptionFieldAttribute),
64
65
  },
66
+ {
67
+ GATE: () => !hasGuid,
68
+ ALT: () => $.SUBRULE($.guidFieldAttribute),
69
+ },
65
70
  {
66
71
  GATE: () => !hasTags,
67
72
  ALT: () => $.SUBRULE($.tagsAttribute),
@@ -34,6 +34,26 @@ describe("table_parser", () => {
34
34
  expect(parser.errors).to.be.empty;
35
35
  });
36
36
 
37
+ it("should parse a basic table with an ordering view", () => {
38
+ const parser = xanoscriptParser(`table foo {
39
+ auth = false
40
+
41
+ schema {
42
+ // Primary key
43
+ int id
44
+ }
45
+
46
+ view = {
47
+ asc: {
48
+ alias: "testAlias"
49
+ sort : {Country: "asc"}
50
+ id : "b4530953-23df-401a-a2c9-9432b31cd808"
51
+ }
52
+ }
53
+ }`);
54
+ expect(parser.errors).to.be.empty;
55
+ });
56
+
37
57
  // autocomplete = [{ name: "id" }, { name: "cd" }];
38
58
  it("should parse a table with an autocomplete field", () => {
39
59
  const parser = xanoscriptParser(`table foo {
@@ -15,6 +15,7 @@ export function tableTriggerDeclaration($) {
15
15
  let hasDatasources = false;
16
16
  let hasDbTable = false;
17
17
  let hasDescription = false;
18
+ let hasGuid = false;
18
19
  let hasHistory = false;
19
20
  let hasInput = false;
20
21
  let hasStack = false;
@@ -91,6 +92,13 @@ export function tableTriggerDeclaration($) {
91
92
  $.SUBRULE($.descriptionFieldAttribute);
92
93
  },
93
94
  },
95
+ {
96
+ GATE: () => !hasGuid,
97
+ ALT: () => {
98
+ hasGuid = true;
99
+ $.SUBRULE($.guidFieldAttribute);
100
+ },
101
+ },
94
102
  {
95
103
  GATE: () => !hasHistory,
96
104
  ALT: () => {
@@ -9,6 +9,7 @@ export function taskDeclaration($) {
9
9
  let hasActive = false;
10
10
  let hasDataSource = false;
11
11
  let hasDescription = false;
12
+ let hasGuid = false;
12
13
  let hasDocs = false;
13
14
  let hasHistory = false;
14
15
  let hasMiddleware = false;
@@ -57,6 +58,13 @@ export function taskDeclaration($) {
57
58
  $.SUBRULE($.descriptionFieldAttribute);
58
59
  },
59
60
  },
61
+ {
62
+ GATE: () => !hasGuid,
63
+ ALT: () => {
64
+ hasGuid = true;
65
+ $.SUBRULE($.guidFieldAttribute);
66
+ },
67
+ },
60
68
  {
61
69
  GATE: () => !hasDocs,
62
70
  ALT: () => {
@@ -6,6 +6,7 @@ import { InstructionsToken, ToolToken } from "../lexer/tool.js";
6
6
  export function toolDeclaration($) {
7
7
  return () => {
8
8
  let hasDescription = false;
9
+ let hasGuid = false;
9
10
  let hasDocs = false;
10
11
  let hasHistory = false;
11
12
  let hasInput = false;
@@ -36,6 +37,13 @@ export function toolDeclaration($) {
36
37
  $.SUBRULE($.descriptionFieldAttribute);
37
38
  },
38
39
  },
40
+ {
41
+ GATE: () => !hasGuid,
42
+ ALT: () => {
43
+ hasGuid = true;
44
+ $.SUBRULE($.guidFieldAttribute);
45
+ },
46
+ },
39
47
  {
40
48
  GATE: () => !hasDocs,
41
49
  ALT: () => {
@@ -7,6 +7,7 @@ export function workflowTestDeclaration($) {
7
7
  return () => {
8
8
  let hasDatasource = false;
9
9
  let hasDescription = false;
10
+ let hasGuid = false;
10
11
  let hasStack = false;
11
12
  let hasTags = false;
12
13
 
@@ -40,6 +41,13 @@ export function workflowTestDeclaration($) {
40
41
  $.SUBRULE($.descriptionFieldAttribute);
41
42
  },
42
43
  },
44
+ {
45
+ GATE: () => !hasGuid,
46
+ ALT: () => {
47
+ hasGuid = true;
48
+ $.SUBRULE($.guidFieldAttribute);
49
+ },
50
+ },
43
51
  {
44
52
  GATE: () => !hasStack,
45
53
  ALT: () => {
@@ -12,6 +12,7 @@ export function workspaceTriggerDeclaration($) {
12
12
  let hasActions = false;
13
13
  let hasActive = false;
14
14
  let hasDescription = false;
15
+ let hasGuid = false;
15
16
  let hasHistory = false;
16
17
  let hasInput = false;
17
18
  let hasStack = false;
@@ -67,6 +68,13 @@ export function workspaceTriggerDeclaration($) {
67
68
  $.SUBRULE($.descriptionFieldAttribute);
68
69
  },
69
70
  },
71
+ {
72
+ GATE: () => !hasGuid,
73
+ ALT: () => {
74
+ hasGuid = true;
75
+ $.SUBRULE($.guidFieldAttribute);
76
+ },
77
+ },
70
78
  {
71
79
  GATE: () => !hasHistory,
72
80
  ALT: () => {