@grafana/create-plugin 6.3.0-canary.2320.19638409321.0 → 6.3.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/additions.js +0 -5
- package/dist/codemods/utils.js +2 -2
- package/package.json +2 -7
- package/src/codemods/AGENTS.md +4 -24
- package/src/codemods/additions/additions.ts +0 -5
- package/templates/github/workflows/ci.yml +1 -1
- package/templates/panel/src/plugin.json +1 -1
- package/dist/codemods/additions/scripts/i18n/code-generation.js +0 -122
- package/dist/codemods/additions/scripts/i18n/config-updates.js +0 -113
- package/dist/codemods/additions/scripts/i18n/index.js +0 -49
- package/dist/codemods/additions/scripts/i18n/tooling.js +0 -119
- package/dist/codemods/additions/scripts/i18n/utils.js +0 -50
- package/src/codemods/additions/scripts/i18n/README.md +0 -157
- package/src/codemods/additions/scripts/i18n/code-generation.ts +0 -156
- package/src/codemods/additions/scripts/i18n/config-updates.ts +0 -139
- package/src/codemods/additions/scripts/i18n/index.test.ts +0 -770
- package/src/codemods/additions/scripts/i18n/index.ts +0 -81
- package/src/codemods/additions/scripts/i18n/tooling.ts +0 -146
- package/src/codemods/additions/scripts/i18n/utils.ts +0 -60
|
@@ -1,770 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import * as v from 'valibot';
|
|
3
|
-
|
|
4
|
-
import { Context } from '../../../context.js';
|
|
5
|
-
import i18nAddition, { schema } from './index.js';
|
|
6
|
-
|
|
7
|
-
describe('i18n addition', () => {
|
|
8
|
-
describe('schema validation', () => {
|
|
9
|
-
it('should require locales to be provided', () => {
|
|
10
|
-
const result = v.safeParse(schema, {});
|
|
11
|
-
expect(result.success).toBe(false);
|
|
12
|
-
if (!result.success) {
|
|
13
|
-
const errorMessage = result.issues[0].message;
|
|
14
|
-
expect(errorMessage).toContain('comma-separated list');
|
|
15
|
-
expect(errorMessage).toContain('en-US,es-ES,sv-SE');
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should validate locale format', () => {
|
|
20
|
-
const result = v.safeParse(schema, { locales: ['invalid'] });
|
|
21
|
-
expect(result.success).toBe(false);
|
|
22
|
-
if (!result.success) {
|
|
23
|
-
const errorMessage = result.issues[0].message;
|
|
24
|
-
expect(errorMessage).toContain('xx-XX');
|
|
25
|
-
expect(errorMessage).toContain('en-US');
|
|
26
|
-
expect(errorMessage).toContain('sv-SE');
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('should accept valid locales as array', () => {
|
|
31
|
-
const result = v.safeParse(schema, { locales: ['en-US', 'es-ES', 'sv-SE'] });
|
|
32
|
-
expect(result.success).toBe(true);
|
|
33
|
-
if (result.success) {
|
|
34
|
-
expect(result.output.locales).toEqual(['en-US', 'es-ES', 'sv-SE']);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should parse comma-separated string into array (CLI format)', () => {
|
|
39
|
-
const result = v.safeParse(schema, { locales: 'en-US,es-ES,sv-SE' });
|
|
40
|
-
expect(result.success).toBe(true);
|
|
41
|
-
if (result.success) {
|
|
42
|
-
expect(result.output.locales).toEqual(['en-US', 'es-ES', 'sv-SE']);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should trim whitespace from comma-separated values', () => {
|
|
47
|
-
const result = v.safeParse(schema, { locales: 'en-US, es-ES , sv-SE' });
|
|
48
|
-
expect(result.success).toBe(true);
|
|
49
|
-
if (result.success) {
|
|
50
|
-
expect(result.output.locales).toEqual(['en-US', 'es-ES', 'sv-SE']);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should add i18n support with en-US locale', () => {
|
|
56
|
-
const context = new Context('/virtual');
|
|
57
|
-
|
|
58
|
-
// Set up a minimal plugin structure with Grafana 11.0.0 (needs backward compatibility)
|
|
59
|
-
context.addFile(
|
|
60
|
-
'src/plugin.json',
|
|
61
|
-
JSON.stringify({
|
|
62
|
-
id: 'test-plugin',
|
|
63
|
-
type: 'panel',
|
|
64
|
-
name: 'Test Plugin',
|
|
65
|
-
dependencies: {
|
|
66
|
-
grafanaDependency: '>=11.0.0',
|
|
67
|
-
},
|
|
68
|
-
})
|
|
69
|
-
);
|
|
70
|
-
context.addFile(
|
|
71
|
-
'docker-compose.yaml',
|
|
72
|
-
`services:
|
|
73
|
-
grafana:
|
|
74
|
-
environment:
|
|
75
|
-
FOO: bar`
|
|
76
|
-
);
|
|
77
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
78
|
-
context.addFile(
|
|
79
|
-
'eslint.config.mjs',
|
|
80
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
81
|
-
);
|
|
82
|
-
context.addFile(
|
|
83
|
-
'src/module.ts',
|
|
84
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
88
|
-
|
|
89
|
-
// Check plugin.json was updated
|
|
90
|
-
const pluginJson = JSON.parse(result.getFile('src/plugin.json') || '{}');
|
|
91
|
-
expect(pluginJson.languages).toEqual(['en-US']);
|
|
92
|
-
// Should stay at 11.0.0 for backward compatibility
|
|
93
|
-
expect(pluginJson.dependencies.grafanaDependency).toBe('>=11.0.0');
|
|
94
|
-
|
|
95
|
-
// Check locale file was created
|
|
96
|
-
expect(result.doesFileExist('src/locales/en-US/test-plugin.json')).toBe(true);
|
|
97
|
-
const localeContent = result.getFile('src/locales/en-US/test-plugin.json');
|
|
98
|
-
const localeData = JSON.parse(localeContent || '{}');
|
|
99
|
-
expect(localeData).toEqual({}); // Should be an empty object
|
|
100
|
-
|
|
101
|
-
// Check package.json was updated with dependencies
|
|
102
|
-
const packageJson = JSON.parse(result.getFile('package.json') || '{}');
|
|
103
|
-
expect(packageJson.dependencies['@grafana/i18n']).toBe('^12.2.2');
|
|
104
|
-
expect(packageJson.dependencies['semver']).toBe('^7.6.0');
|
|
105
|
-
expect(packageJson.devDependencies['@types/semver']).toBe('^7.5.0');
|
|
106
|
-
expect(packageJson.devDependencies['i18next-cli']).toBeDefined();
|
|
107
|
-
expect(packageJson.scripts['i18n-extract']).toBe('i18next-cli extract --sync-primary');
|
|
108
|
-
|
|
109
|
-
// Check docker-compose.yaml was updated with feature toggle
|
|
110
|
-
const dockerCompose = result.getFile('docker-compose.yaml');
|
|
111
|
-
expect(dockerCompose).toContain('localizationForPlugins');
|
|
112
|
-
|
|
113
|
-
// Check module.ts was updated with backward compatibility code
|
|
114
|
-
const moduleTs = result.getFile('src/module.ts');
|
|
115
|
-
expect(moduleTs).toContain('initPluginTranslations');
|
|
116
|
-
expect(moduleTs).toContain('semver');
|
|
117
|
-
expect(moduleTs).toContain('loadResources');
|
|
118
|
-
|
|
119
|
-
// Check loadResources.ts was created for backward compatibility
|
|
120
|
-
expect(result.doesFileExist('src/loadResources.ts')).toBe(true);
|
|
121
|
-
const loadResources = result.getFile('src/loadResources.ts');
|
|
122
|
-
expect(loadResources).toContain('ResourceLoader');
|
|
123
|
-
|
|
124
|
-
// Check i18next.config.ts was created
|
|
125
|
-
expect(result.doesFileExist('i18next.config.ts')).toBe(true);
|
|
126
|
-
const i18nextConfig = result.getFile('i18next.config.ts');
|
|
127
|
-
expect(i18nextConfig).toContain('defineConfig');
|
|
128
|
-
expect(i18nextConfig).toContain('pluginJson.id');
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should add i18n support with multiple locales', () => {
|
|
132
|
-
const context = new Context('/virtual');
|
|
133
|
-
|
|
134
|
-
context.addFile(
|
|
135
|
-
'src/plugin.json',
|
|
136
|
-
JSON.stringify({
|
|
137
|
-
id: 'test-plugin',
|
|
138
|
-
type: 'panel',
|
|
139
|
-
name: 'Test Plugin',
|
|
140
|
-
dependencies: {
|
|
141
|
-
grafanaDependency: '>=11.0.0',
|
|
142
|
-
},
|
|
143
|
-
})
|
|
144
|
-
);
|
|
145
|
-
context.addFile(
|
|
146
|
-
'docker-compose.yaml',
|
|
147
|
-
`services:
|
|
148
|
-
grafana:
|
|
149
|
-
environment:
|
|
150
|
-
FOO: bar`
|
|
151
|
-
);
|
|
152
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
153
|
-
context.addFile(
|
|
154
|
-
'eslint.config.mjs',
|
|
155
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
156
|
-
);
|
|
157
|
-
context.addFile(
|
|
158
|
-
'src/module.ts',
|
|
159
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const result = i18nAddition(context, { locales: ['en-US', 'es-ES', 'sv-SE'] });
|
|
163
|
-
|
|
164
|
-
// Check plugin.json has all locales
|
|
165
|
-
const pluginJson = JSON.parse(result.getFile('src/plugin.json') || '{}');
|
|
166
|
-
expect(pluginJson.languages).toEqual(['en-US', 'es-ES', 'sv-SE']);
|
|
167
|
-
|
|
168
|
-
// Check all locale files were created
|
|
169
|
-
expect(result.doesFileExist('src/locales/en-US/test-plugin.json')).toBe(true);
|
|
170
|
-
expect(result.doesFileExist('src/locales/es-ES/test-plugin.json')).toBe(true);
|
|
171
|
-
expect(result.doesFileExist('src/locales/sv-SE/test-plugin.json')).toBe(true);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('should handle adding additional locales when i18n is already configured', () => {
|
|
175
|
-
const context = new Context('/virtual');
|
|
176
|
-
|
|
177
|
-
// Set up a plugin with i18n already configured
|
|
178
|
-
context.addFile(
|
|
179
|
-
'src/plugin.json',
|
|
180
|
-
JSON.stringify({
|
|
181
|
-
id: 'test-plugin',
|
|
182
|
-
type: 'panel',
|
|
183
|
-
name: 'Test Plugin',
|
|
184
|
-
languages: ['en-US'], // Already configured
|
|
185
|
-
dependencies: {
|
|
186
|
-
grafanaDependency: '>=12.1.0',
|
|
187
|
-
},
|
|
188
|
-
})
|
|
189
|
-
);
|
|
190
|
-
context.addFile(
|
|
191
|
-
'docker-compose.yaml',
|
|
192
|
-
`services:
|
|
193
|
-
grafana:
|
|
194
|
-
environment:
|
|
195
|
-
GF_FEATURE_TOGGLES_ENABLE: localizationForPlugins`
|
|
196
|
-
);
|
|
197
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
198
|
-
context.addFile(
|
|
199
|
-
'eslint.config.mjs',
|
|
200
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
201
|
-
);
|
|
202
|
-
context.addFile(
|
|
203
|
-
'src/module.ts',
|
|
204
|
-
'import { PanelPlugin } from "@grafana/data";\nimport { initPluginTranslations } from "@grafana/i18n";\nimport pluginJson from "plugin.json";\nawait initPluginTranslations(pluginJson.id);\nexport const plugin = new PanelPlugin();'
|
|
205
|
-
);
|
|
206
|
-
context.addFile('src/locales/en-US/test-plugin.json', JSON.stringify({ existing: 'translation' }));
|
|
207
|
-
|
|
208
|
-
const result = i18nAddition(context, { locales: ['en-US', 'es-ES'] });
|
|
209
|
-
|
|
210
|
-
// Should keep existing en-US locale file unchanged
|
|
211
|
-
const enUSContent = result.getFile('src/locales/en-US/test-plugin.json');
|
|
212
|
-
expect(JSON.parse(enUSContent || '{}')).toEqual({ existing: 'translation' });
|
|
213
|
-
|
|
214
|
-
// Should create the new es-ES locale file
|
|
215
|
-
expect(result.doesFileExist('src/locales/es-ES/test-plugin.json')).toBe(true);
|
|
216
|
-
|
|
217
|
-
// Should update plugin.json with both locales (defensive update)
|
|
218
|
-
const pluginJson = JSON.parse(result.getFile('src/plugin.json') || '{}');
|
|
219
|
-
expect(pluginJson.languages).toEqual(['en-US', 'es-ES']);
|
|
220
|
-
|
|
221
|
-
// Should not duplicate existing configurations
|
|
222
|
-
const moduleTs = result.getFile('src/module.ts');
|
|
223
|
-
const initCallCount = (moduleTs?.match(/initPluginTranslations/g) || []).length;
|
|
224
|
-
expect(initCallCount).toBe(2); // 1 import + 1 call, not duplicated
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('should handle existing feature toggles in docker-compose.yaml (Grafana >= 12.1.0)', () => {
|
|
228
|
-
const context = new Context('/virtual');
|
|
229
|
-
|
|
230
|
-
context.addFile(
|
|
231
|
-
'src/plugin.json',
|
|
232
|
-
JSON.stringify({
|
|
233
|
-
id: 'test-plugin',
|
|
234
|
-
type: 'panel',
|
|
235
|
-
name: 'Test Plugin',
|
|
236
|
-
dependencies: {
|
|
237
|
-
grafanaDependency: '>=12.1.0',
|
|
238
|
-
},
|
|
239
|
-
})
|
|
240
|
-
);
|
|
241
|
-
context.addFile(
|
|
242
|
-
'docker-compose.yaml',
|
|
243
|
-
`services:
|
|
244
|
-
grafana:
|
|
245
|
-
environment:
|
|
246
|
-
GF_FEATURE_TOGGLES_ENABLE: someOtherFeature`
|
|
247
|
-
);
|
|
248
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
249
|
-
context.addFile(
|
|
250
|
-
'eslint.config.mjs',
|
|
251
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
252
|
-
);
|
|
253
|
-
context.addFile(
|
|
254
|
-
'src/module.ts',
|
|
255
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
259
|
-
|
|
260
|
-
const dockerCompose = result.getFile('docker-compose.yaml');
|
|
261
|
-
expect(dockerCompose).toContain('someOtherFeature,localizationForPlugins');
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
it('should work with module.tsx instead of module.ts', () => {
|
|
265
|
-
const context = new Context('/virtual');
|
|
266
|
-
|
|
267
|
-
context.addFile(
|
|
268
|
-
'src/plugin.json',
|
|
269
|
-
JSON.stringify({
|
|
270
|
-
id: 'test-plugin',
|
|
271
|
-
type: 'panel',
|
|
272
|
-
name: 'Test Plugin',
|
|
273
|
-
dependencies: {
|
|
274
|
-
grafanaDependency: '>=11.0.0',
|
|
275
|
-
},
|
|
276
|
-
})
|
|
277
|
-
);
|
|
278
|
-
context.addFile(
|
|
279
|
-
'docker-compose.yaml',
|
|
280
|
-
`services:
|
|
281
|
-
grafana:
|
|
282
|
-
environment:
|
|
283
|
-
FOO: bar`
|
|
284
|
-
);
|
|
285
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
286
|
-
context.addFile(
|
|
287
|
-
'eslint.config.mjs',
|
|
288
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
289
|
-
);
|
|
290
|
-
context.addFile(
|
|
291
|
-
'src/module.tsx',
|
|
292
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
296
|
-
|
|
297
|
-
const moduleTsx = result.getFile('src/module.tsx');
|
|
298
|
-
expect(moduleTsx).toContain('@grafana/i18n');
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('should not update grafanaDependency if it is already >= 12.1.0', () => {
|
|
302
|
-
const context = new Context('/virtual');
|
|
303
|
-
|
|
304
|
-
context.addFile(
|
|
305
|
-
'src/plugin.json',
|
|
306
|
-
JSON.stringify({
|
|
307
|
-
id: 'test-plugin',
|
|
308
|
-
type: 'panel',
|
|
309
|
-
name: 'Test Plugin',
|
|
310
|
-
dependencies: {
|
|
311
|
-
grafanaDependency: '>=13.0.0',
|
|
312
|
-
},
|
|
313
|
-
})
|
|
314
|
-
);
|
|
315
|
-
context.addFile(
|
|
316
|
-
'docker-compose.yaml',
|
|
317
|
-
`services:
|
|
318
|
-
grafana:
|
|
319
|
-
environment:
|
|
320
|
-
FOO: bar`
|
|
321
|
-
);
|
|
322
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
323
|
-
context.addFile(
|
|
324
|
-
'eslint.config.mjs',
|
|
325
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
326
|
-
);
|
|
327
|
-
context.addFile(
|
|
328
|
-
'src/module.ts',
|
|
329
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
330
|
-
);
|
|
331
|
-
|
|
332
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
333
|
-
|
|
334
|
-
const pluginJson = JSON.parse(result.getFile('src/plugin.json') || '{}');
|
|
335
|
-
expect(pluginJson.dependencies.grafanaDependency).toBe('>=13.0.0');
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
it('should handle plugins without existing scripts in package.json', () => {
|
|
339
|
-
const context = new Context('/virtual');
|
|
340
|
-
|
|
341
|
-
context.addFile(
|
|
342
|
-
'src/plugin.json',
|
|
343
|
-
JSON.stringify({
|
|
344
|
-
id: 'test-plugin',
|
|
345
|
-
type: 'panel',
|
|
346
|
-
name: 'Test Plugin',
|
|
347
|
-
dependencies: {
|
|
348
|
-
grafanaDependency: '>=11.0.0',
|
|
349
|
-
},
|
|
350
|
-
})
|
|
351
|
-
);
|
|
352
|
-
context.addFile(
|
|
353
|
-
'docker-compose.yaml',
|
|
354
|
-
`services:
|
|
355
|
-
grafana:
|
|
356
|
-
environment:
|
|
357
|
-
FOO: bar`
|
|
358
|
-
);
|
|
359
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {} })); // No scripts field
|
|
360
|
-
context.addFile(
|
|
361
|
-
'eslint.config.mjs',
|
|
362
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
363
|
-
);
|
|
364
|
-
context.addFile(
|
|
365
|
-
'src/module.ts',
|
|
366
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
367
|
-
);
|
|
368
|
-
|
|
369
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
370
|
-
|
|
371
|
-
const packageJson = JSON.parse(result.getFile('package.json') || '{}');
|
|
372
|
-
expect(packageJson.scripts['i18n-extract']).toBe('i18next-cli extract --sync-primary');
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
it('should not add ESLint config if already present', () => {
|
|
376
|
-
const context = new Context('/virtual');
|
|
377
|
-
|
|
378
|
-
context.addFile(
|
|
379
|
-
'src/plugin.json',
|
|
380
|
-
JSON.stringify({
|
|
381
|
-
id: 'test-plugin',
|
|
382
|
-
type: 'panel',
|
|
383
|
-
name: 'Test Plugin',
|
|
384
|
-
dependencies: {
|
|
385
|
-
grafanaDependency: '>=12.1.0',
|
|
386
|
-
},
|
|
387
|
-
})
|
|
388
|
-
);
|
|
389
|
-
context.addFile(
|
|
390
|
-
'docker-compose.yaml',
|
|
391
|
-
`services:
|
|
392
|
-
grafana:
|
|
393
|
-
environment:
|
|
394
|
-
FOO: bar`
|
|
395
|
-
);
|
|
396
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
397
|
-
context.addFile(
|
|
398
|
-
'eslint.config.mjs',
|
|
399
|
-
'import { defineConfig } from "eslint/config";\nimport grafanaI18nPlugin from "@grafana/i18n/eslint-plugin";\nexport default defineConfig([]);'
|
|
400
|
-
);
|
|
401
|
-
context.addFile(
|
|
402
|
-
'src/module.ts',
|
|
403
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
404
|
-
);
|
|
405
|
-
|
|
406
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
407
|
-
|
|
408
|
-
// The ESLint config should remain unchanged
|
|
409
|
-
const eslintConfig = result.getFile('eslint.config.mjs');
|
|
410
|
-
expect(eslintConfig).toContain('@grafana/i18n/eslint-plugin');
|
|
411
|
-
// Should not have duplicate imports or configs
|
|
412
|
-
const importCount = (eslintConfig?.match(/@grafana\/i18n\/eslint-plugin/g) || []).length;
|
|
413
|
-
expect(importCount).toBe(1);
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
it('should not create locale files if they already exist', () => {
|
|
417
|
-
const context = new Context('/virtual');
|
|
418
|
-
|
|
419
|
-
context.addFile(
|
|
420
|
-
'src/plugin.json',
|
|
421
|
-
JSON.stringify({
|
|
422
|
-
id: 'test-plugin',
|
|
423
|
-
type: 'panel',
|
|
424
|
-
name: 'Test Plugin',
|
|
425
|
-
dependencies: {
|
|
426
|
-
grafanaDependency: '>=12.1.0',
|
|
427
|
-
},
|
|
428
|
-
})
|
|
429
|
-
);
|
|
430
|
-
context.addFile(
|
|
431
|
-
'docker-compose.yaml',
|
|
432
|
-
`services:
|
|
433
|
-
grafana:
|
|
434
|
-
environment:
|
|
435
|
-
FOO: bar`
|
|
436
|
-
);
|
|
437
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
438
|
-
context.addFile(
|
|
439
|
-
'eslint.config.mjs',
|
|
440
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
441
|
-
);
|
|
442
|
-
context.addFile(
|
|
443
|
-
'src/module.ts',
|
|
444
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
445
|
-
);
|
|
446
|
-
// Pre-existing locale file with custom content
|
|
447
|
-
const customTranslations = JSON.stringify({ custom: { key: 'value' } }, null, 2);
|
|
448
|
-
context.addFile('src/locales/en-US/test-plugin.json', customTranslations);
|
|
449
|
-
|
|
450
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
451
|
-
|
|
452
|
-
// The existing locale file should remain unchanged
|
|
453
|
-
const localeContent = result.getFile('src/locales/en-US/test-plugin.json');
|
|
454
|
-
expect(localeContent).toBe(customTranslations);
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
it('should not add i18n initialization if already present', () => {
|
|
458
|
-
const context = new Context('/virtual');
|
|
459
|
-
|
|
460
|
-
context.addFile(
|
|
461
|
-
'src/plugin.json',
|
|
462
|
-
JSON.stringify({
|
|
463
|
-
id: 'test-plugin',
|
|
464
|
-
type: 'panel',
|
|
465
|
-
name: 'Test Plugin',
|
|
466
|
-
dependencies: {
|
|
467
|
-
grafanaDependency: '>=12.1.0',
|
|
468
|
-
},
|
|
469
|
-
})
|
|
470
|
-
);
|
|
471
|
-
context.addFile(
|
|
472
|
-
'docker-compose.yaml',
|
|
473
|
-
`services:
|
|
474
|
-
grafana:
|
|
475
|
-
environment:
|
|
476
|
-
FOO: bar`
|
|
477
|
-
);
|
|
478
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
479
|
-
context.addFile(
|
|
480
|
-
'eslint.config.mjs',
|
|
481
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
482
|
-
);
|
|
483
|
-
const moduleWithI18n = `import { PanelPlugin } from "@grafana/data";
|
|
484
|
-
import { initPluginTranslations } from "@grafana/i18n";
|
|
485
|
-
import pluginJson from "plugin.json";
|
|
486
|
-
|
|
487
|
-
await initPluginTranslations(pluginJson.id);
|
|
488
|
-
|
|
489
|
-
export const plugin = new PanelPlugin();`;
|
|
490
|
-
context.addFile('src/module.ts', moduleWithI18n);
|
|
491
|
-
|
|
492
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
493
|
-
|
|
494
|
-
// The module file should remain unchanged (no duplicate imports/calls)
|
|
495
|
-
const moduleTs = result.getFile('src/module.ts');
|
|
496
|
-
const initCallCount = (moduleTs?.match(/initPluginTranslations/g) || []).length;
|
|
497
|
-
expect(initCallCount).toBe(2); // 1 import + 1 call
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
it('should not create i18next.config.ts if it already exists', () => {
|
|
501
|
-
const context = new Context('/virtual');
|
|
502
|
-
|
|
503
|
-
context.addFile(
|
|
504
|
-
'src/plugin.json',
|
|
505
|
-
JSON.stringify({
|
|
506
|
-
id: 'test-plugin',
|
|
507
|
-
type: 'panel',
|
|
508
|
-
name: 'Test Plugin',
|
|
509
|
-
dependencies: {
|
|
510
|
-
grafanaDependency: '>=12.1.0',
|
|
511
|
-
},
|
|
512
|
-
})
|
|
513
|
-
);
|
|
514
|
-
context.addFile(
|
|
515
|
-
'docker-compose.yaml',
|
|
516
|
-
`services:
|
|
517
|
-
grafana:
|
|
518
|
-
environment:
|
|
519
|
-
FOO: bar`
|
|
520
|
-
);
|
|
521
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
522
|
-
context.addFile(
|
|
523
|
-
'eslint.config.mjs',
|
|
524
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
525
|
-
);
|
|
526
|
-
context.addFile(
|
|
527
|
-
'src/module.ts',
|
|
528
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
529
|
-
);
|
|
530
|
-
const customI18nextConfig = 'export default { custom: true };';
|
|
531
|
-
context.addFile('i18next.config.ts', customI18nextConfig);
|
|
532
|
-
|
|
533
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
534
|
-
|
|
535
|
-
// The existing i18next.config.ts should remain unchanged
|
|
536
|
-
const i18nextConfig = result.getFile('i18next.config.ts');
|
|
537
|
-
expect(i18nextConfig).toBe(customI18nextConfig);
|
|
538
|
-
});
|
|
539
|
-
|
|
540
|
-
it('should not create loadResources.ts if it already exists', () => {
|
|
541
|
-
const context = new Context('/virtual');
|
|
542
|
-
|
|
543
|
-
context.addFile(
|
|
544
|
-
'src/plugin.json',
|
|
545
|
-
JSON.stringify({
|
|
546
|
-
id: 'test-plugin',
|
|
547
|
-
type: 'panel',
|
|
548
|
-
name: 'Test Plugin',
|
|
549
|
-
dependencies: {
|
|
550
|
-
grafanaDependency: '>=11.0.0',
|
|
551
|
-
},
|
|
552
|
-
})
|
|
553
|
-
);
|
|
554
|
-
context.addFile(
|
|
555
|
-
'docker-compose.yaml',
|
|
556
|
-
`services:
|
|
557
|
-
grafana:
|
|
558
|
-
environment:
|
|
559
|
-
FOO: bar`
|
|
560
|
-
);
|
|
561
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
562
|
-
context.addFile(
|
|
563
|
-
'eslint.config.mjs',
|
|
564
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
565
|
-
);
|
|
566
|
-
context.addFile(
|
|
567
|
-
'src/module.ts',
|
|
568
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
569
|
-
);
|
|
570
|
-
const customLoadResources = 'export const loadResources = () => {};';
|
|
571
|
-
context.addFile('src/loadResources.ts', customLoadResources);
|
|
572
|
-
|
|
573
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
574
|
-
|
|
575
|
-
// The existing loadResources.ts should remain unchanged
|
|
576
|
-
const loadResources = result.getFile('src/loadResources.ts');
|
|
577
|
-
expect(loadResources).toBe(customLoadResources);
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
it('should not add i18n-extract script if it already exists', () => {
|
|
581
|
-
const context = new Context('/virtual');
|
|
582
|
-
|
|
583
|
-
context.addFile(
|
|
584
|
-
'src/plugin.json',
|
|
585
|
-
JSON.stringify({
|
|
586
|
-
id: 'test-plugin',
|
|
587
|
-
type: 'panel',
|
|
588
|
-
name: 'Test Plugin',
|
|
589
|
-
dependencies: {
|
|
590
|
-
grafanaDependency: '>=12.1.0',
|
|
591
|
-
},
|
|
592
|
-
})
|
|
593
|
-
);
|
|
594
|
-
context.addFile(
|
|
595
|
-
'docker-compose.yaml',
|
|
596
|
-
`services:
|
|
597
|
-
grafana:
|
|
598
|
-
environment:
|
|
599
|
-
FOO: bar`
|
|
600
|
-
);
|
|
601
|
-
context.addFile(
|
|
602
|
-
'package.json',
|
|
603
|
-
JSON.stringify({
|
|
604
|
-
dependencies: {},
|
|
605
|
-
devDependencies: {},
|
|
606
|
-
scripts: {
|
|
607
|
-
'i18n-extract': 'custom extract command',
|
|
608
|
-
},
|
|
609
|
-
})
|
|
610
|
-
);
|
|
611
|
-
context.addFile(
|
|
612
|
-
'eslint.config.mjs',
|
|
613
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
614
|
-
);
|
|
615
|
-
context.addFile(
|
|
616
|
-
'src/module.ts',
|
|
617
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
618
|
-
);
|
|
619
|
-
|
|
620
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
621
|
-
|
|
622
|
-
// The existing i18n-extract script should remain unchanged
|
|
623
|
-
const packageJson = JSON.parse(result.getFile('package.json') || '{}');
|
|
624
|
-
expect(packageJson.scripts['i18n-extract']).toBe('custom extract command');
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
it('should add feature toggle to docker-compose for Grafana >= 12.1.0', () => {
|
|
628
|
-
const context = new Context('/virtual');
|
|
629
|
-
|
|
630
|
-
context.addFile(
|
|
631
|
-
'src/plugin.json',
|
|
632
|
-
JSON.stringify({
|
|
633
|
-
id: 'test-plugin',
|
|
634
|
-
type: 'panel',
|
|
635
|
-
name: 'Test Plugin',
|
|
636
|
-
dependencies: {
|
|
637
|
-
grafanaDependency: '>=12.1.0',
|
|
638
|
-
},
|
|
639
|
-
})
|
|
640
|
-
);
|
|
641
|
-
context.addFile(
|
|
642
|
-
'docker-compose.yaml',
|
|
643
|
-
`services:
|
|
644
|
-
grafana:
|
|
645
|
-
environment:
|
|
646
|
-
FOO: bar`
|
|
647
|
-
);
|
|
648
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
649
|
-
context.addFile(
|
|
650
|
-
'eslint.config.mjs',
|
|
651
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
652
|
-
);
|
|
653
|
-
context.addFile(
|
|
654
|
-
'src/module.ts',
|
|
655
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
656
|
-
);
|
|
657
|
-
|
|
658
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
659
|
-
|
|
660
|
-
const dockerCompose = result.getFile('docker-compose.yaml');
|
|
661
|
-
expect(dockerCompose).toContain('GF_FEATURE_TOGGLES_ENABLE: localizationForPlugins');
|
|
662
|
-
|
|
663
|
-
// Should not add backward compatibility dependencies
|
|
664
|
-
const packageJson = JSON.parse(result.getFile('package.json') || '{}');
|
|
665
|
-
expect(packageJson.dependencies['semver']).toBeUndefined();
|
|
666
|
-
expect(packageJson.devDependencies['@types/semver']).toBeUndefined();
|
|
667
|
-
|
|
668
|
-
// Should not create loadResources.ts
|
|
669
|
-
expect(result.doesFileExist('src/loadResources.ts')).toBe(false);
|
|
670
|
-
|
|
671
|
-
// Module should not have semver imports
|
|
672
|
-
const moduleTs = result.getFile('src/module.ts');
|
|
673
|
-
expect(moduleTs).not.toContain('semver');
|
|
674
|
-
expect(moduleTs).not.toContain('loadResources');
|
|
675
|
-
});
|
|
676
|
-
|
|
677
|
-
it('should not duplicate feature toggle if already present', () => {
|
|
678
|
-
const context = new Context('/virtual');
|
|
679
|
-
|
|
680
|
-
context.addFile(
|
|
681
|
-
'src/plugin.json',
|
|
682
|
-
JSON.stringify({
|
|
683
|
-
id: 'test-plugin',
|
|
684
|
-
type: 'panel',
|
|
685
|
-
name: 'Test Plugin',
|
|
686
|
-
dependencies: {
|
|
687
|
-
grafanaDependency: '>=12.1.0',
|
|
688
|
-
},
|
|
689
|
-
})
|
|
690
|
-
);
|
|
691
|
-
context.addFile(
|
|
692
|
-
'docker-compose.yaml',
|
|
693
|
-
`services:
|
|
694
|
-
grafana:
|
|
695
|
-
environment:
|
|
696
|
-
GF_FEATURE_TOGGLES_ENABLE: localizationForPlugins`
|
|
697
|
-
);
|
|
698
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
699
|
-
context.addFile(
|
|
700
|
-
'eslint.config.mjs',
|
|
701
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
702
|
-
);
|
|
703
|
-
context.addFile(
|
|
704
|
-
'src/module.ts',
|
|
705
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
706
|
-
);
|
|
707
|
-
|
|
708
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
709
|
-
|
|
710
|
-
const dockerCompose = result.getFile('docker-compose.yaml');
|
|
711
|
-
// Should only have one instance of localizationForPlugins
|
|
712
|
-
const toggleCount = (dockerCompose?.match(/localizationForPlugins/g) || []).length;
|
|
713
|
-
expect(toggleCount).toBe(1);
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
it('should add correct ESLint config with proper rules and options', () => {
|
|
717
|
-
const context = new Context('/virtual');
|
|
718
|
-
|
|
719
|
-
context.addFile(
|
|
720
|
-
'src/plugin.json',
|
|
721
|
-
JSON.stringify({
|
|
722
|
-
id: 'test-plugin',
|
|
723
|
-
type: 'panel',
|
|
724
|
-
name: 'Test Plugin',
|
|
725
|
-
dependencies: {
|
|
726
|
-
grafanaDependency: '>=12.1.0',
|
|
727
|
-
},
|
|
728
|
-
})
|
|
729
|
-
);
|
|
730
|
-
context.addFile(
|
|
731
|
-
'docker-compose.yaml',
|
|
732
|
-
`services:
|
|
733
|
-
grafana:
|
|
734
|
-
environment:
|
|
735
|
-
FOO: bar`
|
|
736
|
-
);
|
|
737
|
-
context.addFile('package.json', JSON.stringify({ dependencies: {}, devDependencies: {}, scripts: {} }));
|
|
738
|
-
context.addFile(
|
|
739
|
-
'eslint.config.mjs',
|
|
740
|
-
'import { defineConfig } from "eslint/config";\nexport default defineConfig([]);'
|
|
741
|
-
);
|
|
742
|
-
context.addFile(
|
|
743
|
-
'src/module.ts',
|
|
744
|
-
'import { PanelPlugin } from "@grafana/data";\nexport const plugin = new PanelPlugin();'
|
|
745
|
-
);
|
|
746
|
-
|
|
747
|
-
const result = i18nAddition(context, { locales: ['en-US'] });
|
|
748
|
-
|
|
749
|
-
const eslintConfig = result.getFile('eslint.config.mjs');
|
|
750
|
-
|
|
751
|
-
// Check correct import (recast uses double quotes)
|
|
752
|
-
expect(eslintConfig).toContain('import grafanaI18nPlugin from "@grafana/i18n/eslint-plugin"');
|
|
753
|
-
|
|
754
|
-
// Check plugin registration
|
|
755
|
-
expect(eslintConfig).toContain('"@grafana/i18n": grafanaI18nPlugin');
|
|
756
|
-
|
|
757
|
-
// Check rules are present
|
|
758
|
-
expect(eslintConfig).toContain('"@grafana/i18n/no-untranslated-strings"');
|
|
759
|
-
expect(eslintConfig).toContain('"@grafana/i18n/no-translation-top-level"');
|
|
760
|
-
|
|
761
|
-
// Check rule configuration
|
|
762
|
-
expect(eslintConfig).toContain('"error"');
|
|
763
|
-
expect(eslintConfig).toContain('calleesToIgnore');
|
|
764
|
-
expect(eslintConfig).toContain('"^css$"');
|
|
765
|
-
expect(eslintConfig).toContain('"use[A-Z].*"');
|
|
766
|
-
|
|
767
|
-
// Check config name
|
|
768
|
-
expect(eslintConfig).toContain('name: "grafana/i18n-rules"');
|
|
769
|
-
});
|
|
770
|
-
});
|