├── .babelrc ├── .electron-vue ├── build.js ├── dev-client.js ├── dev-runner.js ├── webpack.main.config.js ├── webpack.renderer.config.js └── webpack.web.config.js ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmrc ├── .travis.yml ├── LICENSE ├── README.md ├── appveyor.yml ├── build └── icons │ ├── 256x256.png │ ├── icon.icns │ └── icon.ico ├── dist ├── electron │ └── .gitkeep └── web │ └── .gitkeep ├── doc ├── 1.png ├── 10.png ├── 11.png ├── 12.png ├── 13.png ├── 2.png ├── 3.png ├── 4.png ├── 5.png ├── 6.png ├── 7.png ├── 8.png ├── 9.png └── menu.png ├── package.json ├── src ├── index.ejs ├── main │ ├── event │ │ └── portscan.js │ ├── ftp │ │ └── index.js │ ├── http │ │ └── index.js │ ├── index.dev.js │ ├── index.js │ └── proxy │ │ └── index.js └── renderer │ ├── App.vue │ ├── assets │ ├── .gitkeep │ ├── global.css │ └── logo.png │ ├── components │ ├── Deprecated │ │ ├── ColorCard.vue │ │ ├── Doc.vue │ │ ├── Http.vue │ │ └── SSHEmulator.vue │ ├── LandingPage.vue │ ├── LandingPage │ │ └── SystemInformation.vue │ ├── LeftMenu.vue │ ├── MainView.vue │ └── View │ │ ├── AnyProxy.vue │ │ ├── CodeSnippet.vue │ │ ├── Exec.vue │ │ ├── Settings.vue │ │ ├── Str │ │ ├── StrBejson.vue │ │ ├── StrDiff.vue │ │ ├── StrEncode.vue │ │ └── StrQrcode.vue │ │ ├── Sys │ │ ├── FTPServer.vue │ │ ├── HTTPServer.vue │ │ ├── SysPortScan.vue │ │ └── SysProcess.vue │ │ └── Tail.vue │ ├── datastore.js │ ├── main.js │ ├── router │ └── index.js │ ├── store │ ├── index.js │ └── modules │ │ ├── Counter.js │ │ ├── Exec.js │ │ ├── Nav.js │ │ ├── Settings.js │ │ ├── View.js │ │ └── index.js │ └── utils │ ├── bejson.js │ ├── common.js │ ├── difflib.js │ ├── diffview.js │ └── language.json ├── static ├── .gitkeep └── ports.json └── test ├── .eslintrc ├── e2e ├── index.js ├── specs │ └── Launch.spec.js └── utils.js └── unit ├── index.js ├── karma.conf.js └── specs └── LandingPage.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "comments": false, 3 | "env": { 4 | "test": { 5 | "presets": [ 6 | ["env", { 7 | "targets": { "node": 7 } 8 | }], 9 | "stage-0" 10 | ], 11 | "plugins": ["istanbul"] 12 | }, 13 | "main": { 14 | "presets": [ 15 | ["env", { 16 | "targets": { "node": 7 } 17 | }], 18 | "stage-0" 19 | ] 20 | }, 21 | "renderer": { 22 | "presets": [ 23 | ["env", { 24 | "modules": false 25 | }], 26 | "stage-0" 27 | ] 28 | }, 29 | "web": { 30 | "presets": [ 31 | ["env", { 32 | "modules": false 33 | }], 34 | "stage-0" 35 | ] 36 | } 37 | }, 38 | "plugins": ["transform-runtime"] 39 | } 40 | -------------------------------------------------------------------------------- /.electron-vue/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | const { say } = require('cfonts') 6 | const chalk = require('chalk') 7 | const del = require('del') 8 | const { spawn } = require('child_process') 9 | const webpack = require('webpack') 10 | const Multispinner = require('multispinner') 11 | 12 | 13 | const mainConfig = require('./webpack.main.config') 14 | const rendererConfig = require('./webpack.renderer.config') 15 | const webConfig = require('./webpack.web.config') 16 | 17 | const doneLog = chalk.bgGreen.white(' DONE ') + ' ' 18 | const errorLog = chalk.bgRed.white(' ERROR ') + ' ' 19 | const okayLog = chalk.bgBlue.white(' OKAY ') + ' ' 20 | const isCI = process.env.CI || false 21 | 22 | if (process.env.BUILD_TARGET === 'clean') clean() 23 | else if (process.env.BUILD_TARGET === 'web') web() 24 | else build() 25 | 26 | function clean () { 27 | del.sync(['build/*', '!build/icons', '!build/icons/icon.*']) 28 | console.log(`\n${doneLog}\n`) 29 | process.exit() 30 | } 31 | 32 | function build () { 33 | greeting() 34 | 35 | del.sync(['dist/electron/*', '!.gitkeep']) 36 | 37 | const tasks = ['main', 'renderer'] 38 | const m = new Multispinner(tasks, { 39 | preText: 'building', 40 | postText: 'process' 41 | }) 42 | 43 | let results = '' 44 | 45 | m.on('success', () => { 46 | process.stdout.write('\x1B[2J\x1B[0f') 47 | console.log(`\n\n${results}`) 48 | console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`) 49 | process.exit() 50 | }) 51 | 52 | pack(mainConfig).then(result => { 53 | results += result + '\n\n' 54 | m.success('main') 55 | }).catch(err => { 56 | m.error('main') 57 | console.log(`\n ${errorLog}failed to build main process`) 58 | console.error(`\n${err}\n`) 59 | process.exit(1) 60 | }) 61 | 62 | pack(rendererConfig).then(result => { 63 | results += result + '\n\n' 64 | m.success('renderer') 65 | }).catch(err => { 66 | m.error('renderer') 67 | console.log(`\n ${errorLog}failed to build renderer process`) 68 | console.error(`\n${err}\n`) 69 | process.exit(1) 70 | }) 71 | } 72 | 73 | function pack (config) { 74 | return new Promise((resolve, reject) => { 75 | webpack(config, (err, stats) => { 76 | if (err) reject(err.stack || err) 77 | else if (stats.hasErrors()) { 78 | let err = '' 79 | 80 | stats.toString({ 81 | chunks: false, 82 | colors: true 83 | }) 84 | .split(/\r?\n/) 85 | .forEach(line => { 86 | err += ` ${line}\n` 87 | }) 88 | 89 | reject(err) 90 | } else { 91 | resolve(stats.toString({ 92 | chunks: false, 93 | colors: true 94 | })) 95 | } 96 | }) 97 | }) 98 | } 99 | 100 | function web () { 101 | del.sync(['dist/web/*', '!.gitkeep']) 102 | webpack(webConfig, (err, stats) => { 103 | if (err || stats.hasErrors()) console.log(err) 104 | 105 | console.log(stats.toString({ 106 | chunks: false, 107 | colors: true 108 | })) 109 | 110 | process.exit() 111 | }) 112 | } 113 | 114 | function greeting () { 115 | const cols = process.stdout.columns 116 | let text = '' 117 | 118 | if (cols > 85) text = 'lets-build' 119 | else if (cols > 60) text = 'lets-|build' 120 | else text = false 121 | 122 | if (text && !isCI) { 123 | say(text, { 124 | colors: ['yellow'], 125 | font: 'simple3d', 126 | space: false 127 | }) 128 | } else console.log(chalk.yellow.bold('\n lets-build')) 129 | console.log() 130 | } 131 | -------------------------------------------------------------------------------- /.electron-vue/dev-client.js: -------------------------------------------------------------------------------- 1 | const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 2 | 3 | hotClient.subscribe(event => { 4 | /** 5 | * Reload browser when HTMLWebpackPlugin emits a new index.html 6 | * 7 | * Currently disabled until jantimon/html-webpack-plugin#680 is resolved. 8 | * https://github.com/SimulatedGREG/electron-vue/issues/437 9 | * https://github.com/jantimon/html-webpack-plugin/issues/680 10 | */ 11 | // if (event.action === 'reload') { 12 | // window.location.reload() 13 | // } 14 | 15 | /** 16 | * Notify `mainWindow` when `main` process is compiling, 17 | * giving notice for an expected reload of the `electron` process 18 | */ 19 | if (event.action === 'compiling') { 20 | document.body.innerHTML += ` 21 | 34 | 35 |
36 | Compiling Main Process... 37 |
38 | ` 39 | } 40 | }) 41 | -------------------------------------------------------------------------------- /.electron-vue/dev-runner.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const chalk = require('chalk') 4 | const electron = require('electron') 5 | const path = require('path') 6 | const { say } = require('cfonts') 7 | const { spawn } = require('child_process') 8 | const webpack = require('webpack') 9 | const WebpackDevServer = require('webpack-dev-server') 10 | const webpackHotMiddleware = require('webpack-hot-middleware') 11 | 12 | const mainConfig = require('./webpack.main.config') 13 | const rendererConfig = require('./webpack.renderer.config') 14 | 15 | let electronProcess = null 16 | let manualRestart = false 17 | let hotMiddleware 18 | 19 | function logStats (proc, data) { 20 | let log = '' 21 | 22 | log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`) 23 | log += '\n\n' 24 | 25 | if (typeof data === 'object') { 26 | data.toString({ 27 | colors: true, 28 | chunks: false 29 | }).split(/\r?\n/).forEach(line => { 30 | log += ' ' + line + '\n' 31 | }) 32 | } else { 33 | log += ` ${data}\n` 34 | } 35 | 36 | log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n' 37 | 38 | console.log(log) 39 | } 40 | 41 | function startRenderer () { 42 | return new Promise((resolve, reject) => { 43 | rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer) 44 | 45 | const compiler = webpack(rendererConfig) 46 | hotMiddleware = webpackHotMiddleware(compiler, { 47 | log: false, 48 | heartbeat: 2500 49 | }) 50 | 51 | compiler.plugin('compilation', compilation => { 52 | compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => { 53 | hotMiddleware.publish({ action: 'reload' }) 54 | cb() 55 | }) 56 | }) 57 | 58 | compiler.plugin('done', stats => { 59 | logStats('Renderer', stats) 60 | }) 61 | 62 | const server = new WebpackDevServer( 63 | compiler, 64 | { 65 | contentBase: path.join(__dirname, '../'), 66 | quiet: true, 67 | before (app, ctx) { 68 | app.use(hotMiddleware) 69 | ctx.middleware.waitUntilValid(() => { 70 | resolve() 71 | }) 72 | } 73 | } 74 | ) 75 | 76 | server.listen(9080) 77 | }) 78 | } 79 | 80 | function startMain () { 81 | return new Promise((resolve, reject) => { 82 | mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main) 83 | 84 | const compiler = webpack(mainConfig) 85 | 86 | compiler.plugin('watch-run', (compilation, done) => { 87 | logStats('Main', chalk.white.bold('compiling...')) 88 | hotMiddleware.publish({ action: 'compiling' }) 89 | done() 90 | }) 91 | 92 | compiler.watch({}, (err, stats) => { 93 | if (err) { 94 | console.log(err) 95 | return 96 | } 97 | 98 | logStats('Main', stats) 99 | 100 | if (electronProcess && electronProcess.kill) { 101 | manualRestart = true 102 | process.kill(electronProcess.pid) 103 | electronProcess = null 104 | startElectron() 105 | 106 | setTimeout(() => { 107 | manualRestart = false 108 | }, 5000) 109 | } 110 | 111 | resolve() 112 | }) 113 | }) 114 | } 115 | 116 | function startElectron () { 117 | electronProcess = spawn(electron, ['--inspect=5858', path.join(__dirname, '../dist/electron/main.js')]) 118 | 119 | electronProcess.stdout.on('data', data => { 120 | electronLog(data, 'blue') 121 | }) 122 | electronProcess.stderr.on('data', data => { 123 | electronLog(data, 'red') 124 | }) 125 | 126 | electronProcess.on('close', () => { 127 | if (!manualRestart) process.exit() 128 | }) 129 | } 130 | 131 | function electronLog (data, color) { 132 | let log = '' 133 | data = data.toString().split(/\r?\n/) 134 | data.forEach(line => { 135 | log += ` ${line}\n` 136 | }) 137 | if (/[0-9A-z]+/.test(log)) { 138 | console.log( 139 | chalk[color].bold('┏ Electron -------------------') + 140 | '\n\n' + 141 | log + 142 | chalk[color].bold('┗ ----------------------------') + 143 | '\n' 144 | ) 145 | } 146 | } 147 | 148 | function greeting () { 149 | const cols = process.stdout.columns 150 | let text = '' 151 | 152 | if (cols > 104) text = 'electron-vue' 153 | else if (cols > 76) text = 'electron-|vue' 154 | else text = false 155 | 156 | if (text) { 157 | say(text, { 158 | colors: ['yellow'], 159 | font: 'simple3d', 160 | space: false 161 | }) 162 | } else console.log(chalk.yellow.bold('\n electron-vue')) 163 | console.log(chalk.blue(' getting ready...') + '\n') 164 | } 165 | 166 | function init () { 167 | greeting() 168 | 169 | Promise.all([startRenderer(), startMain()]) 170 | .then(() => { 171 | startElectron() 172 | }) 173 | .catch(err => { 174 | console.error(err) 175 | }) 176 | } 177 | 178 | init() 179 | -------------------------------------------------------------------------------- /.electron-vue/webpack.main.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'main' 4 | 5 | const path = require('path') 6 | const { dependencies } = require('../package.json') 7 | const webpack = require('webpack') 8 | 9 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 10 | 11 | let mainConfig = { 12 | entry: { 13 | main: path.join(__dirname, '../src/main/index.js') 14 | }, 15 | externals: [ 16 | ...Object.keys(dependencies || {}) 17 | ], 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.(js)$/, 22 | enforce: 'pre', 23 | exclude: /node_modules/, 24 | use: { 25 | loader: 'eslint-loader', 26 | options: { 27 | formatter: require('eslint-friendly-formatter') 28 | } 29 | } 30 | }, 31 | { 32 | test: /\.js$/, 33 | use: 'babel-loader', 34 | exclude: /node_modules/ 35 | }, 36 | { 37 | test: /\.node$/, 38 | use: 'node-loader' 39 | } 40 | ] 41 | }, 42 | node: { 43 | __dirname: process.env.NODE_ENV !== 'production', 44 | __filename: process.env.NODE_ENV !== 'production' 45 | }, 46 | output: { 47 | filename: '[name].js', 48 | libraryTarget: 'commonjs2', 49 | path: path.join(__dirname, '../dist/electron') 50 | }, 51 | plugins: [ 52 | new webpack.NoEmitOnErrorsPlugin() 53 | ], 54 | resolve: { 55 | extensions: ['.js', '.json', '.node'] 56 | }, 57 | target: 'electron-main' 58 | } 59 | 60 | /** 61 | * Adjust mainConfig for development settings 62 | */ 63 | if (process.env.NODE_ENV !== 'production') { 64 | mainConfig.plugins.push( 65 | new webpack.DefinePlugin({ 66 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 67 | }) 68 | ) 69 | } 70 | 71 | /** 72 | * Adjust mainConfig for production settings 73 | */ 74 | if (process.env.NODE_ENV === 'production') { 75 | mainConfig.plugins.push( 76 | new BabiliWebpackPlugin(), 77 | new webpack.DefinePlugin({ 78 | 'process.env.NODE_ENV': '"production"' 79 | }) 80 | ) 81 | } 82 | 83 | module.exports = mainConfig 84 | -------------------------------------------------------------------------------- /.electron-vue/webpack.renderer.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'renderer' 4 | 5 | const path = require('path') 6 | const { dependencies } = require('../package.json') 7 | const webpack = require('webpack') 8 | 9 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 10 | const CopyWebpackPlugin = require('copy-webpack-plugin') 11 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 12 | const HtmlWebpackPlugin = require('html-webpack-plugin') 13 | 14 | /** 15 | * List of node_modules to include in webpack bundle 16 | * 17 | * Required for specific packages like Vue UI libraries 18 | * that provide pure *.vue files that need compiling 19 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals 20 | */ 21 | let whiteListedModules = ['vue'] 22 | 23 | let rendererConfig = { 24 | devtool: '#cheap-module-eval-source-map', 25 | entry: { 26 | renderer: path.join(__dirname, '../src/renderer/main.js') 27 | }, 28 | externals: [ 29 | ...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d)) 30 | ], 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.(js|vue)$/, 35 | enforce: 'pre', 36 | exclude: /node_modules/, 37 | use: { 38 | loader: 'eslint-loader', 39 | options: { 40 | formatter: require('eslint-friendly-formatter') 41 | } 42 | } 43 | }, 44 | { 45 | test: /\.css$/, 46 | use: ExtractTextPlugin.extract({ 47 | fallback: 'style-loader', 48 | use: 'css-loader' 49 | }) 50 | }, 51 | { 52 | test: /\.html$/, 53 | use: 'vue-html-loader' 54 | }, 55 | { 56 | test: /\.js$/, 57 | use: 'babel-loader', 58 | exclude: /node_modules/ 59 | }, 60 | { 61 | test: /\.node$/, 62 | use: 'node-loader' 63 | }, 64 | { 65 | test: /\.vue$/, 66 | use: { 67 | loader: 'vue-loader', 68 | options: { 69 | extractCSS: process.env.NODE_ENV === 'production', 70 | loaders: { 71 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 72 | scss: 'vue-style-loader!css-loader!sass-loader' 73 | } 74 | } 75 | } 76 | }, 77 | { 78 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 79 | use: { 80 | loader: 'url-loader', 81 | query: { 82 | limit: 10000, 83 | name: 'imgs/[name]--[folder].[ext]' 84 | } 85 | } 86 | }, 87 | { 88 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 89 | loader: 'url-loader', 90 | options: { 91 | limit: 10000, 92 | name: 'media/[name]--[folder].[ext]' 93 | } 94 | }, 95 | { 96 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 97 | use: { 98 | loader: 'url-loader', 99 | query: { 100 | limit: 10000, 101 | name: 'fonts/[name]--[folder].[ext]' 102 | } 103 | } 104 | } 105 | ] 106 | }, 107 | node: { 108 | __dirname: process.env.NODE_ENV !== 'production', 109 | __filename: process.env.NODE_ENV !== 'production' 110 | }, 111 | plugins: [ 112 | new ExtractTextPlugin('styles.css'), 113 | new HtmlWebpackPlugin({ 114 | filename: 'index.html', 115 | template: path.resolve(__dirname, '../src/index.ejs'), 116 | minify: { 117 | collapseWhitespace: true, 118 | removeAttributeQuotes: true, 119 | removeComments: true 120 | }, 121 | nodeModules: process.env.NODE_ENV !== 'production' 122 | ? path.resolve(__dirname, '../node_modules') 123 | : false 124 | }), 125 | new webpack.HotModuleReplacementPlugin(), 126 | new webpack.NoEmitOnErrorsPlugin() 127 | ], 128 | output: { 129 | filename: '[name].js', 130 | libraryTarget: 'commonjs2', 131 | path: path.join(__dirname, '../dist/electron') 132 | }, 133 | resolve: { 134 | alias: { 135 | '@': path.join(__dirname, '../src/renderer'), 136 | 'vue$': 'vue/dist/vue.esm.js' 137 | }, 138 | extensions: ['.js', '.vue', '.json', '.css', '.node'] 139 | }, 140 | target: 'electron-renderer' 141 | } 142 | 143 | /** 144 | * Adjust rendererConfig for development settings 145 | */ 146 | if (process.env.NODE_ENV !== 'production') { 147 | rendererConfig.plugins.push( 148 | new webpack.DefinePlugin({ 149 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 150 | }) 151 | ) 152 | } 153 | 154 | /** 155 | * Adjust rendererConfig for production settings 156 | */ 157 | if (process.env.NODE_ENV === 'production') { 158 | rendererConfig.devtool = '' 159 | 160 | rendererConfig.plugins.push( 161 | new BabiliWebpackPlugin(), 162 | new CopyWebpackPlugin([ 163 | { 164 | from: path.join(__dirname, '../static'), 165 | to: path.join(__dirname, '../dist/electron/static'), 166 | ignore: ['.*'] 167 | } 168 | ]), 169 | new webpack.DefinePlugin({ 170 | 'process.env.NODE_ENV': '"production"' 171 | }), 172 | new webpack.LoaderOptionsPlugin({ 173 | minimize: true 174 | }) 175 | ) 176 | } 177 | 178 | module.exports = rendererConfig 179 | -------------------------------------------------------------------------------- /.electron-vue/webpack.web.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'web' 4 | 5 | const path = require('path') 6 | const webpack = require('webpack') 7 | 8 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 9 | const CopyWebpackPlugin = require('copy-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const HtmlWebpackPlugin = require('html-webpack-plugin') 12 | 13 | let webConfig = { 14 | devtool: '#cheap-module-eval-source-map', 15 | entry: { 16 | web: path.join(__dirname, '../src/renderer/main.js') 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.(js|vue)$/, 22 | enforce: 'pre', 23 | exclude: /node_modules/, 24 | use: { 25 | loader: 'eslint-loader', 26 | options: { 27 | formatter: require('eslint-friendly-formatter') 28 | } 29 | } 30 | }, 31 | { 32 | test: /\.css$/, 33 | use: ExtractTextPlugin.extract({ 34 | fallback: 'style-loader', 35 | use: 'css-loader' 36 | }) 37 | }, 38 | { 39 | test: /\.html$/, 40 | use: 'vue-html-loader' 41 | }, 42 | { 43 | test: /\.js$/, 44 | use: 'babel-loader', 45 | include: [ path.resolve(__dirname, '../src/renderer') ], 46 | exclude: /node_modules/ 47 | }, 48 | { 49 | test: /\.vue$/, 50 | use: { 51 | loader: 'vue-loader', 52 | options: { 53 | extractCSS: true, 54 | loaders: { 55 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 56 | scss: 'vue-style-loader!css-loader!sass-loader' 57 | } 58 | } 59 | } 60 | }, 61 | { 62 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 63 | use: { 64 | loader: 'url-loader', 65 | query: { 66 | limit: 10000, 67 | name: 'imgs/[name].[ext]' 68 | } 69 | } 70 | }, 71 | { 72 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 73 | use: { 74 | loader: 'url-loader', 75 | query: { 76 | limit: 10000, 77 | name: 'fonts/[name].[ext]' 78 | } 79 | } 80 | } 81 | ] 82 | }, 83 | plugins: [ 84 | new ExtractTextPlugin('styles.css'), 85 | new HtmlWebpackPlugin({ 86 | filename: 'index.html', 87 | template: path.resolve(__dirname, '../src/index.ejs'), 88 | minify: { 89 | collapseWhitespace: true, 90 | removeAttributeQuotes: true, 91 | removeComments: true 92 | }, 93 | nodeModules: false 94 | }), 95 | new webpack.DefinePlugin({ 96 | 'process.env.IS_WEB': 'true' 97 | }), 98 | new webpack.HotModuleReplacementPlugin(), 99 | new webpack.NoEmitOnErrorsPlugin() 100 | ], 101 | output: { 102 | filename: '[name].js', 103 | path: path.join(__dirname, '../dist/web') 104 | }, 105 | resolve: { 106 | alias: { 107 | '@': path.join(__dirname, '../src/renderer'), 108 | 'vue$': 'vue/dist/vue.esm.js' 109 | }, 110 | extensions: ['.js', '.vue', '.json', '.css'] 111 | }, 112 | target: 'web' 113 | } 114 | 115 | /** 116 | * Adjust webConfig for production settings 117 | */ 118 | if (process.env.NODE_ENV === 'production') { 119 | webConfig.devtool = '' 120 | 121 | webConfig.plugins.push( 122 | new BabiliWebpackPlugin(), 123 | new CopyWebpackPlugin([ 124 | { 125 | from: path.join(__dirname, '../static'), 126 | to: path.join(__dirname, '../dist/web/static'), 127 | ignore: ['.*'] 128 | } 129 | ]), 130 | new webpack.DefinePlugin({ 131 | 'process.env.NODE_ENV': '"production"' 132 | }), 133 | new webpack.LoaderOptionsPlugin({ 134 | minimize: true 135 | }) 136 | ) 137 | } 138 | 139 | module.exports = webConfig 140 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/unit/coverage/** 2 | test/unit/*.js 3 | test/e2e/*.js 4 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | env: { 8 | browser: true, 9 | node: true 10 | }, 11 | extends: 'standard', 12 | globals: { 13 | __static: true 14 | }, 15 | plugins: [ 16 | 'html' 17 | ], 18 | 'rules': { 19 | // allow paren-less arrow functions 20 | 'arrow-parens': 0, 21 | // allow async-await 22 | 'generator-star-spacing': 0, 23 | // allow debugger during development 24 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist/electron/* 3 | dist/web/* 4 | build/* 5 | !build/icons 6 | coverage 7 | node_modules/ 8 | npm-debug.log 9 | npm-debug.log.* 10 | thumbs.db 11 | !.gitkeep 12 | package-lock.json 13 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npm.taobao.org 2 | chromedriver_cdnurl=http://npm.taobao.org/mirrors/chromedriver/ 3 | selenium_cdnurl=http://npm.taobao.org/mirrorss/selenium/ 4 | phantomjs_cdnurl=http://npm.taobao.org/mirrors/phantomjs/ 5 | electron_mirror=https://npm.taobao.org/mirrors/electron/ 6 | disturl=http://npm.taobao.org/mirrors/node 7 | sass_binary_site=https://cdn.npm.taobao.org/dist/node-sass/ 8 | operadriver_cdnurl=https://cdn.npm.taobao.org/dist/operadriver/ 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Commented sections below can be used to run tests on the CI server 2 | # https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing 3 | osx_image: xcode8.3 4 | sudo: required 5 | dist: trusty 6 | language: c 7 | matrix: 8 | include: 9 | - os: osx 10 | - os: linux 11 | env: CC=clang CXX=clang++ npm_config_clang=1 12 | compiler: clang 13 | cache: 14 | directories: 15 | - node_modules 16 | - "$HOME/.electron" 17 | - "$HOME/.cache" 18 | addons: 19 | apt: 20 | packages: 21 | - libgnome-keyring-dev 22 | - icnsutils 23 | #- xvfb 24 | before_install: 25 | - mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v1.2.1/git-lfs-$([ 26 | "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-1.2.1.tar.gz 27 | | tar -xz -C /tmp/git-lfs --strip-components 1 && /tmp/git-lfs/git-lfs pull 28 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y icnsutils graphicsmagick xz-utils; fi 29 | install: 30 | #- export DISPLAY=':99.0' 31 | #- Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 32 | - nvm install 7 33 | - curl -o- -L https://yarnpkg.com/install.sh | bash 34 | - source ~/.bashrc 35 | - npm install -g xvfb-maybe 36 | - yarn 37 | script: 38 | #- xvfb-maybe node_modules/.bin/karma start test/unit/karma.conf.js 39 | #- yarn run pack && xvfb-maybe node_modules/.bin/mocha test/e2e 40 | - yarn run build 41 | branches: 42 | only: 43 | - master 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 moonrailgun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # devbox 2 | 3 | > 一款集成程序员常用软件的工具箱应用 4 | 5 | [![Release](https://img.shields.io/github/release/moonrailgun/devbox.svg)](https://github.com/moonrailgun/devbox/releases) 6 | [![Downloads](https://img.shields.io/github/downloads/moonrailgun/devbox/total.svg)](https://github.com/moonrailgun/devbox/releases) 7 | [![Build status](https://ci.appveyor.com/api/projects/status/ygyjp75eg9tfruxw?svg=true)](https://ci.appveyor.com/project/moonrailgun/devbox) 8 | 9 | [稳定版下载](https://github.com/moonrailgun/devbox/releases) 10 | 11 | ## 功能模块 12 | 13 | - [x] [代码片段](#代码片段) 14 | - [x] [命令脚本](#命令脚本) 15 | - [x] [日志监控](#日志监控) 16 | - [x] [代理抓包](#代理抓包) 17 | - 常用工具 18 | - 文本处理 19 | - [x] [加密解密](#加密解密) 20 | - [x] [文本比较](#文本比较) 21 | - [x] [二维码生成](#二维码生成) 22 | - [x] [JSON校验](#JSON校验) 23 | - 系统相关 24 | - [x] [系统进程](#系统进程) 25 | - [x] [端口扫描](#端口扫描) 26 | - [x] [HTTP服务](#HTTP服务) 27 | - [x] [FTP服务](#FTP服务) 28 | - [x] 系统设置 29 | 30 | ![](./doc/menu.png) 31 | 32 | ## 编译步骤 33 | 34 | ``` bash 35 | # install dependencies 36 | npm install 37 | 38 | # serve with hot reload at localhost:9080 39 | npm run dev 40 | 41 | # build electron application for production 42 | npm run build 43 | # or npm run build:dir 44 | 45 | # run unit & end-to-end tests 46 | npm test 47 | 48 | 49 | # lint all JS/Vue component files in `src/` 50 | npm run lint 51 | 52 | ``` 53 | 54 | ## 功能描述 55 | 56 | #### 代码片段 57 | 58 | 一个代码片段的管理应用部件, 用户创建、编辑、保存、管理用户的一些常用代码片段。 59 | 60 | - [x] 片段命名 61 | - [x] 片段选择语言与自定义语言 62 | - [x] 片段预览 63 | - [x] 片段编辑 64 | - [x] 片段保存 65 | - [x] 片段添加到剪切板 66 | 67 | ![](./doc/1.png) 68 | ![](./doc/2.png) 69 | 70 | #### 命令脚本 71 | 72 | 一个管理常用命令的部件,支持自定义变量 73 | 编辑后记得点击保存按钮保存变更 74 | 75 | - [x] 添加命令 76 | - [x] 定义工作空间 77 | - [x] 定义变量空间 78 | - [x] 删除命令 79 | - [x] 运行命令 80 | - [x] 保存命令 81 | 82 | ![](./doc/4.png) 83 | ![](./doc/3.png) 84 | 85 | #### 日志监控 86 | 87 | 一个用户监控日志文件修改的应用,可以最高同时监控三个文件 88 | 因为过多的日志记录会使应用较为卡顿因此设定最大保留日志行数(默认为1000行) 89 | 90 | ![](./doc/5.png) 91 | 92 | #### 代理抓包 93 | 94 | 详见 [AnyProxy](https://github.com/alibaba/anyproxy) 95 | 默认端口: 96 | > 代理服务:`8001` 97 | > 网页服务:`8002` 98 | 99 | #### 加密解密 100 | 101 | 加密/解密字符串的各种算法格式,目前支持的算法有如下几种常见的算法: 102 | - `Unicode` 103 | - `UTF-8` 104 | - `URI` 105 | - `Base64` 106 | - `MD5` 107 | - `SHA1` 108 | - `AES`(需要提供秘钥) 109 | 110 | ![](./doc/6.png) 111 | 112 | #### 文本比较 113 | 114 | 快速比较两段文字的差异,高亮形式表现出差异段落 115 | 116 | ![](./doc/7.png) 117 | 118 | #### 二维码生成 119 | 120 | 快速生成二维码 121 | 常用于生成网页到手机端 122 | 123 | ![](./doc/8.png) 124 | 125 | #### JSON校验 126 | 用于JSON校验, 可以格式化不正确的JSON格式的字符串, 并指出不正确的地方 127 | 也可以用于美化JSON字符串 128 | 129 | ![](./doc/9.png) 130 | 131 | #### 系统进程 132 | 列出系统进程的: 133 | - 进程名 134 | - pid 135 | - 命令 136 | - cpu占用 137 | 138 | 并支持过滤匹配项, 与列表排序 139 | 140 | ![](./doc/10.png) 141 | 142 | #### 端口扫描 143 | 扫描目标ip(域名)监听的tcp端口 144 | 用法: 145 | - `127.0.0.1` 扫描本地所有的端口情况(1~65535) 146 | - `127.0.0.1:22` 扫描本地22端口情况 147 | 148 | ![](./doc/11.png) 149 | 150 | #### HTTP服务 151 | 开放一个简易的静态http服务, 用于局域网快速共享前端网页。但因为没有解释器所以不能运行动态脚本 152 | 153 | ![](./doc/12.png) 154 | 155 | #### FTP服务 156 | 开放一个简易的ftp服务,用于局域网快速共享文件 157 | 如果无法正常列出目录, 请尝试手动指定为主动模式 158 | 159 | ![](./doc/13.png) 160 | 161 | --- 162 | 163 | This project was generated with [electron-vue](https://github.com/SimulatedGREG/electron-vue) using [vue-cli](https://github.com/vuejs/vue-cli). Documentation about the original structure can be found [here](https://simulatedgreg.gitbooks.io/electron-vue/content/index.html). 164 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Commented sections below can be used to run tests on the CI server 2 | # https://simulatedgreg.gitbooks.io/electron-vue/content/en/testing.html#on-the-subject-of-ci-testing 3 | version: 0.1.{build} 4 | 5 | branches: 6 | only: 7 | - master 8 | 9 | image: Visual Studio 2017 10 | platform: 11 | - x64 12 | 13 | cache: 14 | - node_modules 15 | - '%APPDATA%\npm-cache' 16 | - '%USERPROFILE%\.electron' 17 | - '%USERPROFILE%\AppData\Local\Yarn\cache' 18 | 19 | init: 20 | - git config --global core.autocrlf input 21 | 22 | install: 23 | - ps: Install-Product node 8 x64 24 | - choco install yarn --ignore-dependencies 25 | - git reset --hard HEAD 26 | - yarn 27 | - node --version 28 | 29 | build_script: 30 | #- yarn test 31 | - yarn build 32 | 33 | test: off 34 | 35 | artifacts: 36 | - path: build/* 37 | -------------------------------------------------------------------------------- /build/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/build/icons/256x256.png -------------------------------------------------------------------------------- /build/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/build/icons/icon.icns -------------------------------------------------------------------------------- /build/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/build/icons/icon.ico -------------------------------------------------------------------------------- /dist/electron/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/dist/electron/.gitkeep -------------------------------------------------------------------------------- /dist/web/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/dist/web/.gitkeep -------------------------------------------------------------------------------- /doc/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/1.png -------------------------------------------------------------------------------- /doc/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/10.png -------------------------------------------------------------------------------- /doc/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/11.png -------------------------------------------------------------------------------- /doc/12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/12.png -------------------------------------------------------------------------------- /doc/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/13.png -------------------------------------------------------------------------------- /doc/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/2.png -------------------------------------------------------------------------------- /doc/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/3.png -------------------------------------------------------------------------------- /doc/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/4.png -------------------------------------------------------------------------------- /doc/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/5.png -------------------------------------------------------------------------------- /doc/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/6.png -------------------------------------------------------------------------------- /doc/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/7.png -------------------------------------------------------------------------------- /doc/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/8.png -------------------------------------------------------------------------------- /doc/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/9.png -------------------------------------------------------------------------------- /doc/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/doc/menu.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devbox", 3 | "version": "1.1.1", 4 | "author": "moonrailgun", 5 | "description": "An electron-vue project", 6 | "license": null, 7 | "main": "./dist/electron/main.js", 8 | "scripts": { 9 | "build": "node .electron-vue/build.js && electron-builder", 10 | "build:dir": "node .electron-vue/build.js && electron-builder --dir", 11 | "build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js", 12 | "build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js", 13 | "dev": "node .electron-vue/dev-runner.js", 14 | "e2e": "npm run pack && mocha test/e2e", 15 | "lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src test", 16 | "lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter --fix src test", 17 | "pack": "npm run pack:main && npm run pack:renderer", 18 | "pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js", 19 | "pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js", 20 | "test": "npm run unit && npm run e2e", 21 | "unit": "karma start test/unit/karma.conf.js", 22 | "postinstall": "npm run lint:fix" 23 | }, 24 | "build": { 25 | "productName": "devbox", 26 | "appId": "com.moonrailgun.devbox", 27 | "directories": { 28 | "output": "build" 29 | }, 30 | "files": [ 31 | "dist/electron/**/*" 32 | ], 33 | "dmg": { 34 | "contents": [ 35 | { 36 | "x": 410, 37 | "y": 150, 38 | "type": "link", 39 | "path": "/Applications" 40 | }, 41 | { 42 | "x": 130, 43 | "y": 150, 44 | "type": "file" 45 | } 46 | ] 47 | }, 48 | "mac": { 49 | "icon": "build/icons/icon.icns" 50 | }, 51 | "win": { 52 | "icon": "build/icons/icon.ico" 53 | }, 54 | "linux": { 55 | "icon": "build/icons" 56 | } 57 | }, 58 | "dependencies": { 59 | "anyproxy": "^4.0.6", 60 | "axios": "^0.16.1", 61 | "crypto-js": "^3.1.9-1", 62 | "electron-log": "^2.2.14", 63 | "element-ui": "^2.3.3", 64 | "execa": "^0.10.0", 65 | "fs-extra": "^5.0.0", 66 | "ftp-srv": "^2.16.1", 67 | "html2canvas": "^1.0.0-alpha.10", 68 | "http-server": "^0.11.1", 69 | "lodash.debounce": "^4.0.8", 70 | "nedb": "^1.8.0", 71 | "port-numbers": "^2.0.26", 72 | "ps-list": "^4.0.0", 73 | "qrcode": "^1.2.0", 74 | "string-to-color": "^2.0.0", 75 | "tail": "^1.2.3", 76 | "vue": "^2.3.3", 77 | "vue-codemirror": "^4.0.3", 78 | "vue-electron": "^1.0.6", 79 | "vue-router": "^2.5.3", 80 | "vuex": "^2.3.1", 81 | "vuex-persist": "^1.1.1" 82 | }, 83 | "devDependencies": { 84 | "babel-core": "^6.25.0", 85 | "babel-loader": "^7.1.1", 86 | "babel-plugin-transform-runtime": "^6.23.0", 87 | "babel-preset-env": "^1.6.0", 88 | "babel-preset-stage-0": "^6.24.1", 89 | "babel-register": "^6.24.1", 90 | "babili-webpack-plugin": "^0.1.2", 91 | "cfonts": "^1.1.3", 92 | "chalk": "^2.1.0", 93 | "copy-webpack-plugin": "^4.0.1", 94 | "cross-env": "^5.0.5", 95 | "css-loader": "^0.28.4", 96 | "del": "^3.0.0", 97 | "devtron": "^1.4.0", 98 | "electron": "^1.7.5", 99 | "electron-debug": "^1.4.0", 100 | "electron-devtools-installer": "^2.2.0", 101 | "electron-builder": "^19.19.1", 102 | "babel-eslint": "^7.2.3", 103 | "eslint": "^4.4.1", 104 | "eslint-friendly-formatter": "^3.0.0", 105 | "eslint-loader": "^1.9.0", 106 | "eslint-plugin-html": "^3.1.1", 107 | "eslint-config-standard": "^10.2.1", 108 | "eslint-plugin-import": "^2.7.0", 109 | "eslint-plugin-node": "^5.1.1", 110 | "eslint-plugin-promise": "^3.5.0", 111 | "eslint-plugin-standard": "^3.0.1", 112 | "extract-text-webpack-plugin": "^3.0.0", 113 | "file-loader": "^0.11.2", 114 | "html-webpack-plugin": "^2.30.1", 115 | "inject-loader": "^3.0.0", 116 | "karma": "^1.3.0", 117 | "karma-chai": "^0.1.0", 118 | "karma-coverage": "^1.1.1", 119 | "karma-electron": "^5.1.1", 120 | "karma-mocha": "^1.2.0", 121 | "karma-sourcemap-loader": "^0.3.7", 122 | "karma-spec-reporter": "^0.0.31", 123 | "karma-webpack": "^2.0.1", 124 | "webpack-merge": "^4.1.0", 125 | "require-dir": "^0.3.0", 126 | "spectron": "^3.7.1", 127 | "babel-plugin-istanbul": "^4.1.1", 128 | "chai": "^4.0.0", 129 | "mocha": "^3.0.2", 130 | "multispinner": "^0.2.1", 131 | "node-loader": "^0.6.0", 132 | "style-loader": "^0.18.2", 133 | "url-loader": "^0.5.9", 134 | "vue-html-loader": "^1.2.4", 135 | "vue-loader": "^13.0.5", 136 | "vue-style-loader": "^3.0.1", 137 | "vue-template-compiler": "^2.4.2", 138 | "webpack": "^3.5.2", 139 | "webpack-dev-server": "^2.7.1", 140 | "webpack-hot-middleware": "^2.18.2" 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | devbox 6 | <% if (htmlWebpackPlugin.options.nodeModules) { %> 7 | 8 | 11 | <% } %> 12 | 13 | 14 |
15 | 16 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/event/portscan.js: -------------------------------------------------------------------------------- 1 | import { ipcMain } from 'electron' 2 | import net from 'net' 3 | 4 | function scan (host, start, end, callback) { 5 | var count = end - start 6 | var result = [] 7 | console.time('port scan time') 8 | 9 | for (var i = start; i <= end; i++) { 10 | var item = net.connect({ 11 | host: host, 12 | port: i, 13 | timeout: 30000 // 增加半分钟的超时时间 14 | }, (function (i) { 15 | return function () { 16 | result.push(i) 17 | this.destroy() 18 | } 19 | }(i))) 20 | 21 | item.on('error', function (err) { 22 | if (err.errno === 'ECONNREFUSED') { 23 | this.destroy() 24 | } 25 | }) 26 | 27 | item.on('close', function () { 28 | if (!count--) { 29 | console.timeEnd('port scan time') 30 | callback(result) 31 | } 32 | }) 33 | } 34 | } 35 | 36 | ipcMain.on('port-scan', function (event, host, start = 1, end = 65535) { 37 | console.log('开始扫描: ', host, ' | 端口: ', start, ' ~ ', end); 38 | 39 | (function (host, start, end) { 40 | scan(host, start, end, function (result) { 41 | event.sender.send('port-scan-finished', host, result) 42 | }) 43 | })(host, start, end) 44 | }) 45 | -------------------------------------------------------------------------------- /src/main/ftp/index.js: -------------------------------------------------------------------------------- 1 | const { ipcMain, app } = require('electron') 2 | const FtpSrv = require('ftp-srv') 3 | const log = require('electron-log') 4 | 5 | let ftpServer = null 6 | const homePath = app.getPath('home') 7 | 8 | ipcMain.on('ftp-server-start', function (event, options = undefined, error = null) { 9 | if (!ftpServer) { 10 | let port = options.port || 8880 11 | ftpServer = new FtpSrv(`ftp://0.0.0.0:${port}`, { 12 | pasv_range: 8881, 13 | greeting: ['hello', 'world'], 14 | anonymous: true, 15 | file_format: 'ep' 16 | }) 17 | ftpServer.on('login', (data, resolve, reject) => { 18 | resolve({ 19 | root: homePath 20 | }) 21 | }) 22 | ftpServer.listen().then(() => { 23 | log.info('ftp server start') 24 | }) 25 | } else { 26 | log.info('ftp server isrunning!') 27 | } 28 | }) 29 | 30 | ipcMain.on('ftp-server-stop', function (event) { 31 | if (ftpServer) { 32 | ftpServer.close().then(() => { 33 | log.info('ftp server stop') 34 | }) 35 | } 36 | ftpServer = null 37 | }) 38 | -------------------------------------------------------------------------------- /src/main/http/index.js: -------------------------------------------------------------------------------- 1 | const { ipcMain, app } = require('electron') 2 | const { createServer } = require('http-server') 3 | const log = require('electron-log') 4 | 5 | let httpServer = null 6 | const homePath = app.getPath('home') 7 | 8 | const defaultOptions = { 9 | root: homePath, 10 | headers: {}, 11 | cache: 3600, 12 | showDir: 'true', 13 | autoIndex: 'true', 14 | showDotfiles: false, 15 | gzip: true, 16 | contentType: 'application/octet-stream', 17 | ext: undefined, 18 | cors: undefined, 19 | proxy: undefined 20 | } 21 | 22 | ipcMain.on('http-server-start', function (event, port, options = undefined) { 23 | if (!httpServer) { 24 | httpServer = createServer(Object.assign({}, defaultOptions, options)) 25 | httpServer.listen(port) 26 | log.info('http server start') 27 | } else { 28 | log.info('ftp server isrunning!') 29 | } 30 | }) 31 | 32 | ipcMain.on('http-server-stop', function (event) { 33 | if (httpServer) { 34 | httpServer.close() 35 | log.info('http server stop') 36 | } 37 | httpServer = null 38 | }) 39 | -------------------------------------------------------------------------------- /src/main/index.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is used specifically and only for development. It installs 3 | * `electron-debug` & `vue-devtools`. There shouldn't be any need to 4 | * modify this file, but it can be used to extend your development 5 | * environment. 6 | */ 7 | 8 | /* eslint-disable */ 9 | 10 | // Set environment for development 11 | process.env.NODE_ENV = 'development' 12 | 13 | // Install `electron-debug` with `devtron` 14 | require('electron-debug')({ showDevTools: true }) 15 | 16 | // Install `vue-devtools` 17 | require('electron').app.on('ready', () => { 18 | let installExtension = require('electron-devtools-installer') 19 | installExtension.default(installExtension.VUEJS_DEVTOOLS) 20 | .then(() => {}) 21 | .catch(err => { 22 | console.log('Unable to install `vue-devtools`: \n', err) 23 | }) 24 | }) 25 | 26 | // Require `main` process to boot app 27 | require('./index') 28 | -------------------------------------------------------------------------------- /src/main/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | import { app, BrowserWindow, Menu } from 'electron' 4 | import log from 'electron-log' 5 | 6 | /** 7 | * Set `__static` path to static files in production 8 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html 9 | */ 10 | if (process.env.NODE_ENV !== 'development') { 11 | global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\') 12 | } 13 | 14 | let mainWindow 15 | const winURL = process.env.NODE_ENV === 'development' 16 | ? `http://localhost:9080` 17 | : `file://${__dirname}/index.html` 18 | 19 | function createWindow () { 20 | /** 21 | * Initial window options 22 | */ 23 | mainWindow = new BrowserWindow({ 24 | height: 721, 25 | useContentSize: true, 26 | width: 1100, 27 | minWidth: 1100, 28 | minHeight: 721, 29 | webPreferences: {webSecurity: false} 30 | }) 31 | 32 | // Menu 33 | const template = [{ 34 | label: 'Edit', 35 | submenu: [ 36 | {role: 'undo'}, 37 | {role: 'redo'}, 38 | {type: 'separator'}, 39 | {role: 'cut'}, 40 | {role: 'copy'}, 41 | {role: 'paste'}, 42 | {role: 'pasteandmatchstyle'}, 43 | {role: 'delete'}, 44 | {role: 'selectall'} 45 | ] 46 | }, { 47 | label: 'View', 48 | submenu: [ 49 | {role: 'reload'}, 50 | {role: 'forcereload'}, 51 | {role: 'toggledevtools'}, 52 | {type: 'separator'}, 53 | {role: 'resetzoom'}, 54 | {role: 'zoomin'}, 55 | {role: 'zoomout'}, 56 | {type: 'separator'}, 57 | {role: 'togglefullscreen'} 58 | ] 59 | }, { 60 | role: 'window', 61 | submenu: [ 62 | {role: 'minimize'}, 63 | {role: 'close'} 64 | ] 65 | }, { 66 | role: 'help', 67 | submenu: [ 68 | { 69 | label: 'Learn More', 70 | click () { require('electron').shell.openExternal('https://electronjs.org') } 71 | } 72 | ] 73 | } 74 | ] 75 | 76 | if (process.platform === 'darwin') { 77 | template.unshift({ 78 | label: app.getName(), 79 | submenu: [ 80 | {role: 'about'}, 81 | {type: 'separator'}, 82 | {role: 'services', submenu: []}, 83 | {type: 'separator'}, 84 | {role: 'hide'}, 85 | {role: 'hideothers'}, 86 | {role: 'unhide'}, 87 | {type: 'separator'}, 88 | {role: 'quit'} 89 | ] 90 | }) 91 | 92 | // Edit menu 93 | template[1].submenu.push( 94 | {type: 'separator'}, 95 | { 96 | label: 'Speech', 97 | submenu: [ 98 | {role: 'startspeaking'}, 99 | {role: 'stopspeaking'} 100 | ] 101 | } 102 | ) 103 | 104 | // Window menu 105 | template[3].submenu = [ 106 | {role: 'close'}, 107 | {role: 'minimize'}, 108 | {role: 'zoom'}, 109 | {type: 'separator'}, 110 | {role: 'front'} 111 | ] 112 | } 113 | const menu = Menu.buildFromTemplate(template) 114 | Menu.setApplicationMenu(menu) 115 | 116 | mainWindow.loadURL(winURL) 117 | 118 | mainWindow.on('resize', () => { 119 | mainWindow.send('resize') 120 | }) 121 | 122 | mainWindow.on('closed', () => { 123 | mainWindow = null 124 | }) 125 | } 126 | 127 | app.on('ready', createWindow) 128 | 129 | app.on('window-all-closed', () => { 130 | if (process.platform !== 'darwin') { 131 | app.quit() 132 | } 133 | }) 134 | 135 | app.on('activate', () => { 136 | if (mainWindow === null) { 137 | createWindow() 138 | } 139 | }) 140 | 141 | require('./event/portscan') 142 | require('./proxy/') 143 | require('./http/') 144 | require('./ftp/') 145 | 146 | log.info('app start completed!') 147 | 148 | /** 149 | * Auto Updater 150 | * 151 | * Uncomment the following code below and install `electron-updater` to 152 | * support auto updating. Code Signing with a valid certificate is required. 153 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating 154 | */ 155 | 156 | /* 157 | import { autoUpdater } from 'electron-updater' 158 | 159 | autoUpdater.on('update-downloaded', () => { 160 | autoUpdater.quitAndInstall() 161 | }) 162 | 163 | app.on('ready', () => { 164 | if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates() 165 | }) 166 | */ 167 | -------------------------------------------------------------------------------- /src/main/proxy/index.js: -------------------------------------------------------------------------------- 1 | const { ipcMain } = require('electron') 2 | const AnyProxy = require('anyproxy') 3 | const log = require('electron-log') 4 | const defaultOptions = { 5 | port: 8001, 6 | // rule: require('myRuleModule'), 7 | webInterface: { 8 | enable: true, 9 | webPort: 8002 10 | }, 11 | throttle: 10000, 12 | forceProxyHttps: false, 13 | wsIntercept: false, // 不开启websocket代理 14 | silent: false 15 | } 16 | 17 | let isProxyStarted = false 18 | let proxyServer = null 19 | 20 | ipcMain.on('proxy-server-start', function (event, options = null) { 21 | if (!isProxyStarted) { 22 | proxyServer = new AnyProxy.ProxyServer(Object.assign({}, defaultOptions, options)) 23 | proxyServer.on('ready', () => { 24 | log.info('[AnyProxy]:', 'ready') 25 | }) 26 | proxyServer.on('error', (e) => { 27 | log.error('[AnyProxy]:', e) 28 | }) 29 | proxyServer.start() 30 | isProxyStarted = true 31 | } else { 32 | log.info('[AnyProxy]:', 'proxy server has been started!') 33 | } 34 | }) 35 | 36 | ipcMain.on('proxy-server-stop', function (event) { 37 | if (isProxyStarted) { 38 | proxyServer.close() 39 | isProxyStarted = false 40 | } else { 41 | log.info('[AnyProxy]:', 'proxy server has been closed!') 42 | } 43 | }) 44 | -------------------------------------------------------------------------------- /src/renderer/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/renderer/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/src/renderer/assets/.gitkeep -------------------------------------------------------------------------------- /src/renderer/assets/global.css: -------------------------------------------------------------------------------- 1 | code { 2 | padding: 0.2em 0.4em; 3 | margin: 0; 4 | font-size: 85%; 5 | background-color: rgba(27,31,35,0.05); 6 | border-radius: 3px; 7 | vertical-align: middle; 8 | } 9 | -------------------------------------------------------------------------------- /src/renderer/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/src/renderer/assets/logo.png -------------------------------------------------------------------------------- /src/renderer/components/Deprecated/ColorCard.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 63 | 64 | 86 | -------------------------------------------------------------------------------- /src/renderer/components/Deprecated/Doc.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 49 | 50 | 56 | -------------------------------------------------------------------------------- /src/renderer/components/Deprecated/Http.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 65 | 66 | 99 | -------------------------------------------------------------------------------- /src/renderer/components/Deprecated/SSHEmulator.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 70 | 71 | 92 | -------------------------------------------------------------------------------- /src/renderer/components/LandingPage.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 59 | 60 | 152 | -------------------------------------------------------------------------------- /src/renderer/components/LandingPage/SystemInformation.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 47 | 48 | 74 | -------------------------------------------------------------------------------- /src/renderer/components/LeftMenu.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 70 | 71 | 83 | -------------------------------------------------------------------------------- /src/renderer/components/MainView.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 61 | 62 | 69 | -------------------------------------------------------------------------------- /src/renderer/components/View/AnyProxy.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 59 | -------------------------------------------------------------------------------- /src/renderer/components/View/CodeSnippet.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 188 | 189 | 245 | -------------------------------------------------------------------------------- /src/renderer/components/View/Exec.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 156 | 157 | 216 | -------------------------------------------------------------------------------- /src/renderer/components/View/Settings.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 98 | 99 | 105 | -------------------------------------------------------------------------------- /src/renderer/components/View/Str/StrBejson.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 59 | 60 | 83 | -------------------------------------------------------------------------------- /src/renderer/components/View/Str/StrDiff.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 61 | 62 | 102 | -------------------------------------------------------------------------------- /src/renderer/components/View/Str/StrEncode.vue: -------------------------------------------------------------------------------- 1 | 110 | 111 | 200 | 201 | 214 | -------------------------------------------------------------------------------- /src/renderer/components/View/Str/StrQrcode.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 42 | 43 | 52 | -------------------------------------------------------------------------------- /src/renderer/components/View/Sys/FTPServer.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 56 | 57 | 67 | -------------------------------------------------------------------------------- /src/renderer/components/View/Sys/HTTPServer.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 78 | 79 | 86 | -------------------------------------------------------------------------------- /src/renderer/components/View/Sys/SysPortScan.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 90 | 91 | 100 | -------------------------------------------------------------------------------- /src/renderer/components/View/Sys/SysProcess.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 66 | 67 | 76 | -------------------------------------------------------------------------------- /src/renderer/components/View/Tail.vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 154 | 155 | 226 | -------------------------------------------------------------------------------- /src/renderer/datastore.js: -------------------------------------------------------------------------------- 1 | import Datastore from 'nedb' 2 | import path from 'path' 3 | import { remote } from 'electron' 4 | 5 | console.log('用户文件夹', remote.app.getPath('userData')) 6 | 7 | export default new Datastore({ 8 | autoload: true, 9 | filename: path.join(remote.app.getPath('userData'), '/data.db') 10 | }) 11 | -------------------------------------------------------------------------------- /src/renderer/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import axios from 'axios' 3 | import ElementUI from 'element-ui' 4 | import 'element-ui/lib/theme-chalk/index.css' 5 | 6 | import VueCodemirror from 'vue-codemirror' 7 | import 'codemirror/lib/codemirror.css' 8 | import 'codemirror/mode/javascript/javascript.js' 9 | 10 | import App from './App' 11 | import router from './router' 12 | import store from './store' 13 | 14 | import db from './datastore' 15 | 16 | import './utils/common' 17 | import './assets/global.css' 18 | 19 | if (!process.env.IS_WEB) Vue.use(require('vue-electron')) 20 | Vue.http = Vue.prototype.$http = axios 21 | Vue.config.productionTip = false 22 | Vue.prototype.$db = db 23 | 24 | Vue.use(ElementUI) 25 | Vue.use(VueCodemirror) 26 | 27 | /* eslint-disable no-new */ 28 | new Vue({ 29 | components: { App }, 30 | router, 31 | store, 32 | template: '' 33 | }).$mount('#app') 34 | -------------------------------------------------------------------------------- /src/renderer/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | export default new Router({ 7 | routes: [ 8 | { 9 | path: '/', 10 | name: 'landing-page', 11 | component: require('@/components/LandingPage').default 12 | }, 13 | { 14 | path: '*', 15 | redirect: '/' 16 | } 17 | ] 18 | }) 19 | -------------------------------------------------------------------------------- /src/renderer/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import VuexPersistence from 'vuex-persist' 4 | 5 | import modules from './modules' 6 | 7 | Vue.use(Vuex) 8 | 9 | const vuexLocal = new VuexPersistence({ 10 | storage: window.localStorage, 11 | modules: ['Settings', 'Exec'] 12 | }) 13 | 14 | export default new Vuex.Store({ 15 | modules, 16 | plugins: [vuexLocal.plugin], 17 | strict: process.env.NODE_ENV !== 'production' 18 | }) 19 | -------------------------------------------------------------------------------- /src/renderer/store/modules/Counter.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | main: 0 3 | } 4 | 5 | const mutations = { 6 | DECREMENT_MAIN_COUNTER (state) { 7 | state.main-- 8 | }, 9 | INCREMENT_MAIN_COUNTER (state) { 10 | state.main++ 11 | } 12 | } 13 | 14 | const actions = { 15 | someAsyncTask ({ commit }) { 16 | // do something async 17 | commit('INCREMENT_MAIN_COUNTER') 18 | } 19 | } 20 | 21 | export default { 22 | state, 23 | mutations, 24 | actions 25 | } 26 | -------------------------------------------------------------------------------- /src/renderer/store/modules/Exec.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | scripts: [] 3 | } 4 | 5 | const mutations = { 6 | MODIFY_EXEC_SCRIPTS (state, {data}) { 7 | state.scripts = data 8 | } 9 | } 10 | 11 | const actions = { 12 | modifyExecScripts ({ commit }, payload) { 13 | commit('MODIFY_EXEC_SCRIPTS', {data: payload}) 14 | } 15 | } 16 | 17 | export default { 18 | state, 19 | mutations, 20 | actions 21 | } 22 | -------------------------------------------------------------------------------- /src/renderer/store/modules/Nav.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | curNav: 'snippet' 3 | } 4 | 5 | const mutations = { 6 | SET_NAV (state, {navName}) { 7 | state.curNav = navName 8 | } 9 | } 10 | 11 | const actions = { 12 | setNav ({ commit }, name) { 13 | commit('SET_NAV', {navName: name}) 14 | } 15 | } 16 | 17 | export default { 18 | state, 19 | mutations, 20 | actions 21 | } 22 | -------------------------------------------------------------------------------- /src/renderer/store/modules/Settings.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | settings: { 3 | tailMaxLine: 1000, 4 | menuCollapse: false 5 | } 6 | } 7 | 8 | const mutations = { 9 | MODIFY_SETTINGS (state, {data}) { 10 | state.settings = Object.assign({}, state.settings, data) 11 | } 12 | } 13 | 14 | const actions = { 15 | modifySettings ({ commit }, payload) { 16 | commit('MODIFY_SETTINGS', {data: payload}) 17 | } 18 | } 19 | 20 | const getters = { 21 | asideWidth: state => state.settings.menuCollapse ? 64 : 201 22 | } 23 | 24 | export default { 25 | state, 26 | getters, 27 | mutations, 28 | actions 29 | } 30 | -------------------------------------------------------------------------------- /src/renderer/store/modules/View.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | docTree: [{ 3 | id: 0, 4 | label: '文档' 5 | }] 6 | } 7 | 8 | const mutations = { 9 | MODIFY_DOC_TREE (state, {data}) { 10 | state.docTree = Object.assign({}, state.docTree, data) 11 | } 12 | } 13 | 14 | const actions = { 15 | modifyDocTree ({ commit }, payload) { 16 | commit('MODIFY_DOC_TREE', {data: payload}) 17 | } 18 | } 19 | 20 | export default { 21 | state, 22 | mutations, 23 | actions 24 | } 25 | -------------------------------------------------------------------------------- /src/renderer/store/modules/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The file enables `@/store/index.js` to import all vuex modules 3 | * in a one-shot manner. There should not be any reason to edit this file. 4 | */ 5 | 6 | const files = require.context('.', false, /\.js$/) 7 | const modules = {} 8 | 9 | files.keys().forEach(key => { 10 | if (key === './index.js') return 11 | modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default 12 | }) 13 | 14 | export default modules 15 | -------------------------------------------------------------------------------- /src/renderer/utils/bejson.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let Bejson = {}; 3 | 4 | Bejson.parser = function() { 5 | var a = !0, 6 | b = !1, 7 | c = {}, 8 | d = function() { 9 | var a = { 10 | trace: function() {}, 11 | yy: {}, 12 | symbols_: { 13 | error: 2, 14 | JSONString: 3, 15 | STRING: 4, 16 | JSONNumber: 5, 17 | NUMBER: 6, 18 | JSONNullLiteral: 7, 19 | NULL: 8, 20 | JSONBooleanLiteral: 9, 21 | TRUE: 10, 22 | FALSE: 11, 23 | JSONText: 12, 24 | JSONObject: 13, 25 | EOF: 14, 26 | JSONArray: 15, 27 | JSONValue: 16, 28 | "{": 17, 29 | "}": 18, 30 | JSONMemberList: 19, 31 | JSONMember: 20, 32 | ":": 21, 33 | ",": 22, 34 | "[": 23, 35 | "]": 24, 36 | JSONElementList: 25, 37 | $accept: 0, 38 | $end: 1 39 | }, 40 | terminals_: { 41 | 2: "error", 42 | 4: "STRING", 43 | 6: "NUMBER", 44 | 8: "NULL", 45 | 10: "TRUE", 46 | 11: "FALSE", 47 | 14: "EOF", 48 | 17: "{", 49 | 18: "}", 50 | 21: ":", 51 | 22: ",", 52 | 23: "[", 53 | 24: "]" 54 | }, 55 | productions_: [0, [3, 1], 56 | [5, 1], 57 | [7, 1], 58 | [9, 1], 59 | [9, 1], 60 | [12, 2], 61 | [12, 2], 62 | [16, 1], 63 | [16, 1], 64 | [16, 1], 65 | [16, 1], 66 | [16, 1], 67 | [16, 1], 68 | [13, 2], 69 | [13, 3], 70 | [20, 3], 71 | [19, 1], 72 | [19, 3], 73 | [15, 2], 74 | [15, 3], 75 | [25, 1], 76 | [25, 3] 77 | ], 78 | performAction: function(a, b, c, d, e, f, g) { 79 | var h = f.length - 1; 80 | switch (e) { 81 | case 1: 82 | this.$ = a; 83 | break; 84 | case 2: 85 | this.$ = Number(a); 86 | break; 87 | case 3: 88 | this.$ = null; 89 | break; 90 | case 4: 91 | this.$ = !0; 92 | break; 93 | case 5: 94 | this.$ = !1; 95 | break; 96 | case 6: 97 | return this.$ = f[h - 1]; 98 | case 7: 99 | return this.$ = f[h - 1]; 100 | case 8: 101 | this.$ = f[h]; 102 | break; 103 | case 9: 104 | this.$ = f[h]; 105 | break; 106 | case 10: 107 | this.$ = f[h]; 108 | break; 109 | case 11: 110 | this.$ = f[h]; 111 | break; 112 | case 12: 113 | this.$ = f[h]; 114 | break; 115 | case 13: 116 | this.$ = f[h]; 117 | break; 118 | case 14: 119 | this.$ = {}; 120 | break; 121 | case 15: 122 | this.$ = f[h - 1]; 123 | break; 124 | case 16: 125 | this.$ = [f[h - 2], f[h]]; 126 | break; 127 | case 17: 128 | this.$ = {}, this.$[f[h][0]] = f[h][1]; 129 | break; 130 | case 18: 131 | this.$ = f[h - 2], f[h - 2][f[h][0]] = f[h][1]; 132 | break; 133 | case 19: 134 | this.$ = []; 135 | break; 136 | case 20: 137 | this.$ = f[h - 1]; 138 | break; 139 | case 21: 140 | this.$ = [f[h]]; 141 | break; 142 | case 22: 143 | this.$ = f[h - 2], f[h - 2].push(f[h]) 144 | } 145 | }, 146 | table: [{ 147 | 12: 1, 148 | 13: 2, 149 | 15: 3, 150 | 17: [1, 4], 151 | 23: [1, 5] 152 | }, { 153 | 1: [3] 154 | }, { 155 | 14: [1, 6] 156 | }, { 157 | 14: [1, 7] 158 | }, { 159 | 3: 11, 160 | 4: [1, 12], 161 | 18: [1, 8], 162 | 19: 9, 163 | 20: 10 164 | }, { 165 | 3: 18, 166 | 4: [1, 12], 167 | 5: 19, 168 | 6: [1, 25], 169 | 7: 16, 170 | 8: [1, 22], 171 | 9: 17, 172 | 10: [1, 23], 173 | 11: [1, 24], 174 | 13: 20, 175 | 15: 21, 176 | 16: 15, 177 | 17: [1, 4], 178 | 23: [1, 5], 179 | 24: [1, 13], 180 | 25: 14 181 | }, { 182 | 1: [2, 6] 183 | }, { 184 | 1: [2, 7] 185 | }, { 186 | 14: [2, 14], 187 | 18: [2, 14], 188 | 22: [2, 14], 189 | 24: [2, 14] 190 | }, { 191 | 18: [1, 26], 192 | 22: [1, 27] 193 | }, { 194 | 18: [2, 17], 195 | 22: [2, 17] 196 | }, { 197 | 21: [1, 28] 198 | }, { 199 | 18: [2, 1], 200 | 21: [2, 1], 201 | 22: [2, 1], 202 | 24: [2, 1] 203 | }, { 204 | 14: [2, 19], 205 | 18: [2, 19], 206 | 22: [2, 19], 207 | 24: [2, 19] 208 | }, { 209 | 22: [1, 30], 210 | 24: [1, 29] 211 | }, { 212 | 22: [2, 21], 213 | 24: [2, 21] 214 | }, { 215 | 18: [2, 8], 216 | 22: [2, 8], 217 | 24: [2, 8] 218 | }, { 219 | 18: [2, 9], 220 | 22: [2, 9], 221 | 24: [2, 9] 222 | }, { 223 | 18: [2, 10], 224 | 22: [2, 10], 225 | 24: [2, 10] 226 | }, { 227 | 18: [2, 11], 228 | 22: [2, 11], 229 | 24: [2, 11] 230 | }, { 231 | 18: [2, 12], 232 | 22: [2, 12], 233 | 24: [2, 12] 234 | }, { 235 | 18: [2, 13], 236 | 22: [2, 13], 237 | 24: [2, 13] 238 | }, { 239 | 18: [2, 3], 240 | 22: [2, 3], 241 | 24: [2, 3] 242 | }, { 243 | 18: [2, 4], 244 | 22: [2, 4], 245 | 24: [2, 4] 246 | }, { 247 | 18: [2, 5], 248 | 22: [2, 5], 249 | 24: [2, 5] 250 | }, { 251 | 18: [2, 2], 252 | 22: [2, 2], 253 | 24: [2, 2] 254 | }, { 255 | 14: [2, 15], 256 | 18: [2, 15], 257 | 22: [2, 15], 258 | 24: [2, 15] 259 | }, { 260 | 3: 11, 261 | 4: [1, 12], 262 | 20: 31 263 | }, { 264 | 3: 18, 265 | 4: [1, 12], 266 | 5: 19, 267 | 6: [1, 25], 268 | 7: 16, 269 | 8: [1, 22], 270 | 9: 17, 271 | 10: [1, 23], 272 | 11: [1, 24], 273 | 13: 20, 274 | 15: 21, 275 | 16: 32, 276 | 17: [1, 4], 277 | 23: [1, 5] 278 | }, { 279 | 14: [2, 20], 280 | 18: [2, 20], 281 | 22: [2, 20], 282 | 24: [2, 20] 283 | }, { 284 | 3: 18, 285 | 4: [1, 12], 286 | 5: 19, 287 | 6: [1, 25], 288 | 7: 16, 289 | 8: [1, 22], 290 | 9: 17, 291 | 10: [1, 23], 292 | 11: [1, 24], 293 | 13: 20, 294 | 15: 21, 295 | 16: 33, 296 | 17: [1, 4], 297 | 23: [1, 5] 298 | }, { 299 | 18: [2, 18], 300 | 22: [2, 18] 301 | }, { 302 | 18: [2, 16], 303 | 22: [2, 16] 304 | }, { 305 | 22: [2, 22], 306 | 24: [2, 22] 307 | }], 308 | defaultActions: { 309 | 6: [2, 6], 310 | 7: [2, 7] 311 | }, 312 | parseError: function(a, b) { 313 | throw new Error(a) 314 | }, 315 | parse: function(a) { 316 | function o() { 317 | var a; 318 | a = b.lexer.lex() || 1, typeof a != "number" && (a = b.symbols_[a] || a); 319 | return a 320 | } 321 | 322 | function n(a) { 323 | c.length = c.length - 2 * a, d.length = d.length - a, e.length = e.length - a 324 | } 325 | var b = this, 326 | c = [0], 327 | d = [null], 328 | e = [], 329 | f = this.table, 330 | g = "", 331 | h = 0, 332 | i = 0, 333 | j = 0, 334 | k = 2, 335 | l = 1; 336 | this.lexer.setInput(a), this.lexer.yy = this.yy, this.yy.lexer = this.lexer, typeof this.lexer.yylloc == "undefined" && (this.lexer.yylloc = {}); 337 | var m = this.lexer.yylloc; 338 | e.push(m), typeof this.yy.parseError == "function" && (this.parseError = this.yy.parseError); 339 | var p, q, r, s, t, u, v = {}, 340 | w, x, y, z; 341 | for (;;) { 342 | r = c[c.length - 1], this.defaultActions[r] ? s = this.defaultActions[r] : (p == null && (p = o()), s = f[r] && f[r][p]); 343 | if (typeof s == "undefined" || !s.length || !s[0]) { 344 | if (!j) { 345 | z = []; 346 | for (w in f[r]) this.terminals_[w] && w > 2 && z.push("'" + this.terminals_[w] + "'"); 347 | var A = ""; 348 | this.lexer.showPosition ? A = "Parse error on line " + (h + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + z.join(", ") : A = "Parse error on line " + (h + 1) + ": Unexpected " + (p == 1 ? "end of input" : "'" + (this.terminals_[p] || p) + "'"), this.parseError(A, { 349 | text: this.lexer.match, 350 | token: this.terminals_[p] || p, 351 | line: this.lexer.yylineno, 352 | loc: m, 353 | expected: z 354 | }) 355 | } 356 | if (j == 3) { 357 | if (p == l) throw new Error(A || "Parsing halted."); 358 | i = this.lexer.yyleng, g = this.lexer.yytext, h = this.lexer.yylineno, m = this.lexer.yylloc, p = o() 359 | } 360 | for (;;) { 361 | if (k.toString() in f[r]) break; 362 | if (r == 0) throw new Error(A || "Parsing halted."); 363 | n(1), r = c[c.length - 1] 364 | } 365 | q = p, p = k, r = c[c.length - 1], s = f[r] && f[r][k], j = 3 366 | } 367 | if (s[0] instanceof Array && s.length > 1) throw new Error("Parse Error: multiple actions possible at state: " + r + ", token: " + p); 368 | switch (s[0]) { 369 | case 1: 370 | c.push(p), d.push(this.lexer.yytext), e.push(this.lexer.yylloc), c.push(s[1]), p = null, q ? (p = q, q = null) : (i = this.lexer.yyleng, g = this.lexer.yytext, h = this.lexer.yylineno, m = this.lexer.yylloc, j > 0 && j--); 371 | break; 372 | case 2: 373 | x = this.productions_[s[1]][1], v.$ = d[d.length - x], v._$ = { 374 | first_line: e[e.length - (x || 1)].first_line, 375 | last_line: e[e.length - 1].last_line, 376 | first_column: e[e.length - (x || 1)].first_column, 377 | last_column: e[e.length - 1].last_column 378 | }, u = this.performAction.call(v, g, i, h, this.yy, s[1], d, e); 379 | if (typeof u != "undefined") return u; 380 | x && (c = c.slice(0, -1 * x * 2), d = d.slice(0, -1 * x), e = e.slice(0, -1 * x)), c.push(this.productions_[s[1]][0]), d.push(v.$), e.push(v._$), y = f[c[c.length - 2]][c[c.length - 1]], c.push(y); 381 | break; 382 | case 3: 383 | return !0 384 | } 385 | } 386 | return !0 387 | } 388 | }, 389 | f = function() { 390 | var a = { 391 | EOF: 1, 392 | parseError: function(a, b) { 393 | if (this.yy.parseError) this.yy.parseError(a, b); 394 | else throw new Error(a) 395 | }, 396 | setInput: function(a) { 397 | this._input = a, this._more = this._less = this.done = !1, this.yylineno = this.yyleng = 0, this.yytext = this.matched = this.match = "", this.conditionStack = ["INITIAL"], this.yylloc = { 398 | first_line: 1, 399 | first_column: 0, 400 | last_line: 1, 401 | last_column: 0 402 | }; 403 | return this 404 | }, 405 | input: function() { 406 | var a = this._input[0]; 407 | this.yytext += a, this.yyleng++, this.match += a, this.matched += a; 408 | var b = a.match(/\n/); 409 | b && this.yylineno++, this._input = this._input.slice(1); 410 | return a 411 | }, 412 | unput: function(a) { 413 | this._input = a + this._input; 414 | return this 415 | }, 416 | more: function() { 417 | this._more = !0; 418 | return this 419 | }, 420 | pastInput: function() { 421 | var a = this.matched.substr(0, this.matched.length - this.match.length); 422 | return (a.length > 20 ? "..." : "") + a.substr(-20).replace(/\n/g, "") 423 | }, 424 | upcomingInput: function() { 425 | var a = this.match; 426 | a.length < 20 && (a += this._input.substr(0, 20 - a.length)); 427 | return (a.substr(0, 20) + (a.length > 20 ? "..." : "")).replace(/\n/g, "") 428 | }, 429 | showPosition: function() { 430 | var a = this.pastInput(), 431 | b = Array(a.length + 1).join("-"); 432 | return a + this.upcomingInput() + "\n" + b + "^" 433 | }, 434 | next: function() { 435 | if (this.done) return this.EOF; 436 | this._input || (this.done = !0); 437 | var a, b, c, d; 438 | this._more || (this.yytext = "", this.match = ""); 439 | var e = this._currentRules(); 440 | for (var f = 0; f < e.length; f++) { 441 | b = this._input.match(this.rules[e[f]]); 442 | if (b) { 443 | d = b[0].match(/\n.*/g), d && (this.yylineno += d.length), this.yylloc = { 444 | first_line: this.yylloc.last_line, 445 | last_line: this.yylineno + 1, 446 | first_column: this.yylloc.last_column, 447 | last_column: d ? d[d.length - 1].length - 1 : this.yylloc.last_column + b[0].length 448 | }, this.yytext += b[0], this.match += b[0], this.matches = b, this.yyleng = this.yytext.length, this._more = !1, this._input = this._input.slice(b[0].length), this.matched += b[0], a = this.performAction.call(this, this.yy, this, e[f], this.conditionStack[this.conditionStack.length - 1]); 449 | if (a) return a; 450 | return 451 | } 452 | } 453 | if (this._input === "") return this.EOF; 454 | this.parseError("Lexical error on line " + (this.yylineno + 1) + ". Unrecognized text.\n" + this.showPosition(), { 455 | text: "", 456 | token: null, 457 | line: this.yylineno 458 | }) 459 | }, 460 | lex: function() { 461 | var a = this.next(); 462 | return typeof a != "undefined" ? a : this.lex() 463 | }, 464 | begin: function(a) { 465 | this.conditionStack.push(a) 466 | }, 467 | popState: function() { 468 | return this.conditionStack.pop() 469 | }, 470 | _currentRules: function() { 471 | return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules 472 | } 473 | }; 474 | a.performAction = function(a, b, c, d) { 475 | var e = d; 476 | switch (c) { 477 | case 0: 478 | break; 479 | case 1: 480 | return 6; 481 | case 2: 482 | b.yytext = b.yytext.substr(1, b.yyleng - 2); 483 | return 4; 484 | case 3: 485 | return 17; 486 | case 4: 487 | return 18; 488 | case 5: 489 | return 23; 490 | case 6: 491 | return 24; 492 | case 7: 493 | return 22; 494 | case 8: 495 | return 21; 496 | case 9: 497 | return 10; 498 | case 10: 499 | return 11; 500 | case 11: 501 | return 8; 502 | case 12: 503 | return 14; 504 | case 13: 505 | return "INVALID" 506 | } 507 | }, a.rules = [ 508 | /^\s+/, /^-?([0-9]|[1-9][0-9]+)(\.[0-9]+)?([eE][-+]?[0-9]+)?\b/, 509 | /^"(\\["bfnrt/\\]|\\u[a-fA-F0-9]{4}|[^\0-\x09\x0a-\x1f"\\])*"/, 510 | /^\{/, 511 | /^\}/, 512 | /^\[/, 513 | /^\]/, 514 | /^,/, 515 | /^:/, 516 | /^true\b/, 517 | /^false\b/, 518 | /^null\b/, 519 | /^$/, 520 | /^./ 521 | ], a.conditions = { 522 | INITIAL: { 523 | rules: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 524 | inclusive: !0 525 | } 526 | }; 527 | return a 528 | }(); 529 | a.lexer = f; 530 | return a 531 | }(); 532 | typeof a != "undefined" && typeof c != "undefined" && (c.parser = d, c.parse = function() { 533 | return d.parse.apply(d, arguments) 534 | }, c.main = function(b) { 535 | if (!b[1]) throw new Error("Usage: " + b[0] + " FILE"); 536 | if (typeof process != "undefined") var d = a("fs").readFileSync(a("path").join(process.cwd(), b[1]), "utf8"); 537 | else var e = a("file").path(a("file").cwd()), 538 | d = e.join(b[1]).read({ 539 | charset: "utf-8" 540 | }); 541 | return c.parser.parse(d) 542 | }, typeof b != "undefined" && a.main === b && c.main(typeof process != "undefined" ? process.argv.slice(1) : a("system").args)); 543 | return c 544 | }(); 545 | Bejson.format = (function() { 546 | function repeat(s, count) { 547 | return new Array(count + 1).join(s) 548 | } 549 | 550 | function formatJson(json) { 551 | var i = 0, 552 | il = 0, 553 | tab = " ",// change 554 | newJson = "", 555 | indentLevel = 0, 556 | inString = false, 557 | currentChar = null; 558 | for (i = 0, il = json.length; i < il; i += 1) { 559 | currentChar = json.charAt(i); 560 | switch (currentChar) { 561 | case '{': 562 | case '[': 563 | if (!inString) { 564 | newJson += currentChar + "\n" + repeat(tab, indentLevel + 1); 565 | indentLevel += 1 566 | } else { 567 | newJson += currentChar 568 | } 569 | break; 570 | case '}': 571 | case ']': 572 | if (!inString) { 573 | indentLevel -= 1; 574 | newJson += "\n" + repeat(tab, indentLevel) + currentChar 575 | } else { 576 | newJson += currentChar 577 | } 578 | break; 579 | case ',': 580 | if (!inString) { 581 | newJson += ",\n" + repeat(tab, indentLevel) 582 | } else { 583 | newJson += currentChar 584 | } 585 | break; 586 | case ':': 587 | if (!inString) { 588 | newJson += ": " 589 | } else { 590 | newJson += currentChar 591 | } 592 | break; 593 | case ' ': 594 | case "\n": 595 | case "\t": 596 | if (inString) { 597 | newJson += currentChar 598 | } 599 | break; 600 | case '"': 601 | if (i > 0 && json.charAt(i - 1) !== '\\') { 602 | inString = !inString 603 | } 604 | newJson += currentChar; 605 | break; 606 | default: 607 | newJson += currentChar; 608 | break 609 | } 610 | } 611 | return newJson 612 | } 613 | return { 614 | "formatJson": formatJson 615 | } 616 | }()); 617 | 618 | module.exports = Bejson; 619 | -------------------------------------------------------------------------------- /src/renderer/utils/common.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | Date.prototype.format = function (format) { 3 | var o = { 4 | 'M+': this.getMonth() + 1, // month 5 | 'd+': this.getDate(), // day 6 | 'h+': this.getHours(), // hour 7 | 'm+': this.getMinutes(), // minute 8 | 's+': this.getSeconds(), // second 9 | 'q+': Math.floor((this.getMonth() + 3) / 3), // quarter 10 | 'S': this.getMilliseconds() // millisecond 11 | } 12 | if (/(y+)/.test(format)) { 13 | format = format.replace(RegExp.$1, 14 | (this.getFullYear() + '').substr(4 - RegExp.$1.length)) 15 | } 16 | for (var k in o) { 17 | if (new RegExp('(' + k + ')').test(format)) { 18 | format = format.replace(RegExp.$1, 19 | RegExp.$1.length === 1 ? o[k] 20 | : ('00' + o[k]).substr(('' + o[k]).length)) 21 | } 22 | } 23 | return format 24 | } 25 | -------------------------------------------------------------------------------- /src/renderer/utils/difflib.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let __whitespace = { 3 | " ": true, 4 | "\t": true, 5 | "\n": true, 6 | "\f": true, 7 | "\r": true 8 | }; 9 | let difflib = { 10 | defaultJunkFunction: function (c) { 11 | return c in __whitespace; 12 | }, 13 | stripLinebreaks: function (str) { 14 | return str.replace(/^[\n\r]*|[\n\r]*$/g, ""); 15 | }, 16 | stringAsLines: function (str) { 17 | var lfpos = str.indexOf("\n"); 18 | var crpos = str.indexOf("\r"); 19 | var linebreak = ((lfpos > -1 && crpos > -1) || crpos < 0) ? "\n" : "\r"; 20 | var lines = str.split(linebreak); 21 | for (var i = 0; i < lines.length; i++) { 22 | lines[i] = difflib.stripLinebreaks(lines[i]); 23 | } 24 | return lines; 25 | }, 26 | __reduce: function (func, list, initial) { 27 | if (initial != null) { 28 | var value = initial; 29 | var idx = 0; 30 | } else if (list) { 31 | var value = list[0]; 32 | var idx = 1; 33 | } else { 34 | return null; 35 | } 36 | for (; idx < list.length; idx++) { 37 | value = func(value, list[idx]); 38 | } 39 | return value; 40 | }, 41 | __ntuplecomp: function (a, b) { 42 | var mlen = Math.max(a.length, b.length); 43 | for (var i = 0; i < mlen; i++) { 44 | if (a[i] < b[i]) return -1; 45 | if (a[i] > b[i]) return 1; 46 | } 47 | return a.length == b.length ? 0 : (a.length < b.length ? -1 : 1); 48 | }, 49 | __calculate_ratio: function (matches, length) { 50 | return length ? 2.0 * matches / length : 1.0; 51 | }, 52 | __isindict: function (dict) { 53 | return function (key) { 54 | return key in dict; 55 | }; 56 | }, 57 | __dictget: function (dict, key, defaultValue) { 58 | return key in dict ? dict[key] : defaultValue; 59 | }, 60 | SequenceMatcher: function (a, b, isjunk) { 61 | this.set_seqs = function (a, b) { 62 | this.set_seq1(a); 63 | this.set_seq2(b); 64 | } 65 | this.set_seq1 = function (a) { 66 | if (a == this.a) return; 67 | this.a = a; 68 | this.matching_blocks = this.opcodes = null; 69 | } 70 | this.set_seq2 = function (b) { 71 | if (b == this.b) return; 72 | this.b = b; 73 | this.matching_blocks = this.opcodes = this.fullbcount = null; 74 | this.__chain_b(); 75 | } 76 | this.__chain_b = function () { 77 | var b = this.b; 78 | var n = b.length; 79 | var b2j = this.b2j = {}; 80 | var populardict = {}; 81 | for (var i = 0; i < b.length; i++) { 82 | var elt = b[i]; 83 | if (elt in b2j) { 84 | var indices = b2j[elt]; 85 | if (n >= 200 && indices.length * 100 > n) { 86 | populardict[elt] = 1; 87 | delete b2j[elt]; 88 | } else { 89 | indices.push(i); 90 | } 91 | } else { 92 | b2j[elt] = [i]; 93 | } 94 | } 95 | for (var elt in populardict) 96 | delete b2j[elt]; 97 | var isjunk = this.isjunk; 98 | var junkdict = {}; 99 | if (isjunk) { 100 | for (var elt in populardict) { 101 | if (isjunk(elt)) { 102 | junkdict[elt] = 1; 103 | delete populardict[elt]; 104 | } 105 | } 106 | for (var elt in b2j) { 107 | if (isjunk(elt)) { 108 | junkdict[elt] = 1; 109 | delete b2j[elt]; 110 | } 111 | } 112 | } 113 | this.isbjunk = difflib.__isindict(junkdict); 114 | this.isbpopular = difflib.__isindict(populardict); 115 | } 116 | this.find_longest_match = function (alo, ahi, blo, bhi) { 117 | var a = this.a; 118 | var b = this.b; 119 | var b2j = this.b2j; 120 | var isbjunk = this.isbjunk; 121 | var besti = alo; 122 | var bestj = blo; 123 | var bestsize = 0; 124 | var j = null; 125 | var j2len = {}; 126 | var nothing = []; 127 | for (var i = alo; i < ahi; i++) { 128 | var newj2len = {}; 129 | var jdict = difflib.__dictget(b2j, a[i], nothing); 130 | for (var jkey in jdict) { 131 | j = jdict[jkey]; 132 | if (j < blo) continue; 133 | if (j >= bhi) break; 134 | var k; 135 | newj2len[j] = k = difflib.__dictget(j2len, j - 1, 0) + 1; 136 | if (k > bestsize) { 137 | besti = i - k + 1; 138 | bestj = j - k + 1; 139 | bestsize = k; 140 | } 141 | } 142 | j2len = newj2len; 143 | } 144 | while (besti > alo && bestj > blo && !isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) { 145 | besti--; 146 | bestj--; 147 | bestsize++; 148 | } 149 | while (besti + bestsize < ahi && bestj + bestsize < bhi && !isbjunk(b[bestj + bestsize]) && a[besti + bestsize] == b[bestj + bestsize]) { 150 | bestsize++; 151 | } 152 | while (besti > alo && bestj > blo && isbjunk(b[bestj - 1]) && a[besti - 1] == b[bestj - 1]) { 153 | besti--; 154 | bestj--; 155 | bestsize++; 156 | } 157 | while (besti + bestsize < ahi && bestj + bestsize < bhi && isbjunk(b[bestj + bestsize]) && a[besti + bestsize] == b[bestj + bestsize]) { 158 | bestsize++; 159 | } 160 | return [besti, bestj, bestsize]; 161 | } 162 | this.get_matching_blocks = function () { 163 | if (this.matching_blocks != null) return this.matching_blocks; 164 | var la = this.a.length; 165 | var lb = this.b.length; 166 | var queue = [ 167 | [0, la, 0, lb] 168 | ]; 169 | var matching_blocks = []; 170 | var alo, ahi, blo, bhi, qi, i, j, k, x; 171 | while (queue.length) { 172 | qi = queue.pop(); 173 | alo = qi[0]; 174 | ahi = qi[1]; 175 | blo = qi[2]; 176 | bhi = qi[3]; 177 | x = this.find_longest_match(alo, ahi, blo, bhi); 178 | i = x[0]; 179 | j = x[1]; 180 | k = x[2]; 181 | if (k) { 182 | matching_blocks.push(x); 183 | if (alo < i && blo < j) queue.push([alo, i, blo, j]); 184 | if (i + k < ahi && j + k < bhi) queue.push([i + k, ahi, j + k, bhi]); 185 | } 186 | } 187 | matching_blocks.sort(difflib.__ntuplecomp); 188 | var i1 = 0; 189 | var j1 = 0; 190 | var k1 = 0; 191 | var block = 0; 192 | var non_adjacent = []; 193 | for (var idx in matching_blocks) { 194 | block = matching_blocks[idx]; 195 | var i2 = block[0]; 196 | var j2 = block[1]; 197 | var k2 = block[2]; 198 | if (i1 + k1 == i2 && j1 + k1 == j2) { 199 | k1 += k2; 200 | } else { 201 | if (k1) non_adjacent.push([i1, j1, k1]); 202 | i1 = i2; 203 | j1 = j2; 204 | k1 = k2; 205 | } 206 | } 207 | if (k1) non_adjacent.push([i1, j1, k1]); 208 | non_adjacent.push([la, lb, 0]); 209 | this.matching_blocks = non_adjacent; 210 | return this.matching_blocks; 211 | } 212 | this.get_opcodes = function () { 213 | if (this.opcodes != null) return this.opcodes; 214 | var i = 0; 215 | var j = 0; 216 | var answer = []; 217 | this.opcodes = answer; 218 | var block, ai, bj, size, tag; 219 | var blocks = this.get_matching_blocks(); 220 | for (var idx in blocks) { 221 | block = blocks[idx]; 222 | ai = block[0]; 223 | bj = block[1]; 224 | size = block[2]; 225 | tag = ''; 226 | if (i < ai && j < bj) { 227 | tag = 'replace'; 228 | } else if (i < ai) { 229 | tag = 'delete'; 230 | } else if (j < bj) { 231 | tag = 'insert'; 232 | } 233 | if (tag) answer.push([tag, i, ai, j, bj]); 234 | i = ai + size; 235 | j = bj + size; 236 | if (size) answer.push(['equal', ai, i, bj, j]); 237 | } 238 | return answer; 239 | } 240 | this.get_grouped_opcodes = function (n) { 241 | if (!n) n = 3; 242 | var codes = this.get_opcodes(); 243 | if (!codes) codes = [ 244 | ["equal", 0, 1, 0, 1] 245 | ]; 246 | var code, tag, i1, i2, j1, j2; 247 | if (codes[0][0] == 'equal') { 248 | code = codes[0]; 249 | tag = code[0]; 250 | i1 = code[1]; 251 | i2 = code[2]; 252 | j1 = code[3]; 253 | j2 = code[4]; 254 | codes[0] = [tag, Math.max(i1, i2 - n), i2, Math.max(j1, j2 - n), j2]; 255 | } 256 | if (codes[codes.length - 1][0] == 'equal') { 257 | code = codes[codes.length - 1]; 258 | tag = code[0]; 259 | i1 = code[1]; 260 | i2 = code[2]; 261 | j1 = code[3]; 262 | j2 = code[4]; 263 | codes[codes.length - 1] = [tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)]; 264 | } 265 | var nn = n + n; 266 | var groups = []; 267 | for (var idx in codes) { 268 | code = codes[idx]; 269 | tag = code[0]; 270 | i1 = code[1]; 271 | i2 = code[2]; 272 | j1 = code[3]; 273 | j2 = code[4]; 274 | if (tag == 'equal' && i2 - i1 > nn) { 275 | groups.push([tag, i1, Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)]); 276 | i1 = Math.max(i1, i2 - n); 277 | j1 = Math.max(j1, j2 - n); 278 | } 279 | groups.push([tag, i1, i2, j1, j2]); 280 | } 281 | if (groups && groups[groups.length - 1][0] == 'equal') groups.pop(); 282 | return groups; 283 | } 284 | this.ratio = function () { 285 | matches = difflib.__reduce(function (sum, triple) { 286 | return sum + triple[triple.length - 1]; 287 | }, this.get_matching_blocks(), 0); 288 | return difflib.__calculate_ratio(matches, this.a.length + this.b.length); 289 | } 290 | this.quick_ratio = function () { 291 | var fullbcount, elt; 292 | if (this.fullbcount == null) { 293 | this.fullbcount = fullbcount = {}; 294 | for (var i = 0; i < this.b.length; i++) { 295 | elt = this.b[i]; 296 | fullbcount[elt] = difflib.__dictget(fullbcount, elt, 0) + 1; 297 | } 298 | } 299 | fullbcount = this.fullbcount; 300 | var avail = {}; 301 | var availhas = difflib.__isindict(avail); 302 | var matches = numb = 0; 303 | for (var i = 0; i < this.a.length; i++) { 304 | elt = this.a[i]; 305 | if (availhas(elt)) { 306 | numb = avail[elt]; 307 | } else { 308 | numb = difflib.__dictget(fullbcount, elt, 0); 309 | } 310 | avail[elt] = numb - 1; 311 | if (numb > 0) matches++; 312 | } 313 | return difflib.__calculate_ratio(matches, this.a.length + this.b.length); 314 | } 315 | this.real_quick_ratio = function () { 316 | var la = this.a.length; 317 | var lb = this.b.length; 318 | return _calculate_ratio(Math.min(la, lb), la + lb); 319 | } 320 | this.isjunk = isjunk ? isjunk : difflib.defaultJunkFunction; 321 | this.a = this.b = null; 322 | this.set_seqs(a, b); 323 | } 324 | } 325 | 326 | export default difflib; 327 | -------------------------------------------------------------------------------- /src/renderer/utils/diffview.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | let diffview = { 3 | buildView: function (params) { 4 | var baseTextLines = params.baseTextLines; 5 | var newTextLines = params.newTextLines; 6 | var opcodes = params.opcodes; 7 | var baseTextName = params.baseTextName ? params.baseTextName : "Base Text"; 8 | var newTextName = params.newTextName ? params.newTextName : "New Text"; 9 | var contextSize = params.contextSize; 10 | var inline = (params.viewType == 0 || params.viewType == 1) ? params.viewType : 0; 11 | if (baseTextLines == null) throw "Cannot build diff view; baseTextLines is not defined."; 12 | if (newTextLines == null) throw "Cannot build diff view; newTextLines is not defined."; 13 | if (!opcodes) throw "Canno build diff view; opcodes is not defined."; 14 | 15 | function celt(name, clazz) { 16 | var e = document.createElement(name); 17 | e.className = clazz; 18 | return e; 19 | } 20 | function telt(name, text) { 21 | var e = document.createElement(name); 22 | e.appendChild(document.createTextNode(text)); 23 | return e; 24 | } 25 | function ctelt(name, clazz, text) { 26 | var e = document.createElement(name); 27 | e.className = clazz; 28 | e.appendChild(document.createTextNode(text)); 29 | return e; 30 | } 31 | var tdata = document.createElement("thead"); 32 | var node = document.createElement("tr"); 33 | tdata.appendChild(node); 34 | if (inline) { 35 | node.appendChild(document.createElement("th")); 36 | node.appendChild(document.createElement("th")); 37 | node.appendChild(ctelt("th", "texttitle", baseTextName + " vs. " + newTextName)); 38 | } else { 39 | node.appendChild(document.createElement("th")); 40 | node.appendChild(ctelt("th", "texttitle", baseTextName)); 41 | node.appendChild(document.createElement("th")); 42 | node.appendChild(ctelt("th", "texttitle", newTextName)); 43 | } 44 | tdata = [tdata]; 45 | var rows = []; 46 | var node2; 47 | 48 | function addCells(row, tidx, tend, textLines, change) { 49 | if (tidx < tend) { 50 | row.appendChild(telt("th", (tidx + 1).toString())); 51 | row.appendChild(ctelt("td", change, textLines[tidx].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0"))); 52 | return tidx + 1; 53 | } else { 54 | row.appendChild(document.createElement("th")); 55 | row.appendChild(celt("td", "empty")); 56 | return tidx; 57 | } 58 | } 59 | function addCellsInline(row, tidx, tidx2, textLines, change) { 60 | row.appendChild(telt("th", tidx == null ? "" : (tidx + 1).toString())); 61 | row.appendChild(telt("th", tidx2 == null ? "" : (tidx2 + 1).toString())); 62 | row.appendChild(ctelt("td", change, textLines[tidx != null ? tidx : tidx2].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0"))); 63 | } 64 | for (var idx = 0; idx < opcodes.length; idx++) { 65 | var code = opcodes[idx]; 66 | var change = code[0]; 67 | var b = code[1]; 68 | var be = code[2]; 69 | var n = code[3]; 70 | var ne = code[4]; 71 | var rowcnt = Math.max(be - b, ne - n); 72 | var toprows = []; 73 | var botrows = []; 74 | for (var i = 0; i < rowcnt; i++) { 75 | if (contextSize && opcodes.length > 1 && ((idx > 0 && i == contextSize) || (idx == 0 && i == 0)) && change == "equal") { 76 | var jump = rowcnt - ((idx == 0 ? 1 : 2) * contextSize); 77 | if (jump > 1) { 78 | toprows.push(node = document.createElement("tr")); 79 | b += jump; 80 | n += jump; 81 | i += jump - 1; 82 | node.appendChild(telt("th", "...")); 83 | if (!inline) node.appendChild(ctelt("td", "skip", "")); 84 | node.appendChild(telt("th", "...")); 85 | node.appendChild(ctelt("td", "skip", "")); 86 | if (idx + 1 == opcodes.length) { 87 | break; 88 | } else { 89 | continue; 90 | } 91 | } 92 | } 93 | toprows.push(node = document.createElement("tr")); 94 | if (inline) { 95 | if (change == "insert") { 96 | addCellsInline(node, null, n++, newTextLines, change); 97 | } else if (change == "replace") { 98 | botrows.push(node2 = document.createElement("tr")); 99 | if (b < be) addCellsInline(node, b++, null, baseTextLines, "delete"); 100 | if (n < ne) addCellsInline(node2, null, n++, newTextLines, "insert"); 101 | } else if (change == "delete") { 102 | addCellsInline(node, b++, null, baseTextLines, change); 103 | } else { 104 | addCellsInline(node, b++, n++, baseTextLines, change); 105 | } 106 | } else { 107 | b = addCells(node, b, be, baseTextLines, change); 108 | n = addCells(node, n, ne, newTextLines, change); 109 | } 110 | } 111 | for (var i = 0; i < toprows.length; i++) rows.push(toprows[i]); 112 | for (var i = 0; i < botrows.length; i++) rows.push(botrows[i]); 113 | } 114 | tdata.push(node = document.createElement("tbody")); 115 | for (var idx in rows) node.appendChild(rows[idx]); 116 | node = celt("table", "diff" + (inline ? " inlinediff" : "")); 117 | for (var idx in tdata) node.appendChild(tdata[idx]); 118 | return node; 119 | } 120 | } 121 | 122 | export default diffview; 123 | -------------------------------------------------------------------------------- /src/renderer/utils/language.json: -------------------------------------------------------------------------------- 1 | [ 2 | "javascript", 3 | "html", 4 | "css", 5 | "coffee" 6 | ] 7 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moonrailgun/devbox/d725131b59646f1899545107f1fc5637e87840d6/static/.gitkeep -------------------------------------------------------------------------------- /static/ports.json: -------------------------------------------------------------------------------- 1 | { 2 | "21": "FTP服务", 3 | "22": "SSH服务", 4 | "23": "Telnet服务", 5 | "25": "SMTP服务", 6 | "53": "DNS服务", 7 | "80": "HTTP服务", 8 | "109": "POP3服务", 9 | "143": "IMAP服务", 10 | "161": "SNMP服务", 11 | "443": "HTTPS服务", 12 | "993": "IMAP服务", 13 | "1080": "SOCKS服务", 14 | "1433": "SQL Server服务", 15 | "1500": "RPC服务", 16 | "3306": "MySQL服务", 17 | "27017": "mongodb服务" 18 | } 19 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "assert": true, 7 | "expect": true, 8 | "should": true, 9 | "__static": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/e2e/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | // Set BABEL_ENV to use proper env config 4 | process.env.BABEL_ENV = 'test' 5 | 6 | // Enable use of ES6+ on required files 7 | require('babel-register')({ 8 | ignore: /node_modules/ 9 | }) 10 | 11 | // Attach Chai APIs to global scope 12 | const { expect, should, assert } = require('chai') 13 | global.expect = expect 14 | global.should = should 15 | global.assert = assert 16 | 17 | // Require all JS files in `./specs` for Mocha to consume 18 | require('require-dir')('./specs') 19 | -------------------------------------------------------------------------------- /test/e2e/specs/Launch.spec.js: -------------------------------------------------------------------------------- 1 | import utils from '../utils' 2 | 3 | describe('Launch', function () { 4 | beforeEach(utils.beforeEach) 5 | afterEach(utils.afterEach) 6 | 7 | it('shows the proper application title', function () { 8 | return this.app.client.getTitle() 9 | .then(title => { 10 | expect(title).to.equal('devbox') 11 | }) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /test/e2e/utils.js: -------------------------------------------------------------------------------- 1 | import electron from 'electron' 2 | import { Application } from 'spectron' 3 | 4 | export default { 5 | afterEach () { 6 | this.timeout(10000) 7 | 8 | if (this.app && this.app.isRunning()) { 9 | return this.app.stop() 10 | } 11 | }, 12 | beforeEach () { 13 | this.timeout(10000) 14 | this.app = new Application({ 15 | path: electron, 16 | args: ['dist/electron/main.js'], 17 | startTimeout: 10000, 18 | waitTimeout: 10000 19 | }) 20 | 21 | return this.app.start() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | Vue.config.devtools = false 3 | Vue.config.productionTip = false 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | const srcContext = require.context('../../src/renderer', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const path = require('path') 4 | const merge = require('webpack-merge') 5 | const webpack = require('webpack') 6 | 7 | const baseConfig = require('../../.electron-vue/webpack.renderer.config') 8 | const projectRoot = path.resolve(__dirname, '../../src/renderer') 9 | 10 | // Set BABEL_ENV to use proper preset config 11 | process.env.BABEL_ENV = 'test' 12 | 13 | let webpackConfig = merge(baseConfig, { 14 | devtool: '#inline-source-map', 15 | plugins: [ 16 | new webpack.DefinePlugin({ 17 | 'process.env.NODE_ENV': '"testing"' 18 | }) 19 | ] 20 | }) 21 | 22 | // don't treat dependencies as externals 23 | delete webpackConfig.entry 24 | delete webpackConfig.externals 25 | delete webpackConfig.output.libraryTarget 26 | 27 | // apply vue option to apply isparta-loader on js 28 | webpackConfig.module.rules 29 | .find(rule => rule.use.loader === 'vue-loader').use.options.loaders.js = 'babel-loader' 30 | 31 | module.exports = config => { 32 | config.set({ 33 | browsers: ['visibleElectron'], 34 | client: { 35 | useIframe: false 36 | }, 37 | coverageReporter: { 38 | dir: './coverage', 39 | reporters: [ 40 | { type: 'lcov', subdir: '.' }, 41 | { type: 'text-summary' } 42 | ] 43 | }, 44 | customLaunchers: { 45 | 'visibleElectron': { 46 | base: 'Electron', 47 | flags: ['--show'] 48 | } 49 | }, 50 | frameworks: ['mocha', 'chai'], 51 | files: ['./index.js'], 52 | preprocessors: { 53 | './index.js': ['webpack', 'sourcemap'] 54 | }, 55 | reporters: ['spec', 'coverage'], 56 | singleRun: true, 57 | webpack: webpackConfig, 58 | webpackMiddleware: { 59 | noInfo: true 60 | } 61 | }) 62 | } 63 | -------------------------------------------------------------------------------- /test/unit/specs/LandingPage.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import LandingPage from '@/components/LandingPage' 3 | 4 | describe('LandingPage.vue', () => { 5 | it('should render correct contents', () => { 6 | const vm = new Vue({ 7 | el: document.createElement('div'), 8 | render: h => h(LandingPage) 9 | }).$mount() 10 | 11 | expect(vm.$el.querySelector('.title').textContent).to.contain('Welcome to your new project!') 12 | }) 13 | }) 14 | --------------------------------------------------------------------------------