@grafana/create-plugin 6.8.0-canary.2356.20813734793.0 → 6.8.0-canary.2356.20814023201.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # v6.7.1 (Thu Jan 08 2026)
2
+
3
+ #### 🐛 Bug Fix
4
+
5
+ - fix: stop copying all images to bundle [#2369](https://github.com/grafana/plugin-tools/pull/2369) ([@jackw](https://github.com/jackw))
6
+
7
+ #### Authors: 1
8
+
9
+ - Jack Westbrook ([@jackw](https://github.com/jackw))
10
+
11
+ ---
12
+
1
13
  # v6.7.0 (Wed Jan 07 2026)
2
14
 
3
15
  #### 🚀 Enhancement
@@ -2,39 +2,30 @@ import * as v from 'valibot';
2
2
  import * as recast from 'recast';
3
3
  import { coerce, gte } from 'semver';
4
4
  import { additionsDebug } from '../../../utils.js';
5
- import { updateBundlerConfig } from '../../../utils.bundler-config.js';
6
5
  import { updateExternalsArray } from '../../../utils.externals.js';
7
6
 
8
7
  const { builders } = recast.types;
9
8
  const PLUGIN_JSON_PATH = "src/plugin.json";
10
9
  const MIN_GRAFANA_VERSION = "10.2.0";
10
+ const WEBPACK_CONFIG_PATH = ".config/webpack/webpack.config.ts";
11
+ const RSPACK_CONFIG_PATH = ".config/rspack/rspack.config.ts";
11
12
  const schema = v.object({});
12
13
  function bundleGrafanaUI(context, _options) {
13
14
  additionsDebug("Running bundle-grafana-ui addition...");
14
15
  ensureMinGrafanaVersion(context);
15
16
  updateExternalsArray(context, createBundleGrafanaUIModifier());
16
- updateBundlerConfig(context, createResolveModifier(), createModuleRulesModifier());
17
+ updateResolveExtensions(context);
18
+ updateModuleRules(context);
17
19
  return context;
18
20
  }
19
- function isGrafanaUiRegex(element) {
21
+ function isGrafanaRegex(element, pattern) {
20
22
  if (element.type === "RegExpLiteral") {
21
23
  const regexNode = element;
22
- return regexNode.pattern === "^@grafana\\/ui" && regexNode.flags === "i";
24
+ return regexNode.pattern === pattern && regexNode.flags === "i";
23
25
  }
24
26
  if (element.type === "Literal" && "regex" in element && element.regex) {
25
27
  const regex = element.regex;
26
- return regex.pattern === "^@grafana\\/ui" && regex.flags === "i";
27
- }
28
- return false;
29
- }
30
- function isGrafanaDataRegex(element) {
31
- if (element.type === "RegExpLiteral") {
32
- const regexNode = element;
33
- return regexNode.pattern === "^@grafana\\/data" && regexNode.flags === "i";
34
- }
35
- if (element.type === "Literal" && "regex" in element && element.regex) {
36
- const regex = element.regex;
37
- return regex.pattern === "^@grafana\\/data" && regex.flags === "i";
28
+ return regex.pattern === pattern && regex.flags === "i";
38
29
  }
39
30
  return false;
40
31
  }
@@ -46,7 +37,7 @@ function removeGrafanaUiAndAddReactInlineSvg(externalsArray) {
46
37
  if (!element) {
47
38
  continue;
48
39
  }
49
- if (isGrafanaUiRegex(element)) {
40
+ if (isGrafanaRegex(element, "^@grafana\\/ui")) {
50
41
  hasGrafanaUiExternal = true;
51
42
  }
52
43
  if ((element.type === "Literal" || element.type === "StringLiteral") && "value" in element && typeof element.value === "string" && element.value === "react-inlinesvg") {
@@ -58,7 +49,7 @@ function removeGrafanaUiAndAddReactInlineSvg(externalsArray) {
58
49
  if (!element) {
59
50
  return true;
60
51
  }
61
- return !isGrafanaUiRegex(element);
52
+ return !isGrafanaRegex(element, "^@grafana\\/ui");
62
53
  });
63
54
  hasChanges = true;
64
55
  additionsDebug("Removed /^@grafana\\/ui/i from externals array");
@@ -67,7 +58,7 @@ function removeGrafanaUiAndAddReactInlineSvg(externalsArray) {
67
58
  let insertIndex = -1;
68
59
  for (let i = 0; i < externalsArray.elements.length; i++) {
69
60
  const element = externalsArray.elements[i];
70
- if (element && isGrafanaDataRegex(element)) {
61
+ if (element && isGrafanaRegex(element, "^@grafana\\/data")) {
71
62
  insertIndex = i + 1;
72
63
  break;
73
64
  }
@@ -87,106 +78,66 @@ function createBundleGrafanaUIModifier() {
87
78
  return removeGrafanaUiAndAddReactInlineSvg(externalsArray);
88
79
  };
89
80
  }
90
- function createResolveModifier() {
91
- return (resolveObject) => {
92
- if (!resolveObject.properties) {
93
- return false;
94
- }
95
- let hasChanges = false;
96
- let hasMjsExtension = false;
97
- let extensionsProperty = null;
98
- for (const prop of resolveObject.properties) {
99
- if (!prop || prop.type !== "Property" && prop.type !== "ObjectProperty") {
100
- continue;
101
- }
102
- const key = "key" in prop ? prop.key : null;
103
- const value = "value" in prop ? prop.value : null;
104
- if (key && key.type === "Identifier") {
105
- if (key.name === "extensions" && value && value.type === "ArrayExpression") {
106
- extensionsProperty = prop;
107
- for (const element of value.elements) {
108
- if (element && (element.type === "Literal" || element.type === "StringLiteral") && "value" in element && element.value === ".mjs") {
109
- hasMjsExtension = true;
110
- break;
111
- }
112
- }
113
- }
114
- }
115
- }
116
- if (!hasMjsExtension && extensionsProperty && "value" in extensionsProperty) {
117
- const extensionsArray = extensionsProperty.value;
118
- extensionsArray.elements.push(builders.literal(".mjs"));
119
- hasChanges = true;
120
- additionsDebug("Added '.mjs' to resolve.extensions");
81
+ function updateResolveExtensions(context) {
82
+ const configPath = context.doesFileExist(RSPACK_CONFIG_PATH) ? RSPACK_CONFIG_PATH : context.doesFileExist(WEBPACK_CONFIG_PATH) ? WEBPACK_CONFIG_PATH : null;
83
+ if (!configPath) {
84
+ return;
85
+ }
86
+ const content = context.getFile(configPath);
87
+ if (!content) {
88
+ return;
89
+ }
90
+ if (content.includes("'.mjs'") || content.includes('".mjs"')) {
91
+ return;
92
+ }
93
+ const updated = content.replace(/(extensions:\s*\[)([^\]]+)(\])/, (match, prefix, extensions, suffix) => {
94
+ if (extensions.includes(".mjs")) {
95
+ return match;
121
96
  }
122
- return hasChanges;
123
- };
97
+ return `${prefix}${extensions}, '.mjs'${suffix}`;
98
+ });
99
+ if (updated !== content) {
100
+ context.updateFile(configPath, updated);
101
+ additionsDebug("Added '.mjs' to resolve.extensions");
102
+ }
124
103
  }
125
- function createModuleRulesModifier() {
126
- return (moduleObject) => {
127
- if (!moduleObject.properties) {
128
- return false;
129
- }
130
- let hasChanges = false;
131
- let hasMjsRule = false;
132
- let rulesProperty = null;
133
- for (const prop of moduleObject.properties) {
134
- if (!prop || prop.type !== "Property" && prop.type !== "ObjectProperty") {
135
- continue;
136
- }
137
- const key = "key" in prop ? prop.key : null;
138
- const value = "value" in prop ? prop.value : null;
139
- if (key && key.type === "Identifier" && key.name === "rules" && value && value.type === "ArrayExpression") {
140
- rulesProperty = prop;
141
- for (const element of value.elements) {
142
- if (element && element.type === "ObjectExpression" && element.properties) {
143
- for (const ruleProp of element.properties) {
144
- if (ruleProp && (ruleProp.type === "Property" || ruleProp.type === "ObjectProperty") && "key" in ruleProp && ruleProp.key.type === "Identifier" && ruleProp.key.name === "test") {
145
- const testValue = "value" in ruleProp ? ruleProp.value : null;
146
- if (testValue) {
147
- if (testValue.type === "RegExpLiteral" && "pattern" in testValue && testValue.pattern === "\\.mjs$") {
148
- hasMjsRule = true;
149
- break;
150
- }
151
- if (testValue.type === "Literal" && "regex" in testValue && testValue.regex && typeof testValue.regex === "object" && "pattern" in testValue.regex && testValue.regex.pattern === "\\.mjs$") {
152
- hasMjsRule = true;
153
- break;
154
- }
155
- if (testValue.type === "Literal" && "value" in testValue && typeof testValue.value === "string" && testValue.value.includes(".mjs")) {
156
- hasMjsRule = true;
157
- break;
158
- }
159
- }
160
- }
161
- }
162
- }
163
- if (hasMjsRule) {
164
- break;
165
- }
166
- }
167
- break;
104
+ function updateModuleRules(context) {
105
+ const configPath = context.doesFileExist(RSPACK_CONFIG_PATH) ? RSPACK_CONFIG_PATH : context.doesFileExist(WEBPACK_CONFIG_PATH) ? WEBPACK_CONFIG_PATH : null;
106
+ if (!configPath) {
107
+ return;
108
+ }
109
+ const content = context.getFile(configPath);
110
+ if (!content) {
111
+ return;
112
+ }
113
+ if (content.includes("test: /\\.mjs$") || content.includes("test: /\\\\.mjs$")) {
114
+ return;
115
+ }
116
+ const mjsRule = `{
117
+ test: /\\.mjs$/,
118
+ include: /node_modules/,
119
+ resolve: {
120
+ fullySpecified: false,
121
+ },
122
+ type: 'javascript/auto',
123
+ },`;
124
+ let updated = content;
125
+ if (content.match(/rules:\s*\[\s*\]/)) {
126
+ updated = content.replace(/(rules:\s*\[\s*)(\])/, `$1${mjsRule}
127
+ $2`);
128
+ } else {
129
+ updated = content.replace(/(rules:\s*\[\s*)(\{[\s\S]*?\}),(\s*)/, (match, prefix, firstRule, suffix) => {
130
+ if (match.includes("test: /\\.mjs$")) {
131
+ return match;
168
132
  }
169
- }
170
- if (!hasMjsRule && rulesProperty && "value" in rulesProperty) {
171
- const rulesArray = rulesProperty.value;
172
- const mjsRule = builders.objectExpression([
173
- builders.property("init", builders.identifier("test"), builders.literal(/\.mjs$/)),
174
- builders.property("init", builders.identifier("include"), builders.literal(/node_modules/)),
175
- builders.property(
176
- "init",
177
- builders.identifier("resolve"),
178
- builders.objectExpression([
179
- builders.property("init", builders.identifier("fullySpecified"), builders.literal(false))
180
- ])
181
- ),
182
- builders.property("init", builders.identifier("type"), builders.literal("javascript/auto"))
183
- ]);
184
- rulesArray.elements.splice(1, 0, mjsRule);
185
- hasChanges = true;
186
- additionsDebug("Added module rule for .mjs files in node_modules with resolve.fullySpecified: false");
187
- }
188
- return hasChanges;
189
- };
133
+ return `${prefix}${firstRule},
134
+ ${mjsRule}${suffix}`;
135
+ });
136
+ }
137
+ if (updated !== content) {
138
+ context.updateFile(configPath, updated);
139
+ additionsDebug("Added module rule for .mjs files in node_modules with resolve.fullySpecified: false");
140
+ }
190
141
  }
191
142
  function ensureMinGrafanaVersion(context) {
192
143
  if (!context.doesFileExist(PLUGIN_JSON_PATH)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/create-plugin",
3
- "version": "6.8.0-canary.2356.20813734793.0",
3
+ "version": "6.8.0-canary.2356.20814023201.0",
4
4
  "repository": {
5
5
  "directory": "packages/create-plugin",
6
6
  "url": "https://github.com/grafana/plugin-tools"
@@ -55,5 +55,5 @@
55
55
  "engines": {
56
56
  "node": ">=20"
57
57
  },
58
- "gitHead": "7dc0a04f78794e1d23d24b13fa2dfaa5a4312bc3"
58
+ "gitHead": "c56736e56659f6e4b808d59225f1807e32e94062"
59
59
  }
@@ -4,13 +4,14 @@ import { coerce, gte } from 'semver';
4
4
 
5
5
  import type { Context } from '../../../context.js';
6
6
  import { additionsDebug } from '../../../utils.js';
7
- import { updateBundlerConfig, type ModuleRulesModifier, type ResolveModifier } from '../../../utils.bundler-config.js';
8
7
  import { updateExternalsArray, type ExternalsArrayModifier } from '../../../utils.externals.js';
9
8
 
10
9
  const { builders } = recast.types;
11
10
 
12
11
  const PLUGIN_JSON_PATH = 'src/plugin.json';
13
12
  const MIN_GRAFANA_VERSION = '10.2.0';
13
+ const WEBPACK_CONFIG_PATH = '.config/webpack/webpack.config.ts';
14
+ const RSPACK_CONFIG_PATH = '.config/rspack/rspack.config.ts';
14
15
 
15
16
  export const schema = v.object({});
16
17
  type BundleGrafanaUIOptions = v.InferOutput<typeof schema>;
@@ -25,43 +26,29 @@ export default function bundleGrafanaUI(context: Context, _options: BundleGrafan
25
26
  updateExternalsArray(context, createBundleGrafanaUIModifier());
26
27
 
27
28
  // Update bundler resolve configuration to handle ESM imports
28
- updateBundlerConfig(context, createResolveModifier(), createModuleRulesModifier());
29
+ updateResolveExtensions(context);
29
30
 
30
- return context;
31
- }
31
+ // Update module rules directly with simple string manipulation
32
+ updateModuleRules(context);
32
33
 
33
- /**
34
- * Checks if an AST node is a regex matching @grafana/ui
35
- * The pattern in the AST is "^@grafana\/ui" (backslash-escaped forward slash)
36
- */
37
- function isGrafanaUiRegex(element: recast.types.namedTypes.ASTNode): boolean {
38
- // Handle RegExpLiteral (TypeScript parser)
39
- if (element.type === 'RegExpLiteral') {
40
- const regexNode = element as recast.types.namedTypes.RegExpLiteral;
41
- return regexNode.pattern === '^@grafana\\/ui' && regexNode.flags === 'i';
42
- }
43
- // Handle Literal with regex property (other parsers)
44
- if (element.type === 'Literal' && 'regex' in element && element.regex) {
45
- const regex = element.regex as { pattern: string; flags: string };
46
- return regex.pattern === '^@grafana\\/ui' && regex.flags === 'i';
47
- }
48
- return false;
34
+ return context;
49
35
  }
50
36
 
51
37
  /**
52
- * Checks if an AST node is a regex matching @grafana/data
53
- * The pattern in the AST is "^@grafana\/data" (backslash-escaped forward slash)
38
+ * Checks if an AST node is a regex matching a Grafana package pattern
39
+ * @param element - The AST node to check
40
+ * @param pattern - The regex pattern to match (e.g., "^@grafana\\/ui" or "^@grafana\\/data")
54
41
  */
55
- function isGrafanaDataRegex(element: recast.types.namedTypes.ASTNode): boolean {
42
+ function isGrafanaRegex(element: recast.types.namedTypes.ASTNode, pattern: string): boolean {
56
43
  // Handle RegExpLiteral (TypeScript parser)
57
44
  if (element.type === 'RegExpLiteral') {
58
45
  const regexNode = element as recast.types.namedTypes.RegExpLiteral;
59
- return regexNode.pattern === '^@grafana\\/data' && regexNode.flags === 'i';
46
+ return regexNode.pattern === pattern && regexNode.flags === 'i';
60
47
  }
61
48
  // Handle Literal with regex property (other parsers)
62
49
  if (element.type === 'Literal' && 'regex' in element && element.regex) {
63
50
  const regex = element.regex as { pattern: string; flags: string };
64
- return regex.pattern === '^@grafana\\/data' && regex.flags === 'i';
51
+ return regex.pattern === pattern && regex.flags === 'i';
65
52
  }
66
53
  return false;
67
54
  }
@@ -82,7 +69,7 @@ function removeGrafanaUiAndAddReactInlineSvg(externalsArray: recast.types.namedT
82
69
  }
83
70
 
84
71
  // Check for /^@grafana\/ui/i regex
85
- if (isGrafanaUiRegex(element)) {
72
+ if (isGrafanaRegex(element, '^@grafana\\/ui')) {
86
73
  hasGrafanaUiExternal = true;
87
74
  }
88
75
 
@@ -103,7 +90,7 @@ function removeGrafanaUiAndAddReactInlineSvg(externalsArray: recast.types.namedT
103
90
  if (!element) {
104
91
  return true;
105
92
  }
106
- return !isGrafanaUiRegex(element);
93
+ return !isGrafanaRegex(element, '^@grafana\\/ui');
107
94
  });
108
95
  hasChanges = true;
109
96
  additionsDebug('Removed /^@grafana\\/ui/i from externals array');
@@ -115,7 +102,7 @@ function removeGrafanaUiAndAddReactInlineSvg(externalsArray: recast.types.namedT
115
102
  let insertIndex = -1;
116
103
  for (let i = 0; i < externalsArray.elements.length; i++) {
117
104
  const element = externalsArray.elements[i];
118
- if (element && isGrafanaDataRegex(element)) {
105
+ if (element && isGrafanaRegex(element, '^@grafana\\/data')) {
119
106
  insertIndex = i + 1;
120
107
  break;
121
108
  }
@@ -145,158 +132,101 @@ function createBundleGrafanaUIModifier(): ExternalsArrayModifier {
145
132
  }
146
133
 
147
134
  /**
148
- * Creates a modifier function for updateBundlerConfig that adds '.mjs' to resolve.extensions
135
+ * Updates resolve extensions to add .mjs using string manipulation
149
136
  */
150
- function createResolveModifier(): ResolveModifier {
151
- return (resolveObject: recast.types.namedTypes.ObjectExpression): boolean => {
152
- if (!resolveObject.properties) {
153
- return false;
154
- }
155
-
156
- let hasChanges = false;
157
- let hasMjsExtension = false;
158
- let extensionsProperty: recast.types.namedTypes.Property | null = null;
137
+ function updateResolveExtensions(context: Context): void {
138
+ const configPath = context.doesFileExist(RSPACK_CONFIG_PATH)
139
+ ? RSPACK_CONFIG_PATH
140
+ : context.doesFileExist(WEBPACK_CONFIG_PATH)
141
+ ? WEBPACK_CONFIG_PATH
142
+ : null;
143
+
144
+ if (!configPath) {
145
+ return;
146
+ }
159
147
 
160
- // Check current state
161
- for (const prop of resolveObject.properties) {
162
- if (!prop || (prop.type !== 'Property' && prop.type !== 'ObjectProperty')) {
163
- continue;
164
- }
148
+ const content = context.getFile(configPath);
149
+ if (!content) {
150
+ return;
151
+ }
165
152
 
166
- const key = 'key' in prop ? prop.key : null;
167
- const value = 'value' in prop ? prop.value : null;
168
-
169
- if (key && key.type === 'Identifier') {
170
- if (key.name === 'extensions' && value && value.type === 'ArrayExpression') {
171
- extensionsProperty = prop as recast.types.namedTypes.Property;
172
- // Check if .mjs is already in the extensions array
173
- for (const element of value.elements) {
174
- if (
175
- element &&
176
- (element.type === 'Literal' || element.type === 'StringLiteral') &&
177
- 'value' in element &&
178
- element.value === '.mjs'
179
- ) {
180
- hasMjsExtension = true;
181
- break;
182
- }
183
- }
184
- }
185
- }
186
- }
153
+ // Check if .mjs already exists
154
+ if (content.includes("'.mjs'") || content.includes('".mjs"')) {
155
+ return;
156
+ }
187
157
 
188
- // Add .mjs to extensions if missing
189
- if (!hasMjsExtension && extensionsProperty && 'value' in extensionsProperty) {
190
- const extensionsArray = extensionsProperty.value as recast.types.namedTypes.ArrayExpression;
191
- extensionsArray.elements.push(builders.literal('.mjs'));
192
- hasChanges = true;
193
- additionsDebug("Added '.mjs' to resolve.extensions");
158
+ // Add .mjs to extensions array
159
+ const updated = content.replace(/(extensions:\s*\[)([^\]]+)(\])/, (match, prefix, extensions, suffix) => {
160
+ if (extensions.includes('.mjs')) {
161
+ return match;
194
162
  }
163
+ return `${prefix}${extensions}, '.mjs'${suffix}`;
164
+ });
195
165
 
196
- return hasChanges;
197
- };
166
+ if (updated !== content) {
167
+ context.updateFile(configPath, updated);
168
+ additionsDebug("Added '.mjs' to resolve.extensions");
169
+ }
198
170
  }
199
171
 
200
172
  /**
201
- * Creates a modifier function for updateBundlerConfig that adds a module rule for .mjs files
202
- * in node_modules with resolve.fullySpecified: false
173
+ * Updates module rules to add .mjs rule using string manipulation
203
174
  */
204
- function createModuleRulesModifier(): ModuleRulesModifier {
205
- return (moduleObject: recast.types.namedTypes.ObjectExpression): boolean => {
206
- if (!moduleObject.properties) {
207
- return false;
208
- }
175
+ function updateModuleRules(context: Context): void {
176
+ const configPath = context.doesFileExist(RSPACK_CONFIG_PATH)
177
+ ? RSPACK_CONFIG_PATH
178
+ : context.doesFileExist(WEBPACK_CONFIG_PATH)
179
+ ? WEBPACK_CONFIG_PATH
180
+ : null;
181
+
182
+ if (!configPath) {
183
+ return;
184
+ }
209
185
 
210
- let hasChanges = false;
211
- let hasMjsRule = false;
212
- let rulesProperty: recast.types.namedTypes.Property | null = null;
186
+ const content = context.getFile(configPath);
187
+ if (!content) {
188
+ return;
189
+ }
213
190
 
214
- // Find the rules property
215
- for (const prop of moduleObject.properties) {
216
- if (!prop || (prop.type !== 'Property' && prop.type !== 'ObjectProperty')) {
217
- continue;
218
- }
191
+ // Check if rule already exists
192
+ if (content.includes('test: /\\.mjs$') || content.includes('test: /\\\\.mjs$')) {
193
+ return;
194
+ }
219
195
 
220
- const key = 'key' in prop ? prop.key : null;
221
- const value = 'value' in prop ? prop.value : null;
222
-
223
- if (key && key.type === 'Identifier' && key.name === 'rules' && value && value.type === 'ArrayExpression') {
224
- rulesProperty = prop as recast.types.namedTypes.Property;
225
- // Check if .mjs rule already exists
226
- for (const element of value.elements) {
227
- if (element && element.type === 'ObjectExpression' && element.properties) {
228
- for (const ruleProp of element.properties) {
229
- if (
230
- ruleProp &&
231
- (ruleProp.type === 'Property' || ruleProp.type === 'ObjectProperty') &&
232
- 'key' in ruleProp &&
233
- ruleProp.key.type === 'Identifier' &&
234
- ruleProp.key.name === 'test'
235
- ) {
236
- const testValue = 'value' in ruleProp ? ruleProp.value : null;
237
- if (testValue) {
238
- // Check for RegExpLiteral with .mjs pattern
239
- if (testValue.type === 'RegExpLiteral' && 'pattern' in testValue && testValue.pattern === '\\.mjs$') {
240
- hasMjsRule = true;
241
- break;
242
- }
243
- // Check for Literal with regex property
244
- if (
245
- testValue.type === 'Literal' &&
246
- 'regex' in testValue &&
247
- testValue.regex &&
248
- typeof testValue.regex === 'object' &&
249
- 'pattern' in testValue.regex &&
250
- testValue.regex.pattern === '\\.mjs$'
251
- ) {
252
- hasMjsRule = true;
253
- break;
254
- }
255
- // Check for string literal containing .mjs
256
- if (
257
- testValue.type === 'Literal' &&
258
- 'value' in testValue &&
259
- typeof testValue.value === 'string' &&
260
- testValue.value.includes('.mjs')
261
- ) {
262
- hasMjsRule = true;
263
- break;
264
- }
265
- }
266
- }
267
- }
268
- }
269
- if (hasMjsRule) {
270
- break;
271
- }
272
- }
273
- break;
196
+ const mjsRule = `{
197
+ test: /\\.mjs$/,
198
+ include: /node_modules/,
199
+ resolve: {
200
+ fullySpecified: false,
201
+ },
202
+ type: 'javascript/auto',
203
+ },`;
204
+
205
+ // Simple approach: find rules array and insert after first rule
206
+ let updated = content;
207
+
208
+ // Case 1: Empty array - insert at start
209
+ if (content.match(/rules:\s*\[\s*\]/)) {
210
+ updated = content.replace(/(rules:\s*\[\s*)(\])/, `$1${mjsRule}\n $2`);
211
+ }
212
+ // Case 2: Find first rule and insert after it
213
+ else {
214
+ // Match: rules: [ { ... }, and insert mjs rule after the first rule
215
+ // The regex finds the first complete rule object (balanced braces)
216
+ updated = content.replace(/(rules:\s*\[\s*)(\{[\s\S]*?\}),(\s*)/, (match, prefix, firstRule, suffix) => {
217
+ // Check if we already inserted (avoid double insertion)
218
+ if (match.includes('test: /\\.mjs$')) {
219
+ return match;
274
220
  }
275
- }
276
-
277
- // Add .mjs rule if missing (insert at position 1, after imports-loader rule which must be first)
278
- if (!hasMjsRule && rulesProperty && 'value' in rulesProperty) {
279
- const rulesArray = rulesProperty.value as recast.types.namedTypes.ArrayExpression;
280
- const mjsRule = builders.objectExpression([
281
- builders.property('init', builders.identifier('test'), builders.literal(/\.mjs$/)),
282
- builders.property('init', builders.identifier('include'), builders.literal(/node_modules/)),
283
- builders.property(
284
- 'init',
285
- builders.identifier('resolve'),
286
- builders.objectExpression([
287
- builders.property('init', builders.identifier('fullySpecified'), builders.literal(false)),
288
- ])
289
- ),
290
- builders.property('init', builders.identifier('type'), builders.literal('javascript/auto')),
291
- ]);
292
- // Insert at position 1 (second position) to keep imports-loader first
293
- rulesArray.elements.splice(1, 0, mjsRule);
294
- hasChanges = true;
295
- additionsDebug('Added module rule for .mjs files in node_modules with resolve.fullySpecified: false');
296
- }
221
+ // Insert mjs rule after first rule
222
+ return `${prefix}${firstRule},\n ${mjsRule}${suffix}`;
223
+ });
224
+ }
297
225
 
298
- return hasChanges;
299
- };
226
+ if (updated !== content) {
227
+ context.updateFile(configPath, updated);
228
+ additionsDebug('Added module rule for .mjs files in node_modules with resolve.fullySpecified: false');
229
+ }
300
230
  }
301
231
 
302
232
  /**
@@ -21,7 +21,8 @@ import { externals } from '../bundler/externals';
21
21
  const { SubresourceIntegrityPlugin } = rspack.experiments;
22
22
  const pluginJson = getPluginJson();
23
23
  const cpVersion = getCPConfigVersion();
24
-
24
+ const logoPaths = Array.from(new Set([pluginJson.info?.logos?.large, pluginJson.info?.logos?.small])).filter(Boolean);
25
+ const screenshotPaths = pluginJson.info?.screenshots?.map((s: { path: string }) => s.path) || [];
25
26
  const virtualPublicPath = new RspackVirtualModulePlugin({
26
27
  'grafana-public-path': `
27
28
  import amdMetaModule from 'amd-module';
@@ -161,14 +162,13 @@ const config = async (env): Promise<Configuration> => {
161
162
  { from: 'plugin.json', to: '.' },
162
163
  { from: '../LICENSE', to: '.' },
163
164
  { from: '../CHANGELOG.md', to: '.', force: true },
164
- { from: '**/*.json', to: '.' }, // TODO<Add an error for checking the basic structure of the repo>
165
- { from: '**/*.svg', to: '.', noErrorOnMissing: true }, // Optional
166
- { from: '**/*.png', to: '.', noErrorOnMissing: true }, // Optional
167
- { from: '**/*.html', to: '.', noErrorOnMissing: true }, // Optional
168
- { from: 'img/**/*', to: '.', noErrorOnMissing: true }, // Optional
169
- { from: 'libs/**/*', to: '.', noErrorOnMissing: true }, // Optional
170
- { from: 'static/**/*', to: '.', noErrorOnMissing: true }, // Optional
171
- { from: '**/query_help.md', to: '.', noErrorOnMissing: true }, // Optional
165
+ { from: '**/*.json', to: '.' },
166
+ { from: '**/query_help.md', to: '.', noErrorOnMissing: true },
167
+ ...logoPaths.map((logoPath) => ({ from: logoPath, to: logoPath })),
168
+ ...screenshotPaths.map((screenshotPath) => ({
169
+ from: screenshotPath,
170
+ to: screenshotPath,
171
+ })),
172
172
  ],
173
173
  }),
174
174
  // Replace certain template-variables in the README and plugin.json
@@ -24,7 +24,8 @@ import { externals } from '../bundler/externals.ts';
24
24
  const pluginJson = getPluginJson();
25
25
  const cpVersion = getCPConfigVersion();
26
26
  const pluginVersion = getPackageJson().version;
27
-
27
+ const logoPaths = Array.from(new Set([pluginJson.info?.logos?.large, pluginJson.info?.logos?.small])).filter(Boolean);
28
+ const screenshotPaths = pluginJson.info?.screenshots?.map((s: { path: string }) => s.path) || [];
28
29
  const virtualPublicPath = new VirtualModulesPlugin({
29
30
  'node_modules/grafana-public-path.js': `
30
31
  import amdMetaModule from 'amd-module';
@@ -174,13 +175,12 @@ const config = async (env: Env): Promise<Configuration> => {
174
175
  { from: '../LICENSE', to: '.' },
175
176
  { from: '../CHANGELOG.md', to: '.', force: true },
176
177
  { from: '**/*.json', to: '.' },
177
- { from: '**/*.svg', to: '.', noErrorOnMissing: true },
178
- { from: '**/*.png', to: '.', noErrorOnMissing: true },
179
- { from: '**/*.html', to: '.', noErrorOnMissing: true },
180
- { from: 'img/**/*', to: '.', noErrorOnMissing: true },
181
- { from: 'libs/**/*', to: '.', noErrorOnMissing: true },
182
- { from: 'static/**/*', to: '.', noErrorOnMissing: true },
183
178
  { from: '**/query_help.md', to: '.', noErrorOnMissing: true },
179
+ ...logoPaths.map((logoPath) => ({ from: logoPath, to: logoPath })),
180
+ ...screenshotPaths.map((screenshotPath) => ({
181
+ from: screenshotPath,
182
+ to: screenshotPath,
183
+ })),
184
184
  ],
185
185
  }),
186
186
  // Replace certain template-variables in the README and plugin.json
@@ -1,102 +0,0 @@
1
- import * as recast from 'recast';
2
- import * as typeScriptParser from 'recast/parsers/typescript.js';
3
- import { additionsDebug } from './utils.js';
4
-
5
- const WEBPACK_CONFIG_PATH = ".config/webpack/webpack.config.ts";
6
- const RSPACK_CONFIG_PATH = ".config/rspack/rspack.config.ts";
7
- function updateBundlerConfig(context, resolveModifier, moduleRulesModifier) {
8
- if (!resolveModifier && !moduleRulesModifier) {
9
- return;
10
- }
11
- if (context.doesFileExist(RSPACK_CONFIG_PATH)) {
12
- additionsDebug(`Found ${RSPACK_CONFIG_PATH}, updating bundler configuration...`);
13
- const rspackContent = context.getFile(RSPACK_CONFIG_PATH);
14
- if (rspackContent) {
15
- try {
16
- const ast = recast.parse(rspackContent, {
17
- parser: typeScriptParser
18
- });
19
- let hasChanges = false;
20
- recast.visit(ast, {
21
- visitObjectExpression(path) {
22
- const { node } = path;
23
- const properties = node.properties;
24
- if (properties) {
25
- for (const prop of properties) {
26
- if (prop && (prop.type === "Property" || prop.type === "ObjectProperty")) {
27
- const key = "key" in prop ? prop.key : null;
28
- const value = "value" in prop ? prop.value : null;
29
- if (resolveModifier && key && key.type === "Identifier" && key.name === "resolve" && value && value.type === "ObjectExpression") {
30
- hasChanges = resolveModifier(value) || hasChanges;
31
- }
32
- if (moduleRulesModifier && key && key.type === "Identifier" && key.name === "module" && value && value.type === "ObjectExpression") {
33
- hasChanges = moduleRulesModifier(value) || hasChanges;
34
- }
35
- }
36
- }
37
- }
38
- return this.traverse(path);
39
- }
40
- });
41
- if (hasChanges) {
42
- const output = recast.print(ast, {
43
- tabWidth: 2,
44
- trailingComma: true,
45
- lineTerminator: "\n"
46
- });
47
- context.updateFile(RSPACK_CONFIG_PATH, output.code);
48
- additionsDebug(`Updated ${RSPACK_CONFIG_PATH}`);
49
- }
50
- } catch (error) {
51
- additionsDebug(`Error updating ${RSPACK_CONFIG_PATH}:`, error);
52
- }
53
- }
54
- return;
55
- }
56
- if (context.doesFileExist(WEBPACK_CONFIG_PATH)) {
57
- additionsDebug(`Found ${WEBPACK_CONFIG_PATH}, updating bundler configuration...`);
58
- const webpackContent = context.getFile(WEBPACK_CONFIG_PATH);
59
- if (webpackContent) {
60
- try {
61
- const ast = recast.parse(webpackContent, {
62
- parser: typeScriptParser
63
- });
64
- let hasChanges = false;
65
- recast.visit(ast, {
66
- visitObjectExpression(path) {
67
- const { node } = path;
68
- const properties = node.properties;
69
- if (properties) {
70
- for (const prop of properties) {
71
- if (prop && (prop.type === "Property" || prop.type === "ObjectProperty")) {
72
- const key = "key" in prop ? prop.key : null;
73
- const value = "value" in prop ? prop.value : null;
74
- if (resolveModifier && key && key.type === "Identifier" && key.name === "resolve" && value && value.type === "ObjectExpression") {
75
- hasChanges = resolveModifier(value) || hasChanges;
76
- }
77
- if (moduleRulesModifier && key && key.type === "Identifier" && key.name === "module" && value && value.type === "ObjectExpression") {
78
- hasChanges = moduleRulesModifier(value) || hasChanges;
79
- }
80
- }
81
- }
82
- }
83
- return this.traverse(path);
84
- }
85
- });
86
- if (hasChanges) {
87
- const output = recast.print(ast, {
88
- tabWidth: 2,
89
- trailingComma: true,
90
- lineTerminator: "\n"
91
- });
92
- context.updateFile(WEBPACK_CONFIG_PATH, output.code);
93
- additionsDebug(`Updated ${WEBPACK_CONFIG_PATH}`);
94
- }
95
- } catch (error) {
96
- additionsDebug(`Error updating ${WEBPACK_CONFIG_PATH}:`, error);
97
- }
98
- }
99
- }
100
- }
101
-
102
- export { updateBundlerConfig };