Current Dev State

This commit is contained in:
Tim Lorsbach
2025-06-23 20:13:54 +02:00
parent b4f9bb277d
commit ded50edaa2
22617 changed files with 4345095 additions and 174 deletions

308
static/js/ketcher2/node_modules/budo/lib/budo.js generated vendored Normal file
View File

@ -0,0 +1,308 @@
var bole = require('bole')
var xtend = require('xtend')
var once = require('once')
var path = require('path')
var EventEmitter = require('events').EventEmitter
var isMatch = require('micromatch')
var openUrl = require('opn')
var internalIp = require('internal-ip')
var garnish = require('garnish')
var defaults = require('./parse-args').defaults
var getPorts = require('./get-ports')
var createServer = require('./server')
var createBundler = require('./bundler')
var createFileWatch = require('./file-watch')
var createReloadServer = require('./reload/server')
var mapEntry = require('./map-entry')
var noop = function () {}
module.exports = createBudo
function createBudo (entries, opts) {
var log = bole('budo')
// if no entries are specified, just options
if (entries && !Array.isArray(entries) && typeof entries === 'object') {
opts = entries
entries = []
}
// do not mutate user options
opts = xtend({}, defaults, { stream: false }, opts)
entries = entries || []
// perhaps later this will be configurable
opts.cwd = process.cwd()
// log to output stream
if (opts.stream) {
// by default, pretty-print to the stream with info logging
if (!opts.ndjson) {
var pretty = garnish({
level: opts.verbose ? 'debug' : 'info',
name: 'budo'
})
pretty.pipe(opts.stream)
opts.stream = pretty
}
bole.output({
stream: opts.stream,
level: 'debug'
})
}
// optionally allow as arrays
entries = [].concat(entries).filter(Boolean)
var entryObjects = entries.map(mapEntry)
var entryFiles = entryObjects.map(function (entry) {
return entry.from
})
if (opts.serve && typeof opts.serve !== 'string') {
throw new TypeError('opts.serve must be a string or undefined')
} else if (!opts.serve && entries.length > 0) {
opts.serve = entryObjects[0].url
}
// default to cwd
if (!opts.dir || opts.dir.length === 0) {
opts.dir = opts.cwd
}
var emitter = new EventEmitter()
var bundler, middleware
if (entries.length > 0 || (opts.browserify && opts.browserify.entries)) {
bundler = createBundler(entryFiles, opts)
middleware = bundler.middleware
bundler.on('log', function (ev) {
if (ev.type === 'bundle') {
var time = ev.elapsed
ev.elapsed = time
ev.name = 'browserify'
ev.type = undefined
ev.colors = {
elapsed: time > 1000 ? 'yellow' : 'dim',
message: 'dim '
}
log.info(ev)
}
})
// uncaught syntax errors should not stop the server
// this only happens when errorHandler: false
bundler.on('error', function (err) {
console.error('Error:', err.message ? err.message : err)
})
bundler.on('bundle-error', emitter.emit.bind(emitter, 'bundle-error'))
bundler.on('update', emitter.emit.bind(emitter, 'update'))
bundler.on('pending', emitter.emit.bind(emitter, 'pending'))
emitter.on('update', function (contents, deps) {
if (deps.length > 1) {
log.debug({
name: 'browserify',
message: deps.length + ' files changed'
})
}
})
}
var defaultWatchGlob = opts.watchGlob || '**/*.{html,css}'
var server = null
var closed = false
var started = false
var fileWatcher = null
var reloader = null
var deferredWatch = noop
var deferredLive = noop
// public API
emitter.close = once(close)
emitter.reload = reload
emitter.live = live
emitter.watch = watch
// setup defaults for live reload / watchify
if (opts.live) {
var initialLiveOpts = typeof opts.live === 'object' ? opts.live : undefined
emitter
.watch()
.live(initialLiveOpts)
.on('watch', function (ev, file) {
if (ev !== 'change' && ev !== 'add') {
return
}
defaultFileEvent(file)
})
.on('pending', function () {
defaultFileEvent(opts.serve)
})
}
// First, setup a server
createServer(middleware, opts, function (err, serverInstance) {
if (err) {
emitter.emit('error', err)
return
}
server = serverInstance
// start portfinding + connect
getPorts(opts, handlePorts)
})
return emitter
function defaultFileEvent (file) {
var filename = path.basename(file)
if ((Array.isArray(opts.live) || typeof opts.live === 'string') &&
isMatch(filename, opts.live).length === 0) {
return
}
emitter.reload(file)
}
function reload (file) {
process.nextTick(emitter.emit.bind(emitter, 'reload', file))
if (reloader) {
reloader.reload(file)
}
}
// enable file watch capabilities
function watch (glob, watchOpt) {
if (!started) {
deferredWatch = emitter.watch.bind(null, glob, watchOpt)
} else {
// destroy previous
if (fileWatcher) fileWatcher.close()
glob = glob && glob.length > 0 ? glob : defaultWatchGlob
glob = Array.isArray(glob) ? glob : [ glob ]
watchOpt = xtend({ poll: opts.poll }, watchOpt)
fileWatcher = createFileWatch(glob, watchOpt)
fileWatcher.on('watch', emitter.emit.bind(emitter, 'watch'))
}
return emitter
}
// enables LiveReload capabilities
function live (liveOpts) {
if (!started) {
deferredLive = emitter.live.bind(null, liveOpts)
} else {
// destroy previous
if (reloader) reloader.close()
// pass some options for the server middleware
server.setLiveOptions(xtend(liveOpts))
// create a web socket server for live reload
reloader = createReloadServer(server, opts)
}
return emitter
}
function getHostAddress (host) {
// user can specify "::" or "0.0.0.0" as host exactly
// or if undefined, default to internal-ip
if (!host) {
host = server.address().address
if (host === '0.0.0.0') {
// node 0.10 returns this when no host is specified
// node 0.12 returns internal-ip
host = '::'
}
}
if (host === '::') {
host = internalIp()
}
return host
}
function handlePorts (err, result) {
if (closed) return
if (err) {
emitter.emit('error', err)
return
}
opts.port = result.port
// improve error messaging
server.on('error', function (err) {
if (err.code === 'EADDRINUSE') {
err.message = 'port ' + opts.port + ' is in use'
emitter.emit('error', err)
} else {
emitter.emit('error', err)
}
})
// start server
// no host -> use localhost + internal-ip
server.listen(opts.port, opts.host || undefined, connect)
}
function connect () {
if (closed) return
started = true
// default host is internal IP
opts.host = getHostAddress(opts.host)
var port = opts.port
var protocol = opts.ssl ? 'https' : 'http'
var uri = protocol + '://' + opts.host + ':' + port + '/'
log.info({ message: 'Server running at', url: uri, type: 'connect' })
// if live() or watch() was called before connection
deferredWatch()
deferredLive()
// provide info on server connection
emitter.emit('connect', {
uri: uri,
port: port,
host: opts.host,
serve: opts.serve,
entries: entryFiles,
server: server,
webSocketServer: reloader ? reloader.webSocketServer : undefined,
dir: opts.dir
})
// initial bundle should come after
// connect event!
if (bundler) bundler.bundle()
// launch browser
if (opts.open) {
openUrl(uri)
}
}
function close () {
var next = emitter.emit.bind(emitter, 'exit')
if (started) {
server.once('close', next)
} else {
process.nextTick(next)
}
if (started) bole.reset()
if (started) server.close()
if (reloader) reloader.close()
if (bundler) bundler.close()
if (fileWatcher) fileWatcher.close()
closed = true
started = false
}
}

50
static/js/ketcher2/node_modules/budo/lib/bundler.js generated vendored Normal file
View File

@ -0,0 +1,50 @@
var xtend = require('xtend')
var createMiddleware = require('watchify-middleware').emitter
var fromArgs = require('browserify/bin/args')
var browserify = require('browserify')
var path = require('path')
var defaultErrorHandler = require('./error-handler')
module.exports = createBundler
function createBundler (files, opts) {
var bOpts = xtend({
cache: {},
packageCache: {},
debug: opts.debug
}, opts.browserify)
var bundler
var args = opts.browserifyArgs
if (args && Array.isArray(args)) {
// CLI args for browserify
bundler = fromArgs(args, bOpts)
} else {
// just assume JS only options
bundler = browserify(bOpts)
}
files.forEach(function (file) {
bundler.add(path.resolve(file))
})
var errorHandler = opts.errorHandler
if (typeof errorHandler !== 'function' && errorHandler !== false) {
errorHandler = defaultErrorHandler
}
var cwd = opts.cwd
var rootDirName
if (cwd) {
cwd = path.normalize(cwd)
rootDirName = path.basename(cwd) + path.sep
}
return createMiddleware(bundler, {
delay: opts.delay || 0,
initialBundle: false,
errorHandler: typeof errorHandler === 'function'
? function (err) { // pass along directories as well
return errorHandler(err, cwd, rootDirName)
}
: errorHandler // pass undefined / false / etc
})
}

View File

@ -0,0 +1,241 @@
var stripAnsi = require('strip-ansi')
module.exports = errorHandler
module.exports.render = bundleError
function bundleError (message, cwd, rootDirName) {
// Everything has to be contained inside this function
// for it to get stringified correctly. i.e. no require()!
console.error(message)
if (typeof document === 'undefined') {
return
} else if (!document.body) {
document.addEventListener('DOMContentLoaded', createErrorBox)
} else {
createErrorBox()
}
function createErrorBox () {
var parsed = parseError(message)
var overlayBox = document.createElement('div')
css(overlayBox, {
position: 'fixed',
width: '100%',
height: '100%',
zIndex: '100000000',
top: '0',
left: '0',
padding: '20px',
margin: '0px',
'box-sizing': 'border-box',
background: '#fff',
display: 'block',
'font-size': '14px',
'font-weight': 'normal',
'font-family': 'monospace'
})
if (!parsed.format) {
var pre = document.createElement('pre')
pre.textContent = message
css(pre, {
'word-wrap': 'break-word',
'white-space': 'pre-wrap',
'box-sizing': 'border-box',
margin: '0',
color: '#ff0000'
})
overlayBox.appendChild(pre)
} else {
var commonElements = []
var messageDiv = document.createElement('div')
commonElements.push(messageDiv)
messageDiv.textContent = parsed.message
overlayBox.appendChild(messageDiv)
css(messageDiv, {
color: '#ff2e2e',
'font-size': '16px'
})
var pathLocContainer = document.createElement('div')
css(pathLocContainer, { 'padding-top': '10px' })
if (isFinite(parsed.line)) {
var location = document.createElement('div')
commonElements.push(location)
var colStr = isFinite(parsed.column) ? (', column ' + parsed.column) : ''
location.textContent = ('line ' + parsed.line + colStr).trim()
css(location, {
color: 'hsl(0, 0%, 50%)',
'padding-bottom': '0px',
'font-size': '12px',
'font-weight': 'bold'
})
pathLocContainer.appendChild(location)
}
var path = document.createElement('div')
path.textContent = trimPath(parsed.path)
commonElements.push(path)
css(path, { 'font-style': 'italic' })
pathLocContainer.appendChild(path)
overlayBox.appendChild(pathLocContainer)
if (parsed.code) {
var sourceContainer = document.createElement('div')
var source = document.createElement('div')
var hr = document.createElement('div')
css(hr, {
background: 'hsl(0, 0%, 90%)',
width: '100%',
height: '2px',
padding: '0',
'margin-bottom': '10px',
'margin-top': '10px'
})
commonElements.push(source)
source.textContent = parsed.code
css(source, {
color: 'black',
'font-weight': 'bold',
'font-size': '14px',
'padding-left': '0px'
})
sourceContainer.appendChild(hr)
sourceContainer.appendChild(source)
overlayBox.appendChild(sourceContainer)
}
// apply common styles
commonElements.forEach(function (e) {
css(e, {
'word-wrap': 'break-word',
'white-space': 'pre-wrap',
'box-sizing': 'border-box',
display: 'block',
margin: '0',
'vertical-align': 'bottom'
})
})
}
document.body.appendChild(overlayBox)
}
function trimPath (filePath) {
if (filePath.indexOf(cwd) === 0) {
filePath = rootDirName + filePath.substring(cwd.length + 1)
}
return filePath
}
function css (element, style) {
Object.keys(style).forEach(function (k) {
element.style[k] = style[k]
})
}
// parse an error message into pieces
function parseError (err) {
var filePath, lineNum, splitLines
var result = {}
// For root files that syntax-error doesn't pick up:
var parseFilePrefix = 'Parsing file '
if (err.indexOf(parseFilePrefix) === 0) {
var pathWithErr = err.substring(parseFilePrefix.length)
filePath = getFilePath(pathWithErr)
if (!filePath) return result
result.path = filePath
var messageAndLine = pathWithErr.substring(filePath.length)
lineNum = /\((\d+):(\d+)\)/.exec(messageAndLine)
if (!lineNum) return result
result.message = messageAndLine.substring(1, lineNum.index).trim()
result.line = parseInt(lineNum[1], 10)
result.column = parseInt(lineNum[2], 10)
result.format = true
return result
}
// if module not found
var cannotFindModule = /^Cannot find module '(.+)' from '(.+)'(?:$| while parsing file: (.*)$)/.exec(err.trim())
if (cannotFindModule) {
result.missingModule = cannotFindModule[1]
result.path = cannotFindModule[3] || cannotFindModule[2]
result.message = "Cannot find module '" + result.missingModule + "'"
result.format = true
return result
}
// syntax-error returns the path and line number, also a \n at start
err = err.trim()
filePath = getFilePath(err)
if (!filePath) return result
result.path = filePath
var restOfMessage = err.substring(filePath.length)
var parsedSyntaxError = /^:(\d+)/.exec(restOfMessage)
if (parsedSyntaxError) { // this is a syntax-error
lineNum = parseInt(parsedSyntaxError[1], 10)
if (isFinite(lineNum)) result.line = lineNum
splitLines = restOfMessage.split('\n')
var code = splitLines.slice(1, splitLines.length - 1).join('\n')
result.code = code
result.message = splitLines[splitLines.length - 1]
result.format = true
return result
}
// remove colon
restOfMessage = restOfMessage.substring(1).trim()
var whileParsing = 'while parsing file: '
var whileParsingIdx = restOfMessage.indexOf(whileParsing)
if (whileParsingIdx >= 0) {
var beforeWhile = restOfMessage.substring(0, whileParsingIdx)
lineNum = /\((\d+):(\d+)\)/.exec(beforeWhile.split('\n')[0])
var messageStr = beforeWhile
if (lineNum) {
var line = parseInt(lineNum[1], 10)
var col = parseInt(lineNum[2], 10)
if (isFinite(line)) result.line = line
if (isFinite(col)) result.column = col
messageStr = messageStr.substring(0, lineNum.index)
}
result.message = messageStr.trim()
splitLines = restOfMessage.split('\n')
result.code = splitLines.slice(2).join('\n')
result.format = true
}
return result
}
// get a file path from the error message
function getFilePath (str) {
var hasRoot = /^[a-z]:/i.exec(str)
var colonLeftIndex = 0
if (hasRoot) {
colonLeftIndex = hasRoot[0].length
}
var pathEnd = str.split('\n')[0].indexOf(':', colonLeftIndex)
if (pathEnd === -1) {
// invalid string, return non-formattable result
return null
}
return str.substring(0, pathEnd)
}
}
function errorHandler (err, cwd, rootDirName) {
console.error('%s', err)
var msgStr = stripAnsi(err.message)
var params = [
JSON.stringify(msgStr),
JSON.stringify(cwd),
JSON.stringify(rootDirName)
].join(',')
return ';(' + bundleError + ')(' + params + ');'
}

45
static/js/ketcher2/node_modules/budo/lib/file-watch.js generated vendored Normal file
View File

@ -0,0 +1,45 @@
// a thin wrapper around chokidar file watching HTML / CSS
var watch = require('chokidar').watch
var xtend = require('xtend')
var Emitter = require('events/')
var ignores = [
'node_modules/**', 'bower_components/**',
'.git', '.hg', '.svn', '.DS_Store',
'*.swp', 'thumbs.db', 'desktop.ini'
]
module.exports = function (glob, opt) {
opt = xtend({
usePolling: opt && opt.poll,
ignored: ignores,
ignoreInitial: true
}, opt)
var emitter = new Emitter()
var closed = false
var ready = false
var watcher = watch(glob, opt)
watcher.on('add', onWatch.bind(null, 'add'))
watcher.on('change', onWatch.bind(null, 'change'))
// chokidar@1.0.0-r6 only allows close after ready event
watcher.once('ready', function () {
ready = true
if (closed) watcher.close()
})
function onWatch (event, path) {
emitter.emit('watch', event, path)
}
emitter.close = function () {
if (closed) return
if (ready) watcher.close()
closed = true
}
return emitter
}
module.exports.ignores = ignores

24
static/js/ketcher2/node_modules/budo/lib/get-ports.js generated vendored Normal file
View File

@ -0,0 +1,24 @@
var xtend = require('xtend')
var getPorts = require('get-ports')
module.exports = getServerPorts
function getServerPorts (opt, cb) {
opt = xtend({ port: 9966 }, opt)
// try to use exact port specified or the defaults
if (!opt.portfind) {
return process.nextTick(function () {
cb(null, {
port: opt.port
})
})
}
// find available ports
getPorts([ opt.port ], function (err, ports) {
if (err) return cb(err)
cb(null, {
port: ports[0]
})
})
}

43
static/js/ketcher2/node_modules/budo/lib/map-entry.js generated vendored Normal file
View File

@ -0,0 +1,43 @@
var path = require('path')
var url = require('url')
var resolve = require('resolve')
module.exports = mapEntry
function mapEntry (file) {
if (file === '.') {
file = entry()
}
var parts
// absolute path with letter drive, eg C:/
if (/^[A-Z]:[/\\]+/.test(file)) {
parts = file.split(/:(?:(?=[^/\\]))/)
} else {
parts = file.split(':')
}
var pathFrom, pathUrl
if (parts.length > 1 && parts[1].length > 0) {
pathFrom = parts[0]
pathUrl = parts[1]
if (pathFrom === '.') {
pathFrom = entry()
}
} else {
pathFrom = file
pathUrl = url.parse(path.basename(pathFrom)).pathname
}
return {
url: pathUrl,
from: pathFrom
}
}
function entry () {
var cwd = process.cwd()
var file = resolve.sync('.', { basedir: cwd })
return file || 'index.js'
}

248
static/js/ketcher2/node_modules/budo/lib/middleware.js generated vendored Normal file
View File

@ -0,0 +1,248 @@
// TODO: Expose this like webpack-dev-server middleware
var stacked = require('stacked')
var serveStatic = require('serve-static')
var defaultIndex = require('simple-html-index')
var logger = require('./simple-http-logger')
var urlLib = require('url')
var xtend = require('xtend')
var pushState = require('connect-pushstate')
var liveReload = require('inject-lr-script')
var urlTrim = require('url-trim')
var escapeHtml = require('escape-html')
var fs = require('fs')
var browserify = require('browserify')
var path = require('path')
var liveReloadClientFile = path.resolve(__dirname, 'reload', 'client.js')
var bundledReloadClientFile = path.resolve(__dirname, '..', 'build', 'bundled-livereload-client.js')
module.exports = budoMiddleware
function budoMiddleware (entryMiddleware, opts) {
opts = opts || {}
var staticPaths = [].concat(opts.dir).filter(Boolean)
if (staticPaths.length === 0) {
staticPaths = [ process.cwd() ]
}
var entrySrc = opts.serve
var live = opts.live
var cors = opts.cors
var handler = stacked()
var middlewares = [].concat(opts.middleware).filter(Boolean)
// Everything is logged except favicon.ico
var logHandler = logger({
ignores: [ '/favicon.ico' ]
})
handler.use(function (req, res, next) {
if (cors) {
res.setHeader('Access-Control-Allow-Headers', 'Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With')
res.setHeader('Access-Control-Allow-Methods', 'GET, PUT, POST')
res.setHeader('Access-Control-Allow-Origin', '*')
}
logHandler(req, res, next)
})
// User middleware(s) can override others
middlewares.forEach(function (middleware) {
if (typeof middleware !== 'function') {
throw new Error('middleware options must be functions')
}
handler.use(function (req, res, next) {
logHandler.type = 'middleware'
middleware(req, res, next)
})
})
// Re-route for pushState support
if (opts.pushstate) {
if (typeof opts.pushstate === 'string') {
throw new Error('--pushstate is a string, you shouold use subarg options instead')
}
var pushStateOpts = xtend(typeof opts.pushstate === 'boolean' ? {} : opts.pushstate)
delete pushStateOpts._ // added by subarg
handler.use(pushState(pushStateOpts))
}
// Inject liveReload snippet on response
var liveInjector = liveReload({
local: true
})
// this is lazily set and cannot be changed dynamically
var liveScriptUrl
// By default, attempt to optimize the response
var shouldUseBundledLiveReload = true
// Cache the client by default to optimize the response
var liveReloadClient
handler.use(liveReloadHandler)
// Entry (watchify) middleware
if (entryMiddleware) {
var entryRoute = '/' + urlLib.parse(entrySrc).pathname
handler.use(function (req, res, next) {
if (urlTrim(req.url) === urlTrim(entryRoute)) {
entryMiddleware(req, res, next)
} else {
next()
}
})
}
// Ignore favicon clutter
handler.mount('/favicon.ico', favicon)
// If the user wishes to *always* serve
// a generated index instead of a static one.
if (opts.forceDefaultIndex) {
handler.use(indexHandler)
}
// Static assets (html/images/etc)
staticPaths.forEach(function (rootFile) {
var staticOpts = xtend({
cacheControl: false
}, opts.staticOptions)
delete staticOpts._ // from subarg
var staticHandler = serveStatic(rootFile, staticOpts)
handler.use(function (req, res, next) {
logHandler.type = 'static'
staticHandler(req, res, next)
})
})
// Generates a default index.html
// when none is found locally.
handler.use(indexHandler)
// Handle errors
handler.use(function (req, res) {
res.statusCode = 404
res.end('404 not found: ' + escapeHtml(req.url))
})
// Allow live options to be changed at runtime
handler.setLiveOptions = setLiveOptions
return handler
function setLiveOptions (opts) {
live = opts
}
function favicon (req, res) {
var maxAge = 345600 // 4 days
res.setHeader('Cache-Control', 'public, max-age=' + Math.floor(maxAge / 1000))
res.setHeader('Content-Type', 'image/x-icon')
res.statusCode = 200
res.end()
}
function indexHandler (req, res, next) {
if (urlLib.parse(req.url).pathname === '/' || /\/index.html?/i.test(req.url)) {
// If we reach this, our response will be generated
// (not static from local file system)
logHandler.type = 'generated'
res.setHeader('content-type', 'text/html')
var stream = opts.defaultIndex || defaultIndex
stream({
entry: entrySrc,
title: opts.title,
css: opts.css,
base: opts.base === true ? '/' : (opts.base || null)
}, req).pipe(res)
} else {
next()
}
}
function serveBundledLiveReload (res, successCallback) {
if (liveReloadClient) {
res.end(liveReloadClient)
successCallback(true)
} else {
fs.readFile(bundledReloadClientFile, function (err, src) {
if (err) {
if (shouldUseBundledLiveReload) {
console.error([
'NOTE: The bundled LiveReload client could not be found, so budo will',
'generate this on the fly.',
'This is most likely because you are using a git cloned version of budo',
'instead of installing it from npm.',
'You can run this from your cloned budo folder to create a build:',
' npm run bundle-live-client'
].join('\n'))
}
shouldUseBundledLiveReload = false
successCallback(false)
} else {
liveReloadClient = src
res.end(src)
successCallback(true)
}
})
}
}
function serveBrowserifyLiveReload (cache, debug, liveScripts, res) {
// Browserify the client file, e.g. if user has a script to include
if (cache && liveReloadClient) {
res.end(liveReloadClient)
} else {
var b = browserify({ debug: debug })
b.add(liveReloadClientFile)
if (live.expose) {
b.require(liveReloadClientFile, { expose: 'budo-livereload' })
}
liveScripts.forEach(function (file) {
b.add(path.resolve(file))
})
b.bundle(function (err, src) {
if (err) {
console.error('Error bundling LiveReload client:\n' + err.message)
res.statusCode = 500
res.end('Error bundling LiveReload client: ' + err)
} else {
liveReloadClient = src
res.end(src)
}
})
}
}
function liveReloadHandler (req, res, next) {
if (!live || live.plugin) return next()
if (!liveScriptUrl) {
liveScriptUrl = live.path || '/budo/livereload.js'
logHandler.ignores.push(liveScriptUrl)
} else if (liveScriptUrl && live.path && liveScriptUrl !== live.path) {
var errMessage = 'Error: The LiveReload path field cannot be changed dynamically.\n' +
'Please open an issue in budo if you have a specific use case for this.'
console.error(errMessage)
res.statusCode = 500
res.end(errMessage)
return
}
if (req.url === liveScriptUrl) {
res.statusCode = 200
res.setHeader('Content-Type', 'application/javascript')
var liveScripts = (Array.isArray(live.include) ? live.include : [ live.include ]).filter(Boolean)
var cache = live.cache !== false
var debug = live.debug
// Default setup - use a bundled JS file for LiveReload client
if (shouldUseBundledLiveReload && cache && !debug && liveScripts.length === 0) {
serveBundledLiveReload(res, function (success) {
// fall back to browserify on the fly
if (!success) serveBrowserifyLiveReload(cache, debug, liveScripts, res)
})
} else {
serveBrowserifyLiveReload(cache, debug, liveScripts, res)
}
} else {
liveInjector.path = liveScriptUrl
liveInjector(req, res, next)
}
}
}

70
static/js/ketcher2/node_modules/budo/lib/parse-args.js generated vendored Normal file
View File

@ -0,0 +1,70 @@
var subarg = require('subarg')
var xtend = require('xtend')
module.exports = parseArgs
function parseArgs (args, opt) {
// before parsing subarg, remove the bundler arguments
var bundlerFlags = []
var stopIndex = args.indexOf('--')
if (stopIndex >= 0) {
bundlerFlags = args.slice(stopIndex + 1)
args = args.slice(0, stopIndex)
}
var argv = subarg(args, {
boolean: [
'stream',
'debug',
'errorHandler',
'forceDefaultIndex',
'open',
'portfind',
'ndjson',
'verbose',
'cors',
'ssl'
],
string: [
'host',
'port',
'dir',
'onupdate',
'serve',
'title',
'watchGlob',
'cert',
'key'
],
default: module.exports.defaults,
alias: {
port: 'p',
ssl: 'S',
serve: 's',
cert: 'C',
key: 'K',
verbose: 'v',
help: 'h',
host: 'H',
dir: 'd',
live: 'l',
open: 'o',
staticOptions: [ 'static-options' ],
watchGlob: [ 'wg', 'watch-glob' ],
errorHandler: 'error-handler',
forceDefaultIndex: 'force-default-index',
pushstate: 'P'
},
'--': true
})
// add back in the bundler flags
argv['--'] = bundlerFlags
return xtend(argv, opt)
}
module.exports.defaults = {
title: 'budo',
port: 9966,
debug: true,
stream: true,
errorHandler: true,
portfind: true
}

View File

@ -0,0 +1,134 @@
var reloadCSS = require('reload-css')
module.exports = connect()
function connect () {
var reconnectPoll = 1000
var maxRetries = 50
var retries = 0
var reconnectInterval
var isReconnecting = false
var protocol = document.location.protocol
var hostname = document.location.hostname
var port = document.location.port
var host = hostname + ':' + port
var isIOS = /(iOS|iPhone|iPad|iPod)/i.test(navigator.userAgent)
var isSSL = /^https:/i.test(protocol)
var queued = []
var socket = createWebSocket()
var listeners = []
var api = {
send: function (message) {
message = JSON.stringify(message)
if (socket && socket.readyState === 1) {
socket.send(message)
} else {
queued.push(message)
}
},
listen: function (cb) {
if (typeof cb !== 'function') {
throw new TypeError('cb must be a function!')
}
listeners.push(cb)
},
reloadPage: reloadPage,
reloadCSS: reloadCSS
}
return api
function scheduleReconnect () {
if (isIOS && isSSL) {
// Special case for iOS with a self-signed certificate.
console.warn('[budo] LiveReload disconnected. You may need to generate and ' +
'trust a self-signed certificate, see here:\n' +
'https://github.com/mattdesl/budo/blob/master/docs/' +
'command-line-usage.md#ssl-on-ios')
return
}
if (isSSL) {
// Don't attempt to re-connect in SSL since it will likely be insecure
console.warn('[budo] LiveReload disconnected. Please reload the page to retry.')
return
}
if (retries >= maxRetries) {
console.warn('[budo] LiveReload disconnected, exceeded retry count. Please reload the page to retry.')
return
}
if (!isReconnecting) {
isReconnecting = true
console.warn('[budo] LiveReload disconnected, retrying...')
}
retries++
clearTimeout(reconnectInterval)
reconnectInterval = setTimeout(reconnect, reconnectPoll)
}
function reconnect () {
if (socket) {
// force close the existing socket
socket.onclose = function () {}
socket.close()
}
socket = createWebSocket()
}
function createWebSocket () {
var wsProtocol = isSSL ? 'wss://' : 'ws://'
var wsUrl = wsProtocol + host + '/livereload'
var ws = new window.WebSocket(wsUrl)
ws.onmessage = function (event) {
var data
try {
data = JSON.parse(event.data)
} catch (err) {
console.warn('Error parsing LiveReload server data: ' + event.data)
return
}
if (data.event === 'reload') {
if (/^\.?css$/i.test(data.ext)) {
reloadCSS(data.url)
} else {
reloadPage()
}
}
// let listeners receive data
listeners.forEach(function (listener) {
listener(data)
})
}
ws.onclose = function (ev) {
if (ev.code === 1000 || ev.code === 1001) {
// Browser is navigating away.
return
}
scheduleReconnect()
}
ws.onopen = function () {
if (isReconnecting) {
isReconnecting = false
retries = 0
console.warn('[budo] LiveReload reconnected.')
}
if (queued.length && ws.readyState === 1) {
queued.forEach(function (message) {
ws.send(message)
})
queued.length = 0
}
}
ws.onerror = function () {
return false
}
return ws
}
}
function reloadPage () {
window.location.reload(true)
}

View File

@ -0,0 +1,78 @@
var WebSocketServer = require('ws').Server
var log = require('bole')('budo')
var path = require('path')
var isAbsolute = require('path-is-absolute')
var color = require('term-color')
module.exports = function (server, opts) {
opts = opts || {}
log.info({ message: 'LiveReload running' })
// get a list of static folders to use as base dirs
var cwd = path.resolve(opts.cwd || process.cwd())
var staticDirs = Array.isArray(opts.dir) ? opts.dir : [ opts.dir ]
staticDirs = staticDirs.map(function (dir) {
return path.resolve(dir)
})
if (staticDirs.indexOf(cwd) === -1) staticDirs.push(cwd)
var closed = false
var wss = new WebSocketServer({
server: server,
perMessageDeflate: false
})
return {
webSocketServer: wss,
reload: reload,
close: function () {
if (closed) return
wss.close()
closed = true
}
}
function reload (file) {
if (closed) return
var url, ext
if (file && typeof file === 'string') {
// absolute file path
file = isAbsolute(file) ? path.normalize(file) : path.resolve(cwd, file)
// make it relative, removing the static folder parts
for (var i = 0; i < staticDirs.length; i++) {
var dir = staticDirs[i]
url = path.relative(dir, file)
// if the path doesn't starts with "../", then
// it should be relative to this folder
if (!/^(\.\.[/\\]|[/\\])/.test(url)) break
}
// turn it into a URL
url = url.replace(/\\/g, '/')
// ensure it starts at root of app
if (url.charAt(0) !== '/') url = '/' + url
ext = path.extname(file)
}
broadcast({ event: 'reload', ext: ext, url: url })
}
function broadcast (data) {
if (closed) return
data = JSON.stringify(data)
try {
wss.clients.forEach(function (client) {
client.send(data, {
binary: false
})
})
} catch (err) {
console.error(color.red('ERROR'), 'Error sending LiveReload event to client:')
console.error(err)
}
}
}

49
static/js/ketcher2/node_modules/budo/lib/server.js generated vendored Normal file
View File

@ -0,0 +1,49 @@
var http = require('http')
var https = require('https')
var pem = require('pem')
var createMiddleware = require('./middleware')
var fs = require('fs')
module.exports = function createServer (entryMiddleware, opts, cb) {
var handler = createMiddleware(entryMiddleware, opts)
var ssl = opts.ssl
if (ssl && (!opts.cert && opts.key) || (!opts.key && opts.cert)) {
throw new TypeError('If you specify a cert, you must specify a key and vice versa.\n' +
'Or, you can omit the "cert" and "key" options to generate a new self-signed certificate.')
}
if (opts.ssl) {
if (opts.cert && opts.key) {
// user specified their own cert/key pair
create({
cert: fs.readFileSync(opts.cert),
key: fs.readFileSync(opts.key)
})
} else {
// generate a self-signed cert
pem.createCertificate({ days: 1, selfSigned: true }, function (err, keys) {
if (err) return cb(err)
create({
key: keys.serviceKey,
cert: keys.certificate
})
})
}
} else {
// no HTTPS, handle normally
create()
}
function create (httpsOpts) {
var server = ssl
? https.createServer(httpsOpts, handler)
: http.createServer(handler)
server.setLiveOptions = handler.setLiveOptions
// TODO: Perhaps --ssl should support some sort of HTTP -> HTTPS redirect
process.nextTick(function () {
cb(null, server)
})
}
}

View File

@ -0,0 +1,75 @@
var log = require('bole')('budo')
var onResHeaders = require('on-headers')
var onResFinished = require('on-finished')
module.exports = simpleHttpLoggerMiddleware
function simpleHttpLoggerMiddleware (opts) {
opts = opts || {}
var httpLogger = function simpleHttpLogger (req, res, next) {
if (httpLogger.ignores.indexOf(req.url) >= 0) return next()
if (!req.url) return next()
// request data
req._startAt = undefined
// response data
res._startAt = undefined
// record request start
recordStartTime.call(req)
var byteLength = 0
var logRequest = function () {
if (!req._startAt || !res._startAt) {
// missing request and/or response start time
return
}
// calculate diff
var ms = (res._startAt[0] - req._startAt[0]) * 1000 +
(res._startAt[1] - req._startAt[1]) * 1e-6
log.info({
elapsed: ms,
contentLength: byteLength,
method: (req.method || 'GET').toUpperCase(),
url: req.url,
statusCode: res.statusCode,
type: httpLogger.type === 'static' ? undefined : httpLogger.type,
colors: {
elapsed: ms > 1000 ? 'yellow' : 'dim'
}
})
}
var isAlreadyLogging = res._simpleHttpLogger
res._simpleHttpLogger = true
if (!isAlreadyLogging) {
// record response start
onResHeaders(res, recordStartTime)
// log when response finished
onResFinished(res, logRequest)
var writeFn = res.write
// catch content-length of payload
res.write = function (payload) {
if (payload) byteLength += payload.length
return writeFn.apply(res, arguments)
}
}
next()
}
httpLogger.ignores = [].concat(opts.ignores).filter(Boolean)
httpLogger.type = 'static'
return httpLogger
}
function recordStartTime () {
this._startAt = process.hrtime()
}