language.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import type * as monacoType from 'monaco-editor/esm/vs/editor/editor.api';
  2. // Metric Math: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/using-metric-math.html
  3. export const METRIC_MATH_FNS = [
  4. 'ABS',
  5. 'ANOMALY_DETECTION_BAND',
  6. 'AVG',
  7. 'CEIL',
  8. 'DATAPOINT_COUNT',
  9. 'DIFF',
  10. 'DIFF_TIME',
  11. 'FILL',
  12. 'FIRST',
  13. 'LAST',
  14. 'FLOOR',
  15. 'IF',
  16. 'INSIGHT_RULE_METRIC',
  17. 'LOG',
  18. 'LOG10',
  19. 'MAX',
  20. 'METRIC_COUNT',
  21. 'METRICS',
  22. 'MIN',
  23. 'MINUTE',
  24. 'HOUR',
  25. 'DAY',
  26. 'DATE',
  27. 'MONTH',
  28. 'YEAR',
  29. 'EPOCH',
  30. 'PERIOD',
  31. 'RATE',
  32. 'REMOVE_EMPTY',
  33. 'RUNNING_SUM',
  34. 'SEARCH',
  35. 'SERVICE_QUOTA',
  36. 'SLICE',
  37. 'SORT',
  38. 'STDDEV',
  39. 'SUM',
  40. 'TIME_SERIES',
  41. ];
  42. export const METRIC_MATH_STATISTIC_KEYWORD_STRINGS = ['Average', 'Maximum', 'Minimum', 'Sum', 'SampleCount']; // second arguments to SEARCH function
  43. export const METRIC_MATH_KEYWORDS = ['REPEAT', 'LINEAR', 'ASC', 'DSC']; // standalone magic arguments to functions
  44. export const METRIC_MATH_OPERATORS = [
  45. '+',
  46. '-',
  47. '*',
  48. '/',
  49. '^',
  50. '==',
  51. '!=',
  52. '<=',
  53. '>=',
  54. '<',
  55. '>',
  56. 'AND',
  57. '&&',
  58. 'OR',
  59. '||',
  60. ];
  61. export const METRIC_MATH_PERIODS = [10, 60, 300, 900, 3000, 21600, 86400];
  62. export const language: monacoType.languages.IMonarchLanguage = {
  63. id: 'metricMath',
  64. ignoreCase: false,
  65. brackets: [
  66. { open: '[', close: ']', token: 'delimiter.square' },
  67. { open: '(', close: ')', token: 'delimiter.parenthesis' },
  68. { open: '{', close: '}', token: 'delimiter.curly' },
  69. ],
  70. tokenizer: {
  71. root: [{ include: '@nonNestableStates' }, { include: '@strings' }],
  72. nonNestableStates: [
  73. { include: '@variables' },
  74. { include: '@whitespace' },
  75. { include: '@numbers' },
  76. { include: '@assignment' },
  77. { include: '@keywords' },
  78. { include: '@operators' },
  79. { include: '@builtInFunctions' },
  80. [/[;,.]/, 'delimiter'],
  81. [/[(){}\[\]]/, '@brackets'], // [], (), {} are all brackets
  82. ],
  83. keywords: [[METRIC_MATH_KEYWORDS.map(escapeRegExp).join('|'), 'keyword']],
  84. operators: [[METRIC_MATH_OPERATORS.map(escapeRegExp).join('|'), 'operator']],
  85. builtInFunctions: [[METRIC_MATH_FNS.map(escapeRegExp).join('|'), 'predefined']],
  86. variables: [
  87. [/\$[a-zA-Z0-9-_]+/, 'variable'], // $ followed by any letter/number we assume could be grafana template variable
  88. ],
  89. whitespace: [[/\s+/, 'white']],
  90. assignment: [[/=/, 'tag']],
  91. numbers: [
  92. [/0[xX][0-9a-fA-F]*/, 'number'],
  93. [/[$][+-]*\d*(\.\d*)?/, 'number'],
  94. [/((\d+(\.\d*)?)|(\.\d+))([eE][\-+]?\d+)?/, 'number'],
  95. ],
  96. // states that start other states (aka nested states):
  97. strings: [
  98. [/'/, { token: 'string', next: '@string' }],
  99. [/"/, { token: 'type', next: '@string_double' }],
  100. ],
  101. string: [
  102. [/{/, { token: 'delimiter.curly', next: '@nestedCurly' }], // escape out of string and into nestedCurly
  103. [/\(/, { token: 'delimiter.parenthesis', next: '@nestedParens' }], // escape out of string and into nestedCurly
  104. [/"/, { token: 'type', next: '@string_double' }], // jump into double string
  105. [/'/, { token: 'string', next: '@pop' }], // stop being a string
  106. { include: '@nonNestableStates' },
  107. [/[^']/, 'string'], // anything that is not a quote, is marked as string
  108. ],
  109. string_double: [
  110. [/[^"]/, 'type'], // mark anything not a quote as a "type" (different type of string for visual difference)
  111. [/"/, { token: 'type', next: '@pop' }], // mark also as a type and stop being in the double string state
  112. ],
  113. nestedCurly: [
  114. [/}/, { token: 'delimiter.curly', next: '@pop' }], // escape out of string and into braces
  115. [/'/, { token: 'string', next: '@string' }], // go to string if see start of string
  116. [/"/, { token: 'type', next: '@string_double' }], // go to string_double if see start of double string
  117. ],
  118. nestedParens: [
  119. [/\)/, { token: 'delimiter.parenthesis', next: '@pop' }], // escape out of string and into braces
  120. [/'/, { token: 'string', next: '@string' }], // go to string if see start of string
  121. [/"/, { token: 'type', next: '@string_double' }], // go to string_double if see start of double string
  122. ],
  123. },
  124. };
  125. export const conf: monacoType.languages.LanguageConfiguration = {
  126. brackets: [
  127. ['{', '}'],
  128. ['[', ']'],
  129. ['(', ')'],
  130. ],
  131. autoClosingPairs: [
  132. { open: '{', close: '}' },
  133. { open: '[', close: ']' },
  134. { open: '(', close: ')' },
  135. { open: '"', close: '"' },
  136. { open: "'", close: "'" },
  137. ],
  138. surroundingPairs: [
  139. { open: '{', close: '}' },
  140. { open: '[', close: ']' },
  141. { open: '(', close: ')' },
  142. { open: '"', close: '"' },
  143. { open: "'", close: "'" },
  144. ],
  145. };
  146. function escapeRegExp(string: string) {
  147. return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
  148. }