@elastic/monaco-esql 3.1.16 → 3.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,9 +19,7 @@ monaco.languages.setMonarchTokensProvider("esql", monarchLanguage);
19
19
 
20
20
  ## Releasing
21
21
 
22
- To release a new version add a `publish` label to the PR.
23
-
24
- There is no need to bump the version manually, release-it does it automatically.
22
+ To release a new version, bump the `version` field in the `package.json` and add a `publish` label to the PR.
25
23
 
26
24
  ## License
27
25
 
@@ -194,6 +194,7 @@ exports.delimiters = [
194
194
  "/",
195
195
  ".",
196
196
  ",",
197
+ ";",
197
198
  "=~",
198
199
  "<=",
199
200
  ">=",
package/lib/monarch.js CHANGED
@@ -9,6 +9,7 @@
9
9
  */
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.create = void 0;
12
+ const promql_1 = require("./promql");
12
13
  const create = (deps = {}) => {
13
14
  const { headerCommands = [], sourceCommands = [], processingCommands = [], options = [], literals = [], functions = [], delimiters = [], temporalUnits = [], } = deps;
14
15
  const timeUnits = withLowercaseVariants(temporalUnits.flat()).sort((a, b) => a > b ? -1 : 1);
@@ -42,7 +43,33 @@ const create = (deps = {}) => {
42
43
  { open: "<", close: ">", token: "delimiter.angle" },
43
44
  ],
44
45
  tokenizer: {
45
- root: [
46
+ root: [{ include: "@firstCommandName" }, { include: "@restOfQuery" }],
47
+ // This block matches the first command name in the query, and identifies it as a source command.
48
+ // Except if it's a header command.
49
+ // This is useful to color querys that starts with "From" instead of "FROM".
50
+ firstCommandName: [
51
+ { include: "@whitespace" },
52
+ [
53
+ /[a-zA-Z]+/,
54
+ {
55
+ cases: {
56
+ "PROMQL|promql": {
57
+ token: "keyword.command.source.promql",
58
+ switchTo: "@promQLCommand",
59
+ },
60
+ "@headerCommands": {
61
+ token: "keyword.command.header.$0",
62
+ switchTo: "@restOfQuery",
63
+ },
64
+ "@default": {
65
+ token: "keyword.command.source.$0",
66
+ switchTo: "@restOfQuery",
67
+ },
68
+ },
69
+ },
70
+ ],
71
+ ],
72
+ restOfQuery: [
46
73
  { include: "@whitespace" },
47
74
  // Keywords
48
75
  [
@@ -64,6 +91,9 @@ const create = (deps = {}) => {
64
91
  },
65
92
  ],
66
93
  { include: "@expression" },
94
+ // If we found a semicolon, means a header command finished.
95
+ // We go back to root to parse the query.
96
+ [/;/, { token: "delimiter", switchTo: "@root" }],
67
97
  { include: "@processingCommand" },
68
98
  [/\[|\(|\)|\]/, "@brackets"],
69
99
  [
@@ -115,25 +145,32 @@ const create = (deps = {}) => {
115
145
  ["", { token: "", switchTo: "@commandName" }],
116
146
  ],
117
147
  exactCommandName: [
148
+ [
149
+ "PROMQL|promql",
150
+ {
151
+ token: "keyword.command.source.promql",
152
+ switchTo: "@promQLCommand",
153
+ },
154
+ ],
118
155
  [
119
156
  withLowercaseVariants(headerCommands).join("|"),
120
- { token: "keyword.command.header.$0", switchTo: "@root" },
157
+ { token: "keyword.command.header.$0", switchTo: "@restOfQuery" },
121
158
  ],
122
159
  [
123
160
  withLowercaseVariants(sourceCommands).join("|"),
124
- { token: "keyword.command.source.$0", switchTo: "@root" },
161
+ { token: "keyword.command.source.$0", switchTo: "@restOfQuery" },
125
162
  ],
126
163
  [
127
164
  withLowercaseVariants(processingCommands).join("|"),
128
- { token: "keyword.command.processing.$0", switchTo: "@root" },
165
+ { token: "keyword.command.processing.$0", switchTo: "@restOfQuery" },
129
166
  ],
130
167
  ],
131
168
  firstCommandNameInSubQuery: [
132
169
  { include: "@whitespace" },
133
170
  // Try to match an exact command name
134
171
  { include: "@exactCommandName" },
135
- // If not matched, go to root
136
- { include: "@root" },
172
+ // If not matched, go to restOfQuery
173
+ { include: "@restOfQuery" },
137
174
  ],
138
175
  // Matches *command name*, i.e. the mnemonic.
139
176
  commandName: [
@@ -142,7 +179,7 @@ const create = (deps = {}) => {
142
179
  // If command name is not well known, just matches the first word.
143
180
  [
144
181
  /\w+\b/,
145
- { token: "keyword.command.processing.$0", switchTo: "@root" },
182
+ { token: "keyword.command.processing.$0", switchTo: "@restOfQuery" },
146
183
  ],
147
184
  ],
148
185
  // ------------------------------------------------------------- Expressions
@@ -208,6 +245,8 @@ const create = (deps = {}) => {
208
245
  [/\\./, "string.escape.invalid"],
209
246
  [/`/, "string", "@pop"],
210
247
  ],
248
+ // ------------------------------------------------------------- PROMQL
249
+ ...promql_1.promQLStates,
211
250
  },
212
251
  };
213
252
  };
@@ -0,0 +1,36 @@
1
+ import type { languages } from "monaco-editor";
2
+ /**
3
+ * In order to handle the PROMQL command we need to solve two problems:
4
+ * 1. Detect when the params section ends and the query starts, so we can apply the promql query embedding.
5
+ * For this we tokenize the params section with dedicated states, before delegating to the promql query embedding.
6
+ *
7
+ * 2. We need to correctly tokenize ES|QL comments syntax within a promql query.
8
+ * For this we use the promQLQuery state, which is applied while tokenizing the query content.
9
+ * It will tell the embedded language when the query ends (when a pipe is found).
10
+ * And will switch to dedicated states for handling comments.
11
+ */
12
+ /** Main state for PROMQL command. */
13
+ export declare const promQLCommand: languages.IMonarchLanguageRule[];
14
+ /**
15
+ * State to tokenize param name, then switch to value
16
+ */
17
+ export declare const promqlParam: languages.IMonarchLanguageRule[];
18
+ /**
19
+ * State to parse param values.
20
+ * The way of detecting a param value ended is by detecting whitespaces that are not followed by a comma.
21
+ * Example of a value that contains a list of indexes: index-*, `index`, index::selector, ?param, "index"
22
+ */
23
+ export declare const promqlParamValue: languages.IMonarchLanguageRule[];
24
+ /**
25
+ * These rules are applied while tokenizing the query content (inside the embedding language).
26
+ * They run "in parallel" with the rules from the embedded language.
27
+ * We use them the tell the embedded language when the query ends (when a pipe is found).
28
+ * And to be able to tokenize ES|QL comments within the PROMQL query.
29
+ */
30
+ export declare const promQLQuery: languages.IMonarchLanguageRule[];
31
+ /**
32
+ * All PromQL tokenizer states needed to tokenize a PROMQL command bundled in one object.
33
+ */
34
+ export declare const promQLStates: {
35
+ [name: string]: languages.IMonarchLanguageRule[];
36
+ };
package/lib/promql.js ADDED
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.promQLStates = exports.promQLQuery = exports.promqlParamValue = exports.promqlParam = exports.promQLCommand = void 0;
4
+ /**
5
+ * In order to handle the PROMQL command we need to solve two problems:
6
+ * 1. Detect when the params section ends and the query starts, so we can apply the promql query embedding.
7
+ * For this we tokenize the params section with dedicated states, before delegating to the promql query embedding.
8
+ *
9
+ * 2. We need to correctly tokenize ES|QL comments syntax within a promql query.
10
+ * For this we use the promQLQuery state, which is applied while tokenizing the query content.
11
+ * It will tell the embedded language when the query ends (when a pipe is found).
12
+ * And will switch to dedicated states for handling comments.
13
+ */
14
+ /** Main state for PROMQL command. */
15
+ exports.promQLCommand = [
16
+ { include: "@whitespace" },
17
+ // Match param pattern: paramName = ...
18
+ [/[a-zA-Z0-9_*?"`-]+\s*=\s*/, { token: "@rematch", next: "@promqlParam" }],
19
+ // Start PromQL query embedding (no more params)
20
+ [
21
+ /.+/,
22
+ { token: "@rematch", switchTo: "@promQLQuery", nextEmbedded: "promql" },
23
+ ],
24
+ ];
25
+ /**
26
+ * State to tokenize param name, then switch to value
27
+ */
28
+ exports.promqlParam = [
29
+ // Match param name
30
+ { include: "@expression" },
31
+ // Tokenize assignment and go to value
32
+ [/=\s*/, { token: "delimiter.assignment", switchTo: "@promqlParamValue" }],
33
+ ];
34
+ /**
35
+ * State to parse param values.
36
+ * The way of detecting a param value ended is by detecting whitespaces that are not followed by a comma.
37
+ * Example of a value that contains a list of indexes: index-*, `index`, index::selector, ?param, "index"
38
+ */
39
+ exports.promqlParamValue = [
40
+ // Whitespace handling: comma continues list, otherwise pop
41
+ [/\s+(?=,)/, ""], // Whitespace before comma - continue
42
+ [/\s+/, { token: "", next: "@pop" }], // Whitespace not before comma - pop (query or next param)
43
+ // Match value content
44
+ { include: "@expression" },
45
+ // Comma continues the list
46
+ [/,\s*/, "delimiter.comma"],
47
+ // Fallback: pop if nothing else matches
48
+ ["", { token: "", next: "@pop" }],
49
+ ];
50
+ /**
51
+ * These rules are applied while tokenizing the query content (inside the embedding language).
52
+ * They run "in parallel" with the rules from the embedded language.
53
+ * We use them the tell the embedded language when the query ends (when a pipe is found).
54
+ * And to be able to tokenize ES|QL comments within the PROMQL query.
55
+ */
56
+ exports.promQLQuery = [
57
+ // Rules to delegate comments to ES|QL
58
+ [
59
+ /\/\*\*(?!\/)/,
60
+ {
61
+ token: "comment.doc",
62
+ next: "@promqlDocComment",
63
+ nextEmbedded: "@pop",
64
+ },
65
+ ],
66
+ [/\/\*/, { token: "comment", next: "@promqlComment", nextEmbedded: "@pop" }],
67
+ [
68
+ /\/\//,
69
+ {
70
+ token: "comment",
71
+ next: "@promqlLineComment",
72
+ nextEmbedded: "@pop",
73
+ },
74
+ ],
75
+ // String handling, to avoid exiting when finding a pipe inside a string.
76
+ [/"/, { token: "string", next: "@promqlDoubleString", nextEmbedded: "@pop" }],
77
+ [
78
+ /`/,
79
+ { token: "string", next: "@promqlBacktickString", nextEmbedded: "@pop" },
80
+ ],
81
+ // Exit condition
82
+ [
83
+ /\|/,
84
+ {
85
+ token: "delimiter.pipe",
86
+ switchTo: "@beforeMnemonicWhitespace",
87
+ nextEmbedded: "@pop",
88
+ },
89
+ ],
90
+ ];
91
+ /**
92
+ * These states are used for returning control to the promql embedding after a comment or string ends.
93
+ */
94
+ const promQLQueryOverrideRules = {
95
+ promqlDocComment: [
96
+ [/[^/*]+/, "comment.doc"],
97
+ [/\*\//, { token: "comment.doc", next: "@pop", nextEmbedded: "promql" }],
98
+ [/[/*]/, "comment.doc"],
99
+ ],
100
+ promqlComment: [
101
+ [/[^/*]+/, "comment"],
102
+ [/\*\//, { token: "comment", next: "@pop", nextEmbedded: "promql" }],
103
+ [/[/*]/, "comment"],
104
+ ],
105
+ promqlLineComment: [
106
+ [/.*$/, { token: "comment", next: "@pop", nextEmbedded: "promql" }],
107
+ ],
108
+ promqlDoubleString: [
109
+ [/[^"\\]+/, "string"],
110
+ [/\\./, "string.escape"],
111
+ [/"/, { token: "string", next: "@pop", nextEmbedded: "promql" }],
112
+ ],
113
+ promqlBacktickString: [
114
+ [/[^`\\]+/, "string"],
115
+ [/\\./, "string.escape"],
116
+ [/`/, { token: "string", next: "@pop", nextEmbedded: "promql" }],
117
+ ],
118
+ };
119
+ /**
120
+ * All PromQL tokenizer states needed to tokenize a PROMQL command bundled in one object.
121
+ */
122
+ exports.promQLStates = {
123
+ promQLCommand: exports.promQLCommand,
124
+ promqlParam: exports.promqlParam,
125
+ promqlParamValue: exports.promqlParamValue,
126
+ promQLQuery: exports.promQLQuery,
127
+ ...promQLQueryOverrideRules,
128
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elastic/monaco-esql",
3
- "version": "3.1.16",
3
+ "version": "3.1.18",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -24,7 +24,7 @@
24
24
  "build": "yarn build:es2020",
25
25
  "storybook": "storybook dev -p 6006",
26
26
  "build-storybook": "storybook build",
27
- "release": "npx release-it --ci",
27
+ "release": "npx release-it --ci --no-increment",
28
28
  "prepare": "husky"
29
29
  },
30
30
  "license": "MIT",
@@ -49,35 +49,42 @@
49
49
  },
50
50
  "homepage": "https://github.com/elastic/monaco-esql",
51
51
  "peerDependencies": {
52
- "monaco-editor": "*"
52
+ "monaco-editor": "*",
53
+ "monaco-promql": "*"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "monaco-promql": {
57
+ "optional": true
58
+ }
53
59
  },
54
60
  "devDependencies": {
55
- "@babel/eslint-parser": "7.28.5",
61
+ "@babel/eslint-parser": "7.28.6",
56
62
  "@biomejs/biome": "2.3.11",
57
- "@chromatic-com/storybook": "4.1.3",
63
+ "@chromatic-com/storybook": "5.0.0",
58
64
  "@eslint/js": "9.39.2",
59
65
  "@monaco-editor/react": "4.7.0",
60
- "@storybook/addon-docs": "10.1.11",
61
- "@storybook/addon-onboarding": "10.1.11",
62
- "@storybook/addon-vitest": "10.1.11",
63
- "@storybook/react-vite": "10.1.11",
64
- "@types/react": "19.2.7",
65
- "@vitest/browser": "4.0.16",
66
- "@vitest/browser-playwright": "4.0.16",
67
- "@vitest/coverage-v8": "4.0.16",
66
+ "@storybook/addon-docs": "10.2.6",
67
+ "@storybook/addon-onboarding": "10.2.6",
68
+ "@storybook/addon-vitest": "10.2.6",
69
+ "@storybook/react-vite": "10.2.6",
70
+ "@types/react": "19.2.9",
71
+ "@vitest/browser": "4.0.18",
72
+ "@vitest/browser-playwright": "4.0.18",
73
+ "@vitest/coverage-v8": "4.0.18",
68
74
  "eslint": "9.39.2",
69
75
  "eslint-plugin-react": "7.37.5",
70
- "globals": "17.0.0",
76
+ "globals": "17.3.0",
71
77
  "husky": "9.1.7",
72
78
  "lint-staged": "16.2.7",
73
79
  "monaco-editor": "0.55.1",
74
- "playwright": "1.57.0",
80
+ "monaco-promql": "1.8.0",
81
+ "playwright": "1.58.1",
75
82
  "react": "19.2.3",
76
83
  "react-dom": "19.2.3",
77
- "storybook": "10.1.11",
84
+ "storybook": "10.2.6",
78
85
  "typescript": "5.9.3",
79
- "typescript-eslint": "8.52.0",
80
- "vitest": "4.0.16"
86
+ "typescript-eslint": "8.54.0",
87
+ "vitest": "4.0.18"
81
88
  },
82
89
  "lint-staged": {
83
90
  "*.{js,ts,tsx,mjs}": [