@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
186 lines (158 loc) • 6.05 kB
text/typescript
import { SpruceSchemas } from '#spruce/schemas/schemas.types'
import setupVscodeSchema from '#spruce/schemas/spruceCli/v2020_07_22/setupVscodeOptions.schema'
import PkgService from '../../../services/PkgService'
import { NpmPackage } from '../../../types/cli.types'
import AbstractAction from '../../AbstractAction'
import { FeatureActionResponse } from '../../features.types'
import { Extension } from '../services/VsCodeService'
type OptionsSchema =
SpruceSchemas.SpruceCli.v2020_07_22.SetupVscodeOptionsSchema
type Options = SpruceSchemas.SpruceCli.v2020_07_22.SetupVscodeOptions
export default class SetupAction extends AbstractAction<OptionsSchema> {
public invocationMessage = 'Setting up Visual Studio Codez... 👾'
private recommendedExtensions: Extension[] = [
{
id: 'dbaeumer.vscode-eslint',
label: 'ESLint: Syntax validation and fixing. Formats your code on save for you.',
},
{
id: 'christian-kohler.npm-intellisense',
label: 'NPM Intellisense: Autocompletion for npm modules in your package.json.',
},
{
id: 'mikestead.dotenv',
label: 'ENV Formatting: Support for nice .env formatting right in vscode!',
},
{
id: 'yoavbls.pretty-ts-errors',
label: 'Pretty TypeScript Errors: Makes Typescript errors to make them much easier to read.',
},
]
public optionsSchema = setupVscodeSchema
private dependencies: NpmPackage[] = [
{
name: 'eslint',
isDev: true,
},
{
name: 'eslint-config-spruce',
isDev: true,
},
]
public async execute(options: Options): Promise<FeatureActionResponse> {
const { all } = this.validateAndNormalizeOptions(options)
this.ui.startLoading('Checking state of vscode.')
const missing = await this.getMissingExtensions()
const choices = missing.map((ext) => ({
value: ext.id,
label: ext.label,
}))
const response: FeatureActionResponse = {
summaryLines: [],
}
const skipConfirmExtensions = all || missing.length === 0
if (!skipConfirmExtensions) {
this.ui.stopLoading()
}
await this.optionallyInstallVscodeExtensions(
skipConfirmExtensions,
missing,
choices,
response
)
this.ui.startLoading('Writing vscode configurations...')
const files = await this.Writer('vscode').writeVsCodeConfigurations(
this.cwd,
!all
)
response.files = files
response.packagesInstalled = []
await this.optionallyInstallEsListModules(response, all)
response.hints = [
"Ok, now that that's done 😅, lets make sure Visual Studio Code can run tasks whenever you open this project.",
'',
'Step 1: Open the Command Palette (View -> Command Palette or cmd+shift+p) and type "Manage".',
'Step 2: Select "Tasks: Manage Automatic Tasks".',
'Step 3: Allow.',
'Step 4: Open the Command Palette (cmd+shift+p)).',
'Step 5: Select "Developer: Reload Window".',
'💪',
]
return response
}
private async optionallyInstallVscodeExtensions(
skipConfirmExtensions: boolean,
missing: Extension[],
choices: { value: string; label: string }[],
response: FeatureActionResponse
) {
const answers = skipConfirmExtensions
? missing.map((m) => m.id)
: await this.ui.prompt({
type: 'select',
label: 'Which extensions should I install?',
isArray: true,
options: {
choices,
},
})
if (answers && answers?.length > 0) {
this.ui.startLoading(`Installing ${answers.length} extensions...`)
for (const answer of answers) {
response.summaryLines?.push(`Installed ${answer} extension.`)
}
await this.Service('vsCode').installExtensions(answers)
this.ui.stopLoading()
}
}
private async optionallyInstallEsListModules(
response: FeatureActionResponse,
all: boolean | undefined
) {
const pkg = this.Service('pkg')
for (const module of this.dependencies) {
if (!pkg.isInstalled(module.name)) {
;(response.packagesInstalled ?? []).push(module)
}
}
if ((response.packagesInstalled ?? []).length > 0) {
await this.installEsLintModules(all, response, pkg)
}
}
private async installEsLintModules(
all: boolean | undefined,
response: FeatureActionResponse,
pkg: PkgService
) {
this.ui.stopLoading()
const shouldInstallPackages =
all ||
(await this.ui.confirm(
'Last thing! Ready for me to install eslint modules?'
))
this.ui.startLoading('Installing dev dependencies')
if (shouldInstallPackages) {
for (const module of response.packagesInstalled ?? []) {
await pkg.install(module.name, {
isDev: module.isDev,
})
}
}
}
private async getMissingExtensions() {
const currentExtensions =
await this.Service('vsCode').getVSCodeExtensions()
const missingExtensions = this.recommendedExtensions.filter(
(recommendedExtension) => {
const currentExtension = currentExtensions.find(
(e) => e === recommendedExtension.id
)
if (currentExtension) {
return false
}
return true
}
)
return missingExtensions
}
}