@xano/xanoscript-language-server 11.12.0 → 11.12.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 (41) hide show
  1. package/.claude/memory/feedback_no_git.md +11 -0
  2. package/.claude/settings.local.json +13 -28
  3. package/lexer/cast.js +3 -3
  4. package/lexer/control.js +0 -2
  5. package/lexer/literal.js +2 -2
  6. package/lexer/security.js +2 -2
  7. package/package.json +1 -1
  8. package/parser/attributes/columnDefaultValueAttribute.js +10 -3
  9. package/parser/attributes/inputFilterFn.js +11 -4
  10. package/parser/clauses/flexibleStringClause.js +2 -2
  11. package/parser/clauses/nakedStackFn.js +43 -36
  12. package/parser/clauses/nakedStackFn.spec.js +10 -0
  13. package/parser/clauses/responseClause.spec.js +5 -0
  14. package/parser/definitions/columnDefinition.js +7 -2
  15. package/parser/functions/array/arrayNoValueAs.js +1 -1
  16. package/parser/functions/array/arrayPopFn.js +1 -3
  17. package/parser/functions/controls/forEachFn.spec.js +8 -0
  18. package/parser/functions/controls/preconditionFn.js +3 -0
  19. package/parser/functions/db/dbExternalDirectQueryFn.js +1 -0
  20. package/parser/functions/db/dbQueryFn.spec.js +31 -0
  21. package/parser/functions/schema/schemaParseConstantFn.js +11 -10
  22. package/parser/functions/varFn.js +14 -2
  23. package/parser/functions/varFn.spec.js +20 -12
  24. package/parser/generic/asVariable.spec.js +12 -8
  25. package/parser/generic/assignableVariableAs.js +50 -11
  26. package/parser/generic/assignableVariableAs.spec.js +29 -7
  27. package/parser/generic/assignableVariableProperty.js +22 -10
  28. package/parser/generic/assignableVariableProperty.spec.js +21 -12
  29. package/parser/generic/expressionFn.js +9 -2
  30. package/parser/generic/expressionFn.spec.js +5 -0
  31. package/parser/generic/filterNames.js +9 -0
  32. package/parser/multidoc.js +38 -17
  33. package/parser/multidoc.spec.js +7 -1
  34. package/parser/query_parser.js +11 -3
  35. package/parser/query_parser.spec.js +0 -3
  36. package/parser/tests/function/function_parser.spec.js +4 -4
  37. package/parser/tests/multidoc/multidoc_parser.spec.js +55 -0
  38. package/parser/tests/multidoc/valid_sources/function_stack.xs +130603 -0
  39. package/parser/tests/query/query_parser.spec.js +3 -3
  40. package/parser/tool_parser.js +12 -3
  41. package/parser/tool_parser.spec.js +19 -6
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: no-git-interactions
3
+ description: User does not want Claude to interact with git (no commits, no staging, no git commands)
4
+ type: feedback
5
+ ---
6
+
7
+ Do not interact with git — no commits, no staging, no git commands. Focus purely on implementation and testing.
8
+
9
+ **Why:** User manages their own git workflow.
10
+
11
+ **How to apply:** Skip all git-related steps in plans. When dispatching subagents, explicitly tell them not to run any git commands. Remove commit steps from task instructions.
@@ -2,35 +2,20 @@
2
2
  "permissions": {
3
3
  "allow": [
4
4
  "Bash(npm test:*)",
5
- "Bash(npm run lint)",
6
- "Bash(npm run test:*)",
7
- "Bash(npx eslint:*)",
8
- "Bash(node:*)",
9
- "Bash(npm install)",
5
+ "Bash(git checkout:*)",
6
+ "Bash(ls:*)",
7
+ "Bash(npm run lint:*)",
10
8
  "Bash(grep:*)",
11
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server log --all --pretty=format:\"%h %s\")",
12
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server log --all -S \"password\\\\|secret\\\\|api_key\\\\|token\" --oneline)",
13
- "Bash(xargs file:*)",
14
9
  "Bash(find:*)",
15
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server log -p --all -S \"webhook\\\\|Bearer\\\\|discord\\\\|slack\\\\|xano_insiders\" -- \"*.xs\" \"*.js\")",
16
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server ls-files:*)",
17
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server status)",
18
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server diff --stat)",
19
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server log --oneline -5)",
20
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server add README.md LICENSE package.json lexer/tests/query/valid_sources/basic_query.xs parser/functions/stream/streamFromRequestFn.js parser/functions/stream/streamFromRequestFn.spec.js parser/tests/function/valid_sources/discord_poll_send_to_slack.xs parser/tests/query/valid_sources/all_basics.xs)",
21
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server commit -m \"$\\(cat <<''EOF''\nPrepare package for public npm release as @xano/xanoscript-language-server\n\n- Rename package to @xano/xanoscript-language-server\n- Add MIT LICENSE file\n- Add npm metadata \\(description, repository, author, license, bugs, homepage\\)\n- Remove private flag to allow publishing\n- Sanitize test files: replace internal URLs, IDs, and env var names with placeholders\n- Simplify README maintainer section\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
22
- "Bash(git -C /Users/justinalbrecht/git/xs-language-server log -1 --oneline)",
23
- "Bash(git add:*)",
24
- "Bash(git commit:*)",
25
- "Bash(git push)",
26
- "Bash(npm whoami:*)",
27
- "Bash(npm view:*)",
28
- "Bash(npm version:*)",
29
- "Bash(npm publish:*)",
30
- "Bash(wc:*)",
31
- "Bash(git push:*)"
32
- ],
33
- "deny": [],
34
- "ask": []
10
+ "Read(//tmp/**)",
11
+ "Bash(git stash:*)",
12
+ "Bash(do)",
13
+ "Bash(if ! grep -q \"guidFieldAttribute\" \"$f\")",
14
+ "Bash(then)",
15
+ "Bash(echo:*)",
16
+ "Bash(fi)",
17
+ "Bash(done)",
18
+ "Bash(npx eslint:*)"
19
+ ]
35
20
  }
36
21
  }
package/lexer/cast.js CHANGED
@@ -23,14 +23,14 @@ export const BoolCastToken = createUniqToken({
23
23
  // !array
24
24
  export const ArrayCastToken = createUniqToken({
25
25
  name: "ArrayCast",
26
- pattern: /!array/,
26
+ pattern: /!array(?!\.)/,
27
27
  label: "!array",
28
28
  });
29
29
 
30
30
  // !text
31
31
  export const TextCastToken = createUniqToken({
32
32
  name: "TextCast",
33
- pattern: /!text/,
33
+ pattern: /!text(?!\.)/,
34
34
  label: "!text",
35
35
  });
36
36
 
@@ -51,7 +51,7 @@ export const DecimalCastToken = createUniqToken({
51
51
  // !object
52
52
  export const ObjectCastToken = createUniqToken({
53
53
  name: "ObjectCast",
54
- pattern: /!object/,
54
+ pattern: /!object(?!\.)/,
55
55
  label: "!object",
56
56
  });
57
57
 
package/lexer/control.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { Identifier } from "./identifier.js";
2
- import { IntegerLiteral } from "./literal.js";
3
2
  import { createTokenByName, createUniqToken } from "./utils.js";
4
3
 
5
4
  // conditional
@@ -173,7 +172,6 @@ export const Minus = createUniqToken({
173
172
  name: "Minus",
174
173
  pattern: /-/,
175
174
  label: "-",
176
- longer_alt: IntegerLiteral,
177
175
  });
178
176
 
179
177
  // +
package/lexer/literal.js CHANGED
@@ -24,13 +24,13 @@ export const SingleQuotedStringLiteral = createUniqToken({
24
24
  export const FloatLiteral = createUniqToken({
25
25
  name: "FloatLiteral",
26
26
  label: "floating point number",
27
- pattern: /-?\d+\.\d+([eE][+-]?\d+)?/,
27
+ pattern: /\d+\.\d+([eE][+-]?\d+)?/,
28
28
  });
29
29
 
30
30
  export const IntegerLiteral = createUniqToken({
31
31
  name: "IntegerLiteral",
32
32
  label: "integer",
33
- pattern: /-?\d+/,
33
+ pattern: /\d+/,
34
34
  longer_alt: FloatLiteral,
35
35
  });
36
36
 
package/lexer/security.js CHANGED
@@ -51,13 +51,13 @@ export const CreateSecretKeyToken = createTokenByName("create_secret_key", {
51
51
 
52
52
  // decrypt
53
53
  export const DecryptToken = createTokenByName("decrypt", {
54
- llt: Identifier,
54
+ longer_alt: Identifier,
55
55
  categories: [Identifier],
56
56
  });
57
57
 
58
58
  // encrypt
59
59
  export const EncryptToken = createTokenByName("encrypt", {
60
- llt: Identifier,
60
+ longer_alt: Identifier,
61
61
  categories: [Identifier],
62
62
  });
63
63
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xano/xanoscript-language-server",
3
- "version": "11.12.0",
3
+ "version": "11.12.1",
4
4
  "description": "Language Server Protocol implementation for XanoScript",
5
5
  "type": "module",
6
6
  "main": "server.js",
@@ -1,4 +1,4 @@
1
- import { EqualToken } from "../../lexer/control.js";
1
+ import { EqualToken, Minus } from "../../lexer/control.js";
2
2
  import {
3
3
  FloatLiteral,
4
4
  IntegerLiteral,
@@ -21,8 +21,15 @@ export function columnDefaultValueAttribute($) {
21
21
  $.CONSUME(EqualToken); // "="
22
22
  $.OR([
23
23
  { ALT: () => $.CONSUME(StringLiteral) }, // e.g., "default value"
24
- { ALT: () => $.CONSUME(FloatLiteral) }, // e.g., 42.54
25
- { ALT: () => $.CONSUME(IntegerLiteral) }, // e.g., 42
24
+ {
25
+ ALT: () => {
26
+ $.OPTION(() => $.CONSUME(Minus));
27
+ return $.OR1([
28
+ { ALT: () => $.CONSUME(IntegerLiteral) },
29
+ { ALT: () => $.CONSUME(FloatLiteral) },
30
+ ]);
31
+ },
32
+ },
26
33
  { ALT: () => $.CONSUME(TrueToken) }, // true
27
34
  { ALT: () => $.CONSUME(FalseToken) }, // false
28
35
  { ALT: () => $.CONSUME(NowToken) }, // now
@@ -1,5 +1,5 @@
1
1
  import { ExclamationToken } from "../../lexer/cast.js";
2
- import { ColonToken } from "../../lexer/control.js";
2
+ import { ColonToken, Minus } from "../../lexer/control.js";
3
3
  import {
4
4
  FloatLiteral,
5
5
  IntegerLiteral,
@@ -36,8 +36,15 @@ export function inputFilterFn($) {
36
36
  { ALT: () => $.CONSUME2(Identifier) },
37
37
  { ALT: () => $.CONSUME1(StringLiteral) },
38
38
  { ALT: () => $.CONSUME1(RegExpToken) },
39
- { ALT: () => $.CONSUME1(IntegerLiteral) },
40
- { ALT: () => $.CONSUME1(FloatLiteral) },
39
+ {
40
+ ALT: () => {
41
+ $.OPTION1(() => $.CONSUME(Minus));
42
+ $.OR1([
43
+ { ALT: () => $.CONSUME(IntegerLiteral) },
44
+ { ALT: () => $.CONSUME(FloatLiteral) },
45
+ ]);
46
+ },
47
+ },
41
48
  { ALT: () => $.CONSUME1(FalseToken) },
42
49
  { ALT: () => $.CONSUME1(TrueToken) },
43
50
  ]);
@@ -52,7 +59,7 @@ export function inputFilterFn($) {
52
59
  ) {
53
60
  $.addInvalidValueError(
54
61
  filter,
55
- `Filter '${filter.image}' cannot be applied to input of type '${inputTypeToken.image}'`
62
+ `Filter '${filter.image}' cannot be applied to input of type '${inputTypeToken.image}'`,
56
63
  );
57
64
  }
58
65
  },
@@ -1,7 +1,7 @@
1
1
  import { EqualToken } from "../../lexer/control.js";
2
- import { Identifier } from "../../lexer/identifier.js";
3
2
  import { StringLiteral } from "../../lexer/literal.js";
4
3
  import { MultiLineStringToken } from "../../lexer/multiline.js";
4
+ import { InstructionsToken } from "../../lexer/tool.js";
5
5
 
6
6
  /**
7
7
  * @param {import('../base_parser.js').XanoBaseParser} $
@@ -14,7 +14,7 @@ export function flexibleStringClause($) {
14
14
  return (args) => {
15
15
  // During parser initialization, args is undefined
16
16
  // Use a placeholder token for grammar recording
17
- const token = args?.[0] || Identifier;
17
+ const token = args?.[0] || InstructionsToken;
18
18
  const allowEmpty = args?.[1] ?? true;
19
19
 
20
20
  $.sectionStack.push(token.name + "Clause");
@@ -20,46 +20,53 @@ export function nakedStackFn($) {
20
20
  $.CONSUME(LCurly); // "{"
21
21
  $.MANY(() => {
22
22
  $.AT_LEAST_ONE1(() => $.CONSUME1(NewlineToken)); // required new line before each clause
23
- $.OPTION(() => $.CONSUME(ExclamationToken)); // optional "!" to continue on error
23
+ // $.OPTION(() => $.CONSUME(ExclamationToken)); // optional "!" to continue on error
24
24
  $.OR([
25
25
  { ALT: () => $.CONSUME(CommentToken) },
26
- { ALT: () => $.SUBRULE($.aiFn) },
27
- { ALT: () => $.SUBRULE($.dbFn) },
28
- { ALT: () => $.SUBRULE($.varFn) },
29
- { ALT: () => $.SUBRULE($.arrayFn) },
30
- { ALT: () => $.SUBRULE($.cloudFn) },
31
- { ALT: () => $.SUBRULE($.securityFn) },
32
- { ALT: () => $.SUBRULE($.mathFn) },
33
- { ALT: () => $.SUBRULE($.textFn) },
34
- { ALT: () => $.SUBRULE($.utilFn) },
35
- { ALT: () => $.SUBRULE($.preconditionFn) },
36
- { ALT: () => $.SUBRULE($.zipFn) },
37
- { ALT: () => $.SUBRULE($.objectFn) },
38
- { ALT: () => $.SUBRULE($.apiFn, { ARGS: [options] }) },
39
- { ALT: () => $.SUBRULE($.webflowFn) },
40
- { ALT: () => $.SUBRULE($.redisFn) },
41
- { ALT: () => $.SUBRULE($.controlFn, { ARGS: [options] }) },
42
- { ALT: () => $.SUBRULE($.debugFn) },
43
- { ALT: () => $.SUBRULE($.storageFn) },
44
- { ALT: () => $.SUBRULE($.streamFn) },
45
- { ALT: () => $.SUBRULE($.actionCallFn) },
46
26
  {
47
- GATE: () => options.allowCallStatements,
48
- ALT: () => $.SUBRULE($.toolCallFn),
27
+ ALT: () => {
28
+ $.OPTION(() => $.CONSUME(ExclamationToken)); // optional "!" to continue on error
29
+ $.OR1([
30
+ { ALT: () => $.SUBRULE($.aiFn) },
31
+ { ALT: () => $.SUBRULE($.dbFn) },
32
+ { ALT: () => $.SUBRULE($.varFn) },
33
+ { ALT: () => $.SUBRULE($.arrayFn) },
34
+ { ALT: () => $.SUBRULE($.cloudFn) },
35
+ { ALT: () => $.SUBRULE($.securityFn) },
36
+ { ALT: () => $.SUBRULE($.mathFn) },
37
+ { ALT: () => $.SUBRULE($.textFn) },
38
+ { ALT: () => $.SUBRULE($.utilFn) },
39
+ { ALT: () => $.SUBRULE($.preconditionFn) },
40
+ { ALT: () => $.SUBRULE($.zipFn) },
41
+ { ALT: () => $.SUBRULE($.objectFn) },
42
+ { ALT: () => $.SUBRULE($.apiFn, { ARGS: [options] }) },
43
+ { ALT: () => $.SUBRULE($.webflowFn) },
44
+ { ALT: () => $.SUBRULE($.redisFn) },
45
+ { ALT: () => $.SUBRULE($.controlFn, { ARGS: [options] }) },
46
+ { ALT: () => $.SUBRULE($.debugFn) },
47
+ { ALT: () => $.SUBRULE($.storageFn) },
48
+ { ALT: () => $.SUBRULE($.streamFn) },
49
+ { ALT: () => $.SUBRULE($.actionCallFn) },
50
+ {
51
+ GATE: () => options.allowCallStatements,
52
+ ALT: () => $.SUBRULE($.toolCallFn),
53
+ },
54
+ {
55
+ GATE: () => options.allowCallStatements,
56
+ ALT: () => $.SUBRULE($.addonCallFn),
57
+ },
58
+ {
59
+ GATE: () => options.allowCallStatements,
60
+ ALT: () => $.SUBRULE($.middlewareCallFn),
61
+ },
62
+ {
63
+ GATE: () => options.allowCallStatements,
64
+ ALT: () => $.SUBRULE($.triggerCallFn),
65
+ },
66
+ { ALT: () => $.SUBRULE($.workflowExpectFn) },
67
+ ]);
68
+ },
49
69
  },
50
- {
51
- GATE: () => options.allowCallStatements,
52
- ALT: () => $.SUBRULE($.addonCallFn),
53
- },
54
- {
55
- GATE: () => options.allowCallStatements,
56
- ALT: () => $.SUBRULE($.middlewareCallFn),
57
- },
58
- {
59
- GATE: () => options.allowCallStatements,
60
- ALT: () => $.SUBRULE($.triggerCallFn),
61
- },
62
- { ALT: () => $.SUBRULE($.workflowExpectFn) },
63
70
  ]);
64
71
  });
65
72
  $.AT_LEAST_ONE2(() => $.CONSUME2(NewlineToken));
@@ -31,6 +31,16 @@ describe("nakedStack", () => {
31
31
  expect(parser.errors).to.be.empty;
32
32
  });
33
33
 
34
+ it("nakedStack accepts a disabled array statement", () => {
35
+ const parser = parse(`{
36
+ !array.push $my_array {
37
+ value = 1
38
+ }
39
+ }`);
40
+ console.log(parser.errors);
41
+ expect(parser.errors).to.be.empty;
42
+ });
43
+
34
44
  it("nakedStack accepts a multiline statement", () => {
35
45
  const parser = parse(`{
36
46
  var $some_var {
@@ -27,6 +27,11 @@ describe("responseClause", () => {
27
27
  expect(parser.errors).to.be.empty;
28
28
  });
29
29
 
30
+ it("responseClause accepts a string", () => {
31
+ const parser = parse(`response = "no exception"`);
32
+ expect(parser.errors).to.be.empty;
33
+ });
34
+
30
35
  it("responseClause accepts an object", () => {
31
36
  const parser = parse(`response = {result1: $x1, x2: $x2}`);
32
37
  expect(parser.errors).to.be.empty;
@@ -115,7 +115,11 @@ export function columnDefinition($) {
115
115
 
116
116
  // Track table reference from FK column definition
117
117
  if (captured.table?.value) {
118
- $.addReference("table", getVarName(captured.table.value), captured.table.value);
118
+ $.addReference(
119
+ "table",
120
+ getVarName(captured.table.value),
121
+ captured.table.value,
122
+ );
119
123
  }
120
124
 
121
125
  if (inputTypeToken.image == "vector" && !captured.size) {
@@ -126,7 +130,8 @@ export function columnDefinition($) {
126
130
  }
127
131
 
128
132
  const inTable = $.sectionStack.includes("tableDeclaration");
129
- if (captured.visibility && !inTable) {
133
+ const inIntput = $.sectionStack.includes("inputClause");
134
+ if (captured.visibility && !inTable && !inIntput) {
130
135
  $.addInvalidValueError(
131
136
  nameToken,
132
137
  'The "visibility" attribute is only valid within a table schema definition.',
@@ -25,7 +25,7 @@ export function arrayNoValueAs($) {
25
25
  $.CONSUME(RCurly);
26
26
  });
27
27
  $.CONSUME(AsToken);
28
- $.SUBRULE($.variableOnly);
28
+ $.SUBRULE($.assignableVariableAs);
29
29
  $.sectionStack.pop();
30
30
  };
31
31
  }
@@ -1,8 +1,6 @@
1
1
  import { PopToken } from "../../../lexer/arrays.js";
2
2
 
3
- // array.pop {
4
- // value = "test"
5
- // } as test
3
+ // array.pop $var as $unit
6
4
  /**
7
5
  * @param {import('../../base_parser.js').XanoBaseParser} $
8
6
  */
@@ -19,6 +19,14 @@ describe("forEachFn", () => {
19
19
  expect(parser.errors).to.be.empty;
20
20
  });
21
21
 
22
+ it("forEachFn should warn when using a reserved variable name", () => {
23
+ const parser = parse(`foreach ([]|push:1|push:2|push:3|push:4) {
24
+ each as $env
25
+ }`);
26
+ expect(parser.errors).to.be.empty;
27
+ expect(parser.warnings).to.not.be.empty;
28
+ });
29
+
22
30
  it("forEachFn can also be foreach.remove", () => {
23
31
  const parser = parse(`foreach.remove`);
24
32
  expect(parser.errors).to.be.empty;
@@ -1,4 +1,5 @@
1
1
  import { LParent, RParent } from "../../../lexer/control.js";
2
+ import { NewlineToken } from "../../../lexer/tokens.js";
2
3
  import { PreconditionToken } from "../../../lexer/util.js";
3
4
 
4
5
  /**
@@ -13,7 +14,9 @@ export function preconditionFn($) {
13
14
  $.sectionStack.push("preconditionFn");
14
15
  const tokenFn = $.CONSUME(PreconditionToken); // "precondition"
15
16
  $.CONSUME(LParent);
17
+ $.MANY(() => $.CONSUME(NewlineToken));
16
18
  $.SUBRULE($.expressionFn);
19
+ $.MANY1(() => $.CONSUME1(NewlineToken));
17
20
  $.CONSUME(RParent);
18
21
  $.SUBRULE($.schemaParseAttributeFn, {
19
22
  ARGS: [
@@ -14,6 +14,7 @@ export function dbExternalDirectQueryFn($) {
14
14
  {
15
15
  sql: "[expression]",
16
16
  response_type: ["list", "single"],
17
+ "parser?": "template_engine",
17
18
  connection_string: "[expression]",
18
19
  "description?": "[string]",
19
20
  "disabled?": "[boolean]",
@@ -346,4 +346,35 @@ describe("dbQueryFn", () => {
346
346
  const parser = parse(`query user as $user`);
347
347
  expect(parser.errors).to.be.empty;
348
348
  });
349
+
350
+ describe("aggregate eval with aggregator pipes", () => {
351
+ const aggregators = [
352
+ "avg",
353
+ "count",
354
+ "count_distinct",
355
+ "max",
356
+ "median",
357
+ "min",
358
+ "sum",
359
+ "to_distinct_list",
360
+ "to_distinct_list_asc",
361
+ "to_distinct_list_desc",
362
+ "to_list",
363
+ "to_list_asc",
364
+ "to_list_desc",
365
+ ];
366
+
367
+ for (const agg of aggregators) {
368
+ it(`dbQueryFn return eval accepts |${agg} aggregator`, () => {
369
+ const parser = parse(`query user {
370
+ return = {
371
+ type: "aggregate"
372
+ group: {user_name: $db.user.name}
373
+ eval: {result: $db.user.name|${agg}}
374
+ }
375
+ } as $user`);
376
+ expect(parser.errors).to.be.empty;
377
+ });
378
+ }
379
+ });
349
380
  });
@@ -1,4 +1,5 @@
1
1
  import { isArray, some } from "lodash-es";
2
+ import { Minus } from "../../../lexer/control.js";
2
3
  import {
3
4
  FloatLiteral,
4
5
  IntegerLiteral,
@@ -37,18 +38,18 @@ export function schemaParseConstantFn($) {
37
38
  return $.CONSUME(SingleQuotedStringLiteral); // e.g., 'field instructions'
38
39
  },
39
40
  },
41
+
40
42
  {
41
43
  ALT: () => {
44
+ $.OPTION(() => $.CONSUME(Minus));
42
45
  attributeCapturedType = "number";
43
- return $.CONSUME(IntegerLiteral); // e.g., 42
44
- },
45
- },
46
- {
47
- ALT: () => {
48
- attributeCapturedType = "number";
49
- return $.CONSUME(FloatLiteral); // e.g., 42.54
46
+ return $.OR1([
47
+ { ALT: () => $.CONSUME(IntegerLiteral) },
48
+ { ALT: () => $.CONSUME(FloatLiteral) },
49
+ ]);
50
50
  },
51
51
  },
52
+
52
53
  {
53
54
  ALT: () => {
54
55
  attributeCapturedType = "boolean";
@@ -76,7 +77,7 @@ export function schemaParseConstantFn($) {
76
77
  const isMatch = matchValueToSchema(
77
78
  attributeCapturedType,
78
79
  capturedValue.image,
79
- schema
80
+ schema,
80
81
  );
81
82
 
82
83
  if (!isMatch) {
@@ -92,7 +93,7 @@ function matchValueToSchema(attributeCapturedType, value, schema) {
92
93
  // schema can be an array of type/values required
93
94
  if (isArray(schema)) {
94
95
  return some(schema, (s) =>
95
- matchValueToSchema(attributeCapturedType, value, s)
96
+ matchValueToSchema(attributeCapturedType, value, s),
96
97
  );
97
98
  }
98
99
 
@@ -115,7 +116,7 @@ function matchValueToSchema(attributeCapturedType, value, schema) {
115
116
  return schemaValue === null;
116
117
  default:
117
118
  throw new Error(
118
- `schemaParseConstantFn called with non-constant attribute: ${schema}`
119
+ `schemaParseConstantFn called with non-constant attribute: ${schema}`,
119
120
  );
120
121
  }
121
122
  }
@@ -2,9 +2,14 @@ import { DotToken } from "../../lexer/tokens.js";
2
2
  import { UpdateToken, VarToken } from "../../lexer/var.js";
3
3
  import {
4
4
  ApiBaseUrlVariable,
5
+ AuthVariable,
5
6
  BranchVariable,
6
7
  DatasourceVariable,
8
+ EnvVariable,
9
+ ErrorVariable,
7
10
  HttpHeadersVariable,
11
+ InputVariable,
12
+ LongFormVariable,
8
13
  RemoteHostVariable,
9
14
  RemoteIpVariable,
10
15
  RemotePasswordVariable,
@@ -53,16 +58,23 @@ export function varFn($) {
53
58
  { ALT: () => $.CONSUME(RequestUriVariable) },
54
59
  { ALT: () => $.CONSUME(TenantVariable) },
55
60
  { ALT: () => $.CONSUME(WebflowVariable) },
61
+ // Not recommended but still valid
62
+ { ALT: () => $.CONSUME(LongFormVariable) },
63
+ { ALT: () => $.CONSUME(EnvVariable) },
64
+ { ALT: () => $.CONSUME(AuthVariable) },
65
+ { ALT: () => $.CONSUME(InputVariable) },
66
+ { ALT: () => $.CONSUME(ErrorVariable) },
56
67
  ]);
68
+
57
69
  if (variable.image) {
58
70
  // Check for blacklisted variable names
59
71
  const nameWithoutPrefix = variable.image.startsWith("$")
60
72
  ? variable.image.slice(1)
61
73
  : variable.image;
62
74
  if (isBlacklistedVariableName(nameWithoutPrefix)) {
63
- $.addInvalidValueError(
64
- variable,
75
+ $.addWarning(
65
76
  `'${variable.image}' is a reserved variable name and should not be used as a variable.`,
77
+ variable,
66
78
  );
67
79
  }
68
80
  // we can directly add the variable here but
@@ -225,16 +225,18 @@ describe("varFn", () => {
225
225
  const parser = parse(`var $${name} {
226
226
  value = "test"
227
227
  }`);
228
- expect(parser.errors).to.not.be.empty;
229
- expect(parser.errors[0].message).to.include("reserved");
228
+ expect(parser.errors).to.be.empty;
229
+ expect(parser.warnings).to.not.be.empty;
230
+ expect(parser.warnings[0].message).to.include("reserved");
230
231
  });
231
232
 
232
233
  it(`rejects var.update $${name} as variable name (short form)`, () => {
233
234
  const parser = parse(`var.update $${name} {
234
235
  value = "test"
235
236
  }`);
236
- expect(parser.errors).to.not.be.empty;
237
- expect(parser.errors[0].message).to.include("reserved");
237
+ expect(parser.errors).to.be.empty;
238
+ expect(parser.warnings).to.not.be.empty;
239
+ expect(parser.warnings[0].message).to.include("reserved");
238
240
  });
239
241
  }
240
242
 
@@ -249,30 +251,35 @@ describe("varFn", () => {
249
251
  ];
250
252
 
251
253
  for (const name of separateTokenBlacklisted) {
252
- it(`rejects var $${name} as variable name (separate token)`, () => {
254
+ it(`warns var $${name} as variable name (separate token)`, () => {
253
255
  const parser = parse(`var $${name} {
254
256
  value = "test"
255
257
  }`);
256
258
  if (parser.errors.length === 0) {
257
259
  console.log(parser.errors, name);
258
260
  }
259
- expect(parser.errors).to.not.be.empty;
261
+ expect(parser.errors).to.be.empty;
262
+ expect(parser.warnings).to.not.be.empty;
263
+ expect(parser.warnings[0].message).to.include("reserved");
260
264
  });
261
265
 
262
- it(`rejects var.update $${name} as variable name (separate token)`, () => {
266
+ it(`warns var.update $${name} as variable name (separate token)`, () => {
263
267
  const parser = parse(`var.update $${name} {
264
268
  value = "test"
265
269
  }`);
266
- expect(parser.errors).to.not.be.empty;
270
+ expect(parser.errors).to.be.empty;
271
+ expect(parser.warnings).to.not.be.empty;
272
+ expect(parser.warnings[0].message).to.include("reserved");
267
273
  });
268
274
  }
269
275
 
270
276
  // $var is the LongFormVariable prefix, parser expects a dot after it
271
- it("rejects var $var as variable name (long form prefix)", () => {
277
+ it("warns var $var as variable name (long form prefix)", () => {
272
278
  const parser = parse(`var $var {
273
279
  value = "test"
274
280
  }`);
275
- expect(parser.errors).to.not.be.empty;
281
+ expect(parser.warnings).to.not.be.empty;
282
+ expect(parser.errors).to.be.empty;
276
283
  });
277
284
 
278
285
  it("accepts a backtick expression as value", () => {
@@ -301,8 +308,9 @@ describe("varFn", () => {
301
308
  const parser = parse(`var.update $var.${name} {
302
309
  value = "test"
303
310
  }`);
304
- expect(parser.errors).to.not.be.empty;
305
- expect(parser.errors[0].message).to.include("reserved");
311
+ expect(parser.errors).to.be.empty;
312
+ expect(parser.warnings).to.not.be.empty;
313
+ expect(parser.warnings[0].message).to.include("reserved");
306
314
  });
307
315
  }
308
316