@xano/xanoscript-language-server 11.8.1 → 11.8.3
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/lexer/table.js +13 -1
- package/package.json +1 -1
- package/parser/attributes/register.js +13 -14
- package/parser/attributes/visibilityFieldAttribute.js +17 -0
- package/parser/attributes/visibilityFieldAttribute.spec.js +44 -0
- package/parser/clauses/schemaClause.spec.js +38 -2
- package/parser/definitions/columnDefinition.js +11 -2
- package/parser/functions/db/dbQueryFn.spec.js +9 -0
- package/parser/functions/redis/redisPopFn.js +1 -0
- package/parser/functions/redis/redisPopFn.spec.js +8 -0
- package/parser/functions/redis/redisShiftFn.js +1 -0
- package/parser/functions/redis/redisShiftFn.spec.js +8 -0
- package/parser/functions/workflowExpectFn.spec.js +0 -1
- package/parser/generic/expressionFn.js +1 -0
- package/parser/generic/expressionFn.spec.js +7 -0
- package/parser/metadata/enumColumnMetadataDefinition.js +17 -30
- package/parser/metadata/enumColumnMetadataDefinition.spec.js +23 -1
- package/parser/metadata/objectColumnMetadataDefinition.js +41 -4
- package/parser/table_parser.spec.js +18 -0
- package/parser/tests/table/valid_sources/rich_columns.xs +4 -1
- package/parser/workflow_test_parser.spec.js +0 -1
package/lexer/table.js
CHANGED
|
@@ -19,7 +19,18 @@ export const ItemsToken = createTokenByName("items", {
|
|
|
19
19
|
categories: [Identifier],
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
// "visibility"
|
|
23
|
+
export const VisibilityToken = createTokenByName("visibility", {
|
|
24
|
+
longer_alt: Identifier,
|
|
25
|
+
categories: [Identifier],
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const TableTokens = [
|
|
29
|
+
TableToken,
|
|
30
|
+
AutoCompleteToken,
|
|
31
|
+
ItemsToken,
|
|
32
|
+
VisibilityToken,
|
|
33
|
+
];
|
|
23
34
|
|
|
24
35
|
/**
|
|
25
36
|
* Maps a token name to a type
|
|
@@ -31,6 +42,7 @@ export function mapTokenToType(token) {
|
|
|
31
42
|
return "keyword";
|
|
32
43
|
case AutoCompleteToken.name:
|
|
33
44
|
case ItemsToken.name:
|
|
45
|
+
case VisibilityToken.name:
|
|
34
46
|
return "identifier";
|
|
35
47
|
default:
|
|
36
48
|
return null;
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { columnDefaultValueAttribute } from "./columnDefaultValueAttribute.js";
|
|
2
2
|
import { descriptionFieldAttribute } from "./descriptionFieldAttribute.js";
|
|
3
3
|
import { disabledFieldAttribute } from "./disabledFieldAttribute.js";
|
|
4
|
-
import { docsFieldAttribute } from "./docsFieldAttribute.js"
|
|
4
|
+
import { docsFieldAttribute } from "./docsFieldAttribute.js";
|
|
5
5
|
import { guidFieldAttribute } from "./guidFieldAttribute.js";
|
|
6
6
|
import { inputFilterFn } from "./inputFilterFn.js";
|
|
7
7
|
import { sensitiveFieldAttribute } from "./sensitiveFieldAttribute.js";
|
|
8
8
|
import { valueFieldAttribute } from "./valueFieldAttribute.js";
|
|
9
9
|
import { valuesFieldAttribute } from "./valuesFieldAttribute.js";
|
|
10
|
+
import { visibilityFieldAttribute } from "./visibilityFieldAttribute.js";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Registers all the parsers in this folder
|
|
@@ -15,32 +16,30 @@ import { valuesFieldAttribute } from "./valuesFieldAttribute.js";
|
|
|
15
16
|
export const register = ($) => {
|
|
16
17
|
$.columnDefaultValueAttribute = $.RULE(
|
|
17
18
|
"columnDefaultValueAttribute",
|
|
18
|
-
columnDefaultValueAttribute($)
|
|
19
|
+
columnDefaultValueAttribute($),
|
|
19
20
|
);
|
|
20
21
|
$.descriptionFieldAttribute = $.RULE(
|
|
21
22
|
"descriptionFieldAttribute",
|
|
22
|
-
descriptionFieldAttribute($)
|
|
23
|
+
descriptionFieldAttribute($),
|
|
23
24
|
);
|
|
24
25
|
$.disabledFieldAttribute = $.RULE(
|
|
25
26
|
"disabledFieldAttribute",
|
|
26
|
-
disabledFieldAttribute($)
|
|
27
|
-
);
|
|
28
|
-
$.docsFieldAttribute = $.RULE(
|
|
29
|
-
"docsFieldAttribute",
|
|
30
|
-
docsFieldAttribute($)
|
|
31
|
-
);
|
|
32
|
-
$.guidFieldAttribute = $.RULE(
|
|
33
|
-
"guidFieldAttribute",
|
|
34
|
-
guidFieldAttribute($)
|
|
27
|
+
disabledFieldAttribute($),
|
|
35
28
|
);
|
|
29
|
+
$.docsFieldAttribute = $.RULE("docsFieldAttribute", docsFieldAttribute($));
|
|
30
|
+
$.guidFieldAttribute = $.RULE("guidFieldAttribute", guidFieldAttribute($));
|
|
36
31
|
$.inputFilterFn = $.RULE("inputFilterFn", inputFilterFn($));
|
|
37
32
|
$.sensitiveFieldAttribute = $.RULE(
|
|
38
33
|
"sensitiveFieldAttribute",
|
|
39
|
-
sensitiveFieldAttribute($)
|
|
34
|
+
sensitiveFieldAttribute($),
|
|
40
35
|
);
|
|
41
36
|
$.valueFieldAttribute = $.RULE("valueFieldAttribute", valueFieldAttribute($));
|
|
42
37
|
$.valuesFieldAttribute = $.RULE(
|
|
43
38
|
"valuesFieldAttribute",
|
|
44
|
-
valuesFieldAttribute($)
|
|
39
|
+
valuesFieldAttribute($),
|
|
40
|
+
);
|
|
41
|
+
$.visibilityFieldAttribute = $.RULE(
|
|
42
|
+
"visibilityFieldAttribute",
|
|
43
|
+
visibilityFieldAttribute($),
|
|
45
44
|
);
|
|
46
45
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { EqualToken } from "../../lexer/control.js";
|
|
2
|
+
import { VisibilityToken } from "../../lexer/table.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Visibility Field Attribute Parser on table metadata definitions
|
|
6
|
+
* @param {import('../base_parser.js').XanoBaseParser} $
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export const visibilityFieldAttribute = ($) => () => {
|
|
10
|
+
$.sectionStack.push("visibilityFieldAttribute");
|
|
11
|
+
const parent = $.CONSUME(VisibilityToken); // "visibility"
|
|
12
|
+
$.CONSUME(EqualToken); // "="
|
|
13
|
+
$.SUBRULE($.schemaParseEnumFn, {
|
|
14
|
+
ARGS: [parent, ["private", "internal", "public"]],
|
|
15
|
+
});
|
|
16
|
+
$.sectionStack.pop();
|
|
17
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
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) {
|
|
7
|
+
parser.reset();
|
|
8
|
+
const lexResult = lexDocument(inputText);
|
|
9
|
+
parser.input = lexResult.tokens;
|
|
10
|
+
parser.visibilityFieldAttribute();
|
|
11
|
+
return parser;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
describe("visibilityFieldAttribute", () => {
|
|
15
|
+
it("visibilityFieldAttribute accepts a private value", () => {
|
|
16
|
+
const parser = parse(`visibility = "private"`);
|
|
17
|
+
expect(parser.errors).to.be.empty;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("visibilityFieldAttribute accepts an internal value", () => {
|
|
21
|
+
const parser = parse(`visibility = "internal"`);
|
|
22
|
+
expect(parser.errors).to.be.empty;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("visibilityFieldAttribute accepts a public value", () => {
|
|
26
|
+
const parser = parse(`visibility = "public"`);
|
|
27
|
+
expect(parser.errors).to.be.empty;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("visibilityFieldAttribute rejects anything else", () => {
|
|
31
|
+
const parser = parse(`visibility = "something"`);
|
|
32
|
+
expect(parser.errors).to.not.be.empty;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("visibilityFieldAttribute rejects digit", () => {
|
|
36
|
+
const parser = parse("visibility = 123");
|
|
37
|
+
expect(parser.errors).to.not.be.empty;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("visibilityFieldAttribute can be compact", () => {
|
|
41
|
+
const parser = parse(`visibility="private"`);
|
|
42
|
+
expect(parser.errors).to.be.empty;
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -3,10 +3,19 @@ import { describe, it } from "mocha";
|
|
|
3
3
|
import { lexDocument } from "../../lexer/lexer.js";
|
|
4
4
|
import { parser } from "../test_parser.js";
|
|
5
5
|
|
|
6
|
-
function parse(inputText) {
|
|
6
|
+
function parse(inputText, context = null) {
|
|
7
|
+
parser.reset();
|
|
7
8
|
const lexResult = lexDocument(inputText);
|
|
8
9
|
parser.input = lexResult.tokens;
|
|
9
|
-
|
|
10
|
+
|
|
11
|
+
if (context) {
|
|
12
|
+
parser.sectionStack.push(context);
|
|
13
|
+
parser.schemaClause();
|
|
14
|
+
parser.sectionStack.pop();
|
|
15
|
+
} else {
|
|
16
|
+
parser.schemaClause();
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
return parser;
|
|
11
20
|
}
|
|
12
21
|
|
|
@@ -39,6 +48,33 @@ describe("schemaClause", () => {
|
|
|
39
48
|
expect(parser.errors).to.be.empty;
|
|
40
49
|
});
|
|
41
50
|
|
|
51
|
+
it("schemaClause accepts a visibility when in a table definition", () => {
|
|
52
|
+
const parser = parse(
|
|
53
|
+
`schema {
|
|
54
|
+
int rank {
|
|
55
|
+
visibility = "private"
|
|
56
|
+
}
|
|
57
|
+
text label {
|
|
58
|
+
visibility = "internal"
|
|
59
|
+
}
|
|
60
|
+
}`,
|
|
61
|
+
"tableDeclaration",
|
|
62
|
+
);
|
|
63
|
+
expect(parser.errors).to.be.empty;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("schemaClause rejects a visibility when not in a table definition", () => {
|
|
67
|
+
const parser = parse(`schema {
|
|
68
|
+
int rank {
|
|
69
|
+
visibility = "private"
|
|
70
|
+
}
|
|
71
|
+
text label {
|
|
72
|
+
visibility = "internal"
|
|
73
|
+
}
|
|
74
|
+
}`);
|
|
75
|
+
expect(parser.errors).to.not.be.empty;
|
|
76
|
+
});
|
|
77
|
+
|
|
42
78
|
it("schemaClause accepts a description", () => {
|
|
43
79
|
const parser = parse(`schema {
|
|
44
80
|
text label {
|
|
@@ -107,6 +107,7 @@ export function columnDefinition($) {
|
|
|
107
107
|
"table?": "[string]",
|
|
108
108
|
"size?": "[number]",
|
|
109
109
|
"sensitive?": "[boolean]",
|
|
110
|
+
"visibility?": ["public", "private", "internal"],
|
|
110
111
|
},
|
|
111
112
|
captured,
|
|
112
113
|
],
|
|
@@ -115,7 +116,15 @@ export function columnDefinition($) {
|
|
|
115
116
|
if (inputTypeToken.image == "vector" && !captured.size) {
|
|
116
117
|
$.addWarning(
|
|
117
118
|
'Column named "vector" should have a size attribute defining its length.',
|
|
118
|
-
nameToken
|
|
119
|
+
nameToken,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const inTable = $.sectionStack.includes("tableDeclaration");
|
|
124
|
+
if (captured.visibility && !inTable) {
|
|
125
|
+
$.addInvalidValueError(
|
|
126
|
+
nameToken,
|
|
127
|
+
'The "visibility" attribute is only valid within a table schema definition.',
|
|
119
128
|
);
|
|
120
129
|
}
|
|
121
130
|
|
|
@@ -131,7 +140,7 @@ export function columnDefinition($) {
|
|
|
131
140
|
inputTypeToken.image,
|
|
132
141
|
iterable,
|
|
133
142
|
nullable,
|
|
134
|
-
optional
|
|
143
|
+
optional,
|
|
135
144
|
);
|
|
136
145
|
|
|
137
146
|
$.sectionStack.pop();
|
|
@@ -34,6 +34,15 @@ describe("dbQueryFn", () => {
|
|
|
34
34
|
expect(parser.errors).to.be.empty;
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
+
it("dbQueryFn where can split line on binary operators", () => {
|
|
38
|
+
const parser = parse(`query user {
|
|
39
|
+
where = $db.user.visa_work_permit_end_date != null &&
|
|
40
|
+
$db.user.visa_work_permit_end_date <= $input.next_120_days && $db.bug_test_candidate.candidate_status == "mediated" && ($db.user.billing_end_date > now || $db.user.billing_end_date == null)
|
|
41
|
+
return = {type: "list"}
|
|
42
|
+
} as $results`);
|
|
43
|
+
expect(parser.errors).to.be.empty;
|
|
44
|
+
});
|
|
45
|
+
|
|
37
46
|
it("dbQueryFn accepts a description", () => {
|
|
38
47
|
const parser = parse(`query user {
|
|
39
48
|
where = $db.array_columns @> $db.array_columns.id
|
|
@@ -64,4 +64,12 @@ describe("redis.pop", () => {
|
|
|
64
64
|
} as $x7`);
|
|
65
65
|
expect(parser.errors).to.be.empty;
|
|
66
66
|
});
|
|
67
|
+
|
|
68
|
+
it("pop accepts an optional count attribute", () => {
|
|
69
|
+
const parser = parse(`pop {
|
|
70
|
+
key = "list"
|
|
71
|
+
count = 5
|
|
72
|
+
} as $x7`);
|
|
73
|
+
expect(parser.errors).to.be.empty;
|
|
74
|
+
});
|
|
67
75
|
});
|
|
@@ -64,4 +64,12 @@ describe("redis.shift", () => {
|
|
|
64
64
|
} as $x8`);
|
|
65
65
|
expect(parser.errors).to.be.empty;
|
|
66
66
|
});
|
|
67
|
+
|
|
68
|
+
it("shift accepts an optional count attribute", () => {
|
|
69
|
+
const parser = parse(`shift {
|
|
70
|
+
key = "list"
|
|
71
|
+
count = 5
|
|
72
|
+
} as $x8`);
|
|
73
|
+
expect(parser.errors).to.be.empty;
|
|
74
|
+
});
|
|
67
75
|
});
|
|
@@ -107,6 +107,13 @@ describe("expressionFn", () => {
|
|
|
107
107
|
expect(parser.errors).to.be.empty;
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
it("expressionFn can split on multiple lines on binary operators", () => {
|
|
111
|
+
let parser = parse(`$var.value == "test" &&
|
|
112
|
+
$var.other_value != "example" ||
|
|
113
|
+
$var.another_value > 10`);
|
|
114
|
+
expect(parser.errors).to.be.empty;
|
|
115
|
+
});
|
|
116
|
+
|
|
110
117
|
it("expressionFn accepts modulus symbol in expression", () => {
|
|
111
118
|
const parser = parse("$this % 2 == 1");
|
|
112
119
|
expect(parser.errors).to.be.empty;
|
|
@@ -1,46 +1,33 @@
|
|
|
1
|
-
import { LCurly, RCurly } from "../../lexer/control.js";
|
|
2
|
-
import { NewlineToken } from "../../lexer/tokens.js";
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
*
|
|
6
3
|
* @param {import('../base_parser.js').XanoBaseParser} $
|
|
7
4
|
*/
|
|
8
5
|
export function enumColumnMetadataDefinition($) {
|
|
9
|
-
return (parent) => {
|
|
6
|
+
return (parent, captured = {}) => {
|
|
10
7
|
$.sectionStack.push("enumColumnMetadataDefinition");
|
|
11
|
-
$.CONSUME(LCurly); // "{"
|
|
12
|
-
// values = [...] is a required field here
|
|
13
|
-
let hasValues = false;
|
|
14
|
-
let hasDescription = false;
|
|
15
|
-
let hasSensitive = false;
|
|
16
8
|
|
|
17
|
-
$.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
GATE: () => !hasValues,
|
|
22
|
-
ALT: () => {
|
|
23
|
-
hasValues = true;
|
|
24
|
-
$.SUBRULE($.valuesFieldAttribute);
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
GATE: () => !hasDescription,
|
|
29
|
-
ALT: () => $.SUBRULE($.sensitiveFieldAttribute),
|
|
30
|
-
},
|
|
9
|
+
$.SUBRULE($.schemaParseAttributeFn, {
|
|
10
|
+
ARGS: [
|
|
11
|
+
parent,
|
|
31
12
|
{
|
|
32
|
-
|
|
33
|
-
|
|
13
|
+
"description?": "[string]",
|
|
14
|
+
values: ["[string]"],
|
|
15
|
+
"sensitive?": "[boolean]",
|
|
16
|
+
"visibility?": ["public", "private", "internal"],
|
|
34
17
|
},
|
|
35
|
-
|
|
18
|
+
captured,
|
|
19
|
+
],
|
|
36
20
|
});
|
|
37
21
|
|
|
38
|
-
if
|
|
39
|
-
|
|
22
|
+
// you can only provide a visibility attribute if you're in a table definition
|
|
23
|
+
const inTable = $.sectionStack.includes("tableDeclaration");
|
|
24
|
+
if (!inTable && "visibility" in captured) {
|
|
25
|
+
$.addInvalidValueError(
|
|
26
|
+
parent,
|
|
27
|
+
'The "visibility" attribute is only valid within a table schema definition.',
|
|
28
|
+
);
|
|
40
29
|
}
|
|
41
30
|
|
|
42
|
-
$.AT_LEAST_ONE2(() => $.CONSUME2(NewlineToken)); // Require at least one new line after
|
|
43
|
-
$.CONSUME(RCurly); // "}"
|
|
44
31
|
$.sectionStack.pop();
|
|
45
32
|
};
|
|
46
33
|
}
|
|
@@ -3,9 +3,12 @@ import { describe, it } from "mocha";
|
|
|
3
3
|
import { lexDocument } from "../../lexer/lexer.js";
|
|
4
4
|
import { parser } from "../test_parser.js";
|
|
5
5
|
|
|
6
|
-
function parse(inputText) {
|
|
6
|
+
function parse(inputText, context = null) {
|
|
7
7
|
const lexResult = lexDocument(inputText);
|
|
8
8
|
parser.input = lexResult.tokens;
|
|
9
|
+
if (context) {
|
|
10
|
+
parser.sectionStack.push(context);
|
|
11
|
+
}
|
|
9
12
|
parser.enumColumnMetadataDefinition();
|
|
10
13
|
return parser;
|
|
11
14
|
}
|
|
@@ -27,6 +30,25 @@ describe("enumColumnMetadataDefinition", () => {
|
|
|
27
30
|
expect(parser.errors).to.be.empty;
|
|
28
31
|
});
|
|
29
32
|
|
|
33
|
+
it("enumColumnMetadataDefinition accepts a visibility value when in a table declaration", () => {
|
|
34
|
+
const parser = parse(
|
|
35
|
+
`{
|
|
36
|
+
values = ["active", "inactive", "unknown"]
|
|
37
|
+
visibility = "private"
|
|
38
|
+
}`,
|
|
39
|
+
"tableDeclaration",
|
|
40
|
+
);
|
|
41
|
+
expect(parser.errors).to.be.empty;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("enumColumnMetadataDefinition rejects a visibility value when not in a table declaration", () => {
|
|
45
|
+
const parser = parse(`{
|
|
46
|
+
values = ["active", "inactive", "unknown"]
|
|
47
|
+
visibility = "private"
|
|
48
|
+
}`);
|
|
49
|
+
expect(parser.errors).to.not.be.empty;
|
|
50
|
+
});
|
|
51
|
+
|
|
30
52
|
it("enumColumnMetadataDefinition accepts a description value", () => {
|
|
31
53
|
const parser = parse(`{
|
|
32
54
|
values = ["active", "inactive", "unknown"]
|
|
@@ -7,20 +7,57 @@ import { NewlineToken } from "../../lexer/tokens.js";
|
|
|
7
7
|
export function objectColumnMetadataDefinition($) {
|
|
8
8
|
return () => {
|
|
9
9
|
$.sectionStack.push("objectColumnMetadataDefinition");
|
|
10
|
+
|
|
11
|
+
let hasSensitiveField = false;
|
|
12
|
+
let hasVisibilityField = false;
|
|
13
|
+
let hasDescriptionField = false;
|
|
14
|
+
let hasSchemaClause = false;
|
|
15
|
+
|
|
10
16
|
$.CONSUME(LCurly); // "{"
|
|
11
17
|
$.MANY(() => {
|
|
12
18
|
$.AT_LEAST_ONE(() => $.CONSUME(NewlineToken)); // Require at least one new line after {
|
|
13
19
|
$.OR([
|
|
14
|
-
{ ALT: () => $.SUBRULE($.sensitiveFieldAttribute) },
|
|
15
|
-
{ ALT: () => $.SUBRULE($.descriptionFieldAttribute) },
|
|
16
20
|
{
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
GATE: () => !hasSensitiveField, // Only allow the sensitive attribute if it hasn't been used yet
|
|
22
|
+
ALT: () => {
|
|
23
|
+
$.SUBRULE($.sensitiveFieldAttribute);
|
|
24
|
+
hasSensitiveField = true;
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
GATE: () => !hasDescriptionField, // Only allow the description attribute if it hasn't been used yet
|
|
29
|
+
ALT: () => {
|
|
30
|
+
$.SUBRULE($.descriptionFieldAttribute);
|
|
31
|
+
hasDescriptionField = true;
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
GATE: () => !hasVisibilityField, // Only allow the visibility attribute if it hasn't been used yet
|
|
36
|
+
ALT: () => {
|
|
37
|
+
$.SUBRULE($.visibilityFieldAttribute);
|
|
38
|
+
hasVisibilityField = true;
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
GATE: () => !hasSchemaClause, // Only allow the schema clause if it hasn't been used yet
|
|
43
|
+
ALT: () => {
|
|
44
|
+
$.SUBRULE($.schemaClause, { ARGS: [{ include_file: false }] });
|
|
45
|
+
hasSchemaClause = true;
|
|
46
|
+
},
|
|
19
47
|
},
|
|
20
48
|
]);
|
|
21
49
|
});
|
|
22
50
|
$.AT_LEAST_ONE1(() => $.CONSUME1(NewlineToken)); // Require at least one new line after {
|
|
23
51
|
$.CONSUME(RCurly); // "}"
|
|
52
|
+
|
|
53
|
+
const inTable = $.sectionStack.includes("tableDeclaration");
|
|
54
|
+
if (hasVisibilityField && !inTable) {
|
|
55
|
+
$.addInvalidValueError(
|
|
56
|
+
null,
|
|
57
|
+
'The "visibility" attribute is only valid within a table schema definition.',
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
24
61
|
$.sectionStack.pop();
|
|
25
62
|
};
|
|
26
63
|
}
|
|
@@ -69,6 +69,24 @@ describe("table_parser", () => {
|
|
|
69
69
|
expect(parser.errors).to.be.empty;
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
+
it("should should accept a private and internal visibility on input", () => {
|
|
73
|
+
const parser = xanoscriptParser(`table foo {
|
|
74
|
+
auth = false
|
|
75
|
+
|
|
76
|
+
schema {
|
|
77
|
+
int id {
|
|
78
|
+
visibility = "private"
|
|
79
|
+
}
|
|
80
|
+
text cd {
|
|
81
|
+
visibility = "internal"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
autocomplete = [{ name: "id" }, { name: "cd" }]
|
|
86
|
+
}`);
|
|
87
|
+
expect(parser.errors).to.be.empty;
|
|
88
|
+
});
|
|
89
|
+
|
|
72
90
|
// autocomplete = [{ name: "id" }, { name: "cd" }];
|
|
73
91
|
it("should requires a new line between statements", () => {
|
|
74
92
|
const parser = xanoscriptParser(`table foo {
|
|
@@ -3,11 +3,14 @@ table array_columns {
|
|
|
3
3
|
|
|
4
4
|
schema {
|
|
5
5
|
int id
|
|
6
|
-
timestamp created_at?=now
|
|
6
|
+
timestamp created_at?=now {
|
|
7
|
+
visibility = "internal"
|
|
8
|
+
}
|
|
7
9
|
text[] many_text? filters=trim
|
|
8
10
|
email[] many_email_required_sensitive filters=trim|lower {
|
|
9
11
|
description = "with a description"
|
|
10
12
|
sensitive = true
|
|
13
|
+
visibility = "private"
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
enum[] many_enum_required_private {
|