Skip to content

Commit

Permalink
feat(webui): safe module transform with es-module-lexer
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed May 25, 2024
1 parent 72dbe80 commit 2c61921
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 13 deletions.
1 change: 1 addition & 0 deletions plugins/webui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
},
"dependencies": {
"cosmokit": "^1.6.2",
"es-module-lexer": "^1.5.2",
"open": "^8.4.2",
"uuid": "^8.3.2",
"ws": "^8.16.0"
Expand Down
34 changes: 21 additions & 13 deletions plugins/webui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { extname, resolve } from 'node:path'
import { createReadStream, existsSync, Stats } from 'node:fs'
import { readFile, stat } from 'node:fs/promises'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { parse } from 'es-module-lexer'
import { Entry, Events, WebUI } from './shared'
import open from 'open'

Expand Down Expand Up @@ -95,7 +96,7 @@ class NodeWebUI extends WebUI<NodeWebUI.Config> {
this.ctx.server.post(`${this.config.apiPath}/${event}`, async (koa) => {
const { body } = koa.request
try {
koa.body = await (callback as any)(body)
koa.body = await (callback as any)(body) ?? {}
koa.status = 200
} catch (error) {
this.ctx.logger.warn(error)
Expand Down Expand Up @@ -170,20 +171,27 @@ class NodeWebUI extends WebUI<NodeWebUI.Config> {
})
}

private resolveImport(name?: string) {
if (!name) {
this.ctx.logger.warn('cannot transform dynamic import names')
return name
}
return ({
'vue': this.config.uiPath + '/vue.js',
'vue-router': this.config.uiPath + '/vue-router.js',
'@vueuse/core': this.config.uiPath + '/vueuse.js',
'@cordisjs/client': this.config.uiPath + '/client.js',
})[name] ?? name
}

private async transformImport(source: string) {
let output = ''
let cap: RegExpExecArray | null
while ((cap = /((?:^|;)import\b[^'"]+\bfrom\s*)(['"])([^'"]+)\2;/m.exec(source))) {
const [stmt, left, quote, path] = cap
output += source.slice(0, cap.index) + left + quote + ({
'vue': this.config.uiPath + '/vue.js',
'vue-router': this.config.uiPath + '/vue-router.js',
'@vueuse/core': this.config.uiPath + '/vueuse.js',
'@cordisjs/client': this.config.uiPath + '/client.js',
}[path] ?? path) + quote + ';'
source = source.slice(cap.index + stmt.length)
let output = '', lastIndex = 0
const [imports] = parse(source)
for (const { s, e, n } of imports) {
output += source.slice(lastIndex, s) + this.resolveImport(n)
lastIndex = e
}
return output + source
return output + source.slice(lastIndex)
}

private async transformHtml(template: string) {
Expand Down

0 comments on commit 2c61921

Please sign in to comment.