@fc-components/monaco-editor 0.1.27 → 0.3.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 (36) hide show
  1. package/dist/expr/__tests__/__mocks__/monaco-editor.d.ts +28 -0
  2. package/dist/expr/completion/getCompletionProvider.d.ts +4 -0
  3. package/dist/expr/expr.d.ts +83 -0
  4. package/dist/expr/index.d.ts +3 -0
  5. package/dist/expr/parser/index.d.ts +3 -0
  6. package/dist/expr/parser/lexer.d.ts +27 -0
  7. package/dist/expr/parser/parser.d.ts +66 -0
  8. package/dist/expr/parser/types.d.ts +32 -0
  9. package/dist/expr/types.d.ts +17 -0
  10. package/dist/expr/validation.d.ts +12 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/monaco-editor.cjs.development.js +1986 -3
  13. package/dist/monaco-editor.cjs.development.js.map +1 -1
  14. package/dist/monaco-editor.cjs.production.min.js +1 -1
  15. package/dist/monaco-editor.cjs.production.min.js.map +1 -1
  16. package/dist/monaco-editor.esm.js +1989 -7
  17. package/dist/monaco-editor.esm.js.map +1 -1
  18. package/dist/promql/completion/situation.d.ts +2 -0
  19. package/package.json +6 -2
  20. package/src/expr/__tests__/__mocks__/monaco-editor.ts +34 -0
  21. package/src/expr/__tests__/expr.test.tsx +339 -0
  22. package/src/expr/completion/getCompletionProvider.ts +133 -0
  23. package/src/expr/expr.ts +229 -0
  24. package/src/expr/index.tsx +322 -0
  25. package/src/expr/parser/index.ts +3 -0
  26. package/src/expr/parser/lexer.ts +377 -0
  27. package/src/expr/parser/parser.ts +581 -0
  28. package/src/expr/parser/types.ts +77 -0
  29. package/src/expr/types.ts +17 -0
  30. package/src/expr/validation.ts +209 -0
  31. package/src/index.tsx +2 -0
  32. package/src/promql/__tests__/completions.test.ts +72 -0
  33. package/src/promql/__tests__/situation.test.ts +85 -0
  34. package/src/promql/completion/completions.ts +11 -2
  35. package/src/promql/completion/situation.ts +65 -1
  36. package/src/promql/promql.ts +3 -1
@@ -346,6 +346,7 @@ for (var _i = 0, aggregations_1 = aggregations; _i < aggregations_1.length; _i++
346
346
  // PromQL vector matching + the by and without clauses
347
347
  // (https://prometheus.io/docs/prometheus/latest/querying/operators/#vector-matching)
348
348
  var vectorMatching = ['on', 'ignoring', 'group_right', 'group_left', 'by', 'without'];
349
+ var cteKeywords = ['with'];
349
350
  // Produce a regex matching elements : (elt1|elt2|...)
350
351
  var vectorMatchingRegex = '(' + /*#__PURE__*/vectorMatching.reduce(function (prev, curr) {
351
352
  return prev + '|' + curr;
@@ -357,7 +358,7 @@ var operators = ['+', '-', '*', '/', '%', '^', '==', '!=', '>', '<', '>=', '<=',
357
358
  // (https://prometheus.io/docs/prometheus/latest/querying/basics/#offset-modifier)
358
359
  var offsetModifier = ['offset'];
359
360
  // Merging all the keywords in one list
360
- var keywords = /*#__PURE__*/aggregations.concat(functions).concat(aggregationsOverTime).concat(vectorMatching).concat(offsetModifier);
361
+ var keywords = /*#__PURE__*/aggregations.concat(functions).concat(aggregationsOverTime).concat(vectorMatching).concat(offsetModifier).concat(cteKeywords);
361
362
  // noinspection JSUnusedGlobalSymbols
362
363
  var language = {
363
364
  ignoreCase: false,
@@ -1295,6 +1296,15 @@ var RESOLVERS = [{
1295
1296
  }, {
1296
1297
  path: [lezerMetricsql.GroupingLabels],
1297
1298
  fun: resolveLabelsForGrouping
1299
+ }, {
1300
+ path: [lezerMetricsql.WithExpr],
1301
+ fun: resolveWithExpr
1302
+ }, {
1303
+ path: [lezerMetricsql.WithExpr, lezerMetricsql.PromQL],
1304
+ fun: resolveWithExpr
1305
+ }, {
1306
+ path: [lezerMetricsql.WithAssignment, lezerMetricsql.WithExpr],
1307
+ fun: resolveWithExpr
1298
1308
  }];
1299
1309
  var LABEL_OP_MAP = /*#__PURE__*/new Map([[lezerMetricsql.EqlSingle, '='], [lezerMetricsql.EqlRegex, '=~'], [lezerMetricsql.Neq, '!='], [lezerMetricsql.NeqRegex, '!~']]);
1300
1310
  function getLabelOp(opNode) {
@@ -1467,6 +1477,25 @@ function resolveInFunction() {
1467
1477
  type: 'IN_FUNCTION'
1468
1478
  };
1469
1479
  }
1480
+ function resolveWithExpr(node, text, pos) {
1481
+ // Find the containing WithExpr node (node may be a WithAssignment child)
1482
+ var withExprNode = node.type.id === lezerMetricsql.WithExpr ? node : node.parent;
1483
+ while (withExprNode && withExprNode.type.id !== lezerMetricsql.WithExpr) {
1484
+ withExprNode = withExprNode.parent;
1485
+ }
1486
+ if (!withExprNode) return null;
1487
+ // Only return IN_WITH_BODY when cursor is in the body expression (after the closing ')')
1488
+ var children = getNodeChildren(withExprNode);
1489
+ var closeParen = children.find(function (c) {
1490
+ return getNodeText(c, text) === ')';
1491
+ });
1492
+ if (closeParen && pos > closeParen.to) {
1493
+ return {
1494
+ type: 'IN_WITH_BODY'
1495
+ };
1496
+ }
1497
+ return null;
1498
+ }
1470
1499
  function resolveDurations() {
1471
1500
  return {
1472
1501
  type: 'IN_DURATION'
@@ -1576,6 +1605,25 @@ function getErrorNode(tree, pos) {
1576
1605
  }
1577
1606
  return null;
1578
1607
  }
1608
+ function findMatchingParen(text, openPos) {
1609
+ var depth = 0;
1610
+ for (var i = openPos; i < text.length; i++) {
1611
+ if (text[i] === '(') depth++;
1612
+ if (text[i] === ')') {
1613
+ depth--;
1614
+ if (depth === 0) return i;
1615
+ }
1616
+ }
1617
+ return -1;
1618
+ }
1619
+ function isInWithBody(text, pos) {
1620
+ var withMatch = text.match(/^with\s*\(/i);
1621
+ if (!withMatch) return false;
1622
+ var openParenPos = withMatch[0].length - 1;
1623
+ var closeParenPos = findMatchingParen(text, openParenPos);
1624
+ if (closeParenPos === -1) return false;
1625
+ return pos > closeParenPos;
1626
+ }
1579
1627
  function getSituation(text, pos) {
1580
1628
  // there is a special-case when we are at the start of writing text,
1581
1629
  // so we handle that case first
@@ -1584,6 +1632,12 @@ function getSituation(text, pos) {
1584
1632
  type: 'EMPTY'
1585
1633
  };
1586
1634
  }
1635
+ // text-based check for with body (fallback until grammar supports WithExpr)
1636
+ if (isInWithBody(text, pos)) {
1637
+ return {
1638
+ type: 'IN_WITH_BODY'
1639
+ };
1640
+ }
1587
1641
  /**
1588
1642
  PromQL
1589
1643
  Expr
@@ -1666,12 +1720,19 @@ function _getAllFunctionsAndMetricNamesCompletions() {
1666
1720
  while (1) switch (_context.n) {
1667
1721
  case 0:
1668
1722
  metricNames = getAllMetricNamesCompletions(dataProvider);
1669
- return _context.a(2, [].concat(FUNCTION_COMPLETIONS, metricNames));
1723
+ return _context.a(2, [CTE_KEYWORD_COMPLETION].concat(FUNCTION_COMPLETIONS, metricNames));
1670
1724
  }
1671
1725
  }, _callee);
1672
1726
  }));
1673
1727
  return _getAllFunctionsAndMetricNamesCompletions.apply(this, arguments);
1674
1728
  }
1729
+ var CTE_KEYWORD_COMPLETION = {
1730
+ type: 'FUNCTION',
1731
+ label: 'with',
1732
+ insertText: 'with (',
1733
+ detail: 'with (cte_name = expr, ...) expr',
1734
+ documentation: 'Define Common Table Expressions (CTEs) for use in the query. MetricsQL extension.'
1735
+ };
1675
1736
  var DURATION_COMPLETIONS = /*#__PURE__*/['1m', '5m', '10m', '30m', '1h', '1d'].map(function (text) {
1676
1737
  return {
1677
1738
  type: 'DURATION',
@@ -1913,6 +1974,7 @@ function getCompletions(situation, dataProvider) {
1913
1974
  return Promise.resolve(DURATION_COMPLETIONS);
1914
1975
  case 'IN_FUNCTION':
1915
1976
  return getAllFunctionsAndMetricNamesCompletions(dataProvider);
1977
+ case 'IN_WITH_BODY':
1916
1978
  case 'AT_ROOT':
1917
1979
  {
1918
1980
  return getAllFunctionsAndMetricNamesCompletions(dataProvider);
@@ -1921,7 +1983,7 @@ function getCompletions(situation, dataProvider) {
1921
1983
  {
1922
1984
  var metricNames = getAllMetricNamesCompletions(dataProvider);
1923
1985
  var historyCompletions = getAllHistoryCompletions();
1924
- return Promise.resolve([].concat(historyCompletions, FUNCTION_COMPLETIONS, metricNames));
1986
+ return Promise.resolve([].concat(historyCompletions, [CTE_KEYWORD_COMPLETION], FUNCTION_COMPLETIONS, metricNames));
1925
1987
  }
1926
1988
  case 'IN_LABEL_SELECTOR_NO_LABEL_NAME':
1927
1989
  return getLabelNamesForSelectorCompletions(situation.metricName, situation.hasOperator, situation.otherLabels, dataProvider);
@@ -3826,6 +3888,1927 @@ function SqlEditor(props) {
3826
3888
  })));
3827
3889
  }
3828
3890
 
3891
+ var languageConfiguration$3 = {
3892
+ wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
3893
+ comments: {
3894
+ lineComment: '//',
3895
+ blockComment: ['/*', '*/']
3896
+ },
3897
+ brackets: [['{', '}'], ['[', ']'], ['(', ')']],
3898
+ autoClosingPairs: [{
3899
+ open: '{',
3900
+ close: '}'
3901
+ }, {
3902
+ open: '[',
3903
+ close: ']'
3904
+ }, {
3905
+ open: '(',
3906
+ close: ')'
3907
+ }, {
3908
+ open: '"',
3909
+ close: '"'
3910
+ }, {
3911
+ open: "'",
3912
+ close: "'"
3913
+ }, {
3914
+ open: '`',
3915
+ close: '`'
3916
+ }],
3917
+ surroundingPairs: [{
3918
+ open: '{',
3919
+ close: '}'
3920
+ }, {
3921
+ open: '[',
3922
+ close: ']'
3923
+ }, {
3924
+ open: '(',
3925
+ close: ')'
3926
+ }, {
3927
+ open: '"',
3928
+ close: '"'
3929
+ }, {
3930
+ open: "'",
3931
+ close: "'"
3932
+ }, {
3933
+ open: '`',
3934
+ close: '`'
3935
+ }],
3936
+ folding: {
3937
+ offSide: false
3938
+ }
3939
+ };
3940
+ // Expr-lang keywords
3941
+ var keywords$3 = ['let', 'true', 'false', 'nil', 'in', 'not', 'and', 'or', 'if', 'else'];
3942
+ // Expr-lang built-in functions
3943
+ var stringFunctions = ['trim', 'trimPrefix', 'trimSuffix', 'upper', 'lower', 'split', 'splitAfter', 'replace', 'repeat', 'indexOf', 'lastIndexOf', 'hasPrefix', 'hasSuffix', 'contains', 'startsWith', 'endsWith'];
3944
+ var dateFunctions = ['now', 'duration', 'date', 'timezone'];
3945
+ var numberFunctions = ['max', 'min', 'abs', 'ceil', 'floor', 'round'];
3946
+ var arrayFunctions = ['all', 'any', 'one', 'none', 'map', 'filter', 'find', 'findIndex', 'findLast', 'findLastIndex', 'groupBy', 'count', 'concat', 'flatten', 'uniq', 'join', 'reduce', 'sum', 'mean', 'median', 'first', 'last', 'take', 'reverse', 'sort', 'sortBy'];
3947
+ var mapFunctions = ['keys', 'values'];
3948
+ var typeConversionFunctions = ['type', 'int', 'float', 'string', 'toJSON', 'fromJSON', 'toBase64', 'fromBase64', 'toPairs', 'fromPairs'];
3949
+ var miscFunctions = ['len', 'get'];
3950
+ var bitwiseFunctions = ['bitand', 'bitor', 'bitxor', 'bitnand', 'bitnot', 'bitshl', 'bitshr', 'bitushr'];
3951
+ var builtinFunctions = /*#__PURE__*/[].concat(stringFunctions, dateFunctions, numberFunctions, arrayFunctions, mapFunctions, typeConversionFunctions, miscFunctions, bitwiseFunctions);
3952
+ var language$3 = {
3953
+ defaultToken: '',
3954
+ tokenPostfix: '.expr',
3955
+ brackets: [{
3956
+ open: '(',
3957
+ close: ')',
3958
+ token: 'delimiter.parenthesis'
3959
+ }, {
3960
+ open: '{',
3961
+ close: '}',
3962
+ token: 'delimiter.curly'
3963
+ }, {
3964
+ open: '[',
3965
+ close: ']',
3966
+ token: 'delimiter.square'
3967
+ }],
3968
+ keywords: keywords$3,
3969
+ builtinFunctions: builtinFunctions,
3970
+ operators: ['+', '-', '*', '/', '%', '^', '**', '==', '!=', '<', '>', '<=', '>=', '!', '&&', '||', '?:', '??', '.', '?.', 'in', 'matches', '..', '|'],
3971
+ escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,2}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
3972
+ digits: /\d+(_+\d+)*/,
3973
+ hexdigits: /[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,
3974
+ octdigits: /[0-7]+(_+[0-7]+)*/,
3975
+ bindigits: /[01]+(_+[01]+)*/,
3976
+ tokenizer: {
3977
+ root: [{
3978
+ include: '@whitespace'
3979
+ }, {
3980
+ include: '@comments'
3981
+ }, {
3982
+ include: '@numbers'
3983
+ }, {
3984
+ include: '@strings'
3985
+ }, {
3986
+ include: '@bytes'
3987
+ },
3988
+ // Function calls: identifier followed by '('
3989
+ [/[a-zA-Z_]\w*(?=\s*\()/, {
3990
+ cases: {
3991
+ '@builtinFunctions': 'keyword.function',
3992
+ '@default': 'identifier.function'
3993
+ }
3994
+ }],
3995
+ // Keywords and identifiers
3996
+ [/[a-zA-Z_]\w*/, {
3997
+ cases: {
3998
+ '@keywords': 'keyword',
3999
+ '@default': 'identifier'
4000
+ }
4001
+ }],
4002
+ // Operators
4003
+ [/[?][?:]/, 'operator'], [/[?][.]/, 'operator'], [/[.]{2}/, 'operator'], [/[*]{2}/, 'operator'], [/[|]/, 'operator'], [/[+\-*/%^]/, 'operator'], [/==|!=|<=|>=|<|>/, 'operator'], [/!|&&|\|\|/, 'operator'], [/[=]/, 'operator'], [/[.~]/, 'operator'],
4004
+ // Delimiters
4005
+ [/[,;]/, 'delimiter'], [/[{}()\[\]]/, '@brackets']],
4006
+ whitespace: [[/[ \t\r\n]+/, 'white']],
4007
+ comments: [[/\/\/.*$/, 'comment'], [/\/\*/, {
4008
+ token: 'comment.quote',
4009
+ next: '@comment'
4010
+ }]],
4011
+ comment: [[/[^*/]+/, 'comment'], [/\*\//, {
4012
+ token: 'comment.quote',
4013
+ next: '@pop'
4014
+ }], [/./, 'comment']],
4015
+ numbers: [[/0[xX]@hexdigits/, 'number.hex'], [/0[oO]@octdigits/, 'number.octal'], [/0[bB]@bindigits/, 'number.binary'], [/(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?/, 'number']],
4016
+ strings: [[/"/, {
4017
+ token: 'string.double',
4018
+ next: '@string_double'
4019
+ }], [/'/, {
4020
+ token: 'string',
4021
+ next: '@string_single'
4022
+ }], [/`/, {
4023
+ token: 'string.backtick',
4024
+ next: '@string_backtick'
4025
+ }]],
4026
+ string_double: [[/[^"\\]+/, 'string.double'], [/@escapes/, 'string.escape'], [/\\./, 'string.escape.invalid'], [/"/, {
4027
+ token: 'string.double',
4028
+ next: '@pop'
4029
+ }]],
4030
+ string_single: [[/[^'\\]+/, 'string'], [/@escapes/, 'string.escape'], [/\\./, 'string.escape.invalid'], [/'/, {
4031
+ token: 'string',
4032
+ next: '@pop'
4033
+ }]],
4034
+ string_backtick: [[/[^`]+/, 'string.backtick'], [/`/, {
4035
+ token: 'string.backtick',
4036
+ next: '@pop'
4037
+ }]],
4038
+ bytes: [[/[bB]"/, {
4039
+ token: 'string.bytes',
4040
+ next: '@bytes_double'
4041
+ }], [/[bB]'/, {
4042
+ token: 'string.bytes',
4043
+ next: '@bytes_single'
4044
+ }]],
4045
+ bytes_double: [[/[^"\\]+/, 'string.bytes'], [/\\(?:[abfnrtv\\"]|x[0-9A-Fa-f]{2}|[0-7]{3})/, 'string.escape'], [/\\./, 'string.escape.invalid'], [/"/, {
4046
+ token: 'string.bytes',
4047
+ next: '@pop'
4048
+ }]],
4049
+ bytes_single: [[/[^'\\]+/, 'string.bytes'], [/\\(?:[abfnrtv\\']|x[0-9A-Fa-f]{2}|[0-7]{3})/, 'string.escape'], [/\\./, 'string.escape.invalid'], [/'/, {
4050
+ token: 'string.bytes',
4051
+ next: '@pop'
4052
+ }]]
4053
+ }
4054
+ };
4055
+
4056
+ var EXPR_KEYWORDS = ['let', 'true', 'false', 'nil', 'in', 'not', 'and', 'or', 'if', 'else'];
4057
+ var EXPR_FUNCTIONS = [
4058
+ // String functions
4059
+ {
4060
+ name: 'trim',
4061
+ signature: 'trim(str[, chars])',
4062
+ description: 'Removes white spaces from both ends of a string',
4063
+ category: 'string'
4064
+ }, {
4065
+ name: 'trimPrefix',
4066
+ signature: 'trimPrefix(str, prefix)',
4067
+ description: 'Removes the specified prefix from the string',
4068
+ category: 'string'
4069
+ }, {
4070
+ name: 'trimSuffix',
4071
+ signature: 'trimSuffix(str, suffix)',
4072
+ description: 'Removes the specified suffix from the string',
4073
+ category: 'string'
4074
+ }, {
4075
+ name: 'upper',
4076
+ signature: 'upper(str)',
4077
+ description: 'Converts all characters to uppercase',
4078
+ category: 'string'
4079
+ }, {
4080
+ name: 'lower',
4081
+ signature: 'lower(str)',
4082
+ description: 'Converts all characters to lowercase',
4083
+ category: 'string'
4084
+ }, {
4085
+ name: 'split',
4086
+ signature: 'split(str, delimiter[, n])',
4087
+ description: 'Splits a string at each instance of the delimiter',
4088
+ category: 'string'
4089
+ }, {
4090
+ name: 'splitAfter',
4091
+ signature: 'splitAfter(str, delimiter[, n])',
4092
+ description: 'Splits a string after each instance of the delimiter',
4093
+ category: 'string'
4094
+ }, {
4095
+ name: 'replace',
4096
+ signature: 'replace(str, old, new)',
4097
+ description: 'Replaces all occurrences of old with new',
4098
+ category: 'string'
4099
+ }, {
4100
+ name: 'repeat',
4101
+ signature: 'repeat(str, n)',
4102
+ description: 'Repeats a string n times',
4103
+ category: 'string'
4104
+ }, {
4105
+ name: 'indexOf',
4106
+ signature: 'indexOf(str, substring)',
4107
+ description: 'Returns the index of the first occurrence of substring',
4108
+ category: 'string'
4109
+ }, {
4110
+ name: 'lastIndexOf',
4111
+ signature: 'lastIndexOf(str, substring)',
4112
+ description: 'Returns the index of the last occurrence of substring',
4113
+ category: 'string'
4114
+ }, {
4115
+ name: 'hasPrefix',
4116
+ signature: 'hasPrefix(str, prefix)',
4117
+ description: 'Returns true if string starts with the given prefix',
4118
+ category: 'string'
4119
+ }, {
4120
+ name: 'hasSuffix',
4121
+ signature: 'hasSuffix(str, suffix)',
4122
+ description: 'Returns true if string ends with the given suffix',
4123
+ category: 'string'
4124
+ }, {
4125
+ name: 'contains',
4126
+ signature: 'contains(str, substr)',
4127
+ description: 'Returns true if string contains the given substring',
4128
+ category: 'string'
4129
+ }, {
4130
+ name: 'startsWith',
4131
+ signature: 'startsWith(str, prefix)',
4132
+ description: 'Returns true if string starts with the given prefix',
4133
+ category: 'string'
4134
+ }, {
4135
+ name: 'endsWith',
4136
+ signature: 'endsWith(str, suffix)',
4137
+ description: 'Returns true if string ends with the given suffix',
4138
+ category: 'string'
4139
+ },
4140
+ // Date functions
4141
+ {
4142
+ name: 'now',
4143
+ signature: 'now()',
4144
+ description: 'Returns the current date as a time.Time value',
4145
+ category: 'date'
4146
+ }, {
4147
+ name: 'duration',
4148
+ signature: 'duration(str)',
4149
+ description: 'Returns time.Duration value of the given string',
4150
+ category: 'date'
4151
+ }, {
4152
+ name: 'date',
4153
+ signature: 'date(str[, format[, timezone]])',
4154
+ description: 'Converts the given string into a date representation',
4155
+ category: 'date'
4156
+ }, {
4157
+ name: 'timezone',
4158
+ signature: 'timezone(str)',
4159
+ description: 'Returns the timezone of the given string',
4160
+ category: 'date'
4161
+ },
4162
+ // Number functions
4163
+ {
4164
+ name: 'max',
4165
+ signature: 'max(n1, n2)',
4166
+ description: 'Returns the maximum of two numbers',
4167
+ category: 'number'
4168
+ }, {
4169
+ name: 'min',
4170
+ signature: 'min(n1, n2)',
4171
+ description: 'Returns the minimum of two numbers',
4172
+ category: 'number'
4173
+ }, {
4174
+ name: 'abs',
4175
+ signature: 'abs(n)',
4176
+ description: 'Returns the absolute value of a number',
4177
+ category: 'number'
4178
+ }, {
4179
+ name: 'ceil',
4180
+ signature: 'ceil(n)',
4181
+ description: 'Returns the least integer value greater than or equal to x',
4182
+ category: 'number'
4183
+ }, {
4184
+ name: 'floor',
4185
+ signature: 'floor(n)',
4186
+ description: 'Returns the greatest integer value less than or equal to x',
4187
+ category: 'number'
4188
+ }, {
4189
+ name: 'round',
4190
+ signature: 'round(n)',
4191
+ description: 'Returns the nearest integer, rounding half away from zero',
4192
+ category: 'number'
4193
+ },
4194
+ // Array functions
4195
+ {
4196
+ name: 'all',
4197
+ signature: 'all(array, predicate)',
4198
+ description: 'Returns true if all elements satisfy the predicate',
4199
+ category: 'array'
4200
+ }, {
4201
+ name: 'any',
4202
+ signature: 'any(array, predicate)',
4203
+ description: 'Returns true if any elements satisfy the predicate',
4204
+ category: 'array'
4205
+ }, {
4206
+ name: 'one',
4207
+ signature: 'one(array, predicate)',
4208
+ description: 'Returns true if exactly one element satisfies the predicate',
4209
+ category: 'array'
4210
+ }, {
4211
+ name: 'none',
4212
+ signature: 'none(array, predicate)',
4213
+ description: 'Returns true if no elements satisfy the predicate',
4214
+ category: 'array'
4215
+ }, {
4216
+ name: 'map',
4217
+ signature: 'map(array, predicate)',
4218
+ description: 'Returns new array by applying the predicate to each element',
4219
+ category: 'array'
4220
+ }, {
4221
+ name: 'filter',
4222
+ signature: 'filter(array, predicate)',
4223
+ description: 'Returns new array by filtering elements by predicate',
4224
+ category: 'array'
4225
+ }, {
4226
+ name: 'find',
4227
+ signature: 'find(array, predicate)',
4228
+ description: 'Finds the first element satisfying the predicate',
4229
+ category: 'array'
4230
+ }, {
4231
+ name: 'findIndex',
4232
+ signature: 'findIndex(array, predicate)',
4233
+ description: 'Finds the index of the first element satisfying the predicate',
4234
+ category: 'array'
4235
+ }, {
4236
+ name: 'findLast',
4237
+ signature: 'findLast(array, predicate)',
4238
+ description: 'Finds the last element satisfying the predicate',
4239
+ category: 'array'
4240
+ }, {
4241
+ name: 'findLastIndex',
4242
+ signature: 'findLastIndex(array, predicate)',
4243
+ description: 'Finds the index of the last element satisfying the predicate',
4244
+ category: 'array'
4245
+ }, {
4246
+ name: 'groupBy',
4247
+ signature: 'groupBy(array, predicate)',
4248
+ description: 'Groups elements by the result of the predicate',
4249
+ category: 'array'
4250
+ }, {
4251
+ name: 'count',
4252
+ signature: 'count(array[, predicate])',
4253
+ description: 'Returns the number of elements satisfying the predicate',
4254
+ category: 'array'
4255
+ }, {
4256
+ name: 'concat',
4257
+ signature: 'concat(array1, array2[, ...])',
4258
+ description: 'Concatenates two or more arrays',
4259
+ category: 'array'
4260
+ }, {
4261
+ name: 'flatten',
4262
+ signature: 'flatten(array)',
4263
+ description: 'Flattens an array into one-dimensional array',
4264
+ category: 'array'
4265
+ }, {
4266
+ name: 'uniq',
4267
+ signature: 'uniq(array)',
4268
+ description: 'Removes duplicates from an array',
4269
+ category: 'array'
4270
+ }, {
4271
+ name: 'join',
4272
+ signature: 'join(array[, delimiter])',
4273
+ description: 'Joins an array of strings into a single string',
4274
+ category: 'array'
4275
+ }, {
4276
+ name: 'reduce',
4277
+ signature: 'reduce(array, predicate[, initial])',
4278
+ description: 'Reduces an array to a single value',
4279
+ category: 'array'
4280
+ }, {
4281
+ name: 'sum',
4282
+ signature: 'sum(array[, predicate])',
4283
+ description: 'Returns the sum of all numbers in an array',
4284
+ category: 'array'
4285
+ }, {
4286
+ name: 'mean',
4287
+ signature: 'mean(array)',
4288
+ description: 'Returns the average of all numbers in an array',
4289
+ category: 'array'
4290
+ }, {
4291
+ name: 'median',
4292
+ signature: 'median(array)',
4293
+ description: 'Returns the median of all numbers in an array',
4294
+ category: 'array'
4295
+ }, {
4296
+ name: 'first',
4297
+ signature: 'first(array)',
4298
+ description: 'Returns the first element from an array',
4299
+ category: 'array'
4300
+ }, {
4301
+ name: 'last',
4302
+ signature: 'last(array)',
4303
+ description: 'Returns the last element from an array',
4304
+ category: 'array'
4305
+ }, {
4306
+ name: 'take',
4307
+ signature: 'take(array, n)',
4308
+ description: 'Returns the first n elements from an array',
4309
+ category: 'array'
4310
+ }, {
4311
+ name: 'reverse',
4312
+ signature: 'reverse(array)',
4313
+ description: 'Returns a new reversed copy of the array',
4314
+ category: 'array'
4315
+ }, {
4316
+ name: 'sort',
4317
+ signature: 'sort(array[, order])',
4318
+ description: 'Sorts an array in ascending or descending order',
4319
+ category: 'array'
4320
+ }, {
4321
+ name: 'sortBy',
4322
+ signature: 'sortBy(array[, predicate, order])',
4323
+ description: 'Sorts an array by the result of the predicate',
4324
+ category: 'array'
4325
+ },
4326
+ // Map functions
4327
+ {
4328
+ name: 'keys',
4329
+ signature: 'keys(map)',
4330
+ description: 'Returns an array containing the keys of the map',
4331
+ category: 'map'
4332
+ }, {
4333
+ name: 'values',
4334
+ signature: 'values(map)',
4335
+ description: 'Returns an array containing the values of the map',
4336
+ category: 'map'
4337
+ },
4338
+ // Type conversion functions
4339
+ {
4340
+ name: 'type',
4341
+ signature: 'type(v)',
4342
+ description: 'Returns the type of the given value',
4343
+ category: 'conversion'
4344
+ }, {
4345
+ name: 'int',
4346
+ signature: 'int(v)',
4347
+ description: 'Returns the integer value of a number or string',
4348
+ category: 'conversion'
4349
+ }, {
4350
+ name: 'float',
4351
+ signature: 'float(v)',
4352
+ description: 'Returns the float value of a number or string',
4353
+ category: 'conversion'
4354
+ }, {
4355
+ name: 'string',
4356
+ signature: 'string(v)',
4357
+ description: 'Converts a value to its string representation',
4358
+ category: 'conversion'
4359
+ }, {
4360
+ name: 'toJSON',
4361
+ signature: 'toJSON(v)',
4362
+ description: 'Converts a value to JSON string representation',
4363
+ category: 'conversion'
4364
+ }, {
4365
+ name: 'fromJSON',
4366
+ signature: 'fromJSON(v)',
4367
+ description: 'Parses a JSON string to a value',
4368
+ category: 'conversion'
4369
+ }, {
4370
+ name: 'toBase64',
4371
+ signature: 'toBase64(v)',
4372
+ description: 'Encodes a string into Base64 format',
4373
+ category: 'conversion'
4374
+ }, {
4375
+ name: 'fromBase64',
4376
+ signature: 'fromBase64(v)',
4377
+ description: 'Decodes a Base64 encoded string',
4378
+ category: 'conversion'
4379
+ }, {
4380
+ name: 'toPairs',
4381
+ signature: 'toPairs(map)',
4382
+ description: 'Converts a map to an array of key-value pairs',
4383
+ category: 'conversion'
4384
+ }, {
4385
+ name: 'fromPairs',
4386
+ signature: 'fromPairs(array)',
4387
+ description: 'Converts an array of key-value pairs to a map',
4388
+ category: 'conversion'
4389
+ },
4390
+ // Miscellaneous functions
4391
+ {
4392
+ name: 'len',
4393
+ signature: 'len(v)',
4394
+ description: 'Returns the length of an array, map, or string',
4395
+ category: 'misc'
4396
+ }, {
4397
+ name: 'get',
4398
+ signature: 'get(v, index)',
4399
+ description: 'Retrieves element at the specified index from an array or map',
4400
+ category: 'misc'
4401
+ },
4402
+ // Bitwise functions
4403
+ {
4404
+ name: 'bitand',
4405
+ signature: 'bitand(int, int)',
4406
+ description: 'Returns the bitwise AND of two integers',
4407
+ category: 'bitwise'
4408
+ }, {
4409
+ name: 'bitor',
4410
+ signature: 'bitor(int, int)',
4411
+ description: 'Returns the bitwise OR of two integers',
4412
+ category: 'bitwise'
4413
+ }, {
4414
+ name: 'bitxor',
4415
+ signature: 'bitxor(int, int)',
4416
+ description: 'Returns the bitwise XOR of two integers',
4417
+ category: 'bitwise'
4418
+ }, {
4419
+ name: 'bitnand',
4420
+ signature: 'bitnand(int, int)',
4421
+ description: 'Returns the bitwise AND NOT of two integers',
4422
+ category: 'bitwise'
4423
+ }, {
4424
+ name: 'bitnot',
4425
+ signature: 'bitnot(int)',
4426
+ description: 'Returns the bitwise NOT of an integer',
4427
+ category: 'bitwise'
4428
+ }, {
4429
+ name: 'bitshl',
4430
+ signature: 'bitshl(int, int)',
4431
+ description: 'Returns the Left Shift of an integer',
4432
+ category: 'bitwise'
4433
+ }, {
4434
+ name: 'bitshr',
4435
+ signature: 'bitshr(int, int)',
4436
+ description: 'Returns the Right Shift of an integer',
4437
+ category: 'bitwise'
4438
+ }, {
4439
+ name: 'bitushr',
4440
+ signature: 'bitushr(int, int)',
4441
+ description: 'Returns the unsigned Right Shift of an integer',
4442
+ category: 'bitwise'
4443
+ }];
4444
+ var getExprCompletionProvider = function getExprCompletionProvider() {
4445
+ return {
4446
+ provideCompletionItems: function provideCompletionItems(model, position, _context, _token) {
4447
+ var word = model.getWordUntilPosition(position);
4448
+ var range = new monaco.Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
4449
+ var suggestions = [].concat(EXPR_KEYWORDS.map(function (keyword) {
4450
+ return {
4451
+ label: keyword,
4452
+ kind: monaco.languages.CompletionItemKind.Keyword,
4453
+ insertText: keyword,
4454
+ range: range,
4455
+ sortText: '1' + keyword
4456
+ };
4457
+ }), EXPR_FUNCTIONS.map(function (func) {
4458
+ return {
4459
+ label: func.name,
4460
+ kind: monaco.languages.CompletionItemKind.Function,
4461
+ insertText: func.name,
4462
+ detail: func.signature,
4463
+ documentation: func.description + (" (" + func.category + ")"),
4464
+ range: range,
4465
+ sortText: '2' + func.name,
4466
+ insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
4467
+ };
4468
+ }));
4469
+ return {
4470
+ suggestions: suggestions
4471
+ };
4472
+ }
4473
+ };
4474
+ };
4475
+
4476
+ /**
4477
+ * Expr-lang token types and AST definitions
4478
+ */
4479
+ var TokenKind;
4480
+ (function (TokenKind) {
4481
+ TokenKind["Identifier"] = "Identifier";
4482
+ TokenKind["Number"] = "Number";
4483
+ TokenKind["String"] = "String";
4484
+ TokenKind["Operator"] = "Operator";
4485
+ TokenKind["Bracket"] = "Bracket";
4486
+ TokenKind["EOF"] = "EOF";
4487
+ })(TokenKind || (TokenKind = {}));
4488
+ var EOF_TOKEN = {
4489
+ kind: TokenKind.EOF,
4490
+ value: '',
4491
+ start: 0,
4492
+ end: 0,
4493
+ line: 0,
4494
+ column: 0
4495
+ };
4496
+ // Operator precedence (higher = binds tighter)
4497
+ var OPERATOR_PRECEDENCE = {
4498
+ '??': 1,
4499
+ '||': 2,
4500
+ or: 2,
4501
+ '&&': 3,
4502
+ and: 3,
4503
+ '==': 4,
4504
+ '!=': 4,
4505
+ '<': 5,
4506
+ '>': 5,
4507
+ '<=': 5,
4508
+ '>=': 5,
4509
+ "in": 5,
4510
+ matches: 5,
4511
+ contains: 5,
4512
+ startsWith: 5,
4513
+ endsWith: 5,
4514
+ '+': 6,
4515
+ '-': 6,
4516
+ '*': 7,
4517
+ '/': 7,
4518
+ '%': 7,
4519
+ '^': 8,
4520
+ '**': 8
4521
+ };
4522
+ // Unary operators
4523
+ var UNARY_OPERATORS = /*#__PURE__*/new Set(['!', 'not', '-']);
4524
+ // Comparison operators (for chained comparisons)
4525
+ var COMPARISON_OPERATORS = /*#__PURE__*/new Set(['<', '>', '<=', '>=', '==', '!=']);
4526
+
4527
+ // Tokens that should be treated as Operators even if they look like identifiers
4528
+ var OPERATOR_TOKENS = /*#__PURE__*/new Set(['let', 'if', 'else', 'not', 'and', 'or', 'in', 'matches', 'contains', 'startsWith', 'endsWith', 'hasPrefix', 'hasSuffix']);
4529
+ var Lexer = /*#__PURE__*/function () {
4530
+ function Lexer() {
4531
+ this.input = '';
4532
+ this.pos = 0;
4533
+ this.line = 1;
4534
+ this.column = 1;
4535
+ this.startLine = 1;
4536
+ this.startColumn = 1;
4537
+ }
4538
+ var _proto = Lexer.prototype;
4539
+ _proto.reset = function reset(input) {
4540
+ this.input = input;
4541
+ this.pos = 0;
4542
+ this.line = 1;
4543
+ this.column = 1;
4544
+ this.startLine = 1;
4545
+ this.startColumn = 1;
4546
+ };
4547
+ _proto.next = function next() {
4548
+ this.skipWhitespace();
4549
+ this.skipComments();
4550
+ if (this.pos >= this.input.length) {
4551
+ return _extends({}, EOF_TOKEN, {
4552
+ start: this.pos,
4553
+ end: this.pos,
4554
+ line: this.line,
4555
+ column: this.column
4556
+ });
4557
+ }
4558
+ this.startLine = this.line;
4559
+ this.startColumn = this.column;
4560
+ var ch = this.input[this.pos];
4561
+ // String literals
4562
+ if (ch === '"' || ch === "'") {
4563
+ return this.readString(ch);
4564
+ }
4565
+ if (ch === '`') {
4566
+ return this.readBacktickString();
4567
+ }
4568
+ // Byte literals: b"..." or b'...' or B"..." or B'...'
4569
+ if ((ch === 'b' || ch === 'B') && this.pos + 1 < this.input.length) {
4570
+ var _next = this.input[this.pos + 1];
4571
+ if (_next === '"' || _next === "'") {
4572
+ return this.readByteLiteral();
4573
+ }
4574
+ }
4575
+ // Numbers
4576
+ if (this.isDigit(ch) || ch === '.' && this.pos + 1 < this.input.length && this.isDigit(this.input[this.pos + 1])) {
4577
+ return this.readNumber();
4578
+ }
4579
+ // Identifiers and keywords
4580
+ if (this.isIdentStart(ch)) {
4581
+ var token = this.readIdentOrKeyword();
4582
+ return token;
4583
+ }
4584
+ // Operators and brackets
4585
+ return this.readOperatorOrBracket();
4586
+ };
4587
+ _proto.skipWhitespace = function skipWhitespace() {
4588
+ while (this.pos < this.input.length) {
4589
+ var ch = this.input[this.pos];
4590
+ if (ch === ' ' || ch === '\t' || ch === '\r') {
4591
+ this.pos++;
4592
+ this.column++;
4593
+ } else if (ch === '\n') {
4594
+ this.pos++;
4595
+ this.line++;
4596
+ this.column = 1;
4597
+ } else {
4598
+ break;
4599
+ }
4600
+ }
4601
+ };
4602
+ _proto.skipComments = function skipComments() {
4603
+ while (this.pos < this.input.length) {
4604
+ // Line comment //
4605
+ if (this.input[this.pos] === '/' && this.pos + 1 < this.input.length && this.input[this.pos + 1] === '/') {
4606
+ this.pos += 2;
4607
+ this.column += 2;
4608
+ while (this.pos < this.input.length && this.input[this.pos] !== '\n') {
4609
+ this.pos++;
4610
+ this.column++;
4611
+ }
4612
+ this.skipWhitespace();
4613
+ continue;
4614
+ }
4615
+ // Block comment /* */
4616
+ if (this.input[this.pos] === '/' && this.pos + 1 < this.input.length && this.input[this.pos + 1] === '*') {
4617
+ this.pos += 2;
4618
+ this.column += 2;
4619
+ while (this.pos < this.input.length) {
4620
+ if (this.input[this.pos] === '*' && this.pos + 1 < this.input.length && this.input[this.pos + 1] === '/') {
4621
+ this.pos += 2;
4622
+ this.column += 2;
4623
+ break;
4624
+ }
4625
+ if (this.input[this.pos] === '\n') {
4626
+ this.line++;
4627
+ this.column = 1;
4628
+ } else {
4629
+ this.column++;
4630
+ }
4631
+ this.pos++;
4632
+ }
4633
+ this.skipWhitespace();
4634
+ continue;
4635
+ }
4636
+ break;
4637
+ }
4638
+ };
4639
+ _proto.readString = function readString(quote) {
4640
+ var start = this.pos;
4641
+ this.pos++; // skip opening quote
4642
+ this.column++;
4643
+ var value = '';
4644
+ while (this.pos < this.input.length) {
4645
+ var ch = this.input[this.pos];
4646
+ if (ch === '\\') {
4647
+ if (this.pos + 1 >= this.input.length) break;
4648
+ var next = this.input[this.pos + 1];
4649
+ switch (next) {
4650
+ case 'n':
4651
+ value += '\n';
4652
+ break;
4653
+ case 't':
4654
+ value += '\t';
4655
+ break;
4656
+ case 'r':
4657
+ value += '\r';
4658
+ break;
4659
+ case '\\':
4660
+ value += '\\';
4661
+ break;
4662
+ case quote:
4663
+ value += quote;
4664
+ break;
4665
+ case 'x':
4666
+ {
4667
+ var hex = this.input.substr(this.pos + 2, 2);
4668
+ value += String.fromCharCode(parseInt(hex, 16));
4669
+ this.pos += 2;
4670
+ this.column += 2;
4671
+ break;
4672
+ }
4673
+ case 'u':
4674
+ {
4675
+ var unicode = this.input.substr(this.pos + 2, 4);
4676
+ value += String.fromCharCode(parseInt(unicode, 16));
4677
+ this.pos += 2;
4678
+ this.column += 2;
4679
+ break;
4680
+ }
4681
+ default:
4682
+ value += next;
4683
+ }
4684
+ this.pos += 2;
4685
+ this.column += 2;
4686
+ } else if (ch === quote) {
4687
+ this.pos++; // skip closing quote
4688
+ this.column++;
4689
+ return this.makeToken(TokenKind.String, value, start);
4690
+ } else {
4691
+ value += ch;
4692
+ this.pos++;
4693
+ this.column++;
4694
+ if (ch === '\n') {
4695
+ this.line++;
4696
+ this.column = 1;
4697
+ }
4698
+ }
4699
+ }
4700
+ return this.makeToken(TokenKind.String, value, start);
4701
+ };
4702
+ _proto.readBacktickString = function readBacktickString() {
4703
+ var start = this.pos;
4704
+ this.pos++; // skip opening backtick
4705
+ this.column++;
4706
+ var value = '';
4707
+ while (this.pos < this.input.length) {
4708
+ var ch = this.input[this.pos];
4709
+ if (ch === '`') {
4710
+ this.pos++;
4711
+ this.column++;
4712
+ return this.makeToken(TokenKind.String, value, start);
4713
+ }
4714
+ value += ch;
4715
+ this.pos++;
4716
+ if (ch === '\n') {
4717
+ this.line++;
4718
+ this.column = 1;
4719
+ } else {
4720
+ this.column++;
4721
+ }
4722
+ }
4723
+ return this.makeToken(TokenKind.String, value, start);
4724
+ };
4725
+ _proto.readByteLiteral = function readByteLiteral() {
4726
+ // b"..." or b'...' or B"..." or B'...'
4727
+ var start = this.pos;
4728
+ this.pos++; // skip 'b' or 'B'
4729
+ this.column++;
4730
+ var quote = this.input[this.pos];
4731
+ this.pos++; // skip quote
4732
+ this.column++;
4733
+ var value = '';
4734
+ while (this.pos < this.input.length) {
4735
+ var ch = this.input[this.pos];
4736
+ if (ch === '\\') {
4737
+ if (this.pos + 1 >= this.input.length) break;
4738
+ var next = this.input[this.pos + 1];
4739
+ switch (next) {
4740
+ case 'n':
4741
+ value += '\n';
4742
+ break;
4743
+ case 't':
4744
+ value += '\t';
4745
+ break;
4746
+ case 'r':
4747
+ value += '\r';
4748
+ break;
4749
+ case '\\':
4750
+ value += '\\';
4751
+ break;
4752
+ case quote:
4753
+ value += quote;
4754
+ break;
4755
+ case 'x':
4756
+ {
4757
+ var hex = this.input.substr(this.pos + 2, 2);
4758
+ value += String.fromCharCode(parseInt(hex, 16));
4759
+ this.pos += 2;
4760
+ this.column += 2;
4761
+ break;
4762
+ }
4763
+ default:
4764
+ // octal escape \NNN
4765
+ if (this.isDigit(next)) {
4766
+ var octal = this.input.substr(this.pos + 1, 3);
4767
+ value += String.fromCharCode(parseInt(octal, 8));
4768
+ this.pos += 2;
4769
+ this.column += 2;
4770
+ break;
4771
+ }
4772
+ value += next;
4773
+ }
4774
+ this.pos += 2;
4775
+ this.column += 2;
4776
+ } else if (ch === quote) {
4777
+ this.pos++;
4778
+ this.column++;
4779
+ return this.makeToken(TokenKind.String, value, start);
4780
+ } else {
4781
+ value += ch;
4782
+ this.pos++;
4783
+ this.column++;
4784
+ }
4785
+ }
4786
+ return this.makeToken(TokenKind.String, value, start);
4787
+ };
4788
+ _proto.readNumber = function readNumber() {
4789
+ var start = this.pos;
4790
+ var value = '';
4791
+ while (this.pos < this.input.length) {
4792
+ var ch = this.input[this.pos];
4793
+ if (this.isDigit(ch) || ch === '.' || ch === 'e' || ch === 'E' || ch === '+' || ch === '-' || ch === '_' || ch === 'x' || ch === 'X' || ch === 'o' || ch === 'O' || ch === 'b' || ch === 'B' || ch >= 'a' && ch <= 'f' || ch >= 'A' && ch <= 'F') {
4794
+ value += ch;
4795
+ this.pos++;
4796
+ this.column++;
4797
+ } else {
4798
+ break;
4799
+ }
4800
+ }
4801
+ return this.makeToken(TokenKind.Number, value, start);
4802
+ };
4803
+ _proto.readIdentOrKeyword = function readIdentOrKeyword() {
4804
+ var start = this.pos;
4805
+ var value = '';
4806
+ while (this.pos < this.input.length) {
4807
+ var ch = this.input[this.pos];
4808
+ if (this.isIdentPart(ch)) {
4809
+ value += ch;
4810
+ this.pos++;
4811
+ this.column++;
4812
+ } else {
4813
+ break;
4814
+ }
4815
+ }
4816
+ // Keywords that are operators
4817
+ if (OPERATOR_TOKENS.has(value)) {
4818
+ return this.makeToken(TokenKind.Operator, value, start);
4819
+ }
4820
+ return this.makeToken(TokenKind.Identifier, value, start);
4821
+ };
4822
+ _proto.readOperatorOrBracket = function readOperatorOrBracket() {
4823
+ var start = this.pos;
4824
+ var ch = this.input[this.pos];
4825
+ // Brackets
4826
+ if ('()[]{}'.includes(ch)) {
4827
+ this.pos++;
4828
+ this.column++;
4829
+ return this.makeToken(TokenKind.Bracket, ch, start);
4830
+ }
4831
+ // Multi-character operators
4832
+ var twoChar = this.input.substr(this.pos, 2);
4833
+ var threeChar = this.input.substr(this.pos, 3);
4834
+ // 3-character operators: **=
4835
+ // 2-character operators
4836
+ var twoCharOps = ['==', '!=', '<=', '>=', '&&', '||', '??', '?.', '..', '**', '//', '::', '->'];
4837
+ var threeCharOps = ['...', '<<=', '>>='];
4838
+ if (threeCharOps.includes(threeChar)) {
4839
+ this.pos += 3;
4840
+ this.column += 3;
4841
+ return this.makeToken(TokenKind.Operator, threeChar, start);
4842
+ }
4843
+ if (twoCharOps.includes(twoChar)) {
4844
+ this.pos += 2;
4845
+ this.column += 2;
4846
+ return this.makeToken(TokenKind.Operator, twoChar, start);
4847
+ }
4848
+ // Single-character operators and separators
4849
+ var singleCharOps = '+-*/%^=<>!&|?.,;:#@$~';
4850
+ if (singleCharOps.includes(ch)) {
4851
+ this.pos++;
4852
+ this.column++;
4853
+ return this.makeToken(TokenKind.Operator, ch, start);
4854
+ }
4855
+ // Unrecognized character
4856
+ this.pos++;
4857
+ this.column++;
4858
+ return this.makeToken(TokenKind.Operator, ch, start);
4859
+ };
4860
+ _proto.isDigit = function isDigit(ch) {
4861
+ return ch >= '0' && ch <= '9';
4862
+ };
4863
+ _proto.isIdentStart = function isIdentStart(ch) {
4864
+ return ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch === '_' || ch === '$';
4865
+ };
4866
+ _proto.isIdentPart = function isIdentPart(ch) {
4867
+ return this.isIdentStart(ch) || this.isDigit(ch);
4868
+ };
4869
+ _proto.makeToken = function makeToken(kind, value, start) {
4870
+ return {
4871
+ kind: kind,
4872
+ value: value,
4873
+ start: start,
4874
+ end: this.pos,
4875
+ line: this.startLine,
4876
+ column: this.startColumn
4877
+ };
4878
+ };
4879
+ return Lexer;
4880
+ }();
4881
+
4882
+ var ExprParser = /*#__PURE__*/function () {
4883
+ function ExprParser() {
4884
+ this.current = _extends({}, EOF_TOKEN);
4885
+ this.errors = [];
4886
+ this.lexer = new Lexer();
4887
+ }
4888
+ /**
4889
+ * Parse an expr-lang expression and return any syntax errors.
4890
+ * Returns empty array if the expression is valid.
4891
+ */
4892
+ var _proto = ExprParser.prototype;
4893
+ _proto.parse = function parse(input) {
4894
+ this.errors = [];
4895
+ this.lexer.reset(input);
4896
+ this.advance();
4897
+ if (input.trim().length === 0) {
4898
+ return [];
4899
+ }
4900
+ this.parseSequenceExpression();
4901
+ // Check for unexpected tokens at the end
4902
+ if (this.curKind() !== TokenKind.EOF && this.errors.length === 0) {
4903
+ this.error("unexpected token \"" + this.curVal() + "\"");
4904
+ }
4905
+ return this.errors;
4906
+ };
4907
+ _proto.advance = function advance() {
4908
+ this.current = this.lexer.next();
4909
+ };
4910
+ _proto.curKind = function curKind() {
4911
+ return this.current.kind;
4912
+ };
4913
+ _proto.curVal = function curVal() {
4914
+ return this.current.value;
4915
+ };
4916
+ _proto.expect = function expect(kind, value) {
4917
+ if (this.curKind() === kind && (value === undefined || this.curVal() === value)) {
4918
+ this.advance();
4919
+ return true;
4920
+ }
4921
+ if (value) {
4922
+ this.error("expected \"" + value + "\" but got \"" + this.curVal() + "\"");
4923
+ } else {
4924
+ this.error("unexpected token \"" + this.curVal() + "\"");
4925
+ }
4926
+ return false;
4927
+ };
4928
+ _proto.error = function error(message) {
4929
+ if (this.errors.length === 0) {
4930
+ // Calculate end position — approximate
4931
+ var endLine = this.current.line;
4932
+ var endColumn = this.current.column + this.curVal().length;
4933
+ this.errors.push({
4934
+ message: message,
4935
+ startLine: this.current.line,
4936
+ startColumn: this.current.column,
4937
+ endLine: endLine,
4938
+ endColumn: endColumn
4939
+ });
4940
+ }
4941
+ };
4942
+ _proto.errorAt = function errorAt(token, message) {
4943
+ if (this.errors.length === 0) {
4944
+ var endColumn = token.column + token.value.length;
4945
+ this.errors.push({
4946
+ message: message,
4947
+ startLine: token.line,
4948
+ startColumn: token.column,
4949
+ endLine: token.line,
4950
+ endColumn: endColumn
4951
+ });
4952
+ }
4953
+ }
4954
+ // ========== Parsing Functions ==========
4955
+ /**
4956
+ * parseSequenceExpression parses multiple expressions separated by semicolons.
4957
+ */;
4958
+ _proto.parseSequenceExpression = function parseSequenceExpression() {
4959
+ if (this.errors.length > 0) return;
4960
+ this.parseExpression(0);
4961
+ while (this.curVal() === ';' && this.errors.length === 0) {
4962
+ this.advance();
4963
+ if (this.curKind() === TokenKind.EOF) break;
4964
+ this.parseExpression(0);
4965
+ }
4966
+ }
4967
+ /**
4968
+ * parseExpression uses precedence climbing to parse binary expressions.
4969
+ */;
4970
+ _proto.parseExpression = function parseExpression(precedence) {
4971
+ if (this.errors.length > 0) return;
4972
+ // Handle "let" at precedence 0
4973
+ if (precedence === 0 && this.curVal() === 'let') {
4974
+ this.parseVariableDeclaration();
4975
+ return;
4976
+ }
4977
+ // Handle "if" at precedence 0
4978
+ if (precedence === 0 && this.curVal() === 'if') {
4979
+ this.parseConditionalIf();
4980
+ return;
4981
+ }
4982
+ // Handle unary operators
4983
+ if (UNARY_OPERATORS.has(this.curVal()) && this.curKind() === TokenKind.Operator) {
4984
+ var unaryToken = this.current;
4985
+ this.advance();
4986
+ if (this.curKind() === TokenKind.EOF) {
4987
+ this.errorAt(unaryToken, 'unexpected token EOF');
4988
+ return;
4989
+ }
4990
+ if (this.errors.length > 0) return;
4991
+ this.parsePrimary();
4992
+ if (this.errors.length > 0) return;
4993
+ this.parsePostfixExpression();
4994
+ return;
4995
+ }
4996
+ this.parsePrimary();
4997
+ if (this.errors.length > 0) return;
4998
+ this.parsePostfixExpression();
4999
+ if (this.errors.length > 0) return;
5000
+ // Handle binary operators with precedence climbing
5001
+ while (this.curKind() === TokenKind.Operator && this.errors.length === 0) {
5002
+ var op = this.curVal();
5003
+ var opToken = this.current;
5004
+ // Handle pipe operator |
5005
+ if (op === '|') {
5006
+ this.advance(); // skip |
5007
+ if (this.curKind() === TokenKind.EOF) {
5008
+ this.errorAt(opToken, 'unexpected token EOF');
5009
+ return;
5010
+ }
5011
+ if (this.curKind() === TokenKind.Identifier) {
5012
+ this.advance(); // skip identifier
5013
+ this.parseArguments();
5014
+ if (this.curVal() === ';') break;
5015
+ continue;
5016
+ }
5017
+ this.error("expected identifier after pipe \"|\" but got \"" + this.curVal() + "\"");
5018
+ return;
5019
+ }
5020
+ // Handle semicolon — end of this expression
5021
+ if (op === ';') break;
5022
+ // Check precedence
5023
+ var opPrec = OPERATOR_PRECEDENCE[op];
5024
+ if (opPrec === undefined || opPrec < precedence) break;
5025
+ // Handle "not" prefix for "not in", "not contains", etc.
5026
+ if (op === 'not') {
5027
+ this.advance();
5028
+ var nextOp = this.curVal();
5029
+ var negatedPrec = OPERATOR_PRECEDENCE[nextOp];
5030
+ if (negatedPrec !== undefined && negatedPrec >= precedence) {
5031
+ this.advance();
5032
+ this.parseExpression(negatedPrec + 1);
5033
+ continue;
5034
+ }
5035
+ this.error("unexpected token \"" + nextOp + "\" after \"not\"");
5036
+ return;
5037
+ }
5038
+ // Handle chained comparisons: a < b < c => (a < b) && (b < c)
5039
+ if (COMPARISON_OPERATORS.has(op)) {
5040
+ this.advance();
5041
+ if (this.curKind() === TokenKind.EOF) {
5042
+ this.errorAt(opToken, 'unexpected token EOF');
5043
+ return;
5044
+ }
5045
+ this.parseExpression(opPrec + 1);
5046
+ // Keep parsing chained comparisons
5047
+ while (this.curKind() === TokenKind.Operator && COMPARISON_OPERATORS.has(this.curVal()) && this.errors.length === 0) {
5048
+ var chainOpToken = this.current;
5049
+ this.advance();
5050
+ if (this.curKind() === TokenKind.EOF) {
5051
+ this.errorAt(chainOpToken, 'unexpected token EOF');
5052
+ return;
5053
+ }
5054
+ this.parseExpression((OPERATOR_PRECEDENCE[this.curVal()] || 0) + 1);
5055
+ }
5056
+ continue;
5057
+ }
5058
+ this.advance();
5059
+ if (this.curKind() === TokenKind.EOF) {
5060
+ this.errorAt(opToken, 'unexpected token EOF');
5061
+ return;
5062
+ }
5063
+ // Right-associative operators bind to the right
5064
+ // For simplicity, parse with same precedence for right-assoc
5065
+ this.parseExpression(opPrec + 1);
5066
+ // Handle ternary ? :
5067
+ if (precedence === 0 && this.curVal() === '?') {
5068
+ this.parseConditional();
5069
+ }
5070
+ }
5071
+ // Handle ternary ? : at precedence 0
5072
+ if (precedence === 0 && this.curVal() === '?') {
5073
+ this.parseConditional();
5074
+ }
5075
+ }
5076
+ /**
5077
+ * parsePrimary handles unary operators, parentheses, and the #/. pointer prefix.
5078
+ */;
5079
+ _proto.parsePrimary = function parsePrimary() {
5080
+ if (this.errors.length > 0) return;
5081
+ // Unary operators are handled in parseExpression
5082
+ // Parenthesized expression
5083
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === '(') {
5084
+ this.advance(); // skip (
5085
+ this.parseSequenceExpression();
5086
+ if (!this.expect(TokenKind.Bracket, ')')) {
5087
+ return;
5088
+ }
5089
+ return;
5090
+ }
5091
+ // Handle # or . prefix (in predicates)
5092
+ if ((this.curVal() === '#' || this.curVal() === '.') && this.curKind() === TokenKind.Operator) {
5093
+ this.advance();
5094
+ if (this.curKind() === TokenKind.Identifier) {
5095
+ this.advance();
5096
+ }
5097
+ this.parsePostfixExpression();
5098
+ return;
5099
+ }
5100
+ this.parseSecondary();
5101
+ }
5102
+ /**
5103
+ * parseSecondary handles identifiers, literals, arrays, and maps.
5104
+ */;
5105
+ _proto.parseSecondary = function parseSecondary() {
5106
+ if (this.errors.length > 0) return;
5107
+ var token = this.current;
5108
+ switch (token.kind) {
5109
+ case TokenKind.Identifier:
5110
+ {
5111
+ this.advance();
5112
+ // Check for function call
5113
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === '(') {
5114
+ this.parseArguments();
5115
+ }
5116
+ break;
5117
+ }
5118
+ case TokenKind.Number:
5119
+ {
5120
+ this.advance();
5121
+ break;
5122
+ }
5123
+ case TokenKind.String:
5124
+ {
5125
+ this.advance();
5126
+ break;
5127
+ }
5128
+ case TokenKind.Bracket:
5129
+ {
5130
+ if (token.value === '[') {
5131
+ this.parseArrayExpression();
5132
+ } else if (token.value === '{') {
5133
+ this.parseMapExpression();
5134
+ } else {
5135
+ this.error("unexpected token \"" + token.value + "\"");
5136
+ }
5137
+ break;
5138
+ }
5139
+ default:
5140
+ this.error("unexpected token \"" + token.value + "\"");
5141
+ break;
5142
+ }
5143
+ }
5144
+ /**
5145
+ * parsePostfixExpression handles .member, ?.member, [index], [from:to], and calls after the primary.
5146
+ */;
5147
+ _proto.parsePostfixExpression = function parsePostfixExpression() {
5148
+ while (this.errors.length === 0) {
5149
+ var token = this.current;
5150
+ // .member or ?.member
5151
+ if (token.kind === TokenKind.Operator && (token.value === '.' || token.value === '?.')) {
5152
+ this.advance();
5153
+ // After . or ?., expect an identifier (or operator like "not" that can be a method name)
5154
+ if (this.curKind() === TokenKind.Identifier || this.curKind() === TokenKind.Operator) {
5155
+ this.advance();
5156
+ // Check for method call: obj.method()
5157
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === '(') {
5158
+ this.parseArguments();
5159
+ }
5160
+ } else if (this.curKind() === TokenKind.Bracket && this.curVal() === '[' && token.value === '?.') {
5161
+ // obj?[index] — handle bracket after ?.
5162
+ this.advance();
5163
+ this.parseExpression(0);
5164
+ this.expect(TokenKind.Bracket, ']');
5165
+ } else {
5166
+ this.error("expected property name after \"" + token.value + "\" but got \"" + this.curVal() + "\"");
5167
+ return;
5168
+ }
5169
+ continue;
5170
+ }
5171
+ // [index] or [from:to]
5172
+ if (token.kind === TokenKind.Bracket && token.value === '[') {
5173
+ this.advance();
5174
+ // Check for slice: [:] or [:to]
5175
+ if (this.curKind() === TokenKind.Operator && this.curVal() === ':') {
5176
+ this.advance();
5177
+ if (this.curKind() !== TokenKind.Bracket || this.curVal() !== ']') {
5178
+ this.parseExpression(0);
5179
+ }
5180
+ this.expect(TokenKind.Bracket, ']');
5181
+ } else {
5182
+ // Index expression
5183
+ this.parseExpression(0);
5184
+ // Check for slice: [from:]
5185
+ if (this.curKind() === TokenKind.Operator && this.curVal() === ':') {
5186
+ this.advance();
5187
+ if (this.curKind() !== TokenKind.Bracket || this.curVal() !== ']') {
5188
+ this.parseExpression(0);
5189
+ }
5190
+ }
5191
+ this.expect(TokenKind.Bracket, ']');
5192
+ }
5193
+ continue;
5194
+ }
5195
+ // Function call after member access
5196
+ if (token.kind === TokenKind.Bracket && token.value === '(') {
5197
+ this.parseArguments();
5198
+ continue;
5199
+ }
5200
+ break;
5201
+ }
5202
+ }
5203
+ /**
5204
+ * parseVariableDeclaration parses "let name = value; rest"
5205
+ */;
5206
+ _proto.parseVariableDeclaration = function parseVariableDeclaration() {
5207
+ this.expect(TokenKind.Operator, 'let');
5208
+ if (this.errors.length > 0) return;
5209
+ if (this.curKind() !== TokenKind.Identifier) {
5210
+ this.error("expected variable name after \"let\" but got \"" + this.curVal() + "\"");
5211
+ return;
5212
+ }
5213
+ this.advance(); // skip variable name
5214
+ if (!this.expect(TokenKind.Operator, '=')) return;
5215
+ this.parseExpression(0);
5216
+ if (this.errors.length > 0) return;
5217
+ // Optional semicolon after value
5218
+ if (this.curVal() === ';') {
5219
+ this.advance();
5220
+ if (this.curKind() !== TokenKind.EOF) {
5221
+ this.parseSequenceExpression();
5222
+ }
5223
+ }
5224
+ }
5225
+ /**
5226
+ * parseConditionalIf parses "if expr { expr1 } else { expr2 }" or "if expr { expr1 } else if ..."
5227
+ */;
5228
+ _proto.parseConditionalIf = function parseConditionalIf() {
5229
+ this.advance(); // skip 'if'
5230
+ if (this.errors.length > 0) return;
5231
+ this.parseExpression(0);
5232
+ if (this.errors.length > 0) return;
5233
+ if (!this.expect(TokenKind.Bracket, '{')) return;
5234
+ this.parseSequenceExpression();
5235
+ if (this.errors.length > 0) return;
5236
+ if (!this.expect(TokenKind.Bracket, '}')) return;
5237
+ if (!this.expect(TokenKind.Operator, 'else')) return;
5238
+ // Nested if
5239
+ if (this.curVal() === 'if') {
5240
+ this.parseConditionalIf();
5241
+ return;
5242
+ }
5243
+ if (!this.expect(TokenKind.Bracket, '{')) return;
5244
+ this.parseSequenceExpression();
5245
+ if (this.errors.length > 0) return;
5246
+ this.expect(TokenKind.Bracket, '}');
5247
+ }
5248
+ /**
5249
+ * parseConditional parses "expr ? expr1 : expr2" or "expr ?: expr2"
5250
+ */;
5251
+ _proto.parseConditional = function parseConditional() {
5252
+ if (this.curVal() !== '?') return;
5253
+ this.advance(); // skip ?
5254
+ // Elvis operator ?:
5255
+ if (this.curVal() === ':') {
5256
+ this.advance();
5257
+ this.parseExpression(0);
5258
+ return;
5259
+ }
5260
+ this.parseExpression(0);
5261
+ if (this.errors.length > 0) return;
5262
+ if (!this.expect(TokenKind.Operator, ':')) return;
5263
+ this.parseExpression(0);
5264
+ }
5265
+ /**
5266
+ * parseArguments parses function call arguments: (arg1, arg2, ...)
5267
+ */;
5268
+ _proto.parseArguments = function parseArguments() {
5269
+ if (!this.expect(TokenKind.Bracket, '(')) return;
5270
+ while (this.curKind() !== TokenKind.Bracket || this.curVal() !== ')') {
5271
+ if (this.curKind() === TokenKind.EOF) {
5272
+ this.error('unexpected end of expression, expected ")"');
5273
+ return;
5274
+ }
5275
+ if (this.curVal() === ',') {
5276
+ this.advance();
5277
+ continue;
5278
+ }
5279
+ // Check for predicate { ... } argument
5280
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === '{') {
5281
+ this.advance();
5282
+ this.parseSequenceExpression();
5283
+ this.expect(TokenKind.Bracket, '}');
5284
+ } else {
5285
+ this.parseExpression(0);
5286
+ }
5287
+ if (this.errors.length > 0) return;
5288
+ if (this.curVal() === ',') {
5289
+ this.advance();
5290
+ // Allow trailing comma
5291
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === ')') {
5292
+ break;
5293
+ }
5294
+ }
5295
+ }
5296
+ this.expect(TokenKind.Bracket, ')');
5297
+ }
5298
+ /**
5299
+ * parseArrayExpression parses "[elem1, elem2, ...]"
5300
+ */;
5301
+ _proto.parseArrayExpression = function parseArrayExpression() {
5302
+ this.expect(TokenKind.Bracket, '[');
5303
+ if (this.errors.length > 0) return;
5304
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === ']') {
5305
+ this.advance();
5306
+ return;
5307
+ }
5308
+ while (this.errors.length === 0) {
5309
+ this.parseExpression(0);
5310
+ if (this.errors.length > 0) return;
5311
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === ']') {
5312
+ break;
5313
+ }
5314
+ if (this.curVal() === ',') {
5315
+ this.advance();
5316
+ // Allow trailing comma
5317
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === ']') {
5318
+ break;
5319
+ }
5320
+ continue;
5321
+ }
5322
+ this.error("expected \",\" or \"]\" but got \"" + this.curVal() + "\"");
5323
+ return;
5324
+ }
5325
+ this.expect(TokenKind.Bracket, ']');
5326
+ }
5327
+ /**
5328
+ * parseMapExpression parses "{key: value, ...}"
5329
+ */;
5330
+ _proto.parseMapExpression = function parseMapExpression() {
5331
+ this.expect(TokenKind.Bracket, '{');
5332
+ if (this.errors.length > 0) return;
5333
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === '}') {
5334
+ this.advance();
5335
+ return;
5336
+ }
5337
+ while (this.errors.length === 0) {
5338
+ // Key: identifier, string, number, or parenthesized expression
5339
+ if (this.curKind() === TokenKind.Identifier || this.curKind() === TokenKind.String || this.curKind() === TokenKind.Number) {
5340
+ this.advance();
5341
+ } else if (this.curKind() === TokenKind.Bracket && this.curVal() === '(') {
5342
+ this.advance();
5343
+ this.parseExpression(0);
5344
+ this.expect(TokenKind.Bracket, ')');
5345
+ } else {
5346
+ this.error("map key must be a string, number, identifier, or parenthesized expression, got \"" + this.curVal() + "\"");
5347
+ return;
5348
+ }
5349
+ if (!this.expect(TokenKind.Operator, ':')) return;
5350
+ this.parseExpression(0);
5351
+ if (this.errors.length > 0) return;
5352
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === '}') {
5353
+ break;
5354
+ }
5355
+ if (this.curVal() === ',') {
5356
+ this.advance();
5357
+ if (this.curKind() === TokenKind.Bracket && this.curVal() === '}') {
5358
+ break;
5359
+ }
5360
+ continue;
5361
+ }
5362
+ this.error("expected \",\" or \"}\" but got \"" + this.curVal() + "\"");
5363
+ return;
5364
+ }
5365
+ this.expect(TokenKind.Bracket, '}');
5366
+ };
5367
+ return ExprParser;
5368
+ }();
5369
+
5370
+ var EXPR_LANG_ID = 'expr';
5371
+ var parser = /*#__PURE__*/new ExprParser();
5372
+ /**
5373
+ * Validate an expr-lang expression and return Monaco editor markers.
5374
+ * Uses the recursive descent parser for syntax errors,
5375
+ * plus regex-based checks for structural issues like unbalanced quotes/brackets.
5376
+ */
5377
+ var validateExpr = function validateExpr(expr) {
5378
+ var markers = [];
5379
+ if (!expr || expr.trim().length === 0) {
5380
+ return markers;
5381
+ }
5382
+ // 1. Parser-based syntax validation
5383
+ var parseErrors = parser.parse(expr);
5384
+ for (var _iterator = _createForOfIteratorHelperLoose(parseErrors), _step; !(_step = _iterator()).done;) {
5385
+ var err = _step.value;
5386
+ markers.push({
5387
+ severity: monaco.MarkerSeverity.Error,
5388
+ startLineNumber: err.startLine,
5389
+ startColumn: err.startColumn,
5390
+ endLineNumber: err.endLine,
5391
+ endColumn: err.endColumn,
5392
+ message: err.message
5393
+ });
5394
+ }
5395
+ // 2. Line-level structural checks (fallback for issues the parser might miss)
5396
+ var structuralMarkers = validateLineLevel(expr);
5397
+ markers.push.apply(markers, structuralMarkers);
5398
+ return markers;
5399
+ };
5400
+ /**
5401
+ * Basic line-level validation for quotes and bracket balancing.
5402
+ */
5403
+ function validateLineLevel(expr) {
5404
+ var markers = [];
5405
+ var lines = expr.split('\n');
5406
+ var inBlockComment = false;
5407
+ lines.forEach(function (line, index) {
5408
+ var lineNumber = index + 1;
5409
+ // Track block comment state
5410
+ if (!inBlockComment) {
5411
+ var blockCommentStart = line.indexOf('/*');
5412
+ if (blockCommentStart !== -1) {
5413
+ var blockCommentEnd = line.indexOf('*/', blockCommentStart + 2);
5414
+ if (blockCommentEnd === -1) {
5415
+ inBlockComment = true;
5416
+ }
5417
+ }
5418
+ } else {
5419
+ var _blockCommentEnd = line.indexOf('*/');
5420
+ if (_blockCommentEnd !== -1) {
5421
+ inBlockComment = false;
5422
+ }
5423
+ if (inBlockComment || line.trim().startsWith('/*')) {
5424
+ return;
5425
+ }
5426
+ }
5427
+ var trimmedLine = line.trim();
5428
+ if (trimmedLine.startsWith('//') || trimmedLine.startsWith('/*')) {
5429
+ return;
5430
+ }
5431
+ // Check for unclosed quotes
5432
+ var singleQuotes = countQuotesOutsideBlockComments(line);
5433
+ if (singleQuotes % 2 !== 0) {
5434
+ markers.push({
5435
+ severity: monaco.MarkerSeverity.Warning,
5436
+ startLineNumber: lineNumber,
5437
+ startColumn: 1,
5438
+ endLineNumber: lineNumber,
5439
+ endColumn: line.length + 1,
5440
+ message: "Unclosed single quote '",
5441
+ source: EXPR_LANG_ID
5442
+ });
5443
+ }
5444
+ var doubleQuotes = countDoubleQuotesOutsideBlockComments(line);
5445
+ if (doubleQuotes % 2 !== 0) {
5446
+ markers.push({
5447
+ severity: monaco.MarkerSeverity.Warning,
5448
+ startLineNumber: lineNumber,
5449
+ startColumn: 1,
5450
+ endLineNumber: lineNumber,
5451
+ endColumn: line.length + 1,
5452
+ message: 'Unclosed double quote "',
5453
+ source: EXPR_LANG_ID
5454
+ });
5455
+ }
5456
+ var backticks = (line.match(/`/g) || []).length;
5457
+ if (backticks % 2 !== 0) {
5458
+ markers.push({
5459
+ severity: monaco.MarkerSeverity.Warning,
5460
+ startLineNumber: lineNumber,
5461
+ startColumn: 1,
5462
+ endLineNumber: lineNumber,
5463
+ endColumn: line.length + 1,
5464
+ message: 'Unclosed backtick `',
5465
+ source: EXPR_LANG_ID
5466
+ });
5467
+ }
5468
+ // Check for unbalanced brackets
5469
+ var openParens = (line.match(/\(/g) || []).length;
5470
+ var closeParens = (line.match(/\)/g) || []).length;
5471
+ if (openParens > closeParens) {
5472
+ markers.push({
5473
+ severity: monaco.MarkerSeverity.Warning,
5474
+ startLineNumber: lineNumber,
5475
+ startColumn: 1,
5476
+ endLineNumber: lineNumber,
5477
+ endColumn: line.length + 1,
5478
+ message: 'Unmatched opening parenthesis',
5479
+ source: EXPR_LANG_ID
5480
+ });
5481
+ } else if (closeParens > openParens) {
5482
+ markers.push({
5483
+ severity: monaco.MarkerSeverity.Warning,
5484
+ startLineNumber: lineNumber,
5485
+ startColumn: 1,
5486
+ endLineNumber: lineNumber,
5487
+ endColumn: line.length + 1,
5488
+ message: 'Unmatched closing parenthesis',
5489
+ source: EXPR_LANG_ID
5490
+ });
5491
+ }
5492
+ var openBrackets = (line.match(/\[/g) || []).length;
5493
+ var closeBrackets = (line.match(/\]/g) || []).length;
5494
+ if (openBrackets > closeBrackets) {
5495
+ markers.push({
5496
+ severity: monaco.MarkerSeverity.Warning,
5497
+ startLineNumber: lineNumber,
5498
+ startColumn: 1,
5499
+ endLineNumber: lineNumber,
5500
+ endColumn: line.length + 1,
5501
+ message: 'Unmatched opening bracket',
5502
+ source: EXPR_LANG_ID
5503
+ });
5504
+ } else if (closeBrackets > openBrackets) {
5505
+ markers.push({
5506
+ severity: monaco.MarkerSeverity.Warning,
5507
+ startLineNumber: lineNumber,
5508
+ startColumn: 1,
5509
+ endLineNumber: lineNumber,
5510
+ endColumn: line.length + 1,
5511
+ message: 'Unmatched closing bracket',
5512
+ source: EXPR_LANG_ID
5513
+ });
5514
+ }
5515
+ var openBraces = (line.match(/\{/g) || []).length;
5516
+ var closeBraces = (line.match(/\}/g) || []).length;
5517
+ if (openBraces > closeBraces) {
5518
+ markers.push({
5519
+ severity: monaco.MarkerSeverity.Warning,
5520
+ startLineNumber: lineNumber,
5521
+ startColumn: 1,
5522
+ endLineNumber: lineNumber,
5523
+ endColumn: line.length + 1,
5524
+ message: 'Unmatched opening curly brace',
5525
+ source: EXPR_LANG_ID
5526
+ });
5527
+ } else if (closeBraces > openBraces) {
5528
+ markers.push({
5529
+ severity: monaco.MarkerSeverity.Warning,
5530
+ startLineNumber: lineNumber,
5531
+ startColumn: 1,
5532
+ endLineNumber: lineNumber,
5533
+ endColumn: line.length + 1,
5534
+ message: 'Unmatched closing curly brace',
5535
+ source: EXPR_LANG_ID
5536
+ });
5537
+ }
5538
+ });
5539
+ return markers;
5540
+ }
5541
+ function countQuotesOutsideBlockComments(line) {
5542
+ var withoutBlockComments = line.replace(/\/\*[\s\S]*?\*\//g, '');
5543
+ return (withoutBlockComments.match(/'/g) || []).length;
5544
+ }
5545
+ function countDoubleQuotesOutsideBlockComments(line) {
5546
+ var withoutBlockComments = line.replace(/\/\*[\s\S]*?\*\//g, '');
5547
+ return (withoutBlockComments.match(/"/g) || []).length;
5548
+ }
5549
+
5550
+ var _templateObject$3, _templateObject2$3;
5551
+ var EXPR_LANG_ID$1 = 'expr';
5552
+ var SIZE_MAP$3 = {
5553
+ small: {
5554
+ className: 'ant-input-sm',
5555
+ top: 1,
5556
+ bottom: 1,
5557
+ minHeight: 24
5558
+ },
5559
+ middle: {
5560
+ className: 'ant-input-md',
5561
+ top: 1,
5562
+ bottom: 1,
5563
+ minHeight: 32
5564
+ },
5565
+ large: {
5566
+ className: 'ant-input-lg',
5567
+ top: 3,
5568
+ bottom: 2,
5569
+ minHeight: 40
5570
+ }
5571
+ };
5572
+ var themeMap$3 = {
5573
+ light: 'expr-light',
5574
+ dark: 'expr-dark'
5575
+ };
5576
+ var containerDisabledClassName$3 = /*#__PURE__*/css.css(_templateObject$3 || (_templateObject$3 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n .monaco-editor {\n user-select: none;\n pointer-events: none;\n }\n"])));
5577
+ var containerReadOnlyClassName$3 = /*#__PURE__*/css.css(_templateObject2$3 || (_templateObject2$3 = /*#__PURE__*/_taggedTemplateLiteralLoose(["\n .monaco-editor .cursors-layer > .cursor {\n opacity: 0 !important;\n }\n"])));
5578
+ function ExprEditor(props) {
5579
+ var id = uuid.v4();
5580
+ var className = props.className,
5581
+ maxHeight = props.maxHeight,
5582
+ fontSize = props.fontSize,
5583
+ _props$size = props.size,
5584
+ size = _props$size === void 0 ? 'middle' : _props$size,
5585
+ _props$theme = props.theme,
5586
+ theme = _props$theme === void 0 ? 'light' : _props$theme,
5587
+ _props$value = props.value,
5588
+ value = _props$value === void 0 ? '' : _props$value,
5589
+ placeholder = props.placeholder,
5590
+ _props$enableAutocomp = props.enableAutocomplete,
5591
+ enableAutocomplete = _props$enableAutocomp === void 0 ? true : _props$enableAutocomp,
5592
+ _props$readOnly = props.readOnly,
5593
+ readOnly = _props$readOnly === void 0 ? false : _props$readOnly,
5594
+ _props$disabled = props.disabled,
5595
+ disabled = _props$disabled === void 0 ? false : _props$disabled,
5596
+ onChange = props.onChange,
5597
+ onEnter = props.onEnter,
5598
+ onBlur = props.onBlur,
5599
+ onFocus = props.onFocus,
5600
+ editorDidMount = props.editorDidMount;
5601
+ var containerRef = React.useRef(null);
5602
+ var editorRef = React.useRef(null);
5603
+ var modelRef = React.useRef(null);
5604
+ var disposablesRef = React.useRef([]);
5605
+ React.useEffect(function () {
5606
+ // Register language
5607
+ if (!monaco.languages.getLanguages().some(function (lang) {
5608
+ return lang.id === EXPR_LANG_ID$1;
5609
+ })) {
5610
+ monaco.languages.register({
5611
+ id: EXPR_LANG_ID$1
5612
+ });
5613
+ monaco.languages.setMonarchTokensProvider(EXPR_LANG_ID$1, language$3);
5614
+ monaco.languages.setLanguageConfiguration(EXPR_LANG_ID$1, languageConfiguration$3);
5615
+ }
5616
+ // Register completion provider
5617
+ if (enableAutocomplete) {
5618
+ var disposable = monaco.languages.registerCompletionItemProvider(EXPR_LANG_ID$1, getExprCompletionProvider());
5619
+ disposablesRef.current.push(disposable);
5620
+ }
5621
+ return function () {
5622
+ disposablesRef.current.forEach(function (disposable) {
5623
+ return disposable.dispose();
5624
+ });
5625
+ disposablesRef.current = [];
5626
+ };
5627
+ }, [enableAutocomplete]);
5628
+ var handleEditorMount = function handleEditorMount(editor) {
5629
+ editorRef.current = editor;
5630
+ modelRef.current = editor.getModel();
5631
+ monaco.editor.defineTheme('expr-light', {
5632
+ base: 'vs',
5633
+ inherit: true,
5634
+ rules: [],
5635
+ colors: {
5636
+ 'editor.background': '#00000000',
5637
+ focusBorder: '#00000000'
5638
+ }
5639
+ });
5640
+ monaco.editor.defineTheme('expr-dark', {
5641
+ base: 'vs-dark',
5642
+ inherit: true,
5643
+ rules: [],
5644
+ colors: {
5645
+ 'editor.background': '#00000000',
5646
+ focusBorder: '#00000000'
5647
+ }
5648
+ });
5649
+ var isEditorFocused = editor.createContextKey('isEditorFocused' + id, false);
5650
+ editor.onDidBlurEditorWidget(function () {
5651
+ isEditorFocused.set(false);
5652
+ onBlur == null || onBlur(editor.getValue());
5653
+ var position = editor.getPosition();
5654
+ if (position) {
5655
+ var newSelection = new monaco.Selection(position.lineNumber, position.column, position.lineNumber, position.column);
5656
+ editor.setSelection(newSelection);
5657
+ }
5658
+ });
5659
+ editor.onDidFocusEditorText(function () {
5660
+ isEditorFocused.set(true);
5661
+ onFocus == null || onFocus(editor.getValue());
5662
+ });
5663
+ // Auto-height
5664
+ var updateElementHeight = function updateElementHeight() {
5665
+ var containerDiv = containerRef.current;
5666
+ if (containerDiv !== null) {
5667
+ var pixelHeight = editor.getContentHeight();
5668
+ containerDiv.style.minHeight = pixelHeight + "px";
5669
+ containerDiv.style.width = '100%';
5670
+ var pixelWidth = containerDiv.clientWidth;
5671
+ editor.layout({
5672
+ width: pixelWidth,
5673
+ height: pixelHeight
5674
+ });
5675
+ }
5676
+ };
5677
+ editor.onDidContentSizeChange(updateElementHeight);
5678
+ updateElementHeight();
5679
+ // Disable search box
5680
+ monaco.editor.addKeybindingRule({
5681
+ keybinding: monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyF,
5682
+ command: null
5683
+ });
5684
+ // Shift+Enter for newline
5685
+ editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, function () {
5686
+ var position = editor.getPosition();
5687
+ if (position) {
5688
+ editor.executeEdits('shift-enter', [{
5689
+ range: new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column),
5690
+ text: '\n'
5691
+ }]);
5692
+ editor.setPosition({
5693
+ lineNumber: position.lineNumber + 1,
5694
+ column: 1
5695
+ });
5696
+ }
5697
+ }, 'isEditorFocused' + id);
5698
+ // Prevent default Enter
5699
+ monaco.editor.addKeybindingRule({
5700
+ keybinding: monaco.KeyCode.Enter,
5701
+ command: '-',
5702
+ when: '!suggestWidgetVisible'
5703
+ });
5704
+ // Custom Enter handler
5705
+ editor.addCommand(monaco.KeyCode.Enter, function () {
5706
+ onEnter == null || onEnter(editor.getValue());
5707
+ }, '!suggestWidgetVisible && isEditorFocused' + id);
5708
+ // Setup validation on content change using decorations (no marker hover clutter)
5709
+ var model = editor.getModel();
5710
+ var errorDecorations = [];
5711
+ if (model) {
5712
+ var updateDecorations = function updateDecorations() {
5713
+ var exprValue = model.getValue();
5714
+ var markers = validateExpr(exprValue);
5715
+ var newDecorations = markers.map(function (m) {
5716
+ return {
5717
+ range: new monaco.Range(m.startLineNumber, m.startColumn, m.endLineNumber, m.endColumn),
5718
+ options: {
5719
+ className: 'expr-error-squiggly',
5720
+ hoverMessage: {
5721
+ value: m.message
5722
+ },
5723
+ minimap: {
5724
+ color: '#e51400',
5725
+ position: 1
5726
+ },
5727
+ overviewRuler: {
5728
+ color: '#e51400',
5729
+ position: monaco.editor.OverviewRulerLane.Right
5730
+ }
5731
+ }
5732
+ };
5733
+ });
5734
+ errorDecorations = model.deltaDecorations(errorDecorations, newDecorations);
5735
+ };
5736
+ var validateDisposable = model.onDidChangeContent(updateDecorations);
5737
+ disposablesRef.current.push(validateDisposable);
5738
+ // Run initial validation
5739
+ updateDecorations();
5740
+ }
5741
+ // Inject CSS for the red squiggly underline
5742
+ var styleEl = document.createElement('style');
5743
+ styleEl.textContent = "\n .expr-error-squiggly {\n background: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 6 3' preserveAspectRatio='none'%3E%3Cpath d='M0,2.5 L1.5,1 L3,2.5 L4.5,1 L6,2.5' stroke='%23e51400' stroke-width='0.6' fill='none'/%3E%3C/svg%3E\") repeat-x left bottom;\n background-size: 6px 3px;\n padding-bottom: 3px;\n }\n ";
5744
+ document.head.appendChild(styleEl);
5745
+ disposablesRef.current.push({
5746
+ dispose: function dispose() {
5747
+ return styleEl.remove();
5748
+ }
5749
+ });
5750
+ editorDidMount == null || editorDidMount(editor);
5751
+ };
5752
+ var handleChange = function handleChange(newValue, _e) {
5753
+ onChange == null || onChange(newValue);
5754
+ };
5755
+ var themeValue = themeMap$3[theme];
5756
+ return React__default.createElement("div", {
5757
+ className: 'ant-input' + (size ? " " + SIZE_MAP$3[size].className : '') + (disabled ? " ant-input-disabled " + containerDisabledClassName$3 : '') + (readOnly ? " " + containerReadOnlyClassName$3 : '') + (className ? " " + className : ''),
5758
+ style: {
5759
+ display: 'block',
5760
+ resize: 'vertical',
5761
+ overflow: 'auto',
5762
+ minHeight: SIZE_MAP$3[size].minHeight,
5763
+ maxHeight: maxHeight
5764
+ }
5765
+ }, React__default.createElement("div", {
5766
+ ref: containerRef,
5767
+ style: {
5768
+ height: '100%'
5769
+ }
5770
+ }, React__default.createElement(MonacoEditor, {
5771
+ language: EXPR_LANG_ID$1,
5772
+ theme: themeValue,
5773
+ value: value,
5774
+ onChange: handleChange,
5775
+ options: {
5776
+ placeholder: placeholder,
5777
+ selectOnLineNumbers: true,
5778
+ fontSize: fontSize || 12,
5779
+ roundedSelection: false,
5780
+ scrollBeyondLastLine: false,
5781
+ readOnly: readOnly || disabled,
5782
+ minimap: {
5783
+ enabled: false
5784
+ },
5785
+ lineNumbers: 'off',
5786
+ lineNumbersMinChars: 0,
5787
+ glyphMargin: false,
5788
+ folding: false,
5789
+ lineDecorationsWidth: 0,
5790
+ overviewRulerLanes: 0,
5791
+ overviewRulerBorder: false,
5792
+ hideCursorInOverviewRuler: true,
5793
+ hover: {
5794
+ enabled: true,
5795
+ delay: 200
5796
+ },
5797
+ fixedOverflowWidgets: true,
5798
+ renderLineHighlight: 'none',
5799
+ renderValidationDecorations: 'on',
5800
+ scrollbar: {
5801
+ vertical: 'hidden',
5802
+ horizontal: 'auto'
5803
+ },
5804
+ automaticLayout: true,
5805
+ wordWrap: 'on'
5806
+ },
5807
+ editorDidMount: handleEditorMount
5808
+ })));
5809
+ }
5810
+
5811
+ exports.ExprMonacoEditor = ExprEditor;
3829
5812
  exports.PromQLMonacoEditor = PromQLEditor;
3830
5813
  exports.SqlMonacoEditor = SqlEditor;
3831
5814
  exports.YamlMonacoEditor = YamlEditor;