@grafana/create-plugin 6.2.0-canary.2233.18586197736.0 → 6.2.0-canary.2233.18936109308.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,61 +1,22 @@
1
- import { getAdditionByName, getAvailableAdditions, runAddition } from '../additions/manager.js';
1
+ import { getAdditionFlags, getAvailableAdditions, runAdditionByName } from '../additions/manager.js';
2
2
  import { isGitDirectory, isGitDirectoryClean } from '../utils/utils.git.js';
3
3
 
4
4
  import { isPluginDirectory } from '../utils/utils.plugin.js';
5
5
  import minimist from 'minimist';
6
6
  import { output } from '../utils/utils.console.js';
7
- import { promptI18nOptions } from './add/prompts.js';
8
7
 
9
8
  export const add = async (argv: minimist.ParsedArgs) => {
10
9
  const subCommand = argv._[1];
11
10
 
12
11
  if (!subCommand) {
13
- const availableAdditions = getAvailableAdditions();
14
- const additionsList = Object.values(availableAdditions).map(
15
- (addition) => `${addition.name} - ${addition.description}`
16
- );
17
-
18
- output.error({
19
- title: 'No addition specified',
20
- body: [
21
- 'Usage: npx @grafana/create-plugin add <addition-name>',
22
- '',
23
- 'Available additions:',
24
- ...output.bulletList(additionsList),
25
- ],
26
- });
12
+ await showAdditionsHelp();
27
13
  process.exit(1);
28
14
  }
29
15
 
30
16
  await performPreAddChecks(argv);
31
17
 
32
- const addition = getAdditionByName(subCommand);
33
-
34
- if (!addition) {
35
- const availableAdditions = getAvailableAdditions();
36
- const additionsList = Object.values(availableAdditions).map((addition) => addition.name);
37
-
38
- output.error({
39
- title: `Unknown addition: ${subCommand}`,
40
- body: ['Available additions:', ...output.bulletList(additionsList)],
41
- });
42
- process.exit(1);
43
- }
44
-
45
18
  try {
46
- // Gather options based on the addition type
47
- let options = {};
48
-
49
- switch (addition.name) {
50
- case 'i18n':
51
- options = await promptI18nOptions();
52
- break;
53
- default:
54
- break;
55
- }
56
-
57
- const commitChanges = argv.commit;
58
- await runAddition(addition, options, { commitChanges });
19
+ await runAdditionByName(subCommand, argv, { commitChanges: argv.commit });
59
20
  } catch (error) {
60
21
  if (error instanceof Error) {
61
22
  output.error({
@@ -67,6 +28,34 @@ export const add = async (argv: minimist.ParsedArgs) => {
67
28
  }
68
29
  };
69
30
 
31
+ async function showAdditionsHelp() {
32
+ const availableAdditions = getAvailableAdditions();
33
+ const additionsList = await Promise.all(
34
+ Object.values(availableAdditions).map(async (addition) => {
35
+ let info = `${addition.name} - ${addition.description}`;
36
+ const flags = await getAdditionFlags(addition);
37
+ if (flags.length > 0) {
38
+ const flagDocs = flags.map((flag) => {
39
+ const req = flag.required ? ' (required)' : ' (optional)';
40
+ return ` --${flag.name}: ${flag.description}${req}`;
41
+ });
42
+ info += '\n' + flagDocs.join('\n');
43
+ }
44
+ return info;
45
+ })
46
+ );
47
+
48
+ output.error({
49
+ title: 'No addition specified',
50
+ body: [
51
+ 'Usage: npx @grafana/create-plugin add <addition-name> [options]',
52
+ '',
53
+ 'Available additions:',
54
+ ...output.bulletList(additionsList),
55
+ ],
56
+ });
57
+ }
58
+
70
59
  async function performPreAddChecks(argv: minimist.ParsedArgs) {
71
60
  if (!(await isGitDirectory()) && !argv.force) {
72
61
  output.error({
package/src/constants.ts CHANGED
@@ -1,5 +1,5 @@
1
- import path from 'node:path';
2
1
  import { fileURLToPath } from 'node:url';
2
+ import path from 'node:path';
3
3
 
4
4
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
5
5
 
@@ -51,19 +51,11 @@ export const EXTRA_TEMPLATE_VARIABLES = {
51
51
  export const DEFAULT_FEATURE_FLAGS = {
52
52
  useReactRouterV6: true,
53
53
  bundleGrafanaUI: false,
54
- usePlaywright: true,
55
54
  useExperimentalRspack: false,
56
55
  useExperimentalUpdates: true,
57
56
  };
58
57
 
59
- export const GRAFANA_FE_PACKAGES = [
60
- '@grafana/data',
61
- '@grafana/e2e-selectors',
62
- '@grafana/e2e',
63
- '@grafana/runtime',
64
- '@grafana/schema',
65
- '@grafana/ui',
66
- ];
58
+ export const GRAFANA_FE_PACKAGES = ['@grafana/data', '@grafana/runtime', '@grafana/schema', '@grafana/ui'];
67
59
 
68
60
  export const MIGRATION_CONFIG = {
69
61
  // Files that should be overriden during a migration.
package/src/types.ts CHANGED
@@ -25,8 +25,6 @@ export type TemplateData = {
25
25
  useReactRouterV6: boolean;
26
26
  scenesVersion: string;
27
27
  reactRouterVersion: string;
28
- usePlaywright: boolean;
29
- useCypress: boolean;
30
28
  useExperimentalRspack: boolean;
31
29
  pluginExecutable?: string;
32
30
  frontendBundler: 'webpack' | 'rspack';
@@ -1,11 +1,13 @@
1
- import fs from 'node:fs';
2
- import { writeFile } from 'node:fs/promises';
3
- import path from 'node:path';
4
- import { CURRENT_APP_VERSION } from './utils.version.js';
5
1
  import { argv, commandName } from './utils.cli.js';
2
+
3
+ import { CURRENT_APP_VERSION } from './utils.version.js';
6
4
  import { DEFAULT_FEATURE_FLAGS } from '../constants.js';
5
+ import fs from 'node:fs';
7
6
  import { output } from './utils.console.js';
8
7
  import { partitionArr } from './utils.helpers.js';
8
+ import path from 'node:path';
9
+ import { writeFile } from 'node:fs/promises';
10
+ import { EOL } from 'node:os';
9
11
 
10
12
  export type FeatureFlags = {
11
13
  bundleGrafanaUI?: boolean;
@@ -13,7 +15,6 @@ export type FeatureFlags = {
13
15
  // If set to true, the plugin will be scaffolded with React Router v6. Defaults to true.
14
16
  // (Attention! We always scaffold new projects with React Router v6, so if you are changing this to `false` manually you will need to make changes to the React code as well.)
15
17
  useReactRouterV6?: boolean;
16
- usePlaywright?: boolean;
17
18
  useExperimentalRspack?: boolean;
18
19
  useExperimentalUpdates?: boolean;
19
20
  };
@@ -127,7 +128,7 @@ export async function setRootConfig(configOverride: Partial<CreatePluginConfig>
127
128
  const rootConfigPath = path.resolve(process.cwd(), '.config/.cprc.json');
128
129
  const updatedConfig = { ...rootConfig, ...configOverride };
129
130
 
130
- await writeFile(rootConfigPath, JSON.stringify(updatedConfig, null, 2));
131
+ await writeFile(rootConfigPath, JSON.stringify(updatedConfig, null, 2) + EOL);
131
132
 
132
133
  return updatedConfig;
133
134
  }
@@ -1,27 +1,27 @@
1
- import { lt as semverLt } from 'semver';
2
- import { glob } from 'glob';
3
- import path from 'node:path';
4
- import fs from 'node:fs';
5
- import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
6
- import { normalizeId, renderHandlebarsTemplate } from './utils.handlebars.js';
7
- import { getPluginJson } from './utils.plugin.js';
8
- import { debug } from './utils.cli.js';
9
1
  import {
10
- TEMPLATE_PATHS,
2
+ DEFAULT_FEATURE_FLAGS,
11
3
  EXPORT_PATH_PREFIX,
12
4
  EXTRA_TEMPLATE_VARIABLES,
13
5
  PLUGIN_TYPES,
14
- DEFAULT_FEATURE_FLAGS,
6
+ TEMPLATE_PATHS,
15
7
  } from '../constants.js';
16
8
  import { GenerateCliArgs, TemplateData } from '../types.js';
9
+ import { filterOutCommonFiles, isFile, isFileStartingWith } from './utils.files.js';
17
10
  import {
11
+ getPackageManagerFromUserAgent,
18
12
  getPackageManagerInstallCmd,
19
13
  getPackageManagerWithFallback,
20
- getPackageManagerFromUserAgent,
21
14
  } from './utils.packageManager.js';
22
- import { getExportFileName } from '../utils/utils.files.js';
23
- import { getGrafanaRuntimeVersion, CURRENT_APP_VERSION } from './utils.version.js';
15
+ import { normalizeId, renderHandlebarsTemplate } from './utils.handlebars.js';
16
+
17
+ import { CURRENT_APP_VERSION } from './utils.version.js';
18
+ import { debug } from './utils.cli.js';
19
+ import fs from 'node:fs';
24
20
  import { getConfig } from './utils.config.js';
21
+ import { getExportFileName } from '../utils/utils.files.js';
22
+ import { getPluginJson } from './utils.plugin.js';
23
+ import { glob } from 'glob';
24
+ import path from 'node:path';
25
25
 
26
26
  const templatesDebugger = debug.extend('templates');
27
27
 
@@ -95,11 +95,6 @@ export function renderTemplateFromFile(templateFile: string, data?: any) {
95
95
  export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
96
96
  const { features } = getConfig();
97
97
  const currentVersion = CURRENT_APP_VERSION;
98
- const grafanaVersion = getGrafanaRuntimeVersion();
99
- const usePlaywright = features.usePlaywright === true || isFile(path.join(process.cwd(), 'playwright.config.ts'));
100
- //@grafana/e2e was deprecated in Grafana 11
101
- const useCypress =
102
- !usePlaywright && semverLt(grafanaVersion, '11.0.0') && fs.existsSync(path.join(process.cwd(), 'cypress'));
103
98
  const bundleGrafanaUI = features.bundleGrafanaUI ?? DEFAULT_FEATURE_FLAGS.bundleGrafanaUI;
104
99
  const getReactRouterVersion = () => (features.useReactRouterV6 ? '6.22.0' : '5.2.0');
105
100
  const isAppType = (pluginType: string) => pluginType === PLUGIN_TYPES.app || pluginType === PLUGIN_TYPES.scenes;
@@ -130,8 +125,6 @@ export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
130
125
  useReactRouterV6: features.useReactRouterV6 ?? DEFAULT_FEATURE_FLAGS.useReactRouterV6,
131
126
  reactRouterVersion: getReactRouterVersion(),
132
127
  scenesVersion: features.useReactRouterV6 ? '^6.10.4' : '^5.41.3',
133
- usePlaywright,
134
- useCypress,
135
128
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
136
129
  frontendBundler,
137
130
  };
@@ -158,8 +151,6 @@ export function getTemplateData(cliArgs?: GenerateCliArgs): TemplateData {
158
151
  useReactRouterV6: features.useReactRouterV6 ?? DEFAULT_FEATURE_FLAGS.useReactRouterV6,
159
152
  reactRouterVersion: getReactRouterVersion(),
160
153
  scenesVersion: features.useReactRouterV6 ? '^6.10.4' : '^5.41.3',
161
- usePlaywright,
162
- useCypress,
163
154
  pluginExecutable: pluginJson.executable,
164
155
  useExperimentalRspack: Boolean(features.useExperimentalRspack),
165
156
  frontendBundler,
@@ -8,26 +8,22 @@
8
8
  "test:ci": "jest --passWithNoTests --maxWorkers 4",
9
9
  "typecheck": "tsc --noEmit",
10
10
  "lint": "eslint --cache .",
11
- "lint:fix": "{{ packageManagerName }} run lint{{#if isNPM}} --{{/if}} --fix && prettier --write --list-different .",{{#if usePlaywright}}
12
- "e2e": "playwright test",{{/if}}{{#if useCypress}}
13
- "e2e": "{{ packageManagerName }} exec cypress install && {{ packageManagerName }} exec grafana-e2e run",
14
- "e2e:update": "{{ packageManagerName }} exec cypress install && {{ packageManagerName }} exec grafana-e2e run --update-screenshots",{{/if}}
11
+ "lint:fix": "{{ packageManagerName }} run lint{{#if isNPM}} --{{/if}} --fix && prettier --write --list-different .",
12
+ "e2e": "playwright test",
15
13
  "server": "docker compose up --build",
16
14
  "sign": "npx --yes @grafana/sign-plugin@latest"
17
15
  },
18
16
  "author": "{{ sentenceCase orgName }}",
19
17
  "license": "Apache-2.0",
20
18
  "devDependencies": {
21
- {{#if useCypress}} "@grafana/e2e": "^11.0.7",
22
- "@grafana/e2e-selectors": "^12.2.0",{{/if}}
23
- "@grafana/eslint-config": "^8.2.0",{{#if usePlaywright}}
24
- "@grafana/plugin-e2e": "^2.2.0",{{/if}}
25
- "@grafana/tsconfig": "^2.0.0",{{#if usePlaywright}}
26
- "@playwright/test": "^1.52.0",{{/if}}{{#if useExperimentalRspack}}
19
+ "@grafana/eslint-config": "^8.2.0",
20
+ "@grafana/plugin-e2e": "^2.2.0",
21
+ "@grafana/tsconfig": "^2.0.0",
22
+ "@playwright/test": "^1.52.0",{{#if useExperimentalRspack}}
27
23
  "@rspack/core": "^1.3.0",
28
24
  "@rspack/cli": "^1.3.0",{{/if}}
29
25
  "@stylistic/eslint-plugin-ts": "^2.9.0",
30
- "@swc/core": "^1.3.90",
26
+ "@swc/core": "1.13.20",
31
27
  "@swc/helpers": "^0.5.0",
32
28
  "@swc/jest": "^0.2.26",
33
29
  "@testing-library/jest-dom": "6.1.4",
@@ -56,8 +52,8 @@
56
52
  "replace-in-file-webpack-plugin": "^1.0.6",{{#if useExperimentalRspack}}
57
53
  "rspack-plugin-virtual-module": "^0.1.13",{{/if}}
58
54
  "sass": "1.63.2",
59
- "sass-loader": "13.3.1",{{#if usePlaywright}}
60
- "semver": "^7.6.3",{{/if}}
55
+ "sass-loader": "13.3.1",
56
+ "semver": "^7.6.3",
61
57
  "style-loader": "3.3.3",{{#unless useExperimentalRspack}}
62
58
  "swc-loader": "^0.2.3",{{/unless}}
63
59
  "terser-webpack-plugin": "^5.3.10",
@@ -10,6 +10,3 @@ public-hoist-pattern[]="*prettier*"
10
10
  # Hoist all types packages to the root for better TS support
11
11
  public-hoist-pattern[]="@types/*"
12
12
  public-hoist-pattern[]="*terser-webpack-plugin*"
13
- {{#unless usePlaywright}}
14
- # @grafana/e2e expects cypress to exist in the root of the node_modules directory
15
- public-hoist-pattern[]="*cypress*"{{/unless}}
@@ -24,4 +24,4 @@ jobs:
24
24
  with:
25
25
  persist-credentials: false
26
26
 
27
- - uses: grafana/plugin-actions/bundle-size@main # zizmor: ignore[unpinned-uses] provided by grafana
27
+ - uses: grafana/plugin-actions/bundle-size@v1.0.2
@@ -146,7 +146,7 @@ jobs:
146
146
 
147
147
  - name: Resolve Grafana E2E versions
148
148
  id: resolve-versions
149
- uses: grafana/plugin-actions/e2e-version@main # zizmor: ignore[unpinned-uses] provided by grafana
149
+ uses: grafana/plugin-actions/e2e-version@v1.1.2
150
150
 
151
151
  playwright-tests:
152
152
  needs: [resolve-versions, build]
@@ -197,7 +197,7 @@ jobs:
197
197
  ANONYMOUS_AUTH_ENABLED=false DEVELOPMENT=false GRAFANA_VERSION=$\{{ matrix.GRAFANA_IMAGE.VERSION }} GRAFANA_IMAGE=$\{{ matrix.GRAFANA_IMAGE.NAME }} docker compose up -d
198
198
 
199
199
  - name: Wait for grafana server
200
- uses: grafana/plugin-actions/wait-for-grafana@main # zizmor: ignore[unpinned-uses] provided by grafana
200
+ uses: grafana/plugin-actions/wait-for-grafana@v1.0.2
201
201
  with:
202
202
  url: http://localhost:3000/login
203
203
 
@@ -209,7 +209,7 @@ jobs:
209
209
  run: {{ packageManagerName }} run e2e
210
210
 
211
211
  - name: Upload e2e test summary
212
- uses: grafana/plugin-actions/playwright-gh-pages/upload-report-artifacts@main # zizmor: ignore[unpinned-uses] provided by grafana
212
+ uses: grafana/plugin-actions/playwright-gh-pages/upload-report-artifacts@v1.0.1
213
213
  if: $\{{ always() && !cancelled() }}
214
214
  with:
215
215
  upload-report: false
@@ -247,7 +247,7 @@ jobs:
247
247
  # required for playwright-gh-pages
248
248
  persist-credentials: true
249
249
  - name: Publish report
250
- uses: grafana/plugin-actions/playwright-gh-pages/deploy-report-pages@main # zizmor: ignore[unpinned-uses] provided by grafana
250
+ uses: grafana/plugin-actions/playwright-gh-pages/deploy-report-pages@v1.0.1
251
251
  with:
252
252
  github-token: $\{{ secrets.GITHUB_TOKEN }}
253
253
 
@@ -18,7 +18,7 @@ jobs:
18
18
  release:
19
19
  runs-on: ubuntu-latest
20
20
  steps:
21
- - uses: grafana/plugin-actions/create-plugin-update@main # zizmor: ignore[unpinned-uses] provided by grafana
21
+ - uses: grafana/plugin-actions/create-plugin-update@v1.1.0
22
22
  # Uncomment to use a fine-grained personal access token instead of default github token
23
23
  # (For more info on how to generate the token see https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
24
24
  # with:
@@ -36,7 +36,7 @@ jobs:
36
36
  echo "modulets=${MODULETS}" >> $GITHUB_OUTPUT
37
37
 
38
38
  - name: Compatibility check
39
- uses: grafana/plugin-actions/is-compatible@main
39
+ uses: grafana/plugin-actions/is-compatible@v1.0.2
40
40
  with:
41
41
  module: $\{{ steps.find-module-ts.outputs.modulets }}
42
42
  comment-pr: "no"
@@ -20,7 +20,7 @@ jobs:
20
20
  with:
21
21
  persist-credentials: false
22
22
 
23
- - uses: grafana/plugin-actions/build-plugin@main # zizmor: ignore[unpinned-uses] provided by grafana
23
+ - uses: grafana/plugin-actions/build-plugin@v1.0.2
24
24
  # Uncomment to enable plugin signing
25
25
  # (For more info on how to generate the access policy token see https://grafana.com/developers/plugin-tools/publish-a-plugin/sign-a-plugin#generate-an-access-policy-token)
26
26
  #with:
@@ -1,72 +0,0 @@
1
- import Enquirer from 'enquirer';
2
- import { output } from '../../utils/utils.console.js';
3
-
4
- const COMMON_LOCALES = [
5
- { name: "en-US", message: "English (US)" },
6
- { name: "es-ES", message: "Spanish (Spain)" },
7
- { name: "fr-FR", message: "French (France)" },
8
- { name: "de-DE", message: "German (Germany)" },
9
- { name: "zh-Hans", message: "Chinese (Simplified)" },
10
- { name: "pt-BR", message: "Portuguese (Brazil)" },
11
- { name: "sv-SE", message: "Swedish (Sweden)" },
12
- { name: "nl-NL", message: "Dutch (Netherlands)" },
13
- { name: "ja-JP", message: "Japanese (Japan)" },
14
- { name: "it-IT", message: "Italian (Italy)" }
15
- ];
16
- async function promptI18nOptions() {
17
- const enquirer = new Enquirer();
18
- output.log({
19
- title: "Configure internationalization (i18n) for your plugin",
20
- body: [
21
- "Select the locales you want to support. At least one locale must be selected.",
22
- "Use space to select, enter to continue."
23
- ]
24
- });
25
- const localeChoices = COMMON_LOCALES.map((locale) => ({
26
- name: locale.name,
27
- message: locale.message,
28
- value: locale.name
29
- }));
30
- let selectedLocales = [];
31
- try {
32
- const result = await enquirer.prompt({
33
- type: "multiselect",
34
- name: "locales",
35
- message: "Select locales to support:",
36
- choices: localeChoices,
37
- initial: [0],
38
- // Pre-select en-US by default
39
- validate(value) {
40
- if (value.length === 0) {
41
- return "At least one locale must be selected";
42
- }
43
- return true;
44
- }
45
- });
46
- selectedLocales = result.locales;
47
- } catch (error) {
48
- output.warning({ title: "Addition cancelled by user." });
49
- process.exit(0);
50
- }
51
- try {
52
- const addMoreResult = await enquirer.prompt({
53
- type: "input",
54
- name: "additionalLocales",
55
- message: 'Enter additional locale codes (comma-separated, e.g., "ko-KR,ru-RU") or press enter to skip:'
56
- });
57
- const additionalLocalesInput = addMoreResult.additionalLocales;
58
- if (additionalLocalesInput && additionalLocalesInput.trim()) {
59
- const additionalLocales = additionalLocalesInput.split(",").map((locale) => locale.trim()).filter((locale) => locale.length > 0 && !selectedLocales.includes(locale));
60
- selectedLocales.push(...additionalLocales);
61
- }
62
- } catch (error) {
63
- }
64
- output.log({
65
- title: `Selected locales: ${selectedLocales.join(", ")}`
66
- });
67
- return {
68
- locales: selectedLocales
69
- };
70
- }
71
-
72
- export { promptI18nOptions };
@@ -1,93 +0,0 @@
1
- import Enquirer from 'enquirer';
2
- import { output } from '../../utils/utils.console.js';
3
-
4
- // Common locales supported by Grafana
5
- // Reference: https://github.com/grafana/grafana/blob/main/packages/grafana-i18n/src/constants.ts
6
- const COMMON_LOCALES = [
7
- { name: 'en-US', message: 'English (US)' },
8
- { name: 'es-ES', message: 'Spanish (Spain)' },
9
- { name: 'fr-FR', message: 'French (France)' },
10
- { name: 'de-DE', message: 'German (Germany)' },
11
- { name: 'zh-Hans', message: 'Chinese (Simplified)' },
12
- { name: 'pt-BR', message: 'Portuguese (Brazil)' },
13
- { name: 'sv-SE', message: 'Swedish (Sweden)' },
14
- { name: 'nl-NL', message: 'Dutch (Netherlands)' },
15
- { name: 'ja-JP', message: 'Japanese (Japan)' },
16
- { name: 'it-IT', message: 'Italian (Italy)' },
17
- ];
18
-
19
- export type I18nOptions = {
20
- locales: string[];
21
- };
22
-
23
- export async function promptI18nOptions(): Promise<I18nOptions> {
24
- const enquirer = new Enquirer();
25
-
26
- output.log({
27
- title: 'Configure internationalization (i18n) for your plugin',
28
- body: [
29
- 'Select the locales you want to support. At least one locale must be selected.',
30
- 'Use space to select, enter to continue.',
31
- ],
32
- });
33
-
34
- const localeChoices = COMMON_LOCALES.map((locale) => ({
35
- name: locale.name,
36
- message: locale.message,
37
- value: locale.name,
38
- }));
39
-
40
- let selectedLocales: string[] = [];
41
-
42
- try {
43
- const result = (await enquirer.prompt({
44
- type: 'multiselect',
45
- name: 'locales',
46
- message: 'Select locales to support:',
47
- choices: localeChoices,
48
- initial: [0], // Pre-select en-US by default
49
- validate(value: string[]) {
50
- if (value.length === 0) {
51
- return 'At least one locale must be selected';
52
- }
53
- return true;
54
- },
55
- } as any)) as { locales: string[] };
56
-
57
- selectedLocales = result.locales;
58
- } catch (error) {
59
- // User cancelled the prompt
60
- output.warning({ title: 'Addition cancelled by user.' });
61
- process.exit(0);
62
- }
63
-
64
- // Ask if they want to add additional locales
65
- try {
66
- const addMoreResult = (await enquirer.prompt({
67
- type: 'input',
68
- name: 'additionalLocales',
69
- message: 'Enter additional locale codes (comma-separated, e.g., "ko-KR,ru-RU") or press enter to skip:',
70
- } as any)) as { additionalLocales: string };
71
-
72
- const additionalLocalesInput = addMoreResult.additionalLocales;
73
-
74
- if (additionalLocalesInput && additionalLocalesInput.trim()) {
75
- const additionalLocales = additionalLocalesInput
76
- .split(',')
77
- .map((locale: string) => locale.trim())
78
- .filter((locale: string) => locale.length > 0 && !selectedLocales.includes(locale));
79
-
80
- selectedLocales.push(...additionalLocales);
81
- }
82
- } catch (error) {
83
- // User cancelled, just continue with what we have
84
- }
85
-
86
- output.log({
87
- title: `Selected locales: ${selectedLocales.join(', ')}`,
88
- });
89
-
90
- return {
91
- locales: selectedLocales,
92
- };
93
- }