@xdbml/parse 0.3.0 → 0.3.2
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/dist/parser.d.ts +11 -0
- package/dist/parser.js +51 -5
- package/package.json +1 -1
package/dist/parser.d.ts
CHANGED
|
@@ -216,9 +216,20 @@ export declare class Parser {
|
|
|
216
216
|
* otherwise the first thing is the bare type.
|
|
217
217
|
*/
|
|
218
218
|
private parseArrayType;
|
|
219
|
+
/** array/set sugar: fold a following comma-list of union-eligible members
|
|
220
|
+
* (`[T1, T2, ...]`) into a UnionType. Applies only when the element is a
|
|
221
|
+
* scalar/named type with no per-member settings; `null` is allowed as a
|
|
222
|
+
* later member. Object shapes use `oneOf`, positional layouts use a tuple. */
|
|
223
|
+
private maybeFoldUnionSugar;
|
|
224
|
+
/** A type usable as a `union` member (and thus foldable from array sugar).
|
|
225
|
+
* `null` is only ever a later member (parsed via parseUnionMember), never
|
|
226
|
+
* the first standalone element type, so it is not listed here. */
|
|
227
|
+
private isUnionMemberType;
|
|
219
228
|
/** True if the token looks like the start of a TypeExpression. */
|
|
220
229
|
private tokenStartsType;
|
|
221
230
|
private parseTupleElements;
|
|
231
|
+
/** Lookahead for a tuple position marker `[ <number> ]` (vs. a settings block). */
|
|
232
|
+
private positionMarkerAhead;
|
|
222
233
|
private parseMapType;
|
|
223
234
|
private parseSetType;
|
|
224
235
|
/**
|
package/dist/parser.js
CHANGED
|
@@ -1020,8 +1020,11 @@ export class Parser {
|
|
|
1020
1020
|
&& this.tokenStartsType(second)) {
|
|
1021
1021
|
elementName = this.advance().text;
|
|
1022
1022
|
}
|
|
1023
|
-
const
|
|
1023
|
+
const elemStart = this.peek().start;
|
|
1024
|
+
let elementType = this.parseTypeExpression();
|
|
1024
1025
|
const elementSettings = this.maybeSettingsBlock();
|
|
1026
|
+
// Sugar: `array [T1, T2, ...]` == `array [union [T1, T2, ...]]` (see helper).
|
|
1027
|
+
elementType = this.maybeFoldUnionSugar(elementType, elemStart, elementSettings.length === 0);
|
|
1025
1028
|
this.expect(TokenKind.RBracket, "Expected ']' closing array");
|
|
1026
1029
|
return {
|
|
1027
1030
|
kind: 'ArrayType',
|
|
@@ -1032,6 +1035,33 @@ export class Parser {
|
|
|
1032
1035
|
span: this.spanFrom(start),
|
|
1033
1036
|
};
|
|
1034
1037
|
}
|
|
1038
|
+
/** array/set sugar: fold a following comma-list of union-eligible members
|
|
1039
|
+
* (`[T1, T2, ...]`) into a UnionType. Applies only when the element is a
|
|
1040
|
+
* scalar/named type with no per-member settings; `null` is allowed as a
|
|
1041
|
+
* later member. Object shapes use `oneOf`, positional layouts use a tuple. */
|
|
1042
|
+
maybeFoldUnionSugar(elementType, elemStart, noElementSettings) {
|
|
1043
|
+
if (noElementSettings
|
|
1044
|
+
&& this.check(TokenKind.Comma)
|
|
1045
|
+
&& this.isUnionMemberType(elementType)) {
|
|
1046
|
+
const members = [elementType];
|
|
1047
|
+
while (this.match(TokenKind.Comma)) {
|
|
1048
|
+
members.push(this.parseUnionMember());
|
|
1049
|
+
}
|
|
1050
|
+
return {
|
|
1051
|
+
kind: 'UnionType',
|
|
1052
|
+
members,
|
|
1053
|
+
span: this.spanFrom(elemStart),
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
return elementType;
|
|
1057
|
+
}
|
|
1058
|
+
/** A type usable as a `union` member (and thus foldable from array sugar).
|
|
1059
|
+
* `null` is only ever a later member (parsed via parseUnionMember), never
|
|
1060
|
+
* the first standalone element type, so it is not listed here. */
|
|
1061
|
+
isUnionMemberType(t) {
|
|
1062
|
+
return t.kind === 'ScalarType'
|
|
1063
|
+
|| t.kind === 'NamedTypeReference';
|
|
1064
|
+
}
|
|
1035
1065
|
/** True if the token looks like the start of a TypeExpression. */
|
|
1036
1066
|
tokenStartsType(t) {
|
|
1037
1067
|
if (t.kind === TokenKind.LBrace)
|
|
@@ -1049,7 +1079,11 @@ export class Parser {
|
|
|
1049
1079
|
this.expect(TokenKind.RBracket, "Expected ']' after position");
|
|
1050
1080
|
const nameTok = this.expect(TokenKind.Identifier, 'Expected tuple element name');
|
|
1051
1081
|
const type = this.parseTypeExpression();
|
|
1052
|
-
|
|
1082
|
+
// Optional per-element settings. A following `[` only opens a settings
|
|
1083
|
+
// block if it is NOT the next element's `[N]` position marker; otherwise
|
|
1084
|
+
// maybeSettingsBlock would greedily consume it and fail on the number
|
|
1085
|
+
// (grammar: tupleElement's settingsBlock is optional).
|
|
1086
|
+
const settings = this.positionMarkerAhead() ? [] : this.maybeSettingsBlock();
|
|
1053
1087
|
out.push({
|
|
1054
1088
|
kind: 'TupleElement',
|
|
1055
1089
|
position: parseInt(numTok.text, 10),
|
|
@@ -1058,11 +1092,19 @@ export class Parser {
|
|
|
1058
1092
|
settings,
|
|
1059
1093
|
span: this.spanFrom(start),
|
|
1060
1094
|
});
|
|
1061
|
-
|
|
1062
|
-
|
|
1095
|
+
// Elements may be separated by a comma OR by whitespace/newline alone
|
|
1096
|
+
// (grammar: `tupleElement (COMMA? tupleElement)+`). Consume an optional
|
|
1097
|
+
// separator; the loop condition resumes on the next `[N]`.
|
|
1098
|
+
this.match(TokenKind.Comma);
|
|
1063
1099
|
}
|
|
1064
1100
|
return out;
|
|
1065
1101
|
}
|
|
1102
|
+
/** Lookahead for a tuple position marker `[ <number> ]` (vs. a settings block). */
|
|
1103
|
+
positionMarkerAhead() {
|
|
1104
|
+
return this.check(TokenKind.LBracket)
|
|
1105
|
+
&& this.peek(1).kind === TokenKind.NumberLiteral
|
|
1106
|
+
&& this.peek(2).kind === TokenKind.RBracket;
|
|
1107
|
+
}
|
|
1066
1108
|
parseMapType() {
|
|
1067
1109
|
const start = this.peek().start;
|
|
1068
1110
|
const kwTok = this.advance();
|
|
@@ -1083,7 +1125,11 @@ export class Parser {
|
|
|
1083
1125
|
const start = this.peek().start;
|
|
1084
1126
|
this.advance(); // set
|
|
1085
1127
|
this.expect(TokenKind.LBracket, "Expected '[' after set");
|
|
1086
|
-
const
|
|
1128
|
+
const elemStart = this.peek().start;
|
|
1129
|
+
let elementType = this.parseTypeExpression();
|
|
1130
|
+
// Sugar: `set [T1, T2, ...]` == `set [union [T1, T2, ...]]` (set has no
|
|
1131
|
+
// per-element settings, so the fold is always eligible).
|
|
1132
|
+
elementType = this.maybeFoldUnionSugar(elementType, elemStart, true);
|
|
1087
1133
|
this.expect(TokenKind.RBracket, "Expected ']' closing set");
|
|
1088
1134
|
return {
|
|
1089
1135
|
kind: 'SetType',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xdbml/parse",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Parser for xDBML (eXtended Database Markup Language), a strict superset of DBML 3.13.6: tokenizer, parser, module resolver, and name resolver.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Hackolade",
|