@grafana/create-plugin 6.5.1 → 6.5.2-canary.2349.20294543760.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/dist/codemods/utils.js +4 -4
- package/dist/commands/generate/print-success-message.js +9 -8
- package/dist/commands/generate.command.js +3 -3
- package/dist/commands/migrate.command.js +2 -2
- package/dist/libs/output/src/index.js +16 -23
- package/dist/utils/utils.console.js +2 -2
- package/package.json +3 -4
- package/src/codemods/utils.ts +4 -4
- package/src/commands/generate/print-success-message.ts +9 -8
- package/src/commands/generate.command.ts +3 -3
- package/src/commands/migrate.command.ts +2 -2
- package/src/utils/utils.console.ts +3 -3
package/dist/codemods/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { join, dirname } from 'node:path';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { mkdirSync, writeFileSync, rmSync } from 'node:fs';
|
|
4
|
-
import
|
|
4
|
+
import { styleText } from 'node:util';
|
|
5
5
|
import { output } from '../utils/utils.console.js';
|
|
6
6
|
import { getPackageManagerWithFallback, getPackageManagerSilentInstallCmd } from '../utils/utils.packageManager.js';
|
|
7
7
|
import { execSync } from 'node:child_process';
|
|
@@ -13,11 +13,11 @@ function printChanges(context, key, description) {
|
|
|
13
13
|
const lines = [];
|
|
14
14
|
for (const [filePath, { changeType }] of Object.entries(changes)) {
|
|
15
15
|
if (changeType === "add") {
|
|
16
|
-
lines.push(`${
|
|
16
|
+
lines.push(`${styleText(["green"], "ADD")} ${filePath}`);
|
|
17
17
|
} else if (changeType === "update") {
|
|
18
|
-
lines.push(`${
|
|
18
|
+
lines.push(`${styleText(["yellow"], "UPDATE")} ${filePath}`);
|
|
19
19
|
} else if (changeType === "delete") {
|
|
20
|
-
lines.push(`${
|
|
20
|
+
lines.push(`${styleText(["red"], "DELETE")} ${filePath}`);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
output.addHorizontalLine("gray");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { machine } from 'node:os';
|
|
2
|
-
import
|
|
2
|
+
import { styleText } from 'node:util';
|
|
3
3
|
import { output } from '../../utils/utils.console.js';
|
|
4
4
|
import { normalizeId } from '../../utils/utils.handlebars.js';
|
|
5
5
|
import { getPackageManagerFromUserAgent } from '../../utils/utils.packageManager.js';
|
|
@@ -9,14 +9,14 @@ function printGenerateSuccessMessage(answers) {
|
|
|
9
9
|
const { packageManagerName } = getPackageManagerFromUserAgent();
|
|
10
10
|
const commands = output.bulletList([
|
|
11
11
|
output.formatCode(`cd ./${directory}`),
|
|
12
|
-
`${output.formatCode(packageManagerName + " install")} ${
|
|
13
|
-
`${output.formatCode(packageManagerName + " exec playwright install chromium")} ${
|
|
14
|
-
`${output.formatCode(packageManagerName + " run dev")} ${
|
|
12
|
+
`${output.formatCode(packageManagerName + " install")} ${styleText(["dim"], "to install frontend dependencies")}`,
|
|
13
|
+
`${output.formatCode(packageManagerName + " exec playwright install chromium")} ${styleText(["dim"], "to install e2e test dependencies")}`,
|
|
14
|
+
`${output.formatCode(packageManagerName + " run dev")} ${styleText(["dim"], "to build (and watch) the plugin frontend code")}`,
|
|
15
15
|
...answers.hasBackend ? [
|
|
16
|
-
`${getBackendCmd()} ${
|
|
16
|
+
`${getBackendCmd()} ${styleText(["dim"], "to build the plugin backend code. Rerun this command every time you edit your backend files")}`
|
|
17
17
|
] : [],
|
|
18
|
-
`${output.formatCode("docker compose up")} ${
|
|
19
|
-
`Open ${output.formatUrl("http://localhost:3000")} ${
|
|
18
|
+
`${output.formatCode("docker compose up")} ${styleText(["dim"], "to start a grafana development server")}`,
|
|
19
|
+
`Open ${output.formatUrl("http://localhost:3000")} ${styleText(["dim"], "in your browser to begin developing your plugin")}`
|
|
20
20
|
]);
|
|
21
21
|
output.log({
|
|
22
22
|
title: "Next steps:",
|
|
@@ -24,7 +24,8 @@ function printGenerateSuccessMessage(answers) {
|
|
|
24
24
|
"Run the following commands to get started:",
|
|
25
25
|
...commands,
|
|
26
26
|
"",
|
|
27
|
-
|
|
27
|
+
styleText(
|
|
28
|
+
["italic"],
|
|
28
29
|
`Note: We strongly recommend creating a new Git repository by running ${output.formatCode("git init")} in ./${directory} before continuing.`
|
|
29
30
|
),
|
|
30
31
|
"",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
2
|
import { glob } from 'glob';
|
|
3
3
|
import { readdir, mkdir, writeFile } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
@@ -22,7 +22,7 @@ const generate = async (argv) => {
|
|
|
22
22
|
if (exportPathIsPopulated && !IS_DEV) {
|
|
23
23
|
output.error({
|
|
24
24
|
title: "Aborting plugin scaffold.",
|
|
25
|
-
body: [`Directory ${
|
|
25
|
+
body: [`Directory ${styleText(["bold"], exportPath)} exists and contains files.`]
|
|
26
26
|
});
|
|
27
27
|
process.exit(1);
|
|
28
28
|
}
|
|
@@ -148,7 +148,7 @@ async function execPostScaffoldFunction(fn, ...args) {
|
|
|
148
148
|
try {
|
|
149
149
|
const resultMsg = await fn.apply(void 0, args);
|
|
150
150
|
if (resultMsg) {
|
|
151
|
-
console.log(`${
|
|
151
|
+
console.log(`${styleText(["green"], "\u2714\uFE0E")} ${resultMsg}`);
|
|
152
152
|
}
|
|
153
153
|
} catch (error) {
|
|
154
154
|
if (error instanceof Error) {
|
|
@@ -4,7 +4,7 @@ import { getTemplateData, compileTemplateFiles } from '../utils/utils.templates.
|
|
|
4
4
|
import { getExportTemplateName, getOnlyNotExistingInCwd, getOnlyExistingInCwd, removeFilesInCwd } from '../utils/utils.files.js';
|
|
5
5
|
import { hasNpmDependenciesToUpdate, getPackageJsonUpdatesAsText, updatePackageJson, getRemovableNpmDependencies, removeNpmDependencies, updateNpmScripts, writePackageManagerInPackageJson, cleanUpPackageJson } from '../utils/utils.npm.js';
|
|
6
6
|
import { getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
|
|
7
|
-
import
|
|
7
|
+
import { styleText } from 'node:util';
|
|
8
8
|
|
|
9
9
|
const migrate = async () => {
|
|
10
10
|
try {
|
|
@@ -91,7 +91,7 @@ const migrate = async () => {
|
|
|
91
91
|
output.success({
|
|
92
92
|
title: "Migration completed successfully.",
|
|
93
93
|
body: [
|
|
94
|
-
|
|
94
|
+
styleText(["bold"], "What's next?"),
|
|
95
95
|
...nextSteps,
|
|
96
96
|
"See instructions on how to customize your configuration here: https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations"
|
|
97
97
|
]
|
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
2
|
import { EOL } from 'os';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
6
6
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
7
|
-
function isCI() {
|
|
8
|
-
return process.env.CI && process.env.CI !== "false" || // Drone CI plus others
|
|
9
|
-
process.env.GITHUB_ACTIONS === "true";
|
|
10
|
-
}
|
|
11
|
-
if (isCI()) {
|
|
12
|
-
chalk.level = 0;
|
|
13
|
-
}
|
|
14
7
|
class Output {
|
|
15
8
|
constructor(name, version) {
|
|
16
9
|
__publicField(this, "appName");
|
|
@@ -29,7 +22,7 @@ class Output {
|
|
|
29
22
|
return separator;
|
|
30
23
|
}
|
|
31
24
|
addHorizontalLine(color) {
|
|
32
|
-
const separator =
|
|
25
|
+
const separator = styleText(["dim", color], this.separator);
|
|
33
26
|
this.write(`${separator}${EOL}`);
|
|
34
27
|
}
|
|
35
28
|
addNewLine() {
|
|
@@ -45,19 +38,19 @@ class Output {
|
|
|
45
38
|
getStatusIcon(taskStatus) {
|
|
46
39
|
switch (taskStatus) {
|
|
47
40
|
case "success":
|
|
48
|
-
return
|
|
41
|
+
return styleText(["green"], "\u2713");
|
|
49
42
|
case "failure":
|
|
50
|
-
return
|
|
43
|
+
return styleText(["red"], "\u2A2F");
|
|
51
44
|
case "skipped":
|
|
52
|
-
return
|
|
45
|
+
return styleText(["yellow"], "\u2212");
|
|
53
46
|
}
|
|
54
47
|
}
|
|
55
48
|
addPrefix(color, text) {
|
|
56
|
-
const namePrefix =
|
|
49
|
+
const namePrefix = styleText(["reset", "inverse", "bold", color], ` ${this.appName} `);
|
|
57
50
|
if (!this.appVersion) {
|
|
58
51
|
return `${namePrefix} ${text}`;
|
|
59
52
|
}
|
|
60
|
-
const nameAndVersionPrefix =
|
|
53
|
+
const nameAndVersionPrefix = styleText(["reset", "inverse", "bold", color], ` ${this.appName}@${this.appVersion} `);
|
|
61
54
|
return `${nameAndVersionPrefix} ${text}`;
|
|
62
55
|
}
|
|
63
56
|
writeBody(body) {
|
|
@@ -76,12 +69,12 @@ class Output {
|
|
|
76
69
|
withPrefix = true
|
|
77
70
|
}) {
|
|
78
71
|
this.addNewLine();
|
|
79
|
-
this.writeTitle("red",
|
|
72
|
+
this.writeTitle("red", styleText(["red", "bold"], title), withPrefix);
|
|
80
73
|
this.writeBody(body);
|
|
81
74
|
if (link) {
|
|
82
75
|
this.addNewLine();
|
|
83
|
-
this.write(`${
|
|
84
|
-
${
|
|
76
|
+
this.write(`${styleText(["gray"], "Learn more about this error: ")}
|
|
77
|
+
${styleText(["cyan"], link)}`);
|
|
85
78
|
}
|
|
86
79
|
this.addNewLine();
|
|
87
80
|
}
|
|
@@ -92,24 +85,24 @@ class Output {
|
|
|
92
85
|
withPrefix = true
|
|
93
86
|
}) {
|
|
94
87
|
this.addNewLine();
|
|
95
|
-
this.writeTitle("yellow",
|
|
88
|
+
this.writeTitle("yellow", styleText(["yellow", "bold"], title), withPrefix);
|
|
96
89
|
this.writeBody(body);
|
|
97
90
|
if (link) {
|
|
98
91
|
this.addNewLine();
|
|
99
|
-
this.write(`${
|
|
92
|
+
this.write(`${styleText(["gray"], "Learn more about this warning: ")}
|
|
100
93
|
${this.formatUrl(link)}`);
|
|
101
94
|
}
|
|
102
95
|
this.addNewLine();
|
|
103
96
|
}
|
|
104
97
|
success({ title, body, withPrefix = true }) {
|
|
105
98
|
this.addNewLine();
|
|
106
|
-
this.writeTitle("green",
|
|
99
|
+
this.writeTitle("green", styleText(["green", "bold"], title), withPrefix);
|
|
107
100
|
this.writeBody(body);
|
|
108
101
|
this.addNewLine();
|
|
109
102
|
}
|
|
110
103
|
log({ title, body, withPrefix = true }) {
|
|
111
104
|
this.addNewLine();
|
|
112
|
-
this.writeTitle("cyan",
|
|
105
|
+
this.writeTitle("cyan", styleText(["cyan", "bold"], title), withPrefix);
|
|
113
106
|
this.writeBody(body);
|
|
114
107
|
this.addNewLine();
|
|
115
108
|
}
|
|
@@ -124,10 +117,10 @@ class Output {
|
|
|
124
117
|
});
|
|
125
118
|
}
|
|
126
119
|
formatCode(code) {
|
|
127
|
-
return
|
|
120
|
+
return styleText(["italic", "cyan"], code);
|
|
128
121
|
}
|
|
129
122
|
formatUrl(url) {
|
|
130
|
-
return
|
|
123
|
+
return styleText(["reset", "blue", "underline"], url);
|
|
131
124
|
}
|
|
132
125
|
statusList(status, list) {
|
|
133
126
|
return list.map((item) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
2
|
import Enquirer from 'enquirer';
|
|
3
3
|
import { Output } from '../libs/output/src/index.js';
|
|
4
4
|
import { CURRENT_APP_VERSION } from './utils.version.js';
|
|
@@ -12,7 +12,7 @@ async function confirmPrompt(message) {
|
|
|
12
12
|
const question = await prompt({
|
|
13
13
|
name: "confirmPrompt",
|
|
14
14
|
type: "confirm",
|
|
15
|
-
message:
|
|
15
|
+
message: styleText(["bold"], message)
|
|
16
16
|
});
|
|
17
17
|
return question["confirmPrompt"];
|
|
18
18
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafana/create-plugin",
|
|
3
|
-
"version": "6.5.
|
|
3
|
+
"version": "6.5.2-canary.2349.20294543760.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"directory": "packages/create-plugin",
|
|
6
6
|
"url": "https://github.com/grafana/plugin-tools"
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@babel/parser": "^7.28.5",
|
|
29
29
|
"@ivanmaxlogiudice/gitignore": "^0.0.2",
|
|
30
|
-
"chalk": "^5.3.0",
|
|
31
30
|
"change-case": "^5.4.0",
|
|
32
31
|
"debug": "^4.3.4",
|
|
33
32
|
"enquirer": "^2.4.1",
|
|
@@ -44,7 +43,7 @@
|
|
|
44
43
|
"yaml": "^2.7.0"
|
|
45
44
|
},
|
|
46
45
|
"devDependencies": {
|
|
47
|
-
"@libs/output": "
|
|
46
|
+
"@libs/output": "1.0.3-canary.2349.20294543760.0",
|
|
48
47
|
"@libs/version": "^1.0.2",
|
|
49
48
|
"@types/glob": "^9.0.0",
|
|
50
49
|
"@types/minimist": "^1.2.5",
|
|
@@ -56,5 +55,5 @@
|
|
|
56
55
|
"engines": {
|
|
57
56
|
"node": ">=20"
|
|
58
57
|
},
|
|
59
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "f36c5aa7cc32e4fc4c16a6f918ff966ee4e911c5"
|
|
60
59
|
}
|
package/src/codemods/utils.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { dirname, join } from 'node:path';
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { Context } from './context.js';
|
|
4
4
|
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
|
-
import
|
|
5
|
+
import { styleText } from 'node:util';
|
|
6
6
|
import { output } from '../utils/utils.console.js';
|
|
7
7
|
import { getPackageManagerSilentInstallCmd, getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
|
|
8
8
|
import { execSync } from 'node:child_process';
|
|
@@ -15,11 +15,11 @@ export function printChanges(context: Context, key: string, description: string)
|
|
|
15
15
|
|
|
16
16
|
for (const [filePath, { changeType }] of Object.entries(changes)) {
|
|
17
17
|
if (changeType === 'add') {
|
|
18
|
-
lines.push(`${
|
|
18
|
+
lines.push(`${styleText(['green'], 'ADD')} ${filePath}`);
|
|
19
19
|
} else if (changeType === 'update') {
|
|
20
|
-
lines.push(`${
|
|
20
|
+
lines.push(`${styleText(['yellow'], 'UPDATE')} ${filePath}`);
|
|
21
21
|
} else if (changeType === 'delete') {
|
|
22
|
-
lines.push(`${
|
|
22
|
+
lines.push(`${styleText(['red'], 'DELETE')} ${filePath}`);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { machine } from 'node:os';
|
|
2
|
-
import
|
|
2
|
+
import { styleText } from 'node:util';
|
|
3
3
|
import { TemplateData } from '../../types.js';
|
|
4
4
|
import { output } from '../../utils/utils.console.js';
|
|
5
5
|
import { normalizeId } from '../../utils/utils.handlebars.js';
|
|
@@ -11,16 +11,16 @@ export function printGenerateSuccessMessage(answers: TemplateData) {
|
|
|
11
11
|
|
|
12
12
|
const commands = output.bulletList([
|
|
13
13
|
output.formatCode(`cd ./${directory}`),
|
|
14
|
-
`${output.formatCode(packageManagerName + ' install')} ${
|
|
15
|
-
`${output.formatCode(packageManagerName + ' exec playwright install chromium')} ${
|
|
16
|
-
`${output.formatCode(packageManagerName + ' run dev')} ${
|
|
14
|
+
`${output.formatCode(packageManagerName + ' install')} ${styleText(['dim'], 'to install frontend dependencies')}`,
|
|
15
|
+
`${output.formatCode(packageManagerName + ' exec playwright install chromium')} ${styleText(['dim'], 'to install e2e test dependencies')}`,
|
|
16
|
+
`${output.formatCode(packageManagerName + ' run dev')} ${styleText(['dim'], 'to build (and watch) the plugin frontend code')}`,
|
|
17
17
|
...(answers.hasBackend
|
|
18
18
|
? [
|
|
19
|
-
`${getBackendCmd()} ${
|
|
19
|
+
`${getBackendCmd()} ${styleText(['dim'], 'to build the plugin backend code. Rerun this command every time you edit your backend files')}`,
|
|
20
20
|
]
|
|
21
21
|
: []),
|
|
22
|
-
`${output.formatCode('docker compose up')} ${
|
|
23
|
-
`Open ${output.formatUrl('http://localhost:3000')} ${
|
|
22
|
+
`${output.formatCode('docker compose up')} ${styleText(['dim'], 'to start a grafana development server')}`,
|
|
23
|
+
`Open ${output.formatUrl('http://localhost:3000')} ${styleText(['dim'], 'in your browser to begin developing your plugin')}`,
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
26
|
output.log({
|
|
@@ -29,7 +29,8 @@ export function printGenerateSuccessMessage(answers: TemplateData) {
|
|
|
29
29
|
'Run the following commands to get started:',
|
|
30
30
|
...commands,
|
|
31
31
|
'',
|
|
32
|
-
|
|
32
|
+
styleText(
|
|
33
|
+
['italic'],
|
|
33
34
|
`Note: We strongly recommend creating a new Git repository by running ${output.formatCode('git init')} in ./${directory} before continuing.`
|
|
34
35
|
),
|
|
35
36
|
'',
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
2
|
import { glob } from 'glob';
|
|
3
3
|
import minimist from 'minimist';
|
|
4
4
|
import { mkdir, readdir, writeFile } from 'node:fs/promises';
|
|
@@ -26,7 +26,7 @@ export const generate = async (argv: minimist.ParsedArgs) => {
|
|
|
26
26
|
if (exportPathIsPopulated && !IS_DEV) {
|
|
27
27
|
output.error({
|
|
28
28
|
title: 'Aborting plugin scaffold.',
|
|
29
|
-
body: [`Directory ${
|
|
29
|
+
body: [`Directory ${styleText(['bold'], exportPath)} exists and contains files.`],
|
|
30
30
|
});
|
|
31
31
|
process.exit(1);
|
|
32
32
|
}
|
|
@@ -200,7 +200,7 @@ async function execPostScaffoldFunction<T>(fn: AsyncFunction<T>, ...args: Parame
|
|
|
200
200
|
try {
|
|
201
201
|
const resultMsg = await fn.apply(undefined, args);
|
|
202
202
|
if (resultMsg) {
|
|
203
|
-
console.log(`${
|
|
203
|
+
console.log(`${styleText(['green'], '✔︎')} ${resultMsg}`);
|
|
204
204
|
}
|
|
205
205
|
} catch (error) {
|
|
206
206
|
if (error instanceof Error) {
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
writePackageManagerInPackageJson,
|
|
19
19
|
} from '../utils/utils.npm.js';
|
|
20
20
|
import { getPackageManagerWithFallback } from '../utils/utils.packageManager.js';
|
|
21
|
-
import
|
|
21
|
+
import { styleText } from 'node:util';
|
|
22
22
|
|
|
23
23
|
export const migrate = async () => {
|
|
24
24
|
try {
|
|
@@ -161,7 +161,7 @@ export const migrate = async () => {
|
|
|
161
161
|
output.success({
|
|
162
162
|
title: 'Migration completed successfully.',
|
|
163
163
|
body: [
|
|
164
|
-
|
|
164
|
+
styleText(['bold'], "What's next?"),
|
|
165
165
|
...nextSteps,
|
|
166
166
|
'See instructions on how to customize your configuration here: https://grafana.com/developers/plugin-tools/how-to-guides/extend-configurations',
|
|
167
167
|
],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { styleText } from 'node:util';
|
|
2
2
|
import Enquirer from 'enquirer';
|
|
3
3
|
import { Output } from '@libs/output';
|
|
4
4
|
import { CURRENT_APP_VERSION } from './utils.version.js';
|
|
@@ -14,7 +14,7 @@ export async function confirmPrompt(message: string): Promise<boolean> {
|
|
|
14
14
|
const question: Record<string, boolean> = await prompt({
|
|
15
15
|
name: 'confirmPrompt',
|
|
16
16
|
type: 'confirm',
|
|
17
|
-
message:
|
|
17
|
+
message: styleText(['bold'], message),
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
return question['confirmPrompt'];
|
|
@@ -25,7 +25,7 @@ export async function selectPrompt(message: string, choices: string[]): Promise<
|
|
|
25
25
|
name: 'selectPrompt',
|
|
26
26
|
type: 'select',
|
|
27
27
|
choices,
|
|
28
|
-
message:
|
|
28
|
+
message: styleText(['bold'], message),
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
return question['selectPrompt'];
|