• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SAP / inquirer-gui / 22094

07 May 2025 11:13AM UTC coverage: 91.384% (-3.6%) from 95.011%
22094

push

circleci

TirottaSAP
chore: updated checkbox highlight and color

171 of 199 branches covered (85.93%)

Branch coverage included in aggregate %.

9 of 9 new or added lines in 1 file covered. (100.0%)

45 existing lines in 1 file now uncovered.

1123 of 1217 relevant lines covered (92.28%)

15.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.22
/packages/inquirer-gui/src/Form.vue
1
<template>
1✔
2
  <v-form class="inquirer-gui">
1✔
3
    <template v-for="(question, index) in questions" :key="question.name">
1✔
4
      <p :key="'label-' + index" class="question-label" v-if="question.shouldShow">
1✔
5
        <span class="question-message">{{ question._message }}</span>
1✔
6
        <span class="question-hint" v-if="question.guiOptions && question.guiOptions.hint">
1✔
7
          <v-tooltip location="top" max-width="350px">
1✔
8
            <template v-slot:activator="{ props }">
1✔
9
              <v-icon v-bind="props">mdi-help-circle-outline</v-icon>
1✔
10
            </template>
1✔
11
            <span>{{ question.guiOptions.hint }}</span>
1✔
12
          </v-tooltip>
1✔
13
        </span>
1✔
14
        <span class="mandatory-asterisk" v-if="question.isMandatory">*</span>
1✔
15
        <span class="question-link" v-if="question.guiOptions && question.guiOptions.link">
1✔
16
          <a
1✔
17
            v-if="question.guiOptions.link.command"
1✔
18
            :command="question.guiOptions.link.command.id"
1✔
19
            :params="question.guiOptions.link.command.params"
1✔
20
            @click="executeCommand"
1✔
21
            >{{ question.guiOptions.link.text }}</a
1✔
22
          >
1✔
23
          <a v-else-if="question.guiOptions.link.url" target="_blank" :href="question.guiOptions.link.url">{{
1✔
24
            question.guiOptions.link.text
1✔
25
          }}</a>
1✔
26
        </span>
1✔
27
      </p>
1✔
28
      <component
1✔
29
        v-if="question.shouldShow"
1✔
30
        :is="getComponentByQuestionType(question)"
1✔
31
        :key="index"
1✔
32
        :question="question"
1✔
33
        :answers="getAnswers()"
1✔
34
        @answerChanged="onAnswerChanged"
1✔
35
        @customEvent="onCustomEvent"
1✔
36
        @setBusyIndicator="setBusyIndicator"
1✔
37
      ></component>
1✔
38
      <div
1✔
39
        v-if="shouldShowValidationMessage(question)"
1✔
40
        class="validation-messages"
1✔
41
        :key="'validation-' + index"
1✔
42
        :id="'validation-msg-' + index"
1✔
43
      >
1✔
44
        <span class="error-validation-text">{{ question.validationMessage }}</span>
1✔
45
        <span class="question-link" v-if="question.validationLink">
1✔
46
          <a v-if="question.validationLink.command" @click="executeCommand(question.validationLink.command)">
1✔
47
            <img
1✔
48
              class="validation-link-icon"
1✔
49
              v-if="question.validationLink.icon"
1✔
50
              :src="question.validationLink.icon"
1✔
51
            /><span v-text="question.validationLink.text" id="cmdLinkText"></span>
1✔
52
          </a>
1✔
53
          <a v-else-if="question.validationLink.url" target="_blank" :href="question.validationLink.url">
1✔
54
            <img
1✔
55
              class="validation-link-icon"
1✔
56
              v-if="question.validationLink.icon"
1✔
57
              :src="question.validationLink.icon"
1✔
58
            /><span v-text="question.validationLink.text" id="urlLinkText"></span>
1✔
59
          </a>
1✔
60
        </span>
1✔
61
      </div>
1✔
62
      <div
1✔
63
        v-else-if="shouldShowAdditionalMessages(question)"
1✔
64
        class="add-messages"
1✔
65
        :key="'additional-msg-' + index"
1✔
66
        :id="'add-msg-' + index"
1✔
67
      >
1✔
68
        <v-icon class="messages-icon" :class="severityMessageClass(question._additionalMessages.severity)"
1✔
69
          >mdi-{{ severityIcon(question._additionalMessages.severity) }}</v-icon
1✔
70
        ><span class="messages-text" :class="severityMessageClass(question._additionalMessages.severity)">{{
1✔
71
          question._additionalMessages.message
1✔
72
        }}</span>
1✔
73
      </div>
1✔
74
    </template>
1✔
75
    <vscode-textfield id="form-single-input-issue-key-enter-workaround" style="display: none"></vscode-textfield>
1✔
76
  </v-form>
1✔
77
</template>
1✔
78

1✔
79
<script>
1✔
80
import { markRaw } from "vue";
1✔
81
import Plugins from "./Plugins";
1✔
82
import isEqual from "lodash/isEqual";
1✔
83

1✔
84
const NOT_ANSWERED = "Mandatory field";
1✔
85
const MANDATORY_TYPES = ["list", "rawlist", "expand", "autocomplete"];
1✔
86
const Severity = {
1✔
87
  error: 0,
1✔
88
  warning: 1,
1✔
89
  information: 2,
1✔
90
};
1✔
91

1✔
92
export default {
1✔
93
  // eslint-disable-next-line vue/multi-word-component-names, vue/no-reserved-component-names
1✔
94
  name: "Form",
1✔
95
  props: {
1✔
96
    questions: Array,
1✔
97
  },
1✔
98
  data() {
1✔
99
    return {
40✔
100
      plugins: null,
40✔
101
      severityClass: {
40✔
102
        [Severity.warning]: "severity-warn",
40✔
103
        [Severity.information]: "severity-info",
40✔
104
        [Severity.error]: "severity-error",
40✔
105
      },
40✔
106
      severityIconName: {
40✔
107
        [Severity.warning]: "alert-outline",
40✔
108
        [Severity.information]: "information-outline",
40✔
109
        [Severity.error]: "close-circle-outline",
40✔
110
      },
40✔
111
    };
40✔
112
  },
1✔
113
  computed: {
1✔
114
    console: () => console,
1✔
115
  },
1✔
116
  methods: {
1✔
117
    severityMessageClass(severity) {
1✔
118
      return this.severityClass[severity];
14✔
119
    },
1✔
120
    severityIcon(severity) {
1✔
121
      return this.severityIconName[severity];
7✔
122
    },
1✔
123
    setBusyIndicator(isBusy) {
1✔
124
      this.$emit("setBusyIndicator", isBusy);
×
125
    },
1✔
126
    // Execute a command embedded in an event or directly as { id: <commandIdString>, params: <paramObject> }
1✔
127
    executeCommand(cmdOrEvent) {
1✔
128
      this.$emit("parentExecuteCommand", cmdOrEvent);
×
129
    },
1✔
130
    shouldShowAdditionalMessages(question) {
1✔
131
      return question.shouldShow && question._additionalMessages && question._additionalMessages.message;
125✔
132
    },
1✔
133
    shouldShowValidationMessage(question) {
1✔
134
      return (
133✔
135
        question.shouldShow &&
133✔
136
        !question.isValid &&
133✔
137
        (question.__origAnswer !== undefined || !(question.guiOptions && question.guiOptions.hint && !question.isDirty))
10✔
138
      );
133✔
139
    },
1✔
140
    removeShouldntShows(questions, answers) {
1✔
141
      for (let question of this.questions) {
75✔
142
        // remove answers to questions whose when() evaluated to false
122✔
143
        if (!question.shouldShow) {
122✔
144
          delete answers[question.name];
6✔
145
        }
6✔
146
      }
122✔
147
    },
1✔
148
    async doValidate(question, answer) {
1✔
149
      // evaluate validate()
102✔
150
      try {
102✔
151
        if (typeof question.validate === "function") {
102✔
152
          const answers = this.getAnswers();
48✔
153
          const response = await question.validate(answer, answers);
48✔
154
          if (response === true) {
48✔
155
            this.setValid(question);
39✔
156
          } else if (response === false) {
48!
157
            this.setInvalid(question);
×
158
          } else if (
9✔
159
            // eslint-disable-next-line no-prototype-builtins
9✔
160
            response?.hasOwnProperty("link") &&
9✔
161
            // eslint-disable-next-line no-prototype-builtins
4✔
162
            response.hasOwnProperty("message")
4✔
163
          ) {
9✔
164
            // Validation messages with links
4✔
165
            this.setInvalidWithLink(question, response);
4✔
166
          } else if (response) {
9✔
167
            this.setInvalid(question, response);
5✔
168
          } else {
5!
169
            this.setValid(question);
×
170
          }
×
171
        } else if (MANDATORY_TYPES.includes(question.type) && answer === undefined) {
102!
UNCOV
172
          this.setInvalid(question);
×
173
        } else {
54✔
174
          this.setValid(question);
54✔
175
        }
54✔
176
      } catch (e) {
102!
177
        const errorMessage = `Could not evaluate validate() for ${question.name}. ${e.message}`;
×
178
        this.console.error(errorMessage);
×
179
        this.setInvalid(question, errorMessage);
×
180
      }
×
181
    },
1✔
182
    setInvalidWithLink(question, linkMsg = { message: "", link: {} }) {
1✔
183
      question.isValid = false;
4✔
184
      question.validationMessage = linkMsg.message;
4✔
185
      question.validationLink = linkMsg.link;
4✔
186
    },
1✔
187
    setInvalid(question, message = NOT_ANSWERED) {
1✔
188
      question.isValid = false;
5✔
189
      question.validationLink = undefined; // Ensure existing validation link is removed
5✔
190
      question.validationMessage = message;
5✔
191
    },
1✔
192
    setValid(question) {
1✔
193
      question.isValid = true;
93✔
194
      question.validationMessage = "";
93✔
195
    },
1✔
196
    setIsMandatory(question) {
1✔
197
      question.isMandatory =
50✔
198
        MANDATORY_TYPES.includes(question.type) ||
50✔
199
        (question.guiOptions && question.guiOptions.mandatory === true && typeof question.validate === "function");
50!
200
    },
1✔
201
    getComponentByQuestionType(question) {
1✔
202
      const guiType = question.guiOptions && question.guiOptions.type ? question.guiOptions.type : question.guiType;
125✔
203
      let foundPlugin;
125✔
204
      if (guiType) {
125✔
205
        foundPlugin = this.plugins.find((plugin) => {
1✔
206
          return plugin.questionType === guiType;
1✔
207
        });
1✔
208
        if (foundPlugin) {
1✔
209
          return foundPlugin.component;
1✔
210
        }
1✔
211
      }
1✔
212
      foundPlugin = this.plugins.find((plugin) => {
124✔
213
        return plugin.questionType === question.type;
132✔
214
      });
124✔
215
      if (foundPlugin) {
124✔
216
        return foundPlugin.component;
124✔
217
      }
124✔
218
    },
1✔
219
    registerPlugin(plugin) {
1✔
220
      this.plugins.push(markRaw(plugin));
1✔
221
    },
1✔
222
    getAnswers() {
1✔
223
      let result = {};
247✔
224
      for (let question of this.questions) {
247✔
225
        result[question.name] = question.answer;
448✔
226
      }
448✔
227
      return result;
247✔
228
    },
1✔
229
    getIssues() {
1✔
230
      let someInvalid = false;
76✔
231
      let result = {};
76✔
232
      for (let question of this.questions) {
76✔
233
        if (question.shouldShow && !question.isValid) {
124✔
234
          if (question.validationMessage === "") {
11!
235
            result[question.name] = "Invalid";
×
236
            someInvalid = true;
×
237
          } else {
11✔
238
            result[question.name] = question.validationMessage;
11✔
239
            someInvalid = true;
11✔
240
          }
11✔
241
        } else if (question.shouldShow && question.answer === undefined) {
124!
UNCOV
242
          result[question.name] = NOT_ANSWERED;
×
UNCOV
243
          someInvalid = true;
×
UNCOV
244
        }
×
245
      }
124✔
246
      return someInvalid ? result : undefined;
76✔
247
    },
1✔
248
    normalizeChoices(choices) {
1✔
249
      if (Array.isArray(choices)) {
13✔
250
        const mappedChoices = choices.map((value) => {
12✔
251
          if (value === undefined || typeof value === "string" || typeof value === "number") {
43✔
252
            return { name: value, value: value };
37✔
253
          } else {
43✔
254
            if (
6✔
255
              // eslint-disable-next-line no-prototype-builtins
6✔
256
              value.hasOwnProperty("name") &&
6✔
257
              // eslint-disable-next-line no-prototype-builtins
4✔
258
              !value.hasOwnProperty("value")
4✔
259
            ) {
6✔
260
              return { name: value.name, value: value.name };
4✔
261
            }
4✔
262
          }
6✔
263
          return value;
2✔
264
        });
12✔
265
        return mappedChoices;
12✔
266
      }
12✔
267
    },
1✔
268
    getInitialAnswer(question) {
1✔
269
      let answer;
85✔
270
      switch (question.type) {
85✔
271
        case "input":
85✔
272
        case "password":
85✔
273
        case "editor":
85✔
274
          answer = question._default;
64✔
275
          if (answer === undefined) {
64✔
276
            answer = "";
26✔
277
          }
26✔
278
          return answer;
64✔
279
        case "number":
85✔
280
          answer = question._default;
4✔
281
          if (answer === undefined) {
4✔
282
            answer = 0;
1✔
283
          }
1✔
284
          return answer;
4✔
285
        case "confirm":
85✔
286
          answer = question._default;
3✔
287
          if (answer !== false) {
3✔
288
            answer = true;
2✔
289
          }
2✔
290
          return answer;
3✔
291
        case "list":
85✔
292
        case "rawlist":
85✔
293
        case "expand":
85✔
294
        case "checkbox":
85✔
295
          if (!Array.isArray(question._choices)) {
12✔
296
            this.setInvalid(question);
1✔
297
            return;
1✔
298
          }
1✔
299
          // handle complex choice cases below
11✔
300
          break;
11✔
301
        default:
85✔
302
          if (question._default === undefined) {
2✔
303
            this.setInvalid(question);
1✔
304
          }
1✔
305
          return question._default;
2✔
306
      }
85✔
307

11✔
308
      // handle complex choice cases
11✔
309
      let index = -1;
11✔
310
      switch (question.type) {
11✔
311
        case "list":
85✔
312
        case "rawlist":
85✔
313
          if (question._choices.length === 0 || question._default === undefined) {
4✔
314
            this.setInvalid(question);
1✔
315
            return;
1✔
316
          }
1✔
317
          if (typeof question._default === "number") {
4✔
318
            index = question._default;
2✔
319
            if (index > question._choices.length - 1) {
2✔
320
              index = -1;
1✔
321
            }
1✔
322
          }
2✔
323
          if (index < 0) {
4✔
324
            index = question._choices.findIndex((choice) => {
2✔
325
              if (question._default) {
3✔
326
                return isEqual(choice.value, question._default);
3✔
327
              }
3✔
328
            });
2✔
329
          }
2✔
330
          if (index < 0 || index > question._choices.length - 1) {
4✔
331
            this.setInvalid(question);
1✔
332
            return;
1✔
333
          } else {
4✔
334
            return question._choices[index].value;
2✔
335
          }
2✔
336
        case "expand":
85✔
337
          if (question._choices.length === 0) {
3!
UNCOV
338
            this.setInvalid(question);
×
UNCOV
339
            return;
×
UNCOV
340
          }
×
341
          if (typeof question._default === "number") {
3✔
342
            index = question._default;
2✔
343
          } else {
3✔
344
            index = question._choices.findIndex(function (choice) {
1✔
345
              if (question._default) {
1✔
346
                return choice.value === question._default;
1✔
347
              }
1✔
348
            });
1✔
349
          }
1✔
350
          if (index < 0 || index > question._choices.length - 1) {
3✔
351
            this.setInvalid(question);
1✔
352
            return;
1✔
353
          } else {
3✔
354
            return question._choices[index].value;
2✔
355
          }
2✔
356
        case "checkbox": {
85✔
357
          const initialAnswersArray = [];
4✔
358
          for (let choice of question._choices) {
4✔
359
            let wasPushed = false;
8✔
360

8✔
361
            // add to answers if choice is in default
8✔
362
            if (Array.isArray(question._default)) {
8✔
363
              let foundIndex = question._default.findIndex((currentDefaultValue) => {
6✔
364
                return choice.value === currentDefaultValue;
4✔
365
              });
6✔
366
              if (foundIndex >= 0) {
6✔
367
                initialAnswersArray.push(choice.value);
2✔
368
                wasPushed = true;
2✔
369
              }
2✔
370
            }
6✔
371

8✔
372
            // add to answers if choice is marked as checked
8✔
373
            if (choice.checked === true && !(question.__ForceDefault === true) && !wasPushed) {
8✔
374
              initialAnswersArray.push(choice.value);
3✔
375
            }
3✔
376
          }
8✔
377

4✔
378
          return initialAnswersArray;
4✔
379
        }
4✔
380
      }
85✔
381
    },
1✔
382
    async onCustomEvent(questionName, methodName, callback, ...params) {
1✔
383
      const relevantQuestion = this.questions.find((value) => {
2✔
384
        return value["name"] === questionName;
2✔
385
      });
2✔
386

2✔
387
      if (typeof relevantQuestion[methodName] === "function") {
2✔
388
        try {
2✔
389
          let response = await relevantQuestion[methodName](...params);
2✔
390
          if (callback) {
1✔
391
            callback(response);
1✔
392
          }
1✔
393
        } catch (e) {
2✔
394
          this.console.error(`Could not evaluate ${methodName}() for ${relevantQuestion.name}`);
1✔
395
        }
1✔
396
      }
2✔
397
    },
1✔
398

1✔
399
    async updateAdditionalMessages(question, answers, questionIndex) {
1✔
400
      if (typeof question.additionalMessages === "function") {
48✔
401
        try {
10✔
402
          question._additionalMessages = await question.additionalMessages(question.answer, answers);
10✔
403
          // Vue 2 requires a new object for reactivity to trigger updates
10✔
404
          this.questions.splice(questionIndex, 1, Object.assign({}, question));
10✔
405
        } catch (e) {
10!
406
          this.console.error(`Could not evaluate additionalMessages() for ${question.name}`);
×
407
        }
×
408
      }
10✔
409
    },
1✔
410
    async onAnswerChanged(name, answer) {
1✔
411
      if (answer === undefined) {
38!
UNCOV
412
        // we regard undefined as unanswered, so we do not
×
UNCOV
413
        // call question methods or emit the answered event
×
UNCOV
414
        return;
×
UNCOV
415
      }
×
416
      const index = this.questions.findIndex((question) => {
38✔
417
        return question["name"] === name;
52✔
418
      });
38✔
419

38✔
420
      if (index === -1) {
38!
421
        return;
×
422
      }
×
423

38✔
424
      const answeredQuestion = this.questions[index];
38✔
425
      answeredQuestion.isDirty = true;
38✔
426

38✔
427
      // TODO: if input is invalid, should we update the answer?
38✔
428
      // set the answer
38✔
429
      answeredQuestion.answer = answer;
38✔
430
      await this.doValidate(answeredQuestion, answer);
38✔
431

38✔
432
      const answers = this.getAnswers();
38✔
433

38✔
434
      // More messages (info/warn) should only be shown when the input is valid
38✔
435
      if (answeredQuestion.isValid) {
38✔
436
        this.updateAdditionalMessages(answeredQuestion, answers, index);
32✔
437
      }
32✔
438

38✔
439
      // evaluate methods for other questions following answered question (e.g. when)
38✔
440
      let shouldStart = false;
38✔
441
      const whenPromises = [];
38✔
442
      let questionIndex = 0;
38✔
443
      for (let question of this.questions) {
38✔
444
        if (question.name === answeredQuestion.name) {
72✔
445
          shouldStart = true;
38✔
446
        } else if (shouldStart) {
72✔
447
          let shouldValidate = false;
20✔
448
          // evaluate when()
20✔
449
          if (typeof question.when === "function") {
20✔
450
            try {
2✔
451
              const whenPromise = question.when(answers);
2✔
452
              whenPromises.push(whenPromise);
2✔
453
              let response = await whenPromise;
2✔
454
              // When question shouldShow === true call validate()
2✔
455
              if (response) {
2!
UNCOV
456
                shouldValidate = true;
×
UNCOV
457
              }
×
458
              question.shouldShow = response;
2✔
459
            } catch (e) {
2!
460
              this.console.error(`Could not evaluate when() for ${question.name}`);
×
461
            }
×
462
          } else if (question.when !== false) {
20✔
463
            question.shouldShow = true;
16✔
464
            shouldValidate = true;
16✔
465
          }
16✔
466
          if (question.shouldShow) {
20✔
467
            // evaluate message()
16✔
468
            if (typeof question.message === "function") {
16✔
469
              try {
2✔
470
                let response = await question.message(answers);
2✔
471
                question._message = response;
2✔
472
              } catch (e) {
2!
473
                this.console.error(`Could not evaluate message() for ${question.name}`);
×
474
              }
×
475
            }
2✔
476

16✔
477
            // evaluate choices()
16✔
478
            if (typeof question.choices === "function") {
16!
UNCOV
479
              try {
×
UNCOV
480
                const response = await question.choices(answers);
×
UNCOV
481
                question._choices = this.normalizeChoices(response);
×
UNCOV
482
                if (!question.isDirty) {
×
UNCOV
483
                  question.answer = this.getInitialAnswer(question);
×
UNCOV
484
                  // optimization: avoid repeatedly calling this.getAnswers()
×
UNCOV
485
                  answers[question.name] = question.answer;
×
UNCOV
486
                  shouldValidate = true;
×
UNCOV
487
                }
×
UNCOV
488
              } catch (e) {
×
489
                this.console.error(`Could not evaluate choices() for ${question.name}`);
×
490
              }
×
UNCOV
491
            }
×
492

16✔
493
            // evaluate default()
16✔
494
            const applyDefaultWhenDirty =
16✔
495
              !question.isDirty || (question.guiOptions && question.guiOptions.applyDefaultWhenDirty);
16✔
496
            if (applyDefaultWhenDirty) {
16✔
497
              if (typeof question.default === "function") {
12✔
498
                try {
6✔
499
                  question._default = await question.default(answers);
6✔
500
                } catch (e) {
6!
501
                  this.console.error(`Could not evaluate default() for ${question.name}`);
×
502
                }
×
503
              } else {
6✔
504
                question._default = question.default;
6✔
505
              }
6✔
506
              question.answer = this.getInitialAnswer(question);
12✔
507
              // optimization: avoid repeatedly calling this.getAnswers()
12✔
508
              answers[question.name] = question.answer;
12✔
509
              shouldValidate = true;
12✔
510
            }
12✔
511

16✔
512
            if (shouldValidate) {
16✔
513
              await this.doValidate(question, question.answer);
16✔
514
            }
16✔
515
            // evaluate additionalMessages
16✔
516
            if (question.isValid) {
16✔
517
              this.updateAdditionalMessages(question, answers, questionIndex);
16✔
518
            }
16✔
519
          }
16✔
520
        }
20✔
521
        questionIndex++;
72✔
522
      }
72✔
523

38✔
524
      // apply filters
38✔
525
      let filteredAnswers = {};
38✔
526
      Object.assign(filteredAnswers, answers);
38✔
527
      for (let question of this.questions) {
38✔
528
        if (question.filter) {
72!
UNCOV
529
          // call filter()
×
UNCOV
530
          const currentAnswer = answers[question.name];
×
UNCOV
531
          try {
×
UNCOV
532
            const filteredAnswer = await question.filter(currentAnswer);
×
UNCOV
533
            filteredAnswers[question.name] = filteredAnswer;
×
UNCOV
534
          } catch (e) {
×
535
            this.console.error(`Could not evaluate filter() for ${question.name}`);
×
536
          }
×
UNCOV
537
        }
×
538
      }
72✔
539

38✔
540
      Promise.all(whenPromises).then(() => {
38✔
541
        this.$emit("whensEvaluated");
38✔
542
      });
38✔
543

38✔
544
      const issues = this.getIssues();
38✔
545
      this.removeShouldntShows(this.questions, filteredAnswers);
38✔
546
      // fire 'answered' event
38✔
547
      this.$emit("answered", filteredAnswers, issues);
38✔
548
    },
38✔
549
  },
1✔
550
  watch: {
1✔
551
    questions: async function (newVal, oldVal) {
1✔
552
      if (newVal === oldVal) {
37!
553
        return;
×
554
      }
×
555

37✔
556
      // 1st pass: set initial values
37✔
557
      for (let question of this.questions) {
37✔
558
        // question type
50✔
559
        if (!question.type) {
50!
560
          question.type = "input";
×
561
        }
×
562

50✔
563
        // message
50✔
564
        const message = typeof question.message === "string" ? question.message : question.name;
50✔
565
        question["_message"] = message;
50✔
566

50✔
567
        // choices
50✔
568
        if (question.choices) {
50!
UNCOV
569
          let choices = [];
×
UNCOV
570
          if (typeof question.choices !== "function") {
×
UNCOV
571
            choices = this.normalizeChoices(question.choices);
×
UNCOV
572
          }
×
UNCOV
573
          question["_choices"] = choices;
×
UNCOV
574
        }
×
575

50✔
576
        // default
50✔
577
        if (question.default !== undefined) {
50✔
578
          let _default;
34✔
579
          if (typeof question.default !== "function") {
34✔
580
            if (question.__origAnswer === undefined) {
31✔
581
              _default = question.default;
31✔
582
            } else {
31!
583
              _default = question.__origAnswer;
×
584
            }
×
585
          }
31✔
586
          question["_default"] = _default;
34✔
587
        } else if (question._default === undefined) {
50✔
588
          question["_default"] = question.__origAnswer;
16✔
589
        }
16✔
590

50✔
591
        // validity
50✔
592
        question["isValid"] = true;
50✔
593
        question["validationMessage"] = "";
50✔
594

50✔
595
        // mandatory
50✔
596
        this.setIsMandatory(question);
50✔
597

50✔
598
        // dirty
50✔
599
        question["isDirty"] = question.__origAnswer !== undefined;
50✔
600

50✔
601
        // answer
50✔
602
        let answer = this.getInitialAnswer(question);
50✔
603
        question["answer"] = answer;
50✔
604

50✔
605
        // visibility
50✔
606
        const shouldShow = question.when === false || typeof question.when === "function" ? false : true;
50✔
607
        question["shouldShow"] = shouldShow;
50✔
608
      }
50✔
609

37✔
610
      const answers = this.getAnswers();
37✔
611
      // 2nd pass: evaluate properties that are functions
37✔
612
      const whenPromises = [];
37✔
613
      let questionIndex = 0;
37✔
614
      for (let question of this.questions) {
37✔
615
        // evaluate when()
50✔
616
        if (typeof question.when === "function") {
50✔
617
          try {
2✔
618
            const whenPromise = question.when(answers);
2✔
619
            whenPromises.push(whenPromise);
2✔
620
            let response = await whenPromise;
2✔
621
            question.shouldShow = response;
2✔
622
          } catch (e) {
2!
623
            this.console.error(`Could not evaluate when() for ${question.name}`);
×
624
          }
×
625
        }
2✔
626

50✔
627
        if (question.shouldShow) {
50✔
628
          // evaluate message()
48✔
629
          if (typeof question.message === "function") {
48✔
630
            try {
1✔
631
              const response = await question.message(answers);
1✔
632
              question._message = response;
1✔
633
            } catch (e) {
1!
634
              this.console.error(`Could not evaluate message() for ${question.name}`);
×
635
            }
×
636
          }
1✔
637

48✔
638
          // evaluate choices()
48✔
639
          if (typeof question.choices === "function") {
48!
UNCOV
640
            try {
×
UNCOV
641
              const response = await question.choices(answers);
×
UNCOV
642
              question._choices = this.normalizeChoices(response);
×
UNCOV
643
              question.answer = this.getInitialAnswer(question);
×
UNCOV
644
              // optimization: avoid repeatedly calling this.getAnswers()
×
UNCOV
645
              answers[question.name] = question.answer;
×
UNCOV
646
            } catch (e) {
×
647
              this.console.error(`Could not evaluate choices() for ${question.name}`);
×
648
            }
×
UNCOV
649
          }
×
650

48✔
651
          // evaluate default()
48✔
652
          if (typeof question.default === "function") {
48✔
653
            try {
3✔
654
              if (question.__origAnswer === undefined) {
3✔
655
                question._default = await question.default(answers);
3✔
656
              } else {
3!
657
                question._default = question.__origAnswer;
×
658
              }
✔
659
              question.answer = this.getInitialAnswer(question);
2✔
660

2✔
661
              // optimization: avoid repeatedly calling this.getAnswers()
2✔
662
              answers[question.name] = question.answer;
2✔
663
            } catch (e) {
3✔
664
              this.console.error(`Could not evaluate default() for ${question.name}`);
1✔
665
            }
1✔
666
          }
3✔
667

48✔
668
          // evaluate validate()
48✔
669
          await this.doValidate(question, question.answer);
48✔
670
          // evaluate additionalMessages()
48✔
671
          if (typeof question.additionalMessages === "function" && question.isValid) {
48!
672
            this.updateAdditionalMessages(question, answers, questionIndex);
×
673
          }
×
674
        }
48✔
675
        questionIndex++;
50✔
676
      }
50✔
677

37✔
678
      Promise.all(whenPromises).then(() => {
37✔
679
        this.$emit("whensEvaluated");
37✔
680
      });
37✔
681

37✔
682
      const issues = this.getIssues();
37✔
683
      this.removeShouldntShows(this.questions, answers);
37✔
684
      // fire 'answered' event
37✔
685
      this.$emit("answered", answers, issues);
37✔
686
    },
37✔
687
  },
1✔
688
  created() {
1✔
689
    this.plugins = markRaw(Plugins.registerBuiltinPlugins());
40✔
690
  },
40✔
691
};
1✔
692
</script>
1✔
693

1✔
694
<style lang="scss">
1✔
695
$color-error: var(--vscode-notificationsErrorIcon-foreground, #f14c4c);
1✔
696
$color-warn: var(--vscode-notificationsWarningIcon-foreground, #cca700);
1✔
697
$color-info: var(--vscode-notificationsInfoIcon-foreground, #3794ff);
1✔
698

1✔
699
a {
1✔
700
  color: var(--vscode-textLink-foreground, #1976d2);
1✔
701
  cursor: pointer;
1✔
702
}
1✔
703

1✔
704
.inquirer-gui p.question-label {
1✔
705
  margin-top: 0.6rem;
1✔
706
  margin-bottom: 0.05rem;
1✔
707
}
1✔
708

1✔
709
.inquirer-gui .v-text-field div.v-text-field__details {
1✔
710
  margin-bottom: 2px;
1✔
711
}
1✔
712

1✔
713
.inquirer-gui .v-text-field input {
1✔
714
  padding: 0px;
1✔
715
}
1✔
716

1✔
717
.inquirer-gui .v-input--selection-controls {
1✔
718
  margin-top: 0rem;
1✔
719
}
1✔
720

1✔
721
/* mandatory asterisk div */
1✔
722
.mandatory-asterisk {
1✔
723
  padding-left: 4px;
1✔
724
}
1✔
725

1✔
726
/* Question hint div, Question link div */
1✔
727
.question-hint,
1✔
728
.question-link {
1✔
729
  padding-left: 4px;
1✔
730
}
1✔
731

1✔
732
/* Error validation text div */
1✔
733
.error-validation-text {
1✔
734
  @extend .messages-text;
1✔
735
  @extend .severity-error;
1✔
736
}
1✔
737

1✔
738
/* Question valdation message with link icon img */
1✔
739
.validation-link-icon {
1✔
740
  vertical-align: middle;
1✔
741
  padding-right: 5px;
1✔
742
}
1✔
743

1✔
744
.add-messages,
1✔
745
.validation-messages {
1✔
746
  padding-top: 4px;
1✔
747
  display: flex;
1✔
748
  align-items: flex-start;
1✔
749
  /* Icons that appear adjacent to message texts */
1✔
750
  .messages-icon.v-icon {
1✔
751
    font-size: 20px;
1✔
752
    padding-right: 4px;
1✔
753
    &.severity-error {
1✔
754
      color: #{$color-error};
1✔
755
    }
1✔
756
    &.severity-warn {
1✔
757
      color: #{$color-warn};
1✔
758
    }
1✔
759
    &.severity-info {
1✔
760
      color: #{$color-info};
1✔
761
    }
1✔
762
  }
1✔
763

1✔
764
  /* Messages that appear under prompts - validation (error), info and warning */
1✔
765
  .messages-text {
1✔
766
    font-size: 12px;
1✔
767
    text-overflow: ellipsis;
1✔
768
    overflow: hidden;
1✔
769
    display: -webkit-box;
1✔
770
    -webkit-line-clamp: 2;
1✔
771
    -webkit-box-orient: vertical;
1✔
772
    line-break: normal;
1✔
773
    padding-top: 0.083em; // 1px at font-size 12px
1✔
774

1✔
775
    &.severity-error {
1✔
776
      color: #{$color-error};
1✔
777
    }
1✔
778
    &.severity-warn {
1✔
779
      color: #{$color-warn};
1✔
780
    }
1✔
781
    &.severity-info {
1✔
782
      color: var(--vscode-foreground);
1✔
783
    }
1✔
784
  }
1✔
785
}
1✔
786
</style>
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc