diff --git a/src/commands/docs.js b/src/commands/docs.js index 98769a8..ce3fe48 100644 --- a/src/commands/docs.js +++ b/src/commands/docs.js @@ -2,29 +2,94 @@ var path = require('path'); var fs = require('fs'); +var http = require('http'); var { exec } = require('child_process'); var { getPlatformDir } = require('../utils/platform'); var DOCS = { - desktop: { label: 'Desktop (Java)', subpath: path.join('docs', 'java', 'index.html') }, - mobile: { label: 'Mobile (React Native)', subpath: path.join('docs', 'react-native', 'index.html') }, + desktop: { label: 'Desktop (Java)', subpath: 'docs/java/index.html' }, + mobile: { label: 'Mobile (React Native)', subpath: 'docs/react-native/index.html' }, }; -function openUrl(filePath) { - var cmd; - if (process.platform === 'win32') cmd = 'start "" "' + filePath + '"'; - else if (process.platform === 'darwin') cmd = 'open "' + filePath + '"'; - else cmd = 'xdg-open "' + filePath + '"'; +var MIME = { + '.html': 'text/html; charset=utf-8', + '.css': 'text/css', + '.js': 'application/javascript', + '.json': 'application/json', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.gif': 'image/gif', + '.svg': 'image/svg+xml', + '.ico': 'image/x-icon', + '.woff': 'font/woff', + '.woff2':'font/woff2', + '.ttf': 'font/ttf', +}; +function getMime(filePath) { + return MIME[path.extname(filePath).toLowerCase()] || 'application/octet-stream'; +} + +function openBrowser(url) { + var cmd; + if (process.platform === 'win32') cmd = 'start "" "' + url + '"'; + else if (process.platform === 'darwin') cmd = 'open "' + url + '"'; + else cmd = 'xdg-open "' + url + '"'; exec(cmd, function (err) { if (err) { console.error('Erro ao abrir o navegador: ' + err.message); - console.error('Abra manualmente: ' + filePath); - process.exit(1); + console.error('Acesse manualmente: ' + url); } }); } +function serve(platformDir, entryUrl, selectorHtml) { + var server = http.createServer(function (req, res) { + var urlPath = req.url.split('?')[0]; + + if (urlPath === '/' || urlPath === '/index.html') { + res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); + res.end(selectorHtml); + return; + } + + // Normalize URL path separators for Windows + var relative = urlPath.replace(/\//g, path.sep).replace(/^\\/, ''); + var filePath = path.join(platformDir, relative); + + // Prevent path traversal + if (!filePath.startsWith(platformDir + path.sep) && filePath !== platformDir) { + res.writeHead(403); + res.end(); + return; + } + + // Serve directory index + try { + if (fs.statSync(filePath).isDirectory()) { + filePath = path.join(filePath, 'index.html'); + } + } catch (_) {} + + fs.readFile(filePath, function (err, data) { + if (err) { res.writeHead(404); res.end(); return; } + res.writeHead(200, { 'Content-Type': getMime(filePath) }); + res.end(data); + }); + }); + + server.listen(0, '127.0.0.1', function () { + var port = server.address().port; + var url = 'http://127.0.0.1:' + port + entryUrl; + console.log('Servidor local em ' + url); + console.log('Pressione Ctrl+C para encerrar.'); + openBrowser(url); + }); + + process.on('SIGINT', function () { server.close(function () { process.exit(0); }); }); + process.on('SIGTERM', function () { server.close(function () { process.exit(0); }); }); +} + function buildSelectionPage() { return ` @@ -105,16 +170,8 @@ function buildSelectionPage() { box-shadow: 0 6px 20px rgba(247, 130, 89, 0.25); } - .btn-primary { - background: #F78259; - color: #fff; - } - - .btn-secondary { - background: #fff3ef; - color: #c05a30; - border: 2px solid #f7c2ad; - } + .btn-primary { background: #F78259; color: #fff; } + .btn-secondary { background: #fff3ef; color: #c05a30; border: 2px solid #f7c2ad; } .btn-icon { width: 38px; @@ -127,10 +184,7 @@ function buildSelectionPage() { flex-shrink: 0; } - .btn-secondary .btn-icon { - background: rgba(247, 130, 89, 0.12); - } - + .btn-secondary .btn-icon { background: rgba(247, 130, 89, 0.12); } .btn-icon svg { width: 20px; height: 20px; } .btn-primary .btn-icon svg { fill: #fff; } .btn-secondary .btn-icon svg { fill: #F78259; } @@ -144,11 +198,7 @@ function buildSelectionPage() { margin-top: 2px; } - footer { - margin-top: 32px; - font-size: 0.78rem; - color: #bbb; - } + footer { margin-top: 32px; font-size: 0.78rem; color: #bbb; }
@@ -163,7 +213,7 @@ function buildSelectionPage() {Selecione abaixo qual documentação você deseja consultar.