@perses-dev/loki-plugin 0.5.0-rc.0 → 0.5.0

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 (153) hide show
  1. package/__mf/js/{Loki.21b585d6.js → Loki.2bd94c1e.js} +3 -3
  2. package/__mf/js/async/1728.326f0c08.js +1 -0
  3. package/__mf/js/async/1750.eba509e1.js +1 -0
  4. package/__mf/js/async/392.2c7c202d.js +2 -0
  5. package/__mf/js/async/54.b3492a7a.js +22 -0
  6. package/__mf/js/async/5440.995ad0c5.js +2 -0
  7. package/__mf/js/async/{5440.3fedd5ea.js.LICENSE.txt → 5440.995ad0c5.js.LICENSE.txt} +3 -3
  8. package/__mf/js/async/6710.a94fd362.js +2 -0
  9. package/__mf/js/async/7958.f25f7332.js +7 -0
  10. package/__mf/js/async/9010.44bf2927.js +2 -0
  11. package/__mf/js/async/{1238.71fd7843.js → 9249.d90da2ad.js} +1 -1
  12. package/__mf/js/async/9389.29616aa6.js +2 -0
  13. package/__mf/js/async/9877.b76d1711.js +38 -0
  14. package/__mf/js/async/{__federation_expose_LokiDatasource.44ac1fa6.js → __federation_expose_LokiDatasource.3fe6141d.js} +2 -2
  15. package/__mf/js/async/{__federation_expose_LokiLogQuery.22f7c517.js → __federation_expose_LokiLogQuery.6591d0db.js} +1 -1
  16. package/__mf/js/async/{__federation_expose_LokiTimeSeriesQuery.4909566f.js → __federation_expose_LokiTimeSeriesQuery.2a9b451a.js} +1 -1
  17. package/__mf/js/{main.59f3d316.js → main.4d84b446.js} +3 -3
  18. package/lib/bootstrap.js +12 -0
  19. package/lib/bootstrap.js.map +1 -1
  20. package/lib/cjs/bootstrap.js +12 -0
  21. package/lib/cjs/components/complete.js +260 -34
  22. package/lib/cjs/components/index.js +1 -1
  23. package/lib/cjs/components/logql-editor.js +1 -1
  24. package/lib/cjs/components/logql-extension.js +1 -1
  25. package/lib/cjs/components/logql-highlight.js +1 -1
  26. package/lib/cjs/datasources/index.js +1 -1
  27. package/lib/cjs/datasources/loki-datasource/LokiDatasource.js +1 -1
  28. package/lib/cjs/datasources/loki-datasource/LokiDatasourceEditor.js +1 -1
  29. package/lib/cjs/datasources/loki-datasource/index.js +1 -1
  30. package/lib/cjs/datasources/loki-datasource/loki-datasource-types.js +1 -1
  31. package/lib/cjs/env.d.js +12 -0
  32. package/lib/cjs/getPluginModule.js +12 -0
  33. package/lib/cjs/index-federation.js +12 -0
  34. package/lib/cjs/index.js +12 -0
  35. package/lib/cjs/model/index.js +1 -1
  36. package/lib/cjs/model/loki-client-types.js +1 -1
  37. package/lib/cjs/model/loki-client.js +1 -1
  38. package/lib/cjs/model/loki-data-types.js +1 -1
  39. package/lib/cjs/model/loki-selectors.js +1 -1
  40. package/lib/cjs/queries/constants.js +12 -0
  41. package/lib/cjs/queries/index.js +1 -1
  42. package/lib/cjs/queries/loki-log-query/LokiLogQuery.js +12 -0
  43. package/lib/cjs/queries/loki-log-query/LokiLogQueryEditor.js +1 -1
  44. package/lib/cjs/queries/loki-log-query/get-loki-log-data.js +12 -0
  45. package/lib/cjs/queries/loki-log-query/index.js +12 -0
  46. package/lib/cjs/queries/loki-log-query/log-query-plugin-interface.js +12 -0
  47. package/lib/cjs/queries/loki-log-query/loki-log-query-types.js +12 -0
  48. package/lib/cjs/queries/loki-time-series-query/LokiTimeSeriesQuery.js +1 -1
  49. package/lib/cjs/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.js +1 -1
  50. package/lib/cjs/queries/loki-time-series-query/get-loki-time-series-data.js +1 -1
  51. package/lib/cjs/queries/loki-time-series-query/index.js +1 -1
  52. package/lib/cjs/queries/loki-time-series-query/loki-time-series-query-types.js +1 -1
  53. package/lib/cjs/queries/query-editor-model.js +1 -1
  54. package/lib/cjs/setup-tests.js +12 -0
  55. package/lib/components/complete.d.ts +5 -0
  56. package/lib/components/complete.d.ts.map +1 -1
  57. package/lib/components/complete.js +259 -33
  58. package/lib/components/complete.js.map +1 -1
  59. package/lib/components/index.js +1 -1
  60. package/lib/components/index.js.map +1 -1
  61. package/lib/components/logql-editor.js +1 -1
  62. package/lib/components/logql-editor.js.map +1 -1
  63. package/lib/components/logql-extension.js +1 -1
  64. package/lib/components/logql-extension.js.map +1 -1
  65. package/lib/components/logql-highlight.js +1 -1
  66. package/lib/components/logql-highlight.js.map +1 -1
  67. package/lib/datasources/index.js +1 -1
  68. package/lib/datasources/index.js.map +1 -1
  69. package/lib/datasources/loki-datasource/LokiDatasource.js +1 -1
  70. package/lib/datasources/loki-datasource/LokiDatasource.js.map +1 -1
  71. package/lib/datasources/loki-datasource/LokiDatasourceEditor.js +1 -1
  72. package/lib/datasources/loki-datasource/LokiDatasourceEditor.js.map +1 -1
  73. package/lib/datasources/loki-datasource/index.js +1 -1
  74. package/lib/datasources/loki-datasource/index.js.map +1 -1
  75. package/lib/datasources/loki-datasource/loki-datasource-types.js +1 -1
  76. package/lib/datasources/loki-datasource/loki-datasource-types.js.map +1 -1
  77. package/lib/env.d.js +12 -0
  78. package/lib/env.d.js.map +1 -1
  79. package/lib/getPluginModule.d.ts.map +1 -1
  80. package/lib/getPluginModule.js +12 -0
  81. package/lib/getPluginModule.js.map +1 -1
  82. package/lib/index-federation.js +12 -0
  83. package/lib/index-federation.js.map +1 -1
  84. package/lib/index.d.ts.map +1 -1
  85. package/lib/index.js +12 -0
  86. package/lib/index.js.map +1 -1
  87. package/lib/model/index.js +1 -1
  88. package/lib/model/index.js.map +1 -1
  89. package/lib/model/loki-client-types.js +1 -1
  90. package/lib/model/loki-client-types.js.map +1 -1
  91. package/lib/model/loki-client.js +1 -1
  92. package/lib/model/loki-client.js.map +1 -1
  93. package/lib/model/loki-data-types.js +1 -1
  94. package/lib/model/loki-data-types.js.map +1 -1
  95. package/lib/model/loki-selectors.js +1 -1
  96. package/lib/model/loki-selectors.js.map +1 -1
  97. package/lib/queries/constants.d.ts.map +1 -1
  98. package/lib/queries/constants.js +12 -0
  99. package/lib/queries/constants.js.map +1 -1
  100. package/lib/queries/index.js +1 -1
  101. package/lib/queries/index.js.map +1 -1
  102. package/lib/queries/loki-log-query/LokiLogQuery.d.ts.map +1 -1
  103. package/lib/queries/loki-log-query/LokiLogQuery.js +12 -0
  104. package/lib/queries/loki-log-query/LokiLogQuery.js.map +1 -1
  105. package/lib/queries/loki-log-query/LokiLogQueryEditor.js +1 -1
  106. package/lib/queries/loki-log-query/LokiLogQueryEditor.js.map +1 -1
  107. package/lib/queries/loki-log-query/get-loki-log-data.d.ts.map +1 -1
  108. package/lib/queries/loki-log-query/get-loki-log-data.js +12 -0
  109. package/lib/queries/loki-log-query/get-loki-log-data.js.map +1 -1
  110. package/lib/queries/loki-log-query/index.d.ts.map +1 -1
  111. package/lib/queries/loki-log-query/index.js +12 -0
  112. package/lib/queries/loki-log-query/index.js.map +1 -1
  113. package/lib/queries/loki-log-query/log-query-plugin-interface.d.ts.map +1 -1
  114. package/lib/queries/loki-log-query/log-query-plugin-interface.js +12 -0
  115. package/lib/queries/loki-log-query/log-query-plugin-interface.js.map +1 -1
  116. package/lib/queries/loki-log-query/loki-log-query-types.d.ts.map +1 -1
  117. package/lib/queries/loki-log-query/loki-log-query-types.js +12 -0
  118. package/lib/queries/loki-log-query/loki-log-query-types.js.map +1 -1
  119. package/lib/queries/loki-time-series-query/LokiTimeSeriesQuery.js +1 -1
  120. package/lib/queries/loki-time-series-query/LokiTimeSeriesQuery.js.map +1 -1
  121. package/lib/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.js +1 -1
  122. package/lib/queries/loki-time-series-query/LokiTimeSeriesQueryEditor.js.map +1 -1
  123. package/lib/queries/loki-time-series-query/get-loki-time-series-data.js +1 -1
  124. package/lib/queries/loki-time-series-query/get-loki-time-series-data.js.map +1 -1
  125. package/lib/queries/loki-time-series-query/index.js +1 -1
  126. package/lib/queries/loki-time-series-query/index.js.map +1 -1
  127. package/lib/queries/loki-time-series-query/loki-time-series-query-types.js +1 -1
  128. package/lib/queries/loki-time-series-query/loki-time-series-query-types.js.map +1 -1
  129. package/lib/queries/query-editor-model.js +1 -1
  130. package/lib/queries/query-editor-model.js.map +1 -1
  131. package/lib/setup-tests.d.ts.map +1 -1
  132. package/lib/setup-tests.js +12 -0
  133. package/lib/setup-tests.js.map +1 -1
  134. package/mf-manifest.json +46 -46
  135. package/mf-stats.json +46 -46
  136. package/package.json +6 -6
  137. package/__mf/js/async/1490.5aa6cbcc.js +0 -22
  138. package/__mf/js/async/1501.f1011a16.js +0 -1
  139. package/__mf/js/async/1728.516fcaaf.js +0 -1
  140. package/__mf/js/async/3849.89f86737.js +0 -7
  141. package/__mf/js/async/392.c0f9d49a.js +0 -2
  142. package/__mf/js/async/5440.3fedd5ea.js +0 -2
  143. package/__mf/js/async/5501.929e6257.js +0 -2
  144. package/__mf/js/async/6498.903f2a94.js +0 -2
  145. package/__mf/js/async/8035.8dab4893.js +0 -38
  146. package/__mf/js/async/9389.a8ea42a0.js +0 -2
  147. /package/__mf/js/async/{392.c0f9d49a.js.LICENSE.txt → 392.2c7c202d.js.LICENSE.txt} +0 -0
  148. /package/__mf/js/async/{1490.5aa6cbcc.js.LICENSE.txt → 54.b3492a7a.js.LICENSE.txt} +0 -0
  149. /package/__mf/js/async/{6498.903f2a94.js.LICENSE.txt → 6710.a94fd362.js.LICENSE.txt} +0 -0
  150. /package/__mf/js/async/{3849.89f86737.js.LICENSE.txt → 7958.f25f7332.js.LICENSE.txt} +0 -0
  151. /package/__mf/js/async/{5501.929e6257.js.LICENSE.txt → 9010.44bf2927.js.LICENSE.txt} +0 -0
  152. /package/__mf/js/async/{9389.a8ea42a0.js.LICENSE.txt → 9389.29616aa6.js.LICENSE.txt} +0 -0
  153. /package/__mf/js/async/{__federation_expose_LokiDatasource.44ac1fa6.js.LICENSE.txt → __federation_expose_LokiDatasource.3fe6141d.js.LICENSE.txt} +0 -0
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -1,3 +1,15 @@
1
+ // Copyright The Perses Authors
2
+ // Licensed under the Apache License, Version 2.0 (the \"License\");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an \"AS IS\" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
1
13
  "use strict";
2
14
  Object.defineProperty(exports, "__esModule", {
3
15
  value: true
@@ -9,6 +9,11 @@ type CompletionScope = {
9
9
  } | {
10
10
  kind: 'LabelValue';
11
11
  label: string;
12
+ } | {
13
+ kind: 'PipeFunction';
14
+ afterPipe: boolean;
15
+ hasSpace: boolean;
16
+ afterExclamation: boolean;
12
17
  };
13
18
  /**
14
19
  * CompletionInfo specifies the identified scope and position of the completion in the current editor text.
@@ -1 +1 @@
1
- {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/components/complete.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAwB,MAAM,0BAA0B,CAAC;AAEjH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,oGAAoG;AACpG,KAAK,eAAe,GAAG;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAErF;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,eAAe,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAKD,wBAAsB,QAAQ,CAC5B,aAAa,EAAE,gBAAgB,EAC/B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,iBAAiB,GAChC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAWlC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,cAAc,GAAG,SAAS,CA6G1G;AAkDD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAmB9G"}
1
+ {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/components/complete.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAwB,MAAM,0BAA0B,CAAC;AAEjH,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAc,IAAI,EAAE,MAAM,eAAe,CAAC;AAajD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,oGAAoG;AACpG,KAAK,eAAe,GAChB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAA;CAAE,CAAC;AAE/F;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,eAAe,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAMD,wBAAsB,QAAQ,CAC5B,aAAa,EAAE,gBAAgB,EAC/B,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,iBAAiB,GAChC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAWlC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,cAAc,GAAG,SAAS,CA6D1G;AA8SD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAmB9G"}
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -12,13 +12,14 @@
12
12
  // limitations under the License.
13
13
  import { insertCompletionText } from '@codemirror/autocomplete';
14
14
  import { syntaxTree } from '@codemirror/language';
15
- import { Selector, Matchers, Matcher, Identifier, Eq, Neq, Re, Nre, String as StringType } from '@grafana/lezer-logql';
16
- import { toUnixSeconds } from '../model/loki-client';
15
+ import { Selector, Matchers, Matcher, Identifier, Eq, Neq, Re, Nre, String as StringType, Pipe } from '@grafana/lezer-logql';
16
+ import { toUnixSeconds } from '../model';
17
17
  const quoteChars = [
18
18
  '"',
19
19
  '`'
20
20
  ];
21
21
  const defaultQuoteChar = '"';
22
+ const ERROR_NODE = 0; // Lezer parser creates error nodes for incomplete/malformed syntax
22
23
  export async function complete(completionCfg, { state, pos }) {
23
24
  // First, identify the completion scope
24
25
  const completion = identifyCompletion(state, pos, syntaxTree(state));
@@ -40,12 +41,98 @@ export async function complete(completionCfg, { state, pos }) {
40
41
  * Function is exported for tests only.
41
42
  */ export function identifyCompletion(state, pos, tree) {
42
43
  const node = tree.resolveInner(pos, -1);
44
+ switch(node.type.id){
45
+ case Selector:
46
+ case Matchers:
47
+ case Matcher:
48
+ case Identifier:
49
+ case Eq:
50
+ case Neq:
51
+ case Re:
52
+ case Nre:
53
+ case StringType:
54
+ {
55
+ const labelCompletion = detectLabelCompletion(state, pos, node);
56
+ if (labelCompletion) return labelCompletion;
57
+ break;
58
+ }
59
+ case ERROR_NODE:
60
+ {
61
+ // Check for pipe context first
62
+ const pipeCompletion = detectPipeCompletion(state, node);
63
+ if (pipeCompletion) return pipeCompletion;
64
+ // Then check for label completion in error nodes
65
+ const labelCompletion = detectLabelCompletion(state, pos, node);
66
+ if (labelCompletion) return labelCompletion;
67
+ break;
68
+ }
69
+ case Pipe:
70
+ {
71
+ // Pipe operator: suggest parser functions and line filters
72
+ // Examples: {job="nginx"} |▯ or {job="nginx"} | ▯
73
+ const hasSpaceAfterPipe = state.sliceDoc(pos - 1, pos) === ' ';
74
+ return {
75
+ scope: {
76
+ kind: 'PipeFunction',
77
+ afterPipe: true,
78
+ hasSpace: hasSpaceAfterPipe,
79
+ afterExclamation: false
80
+ },
81
+ from: pos
82
+ };
83
+ }
84
+ }
85
+ // Fallback checks for contexts not directly on a node
86
+ const textBeforeCursor = state.sliceDoc(0, pos).trim();
87
+ const hasSpace = state.sliceDoc(pos - 1, pos).match(/\s/) !== null;
88
+ // Check if cursor is after a pipe operator followed by whitespace
89
+ // This enables autocomplete after: {job="nginx"} | ▯
90
+ if (textBeforeCursor.endsWith('|') && hasSpace) {
91
+ return {
92
+ scope: {
93
+ kind: 'PipeFunction',
94
+ afterPipe: true,
95
+ hasSpace: true,
96
+ afterExclamation: false
97
+ },
98
+ from: pos
99
+ };
100
+ }
101
+ // Check if cursor is after a closing brace (stream selector) followed by whitespace
102
+ // This enables autocomplete after: {job="nginx"} ▯
103
+ if (textBeforeCursor.endsWith('}') && hasSpace) {
104
+ return {
105
+ scope: {
106
+ kind: 'PipeFunction',
107
+ afterPipe: false,
108
+ hasSpace: true,
109
+ afterExclamation: false
110
+ },
111
+ from: pos
112
+ };
113
+ }
114
+ }
115
+ /**
116
+ * Retrieve completion options based on the identified completion scope.
117
+ */ async function retrieveOptions(completionCfg, completion) {
118
+ switch(completion.kind){
119
+ case 'LabelName':
120
+ return completeLabelName(completionCfg);
121
+ case 'LabelValue':
122
+ return completeLabelValue(completionCfg, completion.label);
123
+ case 'PipeFunction':
124
+ return completePipeFunctions(completion.afterPipe, completion.hasSpace, completion.afterExclamation);
125
+ }
126
+ }
127
+ /**
128
+ * Detect label name or value completion contexts within selectors.
129
+ */ function detectLabelCompletion(state, pos, node) {
43
130
  switch(node.type.id){
44
131
  case Selector:
45
132
  // Selector is the entire {label matchers} expression
46
133
  // Autocomplete at start: {▯ or empty: {}
47
134
  // Do not autocomplete if cursor is after closing brace: {job="mysql"}▯
48
- if ((node.firstChild === null || node.firstChild?.type.id === 0) && !state.sliceDoc(node.from, pos).includes('}')) {
135
+ if ((node.firstChild === null || node.firstChild?.type.id === ERROR_NODE) && !state.sliceDoc(node.from, pos).includes('}')) {
49
136
  return {
50
137
  scope: {
51
138
  kind: 'LabelName'
@@ -130,7 +217,7 @@ export async function complete(completionCfg, { state, pos }) {
130
217
  }
131
218
  }
132
219
  break;
133
- case 0 /* error node */ :
220
+ case ERROR_NODE:
134
221
  // Error nodes represent incomplete or malformed syntax
135
222
  // Autocomplete incomplete value after operator: { job=mys▯ or { job="mys▯
136
223
  if ((node.prevSibling?.type.id === Eq || node.prevSibling?.type.id === Neq || node.prevSibling?.type.id === Re || node.prevSibling?.type.id === Nre) && node.parent?.type.id === Matcher) {
@@ -159,16 +246,132 @@ export async function complete(completionCfg, { state, pos }) {
159
246
  }
160
247
  break;
161
248
  }
249
+ return undefined;
162
250
  }
163
251
  /**
164
- * Retrieve completion options based on the identified completion scope.
165
- */ async function retrieveOptions(completionCfg, completion) {
166
- switch(completion.kind){
167
- case 'LabelName':
168
- return completeLabelName(completionCfg);
169
- case 'LabelValue':
170
- return completeLabelValue(completionCfg, completion.label);
252
+ * Detect pipe function completion contexts (line filters, parsers, formatters).
253
+ */ function detectPipeCompletion(state, node) {
254
+ // Check if we're in an error node right after a pipe operator
255
+ // This handles cases like: {job="nginx"} | !▯
256
+ if (node.prevSibling?.type.id === Pipe) {
257
+ return {
258
+ scope: {
259
+ kind: 'PipeFunction',
260
+ afterPipe: true,
261
+ hasSpace: true,
262
+ afterExclamation: false
263
+ },
264
+ from: node.from
265
+ };
266
+ }
267
+ // Check if we're after selector with space and text starts with !
268
+ // This handles cases like: {job="nginx"} !▯
269
+ const errorText = state.sliceDoc(node.from, node.to);
270
+ if (errorText.startsWith('!')) {
271
+ const textBeforeError = state.sliceDoc(0, node.from).trim();
272
+ if (textBeforeError.endsWith('}')) {
273
+ return {
274
+ scope: {
275
+ kind: 'PipeFunction',
276
+ afterPipe: false,
277
+ hasSpace: true,
278
+ afterExclamation: true
279
+ },
280
+ from: node.from
281
+ };
282
+ }
283
+ }
284
+ return undefined;
285
+ }
286
+ /**
287
+ * Complete LogQL pipe functions, line filters, and parser functions.
288
+ * Context-aware suggestions based on LogQL syntax:
289
+ * - After "{} ": Show all line filters (|=, !=, |~, !~) + parsers (with | prefix)
290
+ * - After "{} !": Show ONLY != and !~
291
+ * - After "{} |": Show only pipe-based filters WITHOUT the | (=, ~) + parsers
292
+ * - After "{} | ": Show ONLY parsers, NO line filters
293
+ */ function completePipeFunctions(afterPipe, hasSpace, afterExclamation) {
294
+ const completions = [];
295
+ // Line filter operators that START with pipe: |= and |~
296
+ const pipeLineFilters = [
297
+ {
298
+ operator: '|=',
299
+ detail: 'Line contains'
300
+ },
301
+ {
302
+ operator: '|~',
303
+ detail: 'Line matches regex'
304
+ }
305
+ ];
306
+ // Line filter operators that DON'T start with pipe: != and !~
307
+ const nonPipeLineFilters = [
308
+ {
309
+ operator: '!=',
310
+ detail: 'Line does not contain'
311
+ },
312
+ {
313
+ operator: '!~',
314
+ detail: 'Line does not match regex'
315
+ }
316
+ ];
317
+ // Context: After "{} !" - Show ONLY != and !~
318
+ if (afterExclamation) {
319
+ nonPipeLineFilters.forEach(({ operator, detail })=>{
320
+ completions.push(createLineFilterCompletion(operator, detail));
321
+ });
322
+ return completions; // Don't show parsers after !
171
323
  }
324
+ // Context 1: After "{} | " (pipe + space) - ONLY parsers, NO line filters
325
+ if (afterPipe && hasSpace) {
326
+ // Don't show any line filters
327
+ } else if (afterPipe && !hasSpace) {
328
+ pipeLineFilters.forEach(({ operator, detail })=>{
329
+ // Strip the | since user already typed it
330
+ const strippedOp = operator.replace('|', '');
331
+ completions.push(createLineFilterCompletion(strippedOp, detail));
332
+ });
333
+ } else {
334
+ [
335
+ ...pipeLineFilters,
336
+ ...nonPipeLineFilters
337
+ ].forEach(({ operator, detail })=>{
338
+ completions.push(createLineFilterCompletion(operator, detail));
339
+ });
340
+ }
341
+ // Parser functions and pipe operations: always show
342
+ // Add pipe prefix when not after pipe (e.g., "{} " needs "| json" not " json")
343
+ const parserPrefix = !afterPipe ? '| ' : hasSpace ? '' : ' ';
344
+ // Parsing expressions: Extract structured data
345
+ const parsingExpressions = [
346
+ 'json',
347
+ 'logfmt',
348
+ 'pattern',
349
+ 'regexp',
350
+ 'unpack',
351
+ 'unwrap'
352
+ ];
353
+ parsingExpressions.forEach((parser)=>{
354
+ completions.push({
355
+ label: `${parserPrefix}${parser}`,
356
+ type: 'function',
357
+ boost: 5
358
+ });
359
+ });
360
+ // Formatting and labels expressions: Format output and manipulate labels
361
+ const formattingAndLabels = [
362
+ 'line_format',
363
+ 'label_format',
364
+ 'decolorize',
365
+ 'drop',
366
+ 'keep'
367
+ ];
368
+ formattingAndLabels.forEach((expr)=>{
369
+ completions.push({
370
+ label: `${parserPrefix}${expr}`,
371
+ type: 'method'
372
+ });
373
+ });
374
+ return completions;
172
375
  }
173
376
  async function completeLabelName(completionCfg) {
174
377
  if (!completionCfg.client) {
@@ -189,6 +392,50 @@ async function completeLabelName(completionCfg) {
189
392
  return [];
190
393
  }
191
394
  }
395
+ async function completeLabelValue(completionCfg, label) {
396
+ if (!completionCfg.client) {
397
+ return [];
398
+ }
399
+ const start = completionCfg.timeRange?.start ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime()) : undefined;
400
+ const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;
401
+ try {
402
+ const response = await completionCfg.client.labelValues(label, start, end);
403
+ if (response.status === 'success') {
404
+ return response.data.map((value)=>({
405
+ label: value ?? '',
406
+ displayLabel: value ?? '(empty string)',
407
+ apply: applyQuotedCompletion
408
+ }));
409
+ }
410
+ return [];
411
+ } catch (error) {
412
+ console.error(`Error fetching values for label ${label}:`, error);
413
+ return [];
414
+ }
415
+ }
416
+ /**
417
+ * Create a line filter completion with consistent cursor positioning.
418
+ */ function createLineFilterCompletion(operator, detail) {
419
+ return {
420
+ label: `${operator} ""`,
421
+ detail,
422
+ apply: (view, _completion, from, to)=>{
423
+ const insert = `${operator} ""`;
424
+ view.dispatch({
425
+ changes: {
426
+ from,
427
+ to,
428
+ insert
429
+ },
430
+ selection: {
431
+ anchor: from + insert.length - 1
432
+ }
433
+ });
434
+ },
435
+ type: 'text',
436
+ boost: 10
437
+ };
438
+ }
192
439
  function escapeString(input, quoteChar) {
193
440
  // do not escape raw strings (when using backticks)
194
441
  if (quoteChar === '`') {
@@ -224,26 +471,5 @@ function escapeString(input, quoteChar) {
224
471
  const insertText = `${quoteChar}${escapeString(completion.label, quoteChar)}${quoteChar}`;
225
472
  view.dispatch(insertCompletionText(view.state, insertText, from, to));
226
473
  }
227
- async function completeLabelValue(completionCfg, label) {
228
- if (!completionCfg.client) {
229
- return [];
230
- }
231
- const start = completionCfg.timeRange?.start ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime()) : undefined;
232
- const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;
233
- try {
234
- const response = await completionCfg.client.labelValues(label, start, end);
235
- if (response.status === 'success') {
236
- return response.data.map((value)=>({
237
- label: value ?? '',
238
- displayLabel: value ?? '(empty string)',
239
- apply: applyQuotedCompletion
240
- }));
241
- }
242
- return [];
243
- } catch (error) {
244
- console.error(`Error fetching values for label ${label}:`, error);
245
- return [];
246
- }
247
- }
248
474
 
249
475
  //# sourceMappingURL=complete.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/complete.ts"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Completion, CompletionContext, CompletionResult, insertCompletionText } from '@codemirror/autocomplete';\nimport { syntaxTree } from '@codemirror/language';\nimport { EditorState } from '@codemirror/state';\nimport { Tree } from '@lezer/common';\nimport { Selector, Matchers, Matcher, Identifier, Eq, Neq, Re, Nre, String as StringType } from '@grafana/lezer-logql';\nimport { EditorView } from '@uiw/react-codemirror';\nimport { toUnixSeconds } from '../model/loki-client';\nimport { CompletionConfig } from './logql-extension';\n\n/** CompletionScope specifies the completion kind, e.g. whether to complete label names or values */\ntype CompletionScope = { kind: 'LabelName' } | { kind: 'LabelValue'; label: string };\n\n/**\n * CompletionInfo specifies the identified scope and position of the completion in the current editor text.\n */\nexport interface CompletionInfo {\n scope: CompletionScope;\n from: number;\n to?: number;\n}\n\nconst quoteChars = ['\"', '`'];\nconst defaultQuoteChar = '\"';\n\nexport async function complete(\n completionCfg: CompletionConfig,\n { state, pos }: CompletionContext\n): Promise<CompletionResult | null> {\n // First, identify the completion scope\n const completion = identifyCompletion(state, pos, syntaxTree(state));\n if (!completion) {\n // No completion scope found for current cursor position.\n return null;\n }\n\n // Then, retrieve completion options for the identified scope (from the Loki API).\n const options = await retrieveOptions(completionCfg, completion.scope);\n return { options, from: completion.from, to: completion.to };\n}\n\n/**\n * Identify completion scope (e.g. LabelName, LabelValue) and position, based on the current node in the syntax tree.\n *\n * Function is exported for tests only.\n */\nexport function identifyCompletion(state: EditorState, pos: number, tree: Tree): CompletionInfo | undefined {\n const node = tree.resolveInner(pos, -1);\n\n switch (node.type.id) {\n case Selector:\n // Selector is the entire {label matchers} expression\n // Autocomplete at start: {▯ or empty: {}\n // Do not autocomplete if cursor is after closing brace: {job=\"mysql\"}▯\n if (\n (node.firstChild === null || node.firstChild?.type.id === 0) &&\n !state.sliceDoc(node.from, pos).includes('}')\n ) {\n return {\n scope: { kind: 'LabelName' },\n from: pos,\n };\n }\n break;\n\n case Matchers: {\n // Matchers node contains all label matchers inside {}\n // Autocomplete after comma: { job=\"mysql\",▯ or { job=\"mysql\", ▯\n const text = state.sliceDoc(node.from, pos);\n if (text.endsWith(',') || text.endsWith(', ')) {\n return {\n scope: { kind: 'LabelName' },\n from: pos,\n };\n }\n break;\n }\n\n case Matcher:\n // Single matcher like job=\"mysql\"\n // Autocomplete when cursor is after a complete matcher: { job=\"mysql\" ▯\n if (node.parent?.type.id === Matchers) {\n return {\n scope: { kind: 'LabelName' },\n from: pos,\n };\n }\n break;\n\n case Identifier:\n // Identifier is a label name being typed\n // Autocomplete partial label names: { jo▯ or { job=\"mysql\", na▯\n if (node.parent?.type.id === Matcher) {\n return {\n scope: { kind: 'LabelName' },\n from: node.from,\n };\n }\n break;\n\n case Eq:\n case Neq:\n case Re:\n case Nre:\n // Operators for label matching: =, !=, =~, !~\n // Autocomplete label values right after operator: { job=▯ or { job!=▯\n if (node.parent?.type.id === Matcher) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n return { scope: { kind: 'LabelValue', label }, from: pos };\n }\n }\n break;\n\n case StringType:\n // String value in a matcher: { job=\"▯\n // Do not autocomplete if cursor is after closing quotes: { job=\"\"▯\n if (node.parent?.type.id === Matcher && !/^\".*\"$/.test(state.sliceDoc(node.from, pos))) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n return { scope: { kind: 'LabelValue', label }, from: node.from + 1 }; // +1 to skip opening quote\n }\n }\n break;\n\n case 0 /* error node */:\n // Error nodes represent incomplete or malformed syntax\n // Autocomplete incomplete value after operator: { job=mys▯ or { job=\"mys▯\n if (\n (node.prevSibling?.type.id === Eq ||\n node.prevSibling?.type.id === Neq ||\n node.prevSibling?.type.id === Re ||\n node.prevSibling?.type.id === Nre) &&\n node.parent?.type.id === Matcher\n ) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n // Skip leading quote if present: { name=\"HT▯\n const from = quoteChars.includes(state.sliceDoc(node.from, node.from + 1)) ? node.from + 1 : node.from;\n return { scope: { kind: 'LabelValue', label }, from };\n }\n }\n\n // Autocomplete partial label name: { j▯ or { job=\"mysql\", n▯\n if (node.parent?.type.id === Selector || node.parent?.type.id === Matchers) {\n return {\n scope: { kind: 'LabelName' },\n from: node.from,\n };\n }\n break;\n }\n}\n\n/**\n * Retrieve completion options based on the identified completion scope.\n */\nasync function retrieveOptions(completionCfg: CompletionConfig, completion: CompletionScope): Promise<Completion[]> {\n switch (completion.kind) {\n case 'LabelName':\n return completeLabelName(completionCfg);\n\n case 'LabelValue':\n return completeLabelValue(completionCfg, completion.label);\n }\n}\n\nasync function completeLabelName(completionCfg: CompletionConfig): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const start = completionCfg.timeRange?.start\n ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime())\n : undefined;\n const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;\n\n try {\n const response = await completionCfg.client.labels(start, end);\n if (response.status === 'success') {\n return response.data.map((label: string) => ({ label }));\n }\n return [];\n } catch (error) {\n console.error('Error fetching label names:', error);\n return [];\n }\n}\n\nfunction escapeString(input: string, quoteChar: string) {\n // do not escape raw strings (when using backticks)\n if (quoteChar === '`') {\n return input;\n }\n\n let escaped = input;\n // escape backslashes and quotes\n escaped = escaped.replaceAll('\\\\', '\\\\\\\\');\n escaped = escaped.replaceAll('\"', '\\\\\"');\n return escaped;\n}\n\n/**\n * Add quotes to the completion text in case quotes are not present already.\n * This handles the following cases:\n * { name=HTTP\n * { name=\"x\n * { name=\"x\" where cursor is after the 'x'\n */\nexport function applyQuotedCompletion(view: EditorView, completion: Completion, from: number, to: number): void {\n let quoteChar = defaultQuoteChar;\n if (quoteChars.includes(view.state.sliceDoc(from - 1, from))) {\n quoteChar = view.state.sliceDoc(from - 1, from);\n from--;\n }\n if (quoteChars.includes(view.state.sliceDoc(to, to + 1))) {\n quoteChar = view.state.sliceDoc(to, to + 1);\n to++;\n }\n\n // When using raw strings (`), we cannot escape a backtick.\n // Therefore, switch the quote character.\n if (completion.label.includes('`')) {\n quoteChar = '\"';\n }\n\n const insertText = `${quoteChar}${escapeString(completion.label, quoteChar)}${quoteChar}`;\n view.dispatch(insertCompletionText(view.state, insertText, from, to));\n}\n\nasync function completeLabelValue(completionCfg: CompletionConfig, label: string): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const start = completionCfg.timeRange?.start\n ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime())\n : undefined;\n const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;\n\n try {\n const response = await completionCfg.client.labelValues(label, start, end);\n if (response.status === 'success') {\n return response.data.map((value: string) => ({\n label: value ?? '',\n displayLabel: value ?? '(empty string)',\n apply: applyQuotedCompletion,\n }));\n }\n return [];\n } catch (error) {\n console.error(`Error fetching values for label ${label}:`, error);\n return [];\n }\n}\n"],"names":["insertCompletionText","syntaxTree","Selector","Matchers","Matcher","Identifier","Eq","Neq","Re","Nre","String","StringType","toUnixSeconds","quoteChars","defaultQuoteChar","complete","completionCfg","state","pos","completion","identifyCompletion","options","retrieveOptions","scope","from","to","tree","node","resolveInner","type","id","firstChild","sliceDoc","includes","kind","text","endsWith","parent","labelNode","label","test","prevSibling","completeLabelName","completeLabelValue","client","start","timeRange","Date","getTime","undefined","end","response","labels","status","data","map","error","console","escapeString","input","quoteChar","escaped","replaceAll","applyQuotedCompletion","view","insertText","dispatch","labelValues","value","displayLabel","apply"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/components/complete.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Completion, CompletionContext, CompletionResult, insertCompletionText } from '@codemirror/autocomplete';\nimport { syntaxTree } from '@codemirror/language';\nimport { EditorState } from '@codemirror/state';\nimport { SyntaxNode, Tree } from '@lezer/common';\nimport {\n Selector,\n Matchers,\n Matcher,\n Identifier,\n Eq,\n Neq,\n Re,\n Nre,\n String as StringType,\n Pipe,\n} from '@grafana/lezer-logql';\nimport { EditorView } from '@uiw/react-codemirror';\nimport { toUnixSeconds } from '../model';\nimport { CompletionConfig } from './logql-extension';\n\n/** CompletionScope specifies the completion kind, e.g. whether to complete label names or values */\ntype CompletionScope =\n | { kind: 'LabelName' }\n | { kind: 'LabelValue'; label: string }\n | { kind: 'PipeFunction'; afterPipe: boolean; hasSpace: boolean; afterExclamation: boolean };\n\n/**\n * CompletionInfo specifies the identified scope and position of the completion in the current editor text.\n */\nexport interface CompletionInfo {\n scope: CompletionScope;\n from: number;\n to?: number;\n}\n\nconst quoteChars = ['\"', '`'];\nconst defaultQuoteChar = '\"';\nconst ERROR_NODE = 0; // Lezer parser creates error nodes for incomplete/malformed syntax\n\nexport async function complete(\n completionCfg: CompletionConfig,\n { state, pos }: CompletionContext\n): Promise<CompletionResult | null> {\n // First, identify the completion scope\n const completion = identifyCompletion(state, pos, syntaxTree(state));\n if (!completion) {\n // No completion scope found for current cursor position.\n return null;\n }\n\n // Then, retrieve completion options for the identified scope (from the Loki API).\n const options = await retrieveOptions(completionCfg, completion.scope);\n return { options, from: completion.from, to: completion.to };\n}\n\n/**\n * Identify completion scope (e.g. LabelName, LabelValue) and position, based on the current node in the syntax tree.\n *\n * Function is exported for tests only.\n */\nexport function identifyCompletion(state: EditorState, pos: number, tree: Tree): CompletionInfo | undefined {\n const node = tree.resolveInner(pos, -1);\n\n switch (node.type.id) {\n case Selector:\n case Matchers:\n case Matcher:\n case Identifier:\n case Eq:\n case Neq:\n case Re:\n case Nre:\n case StringType: {\n const labelCompletion = detectLabelCompletion(state, pos, node);\n if (labelCompletion) return labelCompletion;\n break;\n }\n\n case ERROR_NODE: {\n // Check for pipe context first\n const pipeCompletion = detectPipeCompletion(state, node);\n if (pipeCompletion) return pipeCompletion;\n\n // Then check for label completion in error nodes\n const labelCompletion = detectLabelCompletion(state, pos, node);\n if (labelCompletion) return labelCompletion;\n break;\n }\n\n case Pipe: {\n // Pipe operator: suggest parser functions and line filters\n // Examples: {job=\"nginx\"} |▯ or {job=\"nginx\"} | ▯\n const hasSpaceAfterPipe = state.sliceDoc(pos - 1, pos) === ' ';\n return {\n scope: { kind: 'PipeFunction', afterPipe: true, hasSpace: hasSpaceAfterPipe, afterExclamation: false },\n from: pos,\n };\n }\n }\n\n // Fallback checks for contexts not directly on a node\n const textBeforeCursor = state.sliceDoc(0, pos).trim();\n const hasSpace = state.sliceDoc(pos - 1, pos).match(/\\s/) !== null;\n\n // Check if cursor is after a pipe operator followed by whitespace\n // This enables autocomplete after: {job=\"nginx\"} | ▯\n if (textBeforeCursor.endsWith('|') && hasSpace) {\n return {\n scope: { kind: 'PipeFunction', afterPipe: true, hasSpace: true, afterExclamation: false },\n from: pos,\n };\n }\n\n // Check if cursor is after a closing brace (stream selector) followed by whitespace\n // This enables autocomplete after: {job=\"nginx\"} ▯\n if (textBeforeCursor.endsWith('}') && hasSpace) {\n return {\n scope: { kind: 'PipeFunction', afterPipe: false, hasSpace: true, afterExclamation: false },\n from: pos,\n };\n }\n}\n\n/**\n * Retrieve completion options based on the identified completion scope.\n */\nasync function retrieveOptions(completionCfg: CompletionConfig, completion: CompletionScope): Promise<Completion[]> {\n switch (completion.kind) {\n case 'LabelName':\n return completeLabelName(completionCfg);\n\n case 'LabelValue':\n return completeLabelValue(completionCfg, completion.label);\n\n case 'PipeFunction':\n return completePipeFunctions(completion.afterPipe, completion.hasSpace, completion.afterExclamation);\n }\n}\n\n/**\n * Detect label name or value completion contexts within selectors.\n */\nfunction detectLabelCompletion(state: EditorState, pos: number, node: SyntaxNode): CompletionInfo | undefined {\n switch (node.type.id) {\n case Selector:\n // Selector is the entire {label matchers} expression\n // Autocomplete at start: {▯ or empty: {}\n // Do not autocomplete if cursor is after closing brace: {job=\"mysql\"}▯\n if (\n (node.firstChild === null || node.firstChild?.type.id === ERROR_NODE) &&\n !state.sliceDoc(node.from, pos).includes('}')\n ) {\n return { scope: { kind: 'LabelName' }, from: pos };\n }\n break;\n\n case Matchers: {\n // Matchers node contains all label matchers inside {}\n // Autocomplete after comma: { job=\"mysql\",▯ or { job=\"mysql\", ▯\n const text = state.sliceDoc(node.from, pos);\n if (text.endsWith(',') || text.endsWith(', ')) {\n return { scope: { kind: 'LabelName' }, from: pos };\n }\n break;\n }\n\n case Matcher:\n // Single matcher like job=\"mysql\"\n // Autocomplete when cursor is after a complete matcher: { job=\"mysql\" ▯\n if (node.parent?.type.id === Matchers) {\n return { scope: { kind: 'LabelName' }, from: pos };\n }\n break;\n\n case Identifier:\n // Identifier is a label name being typed\n // Autocomplete partial label names: { jo▯ or { job=\"mysql\", na▯\n if (node.parent?.type.id === Matcher) {\n return { scope: { kind: 'LabelName' }, from: node.from };\n }\n break;\n\n case Eq:\n case Neq:\n case Re:\n case Nre:\n // Operators for label matching: =, !=, =~, !~\n // Autocomplete label values right after operator: { job=▯ or { job!=▯\n if (node.parent?.type.id === Matcher) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n return { scope: { kind: 'LabelValue', label }, from: pos };\n }\n }\n break;\n\n case StringType:\n // String value in a matcher: { job=\"▯\n // Do not autocomplete if cursor is after closing quotes: { job=\"\"▯\n if (node.parent?.type.id === Matcher && !/^\".*\"$/.test(state.sliceDoc(node.from, pos))) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n return { scope: { kind: 'LabelValue', label }, from: node.from + 1 }; // +1 to skip opening quote\n }\n }\n break;\n\n case ERROR_NODE:\n // Error nodes represent incomplete or malformed syntax\n // Autocomplete incomplete value after operator: { job=mys▯ or { job=\"mys▯\n if (\n (node.prevSibling?.type.id === Eq ||\n node.prevSibling?.type.id === Neq ||\n node.prevSibling?.type.id === Re ||\n node.prevSibling?.type.id === Nre) &&\n node.parent?.type.id === Matcher\n ) {\n const labelNode = node.parent.firstChild;\n if (labelNode?.type.id === Identifier) {\n const label = state.sliceDoc(labelNode.from, labelNode.to);\n // Skip leading quote if present: { name=\"HT▯\n const from = quoteChars.includes(state.sliceDoc(node.from, node.from + 1)) ? node.from + 1 : node.from;\n return { scope: { kind: 'LabelValue', label }, from };\n }\n }\n\n // Autocomplete partial label name: { j▯ or { job=\"mysql\", n▯\n if (node.parent?.type.id === Selector || node.parent?.type.id === Matchers) {\n return { scope: { kind: 'LabelName' }, from: node.from };\n }\n break;\n }\n\n return undefined;\n}\n\n/**\n * Detect pipe function completion contexts (line filters, parsers, formatters).\n */\nfunction detectPipeCompletion(state: EditorState, node: SyntaxNode): CompletionInfo | undefined {\n // Check if we're in an error node right after a pipe operator\n // This handles cases like: {job=\"nginx\"} | !▯\n if (node.prevSibling?.type.id === Pipe) {\n return {\n scope: { kind: 'PipeFunction', afterPipe: true, hasSpace: true, afterExclamation: false },\n from: node.from,\n };\n }\n\n // Check if we're after selector with space and text starts with !\n // This handles cases like: {job=\"nginx\"} !▯\n const errorText = state.sliceDoc(node.from, node.to);\n if (errorText.startsWith('!')) {\n const textBeforeError = state.sliceDoc(0, node.from).trim();\n if (textBeforeError.endsWith('}')) {\n return {\n scope: { kind: 'PipeFunction', afterPipe: false, hasSpace: true, afterExclamation: true },\n from: node.from,\n };\n }\n }\n\n return undefined;\n}\n\n/**\n * Complete LogQL pipe functions, line filters, and parser functions.\n * Context-aware suggestions based on LogQL syntax:\n * - After \"{} \": Show all line filters (|=, !=, |~, !~) + parsers (with | prefix)\n * - After \"{} !\": Show ONLY != and !~\n * - After \"{} |\": Show only pipe-based filters WITHOUT the | (=, ~) + parsers\n * - After \"{} | \": Show ONLY parsers, NO line filters\n */\nfunction completePipeFunctions(afterPipe: boolean, hasSpace: boolean, afterExclamation: boolean): Completion[] {\n const completions: Completion[] = [];\n\n // Line filter operators that START with pipe: |= and |~\n const pipeLineFilters = [\n { operator: '|=', detail: 'Line contains' },\n { operator: '|~', detail: 'Line matches regex' },\n ];\n\n // Line filter operators that DON'T start with pipe: != and !~\n const nonPipeLineFilters = [\n { operator: '!=', detail: 'Line does not contain' },\n { operator: '!~', detail: 'Line does not match regex' },\n ];\n\n // Context: After \"{} !\" - Show ONLY != and !~\n if (afterExclamation) {\n nonPipeLineFilters.forEach(({ operator, detail }) => {\n completions.push(createLineFilterCompletion(operator, detail));\n });\n return completions; // Don't show parsers after !\n }\n\n // Context 1: After \"{} | \" (pipe + space) - ONLY parsers, NO line filters\n if (afterPipe && hasSpace) {\n // Don't show any line filters\n }\n // Context 2: After \"{} |\" (pipe, no space) - Show = and ~ (without pipe prefix)\n else if (afterPipe && !hasSpace) {\n pipeLineFilters.forEach(({ operator, detail }) => {\n // Strip the | since user already typed it\n const strippedOp = operator.replace('|', '');\n completions.push(createLineFilterCompletion(strippedOp, detail));\n });\n }\n // Context 3: After \"{} \" (no pipe) - Show ALL line filters with full syntax\n else {\n [...pipeLineFilters, ...nonPipeLineFilters].forEach(({ operator, detail }) => {\n completions.push(createLineFilterCompletion(operator, detail));\n });\n }\n\n // Parser functions and pipe operations: always show\n // Add pipe prefix when not after pipe (e.g., \"{} \" needs \"| json\" not \" json\")\n const parserPrefix = !afterPipe ? '| ' : hasSpace ? '' : ' ';\n\n // Parsing expressions: Extract structured data\n const parsingExpressions = ['json', 'logfmt', 'pattern', 'regexp', 'unpack', 'unwrap'];\n parsingExpressions.forEach((parser) => {\n completions.push({\n label: `${parserPrefix}${parser}`,\n type: 'function',\n boost: 5,\n });\n });\n\n // Formatting and labels expressions: Format output and manipulate labels\n const formattingAndLabels = ['line_format', 'label_format', 'decolorize', 'drop', 'keep'];\n formattingAndLabels.forEach((expr) => {\n completions.push({\n label: `${parserPrefix}${expr}`,\n type: 'method',\n });\n });\n\n return completions;\n}\n\nasync function completeLabelName(completionCfg: CompletionConfig): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const start = completionCfg.timeRange?.start\n ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime())\n : undefined;\n const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;\n\n try {\n const response = await completionCfg.client.labels(start, end);\n if (response.status === 'success') {\n return response.data.map((label: string) => ({ label }));\n }\n return [];\n } catch (error) {\n console.error('Error fetching label names:', error);\n return [];\n }\n}\n\nasync function completeLabelValue(completionCfg: CompletionConfig, label: string): Promise<Completion[]> {\n if (!completionCfg.client) {\n return [];\n }\n\n const start = completionCfg.timeRange?.start\n ? toUnixSeconds(new Date(completionCfg.timeRange.start).getTime())\n : undefined;\n const end = completionCfg.timeRange?.end ? toUnixSeconds(new Date(completionCfg.timeRange.end).getTime()) : undefined;\n\n try {\n const response = await completionCfg.client.labelValues(label, start, end);\n if (response.status === 'success') {\n return response.data.map((value: string) => ({\n label: value ?? '',\n displayLabel: value ?? '(empty string)',\n apply: applyQuotedCompletion,\n }));\n }\n return [];\n } catch (error) {\n console.error(`Error fetching values for label ${label}:`, error);\n return [];\n }\n}\n\n/**\n * Create a line filter completion with consistent cursor positioning.\n */\nfunction createLineFilterCompletion(operator: string, detail: string): Completion {\n return {\n label: `${operator} \"\"`,\n detail,\n apply: (view, _completion, from, to) => {\n const insert = `${operator} \"\"`;\n view.dispatch({\n changes: { from, to, insert },\n selection: { anchor: from + insert.length - 1 },\n });\n },\n type: 'text',\n boost: 10,\n };\n}\n\nfunction escapeString(input: string, quoteChar: string) {\n // do not escape raw strings (when using backticks)\n if (quoteChar === '`') {\n return input;\n }\n\n let escaped = input;\n // escape backslashes and quotes\n escaped = escaped.replaceAll('\\\\', '\\\\\\\\');\n escaped = escaped.replaceAll('\"', '\\\\\"');\n return escaped;\n}\n\n/**\n * Add quotes to the completion text in case quotes are not present already.\n * This handles the following cases:\n * { name=HTTP\n * { name=\"x\n * { name=\"x\" where cursor is after the 'x'\n */\nexport function applyQuotedCompletion(view: EditorView, completion: Completion, from: number, to: number): void {\n let quoteChar = defaultQuoteChar;\n if (quoteChars.includes(view.state.sliceDoc(from - 1, from))) {\n quoteChar = view.state.sliceDoc(from - 1, from);\n from--;\n }\n if (quoteChars.includes(view.state.sliceDoc(to, to + 1))) {\n quoteChar = view.state.sliceDoc(to, to + 1);\n to++;\n }\n\n // When using raw strings (`), we cannot escape a backtick.\n // Therefore, switch the quote character.\n if (completion.label.includes('`')) {\n quoteChar = '\"';\n }\n\n const insertText = `${quoteChar}${escapeString(completion.label, quoteChar)}${quoteChar}`;\n view.dispatch(insertCompletionText(view.state, insertText, from, to));\n}\n"],"names":["insertCompletionText","syntaxTree","Selector","Matchers","Matcher","Identifier","Eq","Neq","Re","Nre","String","StringType","Pipe","toUnixSeconds","quoteChars","defaultQuoteChar","ERROR_NODE","complete","completionCfg","state","pos","completion","identifyCompletion","options","retrieveOptions","scope","from","to","tree","node","resolveInner","type","id","labelCompletion","detectLabelCompletion","pipeCompletion","detectPipeCompletion","hasSpaceAfterPipe","sliceDoc","kind","afterPipe","hasSpace","afterExclamation","textBeforeCursor","trim","match","endsWith","completeLabelName","completeLabelValue","label","completePipeFunctions","firstChild","includes","text","parent","labelNode","test","prevSibling","undefined","errorText","startsWith","textBeforeError","completions","pipeLineFilters","operator","detail","nonPipeLineFilters","forEach","push","createLineFilterCompletion","strippedOp","replace","parserPrefix","parsingExpressions","parser","boost","formattingAndLabels","expr","client","start","timeRange","Date","getTime","end","response","labels","status","data","map","error","console","labelValues","value","displayLabel","apply","applyQuotedCompletion","view","_completion","insert","dispatch","changes","selection","anchor","length","escapeString","input","quoteChar","escaped","replaceAll","insertText"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/index.ts"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport { LogQLEditor } from './logql-editor';\nexport type { LogQLEditorProps } from './logql-editor';\n"],"names":["LogQLEditor"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,WAAW,QAAQ,iBAAiB"}
1
+ {"version":3,"sources":["../../../src/components/index.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nexport { LogQLEditor } from './logql-editor';\nexport type { LogQLEditorProps } from './logql-editor';\n"],"names":["LogQLEditor"],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,WAAW,QAAQ,iBAAiB"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- // Copyright 2025 The Perses Authors
2
+ // Copyright The Perses Authors
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
5
5
  // You may obtain a copy of the License at
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/logql-editor.tsx"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo } from 'react';\nimport { useTheme } from '@mui/material';\nimport CodeMirror, { EditorView, ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport { LogQLExtension, CompletionConfig } from './logql-extension';\n\nexport type LogQLEditorProps = Omit<ReactCodeMirrorProps, 'theme' | 'extensions'> & {\n completionConfig?: CompletionConfig;\n};\n\nexport function LogQLEditor(props: LogQLEditorProps): ReactElement {\n const { completionConfig, ...codemirrorProps } = props;\n const theme = useTheme();\n const isDarkMode = theme.palette.mode === 'dark';\n\n const logqlExtension = useMemo(() => {\n return LogQLExtension(completionConfig);\n }, [completionConfig]);\n\n const codemirrorTheme = useMemo(() => {\n const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';\n\n return EditorView.theme({\n '&': {\n backgroundColor: 'transparent !important', // required for dark mode\n border: `1px solid ${borderColor}`,\n borderRadius: `${theme.shape.borderRadius}px`,\n },\n '&.cm-focused.cm-editor': {\n outline: 'none',\n },\n '.cm-content': {\n padding: '8px',\n },\n });\n }, [theme]);\n\n return (\n <CodeMirror\n {...codemirrorProps}\n theme={isDarkMode ? 'dark' : 'light'}\n basicSetup={{\n lineNumbers: false,\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n foldGutter: false,\n syntaxHighlighting: true,\n }}\n extensions={[EditorView.lineWrapping, logqlExtension, codemirrorTheme]}\n placeholder='Example: {job=\"my-service\"} |= \"error\"'\n />\n );\n}\n"],"names":["useMemo","useTheme","CodeMirror","EditorView","LogQLExtension","LogQLEditor","props","completionConfig","codemirrorProps","theme","isDarkMode","palette","mode","logqlExtension","codemirrorTheme","borderColor","backgroundColor","border","borderRadius","shape","outline","padding","basicSetup","lineNumbers","highlightActiveLine","highlightActiveLineGutter","foldGutter","syntaxHighlighting","extensions","lineWrapping","placeholder"],"mappings":";AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAAuBA,OAAO,QAAQ,QAAQ;AAC9C,SAASC,QAAQ,QAAQ,gBAAgB;AACzC,OAAOC,cAAcC,UAAU,QAA8B,wBAAwB;AACrF,SAASC,cAAc,QAA0B,oBAAoB;AAMrE,OAAO,SAASC,YAAYC,KAAuB;IACjD,MAAM,EAAEC,gBAAgB,EAAE,GAAGC,iBAAiB,GAAGF;IACjD,MAAMG,QAAQR;IACd,MAAMS,aAAaD,MAAME,OAAO,CAACC,IAAI,KAAK;IAE1C,MAAMC,iBAAiBb,QAAQ;QAC7B,OAAOI,eAAeG;IACxB,GAAG;QAACA;KAAiB;IAErB,MAAMO,kBAAkBd,QAAQ;QAC9B,MAAMe,cAAcN,MAAME,OAAO,CAACC,IAAI,KAAK,UAAU,wBAAwB;QAE7E,OAAOT,WAAWM,KAAK,CAAC;YACtB,KAAK;gBACHO,iBAAiB;gBACjBC,QAAQ,CAAC,UAAU,EAAEF,aAAa;gBAClCG,cAAc,GAAGT,MAAMU,KAAK,CAACD,YAAY,CAAC,EAAE,CAAC;YAC/C;YACA,0BAA0B;gBACxBE,SAAS;YACX;YACA,eAAe;gBACbC,SAAS;YACX;QACF;IACF,GAAG;QAACZ;KAAM;IAEV,qBACE,KAACP;QACE,GAAGM,eAAe;QACnBC,OAAOC,aAAa,SAAS;QAC7BY,YAAY;YACVC,aAAa;YACbC,qBAAqB;YACrBC,2BAA2B;YAC3BC,YAAY;YACZC,oBAAoB;QACtB;QACAC,YAAY;YAACzB,WAAW0B,YAAY;YAAEhB;YAAgBC;SAAgB;QACtEgB,aAAY;;AAGlB"}
1
+ {"version":3,"sources":["../../../src/components/logql-editor.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo } from 'react';\nimport { useTheme } from '@mui/material';\nimport CodeMirror, { EditorView, ReactCodeMirrorProps } from '@uiw/react-codemirror';\nimport { LogQLExtension, CompletionConfig } from './logql-extension';\n\nexport type LogQLEditorProps = Omit<ReactCodeMirrorProps, 'theme' | 'extensions'> & {\n completionConfig?: CompletionConfig;\n};\n\nexport function LogQLEditor(props: LogQLEditorProps): ReactElement {\n const { completionConfig, ...codemirrorProps } = props;\n const theme = useTheme();\n const isDarkMode = theme.palette.mode === 'dark';\n\n const logqlExtension = useMemo(() => {\n return LogQLExtension(completionConfig);\n }, [completionConfig]);\n\n const codemirrorTheme = useMemo(() => {\n const borderColor = theme.palette.mode === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)';\n\n return EditorView.theme({\n '&': {\n backgroundColor: 'transparent !important', // required for dark mode\n border: `1px solid ${borderColor}`,\n borderRadius: `${theme.shape.borderRadius}px`,\n },\n '&.cm-focused.cm-editor': {\n outline: 'none',\n },\n '.cm-content': {\n padding: '8px',\n },\n });\n }, [theme]);\n\n return (\n <CodeMirror\n {...codemirrorProps}\n theme={isDarkMode ? 'dark' : 'light'}\n basicSetup={{\n lineNumbers: false,\n highlightActiveLine: false,\n highlightActiveLineGutter: false,\n foldGutter: false,\n syntaxHighlighting: true,\n }}\n extensions={[EditorView.lineWrapping, logqlExtension, codemirrorTheme]}\n placeholder='Example: {job=\"my-service\"} |= \"error\"'\n />\n );\n}\n"],"names":["useMemo","useTheme","CodeMirror","EditorView","LogQLExtension","LogQLEditor","props","completionConfig","codemirrorProps","theme","isDarkMode","palette","mode","logqlExtension","codemirrorTheme","borderColor","backgroundColor","border","borderRadius","shape","outline","padding","basicSetup","lineNumbers","highlightActiveLine","highlightActiveLineGutter","foldGutter","syntaxHighlighting","extensions","lineWrapping","placeholder"],"mappings":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAAuBA,OAAO,QAAQ,QAAQ;AAC9C,SAASC,QAAQ,QAAQ,gBAAgB;AACzC,OAAOC,cAAcC,UAAU,QAA8B,wBAAwB;AACrF,SAASC,cAAc,QAA0B,oBAAoB;AAMrE,OAAO,SAASC,YAAYC,KAAuB;IACjD,MAAM,EAAEC,gBAAgB,EAAE,GAAGC,iBAAiB,GAAGF;IACjD,MAAMG,QAAQR;IACd,MAAMS,aAAaD,MAAME,OAAO,CAACC,IAAI,KAAK;IAE1C,MAAMC,iBAAiBb,QAAQ;QAC7B,OAAOI,eAAeG;IACxB,GAAG;QAACA;KAAiB;IAErB,MAAMO,kBAAkBd,QAAQ;QAC9B,MAAMe,cAAcN,MAAME,OAAO,CAACC,IAAI,KAAK,UAAU,wBAAwB;QAE7E,OAAOT,WAAWM,KAAK,CAAC;YACtB,KAAK;gBACHO,iBAAiB;gBACjBC,QAAQ,CAAC,UAAU,EAAEF,aAAa;gBAClCG,cAAc,GAAGT,MAAMU,KAAK,CAACD,YAAY,CAAC,EAAE,CAAC;YAC/C;YACA,0BAA0B;gBACxBE,SAAS;YACX;YACA,eAAe;gBACbC,SAAS;YACX;QACF;IACF,GAAG;QAACZ;KAAM;IAEV,qBACE,KAACP;QACE,GAAGM,eAAe;QACnBC,OAAOC,aAAa,SAAS;QAC7BY,YAAY;YACVC,aAAa;YACbC,qBAAqB;YACrBC,2BAA2B;YAC3BC,YAAY;YACZC,oBAAoB;QACtB;QACAC,YAAY;YAACzB,WAAW0B,YAAY;YAAEhB;YAAgBC;SAAgB;QACtEgB,aAAY;;AAGlB"}
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/logql-extension.ts"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { LRLanguage } from '@codemirror/language';\nimport { parser } from '@grafana/lezer-logql';\nimport { CompletionContext } from '@codemirror/autocomplete';\nimport { Extension } from '@uiw/react-codemirror';\nimport { AbsoluteTimeRange } from '@perses-dev/core';\nimport { LokiClient } from '../model';\nimport { logqlHighlight } from './logql-highlight';\nimport { complete } from './complete';\n\nfunction logqlLanguage(): LRLanguage {\n return LRLanguage.define({\n parser: parser.configure({\n props: [logqlHighlight],\n }),\n languageData: {\n closeBrackets: { brackets: ['(', '[', '{', \"'\", '\"', '`'] },\n commentTokens: { line: '#' },\n },\n });\n}\n\nexport interface CompletionConfig {\n /** a LokiClient instance, can be created with LokiDatasource.createClient() */\n client?: LokiClient;\n\n /** search for label values in a given time range */\n timeRange?: AbsoluteTimeRange;\n}\n\nexport function LogQLExtension(completionCfg?: CompletionConfig): Array<LRLanguage | Extension> {\n const language = logqlLanguage();\n\n // Only add autocomplete if config is provided\n if (completionCfg) {\n const completion = language.data.of({\n autocomplete: (ctx: CompletionContext) =>\n complete(completionCfg, ctx).catch((e) => {\n console.error('error during LogQL auto-complete', e);\n return null;\n }),\n });\n return [language, completion];\n }\n\n return [language];\n}\n"],"names":["LRLanguage","parser","logqlHighlight","complete","logqlLanguage","define","configure","props","languageData","closeBrackets","brackets","commentTokens","line","LogQLExtension","completionCfg","language","completion","data","of","autocomplete","ctx","catch","e","console","error"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,UAAU,QAAQ,uBAAuB;AAClD,SAASC,MAAM,QAAQ,uBAAuB;AAK9C,SAASC,cAAc,QAAQ,oBAAoB;AACnD,SAASC,QAAQ,QAAQ,aAAa;AAEtC,SAASC;IACP,OAAOJ,WAAWK,MAAM,CAAC;QACvBJ,QAAQA,OAAOK,SAAS,CAAC;YACvBC,OAAO;gBAACL;aAAe;QACzB;QACAM,cAAc;YACZC,eAAe;gBAAEC,UAAU;oBAAC;oBAAK;oBAAK;oBAAK;oBAAK;oBAAK;iBAAI;YAAC;YAC1DC,eAAe;gBAAEC,MAAM;YAAI;QAC7B;IACF;AACF;AAUA,OAAO,SAASC,eAAeC,aAAgC;IAC7D,MAAMC,WAAWX;IAEjB,8CAA8C;IAC9C,IAAIU,eAAe;QACjB,MAAME,aAAaD,SAASE,IAAI,CAACC,EAAE,CAAC;YAClCC,cAAc,CAACC,MACbjB,SAASW,eAAeM,KAAKC,KAAK,CAAC,CAACC;oBAClCC,QAAQC,KAAK,CAAC,oCAAoCF;oBAClD,OAAO;gBACT;QACJ;QACA,OAAO;YAACP;YAAUC;SAAW;IAC/B;IAEA,OAAO;QAACD;KAAS;AACnB"}
1
+ {"version":3,"sources":["../../../src/components/logql-extension.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { LRLanguage } from '@codemirror/language';\nimport { parser } from '@grafana/lezer-logql';\nimport { CompletionContext } from '@codemirror/autocomplete';\nimport { Extension } from '@uiw/react-codemirror';\nimport { AbsoluteTimeRange } from '@perses-dev/core';\nimport { LokiClient } from '../model';\nimport { logqlHighlight } from './logql-highlight';\nimport { complete } from './complete';\n\nfunction logqlLanguage(): LRLanguage {\n return LRLanguage.define({\n parser: parser.configure({\n props: [logqlHighlight],\n }),\n languageData: {\n closeBrackets: { brackets: ['(', '[', '{', \"'\", '\"', '`'] },\n commentTokens: { line: '#' },\n },\n });\n}\n\nexport interface CompletionConfig {\n /** a LokiClient instance, can be created with LokiDatasource.createClient() */\n client?: LokiClient;\n\n /** search for label values in a given time range */\n timeRange?: AbsoluteTimeRange;\n}\n\nexport function LogQLExtension(completionCfg?: CompletionConfig): Array<LRLanguage | Extension> {\n const language = logqlLanguage();\n\n // Only add autocomplete if config is provided\n if (completionCfg) {\n const completion = language.data.of({\n autocomplete: (ctx: CompletionContext) =>\n complete(completionCfg, ctx).catch((e) => {\n console.error('error during LogQL auto-complete', e);\n return null;\n }),\n });\n return [language, completion];\n }\n\n return [language];\n}\n"],"names":["LRLanguage","parser","logqlHighlight","complete","logqlLanguage","define","configure","props","languageData","closeBrackets","brackets","commentTokens","line","LogQLExtension","completionCfg","language","completion","data","of","autocomplete","ctx","catch","e","console","error"],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,UAAU,QAAQ,uBAAuB;AAClD,SAASC,MAAM,QAAQ,uBAAuB;AAK9C,SAASC,cAAc,QAAQ,oBAAoB;AACnD,SAASC,QAAQ,QAAQ,aAAa;AAEtC,SAASC;IACP,OAAOJ,WAAWK,MAAM,CAAC;QACvBJ,QAAQA,OAAOK,SAAS,CAAC;YACvBC,OAAO;gBAACL;aAAe;QACzB;QACAM,cAAc;YACZC,eAAe;gBAAEC,UAAU;oBAAC;oBAAK;oBAAK;oBAAK;oBAAK;oBAAK;iBAAI;YAAC;YAC1DC,eAAe;gBAAEC,MAAM;YAAI;QAC7B;IACF;AACF;AAUA,OAAO,SAASC,eAAeC,aAAgC;IAC7D,MAAMC,WAAWX;IAEjB,8CAA8C;IAC9C,IAAIU,eAAe;QACjB,MAAME,aAAaD,SAASE,IAAI,CAACC,EAAE,CAAC;YAClCC,cAAc,CAACC,MACbjB,SAASW,eAAeM,KAAKC,KAAK,CAAC,CAACC;oBAClCC,QAAQC,KAAK,CAAC,oCAAoCF;oBAClD,OAAO;gBACT;QACJ;QACA,OAAO;YAACP;YAAUC;SAAW;IAC/B;IAEA,OAAO;QAACD;KAAS;AACnB"}
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/logql-highlight.ts"],"sourcesContent":["// Copyright 2025 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { styleTags, tags } from '@lezer/highlight';\n\nexport const logqlHighlight = styleTags({\n LineComment: tags.comment,\n 'Identifier StreamSelector': tags.labelName,\n 'LabelName LabelMatcher': tags.labelName,\n String: tags.string,\n 'Number Float Duration': tags.number,\n 'LogRangeAggregation VectorAggregation': tags.function(tags.keyword),\n 'And Or Unless': tags.logicOperator,\n 'Eq Neq Re Nre Gt Lt Gte Lte': tags.compareOperator,\n 'Add Sub Mul Div Mod Pow': tags.arithmeticOperator,\n Pipe: tags.operator,\n 'By Without': tags.keyword,\n '( )': tags.paren,\n '[ ]': tags.squareBracket,\n '{ }': tags.brace,\n '⚠': tags.invalid,\n});\n"],"names":["styleTags","tags","logqlHighlight","LineComment","comment","labelName","String","string","number","function","keyword","logicOperator","compareOperator","arithmeticOperator","Pipe","operator","paren","squareBracket","brace","invalid"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,SAAS,EAAEC,IAAI,QAAQ,mBAAmB;AAEnD,OAAO,MAAMC,iBAAiBF,UAAU;IACtCG,aAAaF,KAAKG,OAAO;IACzB,6BAA6BH,KAAKI,SAAS;IAC3C,0BAA0BJ,KAAKI,SAAS;IACxCC,QAAQL,KAAKM,MAAM;IACnB,yBAAyBN,KAAKO,MAAM;IACpC,yCAAyCP,KAAKQ,QAAQ,CAACR,KAAKS,OAAO;IACnE,iBAAiBT,KAAKU,aAAa;IACnC,+BAA+BV,KAAKW,eAAe;IACnD,2BAA2BX,KAAKY,kBAAkB;IAClDC,MAAMb,KAAKc,QAAQ;IACnB,cAAcd,KAAKS,OAAO;IAC1B,OAAOT,KAAKe,KAAK;IACjB,OAAOf,KAAKgB,aAAa;IACzB,OAAOhB,KAAKiB,KAAK;IACjB,KAAKjB,KAAKkB,OAAO;AACnB,GAAG"}
1
+ {"version":3,"sources":["../../../src/components/logql-highlight.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { styleTags, tags } from '@lezer/highlight';\n\nexport const logqlHighlight = styleTags({\n LineComment: tags.comment,\n 'Identifier StreamSelector': tags.labelName,\n 'LabelName LabelMatcher': tags.labelName,\n String: tags.string,\n 'Number Float Duration': tags.number,\n 'LogRangeAggregation VectorAggregation': tags.function(tags.keyword),\n 'And Or Unless': tags.logicOperator,\n 'Eq Neq Re Nre Gt Lt Gte Lte': tags.compareOperator,\n 'Add Sub Mul Div Mod Pow': tags.arithmeticOperator,\n Pipe: tags.operator,\n 'By Without': tags.keyword,\n '( )': tags.paren,\n '[ ]': tags.squareBracket,\n '{ }': tags.brace,\n '⚠': tags.invalid,\n});\n"],"names":["styleTags","tags","logqlHighlight","LineComment","comment","labelName","String","string","number","function","keyword","logicOperator","compareOperator","arithmeticOperator","Pipe","operator","paren","squareBracket","brace","invalid"],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,SAAS,EAAEC,IAAI,QAAQ,mBAAmB;AAEnD,OAAO,MAAMC,iBAAiBF,UAAU;IACtCG,aAAaF,KAAKG,OAAO;IACzB,6BAA6BH,KAAKI,SAAS;IAC3C,0BAA0BJ,KAAKI,SAAS;IACxCC,QAAQL,KAAKM,MAAM;IACnB,yBAAyBN,KAAKO,MAAM;IACpC,yCAAyCP,KAAKQ,QAAQ,CAACR,KAAKS,OAAO;IACnE,iBAAiBT,KAAKU,aAAa;IACnC,+BAA+BV,KAAKW,eAAe;IACnD,2BAA2BX,KAAKY,kBAAkB;IAClDC,MAAMb,KAAKc,QAAQ;IACnB,cAAcd,KAAKS,OAAO;IAC1B,OAAOT,KAAKe,KAAK;IACjB,OAAOf,KAAKgB,aAAa;IACzB,OAAOhB,KAAKiB,KAAK;IACjB,KAAKjB,KAAKkB,OAAO;AACnB,GAAG"}
@@ -1,4 +1,4 @@
1
- // Copyright 2025 The Perses Authors
1
+ // Copyright The Perses Authors
2
2
  // Licensed under the Apache License, Version 2.0 (the "License");
3
3
  // you may not use this file except in compliance with the License.
4
4
  // You may obtain a copy of the License at