Skip to content

Commit

Permalink
feat(ui): config improvements (#1487)
Browse files Browse the repository at this point in the history
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
        ]
      }
    ]
  })
})
```
  • Loading branch information
Akryum authored Jun 10, 2018
1 parent e258f5a commit dbef5e9
Show file tree
Hide file tree
Showing 15 changed files with 619 additions and 329 deletions.
154 changes: 139 additions & 15 deletions docs/dev-guide/ui-plugin-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,9 @@ api.describeConfig({

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

#### Config file
#### Config files

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

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

Expand All @@ -118,17 +118,22 @@ api.describeConfig({
/* ... */
// All possible files for this config
files: {
json: ['.eslintrc', '.eslintrc.json'],
js: ['.eslintrc.js'],
// Will read from `package.json`
package: 'eslintConfig'
// 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']
}
},
})
```

Supported types: `json`, `yaml`, `js`, `package`.

**⚠️ Currently, only 1 file can be read and written to at a time.**
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.

#### Display config prompts

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

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

The `data` object contains the JSON result of each config file content.

For example, let's say the user has the following `vue.config.js` in his project:

```js
module.exports = {
lintOnSave: false
}
```

We declare the config file in our plugin like this:

```js
api.describeConfig({
/* ... */
// All possible files for this config
files: {
// vue.config.js
vue: {
js: ['vue.config.js']
}
},
})
```

Then the `data` object will be:

```js
{
// File
vue: {
// File data
lintOnSave: false
}
}
```

Multiple files example: if we add the following `eslintrc.js` file in the user project:

```js
module.exports = {
root: true,
extends: [
'plugin:vue/essential',
'@vue/standard'
]
}
```

And change the `files` option in our plugin to this:

```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']
}
},
})
```

Then the `data` object will be:

```js
{
eslint: {
root: true,
extends: [
'plugin:vue/essential',
'@vue/standard'
]
},
vue: {
lintOnSave: false
}
}
```

#### Configuration tabs

You can organize the prompts into several tabs:

```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
]
}
]
})
})
```

#### Save config changes

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

```js
api.describeConfig({
/* ... */
onWrite: ({ prompts, answers, data, file, cwd, api }) => {
onWrite: ({ prompts, answers, data, files, cwd, api }) => {
// ...
}
})
Expand All @@ -166,8 +289,8 @@ Arguments:

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

Expand All @@ -190,15 +313,16 @@ Prompts runtime objects:
// true if changed by user
valueChanged: false,
error: null,
tabId: null,
// Original inquirer prompt object
raw: data
}
```

`onWrite` API:

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

Example (from the ESLint plugin):
Expand All @@ -213,7 +337,7 @@ api.describeConfig({
for (const prompt of prompts) {
result[`rules.${prompt.id}`] = await api.getAnswer(prompt.id, JSON.parse)
}
api.setData(result)
api.setData('eslint', result)
}
})
```
Expand Down
Loading

0 comments on commit dbef5e9

Please sign in to comment.