plugin.ts: Adjust to implement pluginapi.d.ts correctly

This commit is contained in:
Anmol Sethi 2020-11-03 21:11:14 -05:00
parent fed545e67d
commit afff86ae9c
No known key found for this signature in database
GPG Key ID: 8CEF1878FF10ADEB
6 changed files with 48 additions and 18 deletions

View File

@ -10,11 +10,11 @@ const fsp = fs.promises
interface Plugin extends pluginapi.Plugin { interface Plugin extends pluginapi.Plugin {
/** /**
* These fields are populated from the plugin's package.json. * These fields are populated from the plugin's package.json
* and now guaranteed to exist.
*/ */
name: string name: string
version: string version: string
description: string
/** /**
* path to the node module on the disk. * path to the node module on the disk.
@ -34,7 +34,7 @@ interface Application extends pluginapi.Application {
* Please see that file for details. * Please see that file for details.
*/ */
export class PluginAPI { export class PluginAPI {
private readonly plugins = new Array<Plugin>() private readonly plugins = new Map<string, Plugin>()
private readonly logger: Logger private readonly logger: Logger
public constructor( public constructor(
@ -54,7 +54,7 @@ export class PluginAPI {
*/ */
public async applications(): Promise<Application[]> { public async applications(): Promise<Application[]> {
const apps = new Array<Application>() const apps = new Array<Application>()
for (const p of this.plugins) { for (const [_, p] of this.plugins) {
const pluginApps = await p.applications() const pluginApps = await p.applications()
// Add plugin key to each app. // Add plugin key to each app.
@ -65,8 +65,11 @@ export class PluginAPI {
plugin: { plugin: {
name: p.name, name: p.name,
version: p.version, version: p.version,
description: p.description,
modulePath: p.modulePath, modulePath: p.modulePath,
displayName: p.displayName,
description: p.description,
path: p.path,
}, },
} }
}), }),
@ -79,7 +82,7 @@ export class PluginAPI {
* mount mounts all plugin routers onto r. * mount mounts all plugin routers onto r.
*/ */
public mount(r: express.Router): void { public mount(r: express.Router): void {
for (const p of this.plugins) { for (const [_, p] of this.plugins) {
r.use(`/${p.name}`, p.router()) r.use(`/${p.name}`, p.router())
} }
} }
@ -129,7 +132,7 @@ export class PluginAPI {
encoding: "utf8", encoding: "utf8",
}) })
const packageJSON: PackageJSON = JSON.parse(str) const packageJSON: PackageJSON = JSON.parse(str)
for (const p of this.plugins) { for (const [_, p] of this.plugins) {
if (p.name === packageJSON.name) { if (p.name === packageJSON.name) {
this.logger.warn( this.logger.warn(
`ignoring duplicate plugin ${q(p.name)} at ${q(dir)}, using previously loaded ${q(p.modulePath)}`, `ignoring duplicate plugin ${q(p.name)} at ${q(dir)}, using previously loaded ${q(p.modulePath)}`,
@ -138,7 +141,7 @@ export class PluginAPI {
} }
} }
const p = this._loadPlugin(dir, packageJSON) const p = this._loadPlugin(dir, packageJSON)
this.plugins.push(p) this.plugins.set(p.name, p)
} catch (err) { } catch (err) {
if (err.code !== "ENOENT") { if (err.code !== "ENOENT") {
this.logger.warn(`failed to load plugin: ${err.message}`) this.logger.warn(`failed to load plugin: ${err.message}`)
@ -147,6 +150,8 @@ export class PluginAPI {
} }
private _loadPlugin(dir: string, packageJSON: PackageJSON): Plugin { private _loadPlugin(dir: string, packageJSON: PackageJSON): Plugin {
dir = path.resolve(dir)
const logger = this.logger.named(packageJSON.name) const logger = this.logger.named(packageJSON.name)
logger.debug("loading plugin", field("plugin_dir", dir), field("package_json", packageJSON)) logger.debug("loading plugin", field("plugin_dir", dir), field("package_json", packageJSON))
@ -165,11 +170,20 @@ export class PluginAPI {
const p = { const p = {
name: packageJSON.name, name: packageJSON.name,
version: packageJSON.version, version: packageJSON.version,
description: packageJSON.description,
modulePath: dir, modulePath: dir,
...require(dir), ...require(dir),
} as Plugin } as Plugin
if (!p.displayName) {
throw new Error("plugin missing displayName")
}
if (!p.description) {
throw new Error("plugin missing description")
}
if (!p.path) {
throw new Error("plugin missing path")
}
p.init({ p.init({
logger: logger, logger: logger,
}) })
@ -183,7 +197,6 @@ export class PluginAPI {
interface PackageJSON { interface PackageJSON {
name: string name: string
version: string version: string
description: string
engines: { engines: {
"code-server": string "code-server": string
} }

View File

@ -17,14 +17,20 @@ describe("plugin", () => {
assert.deepEqual( assert.deepEqual(
[ [
{ {
name: "goland", name: "test app",
version: "4.0.0", version: "4.0.0",
description: "my description",
iconPath: "/icon.svg", iconPath: "/icon.svg",
plugin: { plugin: {
name: "test-plugin", name: "test-plugin",
version: "1.0.0", version: "1.0.0",
description: "Fake plugin for testing code-server's plugin API",
modulePath: path.join(__dirname, "test-plugin"), modulePath: path.join(__dirname, "test-plugin"),
description: "Plugin used in code-server tests.",
displayName: "Test Plugin",
path: "/test-plugin",
}, },
}, },
], ],

View File

@ -2,7 +2,6 @@
"private": true, "private": true,
"name": "test-plugin", "name": "test-plugin",
"version": "1.0.0", "version": "1.0.0",
"description": "Fake plugin for testing code-server's plugin API",
"engines": { "engines": {
"code-server": "^3.6.0" "code-server": "^3.6.0"
}, },

View File

@ -1,7 +1,11 @@
import * as express from "express" import * as express from "express"
import * as path from "path" import * as fspath from "path"
import * as pluginapi from "../../../typings/pluginapi" import * as pluginapi from "../../../typings/pluginapi"
export const displayName = "Test Plugin"
export const path = "/test-plugin"
export const description = "Plugin used in code-server tests."
export function init(config: pluginapi.PluginConfig) { export function init(config: pluginapi.PluginConfig) {
config.logger.debug("test-plugin loaded!") config.logger.debug("test-plugin loaded!")
} }
@ -9,7 +13,7 @@ export function init(config: pluginapi.PluginConfig) {
export function router(): express.Router { export function router(): express.Router {
const r = express.Router() const r = express.Router()
r.get("/goland/icon.svg", (req, res) => { r.get("/goland/icon.svg", (req, res) => {
res.sendFile(path.resolve(__dirname, "../public/icon.svg")) res.sendFile(fspath.resolve(__dirname, "../public/icon.svg"))
}) })
return r return r
} }
@ -17,9 +21,11 @@ export function router(): express.Router {
export function applications(): pluginapi.Application[] { export function applications(): pluginapi.Application[] {
return [ return [
{ {
name: "goland", name: "test app",
version: "4.0.0", version: "4.0.0",
iconPath: "/icon.svg", iconPath: "/icon.svg",
description: "my description",
}, },
] ]
} }

View File

@ -16,7 +16,8 @@
"tsBuildInfoFile": "./.cache/tsbuildinfo", "tsBuildInfoFile": "./.cache/tsbuildinfo",
"incremental": true, "incremental": true,
"rootDir": "./src", "rootDir": "./src",
"typeRoots": ["./node_modules/@types", "./typings"] "typeRoots": ["./node_modules/@types", "./typings"],
"downlevelIteration": true
}, },
"include": ["./src/**/*.ts"] "include": ["./src/**/*.ts"]
} }

View File

@ -70,9 +70,14 @@ export interface Plugin {
version?: string version?: string
/** /**
* These two are used in the overlay. * Name used in the overlay.
*/ */
displayName: string displayName: string
/**
* Used in overlay.
* Should be a full sentence describing the plugin.
*/
description: string description: string
/** /**