@sprucelabs/spruce-cli
Version:
Command line interface for building Spruce skills.
150 lines (132 loc) • 5.15 kB
text/typescript
import { SettingsService } from '@sprucelabs/spruce-skill-utils'
import {
FILE_ACTION_ALWAYS_SKIP,
FILE_ACTION_OVERWRITE,
FILE_ACTION_SKIP,
} from '../constants'
import AbstractFeature from '../features/AbstractFeature'
import PkgService from '../services/PkgService'
import { GraphicsInterface } from '../types/cli.types'
export default class ScriptUpdaterImpl implements ScriptUpdater {
private pkg: PkgService
private latestScripts: Record<string, any>
private shouldConfirmIfScriptExistsButIsDifferent: boolean
private ui: GraphicsInterface
private settings: SettingsService<string>
public static Class?: new (
options: ScriptUpdaterContructorOptions
) => ScriptUpdater
public constructor(options: ScriptUpdaterContructorOptions) {
this.pkg = options.pkg
this.latestScripts = options.latestScripts
this.shouldConfirmIfScriptExistsButIsDifferent =
options.shouldConfirmIfScriptExistsButIsDifferent ?? true
this.ui = options.ui
this.settings = options.settings
}
public static FromFeature(
feature: AbstractFeature,
options?: { cwd?: string; latestScripts?: Record<string, any> }
) {
const cwd = options?.cwd ?? feature.cwd
const updater = new (this.Class ?? ScriptUpdaterImpl)({
pkg: feature.Service('pkg', cwd),
latestScripts: feature.scripts ?? [],
//@ts-ignore
ui: feature.ui,
settings: feature.Service('settings', cwd),
...options,
})
return updater
}
public async update(options?: {
shouldConfirmIfScriptExistsButIsDifferent?: boolean
}) {
this.shouldConfirmIfScriptExistsButIsDifferent =
options?.shouldConfirmIfScriptExistsButIsDifferent ??
this.shouldConfirmIfScriptExistsButIsDifferent
const scripts =
(this.pkg.get('scripts') as Record<string, string>) ?? {}
const all = this.latestScripts
const oldScripts = this.pkg.get('scripts') ?? {}
let shouldConfirm = this.shouldConfirmIfScriptExistsButIsDifferent
let shouldSkipAll = false
const updaterSettings = {
skipped: [],
...this.settings.get('scriptUpdater'),
}
for (const name in this.latestScripts) {
const script = this.latestScripts[name as keyof typeof all]
const oldScript = oldScripts[name as any]
const shouldAlwaysSkip =
(updaterSettings.skipped ?? []).indexOf(name) > -1
let shouldWrite = !shouldSkipAll && !shouldAlwaysSkip
if (
shouldConfirm &&
!shouldSkipAll &&
oldScript &&
script !== oldScript &&
!shouldAlwaysSkip
) {
this.ui.clear()
this.ui.renderSection({
headline: `Change to \`${name}\` detected in ${this.pkg.getSkillNamespace()}!`,
object: {
Current: oldScript,
' New': script,
},
})
const desiredAction = await this.ui.prompt({
type: 'select',
label: 'What should I do?',
options: {
choices: [
{
label: 'Overwrite',
value: FILE_ACTION_OVERWRITE,
},
{
label: 'Skip',
value: FILE_ACTION_SKIP,
},
{
label: 'Always skip',
value: FILE_ACTION_ALWAYS_SKIP,
},
{
label: 'Skip all',
value: 'skipAll',
},
],
},
})
if (desiredAction === 'alwaysSkip') {
updaterSettings.skipped.push(name)
shouldWrite = false
} else if (desiredAction === 'skipAll') {
shouldSkipAll = true
shouldWrite = false
} else if (desiredAction === 'skip') {
shouldWrite = false
}
}
if (shouldWrite) {
scripts[name] = script
}
}
this.settings.set('scriptUpdater', updaterSettings)
this.pkg.set({ path: 'scripts', value: scripts })
}
}
export interface ScriptUpdater {
update(options?: {
shouldConfirmIfScriptExistsButIsDifferent?: boolean
}): Promise<void>
}
interface ScriptUpdaterContructorOptions {
pkg: PkgService
latestScripts: Record<string, any>
shouldConfirmIfScriptExistsButIsDifferent?: boolean
ui: GraphicsInterface
settings: SettingsService
}