@xano/xanoscript-language-server 11.5.0 → 11.6.1

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.
Files changed (32) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/lexer/literal.js +1 -1
  3. package/onDidChangeContent/onDidChangeContent.js +4 -4
  4. package/onHover/onHoverDocument.js +3 -3
  5. package/onSemanticCheck/highlight.js +3 -3
  6. package/onSemanticCheck/onSemanticCheck.js +1 -1
  7. package/package.json +1 -1
  8. package/parser/agent_parser.js +7 -9
  9. package/parser/api_group_parser.js +10 -23
  10. package/parser/clauses/cacheClause.js +9 -10
  11. package/parser/functions/util/utilGetRawInputFn.js +1 -1
  12. package/parser/functions/util/utilGetRawInputFn.spec.js +7 -0
  13. package/parser/functions/varFn.js +39 -2
  14. package/parser/functions/varFn.spec.js +21 -0
  15. package/parser/generic/assignableVariableProperty.js +40 -3
  16. package/parser/generic/completeEnvVariable.js +1 -1
  17. package/parser/generic/completeEnvVariable.spec.js +5 -0
  18. package/parser/generic/expressionFn.spec.js +9 -4
  19. package/parser/generic/register.js +10 -22
  20. package/parser/mcp_server_parser.js +7 -9
  21. package/parser/mcp_server_trigger_parser.js +2 -6
  22. package/parser/realtime_trigger_parser.js +3 -7
  23. package/parser/table_trigger_parser.js +9 -11
  24. package/parser/test_parser.js +0 -4
  25. package/parser/workspace_trigger_parser.js +4 -8
  26. package/server.js +2 -2
  27. package/parser/generic/arrayOfObjectAttrReq.js +0 -47
  28. package/parser/generic/arrayOfObjectAttrReq.spec.js +0 -254
  29. package/parser/generic/arrayOfStringLiterals.js +0 -45
  30. package/parser/generic/arrayOfStringLiterals.spec.js +0 -56
  31. package/parser/generic/objectAttrReq.js +0 -243
  32. package/parser/generic/objectAttrReq.spec.js +0 -412
@@ -1,243 +0,0 @@
1
- import { MismatchedTokenException } from "chevrotain";
2
- import { ColonToken, CommaToken, LCurly, RCurly } from "../../lexer/control.js";
3
- import { StringLiteral } from "../../lexer/literal.js";
4
- import { MultiLineStringToken } from "../../lexer/multiline.js";
5
- import { Identifier, NewlineToken } from "../../lexer/tokens.js";
6
- import { getVarName } from "./utils.js";
7
-
8
- const DEFAULT_OPTIONS = {
9
- allowDuplicates: [],
10
- allowQueryExpression: false,
11
- recursive: [],
12
- recursiveArray: [],
13
- allowVariables: true,
14
- types: {},
15
- };
16
-
17
- /**
18
- * Dynamicly raises error for missing and required attributes
19
- * @param {import('../base_parser.js').XanoBaseParser} $
20
- */
21
- export function objectAttrReq($) {
22
- /**
23
- * @param {import('chevrotain').IToken} parent
24
- * @param {string[]} required the required attributes
25
- * @param {string[]} optional the optional attributes
26
- * @param {Object} options additional options
27
- * @param {string[]} options.allowDuplicates attributes that are allowed to be duplicated
28
- * @param {string[]} options.allowQueryExpression attributes that are allowed to be duplicated
29
- * @param {string[]} options.recursive the same rules applies to sub-objects deeper in the tree
30
- * @param {string[]} options.recursiveArray the same rules applies to sub-arrays deeper in the tree
31
- * @param {boolean} options.allowVariables whether to allow variables as values
32
- * @param {Object} options.types a map of attribute names to their expected types (string, number, boolean)
33
- * if the type is not specified, any value is allowed
34
- **/
35
- return (parent, required, optional, options = {}) => {
36
- // setup basic defaults
37
- required = required || [];
38
- optional = optional || [];
39
-
40
- options = {
41
- ...DEFAULT_OPTIONS,
42
- ...options,
43
- };
44
-
45
- const definedAttributes = [];
46
- const allowedAttributes = [...required, ...optional];
47
- let identifier;
48
-
49
- $.CONSUME(LCurly); // "{"
50
- $.OPTION(() => {
51
- $.OR([
52
- {
53
- // one line, comma separated { key: value, key2: value2 }
54
- ALT: () => {
55
- $.AT_LEAST_ONE_SEP({
56
- SEP: CommaToken,
57
- DEF: () => {
58
- identifier = $.OR1([
59
- { ALT: () => $.CONSUME(Identifier) }, // key
60
- { ALT: () => $.CONSUME(StringLiteral) }, // "value"
61
- ]);
62
- definedAttributes.push(identifier);
63
- const varName = getVarName(identifier);
64
- $.CONSUME(ColonToken);
65
- if (options.recursive.includes(varName)) {
66
- $.SUBRULE($.objectAttrReq, {
67
- ARGS: [identifier, required, optional, options],
68
- });
69
- } else if (options.recursiveArray.includes(varName)) {
70
- $.SUBRULE($.arrayOfObjectAttrReq, {
71
- ARGS: [identifier, required, optional, options],
72
- });
73
- } else {
74
- const varType = options.types[varName];
75
- if (typeof varType === "function") {
76
- varType.call(null, $, identifier); // custom function handler
77
- } else if (Array.isArray(varType)) {
78
- // Treat array as enum - value must be one of the array elements
79
- const stringToken = $.CONSUME3(StringLiteral);
80
- const providedValue = getVarName(stringToken);
81
-
82
- // Check if the provided value is in the allowed array
83
- if (!varType.includes(providedValue)) {
84
- $.addMissingError(
85
- stringToken,
86
- `Invalid value "${providedValue}". Must be one of: ${varType
87
- .map((v) => `"${v}"`)
88
- .join(", ")}`
89
- );
90
- }
91
- } else {
92
- $.OR4([
93
- {
94
- GATE: () => varType === "boolean",
95
- ALT: () => $.SUBRULE($.booleanValue), // boolean
96
- },
97
- {
98
- GATE: () => varType === "number",
99
- ALT: () => $.SUBRULE($.numberValue), // number
100
- },
101
- {
102
- GATE: () => varType === "string",
103
- ALT: () => $.CONSUME3(StringLiteral), // "..."
104
- },
105
- {
106
- GATE: () => varType === "object",
107
- ALT: () =>
108
- $.SUBRULE1($.objectWithAttributes, {
109
- ARGS: [options],
110
- }),
111
- },
112
- {
113
- GATE: () => !varType,
114
- ALT: () =>
115
- $.SUBRULE($.expressionFn, {
116
- ARGS: [identifier, options],
117
- }), // anything goes
118
- },
119
- ]);
120
- }
121
- }
122
- },
123
- });
124
- },
125
- },
126
- {
127
- // multi line, each key value pair on a new line
128
- // {
129
- // key: value
130
- // key2: value2
131
- // }
132
- ALT: () => {
133
- $.CONSUME(NewlineToken);
134
- $.AT_LEAST_ONE(() => {
135
- const identifier = $.OR2([
136
- { ALT: () => $.CONSUME2(Identifier) }, // key
137
- { ALT: () => $.CONSUME2(StringLiteral) }, // "other key"
138
- ]);
139
- definedAttributes.push(identifier);
140
- $.CONSUME1(ColonToken);
141
- const varName = getVarName(identifier);
142
- if (options.recursive.includes(varName)) {
143
- $.SUBRULE($.objectAttrReq, {
144
- ARGS: [identifier, required, optional, options],
145
- });
146
- } else if (options.recursiveArray.includes(varName)) {
147
- $.SUBRULE($.arrayOfObjectAttrReq, {
148
- ARGS: [identifier, required, optional, options],
149
- });
150
- } else {
151
- const varType = options.types[varName];
152
- if (typeof varType === "function") {
153
- varType.call(null, $, identifier); // custom function handler
154
- } else if (Array.isArray(varType)) {
155
- // Treat array as enum - value must be one of the array elements
156
- const stringToken = $.CONSUME3(StringLiteral);
157
- const providedValue = getVarName(stringToken);
158
-
159
- // Check if the provided value is in the allowed array
160
- if (!varType.includes(providedValue)) {
161
- $.SAVE_ERROR(
162
- new MismatchedTokenException(
163
- `Invalid value "${providedValue}". Must be one of: ${varType
164
- .map((v) => `"${v}"`)
165
- .join(", ")}`,
166
- stringToken,
167
- stringToken
168
- )
169
- );
170
- }
171
- } else {
172
- $.OR3([
173
- {
174
- GATE: () => varType === "boolean",
175
- ALT: () => $.SUBRULE1($.booleanValue), // boolean
176
- },
177
- {
178
- GATE: () => varType === "number",
179
- ALT: () => $.SUBRULE1($.numberValue), // number
180
- },
181
- {
182
- GATE: () => varType === "string",
183
- ALT: () =>
184
- $.OR5([
185
- { ALT: () => $.CONSUME1(StringLiteral) }, // "..."
186
- { ALT: () => $.CONSUME(MultiLineStringToken) },
187
- ]),
188
- },
189
- {
190
- GATE: () => varType === "object",
191
- ALT: () =>
192
- $.SUBRULE($.objectWithAttributes, { ARGS: [options] }),
193
- },
194
- {
195
- GATE: () => !varType,
196
- ALT: () =>
197
- $.SUBRULE1($.expressionFn, {
198
- ARGS: [identifier, options],
199
- }), // anything goes
200
- },
201
- ]);
202
- }
203
- }
204
- $.OPTION1(() => $.CONSUME(CommaToken)); // ","
205
- $.AT_LEAST_ONE1(() => $.CONSUME1(NewlineToken));
206
- });
207
- },
208
- },
209
- ]);
210
- });
211
- $.CONSUME(RCurly); // "}"
212
-
213
- // detects duplicate attributes
214
- const duplicateAttributes = definedAttributes.filter(
215
- (token, index) =>
216
- !options.allowDuplicates.includes(getVarName(token)) &&
217
- definedAttributes.findIndex(
218
- (t) => getVarName(t) === getVarName(token)
219
- ) !== index
220
- );
221
-
222
- for (const token of duplicateAttributes) {
223
- $.addDuplicateAttributeError(token);
224
- }
225
-
226
- // report any illegal attributes
227
- const illegalAttributes = definedAttributes.filter(
228
- (token) => !allowedAttributes.includes(getVarName(token))
229
- );
230
- for (const token of illegalAttributes) {
231
- $.addIllegalAttributeError(token);
232
- }
233
-
234
- // report any missing attributes
235
- const definedAttrNames = definedAttributes.map(getVarName);
236
- const missingAttributes = required.filter(
237
- (reqAttrName) => !definedAttrNames.includes(reqAttrName)
238
- );
239
- if (missingAttributes.length > 0) {
240
- $.addMissingAttributeError(parent, missingAttributes);
241
- }
242
- };
243
- }
@@ -1,412 +0,0 @@
1
- import { expect } from "chai";
2
- import { describe, it } from "mocha";
3
- import { EqualToken } from "../../lexer/control.js";
4
- import { lexDocument } from "../../lexer/lexer.js";
5
- import { Identifier } from "../../lexer/tokens.js";
6
- import { parser } from "../test_parser.js";
7
-
8
- export function parserExtension() {
9
- // this rule requires a foo field to be defined
10
- this.objectAttrReq_test_required = this.RULE(
11
- "objectAttrReq_test_required",
12
- () => {
13
- const name = this.CONSUME(Identifier);
14
- this.CONSUME(EqualToken); // "="
15
- this.SUBRULE(this.objectAttrReq, { ARGS: [name, ["foo"]] });
16
- }
17
- );
18
-
19
- // this rule has no required fields and two optional fields
20
- this.objectAttrReq_test_optionals = this.RULE(
21
- "objectAttrReq_test_optionals",
22
- () => {
23
- const name = this.CONSUME(Identifier);
24
- this.CONSUME(EqualToken); // "="
25
- this.SUBRULE(this.objectAttrReq, { ARGS: [name, [], ["foo", "bar"]] });
26
- }
27
- );
28
-
29
- // this rule has one required and one optional field
30
- this.objectAttrReq_test_optional_and_required = this.RULE(
31
- "objectAttrReq_test_optional_and_required",
32
- () => {
33
- const name = this.CONSUME(Identifier);
34
- this.CONSUME(EqualToken); // "="
35
- this.SUBRULE(this.objectAttrReq, {
36
- ARGS: [name, ["required"], ["option"]],
37
- });
38
- }
39
- );
40
-
41
- // this rule has one required and one optional field
42
- this.objectAttrReq_test_type_req = this.RULE(
43
- "objectAttrReq_test_type_req",
44
- () => {
45
- const name = this.CONSUME(Identifier);
46
- this.CONSUME(EqualToken); // "="
47
- this.SUBRULE(this.objectAttrReq, {
48
- ARGS: [
49
- name,
50
- [],
51
- ["bool", "string", "integer", "decimal", "number", "func"],
52
- {
53
- types: {
54
- bool: "boolean",
55
- string: "string",
56
- integer: "integer",
57
- decimal: "decimal",
58
- number: "number",
59
- func: ($, identifier) => {
60
- $.SUBRULE(this.objectAttrReq, {
61
- ARGS: [
62
- identifier,
63
- ["test"],
64
- [],
65
- {
66
- types: {
67
- test: "string",
68
- },
69
- },
70
- ],
71
- });
72
- },
73
- },
74
- },
75
- ],
76
- });
77
- }
78
- );
79
-
80
- // this rule tests array types as enums
81
- this.objectAttrReq_test_enum_req = this.RULE(
82
- "objectAttrReq_test_enum_req",
83
- () => {
84
- const name = this.CONSUME(Identifier);
85
- this.CONSUME(EqualToken); // "="
86
- this.SUBRULE(this.objectAttrReq, {
87
- ARGS: [
88
- name,
89
- [],
90
- ["status"],
91
- {
92
- types: {
93
- status: ["active", "pending", "inactive"], // array treated as enum
94
- },
95
- },
96
- ],
97
- });
98
- }
99
- );
100
-
101
- // this rule allows duplicates for the "arg" field
102
- this.objectAttrReq_test_allow_duplicates = this.RULE(
103
- "objectAttrReq_test_allow_duplicates",
104
- () => {
105
- const name = this.CONSUME(Identifier);
106
- this.CONSUME(EqualToken); // "="
107
- this.SUBRULE(this.objectAttrReq, {
108
- ARGS: [name, [], ["arg"], { allowDuplicates: ["arg"] }],
109
- });
110
- }
111
- );
112
-
113
- this.objectAttrReq_test_allow_array_object = this.RULE(
114
- "objectAttrReq_test_allow_array_object",
115
- () => {
116
- const name = this.CONSUME(Identifier);
117
- this.CONSUME(EqualToken); // "="
118
- this.SUBRULE(this.objectAttrReq, {
119
- ARGS: [name, [], ["arr", "obj"]],
120
- });
121
- }
122
- );
123
-
124
- this.objectAttrReq_test_obj_in_arr_in_obj = this.RULE(
125
- "objectAttrReq_test_obj_in_arr_in_obj",
126
- () => {
127
- const name = this.CONSUME(Identifier);
128
- this.CONSUME(EqualToken); // "="
129
- this.SUBRULE(this.objectAttrReq, {
130
- ARGS: [name, [], ["type", "field"]],
131
- });
132
- }
133
- );
134
-
135
- this.objectAttrReq_test_allow_multiple_format = this.RULE(
136
- "objectAttrReq_test_allow_multiple_format",
137
- () => {
138
- const name = this.CONSUME(Identifier);
139
- this.CONSUME(EqualToken); // "="
140
- this.SUBRULE(this.objectAttrReq, {
141
- ARGS: [name, [], ["singleline", "multiline"]],
142
- });
143
- }
144
- );
145
- }
146
-
147
- function parse(inputText) {
148
- parser.reset();
149
- const lexResult = lexDocument(inputText);
150
- parser.input = lexResult.tokens;
151
- return parser;
152
- }
153
-
154
- describe("objectAttrReq", () => {
155
- it("objectAttrReq matched requirements", () => {
156
- parse(`something = {
157
- foo: "bar"
158
- }`).objectAttrReq_test_required();
159
-
160
- expect(parser.errors).to.be.empty;
161
- });
162
-
163
- it("objectAttrReq discover missing requirements", () => {
164
- parse(`something = {
165
- foot: "bar"
166
- }`).objectAttrReq_test_required();
167
-
168
- expect(parser.errors).to.not.be.empty;
169
- });
170
-
171
- it("objectAttrReq discover optional requirements", () => {
172
- // should allow one optional requirement
173
- parse(`something = {
174
- foo: "bar"
175
- }`).objectAttrReq_test_optionals();
176
-
177
- expect(parser.errors).to.be.empty;
178
-
179
- // should allow one optional requirement
180
- parse(`something = {
181
- bar: "foo"
182
- }`).objectAttrReq_test_optionals();
183
-
184
- expect(parser.errors).to.be.empty;
185
-
186
- // should allow all optional requirements
187
- parse(`something = {
188
- bar: "foo"
189
- foo: "bar"
190
- }`).objectAttrReq_test_optionals();
191
-
192
- expect(parser.errors).to.be.empty;
193
-
194
- // should allow no optional requirements defined
195
- parse(`something = {}`).objectAttrReq_test_optionals();
196
- expect(parser.errors).to.be.empty;
197
- });
198
-
199
- it("objectAttrReq allows object fields", () => {
200
- parse(`something = {
201
- obj: { foo: "bar" }
202
- }`).objectAttrReq_test_allow_array_object();
203
-
204
- expect(parser.errors).to.be.empty;
205
- });
206
-
207
- it("objectAttrReq allows single line object ", () => {
208
- parse(`something = { obj: "bar" }`).objectAttrReq_test_allow_array_object();
209
- expect(parser.errors).to.be.empty;
210
- });
211
-
212
- it("objectAttrReq key can be a string", () => {
213
- parse(`something = {
214
- "obj": "bar"
215
- }`).objectAttrReq_test_allow_array_object();
216
- expect(parser.errors).to.be.empty;
217
- });
218
-
219
- it("objectAttrReq accepts optional commas", () => {
220
- parse(
221
- `something = { obj: "bar", "arr": "bar" }`
222
- ).objectAttrReq_test_allow_array_object();
223
- expect(parser.errors).to.be.empty;
224
- });
225
-
226
- it("objectAttrReq allows array fields", () => {
227
- parse(`something = {
228
- arr: [1,2, 3]
229
- }`).objectAttrReq_test_allow_array_object();
230
- expect(parser.errors).to.be.empty;
231
- });
232
-
233
- it("objectAttrReq allows obj in array in obj", () => {
234
- parse(
235
- `x = {type: "primary", field: [{name: "id"}]}`
236
- ).objectAttrReq_test_obj_in_arr_in_obj();
237
- expect(parser.errors).to.be.empty;
238
- });
239
-
240
- it("objectAttrReq allows array fields", () => {
241
- parse(`something = {
242
- arr: [1,2, 3]
243
- obj: { foo: "bar", bar: "foo" }
244
- }`).objectAttrReq_test_allow_array_object();
245
- expect(parser.errors).to.be.empty;
246
- });
247
-
248
- it("objectAttrReq allows a mix of single and multiline values", () => {
249
- parse(`something = {
250
- multiline: {
251
- foo: "bar"
252
- bar: "foo"
253
- }
254
- singleline: { foo: "bar", bar: "foo" }
255
- }`).objectAttrReq_test_allow_multiple_format();
256
- expect(parser.errors).to.be.empty;
257
- });
258
-
259
- it("objectAttrReq allows specific duplicates", () => {
260
- // foo is defined twice
261
- parse(`something = {
262
- arg: "fizz"
263
- arg: "buzz"
264
- }`).objectAttrReq_test_allow_duplicates();
265
-
266
- expect(parser.errors).to.be.empty;
267
-
268
- // foo is defined twice
269
- parse(`something = {
270
- arg: "fizz"
271
- arg: "buzz"
272
- foo: "bar"
273
- foo: "baz"
274
- }`).objectAttrReq_test_allow_duplicates();
275
-
276
- expect(parser.errors).to.not.be.empty;
277
- });
278
-
279
- it("objectAttrReq detects duplicates", () => {
280
- // foo is defined twice
281
- parse(`something = {
282
- foo: "fizz"
283
- foo: "buzz"
284
- }`).objectAttrReq_test_required();
285
-
286
- expect(parser.errors).to.not.be.empty;
287
- });
288
-
289
- it("objectAttrReq detects string literal duplicates", () => {
290
- // foo is defined twice
291
- parse(`something = {
292
- "foo": "fizz"
293
- foo: "buzz"
294
- }`).objectAttrReq_test_required();
295
-
296
- expect(parser.errors).to.not.be.empty;
297
- });
298
-
299
- it("objectAttrReq enforces optional requirements", () => {
300
- // foot is not an optional requirement
301
- parse(`something = {
302
- foot = "bar"
303
- }`).objectAttrReq_test_optionals();
304
-
305
- expect(parser.errors).to.not.be.empty;
306
- });
307
-
308
- it("objectAttrReq enforces optional and required fields", () => {
309
- // all optional and required fields are present
310
- parse(`something = {
311
- option: "bar"
312
- required: "bar"
313
- }`).objectAttrReq_test_optional_and_required();
314
- expect(parser.errors).to.be.empty;
315
-
316
- // optional field is missing (all good)
317
- parse(`something = {
318
- required: "bar"
319
- }`).objectAttrReq_test_optional_and_required();
320
-
321
- expect(parser.errors).to.be.empty;
322
-
323
- // required field is missing (not good)
324
- parse(`something = {
325
- option: "bar"
326
- }`).objectAttrReq_test_optional_and_required();
327
-
328
- expect(parser.errors).to.not.be.empty;
329
- });
330
-
331
- describe("objectAttrReq types", () => {
332
- it("enforces string types when provided", () => {
333
- parse(`typed = {
334
- string: "4"
335
- }`).objectAttrReq_test_type_req();
336
-
337
- expect(parser.errors).to.be.empty;
338
-
339
- parse(`typed = {
340
- string: 4
341
- }`).objectAttrReq_test_type_req();
342
-
343
- expect(parser.errors).to.not.be.empty;
344
- });
345
-
346
- it("enforces boolean types when provided", () => {
347
- parse(`typed = {
348
- bool: true
349
- }`).objectAttrReq_test_type_req();
350
-
351
- expect(parser.errors).to.be.empty;
352
-
353
- parse(`typed = {
354
- bool: 4
355
- }`).objectAttrReq_test_type_req();
356
-
357
- expect(parser.errors).to.not.be.empty;
358
- });
359
-
360
- it("enforces number types when provided", () => {
361
- parse(`typed = {
362
- number: 4
363
- }`).objectAttrReq_test_type_req();
364
-
365
- expect(parser.errors).to.be.empty;
366
-
367
- parse(`typed = {
368
- number: 0.5
369
- }`).objectAttrReq_test_type_req();
370
-
371
- expect(parser.errors).to.be.empty;
372
-
373
- parse(`typed = {
374
- number: "4"
375
- }`).objectAttrReq_test_type_req();
376
-
377
- expect(parser.errors).to.not.be.empty;
378
- });
379
-
380
- it("enforces function types when provided", () => {
381
- parse(`typed = {
382
- func: { test: "1" }
383
- }`).objectAttrReq_test_type_req();
384
-
385
- expect(parser.errors).to.be.empty;
386
- });
387
-
388
- it("enforces array types as enums when provided", () => {
389
- // Valid enum value
390
- parse(`typed = {
391
- status: "active"
392
- }`).objectAttrReq_test_enum_req();
393
-
394
- expect(parser.errors).to.be.empty;
395
-
396
- // Another valid enum value
397
- parse(`typed = {
398
- status: "pending"
399
- }`).objectAttrReq_test_enum_req();
400
-
401
- expect(parser.errors).to.be.empty;
402
-
403
- // Invalid enum value
404
- parse(`typed = {
405
- status: "invalid"
406
- }`).objectAttrReq_test_enum_req();
407
-
408
- expect(parser.errors).to.not.be.empty;
409
- expect(parser.errors[0].message).to.include("Must be one of");
410
- });
411
- });
412
- });