@player-ui/player 0.3.0-next.2 → 0.3.0-next.4

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 (77) hide show
  1. package/dist/index.cjs.js +4128 -891
  2. package/dist/index.d.ts +1227 -50
  3. package/dist/index.esm.js +4065 -836
  4. package/package.json +9 -15
  5. package/src/binding/binding.ts +108 -0
  6. package/src/binding/index.ts +188 -0
  7. package/src/binding/resolver.ts +157 -0
  8. package/src/binding/utils.ts +51 -0
  9. package/src/binding-grammar/ast.ts +113 -0
  10. package/src/binding-grammar/custom/index.ts +304 -0
  11. package/src/binding-grammar/ebnf/binding.ebnf +22 -0
  12. package/src/binding-grammar/ebnf/index.ts +186 -0
  13. package/src/binding-grammar/ebnf/types.ts +104 -0
  14. package/src/binding-grammar/index.ts +4 -0
  15. package/src/binding-grammar/parsimmon/index.ts +78 -0
  16. package/src/controllers/constants/index.ts +85 -0
  17. package/src/controllers/constants/utils.ts +37 -0
  18. package/src/{data.ts → controllers/data.ts} +6 -6
  19. package/src/controllers/flow/controller.ts +95 -0
  20. package/src/controllers/flow/flow.ts +205 -0
  21. package/src/controllers/flow/index.ts +2 -0
  22. package/src/controllers/index.ts +5 -0
  23. package/src/{validation → controllers/validation}/binding-tracker.ts +5 -5
  24. package/src/{validation → controllers/validation}/controller.ts +15 -14
  25. package/src/{validation → controllers/validation}/index.ts +0 -0
  26. package/src/{view → controllers/view}/asset-transform.ts +2 -3
  27. package/src/{view → controllers/view}/controller.ts +9 -8
  28. package/src/controllers/view/index.ts +4 -0
  29. package/src/{view → controllers/view}/store.ts +0 -0
  30. package/src/{view → controllers/view}/types.ts +2 -1
  31. package/src/data/dependency-tracker.ts +187 -0
  32. package/src/data/index.ts +4 -0
  33. package/src/data/local-model.ts +41 -0
  34. package/src/data/model.ts +216 -0
  35. package/src/data/noop-model.ts +18 -0
  36. package/src/expressions/evaluator-functions.ts +29 -0
  37. package/src/expressions/evaluator.ts +405 -0
  38. package/src/expressions/index.ts +3 -0
  39. package/src/expressions/parser.ts +889 -0
  40. package/src/expressions/types.ts +200 -0
  41. package/src/expressions/utils.ts +8 -0
  42. package/src/index.ts +9 -12
  43. package/src/logger/consoleLogger.ts +49 -0
  44. package/src/logger/index.ts +5 -0
  45. package/src/logger/noopLogger.ts +13 -0
  46. package/src/logger/proxyLogger.ts +25 -0
  47. package/src/logger/tapableLogger.ts +38 -0
  48. package/src/logger/types.ts +6 -0
  49. package/src/player.ts +21 -18
  50. package/src/plugins/flow-exp-plugin.ts +2 -3
  51. package/src/schema/index.ts +2 -0
  52. package/src/schema/schema.ts +220 -0
  53. package/src/schema/types.ts +60 -0
  54. package/src/string-resolver/index.ts +188 -0
  55. package/src/types.ts +11 -13
  56. package/src/utils/index.ts +1 -0
  57. package/src/utils/replaceParams.ts +17 -0
  58. package/src/validator/index.ts +3 -0
  59. package/src/validator/registry.ts +20 -0
  60. package/src/validator/types.ts +75 -0
  61. package/src/validator/validation-middleware.ts +114 -0
  62. package/src/view/builder/index.ts +81 -0
  63. package/src/view/index.ts +5 -4
  64. package/src/view/parser/index.ts +318 -0
  65. package/src/view/parser/types.ts +141 -0
  66. package/src/view/plugins/applicability.ts +78 -0
  67. package/src/view/plugins/index.ts +5 -0
  68. package/src/view/plugins/options.ts +4 -0
  69. package/src/view/plugins/plugin.ts +21 -0
  70. package/src/view/plugins/string-resolver.ts +149 -0
  71. package/src/view/plugins/switch.ts +120 -0
  72. package/src/view/plugins/template-plugin.ts +172 -0
  73. package/src/view/resolver/index.ts +397 -0
  74. package/src/view/resolver/types.ts +161 -0
  75. package/src/view/resolver/utils.ts +57 -0
  76. package/src/view/view.ts +149 -0
  77. package/src/utils/desc.d.ts +0 -2
@@ -0,0 +1,304 @@
1
+ import type {
2
+ Parser,
3
+ AnyNode,
4
+ PathNode,
5
+ ConcatenatedNode,
6
+ ValueNode,
7
+ QueryNode,
8
+ ExpressionNode,
9
+ } from '../ast';
10
+ import {
11
+ toValue,
12
+ toPath,
13
+ toConcatenatedNode,
14
+ toQuery,
15
+ toExpression,
16
+ } from '../ast';
17
+
18
+ const SEGMENT_SEPARATOR = '.';
19
+ const OPEN_CURL = '{';
20
+ const CLOSE_CURL = '}';
21
+ const OPEN_BRACKET = '[';
22
+ const CLOSE_BRACKET = ']';
23
+ const EQUALS = '=';
24
+ const SINGLE_QUOTE = "'";
25
+ const DOUBLE_QUOTE = '"';
26
+ const BACK_TICK = '`';
27
+ // const IDENTIFIER_REGEX = /[\w\-@]+/;
28
+
29
+ /** A _faster_ way to match chars instead of a regex (/[\w\-@]+/) */
30
+ const isIdentifierChar = (char?: string): boolean => {
31
+ if (!char) {
32
+ return false;
33
+ }
34
+
35
+ const charCode = char.charCodeAt(0);
36
+
37
+ return (
38
+ (charCode >= 48 && charCode <= 57) || // 0 - 9
39
+ (charCode >= 65 && charCode <= 90) || // A-Z
40
+ (charCode >= 97 && charCode <= 122) || // a-z
41
+ charCode === 95 || // _
42
+ charCode === 45 || // -
43
+ charCode === 64 // @
44
+ );
45
+ };
46
+
47
+ /** Parse out a binding AST from a path */
48
+ export const parse: Parser = (path) => {
49
+ let index = 1;
50
+ let ch = path.charAt(0);
51
+
52
+ /** get the next char in the string */
53
+ const next = (expected?: string) => {
54
+ if (expected && ch !== expected) {
55
+ throw new Error(`Expected char: ${expected} but got: ${ch}`);
56
+ }
57
+
58
+ ch = path.charAt(index);
59
+ index += 1;
60
+ // console.log(`Index: ${index} Char: ${ch}`);
61
+ return ch;
62
+ };
63
+
64
+ /** gobble all whitespace */
65
+ const whitespace = () => {
66
+ /* eslint-disable no-unmodified-loop-condition */
67
+ while (ch === ' ') {
68
+ next();
69
+ }
70
+ };
71
+
72
+ /** get an identifier if you can */
73
+ const identifier = (): ValueNode | undefined => {
74
+ if (!isIdentifierChar(ch)) {
75
+ return;
76
+ }
77
+
78
+ let value = ch;
79
+
80
+ while (next()) {
81
+ if (!isIdentifierChar(ch)) {
82
+ break;
83
+ }
84
+
85
+ value += ch;
86
+ }
87
+
88
+ if (value) {
89
+ return toValue(value);
90
+ }
91
+ };
92
+
93
+ /** get an expression node if you can */
94
+ const expression = (): ExpressionNode | undefined => {
95
+ if (ch === BACK_TICK) {
96
+ next(BACK_TICK);
97
+
98
+ let exp = ch;
99
+
100
+ while (next()) {
101
+ if (ch === BACK_TICK) {
102
+ break;
103
+ }
104
+
105
+ exp += ch;
106
+ }
107
+
108
+ next(BACK_TICK);
109
+
110
+ if (exp) {
111
+ return toExpression(exp);
112
+ }
113
+ }
114
+ };
115
+
116
+ /** Grab a value using a regex */
117
+ const regex = (match: RegExp): ValueNode | undefined => {
118
+ if (!ch?.match(match)) {
119
+ return;
120
+ }
121
+
122
+ let value = ch;
123
+
124
+ while (next()) {
125
+ if (!ch?.match(match)) {
126
+ break;
127
+ }
128
+
129
+ value += ch;
130
+ }
131
+
132
+ if (value) {
133
+ return toValue(value);
134
+ }
135
+ };
136
+
137
+ /** parse out a nestedPath if you can */
138
+ const nestedPath = (): PathNode | undefined => {
139
+ if (ch === OPEN_CURL) {
140
+ next(OPEN_CURL);
141
+ if (ch === OPEN_CURL) {
142
+ next(OPEN_CURL);
143
+
144
+ /* eslint-disable-next-line @typescript-eslint/no-use-before-define */
145
+ const modelRef = parsePath();
146
+ next(CLOSE_CURL);
147
+ next(CLOSE_CURL);
148
+ return modelRef;
149
+ }
150
+ }
151
+ };
152
+
153
+ /** get a simple segment node */
154
+ const simpleSegment = () => nestedPath() ?? expression() ?? identifier();
155
+
156
+ /** Parse a segment */
157
+ const segment = ():
158
+ | ConcatenatedNode
159
+ | PathNode
160
+ | ValueNode
161
+ | ExpressionNode
162
+ | undefined => {
163
+ // Either a string, modelRef, or concatenated version (both)
164
+ const segments: Array<ValueNode | PathNode | ExpressionNode> = [];
165
+ let nextSegment = simpleSegment();
166
+
167
+ while (nextSegment !== undefined) {
168
+ segments.push(nextSegment);
169
+ nextSegment = simpleSegment();
170
+ }
171
+
172
+ if (segments.length === 0) {
173
+ return undefined;
174
+ }
175
+
176
+ return toConcatenatedNode(segments);
177
+ };
178
+
179
+ /** get an optionally quoted block */
180
+ const optionallyQuotedSegment = ():
181
+ | ValueNode
182
+ | PathNode
183
+ | ExpressionNode
184
+ | undefined => {
185
+ whitespace();
186
+
187
+ // see if we have a quote
188
+
189
+ if (ch === SINGLE_QUOTE || ch === DOUBLE_QUOTE) {
190
+ const singleQuote = ch === SINGLE_QUOTE;
191
+ next(singleQuote ? SINGLE_QUOTE : DOUBLE_QUOTE);
192
+ const id = regex(/[^'"]+/);
193
+ next(singleQuote ? SINGLE_QUOTE : DOUBLE_QUOTE);
194
+ return id;
195
+ }
196
+
197
+ return simpleSegment();
198
+ };
199
+
200
+ /** eat equals signs */
201
+ const equals = (): boolean => {
202
+ if (ch !== EQUALS) {
203
+ return false;
204
+ }
205
+
206
+ while (ch === EQUALS) {
207
+ next();
208
+ }
209
+
210
+ return true;
211
+ };
212
+
213
+ /** Parse out a bracket */
214
+ const parseBracket = ():
215
+ | ValueNode
216
+ | QueryNode
217
+ | PathNode
218
+ | ExpressionNode
219
+ | undefined => {
220
+ if (ch === OPEN_BRACKET) {
221
+ next(OPEN_BRACKET);
222
+ whitespace();
223
+ let value: ValueNode | QueryNode | PathNode | ExpressionNode | undefined =
224
+ optionallyQuotedSegment();
225
+ if (value) {
226
+ whitespace();
227
+ if (equals()) {
228
+ whitespace();
229
+ const second = optionallyQuotedSegment();
230
+ value = toQuery(value, second);
231
+ whitespace();
232
+ }
233
+ } else {
234
+ throw new Error(`Expected identifier`);
235
+ }
236
+
237
+ if (value) {
238
+ next(CLOSE_BRACKET);
239
+ }
240
+
241
+ return value;
242
+ }
243
+ };
244
+
245
+ /** Parse a segment and any number of brackets following it */
246
+ const parseSegmentAndBrackets = (): Array<AnyNode> => {
247
+ // try to parse a segment first
248
+
249
+ const parsed = [];
250
+
251
+ const firstSegment = segment();
252
+
253
+ if (firstSegment) {
254
+ parsed.push(firstSegment);
255
+
256
+ let bracketSegment = parseBracket();
257
+
258
+ while (bracketSegment !== undefined) {
259
+ parsed.push(bracketSegment);
260
+ bracketSegment = parseBracket();
261
+ }
262
+ }
263
+
264
+ return parsed;
265
+ };
266
+
267
+ /** Parse out a path segment */
268
+ const parsePath = (): PathNode => {
269
+ const parts: AnyNode[] = [];
270
+
271
+ let nextSegment = parseSegmentAndBrackets();
272
+
273
+ while (nextSegment !== undefined) {
274
+ parts.push(...nextSegment);
275
+
276
+ if (!ch || ch === CLOSE_CURL) {
277
+ break;
278
+ }
279
+
280
+ if (nextSegment.length === 0 && ch) {
281
+ throw new Error(`Unexpected character: ${ch}`);
282
+ }
283
+
284
+ next(SEGMENT_SEPARATOR);
285
+ nextSegment = parseSegmentAndBrackets();
286
+ }
287
+
288
+ return toPath(parts);
289
+ };
290
+
291
+ try {
292
+ const result = parsePath();
293
+
294
+ return {
295
+ status: true,
296
+ path: result,
297
+ };
298
+ } catch (e: any) {
299
+ return {
300
+ status: false,
301
+ error: e.message,
302
+ };
303
+ }
304
+ };
@@ -0,0 +1,22 @@
1
+ value ::= segment_and_bracket (SEGMENT_SEPARATOR segment_and_bracket)*
2
+ segment ::= concatenated | expression | modelRef | identifier
3
+ concatenated ::= (expression | modelRef | identifier)+
4
+ modelRef ::= OPEN_CURL OPEN_CURL value CLOSE_CURL CLOSE_CURL
5
+ identifier ::= [\\w\\-@]+
6
+ query ::= WHITESPACE* optionally_quoted_segment WHITESPACE* EQUALS EQUALS? EQUALS? WHITESPACE* optionally_quoted_segment WHITESPACE*
7
+ brackets ::= OPEN_BRACKET WHITESPACE* (query | optionally_quoted_segment) WHITESPACE* CLOSE_BRACKET
8
+ segment_and_bracket ::= segment brackets*
9
+ quoted_value ::= [^"']*
10
+ optionally_quoted_segment ::= WHITESPACE* SINGLE_QUOTE quoted_value SINGLE_QUOTE WHITESPACE* | WHITESPACE* DOUBLE_QUOTE quoted_value DOUBLE_QUOTE WHITESPACE* | WHITESPACE* segment WHITESPACE*
11
+ expression_value ::= [^`]*
12
+ expression ::= BACK_TICK expression_value BACK_TICK
13
+ EQUALS ::= "="
14
+ SEGMENT_SEPARATOR ::= "."
15
+ SINGLE_QUOTE ::= "'"
16
+ DOUBLE_QUOTE ::= '"'
17
+ WHITESPACE ::= " "
18
+ OPEN_CURL ::= "{"
19
+ CLOSE_CURL ::= "}"
20
+ OPEN_BRACKET ::= "["
21
+ CLOSE_BRACKET ::= "]"
22
+ BACK_TICK ::= "`"
@@ -0,0 +1,186 @@
1
+ /* eslint-disable @typescript-eslint/no-use-before-define */
2
+ import { Grammars } from 'ebnf';
3
+ import type {
4
+ Parser,
5
+ AnyNode,
6
+ PathNode,
7
+ ValueNode,
8
+ ConcatenatedNode,
9
+ QueryNode,
10
+ ExpressionNode,
11
+ } from '../ast';
12
+ import {
13
+ toValue,
14
+ toQuery,
15
+ toPath,
16
+ toConcatenatedNode,
17
+ toExpression,
18
+ } from '../ast';
19
+ import type {
20
+ ValueToken,
21
+ ModelRefToken,
22
+ IdentifierToken,
23
+ ConcatenatedToken,
24
+ Token,
25
+ OptionallyQuotedSegment,
26
+ QueryToken,
27
+ QuotedValueToken,
28
+ ExpressionToken,
29
+ } from './types';
30
+
31
+ const parser = new Grammars.W3C.Parser(`
32
+ value ::= segment_and_bracket (SEGMENT_SEPARATOR segment_and_bracket)*
33
+ segment ::= concatenated | expression | modelRef | identifier
34
+ concatenated ::= (expression | modelRef | identifier)+
35
+ modelRef ::= OPEN_CURL OPEN_CURL value CLOSE_CURL CLOSE_CURL
36
+ identifier ::= [\\w\\-@]+
37
+ query ::= WHITESPACE* optionally_quoted_segment WHITESPACE* EQUALS EQUALS? EQUALS? WHITESPACE* optionally_quoted_segment WHITESPACE*
38
+ brackets ::= OPEN_BRACKET WHITESPACE* (query | optionally_quoted_segment) WHITESPACE* CLOSE_BRACKET
39
+ segment_and_bracket ::= segment brackets*
40
+ quoted_value ::= [^"']*
41
+ optionally_quoted_segment ::= WHITESPACE* SINGLE_QUOTE quoted_value SINGLE_QUOTE WHITESPACE* | WHITESPACE* DOUBLE_QUOTE quoted_value DOUBLE_QUOTE WHITESPACE* | WHITESPACE* segment WHITESPACE*
42
+ expression_value ::= [^\`]*
43
+ expression ::= BACK_TICK expression_value BACK_TICK
44
+
45
+ EQUALS ::= "="
46
+ SEGMENT_SEPARATOR ::= "."
47
+ SINGLE_QUOTE ::= "'"
48
+ DOUBLE_QUOTE ::= '"'
49
+ WHITESPACE ::= " "
50
+ OPEN_CURL ::= "{"
51
+ CLOSE_CURL ::= "}"
52
+ OPEN_BRACKET ::= "["
53
+ CLOSE_BRACKET ::= "]"
54
+ BACK_TICK ::= "\`"
55
+ `);
56
+
57
+ /** Map an identifier token to a value */
58
+ function convertIdentifierToken(token: IdentifierToken): ValueNode {
59
+ return toValue(token.text);
60
+ }
61
+
62
+ /** Concert an expression token into a node */
63
+ function convertExpressionToken(token: ExpressionToken): ExpressionNode {
64
+ return toExpression(token.children[0].text);
65
+ }
66
+
67
+ /** map a concatenated token to a node */
68
+ function convertConcatenatedToken(
69
+ token: ConcatenatedToken
70
+ ): ConcatenatedNode | ValueNode | PathNode | ExpressionNode {
71
+ return toConcatenatedNode(
72
+ token.children.map((child) => {
73
+ if (child.type === 'identifier') {
74
+ return convertIdentifierToken(child);
75
+ }
76
+
77
+ if (child.type === 'expression') {
78
+ return convertExpressionToken(child);
79
+ }
80
+
81
+ return convertModelRefToken(child);
82
+ })
83
+ );
84
+ }
85
+
86
+ /** map a quoted value token to a value node */
87
+ function convertQuotedValueToken(token: QuotedValueToken): ValueNode {
88
+ return toValue(token.text);
89
+ }
90
+
91
+ /** map a quoted value token to a value node */
92
+ function convertOptionallyQuotedToken(
93
+ token: OptionallyQuotedSegment
94
+ ): ValueNode | ConcatenatedNode | PathNode | ExpressionNode {
95
+ const child = token.children[0];
96
+ if (child.type === 'quoted_value') {
97
+ return convertQuotedValueToken(child);
98
+ }
99
+
100
+ const grandChild = child.children[0];
101
+ if (grandChild.type === 'identifier') {
102
+ return convertIdentifierToken(grandChild);
103
+ }
104
+
105
+ return convertConcatenatedToken(grandChild);
106
+ }
107
+
108
+ /** map a query token to a value node */
109
+ function convertQueryToken(token: QueryToken): QueryNode {
110
+ return toQuery(
111
+ convertOptionallyQuotedToken(token.children[0]),
112
+ convertOptionallyQuotedToken(token.children[1])
113
+ );
114
+ }
115
+
116
+ /** Convert the IToken */
117
+ function convertValueToken(binding: ValueToken): PathNode {
118
+ const path: AnyNode[] = [];
119
+
120
+ /** Expand a token into it's path refs */
121
+ function expandPath(token: Token) {
122
+ switch (token.type) {
123
+ case 'modelRef':
124
+ path.push(convertModelRefToken(token));
125
+ break;
126
+ case 'identifier':
127
+ path.push(convertIdentifierToken(token));
128
+ break;
129
+ case 'quoted_value':
130
+ path.push(convertQuotedValueToken(token));
131
+ break;
132
+ case 'expression':
133
+ path.push(convertExpressionToken(token));
134
+ break;
135
+ case 'query':
136
+ path.push(convertQueryToken(token));
137
+ break;
138
+ case 'concatenated':
139
+ path.push(convertConcatenatedToken(token));
140
+ break;
141
+ default:
142
+ token.children.forEach(expandPath);
143
+ }
144
+ }
145
+
146
+ expandPath(binding);
147
+
148
+ return toPath(path);
149
+ }
150
+
151
+ /** map a model ref token to a path node */
152
+ function convertModelRefToken(token: ModelRefToken): PathNode {
153
+ return convertValueToken(token.children[0]);
154
+ }
155
+
156
+ /** Parse a binding using ebnf */
157
+ export const parse: Parser = (path) => {
158
+ if (path === '') {
159
+ return {
160
+ status: true,
161
+ path: toPath([]),
162
+ };
163
+ }
164
+
165
+ const ast = parser.getAST(path) as ValueToken;
166
+
167
+ if (!ast) {
168
+ return {
169
+ status: false,
170
+ error: 'Unable to parse binding',
171
+ };
172
+ }
173
+
174
+ if (ast.errors.length > 0) {
175
+ // console.log(ast.errors);
176
+ return {
177
+ status: false,
178
+ error: ast.errors[0].message,
179
+ };
180
+ }
181
+
182
+ return {
183
+ status: true,
184
+ path: convertValueToken(ast),
185
+ };
186
+ };
@@ -0,0 +1,104 @@
1
+ import type { IToken } from 'ebnf';
2
+
3
+ export interface ValueToken extends IToken {
4
+ /** A value type */
5
+ type: 'value';
6
+
7
+ /** Any children of the value */
8
+ children: Array<SegmentAndBracketToken>;
9
+ }
10
+
11
+ export interface SegmentAndBracketToken extends IToken {
12
+ /** A token for a segment + brackets */
13
+ type: 'segment_and_bracket';
14
+
15
+ /** The segment + brackets */
16
+ children: [SegmentToken, ...Array<BracketToken>];
17
+ }
18
+
19
+ export interface SegmentToken extends IToken {
20
+ /** A segment token */
21
+ type: 'segment';
22
+
23
+ /** Any children of the token */
24
+ children: [ConcatenatedToken | IdentifierToken];
25
+ }
26
+
27
+ export interface BracketToken extends IToken {
28
+ /** A bracket token */
29
+ type: 'bracket';
30
+ /** Any children of the token */
31
+ children: [OptionallyQuotedSegment | QueryToken];
32
+ }
33
+
34
+ export interface ExpressionValueToken extends IToken {
35
+ /** Expression value token */
36
+ type: 'expression_value';
37
+
38
+ /** No children here */
39
+ children: [];
40
+ }
41
+
42
+ export interface ExpressionToken extends IToken {
43
+ /** Expression token */
44
+ type: 'expression';
45
+
46
+ /** Children is the expression value */
47
+ children: [ExpressionValueToken];
48
+ }
49
+
50
+ export interface QuotedValueToken extends IToken {
51
+ /** A quoted value */
52
+ type: 'quoted_value';
53
+ /** Any children of the token */
54
+ children: [];
55
+ }
56
+
57
+ export interface IdentifierToken extends IToken {
58
+ /** Any identifier */
59
+ type: 'identifier';
60
+ /** Any children of the token */
61
+ children: [];
62
+ }
63
+
64
+ export interface ConcatenatedToken extends IToken {
65
+ /** A node of more than 1 identifier */
66
+ type: 'concatenated';
67
+ /** Any children of the token */
68
+ children: Array<IdentifierToken | ModelRefToken | ExpressionToken>;
69
+ }
70
+
71
+ export interface ModelRefToken extends IToken {
72
+ /** A nested model reference */
73
+ type: 'modelRef';
74
+ /** Any children of the token */
75
+ children: [ValueToken];
76
+ }
77
+
78
+ export interface OptionallyQuotedSegment extends IToken {
79
+ /** Any optionally quoted segment */
80
+ type: 'optionally_quoted_segment';
81
+ /** Any children of the token */
82
+ children: [QuotedValueToken | SegmentToken];
83
+ }
84
+
85
+ export interface QueryToken extends IToken {
86
+ /** A query */
87
+ type: 'query';
88
+ /** Any children of the token */
89
+ children: [OptionallyQuotedSegment, OptionallyQuotedSegment];
90
+ }
91
+
92
+ export type Token =
93
+ | ValueToken
94
+ | QueryToken
95
+ | QuotedValueToken
96
+ | OptionallyQuotedSegment
97
+ | SegmentAndBracketToken
98
+ | SegmentToken
99
+ | BracketToken
100
+ | IdentifierToken
101
+ | ConcatenatedToken
102
+ | ModelRefToken
103
+ | ExpressionValueToken
104
+ | ExpressionToken;
@@ -0,0 +1,4 @@
1
+ export * from './ast';
2
+ export { parse as parseParsimmon } from './parsimmon';
3
+ export { parse as parseEBNF } from './ebnf';
4
+ export { parse as parseCustom } from './custom';
@@ -0,0 +1,78 @@
1
+ import flatten from 'arr-flatten';
2
+ import type { Parser } from 'parsimmon';
3
+ import P from 'parsimmon';
4
+ import type { Parser as BindingParser } from '../ast';
5
+ import {
6
+ toValue,
7
+ toConcatenatedNode,
8
+ toQuery,
9
+ toPath,
10
+ toExpression,
11
+ } from '../ast';
12
+
13
+ const doubleQuote = P.string('"');
14
+ const singleQuote = P.string("'");
15
+ const backTick = P.string('`');
16
+
17
+ const identifier = P.regex(/[\w\-@]+/)
18
+ .desc('identifier')
19
+ .map(toValue);
20
+
21
+ // eslint-disable-next-line prefer-const
22
+ let path: Parser<any>;
23
+
24
+ const futurePath = P.lazy(() => path);
25
+ const nestedPath = futurePath
26
+ .trim(P.optWhitespace)
27
+ .wrap(P.string('{{'), P.string('}}'))
28
+ .map(toPath);
29
+
30
+ const nestedExpression = P.regex(/[^`]*/)
31
+ .wrap(backTick, backTick)
32
+ .map(toExpression);
33
+
34
+ const segment = P.alt(identifier, nestedPath, nestedExpression)
35
+ .atLeast(1)
36
+ .map(flatten)
37
+ .map(toConcatenatedNode as any);
38
+
39
+ const optionallyQuotedSegment = P.alt(
40
+ P.regex(/[^"]*/).wrap(doubleQuote, doubleQuote).map(toValue),
41
+ P.regex(/[^']*/).wrap(singleQuote, singleQuote).map(toValue),
42
+ segment
43
+ );
44
+
45
+ const query = P.seq(
46
+ optionallyQuotedSegment,
47
+ P.string('=').times(1, 3).trim(P.optWhitespace),
48
+ optionallyQuotedSegment
49
+ ).map(([key, , value]) => toQuery(key as any, value as any));
50
+
51
+ const brackets = P.alt(query, optionallyQuotedSegment)
52
+ .trim(P.optWhitespace)
53
+ .wrap(P.string('['), P.string(']'))
54
+ .many();
55
+
56
+ const segmentAndBrackets = P.seqMap(segment, brackets, (s, bs) => [s, ...bs]);
57
+
58
+ path = P.sepBy(segmentAndBrackets, P.string('.')).map(flatten);
59
+
60
+ /** Parse a binding using parsimmon */
61
+ export const parse: BindingParser = (binding) => {
62
+ const result = path.parse(binding);
63
+
64
+ if (result.status) {
65
+ return {
66
+ status: true,
67
+ path: {
68
+ name: 'PathNode',
69
+ path: result.value,
70
+ },
71
+ };
72
+ }
73
+
74
+ return {
75
+ status: false,
76
+ error: result.expected[0],
77
+ };
78
+ };