@grafana/create-plugin 6.7.1-canary.2370.20798217827.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.
@@ -0,0 +1,181 @@
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
+ /**
8
+ * Utility for updating externals arrays in plugin bundler configurations.
9
+ *
10
+ * This utility is needed because the location of externals configuration has changed over time:
11
+ * - **New plugins** (created with recent versions of @grafana/create-plugin): Externals are defined
12
+ * in a separate file at `.config/bundler/externals.ts`
13
+ * - **Older plugins** (created with earlier versions): Externals are defined inline within
14
+ * `.config/webpack/webpack.config.ts` as part of the webpack Configuration object
15
+ *
16
+ * This utility handles both cases automatically, preferring the modern structure when both exist,
17
+ * to ensure additions and migrations work correctly regardless of when the plugin was created.
18
+ */
19
+
20
+ /**
21
+ * Type for a function that modifies an externals array
22
+ * @param externalsArray - The AST node representing the externals array
23
+ * @returns true if changes were made, false otherwise
24
+ */
25
+ export type ExternalsArrayModifier = (externalsArray: recast.types.namedTypes.ArrayExpression) => boolean;
26
+
27
+ const EXTERNALS_PATH = '.config/bundler/externals.ts';
28
+ const WEBPACK_CONFIG_PATH = '.config/webpack/webpack.config.ts';
29
+
30
+ /**
31
+ * Updates the externals array in either .config/bundler/externals.ts (preferred) or
32
+ * .config/webpack/webpack.config.ts (legacy fallback).
33
+ *
34
+ * @param context - The codemod context
35
+ * @param modifier - A function that modifies the externals array and returns true if changes were made
36
+ * @returns true if changes were made to any file, false otherwise
37
+ */
38
+ export function updateExternalsArray(context: Context, modifier: ExternalsArrayModifier): boolean {
39
+ // Try new structure first: .config/bundler/externals.ts
40
+ if (context.doesFileExist(EXTERNALS_PATH)) {
41
+ additionsDebug(`Found ${EXTERNALS_PATH}, updating externals array...`);
42
+ const externalsContent = context.getFile(EXTERNALS_PATH);
43
+ if (externalsContent) {
44
+ try {
45
+ const ast = recast.parse(externalsContent, {
46
+ parser: typeScriptParser,
47
+ });
48
+
49
+ let hasChanges = false;
50
+
51
+ recast.visit(ast, {
52
+ visitVariableDeclarator(path) {
53
+ const { node } = path;
54
+
55
+ if (
56
+ node.id.type === 'Identifier' &&
57
+ node.id.name === 'externals' &&
58
+ node.init &&
59
+ node.init.type === 'ArrayExpression'
60
+ ) {
61
+ additionsDebug('Found externals array in externals.ts');
62
+ if (modifier(node.init)) {
63
+ hasChanges = true;
64
+ }
65
+ }
66
+
67
+ return this.traverse(path);
68
+ },
69
+ });
70
+
71
+ if (hasChanges) {
72
+ const output = recast.print(ast, {
73
+ tabWidth: 2,
74
+ trailingComma: true,
75
+ lineTerminator: '\n',
76
+ });
77
+ context.updateFile(EXTERNALS_PATH, output.code);
78
+ additionsDebug(`Updated ${EXTERNALS_PATH}`);
79
+ return true;
80
+ }
81
+ return false;
82
+ } catch (error) {
83
+ additionsDebug(`Error updating ${EXTERNALS_PATH}:`, error);
84
+ return false;
85
+ }
86
+ }
87
+ }
88
+
89
+ // Fall back to legacy structure: .config/webpack/webpack.config.ts with inline externals
90
+ additionsDebug(`Checking for ${WEBPACK_CONFIG_PATH}...`);
91
+ if (context.doesFileExist(WEBPACK_CONFIG_PATH)) {
92
+ additionsDebug(`Found ${WEBPACK_CONFIG_PATH}, checking for inline externals...`);
93
+ const webpackContent = context.getFile(WEBPACK_CONFIG_PATH);
94
+ if (webpackContent) {
95
+ try {
96
+ const ast = recast.parse(webpackContent, {
97
+ parser: typeScriptParser,
98
+ });
99
+
100
+ let hasChanges = false;
101
+ let foundExternals = false;
102
+
103
+ recast.visit(ast, {
104
+ visitObjectExpression(path) {
105
+ const { node } = path;
106
+ const properties = node.properties;
107
+
108
+ if (properties) {
109
+ for (const prop of properties) {
110
+ if (prop && (prop.type === 'Property' || prop.type === 'ObjectProperty')) {
111
+ const key = 'key' in prop ? prop.key : null;
112
+ const value = 'value' in prop ? prop.value : null;
113
+
114
+ if (
115
+ key &&
116
+ key.type === 'Identifier' &&
117
+ key.name === 'externals' &&
118
+ value &&
119
+ value.type === 'ArrayExpression'
120
+ ) {
121
+ foundExternals = true;
122
+ additionsDebug('Found externals property in webpack.config.ts');
123
+ if (modifier(value)) {
124
+ hasChanges = true;
125
+ }
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ return this.traverse(path);
132
+ },
133
+ visitProperty(path) {
134
+ const { node } = path;
135
+
136
+ // Also check properties directly (fallback)
137
+ if (
138
+ node.key &&
139
+ node.key.type === 'Identifier' &&
140
+ node.key.name === 'externals' &&
141
+ node.value &&
142
+ node.value.type === 'ArrayExpression'
143
+ ) {
144
+ if (!foundExternals) {
145
+ foundExternals = true;
146
+ additionsDebug('Found externals property in webpack.config.ts (via visitProperty)');
147
+ }
148
+ if (modifier(node.value)) {
149
+ hasChanges = true;
150
+ }
151
+ }
152
+
153
+ return this.traverse(path);
154
+ },
155
+ });
156
+
157
+ if (!foundExternals) {
158
+ additionsDebug('No externals property found in webpack.config.ts');
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
+ return true;
170
+ }
171
+ return false;
172
+ } catch (error) {
173
+ additionsDebug(`Error updating ${WEBPACK_CONFIG_PATH}:`, error);
174
+ return false;
175
+ }
176
+ }
177
+ }
178
+
179
+ additionsDebug('No externals configuration found');
180
+ return false;
181
+ }
package/src/constants.ts CHANGED
@@ -49,7 +49,6 @@ export const EXTRA_TEMPLATE_VARIABLES = {
49
49
  };
50
50
 
51
51
  export const DEFAULT_FEATURE_FLAGS = {
52
- bundleGrafanaUI: false,
53
52
  useExperimentalRspack: false,
54
53
  useExperimentalUpdates: true,
55
54
  };
package/src/types.ts CHANGED
@@ -21,7 +21,6 @@ export type TemplateData = {
21
21
  isAppType: boolean;
22
22
  isNPM: boolean;
23
23
  version: string;
24
- bundleGrafanaUI: boolean;
25
24
  scenesVersion: string;
26
25
  useExperimentalRspack: boolean;
27
26
  pluginExecutable?: string;
@@ -46,13 +46,13 @@ describe('getConfig', () => {
46
46
 
47
47
  it('should override default feature flags via cli args', async () => {
48
48
  mocks.argv = {
49
- 'feature-flags': 'bundleGrafanaUI',
49
+ 'feature-flags': 'useExperimentalRspack',
50
50
  };
51
51
  const config = getConfig(tmpDir);
52
52
 
53
53
  expect(config).toEqual({
54
54
  version: CURRENT_APP_VERSION,
55
- features: { ...DEFAULT_FEATURE_FLAGS, bundleGrafanaUI: true },
55
+ features: { ...DEFAULT_FEATURE_FLAGS, useExperimentalRspack: true },
56
56
  });
57
57
  });
58
58
  });
@@ -94,7 +94,7 @@ describe('getConfig', () => {
94
94
  const userConfigPath = path.join(tmpDir, '.cprc.json');
95
95
  const userConfig: UserConfig = {
96
96
  features: {
97
- bundleGrafanaUI: true,
97
+ useExperimentalRspack: true,
98
98
  },
99
99
  };
100
100
 
@@ -107,27 +107,5 @@ describe('getConfig', () => {
107
107
  features: userConfig.features,
108
108
  });
109
109
  });
110
-
111
- it('should give back the correct config when config files exist', async () => {
112
- const rootConfigPath = path.join(tmpDir, '.config', '.cprc.json');
113
- const userConfigPath = path.join(tmpDir, '.cprc.json');
114
- const rootConfig: CreatePluginConfig = {
115
- version: '1.0.0',
116
- features: {},
117
- };
118
- const userConfig: UserConfig = {
119
- features: {
120
- bundleGrafanaUI: false,
121
- },
122
- };
123
-
124
- await fs.mkdir(path.dirname(rootConfigPath), { recursive: true });
125
- await fs.writeFile(rootConfigPath, JSON.stringify(rootConfig));
126
- await fs.writeFile(userConfigPath, JSON.stringify(userConfig));
127
-
128
- const config = getConfig(tmpDir);
129
-
130
- expect(config).toEqual({ ...rootConfig, ...userConfig });
131
- });
132
110
  });
133
111
  });
@@ -10,7 +10,6 @@ import { writeFile } from 'node:fs/promises';
10
10
  import { EOL } from 'node:os';
11
11
 
12
12
  export type FeatureFlags = {
13
- bundleGrafanaUI?: boolean;
14
13
  useExperimentalRspack?: boolean;
15
14
  useExperimentalUpdates?: boolean;
16
15
  };
@@ -1,10 +1,4 @@
1
- import {
2
- DEFAULT_FEATURE_FLAGS,
3
- EXPORT_PATH_PREFIX,
4
- EXTRA_TEMPLATE_VARIABLES,
5
- PLUGIN_TYPES,
6
- TEMPLATE_PATHS,
7
- } from '../constants.js';
1
+ import { EXPORT_PATH_PREFIX, EXTRA_TEMPLATE_VARIABLES, PLUGIN_TYPES, TEMPLATE_PATHS } from '../constants.js';
8
2
  import { GenerateCliArgs, TemplateData } from '../types.js';
9
3
  import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
10
4
  import {
@@ -95,7 +89,6 @@ export function renderTemplateFromFile(templateFile: string, data?: any) {
95
89
  export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
96
90
  const { features } = getConfig();
97
91
  const currentVersion = CURRENT_APP_VERSION;
98
- const bundleGrafanaUI = features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI;
99
92
  const isAppType = (pluginType: string) => pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
100
93
  const isNPM = (packageManagerName: string) => packageManagerName === 'npm';
101
94
  const frontendBundler = features.useExperimentalRspack ? 'rspack' : 'webpack';
@@ -120,7 +113,6 @@ export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
120
113
  isAppType: isAppType(cliArgs.pluginType),
121
114
  isNPM: isNPM(packageManagerName),
122
115
  version: currentVersion,
123
- bundleGrafanaUI,
124
116
  scenesVersion: '^6.10.4',
125
117
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
126
118
  frontendBundler,
@@ -144,7 +136,6 @@ export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
144
136
  isAppType: isAppType(pluginJson.type),
145
137
  isNPM: isNPM(packageManagerName),
146
138
  version: currentVersion,
147
- bundleGrafanaUI,
148
139
  scenesVersion: '^6.10.4',
149
140
  pluginExecutable: pluginJson.executable,
150
141
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
@@ -1,4 +1,4 @@
1
- import webpack from 'webpack';
1
+ import webpack, { type Compiler } from 'webpack';
2
2
 
3
3
  const PLUGIN_NAME = 'BuildModeWebpack';
4
4
 
@@ -1,6 +1,10 @@
1
1
  {
2
2
  "features": {
3
+ <<<<<<< HEAD
3
4
  "bundleGrafanaUI": {{ bundleGrafanaUI }},
5
+ =======
6
+ "useReactRouterV6": {{ useReactRouterV6 }},
7
+ >>>>>>> 91a41873 (renome var)
4
8
  "useExperimentalRspack": {{ useExperimentalRspack }}
5
9
  }
6
10
  }