Skip to content

Commit

Permalink
feat(manager): support non-plugin deps
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed May 7, 2022
1 parent eb80f1c commit af10bd2
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 61 deletions.
6 changes: 5 additions & 1 deletion docs/.vuepress/layouts/home/screen-6.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ function getSidebarItems(route: string) {
}
&.api {
@media (max-width: 1200px) or (max-height: 800px) {
@media (max-width: 1200px) {
display: none;
}
@media (max-height: 800px) {
display: none;
}
}
Expand Down
3 changes: 1 addition & 2 deletions packages/core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ export class App extends Context {
public options: App.Config
public isActive = false
public registry = new Plugin.Registry()

private _nameRE: RegExp
public _nameRE: RegExp

constructor(options: App.Config = {}) {
super(() => true)
Expand Down
13 changes: 7 additions & 6 deletions plugins/frontend/manager/client/deps/index.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<k-card class="page-deps">
<div class="controls">
<el-checkbox v-model="config.showDepsOnly">只显示依赖的插件</el-checkbox>
<el-checkbox v-model="config.hideWorkspace">忽略工作区依赖{{ config.override }}</el-checkbox>
<span class="float-right" v-if="!overrideCount">当前没有变更的依赖</span>
<template v-else>
<k-button class="float-right" solid @click="install">更新依赖</k-button>
Expand Down Expand Up @@ -46,11 +46,12 @@ import { message, loading } from '@koishijs/client'
import PackageView from './package.vue'
const names = computed(() => {
const data = config.showDepsOnly
? Object.keys(store.dependencies).filter(name => store.packages[name])
: Object.values(store.packages).map(item => item.name).filter(Boolean)
let data = Object.keys(store.dependencies)
if (config.hideWorkspace) {
data = data.filter(name => !store.dependencies[name].workspace)
}
for (const key in config.override) {
if (!data.includes(key) && store.market[key] && config.override[key]) data.push(key)
if (!data.includes(key) && store.market[key]) data.push(key)
}
return data.sort((a, b) => a > b ? 1 : -1)
})
Expand Down Expand Up @@ -105,7 +106,7 @@ main.route-dependencies {
}
tr:hover {
background-color: var(--bg1);
background-color: var(--hover-bg);
}
tr:first-child {
Expand Down
48 changes: 27 additions & 21 deletions plugins/frontend/manager/client/deps/package.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,23 @@
<tr class="dep-package-view">
<td class="name" :class="state">{{ name }}</td>
<td class="current">
<template v-if="store.dependencies[name]">
{{ local.version }}
<template v-if="local?.workspace">(工作区)</template>
<template v-else-if="local?.version === remote?.versions[0].version">(最新)</template>
<template v-if="local">
{{ local.resolved }}
<template v-if="local.workspace">(工作区)</template>
<template v-else-if="local.resolved === remote?.versions[0].version">(最新)</template>
</template>
<span v-else>-</span>
</td>
<td class="target">
<template v-if="local?.workspace">
<k-button v-if="store.dependencies[name]" @click="send('market/patch', name, null)">移除依赖</k-button>
<k-button v-else @click="send('market/patch', name, local.version)">添加依赖</k-button>
<k-button @click="send('market/patch', name, null)">移除依赖</k-button>
</template>
<el-select v-else v-model="value">
<el-option v-if="store.dependencies[name]" value="">移除依赖</el-option>
<el-option value="">移除依赖</el-option>
<el-option
v-for="({ version }) in remote?.versions || []"
:key="version" :value="version"
>{{ version }}{{ version === local?.version ? ' (当前)' : '' }}</el-option>
>{{ version }}{{ version === local?.resolved ? ' (当前)' : '' }}</el-option>
</el-select>
</td>
</tr>
Expand All @@ -38,10 +37,10 @@ const props = defineProps({
const value = computed({
get() {
const target = config.override[props.name]
return target === '' ? '移除插件' : target
return target === '' ? '移除依赖' : target
},
set(target: string) {
if (target === '' && !local.value || target === local.value) {
if (target === '' && !local.value || target === local.value?.resolved) {
delete config.override[props.name]
} else {
config.override[props.name] = target
Expand All @@ -50,13 +49,16 @@ const value = computed({
})
const state = computed(() => {
if (store.dependencies[props.name]) return 'tracked'
if (local.value) return local.value.workspace ? 'workspace' : 'external'
return 'remote'
if (!props.name.includes('koishi-plugin-') && !props.name.startsWith('@koishijs/plugin-')) {
return 'disabled'
}
if (store.packages?.[props.name]?.id) return 'success'
if (local.value) return 'warning'
return 'error'
})
const local = computed(() => {
return store.packages[props.name]
return store.dependencies[props.name]
})
const remote = computed(() => {
Expand Down Expand Up @@ -88,18 +90,22 @@ const remote = computed(() => {
box-shadow: 1px 1px 2px #3333;
}
&.tracked::before {
// 已加载的插件
&.success::before {
background-color: var(--success);
}
&.workspace::before {
background-color: var(--disabled);
}
&.external::before {
background-color: var(--primary);
// 未加载的插件
&.warning::before {
background-color: var(--warning);
}
&.remote::before {
// 未安装的插件
&.error::before {
background-color: var(--error);
}
// 非插件
&.disabled::before {
background-color: var(--disabled);
}
}
.el-select, .k-button {
Expand Down
2 changes: 1 addition & 1 deletion plugins/frontend/manager/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export default (ctx: Context) => {
icon: 'box-open',
order: 610,
authority: 4,
fields: ['market', 'packages', 'dependencies'],
fields: ['market', 'dependencies'],
component: Dependencies,
badge: () => overrideCount.value,
})
Expand Down
10 changes: 5 additions & 5 deletions plugins/frontend/manager/client/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@ import { createStorage, store } from '@koishijs/client'
interface ManagerConfig {
override: Dict<string>
showInstalled?: boolean
showDepsOnly?: boolean
hideWorkspace?: boolean
}

export const config = createStorage<ManagerConfig>('manager', 1, () => ({
export const config = createStorage<ManagerConfig>('manager', 2, () => ({
override: {},
showInstalled: false,
showDepsOnly: false,
hideWorkspace: true,
}))

export const overrideCount = computed(() => {
return Object.values(config.override).filter(value => value !== undefined).length
})

watch(store.dependencies, (value) => {
watch(() => store.dependencies, (value) => {
if (!value) return
for (const key in config.override) {
if (!config.override[key]) {
if (!value[key]) delete config.override[key]
} else if (value[key] === config.override[key]) {
} else if (value[key]?.resolved === config.override[key]) {
delete config.override[key]
}
}
Expand Down
59 changes: 34 additions & 25 deletions plugins/frontend/manager/src/installer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { clone, Context, Dict, Logger } from 'koishi'
import { Context, Dict, Logger } from 'koishi'
import { DataService } from '@koishijs/plugin-console'
import { PackageJson } from '@koishijs/market'
import { resolve } from 'path'
import { promises as fsp } from 'fs'
import { promises as fsp, readFileSync } from 'fs'
import which from 'which-pm-runs'
import spawn from 'cross-spawn'

Expand All @@ -15,11 +15,24 @@ declare module '@koishijs/plugin-console' {

const logger = new Logger('market')

class Installer extends DataService<Dict<string>> {
private metaTask: Promise<PackageJson>
export interface Dependency {
request: string
resolved: string
workspace?: boolean
versions?: Partial<PackageJson>[]
}

function loadJson(path: string) {
return JSON.parse(readFileSync(path, 'utf8'))
}

class Installer extends DataService<Dict<Dependency>> {
private meta: PackageJson

constructor(public ctx: Context) {
super(ctx, 'dependencies', { authority: 4 })
this.meta = loadJson(resolve(this.cwd, 'package.json'))
this.meta.dependencies ||= {}

ctx.console.addListener('market/install', this.installDep, { authority: 4 })
ctx.console.addListener('market/patch', this.patchDep, { authority: 4 })
Expand All @@ -29,17 +42,17 @@ class Installer extends DataService<Dict<string>> {
return this.ctx.app.baseDir
}

async _loadDeps() {
const filename = resolve(this.cwd, 'package.json')
const source = await fsp.readFile(filename, 'utf8')
const meta: PackageJson = JSON.parse(source)
meta.dependencies ||= {}
return meta
}

async get() {
const meta = await (this.metaTask ||= this._loadDeps())
return meta.dependencies
const results: Dict<Dependency> = {}
for (const name in this.meta.dependencies) {
const path = require.resolve(name + '/package.json')
results[name] = {
request: this.meta.dependencies[name],
resolved: loadJson(path).version,
workspace: !path.includes('node_modules'),
}
}
return results
}

async exec(command: string, args: string[]) {
Expand All @@ -66,35 +79,31 @@ class Installer extends DataService<Dict<string>> {

async override(deps: Dict<string>) {
const filename = resolve(this.cwd, 'package.json')
const meta = clone(await (this.metaTask ||= this._loadDeps()))
for (const key in deps) {
if (deps[key]) {
meta.dependencies[key] = deps[key]
this.meta.dependencies[key] = '^' + deps[key]
} else {
delete meta.dependencies[key]
delete this.meta.dependencies[key]
}
}
meta.dependencies = Object.fromEntries(Object.entries(meta.dependencies).sort((a, b) => a[0].localeCompare(b[0])))
await fsp.writeFile(filename, JSON.stringify(meta, null, 2))
return meta
this.meta.dependencies = Object.fromEntries(Object.entries(this.meta.dependencies).sort((a, b) => a[0].localeCompare(b[0])))
await fsp.writeFile(filename, JSON.stringify(this.meta, null, 2))
}

patchDep = async (name: string, version: string) => {
const meta = await this.override({ [name]: version })
this.metaTask = Promise.resolve(meta)
await this.override({ [name]: version })
this.refresh()
}

installDep = async (deps: Dict<string>) => {
const agent = which()?.name || 'npm'
const meta = await this.override(deps)
await this.override(deps)
const args: string[] = []
if (agent === 'yarn') args.push('install')
if (agent !== 'yarn') args.push('install')
const registry = this.ctx.console.market.config.registry
if (registry) args.push('--registry=' + registry)
const code = await this.exec(agent, args)
if (!code) {
this.metaTask = Promise.resolve(meta)
this.refresh()
this.ctx.console.packages.refresh()
}
Expand Down

0 comments on commit af10bd2

Please sign in to comment.