Skip to content

Commit dbef5e9

Browse files
authored
feat(ui): config improvements (#1487)
BREAKING CHANGES: - The configuration API has changed. - The `files` options now accept an object of different config files: ```js api.describeConfig({ /* ... */ // All possible files for this config files: { // eslintrc.js eslint: { js: ['.eslintrc.js'], json: ['.eslintrc', '.eslintrc.json'], // Will read from `package.json` package: 'eslintConfig' }, // vue.config.js vue: { js: ['vue.config.js'] } }, }) ``` - The `onWrite` api has changed: `setData` and `assignData` have now `fileId` as the first argument: ```js api.describeConfig({ onWrite: async ({ api, prompts }) => { const eslintData = {} const vueData = {} for (const prompt of prompts) { // eslintrc if (prompt.id.indexOf('vue/') === 0) { eslintData[`rules.${prompt.id}`] = await api.getAnswer(prompt.id, JSON.parse) } else { // vue.config.js vueData[prompt.id] = await api.getAnswer(prompt.id) } } api.setData('eslint', eslintData) api.setData('vue', vueData) } }) ``` Other changes - Config tabs (optional): ```js api.describeConfig({ /* ... */ onRead: ({ data, cwd }) => ({ tabs: [ { id: 'tab1', label: 'My tab', // Optional icon: 'application_settings', prompts: [ // Prompt objects ] }, { id: 'tab2', label: 'My other tab', prompts: [ // Prompt objects ] } ] }) }) ```
1 parent e258f5a commit dbef5e9

File tree

15 files changed

+619
-329
lines changed

15 files changed

+619
-329
lines changed

docs/dev-guide/ui-plugin-dev.md

Lines changed: 139 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ api.describeConfig({
107107

108108
If you don't specify an icon, the plugin logo will be displayed if any (see [Logo](#logo)).
109109

110-
#### Config file
110+
#### Config files
111111

112-
By default, a configuration UI might read and write to a configuration file, for example `.eslintrc.js`.
112+
By default, a configuration UI might read and write to one or more configuration files, for example both `.eslintrc.js` and `vue.config.js`.
113113

114114
You can provide what are the possible files to be detected in the user project:
115115

@@ -118,17 +118,22 @@ api.describeConfig({
118118
/* ... */
119119
// All possible files for this config
120120
files: {
121-
json: ['.eslintrc', '.eslintrc.json'],
122-
js: ['.eslintrc.js'],
123-
// Will read from `package.json`
124-
package: 'eslintConfig'
121+
// eslintrc.js
122+
eslint: {
123+
js: ['.eslintrc.js'],
124+
json: ['.eslintrc', '.eslintrc.json'],
125+
// Will read from `package.json`
126+
package: 'eslintConfig'
127+
},
128+
// vue.config.js
129+
vue: {
130+
js: ['vue.config.js']
131+
}
125132
},
126133
})
127134
```
128135

129-
Supported types: `json`, `yaml`, `js`, `package`.
130-
131-
**⚠️ Currently, only 1 file can be read and written to at a time.**
136+
Supported types: `json`, `yaml`, `js`, `package`. The order is important: the first filename in the list will be used to create the config file if it doesn't exist.
132137

133138
#### Display config prompts
134139

@@ -149,14 +154,132 @@ Those prompts will be displayed in the configuration details pane.
149154

150155
See [Prompts](#prompts) for more info.
151156

157+
The `data` object contains the JSON result of each config file content.
158+
159+
For example, let's say the user has the following `vue.config.js` in his project:
160+
161+
```js
162+
module.exports = {
163+
lintOnSave: false
164+
}
165+
```
166+
167+
We declare the config file in our plugin like this:
168+
169+
```js
170+
api.describeConfig({
171+
/* ... */
172+
// All possible files for this config
173+
files: {
174+
// vue.config.js
175+
vue: {
176+
js: ['vue.config.js']
177+
}
178+
},
179+
})
180+
```
181+
182+
Then the `data` object will be:
183+
184+
```js
185+
{
186+
// File
187+
vue: {
188+
// File data
189+
lintOnSave: false
190+
}
191+
}
192+
```
193+
194+
Multiple files example: if we add the following `eslintrc.js` file in the user project:
195+
196+
```js
197+
module.exports = {
198+
root: true,
199+
extends: [
200+
'plugin:vue/essential',
201+
'@vue/standard'
202+
]
203+
}
204+
```
205+
206+
And change the `files` option in our plugin to this:
207+
208+
```js
209+
api.describeConfig({
210+
/* ... */
211+
// All possible files for this config
212+
files: {
213+
// eslintrc.js
214+
eslint: {
215+
js: ['.eslintrc.js'],
216+
json: ['.eslintrc', '.eslintrc.json'],
217+
// Will read from `package.json`
218+
package: 'eslintConfig'
219+
},
220+
// vue.config.js
221+
vue: {
222+
js: ['vue.config.js']
223+
}
224+
},
225+
})
226+
```
227+
228+
Then the `data` object will be:
229+
230+
```js
231+
{
232+
eslint: {
233+
root: true,
234+
extends: [
235+
'plugin:vue/essential',
236+
'@vue/standard'
237+
]
238+
},
239+
vue: {
240+
lintOnSave: false
241+
}
242+
}
243+
```
244+
245+
#### Configuration tabs
246+
247+
You can organize the prompts into several tabs:
248+
249+
```js
250+
api.describeConfig({
251+
/* ... */
252+
onRead: ({ data, cwd }) => ({
253+
tabs: [
254+
{
255+
id: 'tab1',
256+
label: 'My tab',
257+
// Optional
258+
icon: 'application_settings',
259+
prompts: [
260+
// Prompt objects
261+
]
262+
},
263+
{
264+
id: 'tab2',
265+
label: 'My other tab',
266+
prompts: [
267+
// Prompt objects
268+
]
269+
}
270+
]
271+
})
272+
})
273+
```
274+
152275
#### Save config changes
153276

154277
Use the `onWrite` hook to write the data to the configuration file (or execute any nodejs code):
155278

156279
```js
157280
api.describeConfig({
158281
/* ... */
159-
onWrite: ({ prompts, answers, data, file, cwd, api }) => {
282+
onWrite: ({ prompts, answers, data, files, cwd, api }) => {
160283
// ...
161284
}
162285
})
@@ -166,8 +289,8 @@ Arguments:
166289

167290
- `prompts`: current prompts runtime objects (see below)
168291
- `answers`: answers data from the user inputs
169-
- `data`: read-only initial data read from the file
170-
- `file`: descriptor of the found file (`{ type: 'json', path: '...' }`)
292+
- `data`: read-only initial data read from the config files
293+
- `files`: descriptors of the found files (`{ type: 'json', path: '...' }`)
171294
- `cwd`: current working directory
172295
- `api`: `onWrite API` (see below)
173296

@@ -190,15 +313,16 @@ Prompts runtime objects:
190313
// true if changed by user
191314
valueChanged: false,
192315
error: null,
316+
tabId: null,
193317
// Original inquirer prompt object
194318
raw: data
195319
}
196320
```
197321

198322
`onWrite` API:
199323

200-
- `assignData(newData)`: use `Object.assign` to update the config data before writing.
201-
- `setData(newData)`: each key of `newData` will be deeply set (or removed if `undefined` value) to the config data before writing.
324+
- `assignData(fileId, newData)`: use `Object.assign` to update the config data before writing.
325+
- `setData(fileId, newData)`: each key of `newData` will be deeply set (or removed if `undefined` value) to the config data before writing.
202326
- `async getAnswer(id, mapper)`: retrieve answer for a given prompt id and map it through `mapper` function if provided (for example `JSON.parse`).
203327

204328
Example (from the ESLint plugin):
@@ -213,7 +337,7 @@ api.describeConfig({
213337
for (const prompt of prompts) {
214338
result[`rules.${prompt.id}`] = await api.getAnswer(prompt.id, JSON.parse)
215339
}
216-
api.setData(result)
340+
api.setData('eslint', result)
217341
}
218342
})
219343
```

0 commit comments

Comments
 (0)