@grafana/create-plugin 6.8.0-canary.2356.20813241719.0 → 6.8.0-canary.2356.20813982803.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 +12 -0
- package/dist/codemods/additions/scripts/bundle-grafana-ui/index.js +65 -203
- package/package.json +2 -2
- package/src/codemods/additions/scripts/bundle-grafana-ui/index.ts +104 -314
- package/src/codemods/utils.bundler-config.ts +180 -0
- package/templates/common/.config/rspack/rspack.config.ts +9 -9
- package/templates/common/.config/webpack/webpack.config.ts +7 -7
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
|
|
@@ -1,39 +1,35 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
2
|
import * as recast from 'recast';
|
|
3
|
-
import * as typeScriptParser from 'recast/parsers/typescript.js';
|
|
4
3
|
import { coerce, gte } from 'semver';
|
|
5
4
|
import { additionsDebug } from '../../../utils.js';
|
|
6
5
|
import { updateExternalsArray } from '../../../utils.externals.js';
|
|
7
6
|
|
|
8
7
|
const { builders } = recast.types;
|
|
9
|
-
const schema = v.object({});
|
|
10
8
|
const PLUGIN_JSON_PATH = "src/plugin.json";
|
|
11
9
|
const MIN_GRAFANA_VERSION = "10.2.0";
|
|
12
10
|
const WEBPACK_CONFIG_PATH = ".config/webpack/webpack.config.ts";
|
|
13
11
|
const RSPACK_CONFIG_PATH = ".config/rspack/rspack.config.ts";
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
return false;
|
|
12
|
+
const schema = v.object({});
|
|
13
|
+
function bundleGrafanaUI(context, _options) {
|
|
14
|
+
additionsDebug("Running bundle-grafana-ui addition...");
|
|
15
|
+
ensureMinGrafanaVersion(context);
|
|
16
|
+
updateExternalsArray(context, createBundleGrafanaUIModifier());
|
|
17
|
+
updateResolveExtensionsSimple(context);
|
|
18
|
+
updateModuleRulesSimple(context);
|
|
19
|
+
return context;
|
|
24
20
|
}
|
|
25
|
-
function
|
|
21
|
+
function isGrafanaRegex(element, pattern) {
|
|
26
22
|
if (element.type === "RegExpLiteral") {
|
|
27
23
|
const regexNode = element;
|
|
28
|
-
return regexNode.pattern ===
|
|
24
|
+
return regexNode.pattern === pattern && regexNode.flags === "i";
|
|
29
25
|
}
|
|
30
26
|
if (element.type === "Literal" && "regex" in element && element.regex) {
|
|
31
27
|
const regex = element.regex;
|
|
32
|
-
return regex.pattern ===
|
|
28
|
+
return regex.pattern === pattern && regex.flags === "i";
|
|
33
29
|
}
|
|
34
30
|
return false;
|
|
35
31
|
}
|
|
36
|
-
function
|
|
32
|
+
function removeGrafanaUiAndAddReactInlineSvg(externalsArray) {
|
|
37
33
|
let hasChanges = false;
|
|
38
34
|
let hasGrafanaUiExternal = false;
|
|
39
35
|
let hasReactInlineSvg = false;
|
|
@@ -41,7 +37,7 @@ function modifyExternalsArray(externalsArray) {
|
|
|
41
37
|
if (!element) {
|
|
42
38
|
continue;
|
|
43
39
|
}
|
|
44
|
-
if (
|
|
40
|
+
if (isGrafanaRegex(element, "^@grafana\\/ui")) {
|
|
45
41
|
hasGrafanaUiExternal = true;
|
|
46
42
|
}
|
|
47
43
|
if ((element.type === "Literal" || element.type === "StringLiteral") && "value" in element && typeof element.value === "string" && element.value === "react-inlinesvg") {
|
|
@@ -53,7 +49,7 @@ function modifyExternalsArray(externalsArray) {
|
|
|
53
49
|
if (!element) {
|
|
54
50
|
return true;
|
|
55
51
|
}
|
|
56
|
-
return !
|
|
52
|
+
return !isGrafanaRegex(element, "^@grafana\\/ui");
|
|
57
53
|
});
|
|
58
54
|
hasChanges = true;
|
|
59
55
|
additionsDebug("Removed /^@grafana\\/ui/i from externals array");
|
|
@@ -62,7 +58,7 @@ function modifyExternalsArray(externalsArray) {
|
|
|
62
58
|
let insertIndex = -1;
|
|
63
59
|
for (let i = 0; i < externalsArray.elements.length; i++) {
|
|
64
60
|
const element = externalsArray.elements[i];
|
|
65
|
-
if (element &&
|
|
61
|
+
if (element && isGrafanaRegex(element, "^@grafana\\/data")) {
|
|
66
62
|
insertIndex = i + 1;
|
|
67
63
|
break;
|
|
68
64
|
}
|
|
@@ -79,196 +75,69 @@ function modifyExternalsArray(externalsArray) {
|
|
|
79
75
|
}
|
|
80
76
|
function createBundleGrafanaUIModifier() {
|
|
81
77
|
return (externalsArray) => {
|
|
82
|
-
return
|
|
78
|
+
return removeGrafanaUiAndAddReactInlineSvg(externalsArray);
|
|
83
79
|
};
|
|
84
80
|
}
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const rspackContent = context.getFile(RSPACK_CONFIG_PATH);
|
|
89
|
-
if (rspackContent) {
|
|
90
|
-
try {
|
|
91
|
-
const ast = recast.parse(rspackContent, {
|
|
92
|
-
parser: typeScriptParser
|
|
93
|
-
});
|
|
94
|
-
let hasChanges = false;
|
|
95
|
-
recast.visit(ast, {
|
|
96
|
-
visitObjectExpression(path) {
|
|
97
|
-
const { node } = path;
|
|
98
|
-
const properties = node.properties;
|
|
99
|
-
if (properties) {
|
|
100
|
-
for (const prop of properties) {
|
|
101
|
-
if (prop && (prop.type === "Property" || prop.type === "ObjectProperty")) {
|
|
102
|
-
const key = "key" in prop ? prop.key : null;
|
|
103
|
-
const value = "value" in prop ? prop.value : null;
|
|
104
|
-
if (key && key.type === "Identifier" && key.name === "resolve" && value && value.type === "ObjectExpression") {
|
|
105
|
-
hasChanges = updateResolveObject(value) || hasChanges;
|
|
106
|
-
}
|
|
107
|
-
if (key && key.type === "Identifier" && key.name === "module" && value && value.type === "ObjectExpression") {
|
|
108
|
-
hasChanges = updateModuleRules(value) || hasChanges;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return this.traverse(path);
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
if (hasChanges) {
|
|
117
|
-
const output = recast.print(ast, {
|
|
118
|
-
tabWidth: 2,
|
|
119
|
-
trailingComma: true,
|
|
120
|
-
lineTerminator: "\n"
|
|
121
|
-
});
|
|
122
|
-
context.updateFile(RSPACK_CONFIG_PATH, output.code);
|
|
123
|
-
additionsDebug(`Updated ${RSPACK_CONFIG_PATH}`);
|
|
124
|
-
}
|
|
125
|
-
} catch (error) {
|
|
126
|
-
additionsDebug(`Error updating ${RSPACK_CONFIG_PATH}:`, error);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
81
|
+
function updateResolveExtensionsSimple(context) {
|
|
82
|
+
const configPath = context.doesFileExist(RSPACK_CONFIG_PATH) ? RSPACK_CONFIG_PATH : context.doesFileExist(WEBPACK_CONFIG_PATH) ? WEBPACK_CONFIG_PATH : null;
|
|
83
|
+
if (!configPath) {
|
|
129
84
|
return;
|
|
130
85
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (webpackContent) {
|
|
135
|
-
try {
|
|
136
|
-
const ast = recast.parse(webpackContent, {
|
|
137
|
-
parser: typeScriptParser
|
|
138
|
-
});
|
|
139
|
-
let hasChanges = false;
|
|
140
|
-
recast.visit(ast, {
|
|
141
|
-
visitObjectExpression(path) {
|
|
142
|
-
const { node } = path;
|
|
143
|
-
const properties = node.properties;
|
|
144
|
-
if (properties) {
|
|
145
|
-
for (const prop of properties) {
|
|
146
|
-
if (prop && (prop.type === "Property" || prop.type === "ObjectProperty")) {
|
|
147
|
-
const key = "key" in prop ? prop.key : null;
|
|
148
|
-
const value = "value" in prop ? prop.value : null;
|
|
149
|
-
if (key && key.type === "Identifier" && key.name === "resolve" && value && value.type === "ObjectExpression") {
|
|
150
|
-
hasChanges = updateResolveObject(value) || hasChanges;
|
|
151
|
-
}
|
|
152
|
-
if (key && key.type === "Identifier" && key.name === "module" && value && value.type === "ObjectExpression") {
|
|
153
|
-
hasChanges = updateModuleRules(value) || hasChanges;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return this.traverse(path);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
if (hasChanges) {
|
|
162
|
-
const output = recast.print(ast, {
|
|
163
|
-
tabWidth: 2,
|
|
164
|
-
trailingComma: true,
|
|
165
|
-
lineTerminator: "\n"
|
|
166
|
-
});
|
|
167
|
-
context.updateFile(WEBPACK_CONFIG_PATH, output.code);
|
|
168
|
-
additionsDebug(`Updated ${WEBPACK_CONFIG_PATH}`);
|
|
169
|
-
}
|
|
170
|
-
} catch (error) {
|
|
171
|
-
additionsDebug(`Error updating ${WEBPACK_CONFIG_PATH}:`, error);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
86
|
+
const content = context.getFile(configPath);
|
|
87
|
+
if (!content) {
|
|
88
|
+
return;
|
|
174
89
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (!moduleObject.properties) {
|
|
178
|
-
return false;
|
|
90
|
+
if (content.includes("'.mjs'") || content.includes('".mjs"')) {
|
|
91
|
+
return;
|
|
179
92
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
for (const prop of moduleObject.properties) {
|
|
184
|
-
if (!prop || prop.type !== "Property" && prop.type !== "ObjectProperty") {
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
const key = "key" in prop ? prop.key : null;
|
|
188
|
-
const value = "value" in prop ? prop.value : null;
|
|
189
|
-
if (key && key.type === "Identifier" && key.name === "rules" && value && value.type === "ArrayExpression") {
|
|
190
|
-
rulesProperty = prop;
|
|
191
|
-
for (const element of value.elements) {
|
|
192
|
-
if (element && element.type === "ObjectExpression" && element.properties) {
|
|
193
|
-
for (const ruleProp of element.properties) {
|
|
194
|
-
if (ruleProp && (ruleProp.type === "Property" || ruleProp.type === "ObjectProperty") && "key" in ruleProp && ruleProp.key.type === "Identifier" && ruleProp.key.name === "test") {
|
|
195
|
-
const testValue = "value" in ruleProp ? ruleProp.value : null;
|
|
196
|
-
if (testValue) {
|
|
197
|
-
if (testValue.type === "RegExpLiteral" && "pattern" in testValue && testValue.pattern === "\\.mjs$") {
|
|
198
|
-
hasMjsRule = true;
|
|
199
|
-
break;
|
|
200
|
-
}
|
|
201
|
-
if (testValue.type === "Literal" && "regex" in testValue && testValue.regex && typeof testValue.regex === "object" && "pattern" in testValue.regex && testValue.regex.pattern === "\\.mjs$") {
|
|
202
|
-
hasMjsRule = true;
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
if (testValue.type === "Literal" && "value" in testValue && typeof testValue.value === "string" && testValue.value.includes(".mjs")) {
|
|
206
|
-
hasMjsRule = true;
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (hasMjsRule) {
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
break;
|
|
93
|
+
const updated = content.replace(/(extensions:\s*\[)([^\]]+)(\])/, (match, prefix, extensions, suffix) => {
|
|
94
|
+
if (extensions.includes(".mjs")) {
|
|
95
|
+
return match;
|
|
218
96
|
}
|
|
97
|
+
return `${prefix}${extensions}, '.mjs'${suffix}`;
|
|
98
|
+
});
|
|
99
|
+
if (updated !== content) {
|
|
100
|
+
context.updateFile(configPath, updated);
|
|
101
|
+
additionsDebug("Added '.mjs' to resolve.extensions");
|
|
219
102
|
}
|
|
220
|
-
if (!hasMjsRule && rulesProperty && "value" in rulesProperty) {
|
|
221
|
-
const rulesArray = rulesProperty.value;
|
|
222
|
-
const mjsRule = builders.objectExpression([
|
|
223
|
-
builders.property("init", builders.identifier("test"), builders.literal(/\.mjs$/)),
|
|
224
|
-
builders.property("init", builders.identifier("include"), builders.literal(/node_modules/)),
|
|
225
|
-
builders.property(
|
|
226
|
-
"init",
|
|
227
|
-
builders.identifier("resolve"),
|
|
228
|
-
builders.objectExpression([
|
|
229
|
-
builders.property("init", builders.identifier("fullySpecified"), builders.literal(false))
|
|
230
|
-
])
|
|
231
|
-
),
|
|
232
|
-
builders.property("init", builders.identifier("type"), builders.literal("javascript/auto"))
|
|
233
|
-
]);
|
|
234
|
-
rulesArray.elements.splice(1, 0, mjsRule);
|
|
235
|
-
hasChanges = true;
|
|
236
|
-
additionsDebug("Added module rule for .mjs files in node_modules with resolve.fullySpecified: false");
|
|
237
|
-
}
|
|
238
|
-
return hasChanges;
|
|
239
103
|
}
|
|
240
|
-
function
|
|
241
|
-
|
|
242
|
-
|
|
104
|
+
function updateModuleRulesSimple(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;
|
|
243
108
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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;
|
|
262
132
|
}
|
|
263
|
-
|
|
133
|
+
return `${prefix}${firstRule},
|
|
134
|
+
${mjsRule}${suffix}`;
|
|
135
|
+
});
|
|
264
136
|
}
|
|
265
|
-
if (
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
hasChanges = true;
|
|
269
|
-
additionsDebug("Added '.mjs' to resolve.extensions");
|
|
137
|
+
if (updated !== content) {
|
|
138
|
+
context.updateFile(configPath, updated);
|
|
139
|
+
additionsDebug("Added module rule for .mjs files in node_modules with resolve.fullySpecified: false");
|
|
270
140
|
}
|
|
271
|
-
return hasChanges;
|
|
272
141
|
}
|
|
273
142
|
function ensureMinGrafanaVersion(context) {
|
|
274
143
|
if (!context.doesFileExist(PLUGIN_JSON_PATH)) {
|
|
@@ -308,12 +177,5 @@ function ensureMinGrafanaVersion(context) {
|
|
|
308
177
|
additionsDebug(`Error updating ${PLUGIN_JSON_PATH}:`, error);
|
|
309
178
|
}
|
|
310
179
|
}
|
|
311
|
-
function bundleGrafanaUI(context, _options) {
|
|
312
|
-
additionsDebug("Running bundle-grafana-ui addition...");
|
|
313
|
-
ensureMinGrafanaVersion(context);
|
|
314
|
-
updateExternalsArray(context, createBundleGrafanaUIModifier());
|
|
315
|
-
updateBundlerResolveConfig(context);
|
|
316
|
-
return context;
|
|
317
|
-
}
|
|
318
180
|
|
|
319
181
|
export { bundleGrafanaUI as default, schema };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafana/create-plugin",
|
|
3
|
-
"version": "6.8.0-canary.2356.
|
|
3
|
+
"version": "6.8.0-canary.2356.20813982803.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": "
|
|
58
|
+
"gitHead": "fedff1c23ee3079d90f0ed2d6984c78fb294b1b9"
|
|
59
59
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as v from 'valibot';
|
|
2
2
|
import * as recast from 'recast';
|
|
3
|
-
import * as typeScriptParser from 'recast/parsers/typescript.js';
|
|
4
3
|
import { coerce, gte } from 'semver';
|
|
5
4
|
|
|
6
5
|
import type { Context } from '../../../context.js';
|
|
@@ -9,47 +8,47 @@ import { updateExternalsArray, type ExternalsArrayModifier } from '../../../util
|
|
|
9
8
|
|
|
10
9
|
const { builders } = recast.types;
|
|
11
10
|
|
|
12
|
-
export const schema = v.object({});
|
|
13
|
-
|
|
14
|
-
type BundleGrafanaUIOptions = v.InferOutput<typeof schema>;
|
|
15
|
-
|
|
16
11
|
const PLUGIN_JSON_PATH = 'src/plugin.json';
|
|
17
12
|
const MIN_GRAFANA_VERSION = '10.2.0';
|
|
18
13
|
const WEBPACK_CONFIG_PATH = '.config/webpack/webpack.config.ts';
|
|
19
14
|
const RSPACK_CONFIG_PATH = '.config/rspack/rspack.config.ts';
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
16
|
+
export const schema = v.object({});
|
|
17
|
+
type BundleGrafanaUIOptions = v.InferOutput<typeof schema>;
|
|
18
|
+
|
|
19
|
+
export default function bundleGrafanaUI(context: Context, _options: BundleGrafanaUIOptions): Context {
|
|
20
|
+
additionsDebug('Running bundle-grafana-ui addition...');
|
|
21
|
+
|
|
22
|
+
// Ensure minimum Grafana version requirement
|
|
23
|
+
ensureMinGrafanaVersion(context);
|
|
24
|
+
|
|
25
|
+
// Update externals array using the shared utility
|
|
26
|
+
updateExternalsArray(context, createBundleGrafanaUIModifier());
|
|
27
|
+
|
|
28
|
+
// Update bundler resolve configuration to handle ESM imports
|
|
29
|
+
updateResolveExtensionsSimple(context);
|
|
30
|
+
|
|
31
|
+
// Update module rules directly with simple string manipulation
|
|
32
|
+
updateModuleRulesSimple(context);
|
|
33
|
+
|
|
34
|
+
return context;
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
/**
|
|
40
|
-
* Checks if an AST node is a regex matching
|
|
41
|
-
*
|
|
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")
|
|
42
41
|
*/
|
|
43
|
-
function
|
|
42
|
+
function isGrafanaRegex(element: recast.types.namedTypes.ASTNode, pattern: string): boolean {
|
|
44
43
|
// Handle RegExpLiteral (TypeScript parser)
|
|
45
44
|
if (element.type === 'RegExpLiteral') {
|
|
46
45
|
const regexNode = element as recast.types.namedTypes.RegExpLiteral;
|
|
47
|
-
return regexNode.pattern ===
|
|
46
|
+
return regexNode.pattern === pattern && regexNode.flags === 'i';
|
|
48
47
|
}
|
|
49
48
|
// Handle Literal with regex property (other parsers)
|
|
50
49
|
if (element.type === 'Literal' && 'regex' in element && element.regex) {
|
|
51
50
|
const regex = element.regex as { pattern: string; flags: string };
|
|
52
|
-
return regex.pattern ===
|
|
51
|
+
return regex.pattern === pattern && regex.flags === 'i';
|
|
53
52
|
}
|
|
54
53
|
return false;
|
|
55
54
|
}
|
|
@@ -58,7 +57,7 @@ function isGrafanaDataRegex(element: recast.types.namedTypes.ASTNode): boolean {
|
|
|
58
57
|
* Removes /^@grafana\/ui/i regex from externals array and adds 'react-inlinesvg'
|
|
59
58
|
* @returns true if changes were made, false otherwise
|
|
60
59
|
*/
|
|
61
|
-
function
|
|
60
|
+
function removeGrafanaUiAndAddReactInlineSvg(externalsArray: recast.types.namedTypes.ArrayExpression): boolean {
|
|
62
61
|
let hasChanges = false;
|
|
63
62
|
let hasGrafanaUiExternal = false;
|
|
64
63
|
let hasReactInlineSvg = false;
|
|
@@ -70,7 +69,7 @@ function modifyExternalsArray(externalsArray: recast.types.namedTypes.ArrayExpre
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
// Check for /^@grafana\/ui/i regex
|
|
73
|
-
if (
|
|
72
|
+
if (isGrafanaRegex(element, '^@grafana\\/ui')) {
|
|
74
73
|
hasGrafanaUiExternal = true;
|
|
75
74
|
}
|
|
76
75
|
|
|
@@ -91,7 +90,7 @@ function modifyExternalsArray(externalsArray: recast.types.namedTypes.ArrayExpre
|
|
|
91
90
|
if (!element) {
|
|
92
91
|
return true;
|
|
93
92
|
}
|
|
94
|
-
return !
|
|
93
|
+
return !isGrafanaRegex(element, '^@grafana\\/ui');
|
|
95
94
|
});
|
|
96
95
|
hasChanges = true;
|
|
97
96
|
additionsDebug('Removed /^@grafana\\/ui/i from externals array');
|
|
@@ -103,7 +102,7 @@ function modifyExternalsArray(externalsArray: recast.types.namedTypes.ArrayExpre
|
|
|
103
102
|
let insertIndex = -1;
|
|
104
103
|
for (let i = 0; i < externalsArray.elements.length; i++) {
|
|
105
104
|
const element = externalsArray.elements[i];
|
|
106
|
-
if (element &&
|
|
105
|
+
if (element && isGrafanaRegex(element, '^@grafana\\/data')) {
|
|
107
106
|
insertIndex = i + 1;
|
|
108
107
|
break;
|
|
109
108
|
}
|
|
@@ -128,302 +127,108 @@ function modifyExternalsArray(externalsArray: recast.types.namedTypes.ArrayExpre
|
|
|
128
127
|
*/
|
|
129
128
|
function createBundleGrafanaUIModifier(): ExternalsArrayModifier {
|
|
130
129
|
return (externalsArray: recast.types.namedTypes.ArrayExpression) => {
|
|
131
|
-
return
|
|
130
|
+
return removeGrafanaUiAndAddReactInlineSvg(externalsArray);
|
|
132
131
|
};
|
|
133
132
|
}
|
|
134
133
|
|
|
135
134
|
/**
|
|
136
|
-
* Updates
|
|
137
|
-
*
|
|
138
|
-
* - Adds fullySpecified: false to allow extensionless imports in node_modules
|
|
135
|
+
* Updates resolve extensions to add .mjs using simple string manipulation
|
|
136
|
+
* This is a simplified approach that may not handle all edge cases, but is much simpler
|
|
139
137
|
*/
|
|
140
|
-
function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
parser: typeScriptParser,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
let hasChanges = false;
|
|
152
|
-
|
|
153
|
-
recast.visit(ast, {
|
|
154
|
-
visitObjectExpression(path) {
|
|
155
|
-
const { node } = path;
|
|
156
|
-
const properties = node.properties;
|
|
157
|
-
|
|
158
|
-
if (properties) {
|
|
159
|
-
for (const prop of properties) {
|
|
160
|
-
if (prop && (prop.type === 'Property' || prop.type === 'ObjectProperty')) {
|
|
161
|
-
const key = 'key' in prop ? prop.key : null;
|
|
162
|
-
const value = 'value' in prop ? prop.value : null;
|
|
163
|
-
|
|
164
|
-
// Find the resolve property
|
|
165
|
-
if (
|
|
166
|
-
key &&
|
|
167
|
-
key.type === 'Identifier' &&
|
|
168
|
-
key.name === 'resolve' &&
|
|
169
|
-
value &&
|
|
170
|
-
value.type === 'ObjectExpression'
|
|
171
|
-
) {
|
|
172
|
-
hasChanges = updateResolveObject(value) || hasChanges;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Find the module property to add .mjs rule
|
|
176
|
-
if (
|
|
177
|
-
key &&
|
|
178
|
-
key.type === 'Identifier' &&
|
|
179
|
-
key.name === 'module' &&
|
|
180
|
-
value &&
|
|
181
|
-
value.type === 'ObjectExpression'
|
|
182
|
-
) {
|
|
183
|
-
hasChanges = updateModuleRules(value) || hasChanges;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return this.traverse(path);
|
|
190
|
-
},
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
if (hasChanges) {
|
|
194
|
-
const output = recast.print(ast, {
|
|
195
|
-
tabWidth: 2,
|
|
196
|
-
trailingComma: true,
|
|
197
|
-
lineTerminator: '\n',
|
|
198
|
-
});
|
|
199
|
-
context.updateFile(RSPACK_CONFIG_PATH, output.code);
|
|
200
|
-
additionsDebug(`Updated ${RSPACK_CONFIG_PATH}`);
|
|
201
|
-
}
|
|
202
|
-
} catch (error) {
|
|
203
|
-
additionsDebug(`Error updating ${RSPACK_CONFIG_PATH}:`, error);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
138
|
+
function updateResolveExtensionsSimple(context: Context): void {
|
|
139
|
+
const configPath = context.doesFileExist(RSPACK_CONFIG_PATH)
|
|
140
|
+
? RSPACK_CONFIG_PATH
|
|
141
|
+
: context.doesFileExist(WEBPACK_CONFIG_PATH)
|
|
142
|
+
? WEBPACK_CONFIG_PATH
|
|
143
|
+
: null;
|
|
144
|
+
|
|
145
|
+
if (!configPath) {
|
|
206
146
|
return;
|
|
207
147
|
}
|
|
208
148
|
|
|
209
|
-
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
const webpackContent = context.getFile(WEBPACK_CONFIG_PATH);
|
|
213
|
-
if (webpackContent) {
|
|
214
|
-
try {
|
|
215
|
-
const ast = recast.parse(webpackContent, {
|
|
216
|
-
parser: typeScriptParser,
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
let hasChanges = false;
|
|
220
|
-
|
|
221
|
-
recast.visit(ast, {
|
|
222
|
-
visitObjectExpression(path) {
|
|
223
|
-
const { node } = path;
|
|
224
|
-
const properties = node.properties;
|
|
225
|
-
|
|
226
|
-
if (properties) {
|
|
227
|
-
for (const prop of properties) {
|
|
228
|
-
if (prop && (prop.type === 'Property' || prop.type === 'ObjectProperty')) {
|
|
229
|
-
const key = 'key' in prop ? prop.key : null;
|
|
230
|
-
const value = 'value' in prop ? prop.value : null;
|
|
231
|
-
|
|
232
|
-
// Find the resolve property
|
|
233
|
-
if (
|
|
234
|
-
key &&
|
|
235
|
-
key.type === 'Identifier' &&
|
|
236
|
-
key.name === 'resolve' &&
|
|
237
|
-
value &&
|
|
238
|
-
value.type === 'ObjectExpression'
|
|
239
|
-
) {
|
|
240
|
-
hasChanges = updateResolveObject(value) || hasChanges;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Find the module property to add .mjs rule
|
|
244
|
-
if (
|
|
245
|
-
key &&
|
|
246
|
-
key.type === 'Identifier' &&
|
|
247
|
-
key.name === 'module' &&
|
|
248
|
-
value &&
|
|
249
|
-
value.type === 'ObjectExpression'
|
|
250
|
-
) {
|
|
251
|
-
hasChanges = updateModuleRules(value) || hasChanges;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return this.traverse(path);
|
|
258
|
-
},
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
if (hasChanges) {
|
|
262
|
-
const output = recast.print(ast, {
|
|
263
|
-
tabWidth: 2,
|
|
264
|
-
trailingComma: true,
|
|
265
|
-
lineTerminator: '\n',
|
|
266
|
-
});
|
|
267
|
-
context.updateFile(WEBPACK_CONFIG_PATH, output.code);
|
|
268
|
-
additionsDebug(`Updated ${WEBPACK_CONFIG_PATH}`);
|
|
269
|
-
}
|
|
270
|
-
} catch (error) {
|
|
271
|
-
additionsDebug(`Error updating ${WEBPACK_CONFIG_PATH}:`, error);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
149
|
+
const content = context.getFile(configPath);
|
|
150
|
+
if (!content) {
|
|
151
|
+
return;
|
|
274
152
|
}
|
|
275
|
-
}
|
|
276
153
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
function updateModuleRules(moduleObject: recast.types.namedTypes.ObjectExpression): boolean {
|
|
281
|
-
if (!moduleObject.properties) {
|
|
282
|
-
return false;
|
|
154
|
+
// Check if .mjs already exists
|
|
155
|
+
if (content.includes("'.mjs'") || content.includes('".mjs"')) {
|
|
156
|
+
return;
|
|
283
157
|
}
|
|
284
158
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
// Find the rules property
|
|
290
|
-
for (const prop of moduleObject.properties) {
|
|
291
|
-
if (!prop || (prop.type !== 'Property' && prop.type !== 'ObjectProperty')) {
|
|
292
|
-
continue;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const key = 'key' in prop ? prop.key : null;
|
|
296
|
-
const value = 'value' in prop ? prop.value : null;
|
|
297
|
-
|
|
298
|
-
if (key && key.type === 'Identifier' && key.name === 'rules' && value && value.type === 'ArrayExpression') {
|
|
299
|
-
rulesProperty = prop as recast.types.namedTypes.Property;
|
|
300
|
-
// Check if .mjs rule already exists
|
|
301
|
-
for (const element of value.elements) {
|
|
302
|
-
if (element && element.type === 'ObjectExpression' && element.properties) {
|
|
303
|
-
for (const ruleProp of element.properties) {
|
|
304
|
-
if (
|
|
305
|
-
ruleProp &&
|
|
306
|
-
(ruleProp.type === 'Property' || ruleProp.type === 'ObjectProperty') &&
|
|
307
|
-
'key' in ruleProp &&
|
|
308
|
-
ruleProp.key.type === 'Identifier' &&
|
|
309
|
-
ruleProp.key.name === 'test'
|
|
310
|
-
) {
|
|
311
|
-
const testValue = 'value' in ruleProp ? ruleProp.value : null;
|
|
312
|
-
if (testValue) {
|
|
313
|
-
// Check for RegExpLiteral with .mjs pattern
|
|
314
|
-
if (testValue.type === 'RegExpLiteral' && 'pattern' in testValue && testValue.pattern === '\\.mjs$') {
|
|
315
|
-
hasMjsRule = true;
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
// Check for Literal with regex property
|
|
319
|
-
if (
|
|
320
|
-
testValue.type === 'Literal' &&
|
|
321
|
-
'regex' in testValue &&
|
|
322
|
-
testValue.regex &&
|
|
323
|
-
typeof testValue.regex === 'object' &&
|
|
324
|
-
'pattern' in testValue.regex &&
|
|
325
|
-
testValue.regex.pattern === '\\.mjs$'
|
|
326
|
-
) {
|
|
327
|
-
hasMjsRule = true;
|
|
328
|
-
break;
|
|
329
|
-
}
|
|
330
|
-
// Check for string literal containing .mjs
|
|
331
|
-
if (
|
|
332
|
-
testValue.type === 'Literal' &&
|
|
333
|
-
'value' in testValue &&
|
|
334
|
-
typeof testValue.value === 'string' &&
|
|
335
|
-
testValue.value.includes('.mjs')
|
|
336
|
-
) {
|
|
337
|
-
hasMjsRule = true;
|
|
338
|
-
break;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
if (hasMjsRule) {
|
|
345
|
-
break;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
break;
|
|
159
|
+
// Add .mjs to extensions array
|
|
160
|
+
const updated = content.replace(/(extensions:\s*\[)([^\]]+)(\])/, (match, prefix, extensions, suffix) => {
|
|
161
|
+
if (extensions.includes('.mjs')) {
|
|
162
|
+
return match;
|
|
349
163
|
}
|
|
350
|
-
|
|
164
|
+
return `${prefix}${extensions}, '.mjs'${suffix}`;
|
|
165
|
+
});
|
|
351
166
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const mjsRule = builders.objectExpression([
|
|
356
|
-
builders.property('init', builders.identifier('test'), builders.literal(/\.mjs$/)),
|
|
357
|
-
builders.property('init', builders.identifier('include'), builders.literal(/node_modules/)),
|
|
358
|
-
builders.property(
|
|
359
|
-
'init',
|
|
360
|
-
builders.identifier('resolve'),
|
|
361
|
-
builders.objectExpression([
|
|
362
|
-
builders.property('init', builders.identifier('fullySpecified'), builders.literal(false)),
|
|
363
|
-
])
|
|
364
|
-
),
|
|
365
|
-
builders.property('init', builders.identifier('type'), builders.literal('javascript/auto')),
|
|
366
|
-
]);
|
|
367
|
-
// Insert at position 1 (second position) to keep imports-loader first
|
|
368
|
-
rulesArray.elements.splice(1, 0, mjsRule);
|
|
369
|
-
hasChanges = true;
|
|
370
|
-
additionsDebug('Added module rule for .mjs files in node_modules with resolve.fullySpecified: false');
|
|
167
|
+
if (updated !== content) {
|
|
168
|
+
context.updateFile(configPath, updated);
|
|
169
|
+
additionsDebug("Added '.mjs' to resolve.extensions");
|
|
371
170
|
}
|
|
372
|
-
|
|
373
|
-
return hasChanges;
|
|
374
171
|
}
|
|
375
172
|
|
|
376
173
|
/**
|
|
377
|
-
* Updates
|
|
378
|
-
*
|
|
379
|
-
* rule-level configuration to override ESM's strict fully-specified import requirements
|
|
174
|
+
* Updates module rules to add .mjs rule using simple string manipulation
|
|
175
|
+
* This is a simplified approach that may not handle all edge cases, but is much simpler
|
|
380
176
|
*/
|
|
381
|
-
function
|
|
382
|
-
|
|
383
|
-
|
|
177
|
+
function updateModuleRulesSimple(context: Context): void {
|
|
178
|
+
const configPath = context.doesFileExist(RSPACK_CONFIG_PATH)
|
|
179
|
+
? RSPACK_CONFIG_PATH
|
|
180
|
+
: context.doesFileExist(WEBPACK_CONFIG_PATH)
|
|
181
|
+
? WEBPACK_CONFIG_PATH
|
|
182
|
+
: null;
|
|
183
|
+
|
|
184
|
+
if (!configPath) {
|
|
185
|
+
return;
|
|
384
186
|
}
|
|
385
187
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
188
|
+
const content = context.getFile(configPath);
|
|
189
|
+
if (!content) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
389
192
|
|
|
390
|
-
// Check
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
193
|
+
// Check if rule already exists
|
|
194
|
+
if (content.includes('test: /\\.mjs$') || content.includes('test: /\\\\.mjs$')) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
395
197
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
198
|
+
const mjsRule = `{
|
|
199
|
+
test: /\\.mjs$/,
|
|
200
|
+
include: /node_modules/,
|
|
201
|
+
resolve: {
|
|
202
|
+
fullySpecified: false,
|
|
203
|
+
},
|
|
204
|
+
type: 'javascript/auto',
|
|
205
|
+
},`;
|
|
206
|
+
|
|
207
|
+
// Simple approach: find rules array and insert after first rule
|
|
208
|
+
let updated = content;
|
|
209
|
+
|
|
210
|
+
// Case 1: Empty array - insert at start
|
|
211
|
+
if (content.match(/rules:\s*\[\s*\]/)) {
|
|
212
|
+
updated = content.replace(/(rules:\s*\[\s*)(\])/, `$1${mjsRule}\n $2`);
|
|
213
|
+
}
|
|
214
|
+
// Case 2: Find first rule and insert after it
|
|
215
|
+
else {
|
|
216
|
+
// Match: rules: [ { ... }, and insert mjs rule after the first rule
|
|
217
|
+
// The regex finds the first complete rule object (balanced braces)
|
|
218
|
+
updated = content.replace(/(rules:\s*\[\s*)(\{[\s\S]*?\}),(\s*)/, (match, prefix, firstRule, suffix) => {
|
|
219
|
+
// Check if we already inserted (avoid double insertion)
|
|
220
|
+
if (match.includes('test: /\\.mjs$')) {
|
|
221
|
+
return match;
|
|
414
222
|
}
|
|
415
|
-
|
|
223
|
+
// Insert mjs rule after first rule
|
|
224
|
+
return `${prefix}${firstRule},\n ${mjsRule}${suffix}`;
|
|
225
|
+
});
|
|
416
226
|
}
|
|
417
227
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
extensionsArray.elements.push(builders.literal('.mjs'));
|
|
422
|
-
hasChanges = true;
|
|
423
|
-
additionsDebug("Added '.mjs' to resolve.extensions");
|
|
228
|
+
if (updated !== content) {
|
|
229
|
+
context.updateFile(configPath, updated);
|
|
230
|
+
additionsDebug('Added module rule for .mjs files in node_modules with resolve.fullySpecified: false');
|
|
424
231
|
}
|
|
425
|
-
|
|
426
|
-
return hasChanges;
|
|
427
232
|
}
|
|
428
233
|
|
|
429
234
|
/**
|
|
@@ -471,18 +276,3 @@ function ensureMinGrafanaVersion(context: Context): void {
|
|
|
471
276
|
additionsDebug(`Error updating ${PLUGIN_JSON_PATH}:`, error);
|
|
472
277
|
}
|
|
473
278
|
}
|
|
474
|
-
|
|
475
|
-
export default function bundleGrafanaUI(context: Context, _options: BundleGrafanaUIOptions): Context {
|
|
476
|
-
additionsDebug('Running bundle-grafana-ui addition...');
|
|
477
|
-
|
|
478
|
-
// Ensure minimum Grafana version requirement
|
|
479
|
-
ensureMinGrafanaVersion(context);
|
|
480
|
-
|
|
481
|
-
// Update externals array using the shared utility
|
|
482
|
-
updateExternalsArray(context, createBundleGrafanaUIModifier());
|
|
483
|
-
|
|
484
|
-
// Update bundler resolve configuration to handle ESM imports
|
|
485
|
-
updateBundlerResolveConfig(context);
|
|
486
|
-
|
|
487
|
-
return context;
|
|
488
|
-
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import * as recast from 'recast';
|
|
2
|
+
import * as typeScriptParser from 'recast/parsers/typescript.js';
|
|
3
|
+
|
|
4
|
+
import type { Context } from './context.js';
|
|
5
|
+
import { additionsDebug } from './utils.js';
|
|
6
|
+
|
|
7
|
+
const WEBPACK_CONFIG_PATH = '.config/webpack/webpack.config.ts';
|
|
8
|
+
const RSPACK_CONFIG_PATH = '.config/rspack/rspack.config.ts';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Type for a function that modifies a resolve object expression
|
|
12
|
+
* @param resolveObject - The AST node representing the resolve configuration
|
|
13
|
+
* @returns true if changes were made, false otherwise
|
|
14
|
+
*/
|
|
15
|
+
export type ResolveModifier = (resolveObject: recast.types.namedTypes.ObjectExpression) => boolean;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Type for a function that modifies a module rules array
|
|
19
|
+
* @param moduleObject - The AST node representing the module configuration
|
|
20
|
+
* @returns true if changes were made, false otherwise
|
|
21
|
+
*/
|
|
22
|
+
export type ModuleRulesModifier = (moduleObject: recast.types.namedTypes.ObjectExpression) => boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Updates the bundler's resolve and module configuration.
|
|
26
|
+
*
|
|
27
|
+
* This utility handles both webpack and rspack configurations, preferring rspack when both exist.
|
|
28
|
+
*
|
|
29
|
+
* @param context - The codemod context
|
|
30
|
+
* @param resolveModifier - Optional function to modify the resolve configuration
|
|
31
|
+
* @param moduleRulesModifier - Optional function to modify the module rules configuration
|
|
32
|
+
*/
|
|
33
|
+
export function updateBundlerConfig(
|
|
34
|
+
context: Context,
|
|
35
|
+
resolveModifier?: ResolveModifier,
|
|
36
|
+
moduleRulesModifier?: ModuleRulesModifier
|
|
37
|
+
): void {
|
|
38
|
+
if (!resolveModifier && !moduleRulesModifier) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Try rspack config first (newer structure)
|
|
43
|
+
if (context.doesFileExist(RSPACK_CONFIG_PATH)) {
|
|
44
|
+
additionsDebug(`Found ${RSPACK_CONFIG_PATH}, updating bundler configuration...`);
|
|
45
|
+
const rspackContent = context.getFile(RSPACK_CONFIG_PATH);
|
|
46
|
+
if (rspackContent) {
|
|
47
|
+
try {
|
|
48
|
+
const ast = recast.parse(rspackContent, {
|
|
49
|
+
parser: typeScriptParser,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
let hasChanges = false;
|
|
53
|
+
|
|
54
|
+
recast.visit(ast, {
|
|
55
|
+
visitObjectExpression(path) {
|
|
56
|
+
const { node } = path;
|
|
57
|
+
const properties = node.properties;
|
|
58
|
+
|
|
59
|
+
if (properties) {
|
|
60
|
+
for (const prop of properties) {
|
|
61
|
+
if (prop && (prop.type === 'Property' || prop.type === 'ObjectProperty')) {
|
|
62
|
+
const key = 'key' in prop ? prop.key : null;
|
|
63
|
+
const value = 'value' in prop ? prop.value : null;
|
|
64
|
+
|
|
65
|
+
// Find the resolve property
|
|
66
|
+
if (
|
|
67
|
+
resolveModifier &&
|
|
68
|
+
key &&
|
|
69
|
+
key.type === 'Identifier' &&
|
|
70
|
+
key.name === 'resolve' &&
|
|
71
|
+
value &&
|
|
72
|
+
value.type === 'ObjectExpression'
|
|
73
|
+
) {
|
|
74
|
+
hasChanges = resolveModifier(value) || hasChanges;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Find the module property
|
|
78
|
+
if (
|
|
79
|
+
moduleRulesModifier &&
|
|
80
|
+
key &&
|
|
81
|
+
key.type === 'Identifier' &&
|
|
82
|
+
key.name === 'module' &&
|
|
83
|
+
value &&
|
|
84
|
+
value.type === 'ObjectExpression'
|
|
85
|
+
) {
|
|
86
|
+
hasChanges = moduleRulesModifier(value) || hasChanges;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return this.traverse(path);
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (hasChanges) {
|
|
97
|
+
const output = recast.print(ast, {
|
|
98
|
+
tabWidth: 2,
|
|
99
|
+
trailingComma: true,
|
|
100
|
+
lineTerminator: '\n',
|
|
101
|
+
});
|
|
102
|
+
context.updateFile(RSPACK_CONFIG_PATH, output.code);
|
|
103
|
+
additionsDebug(`Updated ${RSPACK_CONFIG_PATH}`);
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
additionsDebug(`Error updating ${RSPACK_CONFIG_PATH}:`, error);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Fall back to webpack config (legacy structure)
|
|
113
|
+
if (context.doesFileExist(WEBPACK_CONFIG_PATH)) {
|
|
114
|
+
additionsDebug(`Found ${WEBPACK_CONFIG_PATH}, updating bundler configuration...`);
|
|
115
|
+
const webpackContent = context.getFile(WEBPACK_CONFIG_PATH);
|
|
116
|
+
if (webpackContent) {
|
|
117
|
+
try {
|
|
118
|
+
const ast = recast.parse(webpackContent, {
|
|
119
|
+
parser: typeScriptParser,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
let hasChanges = false;
|
|
123
|
+
|
|
124
|
+
recast.visit(ast, {
|
|
125
|
+
visitObjectExpression(path) {
|
|
126
|
+
const { node } = path;
|
|
127
|
+
const properties = node.properties;
|
|
128
|
+
|
|
129
|
+
if (properties) {
|
|
130
|
+
for (const prop of properties) {
|
|
131
|
+
if (prop && (prop.type === 'Property' || prop.type === 'ObjectProperty')) {
|
|
132
|
+
const key = 'key' in prop ? prop.key : null;
|
|
133
|
+
const value = 'value' in prop ? prop.value : null;
|
|
134
|
+
|
|
135
|
+
// Find the resolve property
|
|
136
|
+
if (
|
|
137
|
+
resolveModifier &&
|
|
138
|
+
key &&
|
|
139
|
+
key.type === 'Identifier' &&
|
|
140
|
+
key.name === 'resolve' &&
|
|
141
|
+
value &&
|
|
142
|
+
value.type === 'ObjectExpression'
|
|
143
|
+
) {
|
|
144
|
+
hasChanges = resolveModifier(value) || hasChanges;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Find the module property
|
|
148
|
+
if (
|
|
149
|
+
moduleRulesModifier &&
|
|
150
|
+
key &&
|
|
151
|
+
key.type === 'Identifier' &&
|
|
152
|
+
key.name === 'module' &&
|
|
153
|
+
value &&
|
|
154
|
+
value.type === 'ObjectExpression'
|
|
155
|
+
) {
|
|
156
|
+
hasChanges = moduleRulesModifier(value) || hasChanges;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return this.traverse(path);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
if (hasChanges) {
|
|
167
|
+
const output = recast.print(ast, {
|
|
168
|
+
tabWidth: 2,
|
|
169
|
+
trailingComma: true,
|
|
170
|
+
lineTerminator: '\n',
|
|
171
|
+
});
|
|
172
|
+
context.updateFile(WEBPACK_CONFIG_PATH, output.code);
|
|
173
|
+
additionsDebug(`Updated ${WEBPACK_CONFIG_PATH}`);
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
additionsDebug(`Error updating ${WEBPACK_CONFIG_PATH}:`, error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -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: '.' },
|
|
165
|
-
{ from: '
|
|
166
|
-
{ from:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|