@grafana/create-plugin 6.8.0-canary.2356.20813241719.0 → 6.8.0-canary.2356.20813734793.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.
|
@@ -1,16 +1,21 @@
|
|
|
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';
|
|
5
|
+
import { updateBundlerConfig } from '../../../utils.bundler-config.js';
|
|
6
6
|
import { updateExternalsArray } from '../../../utils.externals.js';
|
|
7
7
|
|
|
8
8
|
const { builders } = recast.types;
|
|
9
|
-
const schema = v.object({});
|
|
10
9
|
const PLUGIN_JSON_PATH = "src/plugin.json";
|
|
11
10
|
const MIN_GRAFANA_VERSION = "10.2.0";
|
|
12
|
-
const
|
|
13
|
-
|
|
11
|
+
const schema = v.object({});
|
|
12
|
+
function bundleGrafanaUI(context, _options) {
|
|
13
|
+
additionsDebug("Running bundle-grafana-ui addition...");
|
|
14
|
+
ensureMinGrafanaVersion(context);
|
|
15
|
+
updateExternalsArray(context, createBundleGrafanaUIModifier());
|
|
16
|
+
updateBundlerConfig(context, createResolveModifier(), createModuleRulesModifier());
|
|
17
|
+
return context;
|
|
18
|
+
}
|
|
14
19
|
function isGrafanaUiRegex(element) {
|
|
15
20
|
if (element.type === "RegExpLiteral") {
|
|
16
21
|
const regexNode = element;
|
|
@@ -33,7 +38,7 @@ function isGrafanaDataRegex(element) {
|
|
|
33
38
|
}
|
|
34
39
|
return false;
|
|
35
40
|
}
|
|
36
|
-
function
|
|
41
|
+
function removeGrafanaUiAndAddReactInlineSvg(externalsArray) {
|
|
37
42
|
let hasChanges = false;
|
|
38
43
|
let hasGrafanaUiExternal = false;
|
|
39
44
|
let hasReactInlineSvg = false;
|
|
@@ -79,196 +84,109 @@ function modifyExternalsArray(externalsArray) {
|
|
|
79
84
|
}
|
|
80
85
|
function createBundleGrafanaUIModifier() {
|
|
81
86
|
return (externalsArray) => {
|
|
82
|
-
return
|
|
87
|
+
return removeGrafanaUiAndAddReactInlineSvg(externalsArray);
|
|
83
88
|
};
|
|
84
89
|
}
|
|
85
|
-
function
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
}
|
|
90
|
+
function createResolveModifier() {
|
|
91
|
+
return (resolveObject) => {
|
|
92
|
+
if (!resolveObject.properties) {
|
|
93
|
+
return false;
|
|
128
94
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
}
|
|
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;
|
|
157
111
|
}
|
|
158
|
-
return this.traverse(path);
|
|
159
112
|
}
|
|
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
113
|
}
|
|
170
|
-
} catch (error) {
|
|
171
|
-
additionsDebug(`Error updating ${WEBPACK_CONFIG_PATH}:`, error);
|
|
172
114
|
}
|
|
173
115
|
}
|
|
174
|
-
|
|
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");
|
|
121
|
+
}
|
|
122
|
+
return hasChanges;
|
|
123
|
+
};
|
|
175
124
|
}
|
|
176
|
-
function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
let hasChanges = false;
|
|
181
|
-
let hasMjsRule = false;
|
|
182
|
-
let rulesProperty = null;
|
|
183
|
-
for (const prop of moduleObject.properties) {
|
|
184
|
-
if (!prop || prop.type !== "Property" && prop.type !== "ObjectProperty") {
|
|
185
|
-
continue;
|
|
125
|
+
function createModuleRulesModifier() {
|
|
126
|
+
return (moduleObject) => {
|
|
127
|
+
if (!moduleObject.properties) {
|
|
128
|
+
return false;
|
|
186
129
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
+
}
|
|
208
159
|
}
|
|
209
160
|
}
|
|
210
161
|
}
|
|
211
162
|
}
|
|
212
|
-
|
|
213
|
-
if (hasMjsRule) {
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
break;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
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
|
-
}
|
|
240
|
-
function updateResolveObject(resolveObject) {
|
|
241
|
-
if (!resolveObject.properties) {
|
|
242
|
-
return false;
|
|
243
|
-
}
|
|
244
|
-
let hasChanges = false;
|
|
245
|
-
let hasMjsExtension = false;
|
|
246
|
-
let extensionsProperty = null;
|
|
247
|
-
for (const prop of resolveObject.properties) {
|
|
248
|
-
if (!prop || prop.type !== "Property" && prop.type !== "ObjectProperty") {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
251
|
-
const key = "key" in prop ? prop.key : null;
|
|
252
|
-
const value = "value" in prop ? prop.value : null;
|
|
253
|
-
if (key && key.type === "Identifier") {
|
|
254
|
-
if (key.name === "extensions" && value && value.type === "ArrayExpression") {
|
|
255
|
-
extensionsProperty = prop;
|
|
256
|
-
for (const element of value.elements) {
|
|
257
|
-
if (element && (element.type === "Literal" || element.type === "StringLiteral") && "value" in element && element.value === ".mjs") {
|
|
258
|
-
hasMjsExtension = true;
|
|
163
|
+
if (hasMjsRule) {
|
|
259
164
|
break;
|
|
260
165
|
}
|
|
261
166
|
}
|
|
167
|
+
break;
|
|
262
168
|
}
|
|
263
169
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
+
};
|
|
272
190
|
}
|
|
273
191
|
function ensureMinGrafanaVersion(context) {
|
|
274
192
|
if (!context.doesFileExist(PLUGIN_JSON_PATH)) {
|
|
@@ -308,12 +226,5 @@ function ensureMinGrafanaVersion(context) {
|
|
|
308
226
|
additionsDebug(`Error updating ${PLUGIN_JSON_PATH}:`, error);
|
|
309
227
|
}
|
|
310
228
|
}
|
|
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
229
|
|
|
319
230
|
export { bundleGrafanaUI as default, schema };
|
|
@@ -0,0 +1,102 @@
|
|
|
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 };
|
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.20813734793.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": "7dc0a04f78794e1d23d24b13fa2dfaa5a4312bc3"
|
|
59
59
|
}
|
|
@@ -1,22 +1,34 @@
|
|
|
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';
|
|
7
6
|
import { additionsDebug } from '../../../utils.js';
|
|
7
|
+
import { updateBundlerConfig, type ModuleRulesModifier, type ResolveModifier } from '../../../utils.bundler-config.js';
|
|
8
8
|
import { updateExternalsArray, type ExternalsArrayModifier } from '../../../utils.externals.js';
|
|
9
9
|
|
|
10
10
|
const { builders } = recast.types;
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const PLUGIN_JSON_PATH = 'src/plugin.json';
|
|
13
|
+
const MIN_GRAFANA_VERSION = '10.2.0';
|
|
13
14
|
|
|
15
|
+
export const schema = v.object({});
|
|
14
16
|
type BundleGrafanaUIOptions = v.InferOutput<typeof schema>;
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
export default function bundleGrafanaUI(context: Context, _options: BundleGrafanaUIOptions): Context {
|
|
19
|
+
additionsDebug('Running bundle-grafana-ui addition...');
|
|
20
|
+
|
|
21
|
+
// Ensure minimum Grafana version requirement
|
|
22
|
+
ensureMinGrafanaVersion(context);
|
|
23
|
+
|
|
24
|
+
// Update externals array using the shared utility
|
|
25
|
+
updateExternalsArray(context, createBundleGrafanaUIModifier());
|
|
26
|
+
|
|
27
|
+
// Update bundler resolve configuration to handle ESM imports
|
|
28
|
+
updateBundlerConfig(context, createResolveModifier(), createModuleRulesModifier());
|
|
29
|
+
|
|
30
|
+
return context;
|
|
31
|
+
}
|
|
20
32
|
|
|
21
33
|
/**
|
|
22
34
|
* Checks if an AST node is a regex matching @grafana/ui
|
|
@@ -58,7 +70,7 @@ function isGrafanaDataRegex(element: recast.types.namedTypes.ASTNode): boolean {
|
|
|
58
70
|
* Removes /^@grafana\/ui/i regex from externals array and adds 'react-inlinesvg'
|
|
59
71
|
* @returns true if changes were made, false otherwise
|
|
60
72
|
*/
|
|
61
|
-
function
|
|
73
|
+
function removeGrafanaUiAndAddReactInlineSvg(externalsArray: recast.types.namedTypes.ArrayExpression): boolean {
|
|
62
74
|
let hasChanges = false;
|
|
63
75
|
let hasGrafanaUiExternal = false;
|
|
64
76
|
let hasReactInlineSvg = false;
|
|
@@ -128,302 +140,163 @@ function modifyExternalsArray(externalsArray: recast.types.namedTypes.ArrayExpre
|
|
|
128
140
|
*/
|
|
129
141
|
function createBundleGrafanaUIModifier(): ExternalsArrayModifier {
|
|
130
142
|
return (externalsArray: recast.types.namedTypes.ArrayExpression) => {
|
|
131
|
-
return
|
|
143
|
+
return removeGrafanaUiAndAddReactInlineSvg(externalsArray);
|
|
132
144
|
};
|
|
133
145
|
}
|
|
134
146
|
|
|
135
147
|
/**
|
|
136
|
-
*
|
|
137
|
-
* - Adds '.mjs' to resolve.extensions
|
|
138
|
-
* - Adds fullySpecified: false to allow extensionless imports in node_modules
|
|
148
|
+
* Creates a modifier function for updateBundlerConfig that adds '.mjs' to resolve.extensions
|
|
139
149
|
*/
|
|
140
|
-
function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const rspackContent = context.getFile(RSPACK_CONFIG_PATH);
|
|
145
|
-
if (rspackContent) {
|
|
146
|
-
try {
|
|
147
|
-
const ast = recast.parse(rspackContent, {
|
|
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
|
-
}
|
|
150
|
+
function createResolveModifier(): ResolveModifier {
|
|
151
|
+
return (resolveObject: recast.types.namedTypes.ObjectExpression): boolean => {
|
|
152
|
+
if (!resolveObject.properties) {
|
|
153
|
+
return false;
|
|
205
154
|
}
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
155
|
|
|
209
|
-
|
|
210
|
-
|
|
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
|
-
}
|
|
156
|
+
let hasChanges = false;
|
|
157
|
+
let hasMjsExtension = false;
|
|
158
|
+
let extensionsProperty: recast.types.namedTypes.Property | null = null;
|
|
242
159
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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);
|
|
160
|
+
// Check current state
|
|
161
|
+
for (const prop of resolveObject.properties) {
|
|
162
|
+
if (!prop || (prop.type !== 'Property' && prop.type !== 'ObjectProperty')) {
|
|
163
|
+
continue;
|
|
272
164
|
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
165
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
*/
|
|
280
|
-
function updateModuleRules(moduleObject: recast.types.namedTypes.ObjectExpression): boolean {
|
|
281
|
-
if (!moduleObject.properties) {
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
166
|
+
const key = 'key' in prop ? prop.key : null;
|
|
167
|
+
const value = 'value' in prop ? prop.value : null;
|
|
284
168
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
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) {
|
|
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) {
|
|
304
174
|
if (
|
|
305
|
-
|
|
306
|
-
(
|
|
307
|
-
'
|
|
308
|
-
|
|
309
|
-
ruleProp.key.name === 'test'
|
|
175
|
+
element &&
|
|
176
|
+
(element.type === 'Literal' || element.type === 'StringLiteral') &&
|
|
177
|
+
'value' in element &&
|
|
178
|
+
element.value === '.mjs'
|
|
310
179
|
) {
|
|
311
|
-
|
|
312
|
-
|
|
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
|
-
}
|
|
180
|
+
hasMjsExtension = true;
|
|
181
|
+
break;
|
|
341
182
|
}
|
|
342
183
|
}
|
|
343
184
|
}
|
|
344
|
-
if (hasMjsRule) {
|
|
345
|
-
break;
|
|
346
|
-
}
|
|
347
185
|
}
|
|
348
|
-
break;
|
|
349
186
|
}
|
|
350
|
-
}
|
|
351
187
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
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');
|
|
371
|
-
}
|
|
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");
|
|
194
|
+
}
|
|
372
195
|
|
|
373
|
-
|
|
196
|
+
return hasChanges;
|
|
197
|
+
};
|
|
374
198
|
}
|
|
375
199
|
|
|
376
200
|
/**
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
* rule-level configuration to override ESM's strict fully-specified import requirements
|
|
201
|
+
* Creates a modifier function for updateBundlerConfig that adds a module rule for .mjs files
|
|
202
|
+
* in node_modules with resolve.fullySpecified: false
|
|
380
203
|
*/
|
|
381
|
-
function
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
204
|
+
function createModuleRulesModifier(): ModuleRulesModifier {
|
|
205
|
+
return (moduleObject: recast.types.namedTypes.ObjectExpression): boolean => {
|
|
206
|
+
if (!moduleObject.properties) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
385
209
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
210
|
+
let hasChanges = false;
|
|
211
|
+
let hasMjsRule = false;
|
|
212
|
+
let rulesProperty: recast.types.namedTypes.Property | null = null;
|
|
389
213
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
214
|
+
// Find the rules property
|
|
215
|
+
for (const prop of moduleObject.properties) {
|
|
216
|
+
if (!prop || (prop.type !== 'Property' && prop.type !== 'ObjectProperty')) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
395
219
|
|
|
396
|
-
|
|
397
|
-
|
|
220
|
+
const key = 'key' in prop ? prop.key : null;
|
|
221
|
+
const value = 'value' in prop ? prop.value : null;
|
|
398
222
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
// Check if .mjs is already in the extensions array
|
|
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
|
|
403
226
|
for (const element of value.elements) {
|
|
404
|
-
if (
|
|
405
|
-
element
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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) {
|
|
411
270
|
break;
|
|
412
271
|
}
|
|
413
272
|
}
|
|
273
|
+
break;
|
|
414
274
|
}
|
|
415
275
|
}
|
|
416
|
-
}
|
|
417
276
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
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
|
+
}
|
|
425
297
|
|
|
426
|
-
|
|
298
|
+
return hasChanges;
|
|
299
|
+
};
|
|
427
300
|
}
|
|
428
301
|
|
|
429
302
|
/**
|
|
@@ -471,18 +344,3 @@ function ensureMinGrafanaVersion(context: Context): void {
|
|
|
471
344
|
additionsDebug(`Error updating ${PLUGIN_JSON_PATH}:`, error);
|
|
472
345
|
}
|
|
473
346
|
}
|
|
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
|
+
}
|