mirror of
https://github.com/purocean/yn.git
synced 2026-09-24 15:46:02 +08:00
Merge branch 'release/2.0.0-alpha2'
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
.vscode
|
||||
nohup.out
|
||||
*.log
|
||||
config.json
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
6. 在文档中运行 PHP Python Node.js bash 代码块
|
||||
|
||||
## Yank-Note 2.0 开发计划
|
||||
[V2 项目看板](https://github.com/purocean/yn/projects/2)
|
||||
|
||||
+ [x] 项目更名为 **Yank-Note**
|
||||
+ [x] 前端界面可以拖动调整尺寸
|
||||
+ [x] 重构前端项目结构,便于拓展:引入 `vuex`,使用 `async await` 代替可怕的回调,规范文件接口。
|
||||
@@ -37,9 +39,14 @@
|
||||
# yarn run dist-win # or npm run dist-win # Windows 用户
|
||||
|
||||
# 安装后端
|
||||
cd ../background
|
||||
cd app
|
||||
yarn # or npm i
|
||||
node main.js # 运行
|
||||
yarn run serve # 运行后端
|
||||
|
||||
# 运行 electron
|
||||
cd app
|
||||
yarn # Windows 上安装 node-pty 需要费一番功夫,参考 https://github.com/microsoft/node-pty#windows
|
||||
yarn run start
|
||||
```
|
||||
+ 访问 `http://localhost:3000`
|
||||
+ 新增文件:`双击目录`
|
||||
@@ -112,10 +119,6 @@
|
||||
+ 表格解析增强,支持表格标题多行文本,列表等特性 [markdown-it-multimd-table](https://github.com/RedBug312/markdown-it-multimd-table)
|
||||
+ 内置终端 [XTERM.JS](https://xtermjs.org/) [node-pty](https://github.com/Microsoft/node-pty)
|
||||
|
||||
## 开发贡献
|
||||
+ 前端: `cd backend; node main.js`
|
||||
+ 后端: `cd frontend; yarn run serve`
|
||||
|
||||
## 捐赠
|
||||
如果我的工作对您有帮助,请我喝杯咖啡吧 ^_^。**附言可以留下您的 github 用户名或网站连接**。
|
||||
|
||||
@@ -133,6 +136,14 @@
|
||||
## 更新日志
|
||||
[最新发布](https://github.com/purocean/yn/releases)
|
||||
|
||||
### [v2.0.0-alpha2](https://github.com/purocean/yn/releases/tag/v2.0.0-alpha2) 2019-08-02
|
||||
1. 默认仓库数据和配置改为在 `<home>/yank-note` 下保存
|
||||
2. 调整在 Windows 端的仓库配置,不论是否在 WSL 环境下都使用 windows 风格的路径
|
||||
1. 前端重构文件接口
|
||||
2. 尝试引入 Electron
|
||||
3. 后端重构改用 TypeScript
|
||||
4. 修复若干 v2.0.0-alpha1 的问题
|
||||
|
||||
### [v2.0.0-alpha1](https://github.com/purocean/yn/releases/tag/v2.0.0-alpha1) 2019-08-01
|
||||
1. 目录树和集成终端增加拖动调整尺寸功能
|
||||
1. 重构前端代码便于拓展
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
vs
|
||||
Vendored
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"serve": "ts-node src/server/main.ts",
|
||||
"start": "npm run build && electron ./dist/app.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": "^6.0.1",
|
||||
"koa": "^2.4.1",
|
||||
"koa-body": "^2.5.0",
|
||||
"koa-static": "^4.0.2",
|
||||
"mime": "^2.2.0",
|
||||
"natural-orderby": "^1.0.2",
|
||||
"node-plantuml": "^0.6.2",
|
||||
"node-pty": "^0.8.1",
|
||||
"opn": "^5.3.0",
|
||||
"request": "^2.88.0",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"socket.io": "^2.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/fs-extra": "^8.0.0",
|
||||
"@types/koa": "^2.0.49",
|
||||
"@types/koa-static": "^4.0.1",
|
||||
"@types/mime": "^2.0.1",
|
||||
"@types/node": "^12.6.1",
|
||||
"@types/request": "^2.48.2",
|
||||
"electron": "^6.0.0",
|
||||
"ts-node": "^8.3.0",
|
||||
"typescript": "^3.5.3"
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import server from './server/main'
|
||||
import { dialog } from 'electron'
|
||||
|
||||
let win: BrowserWindow | null = null
|
||||
|
||||
@@ -13,12 +15,43 @@ const createWindow = () => {
|
||||
|
||||
// 加载index.html文件
|
||||
// win.loadFile('../../static/index.html')
|
||||
// win.loadURL('http://g.cn')
|
||||
win.loadURL('http://localhost:8066')
|
||||
|
||||
// 打开后端服务器
|
||||
server(3044)
|
||||
|
||||
// 加载页面
|
||||
setTimeout(() => {
|
||||
win.loadURL('http://localhost:8066')
|
||||
win.maximize()
|
||||
}, 1000)
|
||||
|
||||
// 打开开发者工具
|
||||
win.webContents.openDevTools()
|
||||
|
||||
win.on('close', e => {
|
||||
const contents = win.webContents
|
||||
|
||||
if (contents) {
|
||||
contents.executeJavaScript('window.documentSaved', true).then(val => {
|
||||
if (val) {
|
||||
win.destroy()
|
||||
} else {
|
||||
dialog.showMessageBox(win, {
|
||||
type: 'question',
|
||||
buttons: ['取消', '放弃保存并退出'],
|
||||
title: '提示',
|
||||
message: '有文档未保存,是否要退出?'
|
||||
}).then(choice => {
|
||||
if (choice.response === 1) {
|
||||
win.destroy()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
e.preventDefault()
|
||||
}
|
||||
})
|
||||
|
||||
// 当 window 被关闭,这个事件会被触发。
|
||||
win.on('closed', () => {
|
||||
// 取消引用 window 对象,如果你的应用支持多窗口的话,
|
||||
@@ -0,0 +1,39 @@
|
||||
import * as fs from 'fs'
|
||||
import { CONFIG_FILE } from './constant'
|
||||
|
||||
const configFile = CONFIG_FILE
|
||||
|
||||
const writeJson = (data: any) => {
|
||||
fs.writeFileSync(configFile, JSON.stringify(data, null, 4), 'utf8')
|
||||
}
|
||||
|
||||
const readJson = () => {
|
||||
try {
|
||||
const data = fs.readFileSync(configFile)
|
||||
return JSON.parse(data.toString())
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const set = (key: string, value: any) => {
|
||||
const config = readJson() || {}
|
||||
config[key] = value
|
||||
writeJson(config)
|
||||
}
|
||||
|
||||
const get = (key: string, defaultVal: any = null) => {
|
||||
const config = readJson() || {}
|
||||
|
||||
if (config[key] === undefined) {
|
||||
set(key, defaultVal) // 写入默认值到配置文件
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
return config[key]
|
||||
}
|
||||
|
||||
export default {
|
||||
set,
|
||||
get
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import * as path from 'path'
|
||||
import * as os from 'os'
|
||||
import { isWsl, toWslPath, getWinHomePath } from './wsl'
|
||||
|
||||
const homedir = isWsl ? toWslPath(getWinHomePath()) : os.homedir()
|
||||
|
||||
export const HOME_DIR = homedir
|
||||
export const USER_DIR = path.join(homedir, 'yank-note')
|
||||
export const TRASH_DIR = path.join(USER_DIR, 'trash')
|
||||
export const MAIN_REPO_DIR = path.join(USER_DIR, 'main')
|
||||
export const CONFIG_FILE = path.join(USER_DIR, 'config.json')
|
||||
export const STATIC_DIR = path.join(__dirname, '../../static')
|
||||
@@ -0,0 +1,34 @@
|
||||
import * as os from 'os'
|
||||
import * as fs from 'fs'
|
||||
import { spawn } from 'child_process'
|
||||
|
||||
const convert = async (html: string, type: string) => {
|
||||
try {
|
||||
const path = os.tmpdir() + `/yn_convert_${new Date().getTime()}.${type}`
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const process = spawn('pandoc', ['-f', 'html', '-o', path])
|
||||
|
||||
process.on('close', () => {
|
||||
try {
|
||||
const data = fs.readFileSync(path)
|
||||
fs.unlinkSync(path)
|
||||
resolve(data)
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
|
||||
process.on('error', error => {
|
||||
reject(error)
|
||||
})
|
||||
|
||||
process.stdin.write(html)
|
||||
process.stdin.end()
|
||||
})
|
||||
} catch (e) {
|
||||
return e.message
|
||||
}
|
||||
}
|
||||
|
||||
export default convert
|
||||
@@ -0,0 +1,227 @@
|
||||
import * as fs from 'fs'
|
||||
import * as xfs from 'fs-extra'
|
||||
import * as path from 'path'
|
||||
import * as crypto from 'crypto'
|
||||
import * as NaturalOrderby from 'natural-orderby'
|
||||
import * as wsl from './wsl'
|
||||
import repository from './repository'
|
||||
const opn = require('opn')
|
||||
|
||||
const isWsl = wsl.isWsl
|
||||
const ignorePath = /node_modules/
|
||||
|
||||
const mkdirPSync = (location: string) => {
|
||||
let normalizedPath = path.normalize(location)
|
||||
let parsedPathObj = path.parse(normalizedPath)
|
||||
let curDir = parsedPathObj.root
|
||||
let folders = parsedPathObj.dir.split(path.sep)
|
||||
folders.push(parsedPathObj.base)
|
||||
for(let part of folders) {
|
||||
if (part.indexOf(':') > -1) { // 修复 Windows 下面路径错误
|
||||
continue
|
||||
}
|
||||
|
||||
curDir = path.join(curDir, part)
|
||||
if (!fs.existsSync(curDir)) {
|
||||
fs.mkdirSync(curDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rmRecursiveSync = (location: string) => {
|
||||
if (fs.statSync(location).isDirectory()) {
|
||||
let _ = fs.readdirSync(location)
|
||||
_.forEach(childItemName => {
|
||||
rmRecursiveSync(path.join(location, childItemName))
|
||||
})
|
||||
fs.rmdirSync(location)
|
||||
} else {
|
||||
fs.unlinkSync(location)
|
||||
}
|
||||
}
|
||||
|
||||
const resolvePath = (p: string, repo = 'main') => {
|
||||
p = p.replace(/\.\./g, '')
|
||||
|
||||
const basePath = repository.getPath(repo)
|
||||
if (!basePath) {
|
||||
throw new Error(`仓库 ${repo} 不存在`)
|
||||
}
|
||||
|
||||
return path.join(basePath, p)
|
||||
}
|
||||
|
||||
const travels = (location: string, repo: string, basePath: string = null): any => {
|
||||
if (!basePath) {
|
||||
basePath = resolvePath('', repo)
|
||||
}
|
||||
|
||||
if (!fs.statSync(location).isDirectory()) {
|
||||
return []
|
||||
}
|
||||
|
||||
const list = fs.readdirSync(location).filter(x => !x.startsWith('.') && !ignorePath.test(x))
|
||||
|
||||
const dirs = NaturalOrderby.orderBy(list.filter(x => fs.statSync(path.join(location, x)).isDirectory()))
|
||||
const files = NaturalOrderby.orderBy(list.filter(x => !fs.statSync(path.join(location, x)).isDirectory()))
|
||||
|
||||
return dirs.map(x => {
|
||||
const p = path.join(location, x)
|
||||
const xpath = p.replace(basePath, '')
|
||||
|
||||
return {
|
||||
name: x,
|
||||
path: xpath,
|
||||
type: 'dir',
|
||||
repo: repo,
|
||||
children: travels(p, repo, basePath)
|
||||
}
|
||||
}).concat(files.map(x => {
|
||||
const p = path.join(location, x)
|
||||
const xpath = p.replace(basePath, '')
|
||||
|
||||
return {
|
||||
name: x,
|
||||
path: xpath,
|
||||
type: 'file',
|
||||
repo: repo,
|
||||
} as any
|
||||
}))
|
||||
}
|
||||
|
||||
const read = (repo: string, p: string) => {
|
||||
return fs.readFileSync(resolvePath(p, repo))
|
||||
}
|
||||
|
||||
const write = (repo: string, p: string, content: any) => {
|
||||
p = resolvePath(p, repo)
|
||||
|
||||
mkdirPSync(path.dirname(p))
|
||||
|
||||
fs.writeFileSync(p, content)
|
||||
|
||||
return crypto.createHash('md5').update(content).digest('hex')
|
||||
}
|
||||
|
||||
const rm = (repo: string, p: string) => {
|
||||
if (resolvePath(p) !== resolvePath('', repo)) {
|
||||
const newPath = path.join(repository.getTrashPath(repo), p.replace(/\.\./g, '')) + '.' + (new Date).getTime()
|
||||
|
||||
mkdirPSync(path.dirname(newPath))
|
||||
|
||||
try {
|
||||
fs.renameSync(resolvePath(p, repo), newPath)
|
||||
} catch (error) {
|
||||
xfs.moveSync(resolvePath(p, repo), newPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mv = (repo: string, oldPath: string, newPath: string) => {
|
||||
oldPath = resolvePath(oldPath, repo)
|
||||
newPath = resolvePath(newPath, repo)
|
||||
|
||||
if (oldPath !== newPath) {
|
||||
mkdirPSync(path.dirname(newPath))
|
||||
|
||||
try {
|
||||
fs.renameSync(oldPath, newPath)
|
||||
} catch (error) {
|
||||
xfs.moveSync(oldPath, newPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const exists = (repo: string, p: string) => {
|
||||
return fs.existsSync(resolvePath(p, repo))
|
||||
}
|
||||
|
||||
const hash = (repo: string, p: string) => {
|
||||
const content = read(repo, p)
|
||||
return crypto.createHash('md5').update(content).digest('hex')
|
||||
}
|
||||
|
||||
const checkHash = (repo: string, p: string, oldHash: string) => {
|
||||
return oldHash === hash(repo, p)
|
||||
}
|
||||
|
||||
const upload = (repo: string, file: any, path: string) => {
|
||||
write(repo, path, fs.readFileSync(file.path))
|
||||
}
|
||||
|
||||
const tree = (repo: string) => {
|
||||
return [{
|
||||
name: '/',
|
||||
type: 'dir',
|
||||
path: '/',
|
||||
repo: repo,
|
||||
children: travels(resolvePath('', repo), repo)
|
||||
}]
|
||||
}
|
||||
|
||||
const open = (repo: string, p: string) => {
|
||||
let path = resolvePath(p, repo)
|
||||
|
||||
if (isWsl) {
|
||||
path = wsl.toWinPath(path)
|
||||
}
|
||||
|
||||
opn(path)
|
||||
}
|
||||
|
||||
const search = (repo: string, str: string) => {
|
||||
str = str.trim()
|
||||
if (!str) {
|
||||
return []
|
||||
}
|
||||
|
||||
const files = [] as any
|
||||
const basePath = resolvePath('', repo)
|
||||
|
||||
const match = (p: string, str: string) => {
|
||||
return p.endsWith('.md') && !p.endsWith('.c.md') && new RegExp(str, 'i').test(fs.readFileSync(p, 'utf-8'))
|
||||
}
|
||||
|
||||
const travelFiles = (location: string) => {
|
||||
if (!fs.statSync(location).isDirectory()) {
|
||||
return
|
||||
}
|
||||
|
||||
const list = fs.readdirSync(location).filter(x => !x.startsWith('.') && !ignorePath.test(x))
|
||||
|
||||
list.forEach(x => {
|
||||
const p = path.join(location, x)
|
||||
|
||||
if (fs.statSync(p).isDirectory()) {
|
||||
travelFiles(p)
|
||||
} else if (fs.statSync(p).isFile()) {
|
||||
if (match(p, str)) {
|
||||
files.push({
|
||||
repo,
|
||||
name: x,
|
||||
path: p.replace(basePath, ''),
|
||||
type: 'file',
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
travelFiles(resolvePath('', repo))
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
export default {
|
||||
read,
|
||||
write,
|
||||
rm,
|
||||
mv,
|
||||
exists,
|
||||
hash,
|
||||
checkHash,
|
||||
upload,
|
||||
tree,
|
||||
open,
|
||||
search,
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import * as fs from 'fs'
|
||||
import { USER_DIR, TRASH_DIR, MAIN_REPO_DIR } from './constant'
|
||||
|
||||
const init = () => {
|
||||
if (!fs.existsSync(USER_DIR)) {
|
||||
fs.mkdirSync(USER_DIR)
|
||||
}
|
||||
if (!fs.existsSync(MAIN_REPO_DIR)) {
|
||||
fs.mkdirSync(MAIN_REPO_DIR)
|
||||
}
|
||||
if (!fs.existsSync(TRASH_DIR)) {
|
||||
fs.mkdirSync(TRASH_DIR)
|
||||
}
|
||||
}
|
||||
|
||||
export default init
|
||||
@@ -0,0 +1,230 @@
|
||||
import * as fs from 'fs'
|
||||
import * as os from 'os'
|
||||
import * as path from 'path'
|
||||
import * as Koa from 'koa'
|
||||
import * as bodyParser from 'koa-body'
|
||||
import * as xStatic from 'koa-static'
|
||||
import * as mime from 'mime'
|
||||
import * as request from 'request'
|
||||
import * as pty from 'node-pty'
|
||||
|
||||
import { STATIC_DIR, HOME_DIR } from './constant'
|
||||
import init from './init'
|
||||
import file from './file'
|
||||
import dataRepository from './repository'
|
||||
import run from './run'
|
||||
import convert from './convert'
|
||||
import plantuml from './plantuml'
|
||||
|
||||
const result = (status = 'ok', message = '操作成功', data: any = null) => {
|
||||
return { status, message, data }
|
||||
}
|
||||
|
||||
const fileContent = async (ctx: any, next: any) => {
|
||||
if (ctx.path === '/api/file') {
|
||||
if (ctx.method === 'GET') {
|
||||
ctx.body = result('ok', '获取成功', {
|
||||
content: file.read(ctx.query.repo, ctx.query.path).toString(),
|
||||
hash: file.hash(ctx.query.repo, ctx.query.path)
|
||||
})
|
||||
} else if (ctx.method === 'POST') {
|
||||
const oldHash = ctx.request.body.old_hash
|
||||
|
||||
if (!oldHash) {
|
||||
throw new Error('未传递文件hash')
|
||||
} else if (oldHash === 'new' && file.exists(ctx.request.body.repo, ctx.request.body.path)) {
|
||||
throw new Error('文件已经存在')
|
||||
} else if (oldHash !== 'new' && !file.checkHash(ctx.request.body.repo, ctx.request.body.path, oldHash)) {
|
||||
throw new Error('磁盘文件已经更新,请刷新文件')
|
||||
}
|
||||
|
||||
const hash = file.write(ctx.request.body.repo, ctx.request.body.path, ctx.request.body.content)
|
||||
ctx.body = result('ok', '保存成功', hash)
|
||||
} else if (ctx.method === 'DELETE') {
|
||||
file.rm(ctx.query.repo, ctx.query.path)
|
||||
ctx.body = result()
|
||||
} else if (ctx.method === 'PATCH') {
|
||||
if (file.exists(ctx.request.body.repo, ctx.request.body.newPath)) {
|
||||
throw new Error('文件已经存在')
|
||||
}
|
||||
|
||||
file.mv(ctx.request.body.repo, ctx.request.body.oldPath, ctx.request.body.newPath)
|
||||
ctx.body = result()
|
||||
}
|
||||
} else if (ctx.path === '/api/tree') {
|
||||
ctx.body = result('ok', '获取成功', file.tree(ctx.query.repo))
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const attachment = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/attachment')) {
|
||||
if (ctx.method === 'POST') {
|
||||
const path = ctx.request.body.fields.path
|
||||
const repo = ctx.request.body.fields.repo
|
||||
file.upload(repo, ctx.request.body.files.attachment, path)
|
||||
ctx.body = result('ok', '上传成功', path)
|
||||
} else if (ctx.method === 'GET') {
|
||||
ctx.type = mime.getType(ctx.query.path)
|
||||
ctx.body = file.read(ctx.query.repo, ctx.query.path)
|
||||
}
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const open = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/open')) {
|
||||
if (ctx.method === 'GET') {
|
||||
file.open(ctx.query.repo, ctx.query.path)
|
||||
ctx.body = result()
|
||||
}
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const searchFile = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/search')) {
|
||||
const search = ctx.query.search
|
||||
const repo = ctx.query.repo
|
||||
|
||||
ctx.body = result('ok', '操作成功', file.search(repo, search))
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const repository = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/repositories')) {
|
||||
ctx.body = result('ok', '获取成功', dataRepository.list())
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const plantumlGen = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/plantuml/png')) {
|
||||
ctx.set('cache-control', 'max-age=86400') // 一天过期
|
||||
ctx.type = 'image/png'
|
||||
ctx.body = plantuml.generate(ctx.query.data)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const runCode = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/run')) {
|
||||
const rst = run.runCode(ctx.request.body.language, ctx.request.body.code)
|
||||
ctx.body = result('ok', '运行成功', rst)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const convertFile = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/convert/')) {
|
||||
const html = ctx.request.body.html
|
||||
const type = ctx.request.body.type
|
||||
|
||||
ctx.type = mime.getType(`file.${type}`)
|
||||
ctx.body = await convert(html, type)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const proxy = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/proxy')) {
|
||||
const url = ctx.query.url
|
||||
ctx.body = request(url)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const readme = async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/api/readme')) {
|
||||
if (ctx.query.path) {
|
||||
ctx.type = mime.getType(ctx.query.path)
|
||||
ctx.body = fs.readFileSync(path.join(STATIC_DIR, 'readme', ctx.query.path))
|
||||
} else {
|
||||
ctx.body = result('ok', '获取成功', {
|
||||
content: fs.readFileSync(path.join(STATIC_DIR, 'readme/README.md')).toString()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const wrapper = async (ctx: any, next: any, fun: any) => {
|
||||
try {
|
||||
await fun(ctx, next)
|
||||
} catch (error) {
|
||||
ctx.body = result('error', error.message)
|
||||
}
|
||||
}
|
||||
|
||||
const server = (port = 3000) => {
|
||||
init()
|
||||
|
||||
const app = new Koa()
|
||||
|
||||
app.use(xStatic(STATIC_DIR))
|
||||
app.use(async (ctx: any, next: any) => {
|
||||
if (ctx.path.startsWith('/static')) {
|
||||
ctx.response.redirect(ctx.path.replace(/^\/static/, ''))
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
})
|
||||
|
||||
app.use(bodyParser({
|
||||
multipart: true,
|
||||
formLimit: '20mb',
|
||||
jsonLimit: '20mb',
|
||||
textLimit: '20mb'
|
||||
}))
|
||||
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, fileContent))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, attachment))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, open))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, plantumlGen))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, runCode))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, convertFile))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, searchFile))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, repository))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, proxy))
|
||||
app.use(async (ctx: any, next: any) => await wrapper(ctx, next, readme))
|
||||
|
||||
const server = require('http').createServer(app.callback())
|
||||
const io = require('socket.io')(server, {path: '/ws'})
|
||||
|
||||
io.on('connection', (socket: any) => {
|
||||
const ptyProcess = pty.spawn(os.platform() === 'win32' ? 'cmd.exe' : 'bash', [], {
|
||||
name: 'xterm-color',
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
cwd: HOME_DIR,
|
||||
env: process.env
|
||||
})
|
||||
ptyProcess.on('data', (data: any) => socket.emit('output', data))
|
||||
ptyProcess.on('exit', () => socket.disconnect())
|
||||
socket.on('input', (data: any) => ptyProcess.write(data))
|
||||
socket.on('resize', (size: any) => ptyProcess.resize(size[0], size[1]))
|
||||
socket.on('disconnect', () => ptyProcess.kill())
|
||||
})
|
||||
|
||||
server.listen(port)
|
||||
|
||||
console.log(`访问地址:http://localhost:${port}`)
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2)
|
||||
server(Number(args[0]) || 3000)
|
||||
}
|
||||
|
||||
export default server
|
||||
@@ -0,0 +1,18 @@
|
||||
import config from './config'
|
||||
import * as request from 'request'
|
||||
const plantuml = require('node-plantuml')
|
||||
|
||||
const generate = (data: any) => {
|
||||
const api = config.get('plantuml-api', 'local')
|
||||
|
||||
if (api === 'local') {
|
||||
const gen = plantuml.generate(data, {format: 'png'});
|
||||
return gen.out
|
||||
} else {
|
||||
return request(api.replace('{data}', encodeURIComponent(data)))
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
generate
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import * as path from 'path'
|
||||
import config from './config'
|
||||
import { MAIN_REPO_DIR, TRASH_DIR } from './constant'
|
||||
import { isWsl, toWslPath, toWinPath } from './wsl'
|
||||
|
||||
const configKey = 'repositories'
|
||||
|
||||
// windows 上不管是不是 wsl 环境都使用 windows 风格的路径配置
|
||||
const defaultVal = { main: isWsl ? toWinPath(MAIN_REPO_DIR) : MAIN_REPO_DIR }
|
||||
|
||||
const list = () => {
|
||||
return config.get(configKey, defaultVal)
|
||||
}
|
||||
|
||||
const getPath = (name: string) => {
|
||||
let p = config.get(configKey, defaultVal)[name] || ''
|
||||
p = p.trim()
|
||||
|
||||
if (!p) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (isWsl) {
|
||||
return /^[a-zA-Z]:/.test(p) ? toWslPath(p) : path.join(MAIN_REPO_DIR, p)
|
||||
}
|
||||
|
||||
return path.isAbsolute(p) ? p : path.join(MAIN_REPO_DIR, p)
|
||||
}
|
||||
|
||||
const getTrashPath = (name: string) => {
|
||||
return path.join(TRASH_DIR, name)
|
||||
}
|
||||
|
||||
export default {
|
||||
list,
|
||||
getPath,
|
||||
getTrashPath,
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
const fs = require('fs')
|
||||
const os = require('os');
|
||||
const path = require('path')
|
||||
const isWsl = require('is-wsl')
|
||||
const execFileSync = require("child_process").execFileSync
|
||||
const wsl = require('./wsl')
|
||||
import * as fs from 'fs'
|
||||
import * as os from 'os'
|
||||
import * as path from 'path'
|
||||
import { execFileSync } from 'child_process'
|
||||
import * as wsl from './wsl'
|
||||
|
||||
const runCode = (language, code) => {
|
||||
const isWsl = wsl.isWsl
|
||||
|
||||
const runCode = (language: string, code: string) => {
|
||||
try {
|
||||
switch (language) {
|
||||
case 'bat':
|
||||
@@ -38,4 +39,6 @@ const runCode = (language, code) => {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { runCode }
|
||||
export default {
|
||||
runCode
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import * as os from 'os'
|
||||
import * as fs from 'fs'
|
||||
import { execFileSync } from 'child_process'
|
||||
|
||||
export const getIsWsl = () => {
|
||||
if (process.platform !== 'linux') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (os.release().toLowerCase().includes('microsoft')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (fs.readFileSync('/proc/version', 'utf8').toLowerCase().includes('microsoft')) {
|
||||
return true;
|
||||
}
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const isWsl = getIsWsl()
|
||||
|
||||
export const toWslPath = (path: string) => {
|
||||
return execFileSync('wslpath', ['-u', `${path.replace(/\\/g, '/')}`]).toString().trim()
|
||||
}
|
||||
|
||||
export const toWinPath = (path: string) => {
|
||||
return execFileSync('wslpath', ['-w', path]).toString().trim()
|
||||
}
|
||||
|
||||
export const getWinTempPath = () => {
|
||||
return execFileSync('cmd.exe', ['/c', 'echo %temp%']).toString().trim()
|
||||
}
|
||||
|
||||
export const getWinHomePath = () => {
|
||||
return execFileSync('cmd.exe', ['/c', 'echo %HOMEDRIVE%%HOMEPATH%']).toString().trim()
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
*
|
||||
!.gitignore
|
||||
!readme
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"noImplicitAny": true,
|
||||
"outDir": "./dist",
|
||||
"sourceMap": true
|
||||
},
|
||||
"typeRoots": [
|
||||
"node_modules/@types",
|
||||
"global.d.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
node_modules
|
||||
@@ -1,37 +0,0 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const configFile = path.join(__dirname, '../', 'config.json')
|
||||
|
||||
const writeJson = data => {
|
||||
fs.writeFileSync(configFile, JSON.stringify(data, null, 4), 'utf8');
|
||||
}
|
||||
|
||||
const readJson = () => {
|
||||
try {
|
||||
const data = fs.readFileSync(configFile)
|
||||
return JSON.parse(data.toString())
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const set = (key, value) => {
|
||||
const config = readJson() || {}
|
||||
config[key] = value
|
||||
writeJson(config)
|
||||
}
|
||||
|
||||
exports.set = set
|
||||
|
||||
exports.get = (key, defaultVal = null) => {
|
||||
const config = readJson() || {}
|
||||
|
||||
if (config[key] === undefined) {
|
||||
set(key, defaultVal) // 写入默认值到配置文件
|
||||
|
||||
return defaultVal
|
||||
}
|
||||
|
||||
return config[key]
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
const os = require('os')
|
||||
const fs = require('fs')
|
||||
const spawn = require("child_process").spawn
|
||||
|
||||
const convert = async (html, type) => {
|
||||
try {
|
||||
const path = os.tmpdir() + `/yn_convert_${new Date().getTime()}.${type}`
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const process = spawn('pandoc', ['-f', 'html', '-o', path])
|
||||
|
||||
process.on('close', (code) => {
|
||||
try {
|
||||
const data = fs.readFileSync(path)
|
||||
fs.unlinkSync(path)
|
||||
resolve(data)
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
|
||||
process.on('error', error => {
|
||||
reject(error)
|
||||
})
|
||||
|
||||
process.stdin.write(html)
|
||||
process.stdin.end()
|
||||
})
|
||||
} catch (e) {
|
||||
return e.message
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = convert
|
||||
-213
@@ -1,213 +0,0 @@
|
||||
const fs = require('fs')
|
||||
const xfs = require('fs-extra')
|
||||
const path = require('path')
|
||||
const opn = require('opn')
|
||||
const isWsl = require('is-wsl')
|
||||
const crypto = require('crypto')
|
||||
const NaturalOrderby = require('natural-orderby')
|
||||
const wsl = require('./wsl')
|
||||
const repository = require('./repository')
|
||||
|
||||
const ignorePath = /node_modules/
|
||||
|
||||
const mkdirPSync = location => {
|
||||
let normalizedPath = path.normalize(location)
|
||||
let parsedPathObj = path.parse(normalizedPath)
|
||||
let curDir = parsedPathObj.root
|
||||
let folders = parsedPathObj.dir.split(path.sep)
|
||||
folders.push(parsedPathObj.base)
|
||||
for(let part of folders) {
|
||||
if (part.indexOf(':') > -1) { // 修复 Windows 下面路径错误
|
||||
continue
|
||||
}
|
||||
|
||||
curDir = path.join(curDir, part)
|
||||
if (!fs.existsSync(curDir)) {
|
||||
fs.mkdirSync(curDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rmRecursiveSync = location => {
|
||||
if (fs.statSync(location).isDirectory()) {
|
||||
let _ = fs.readdirSync(location)
|
||||
_.forEach(childItemName => {
|
||||
rmRecursiveSync(path.join(location, childItemName))
|
||||
})
|
||||
fs.rmdirSync(location)
|
||||
} else {
|
||||
fs.unlinkSync(location)
|
||||
}
|
||||
}
|
||||
|
||||
const resolvePath = (p, repo = 'main') => {
|
||||
p = p.replace(/\.\./g, '')
|
||||
|
||||
const basePath = repository.getPath(repo)
|
||||
if (!basePath) {
|
||||
throw new Error(`仓库 ${repo} 不存在`)
|
||||
}
|
||||
|
||||
return path.join(basePath, p)
|
||||
}
|
||||
|
||||
const travels = (location, repo, basePath = null) => {
|
||||
if (!basePath) {
|
||||
basePath = resolvePath('', repo)
|
||||
}
|
||||
|
||||
if (!fs.statSync(location).isDirectory()) {
|
||||
return []
|
||||
}
|
||||
|
||||
const list = fs.readdirSync(location).filter(x => !x.startsWith('.') && !ignorePath.test(x))
|
||||
|
||||
const dirs = NaturalOrderby.orderBy(list.filter(x => fs.statSync(path.join(location, x)).isDirectory()))
|
||||
const files = NaturalOrderby.orderBy(list.filter(x => !fs.statSync(path.join(location, x)).isDirectory()))
|
||||
|
||||
return dirs.map(x => {
|
||||
const p = path.join(location, x)
|
||||
const xpath = p.replace(basePath, '')
|
||||
|
||||
return {
|
||||
name: x,
|
||||
path: xpath,
|
||||
type: 'dir',
|
||||
repo: repo,
|
||||
children: travels(p, repo, basePath)
|
||||
}
|
||||
}).concat(files.map(x => {
|
||||
const p = path.join(location, x)
|
||||
const xpath = p.replace(basePath, '')
|
||||
|
||||
return {
|
||||
name: x,
|
||||
path: xpath,
|
||||
type: 'file',
|
||||
repo: repo,
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
exports.read = (repo, p) => {
|
||||
return fs.readFileSync(resolvePath(p, repo))
|
||||
}
|
||||
|
||||
exports.write = (repo, p, content) => {
|
||||
p = resolvePath(p, repo)
|
||||
|
||||
mkdirPSync(path.dirname(p))
|
||||
|
||||
fs.writeFileSync(p, content)
|
||||
|
||||
return crypto.createHash('md5').update(content).digest('hex')
|
||||
}
|
||||
|
||||
exports.rm = (repo, p) => {
|
||||
if (resolvePath(p) !== resolvePath('', repo)) {
|
||||
const newPath = path.join(repository.getTrashPath(repo), p.replace(/\.\./g, '')) + '.' + (new Date).getTime()
|
||||
|
||||
mkdirPSync(path.dirname(newPath))
|
||||
|
||||
try {
|
||||
fs.renameSync(resolvePath(p, repo), newPath)
|
||||
} catch (error) {
|
||||
xfs.moveSync(resolvePath(p, repo), newPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.mv = (repo, oldPath, newPath) => {
|
||||
oldPath = resolvePath(oldPath, repo)
|
||||
newPath = resolvePath(newPath, repo)
|
||||
|
||||
if (oldPath !== newPath) {
|
||||
mkdirPSync(path.dirname(newPath))
|
||||
|
||||
try {
|
||||
fs.renameSync(oldPath, newPath)
|
||||
} catch (error) {
|
||||
xfs.moveSync(oldPath, newPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.exists = (repo, p) => {
|
||||
return fs.existsSync(resolvePath(p, repo))
|
||||
}
|
||||
|
||||
exports.hash = (repo, p) => {
|
||||
const content = exports.read(repo, p)
|
||||
return crypto.createHash('md5').update(content).digest('hex')
|
||||
}
|
||||
|
||||
exports.checkHash = (repo, p, oldHash) => {
|
||||
return oldHash === exports.hash(repo, p)
|
||||
}
|
||||
|
||||
exports.upload = (repo, file, path) => {
|
||||
exports.write(repo, path, fs.readFileSync(file.path))
|
||||
}
|
||||
|
||||
exports.tree = repo => {
|
||||
return [{
|
||||
name: '/',
|
||||
type: 'dir',
|
||||
path: '/',
|
||||
repo: repo,
|
||||
children: travels(resolvePath('', repo), repo)
|
||||
}]
|
||||
}
|
||||
|
||||
exports.open = (repo, p) => {
|
||||
let path = resolvePath(p, repo)
|
||||
|
||||
if (isWsl) {
|
||||
path = wsl.toWinPath(path)
|
||||
}
|
||||
|
||||
opn(path)
|
||||
}
|
||||
|
||||
exports.search = (repo, str) => {
|
||||
str = str.trim()
|
||||
if (!str) {
|
||||
return []
|
||||
}
|
||||
|
||||
const files = []
|
||||
const basePath = resolvePath('', repo)
|
||||
|
||||
const match = (p, str) => {
|
||||
return p.endsWith('.md') && !p.endsWith('.c.md') && new RegExp(str, 'i').test(fs.readFileSync(p, 'utf-8'))
|
||||
}
|
||||
|
||||
const travelFiles = location => {
|
||||
if (!fs.statSync(location).isDirectory()) {
|
||||
return
|
||||
}
|
||||
|
||||
const list = fs.readdirSync(location).filter(x => !x.startsWith('.') && !ignorePath.test(x))
|
||||
|
||||
list.forEach(x => {
|
||||
const p = path.join(location, x)
|
||||
|
||||
if (fs.statSync(p).isDirectory()) {
|
||||
travelFiles(p)
|
||||
} else if (fs.statSync(p).isFile()) {
|
||||
if (match(p, str)) {
|
||||
files.push({
|
||||
repo,
|
||||
name: x,
|
||||
path: p.replace(basePath, ''),
|
||||
type: 'file',
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
travelFiles(resolvePath('', repo))
|
||||
|
||||
return files
|
||||
}
|
||||
-214
@@ -1,214 +0,0 @@
|
||||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const Koa = require('koa')
|
||||
const bodyParser = require('koa-body')
|
||||
const static = require('koa-static')
|
||||
const mime = require('mime')
|
||||
const request = require('request')
|
||||
const pty = require('node-pty')
|
||||
|
||||
const file = require('./file')
|
||||
const dataRepository = require('./repository')
|
||||
const run = require('./run')
|
||||
const convert = require('./convert')
|
||||
const plantuml = require('./plantuml')
|
||||
|
||||
const result = (status = 'ok', message = '操作成功', data = null) => {
|
||||
return { status, message, data }
|
||||
}
|
||||
|
||||
const fileContent = async (ctx, next) => {
|
||||
if (ctx.path === '/api/file') {
|
||||
if (ctx.method === 'GET') {
|
||||
ctx.body = result('ok', '获取成功', {
|
||||
content: file.read(ctx.query.repo, ctx.query.path).toString(),
|
||||
hash: file.hash(ctx.query.repo, ctx.query.path)
|
||||
})
|
||||
} else if (ctx.method === 'POST') {
|
||||
const oldHash = ctx.request.body.old_hash
|
||||
|
||||
if (!oldHash) {
|
||||
throw new Error('未传递文件hash')
|
||||
} else if (oldHash === 'new' && file.exists(ctx.request.body.repo, ctx.request.body.path)) {
|
||||
throw new Error('文件已经存在')
|
||||
} else if (oldHash !== 'new' && !file.checkHash(ctx.request.body.repo, ctx.request.body.path, oldHash)) {
|
||||
throw new Error('磁盘文件已经更新,请刷新文件')
|
||||
}
|
||||
|
||||
const hash = file.write(ctx.request.body.repo, ctx.request.body.path, ctx.request.body.content)
|
||||
ctx.body = result('ok', '保存成功', hash)
|
||||
} else if (ctx.method === 'DELETE') {
|
||||
file.rm(ctx.query.repo, ctx.query.path)
|
||||
ctx.body = result()
|
||||
} else if (ctx.method === 'PATCH') {
|
||||
if (file.exists(ctx.request.body.repo, ctx.request.body.newPath)) {
|
||||
throw new Error('文件已经存在')
|
||||
}
|
||||
|
||||
file.mv(ctx.request.body.repo, ctx.request.body.oldPath, ctx.request.body.newPath)
|
||||
ctx.body = result()
|
||||
}
|
||||
} else if (ctx.path === '/api/tree') {
|
||||
ctx.body = result('ok', '获取成功', file.tree(ctx.query.repo))
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const attachment = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/attachment')) {
|
||||
if (ctx.method === 'POST') {
|
||||
const path = ctx.request.body.fields.path
|
||||
const repo = ctx.request.body.fields.repo
|
||||
file.upload(repo, ctx.request.body.files.attachment, path)
|
||||
ctx.body = result('ok', '上传成功', path)
|
||||
} else if (ctx.method === 'GET') {
|
||||
ctx.type = mime.getType(ctx.query.path)
|
||||
ctx.body = file.read(ctx.query.repo, ctx.query.path)
|
||||
}
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const open = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/open')) {
|
||||
if (ctx.method === 'GET') {
|
||||
file.open(ctx.query.repo, ctx.query.path)
|
||||
ctx.body = result()
|
||||
}
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const searchFile = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/search')) {
|
||||
const search = ctx.query.search
|
||||
const repo = ctx.query.repo
|
||||
|
||||
ctx.body = result('ok', '操作成功', file.search(repo, search))
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const repository = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/repositories')) {
|
||||
ctx.body = result('ok', '获取成功', dataRepository.list())
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const plantumlGen = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/plantuml/png')) {
|
||||
ctx.set('cache-control', 'max-age=86400') // 一天过期
|
||||
ctx.type = 'image/png'
|
||||
ctx.body = plantuml.generate(ctx.query.data)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const runCode = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/run')) {
|
||||
const rst = run.runCode(ctx.request.body.language, ctx.request.body.code)
|
||||
ctx.body = result('ok', '运行成功', rst)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const convertFile = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/convert/')) {
|
||||
const html = ctx.request.body.html
|
||||
const type = ctx.request.body.type
|
||||
|
||||
ctx.type = mime.getType(`file.${type}`)
|
||||
ctx.body = await convert(html, type)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const proxy = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/proxy')) {
|
||||
const url = ctx.query.url
|
||||
ctx.body = request(url)
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const readme = async (ctx, next) => {
|
||||
if (ctx.path.startsWith('/api/readme')) {
|
||||
if (ctx.query.path) {
|
||||
ctx.type = mime.getType(ctx.query.path)
|
||||
ctx.body = fs.readFileSync(path.join(__dirname, '../', ctx.query.path))
|
||||
} else {
|
||||
ctx.body = result('ok', '获取成功', {
|
||||
content: fs.readFileSync(path.join(__dirname, '../README.md')).toString()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
await next()
|
||||
}
|
||||
}
|
||||
|
||||
const app = new Koa()
|
||||
|
||||
app.use(static(
|
||||
path.join(__dirname, '../static')
|
||||
))
|
||||
|
||||
app.use(bodyParser({
|
||||
multipart: true,
|
||||
formLimit: '20mb',
|
||||
jsonLimit: '20mb',
|
||||
textLimit: '20mb'
|
||||
}))
|
||||
|
||||
const wrapper = async (ctx, next, fun) => {
|
||||
try {
|
||||
await fun(ctx, next)
|
||||
} catch (error) {
|
||||
ctx.body = result('error', error.message)
|
||||
}
|
||||
}
|
||||
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, fileContent))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, attachment))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, open))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, plantumlGen))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, runCode))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, convertFile))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, searchFile))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, repository))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, proxy))
|
||||
app.use(async (ctx, next) => await wrapper(ctx, next, readme))
|
||||
|
||||
const port = 3000
|
||||
|
||||
const server = require('http').createServer(app.callback())
|
||||
const io = require('socket.io')(server, {path: '/ws'})
|
||||
|
||||
io.on('connection', socket => {
|
||||
const ptyProcess = pty.spawn(os.platform() === 'win32' ? 'cmd.exe' : 'bash', [], {
|
||||
name: 'xterm-color',
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
cwd: path.join(__dirname, '../'),
|
||||
env: process.env
|
||||
})
|
||||
ptyProcess.on('data', data => socket.emit('output', data))
|
||||
ptyProcess.on('exit', () => socket.disconnect())
|
||||
socket.on('input', data => ptyProcess.write(data))
|
||||
socket.on('resize', size => ptyProcess.resize(size[0], size[1]))
|
||||
socket.on('disconnect', () => ptyProcess.destroy())
|
||||
})
|
||||
|
||||
server.listen(port)
|
||||
|
||||
console.log(`访问地址:http://localhost:${port}`)
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"fs-extra": "^6.0.1",
|
||||
"koa": "^2.4.1",
|
||||
"koa-body": "^2.5.0",
|
||||
"koa-static": "^4.0.2",
|
||||
"mime": "^2.2.0",
|
||||
"natural-orderby": "^1.0.2",
|
||||
"node-plantuml": "^0.6.2",
|
||||
"node-pty": "^0.8.1",
|
||||
"opn": "^5.3.0",
|
||||
"request": "^2.88.0",
|
||||
"safe-buffer": "^5.1.2",
|
||||
"socket.io": "^2.2.0"
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
const plantuml = require('node-plantuml')
|
||||
const config = require('./config')
|
||||
const request = require('request')
|
||||
|
||||
exports.generate = data => {
|
||||
const api = config.get('plantuml-api', 'local')
|
||||
|
||||
if (api === 'local') {
|
||||
const gen = plantuml.generate(data, {format: 'png'});
|
||||
return gen.out
|
||||
} else {
|
||||
return request(api.replace('{data}', encodeURIComponent(data)))
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
const path = require('path')
|
||||
const config = require('./config')
|
||||
|
||||
const configKey = 'repositories'
|
||||
const defaultVal = {"main": "./data"}
|
||||
|
||||
exports.list = () => {
|
||||
return config.get(configKey, defaultVal)
|
||||
}
|
||||
|
||||
exports.getPath = name => {
|
||||
let p = config.get(configKey, defaultVal)[name]
|
||||
|
||||
if (!p) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (path.isAbsolute(p)) {
|
||||
return p
|
||||
}
|
||||
|
||||
return path.join(__dirname, '../', p)
|
||||
}
|
||||
|
||||
exports.getTrashPath = name => {
|
||||
return path.join(__dirname, '/../trash/', name)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
const cp = require('child_process');
|
||||
|
||||
exports.toWslPath = path => {
|
||||
return cp.execFileSync('wslpath', ['-u', `${path.replace(/\\/g, '/')}`]).toString().trim()
|
||||
}
|
||||
|
||||
exports.toWinPath = path => {
|
||||
return cp.execFileSync('wslpath', ['-w', path]).toString().trim()
|
||||
}
|
||||
|
||||
exports.getWinTempPath = () => {
|
||||
return cp.execFileSync('cmd.exe', ['/c', 'echo %temp%']).toString().trim()
|
||||
}
|
||||
@@ -1,881 +0,0 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
accepts@^1.2.2:
|
||||
version "1.3.4"
|
||||
resolved "http://registry.npm.taobao.org/accepts/download/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f"
|
||||
dependencies:
|
||||
mime-types "~2.1.16"
|
||||
negotiator "0.6.1"
|
||||
|
||||
accepts@~1.3.4:
|
||||
version "1.3.5"
|
||||
resolved "http://registry.npm.taobao.org/accepts/download/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"
|
||||
dependencies:
|
||||
mime-types "~2.1.18"
|
||||
negotiator "0.6.1"
|
||||
|
||||
after@0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "http://registry.npm.taobao.org/after/download/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
|
||||
|
||||
ajv@^5.3.0:
|
||||
version "5.5.2"
|
||||
resolved "http://registry.npm.taobao.org/ajv/download/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
|
||||
dependencies:
|
||||
co "^4.6.0"
|
||||
fast-deep-equal "^1.0.0"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.3.0"
|
||||
|
||||
any-promise@^1.0.0, any-promise@^1.1.0:
|
||||
version "1.3.0"
|
||||
resolved "http://registry.npm.taobao.org/any-promise/download/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||
|
||||
arraybuffer.slice@~0.0.7:
|
||||
version "0.0.7"
|
||||
resolved "http://registry.npm.taobao.org/arraybuffer.slice/download/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
|
||||
|
||||
asn1@~0.2.3:
|
||||
version "0.2.4"
|
||||
resolved "http://registry.npm.taobao.org/asn1/download/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||
dependencies:
|
||||
safer-buffer "~2.1.0"
|
||||
|
||||
assert-plus@1.0.0, assert-plus@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/assert-plus/download/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
|
||||
async-limiter@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/async-limiter/download/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "http://registry.npm.taobao.org/asynckit/download/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
|
||||
aws-sign2@~0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "http://registry.npm.taobao.org/aws-sign2/download/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
|
||||
aws4@^1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "http://registry.npm.taobao.org/aws4/download/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
||||
|
||||
backo2@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "http://registry.npm.taobao.org/backo2/download/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
|
||||
|
||||
base64-arraybuffer@0.1.5:
|
||||
version "0.1.5"
|
||||
resolved "http://registry.npm.taobao.org/base64-arraybuffer/download/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
|
||||
|
||||
base64id@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/base64id/download/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "http://registry.npm.taobao.org/bcrypt-pbkdf/download/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
better-assert@~1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "http://registry.npm.taobao.org/better-assert/download/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
|
||||
dependencies:
|
||||
callsite "1.0.0"
|
||||
|
||||
blob@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "http://registry.npm.taobao.org/blob/download/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683"
|
||||
|
||||
bytes@3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "http://registry.npm.taobao.org/bytes/download/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
|
||||
|
||||
callsite@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/callsite/download/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
|
||||
|
||||
caseless@~0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "http://registry.npm.taobao.org/caseless/download/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
|
||||
|
||||
co-body@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "http://registry.npm.taobao.org/co-body/download/co-body-5.1.1.tgz#d97781d1e3344ba4a820fd1806bddf8341505236"
|
||||
dependencies:
|
||||
inflation "^2.0.0"
|
||||
qs "^6.4.0"
|
||||
raw-body "^2.2.0"
|
||||
type-is "^1.6.14"
|
||||
|
||||
co@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "http://registry.npm.taobao.org/co/download/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
|
||||
combined-stream@1.0.6, combined-stream@~1.0.6:
|
||||
version "1.0.6"
|
||||
resolved "http://registry.npm.taobao.org/combined-stream/download/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@^2.8.1:
|
||||
version "2.16.0"
|
||||
resolved "http://registry.npm.taobao.org/commander/download/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50"
|
||||
|
||||
component-bind@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/component-bind/download/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
|
||||
|
||||
component-emitter@1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "http://registry.npm.taobao.org/component-emitter/download/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
|
||||
|
||||
component-inherit@0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "http://registry.npm.taobao.org/component-inherit/download/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
|
||||
|
||||
content-disposition@~0.5.0:
|
||||
version "0.5.2"
|
||||
resolved "http://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||
|
||||
content-type@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "http://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||
|
||||
cookie@0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "http://registry.npm.taobao.org/cookie/download/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||
|
||||
cookies@~0.7.0:
|
||||
version "0.7.1"
|
||||
resolved "http://registry.npm.taobao.org/cookies/download/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b"
|
||||
dependencies:
|
||||
depd "~1.1.1"
|
||||
keygrip "~1.0.2"
|
||||
|
||||
core-util-is@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "http://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||
|
||||
dashdash@^1.12.0:
|
||||
version "1.14.1"
|
||||
resolved "http://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
debug@*, debug@~3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^2.6.3, debug@^2.6.8:
|
||||
version "2.6.9"
|
||||
resolved "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@~4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "http://registry.npm.taobao.org/debug/download/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
deep-equal@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "http://registry.npm.taobao.org/deep-equal/download/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/delayed-stream/download/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
|
||||
delegates@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/delegates/download/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
|
||||
|
||||
depd@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "http://registry.npm.taobao.org/depd/download/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359"
|
||||
|
||||
depd@^1.1.0, depd@~1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "http://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
|
||||
|
||||
destroy@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "http://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
|
||||
|
||||
ecc-jsbn@~0.1.1:
|
||||
version "0.1.2"
|
||||
resolved "http://registry.npm.taobao.org/ecc-jsbn/download/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
|
||||
dependencies:
|
||||
jsbn "~0.1.0"
|
||||
safer-buffer "^2.1.0"
|
||||
|
||||
ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "http://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
|
||||
engine.io-client@~3.3.1:
|
||||
version "3.3.2"
|
||||
resolved "http://registry.npm.taobao.org/engine.io-client/download/engine.io-client-3.3.2.tgz#04e068798d75beda14375a264bb3d742d7bc33aa"
|
||||
dependencies:
|
||||
component-emitter "1.2.1"
|
||||
component-inherit "0.0.3"
|
||||
debug "~3.1.0"
|
||||
engine.io-parser "~2.1.1"
|
||||
has-cors "1.1.0"
|
||||
indexof "0.0.1"
|
||||
parseqs "0.0.5"
|
||||
parseuri "0.0.5"
|
||||
ws "~6.1.0"
|
||||
xmlhttprequest-ssl "~1.5.4"
|
||||
yeast "0.1.2"
|
||||
|
||||
engine.io-parser@~2.1.0, engine.io-parser@~2.1.1:
|
||||
version "2.1.3"
|
||||
resolved "http://registry.npm.taobao.org/engine.io-parser/download/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6"
|
||||
dependencies:
|
||||
after "0.8.2"
|
||||
arraybuffer.slice "~0.0.7"
|
||||
base64-arraybuffer "0.1.5"
|
||||
blob "0.0.5"
|
||||
has-binary2 "~1.0.2"
|
||||
|
||||
engine.io@~3.3.1:
|
||||
version "3.3.2"
|
||||
resolved "http://registry.npm.taobao.org/engine.io/download/engine.io-3.3.2.tgz#18cbc8b6f36e9461c5c0f81df2b830de16058a59"
|
||||
dependencies:
|
||||
accepts "~1.3.4"
|
||||
base64id "1.0.0"
|
||||
cookie "0.3.1"
|
||||
debug "~3.1.0"
|
||||
engine.io-parser "~2.1.0"
|
||||
ws "~6.1.0"
|
||||
|
||||
error-inject@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/error-inject/download/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37"
|
||||
|
||||
escape-html@~1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "http://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
|
||||
extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "http://registry.npm.taobao.org/extend/download/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
|
||||
extsprintf@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "http://registry.npm.taobao.org/extsprintf/download/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
|
||||
|
||||
extsprintf@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "http://registry.npm.taobao.org/extsprintf/download/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||
|
||||
fast-deep-equal@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "http://registry.npm.taobao.org/fast-deep-equal/download/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "http://registry.npm.taobao.org/fast-json-stable-stringify/download/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "http://registry.npm.taobao.org/forever-agent/download/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "http://registry.npm.taobao.org/form-data/download/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formidable@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "http://registry.npm.taobao.org/formidable/download/formidable-1.1.1.tgz#96b8886f7c3c3508b932d6bd70c4d3a88f35f1a9"
|
||||
|
||||
fresh@^0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "http://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||
|
||||
fs-extra@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "http://registry.npm.taobao.org/fs-extra/download/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b"
|
||||
dependencies:
|
||||
graceful-fs "^4.1.2"
|
||||
jsonfile "^4.0.0"
|
||||
universalify "^0.1.0"
|
||||
|
||||
getpass@^0.1.1:
|
||||
version "0.1.7"
|
||||
resolved "http://registry.npm.taobao.org/getpass/download/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
|
||||
graceful-fs@^4.1.2, graceful-fs@^4.1.6:
|
||||
version "4.1.11"
|
||||
resolved "http://registry.npm.taobao.org/graceful-fs/download/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658"
|
||||
|
||||
har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "http://registry.npm.taobao.org/har-schema/download/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
|
||||
har-validator@~5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "http://registry.npm.taobao.org/har-validator/download/har-validator-5.1.0.tgz#44657f5688a22cfd4b72486e81b3a3fb11742c29"
|
||||
dependencies:
|
||||
ajv "^5.3.0"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
has-binary2@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "http://registry.npm.taobao.org/has-binary2/download/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d"
|
||||
dependencies:
|
||||
isarray "2.0.1"
|
||||
|
||||
has-cors@1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "http://registry.npm.taobao.org/has-cors/download/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
|
||||
|
||||
http-assert@^1.1.0:
|
||||
version "1.3.0"
|
||||
resolved "http://registry.npm.taobao.org/http-assert/download/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a"
|
||||
dependencies:
|
||||
deep-equal "~1.0.1"
|
||||
http-errors "~1.6.1"
|
||||
|
||||
http-errors@1.6.2, http-errors@^1.2.8, http-errors@^1.6.1, http-errors@~1.6.1, http-errors@~1.6.2:
|
||||
version "1.6.2"
|
||||
resolved "http://registry.npm.taobao.org/http-errors/download/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736"
|
||||
dependencies:
|
||||
depd "1.1.1"
|
||||
inherits "2.0.3"
|
||||
setprototypeof "1.0.3"
|
||||
statuses ">= 1.3.1 < 2"
|
||||
|
||||
http-signature@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "http://registry.npm.taobao.org/http-signature/download/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
iconv-lite@0.4.19:
|
||||
version "0.4.19"
|
||||
resolved "http://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
|
||||
|
||||
indexof@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "http://registry.npm.taobao.org/indexof/download/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
|
||||
|
||||
inflation@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "http://registry.npm.taobao.org/inflation/download/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f"
|
||||
|
||||
inherits@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "http://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
|
||||
is-generator-function@^1.0.3:
|
||||
version "1.0.7"
|
||||
resolved "http://registry.npm.taobao.org/is-generator-function/download/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522"
|
||||
|
||||
is-typedarray@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
|
||||
|
||||
is-wsl@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "http://registry.npm.taobao.org/is-wsl/download/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
||||
|
||||
isarray@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "http://registry.npm.taobao.org/isarray/download/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
|
||||
|
||||
isstream@~0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "http://registry.npm.taobao.org/isstream/download/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
|
||||
|
||||
jsbn@~0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "http://registry.npm.taobao.org/jsbn/download/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
|
||||
json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "http://registry.npm.taobao.org/json-schema-traverse/download/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
||||
|
||||
json-schema@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "http://registry.npm.taobao.org/json-schema/download/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||
|
||||
json-stringify-safe@~5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "http://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||
|
||||
jsonfile@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "http://registry.npm.taobao.org/jsonfile/download/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
|
||||
optionalDependencies:
|
||||
graceful-fs "^4.1.6"
|
||||
|
||||
jsprim@^1.2.2:
|
||||
version "1.4.1"
|
||||
resolved "http://registry.npm.taobao.org/jsprim/download/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
|
||||
dependencies:
|
||||
assert-plus "1.0.0"
|
||||
extsprintf "1.3.0"
|
||||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
keygrip@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "http://registry.npm.taobao.org/keygrip/download/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91"
|
||||
|
||||
koa-body@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "http://registry.npm.taobao.org/koa-body/download/koa-body-2.5.0.tgz#84e8fcd8d5229a8cc1cb98a926e939069e716915"
|
||||
dependencies:
|
||||
co-body "^5.1.1"
|
||||
formidable "^1.1.1"
|
||||
|
||||
koa-compose@^3.0.0:
|
||||
version "3.2.1"
|
||||
resolved "http://registry.npm.taobao.org/koa-compose/download/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7"
|
||||
dependencies:
|
||||
any-promise "^1.1.0"
|
||||
|
||||
koa-compose@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "http://registry.npm.taobao.org/koa-compose/download/koa-compose-4.0.0.tgz#2800a513d9c361ef0d63852b038e4f6f2d5a773c"
|
||||
|
||||
koa-convert@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "http://registry.npm.taobao.org/koa-convert/download/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0"
|
||||
dependencies:
|
||||
co "^4.6.0"
|
||||
koa-compose "^3.0.0"
|
||||
|
||||
koa-is-json@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/koa-is-json/download/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14"
|
||||
|
||||
koa-send@^4.1.0:
|
||||
version "4.1.3"
|
||||
resolved "http://registry.npm.taobao.org/koa-send/download/koa-send-4.1.3.tgz#0822207bbf5253a414c8f1765ebc29fa41353cb6"
|
||||
dependencies:
|
||||
debug "^2.6.3"
|
||||
http-errors "^1.6.1"
|
||||
mz "^2.6.0"
|
||||
resolve-path "^1.4.0"
|
||||
|
||||
koa-static@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "http://registry.npm.taobao.org/koa-static/download/koa-static-4.0.2.tgz#6cda92d88d771dcaad9f0d825cd94a631c861a1a"
|
||||
dependencies:
|
||||
debug "^2.6.8"
|
||||
koa-send "^4.1.0"
|
||||
|
||||
koa@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "http://registry.npm.taobao.org/koa/download/koa-2.4.1.tgz#d449cfb970a7e9da571f699eda40bb9e32eb1484"
|
||||
dependencies:
|
||||
accepts "^1.2.2"
|
||||
content-disposition "~0.5.0"
|
||||
content-type "^1.0.0"
|
||||
cookies "~0.7.0"
|
||||
debug "*"
|
||||
delegates "^1.0.0"
|
||||
depd "^1.1.0"
|
||||
destroy "^1.0.3"
|
||||
error-inject "~1.0.0"
|
||||
escape-html "~1.0.1"
|
||||
fresh "^0.5.2"
|
||||
http-assert "^1.1.0"
|
||||
http-errors "^1.2.8"
|
||||
is-generator-function "^1.0.3"
|
||||
koa-compose "^4.0.0"
|
||||
koa-convert "^1.2.0"
|
||||
koa-is-json "^1.0.0"
|
||||
mime-types "^2.0.7"
|
||||
on-finished "^2.1.0"
|
||||
only "0.0.2"
|
||||
parseurl "^1.3.0"
|
||||
statuses "^1.2.0"
|
||||
type-is "^1.5.5"
|
||||
vary "^1.0.0"
|
||||
|
||||
media-typer@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "http://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
|
||||
mime-db@~1.30.0:
|
||||
version "1.30.0"
|
||||
resolved "http://registry.npm.taobao.org/mime-db/download/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
|
||||
|
||||
mime-db@~1.35.0:
|
||||
version "1.35.0"
|
||||
resolved "http://registry.npm.taobao.org/mime-db/download/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47"
|
||||
|
||||
mime-db@~1.37.0:
|
||||
version "1.37.0"
|
||||
resolved "http://registry.npm.taobao.org/mime-db/download/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8"
|
||||
|
||||
mime-types@^2.0.7, mime-types@~2.1.15, mime-types@~2.1.16:
|
||||
version "2.1.17"
|
||||
resolved "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a"
|
||||
dependencies:
|
||||
mime-db "~1.30.0"
|
||||
|
||||
mime-types@^2.1.12, mime-types@~2.1.19:
|
||||
version "2.1.19"
|
||||
resolved "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0"
|
||||
dependencies:
|
||||
mime-db "~1.35.0"
|
||||
|
||||
mime-types@~2.1.18:
|
||||
version "2.1.21"
|
||||
resolved "http://registry.npm.taobao.org/mime-types/download/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96"
|
||||
dependencies:
|
||||
mime-db "~1.37.0"
|
||||
|
||||
mime@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "http://registry.npm.taobao.org/mime/download/mime-2.2.0.tgz#161e541965551d3b549fa1114391e3a3d55b923b"
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "http://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
|
||||
ms@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "http://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
|
||||
|
||||
mz@^2.6.0:
|
||||
version "2.7.0"
|
||||
resolved "http://registry.npm.taobao.org/mz/download/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
object-assign "^4.0.1"
|
||||
thenify-all "^1.0.0"
|
||||
|
||||
nan@2.12.1:
|
||||
version "2.12.1"
|
||||
resolved "http://registry.npm.taobao.org/nan/download/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552"
|
||||
|
||||
natural-orderby@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "http://registry.npm.taobao.org/natural-orderby/download/natural-orderby-1.0.2.tgz#287a4778217fbf6af0d704129d55ae90450f7a88"
|
||||
|
||||
negotiator@0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "http://registry.npm.taobao.org/negotiator/download/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
|
||||
|
||||
node-nailgun-client@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "http://registry.npm.taobao.org/node-nailgun-client/download/node-nailgun-client-0.1.0.tgz#b6424db0603781a193f367385e2d615ca6df20b2"
|
||||
dependencies:
|
||||
commander "^2.8.1"
|
||||
|
||||
node-nailgun-server@^0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "http://registry.npm.taobao.org/node-nailgun-server/download/node-nailgun-server-0.1.3.tgz#a650918e48615c8d7c4d2393db67316e5ad012f1"
|
||||
dependencies:
|
||||
commander "^2.8.1"
|
||||
|
||||
node-plantuml@^0.6.2:
|
||||
version "0.6.2"
|
||||
resolved "http://registry.npm.taobao.org/node-plantuml/download/node-plantuml-0.6.2.tgz#cf159fe5bc028a54d5181e2410309266d1fde617"
|
||||
dependencies:
|
||||
commander "^2.8.1"
|
||||
node-nailgun-client "^0.1.0"
|
||||
node-nailgun-server "^0.1.3"
|
||||
plantuml-encoder "^1.2.5"
|
||||
|
||||
node-pty@^0.8.1:
|
||||
version "0.8.1"
|
||||
resolved "http://registry.npm.taobao.org/node-pty/download/node-pty-0.8.1.tgz#94b457bec013e7a09b8d9141f63b0787fa25c23f"
|
||||
dependencies:
|
||||
nan "2.12.1"
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "http://registry.npm.taobao.org/oauth-sign/download/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
|
||||
object-assign@^4.0.1:
|
||||
version "4.1.1"
|
||||
resolved "http://registry.npm.taobao.org/object-assign/download/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
object-component@0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "http://registry.npm.taobao.org/object-component/download/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
|
||||
|
||||
on-finished@^2.1.0:
|
||||
version "2.3.0"
|
||||
resolved "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
|
||||
dependencies:
|
||||
ee-first "1.1.1"
|
||||
|
||||
only@0.0.2:
|
||||
version "0.0.2"
|
||||
resolved "http://registry.npm.taobao.org/only/download/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4"
|
||||
|
||||
opn@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "http://registry.npm.taobao.org/opn/download/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c"
|
||||
dependencies:
|
||||
is-wsl "^1.1.0"
|
||||
|
||||
pako@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "http://registry.npm.taobao.org/pako/download/pako-1.0.3.tgz#5f515b0c6722e1982920ae8005eacb0b7ca73ccf"
|
||||
|
||||
parseqs@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "http://registry.npm.taobao.org/parseqs/download/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
|
||||
dependencies:
|
||||
better-assert "~1.0.0"
|
||||
|
||||
parseuri@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "http://registry.npm.taobao.org/parseuri/download/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
|
||||
dependencies:
|
||||
better-assert "~1.0.0"
|
||||
|
||||
parseurl@^1.3.0:
|
||||
version "1.3.2"
|
||||
resolved "http://registry.npm.taobao.org/parseurl/download/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3"
|
||||
|
||||
path-is-absolute@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "http://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
|
||||
performance-now@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "http://registry.npm.taobao.org/performance-now/download/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
|
||||
plantuml-encoder@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "http://registry.npm.taobao.org/plantuml-encoder/download/plantuml-encoder-1.2.5.tgz#6b8e5b9e1a1dbd88b3fd9fb46f734eec7d44b548"
|
||||
dependencies:
|
||||
pako "1.0.3"
|
||||
utf8-bytes "0.0.1"
|
||||
|
||||
psl@^1.1.24:
|
||||
version "1.1.29"
|
||||
resolved "http://registry.npm.taobao.org/psl/download/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
|
||||
|
||||
punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "http://registry.npm.taobao.org/punycode/download/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
|
||||
qs@^6.4.0:
|
||||
version "6.5.1"
|
||||
resolved "http://registry.npm.taobao.org/qs/download/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "http://registry.npm.taobao.org/qs/download/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
|
||||
raw-body@^2.2.0:
|
||||
version "2.3.2"
|
||||
resolved "http://registry.npm.taobao.org/raw-body/download/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89"
|
||||
dependencies:
|
||||
bytes "3.0.0"
|
||||
http-errors "1.6.2"
|
||||
iconv-lite "0.4.19"
|
||||
unpipe "1.0.0"
|
||||
|
||||
request@^2.88.0:
|
||||
version "2.88.0"
|
||||
resolved "http://registry.npm.taobao.org/request/download/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.0"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.4.3"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
resolve-path@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "http://registry.npm.taobao.org/resolve-path/download/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7"
|
||||
dependencies:
|
||||
http-errors "~1.6.2"
|
||||
path-is-absolute "1.0.1"
|
||||
|
||||
safe-buffer@^5.0.1, safe-buffer@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "http://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
|
||||
safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
version "2.1.2"
|
||||
resolved "http://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
|
||||
setprototypeof@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "http://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
|
||||
|
||||
socket.io-adapter@~1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "http://registry.npm.taobao.org/socket.io-adapter/download/socket.io-adapter-1.1.1.tgz#2a805e8a14d6372124dd9159ad4502f8cb07f06b"
|
||||
|
||||
socket.io-client@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "http://registry.npm.taobao.org/socket.io-client/download/socket.io-client-2.2.0.tgz#84e73ee3c43d5020ccc1a258faeeb9aec2723af7"
|
||||
dependencies:
|
||||
backo2 "1.0.2"
|
||||
base64-arraybuffer "0.1.5"
|
||||
component-bind "1.0.0"
|
||||
component-emitter "1.2.1"
|
||||
debug "~3.1.0"
|
||||
engine.io-client "~3.3.1"
|
||||
has-binary2 "~1.0.2"
|
||||
has-cors "1.1.0"
|
||||
indexof "0.0.1"
|
||||
object-component "0.0.3"
|
||||
parseqs "0.0.5"
|
||||
parseuri "0.0.5"
|
||||
socket.io-parser "~3.3.0"
|
||||
to-array "0.1.4"
|
||||
|
||||
socket.io-parser@~3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "http://registry.npm.taobao.org/socket.io-parser/download/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f"
|
||||
dependencies:
|
||||
component-emitter "1.2.1"
|
||||
debug "~3.1.0"
|
||||
isarray "2.0.1"
|
||||
|
||||
socket.io@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "http://registry.npm.taobao.org/socket.io/download/socket.io-2.2.0.tgz#f0f633161ef6712c972b307598ecd08c9b1b4d5b"
|
||||
dependencies:
|
||||
debug "~4.1.0"
|
||||
engine.io "~3.3.1"
|
||||
has-binary2 "~1.0.2"
|
||||
socket.io-adapter "~1.1.0"
|
||||
socket.io-client "2.2.0"
|
||||
socket.io-parser "~3.3.0"
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.14.2"
|
||||
resolved "http://registry.npm.taobao.org/sshpk/download/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98"
|
||||
dependencies:
|
||||
asn1 "~0.2.3"
|
||||
assert-plus "^1.0.0"
|
||||
dashdash "^1.12.0"
|
||||
getpass "^0.1.1"
|
||||
safer-buffer "^2.0.2"
|
||||
optionalDependencies:
|
||||
bcrypt-pbkdf "^1.0.0"
|
||||
ecc-jsbn "~0.1.1"
|
||||
jsbn "~0.1.0"
|
||||
tweetnacl "~0.14.0"
|
||||
|
||||
"statuses@>= 1.3.1 < 2", statuses@^1.2.0:
|
||||
version "1.4.0"
|
||||
resolved "http://registry.npm.taobao.org/statuses/download/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
||||
|
||||
thenify-all@^1.0.0:
|
||||
version "1.6.0"
|
||||
resolved "http://registry.npm.taobao.org/thenify-all/download/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
|
||||
dependencies:
|
||||
thenify ">= 3.1.0 < 4"
|
||||
|
||||
"thenify@>= 3.1.0 < 4":
|
||||
version "3.3.0"
|
||||
resolved "http://registry.npm.taobao.org/thenify/download/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839"
|
||||
dependencies:
|
||||
any-promise "^1.0.0"
|
||||
|
||||
to-array@0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "http://registry.npm.taobao.org/to-array/download/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
|
||||
|
||||
tough-cookie@~2.4.3:
|
||||
version "2.4.3"
|
||||
resolved "http://registry.npm.taobao.org/tough-cookie/download/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
|
||||
dependencies:
|
||||
psl "^1.1.24"
|
||||
punycode "^1.4.1"
|
||||
|
||||
tunnel-agent@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "http://registry.npm.taobao.org/tunnel-agent/download/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
|
||||
dependencies:
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
version "0.14.5"
|
||||
resolved "http://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
|
||||
type-is@^1.5.5, type-is@^1.6.14:
|
||||
version "1.6.15"
|
||||
resolved "http://registry.npm.taobao.org/type-is/download/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
|
||||
dependencies:
|
||||
media-typer "0.3.0"
|
||||
mime-types "~2.1.15"
|
||||
|
||||
universalify@^0.1.0:
|
||||
version "0.1.2"
|
||||
resolved "http://registry.npm.taobao.org/universalify/download/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
||||
|
||||
unpipe@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "http://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
|
||||
utf8-bytes@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "http://registry.npm.taobao.org/utf8-bytes/download/utf8-bytes-0.0.1.tgz#116b025448c9b500081cdfbf1f4d6c6c37d8837d"
|
||||
|
||||
uuid@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "http://registry.npm.taobao.org/uuid/download/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||
|
||||
vary@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "http://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "http://registry.npm.taobao.org/verror/download/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
|
||||
dependencies:
|
||||
assert-plus "^1.0.0"
|
||||
core-util-is "1.0.2"
|
||||
extsprintf "^1.2.0"
|
||||
|
||||
ws@~6.1.0:
|
||||
version "6.1.3"
|
||||
resolved "http://registry.npm.taobao.org/ws/download/ws-6.1.3.tgz#d2d2e5f0e3c700ef2de89080ebc0ac6e1bf3a72d"
|
||||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
xmlhttprequest-ssl@~1.5.4:
|
||||
version "1.5.5"
|
||||
resolved "http://registry.npm.taobao.org/xmlhttprequest-ssl/download/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e"
|
||||
|
||||
yeast@0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "http://registry.npm.taobao.org/yeast/download/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "npm run build && electron ./dist/app.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.6.1",
|
||||
"electron": "^5.0.6",
|
||||
"ts-node": "^8.3.0",
|
||||
"typescript": "^3.5.3"
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"noImplicitAny": true,
|
||||
"outDir": "./dist",
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
@@ -6,8 +6,8 @@
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint",
|
||||
"dist": "npm run build && cp -r dist/* ../static/",
|
||||
"dist-win": "npm run build && xcopy dist\\* ..\\static\\ /s /e /y"
|
||||
"dist": "npm run build && cp -r ../*.* ../app/static/readme/ && cp -r dist/* ../app/static/",
|
||||
"dist-win": "npm run build && xcopy ..\\*.* ..\\app\\static\\readme\\ /s /e /y && xcopy dist\\* ..\\app\\static\\ /s /e /y"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^2.6.5",
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
import dayjs from 'dayjs'
|
||||
import TurndownService from 'turndown'
|
||||
|
||||
const isElectron = !!(window && window.process && window.process.versions && window.process.versions['electron'])
|
||||
|
||||
const keys = {}
|
||||
|
||||
export default {
|
||||
@@ -19,8 +21,8 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (!(window).require) {
|
||||
let loaderScript = document.createElement('script')
|
||||
if (!(isElectron && window.AMDLoader && window.AMDLoader.global && window.AMDLoader.global.require) || !(window).require) {
|
||||
const loaderScript = document.createElement('script')
|
||||
loaderScript.type = 'text/javascript'
|
||||
loaderScript.src = 'vs/loader.js'
|
||||
loaderScript.addEventListener('load', this.onGotAmdLoader)
|
||||
@@ -50,7 +52,11 @@ export default {
|
||||
}
|
||||
},
|
||||
onGotAmdLoader () {
|
||||
window.require(['vs/editor/editor.main'], () => {
|
||||
const xrequire = isElectron ? window.AMDLoader.global.require : window.require
|
||||
if (isElectron) {
|
||||
xrequire.config({ paths: { 'vs': 'static/vs' } })
|
||||
}
|
||||
xrequire(['vs/editor/editor.main'], () => {
|
||||
this.initMonaco()
|
||||
})
|
||||
},
|
||||
|
||||
@@ -7,15 +7,21 @@
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
|
||||
const isElectron = !!(window && window.process && window.process.versions && window.process.versions['electron'])
|
||||
|
||||
export default {
|
||||
name: 'title-bar',
|
||||
mounted () {
|
||||
window.onbeforeunload = () => {
|
||||
return !this.saved || null
|
||||
if (!isElectron) {
|
||||
window.onbeforeunload = () => {
|
||||
return !this.saved || null
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
window.onbeforeunload = null
|
||||
if (!isElectron) {
|
||||
window.onbeforeunload = null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('app', ['currentFile', 'savedAt', 'previousContent', 'currentContent']),
|
||||
@@ -55,6 +61,12 @@ export default {
|
||||
document.title = val
|
||||
},
|
||||
},
|
||||
saved: {
|
||||
immediate: true,
|
||||
handler (val) {
|
||||
window.documentSaved = val
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -62,7 +62,7 @@ const write = async ({ repo, path }, content, oldHash) => {
|
||||
body: JSON.stringify({ repo, path, content, old_hash: oldHash })
|
||||
})
|
||||
|
||||
return { hash: result.data.hash }
|
||||
return { hash: result.data }
|
||||
}
|
||||
|
||||
const move = async ({ repo, path }, newPath) => {
|
||||
|
||||
@@ -2,11 +2,14 @@ module.exports = {
|
||||
devServer: {
|
||||
port: 8066,
|
||||
proxy: {
|
||||
'/static': {
|
||||
target: 'http://localhost:3044'
|
||||
},
|
||||
'/api': {
|
||||
target: 'http://localhost:3000'
|
||||
target: 'http://localhost:3044'
|
||||
},
|
||||
'/ws': {
|
||||
target: 'http://localhost:3000',
|
||||
target: 'http://localhost:3044',
|
||||
ws: true
|
||||
}
|
||||
}
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"systemParams": "linux-x64-64",
|
||||
"modulesFolders": [],
|
||||
"flags": [],
|
||||
"linkedModules": [],
|
||||
"topLevelPatterns": [],
|
||||
"lockfileEntries": {},
|
||||
"files": [],
|
||||
"artifacts": {}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user