"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const tiny_lr_1 = __importDefault(require("tiny-lr")); const open_1 = __importDefault(require("open")); const immutable_1 = __importDefault(require("immutable")); const parse_1 = __importDefault(require("../parse")); const output_1 = __importDefault(require("../output")); const modifiers_1 = __importDefault(require("../modifiers")); const promise_1 = __importDefault(require("../utils/promise")); const options_1 = __importDefault(require("./options")); const getBook_1 = __importDefault(require("./getBook")); const getOutputFolder_1 = __importDefault(require("./getOutputFolder")); const server_1 = __importDefault(require("./server")); const watch_1 = __importDefault(require("./watch")); const page_cache_1 = require("../output/page-cache"); const fs_1 = __importDefault(require("fs")); let server, lrServer, lrPath; function waitForCtrlC() { const d = promise_1.default.defer(); process.on("SIGINT", () => { d.resolve(); }); return d.promise; } function startServer(args, kwargs) { const outputFolder = (0, getOutputFolder_1.default)(args); const port = kwargs.port; const browser = kwargs["browser"]; const book = (0, getBook_1.default)(args, kwargs); const hasWatch = kwargs["watch"]; const hasOpen = kwargs["open"]; const hasLiveReloading = kwargs["live"]; const reload = kwargs["reload"]; const Generator = output_1.default.getGenerator(kwargs.format); const logger = book.getLogger(); logger.info.ok("Starting server ..."); let lastOutput = null; return promise_1.default.all([ server.start(outputFolder, port), generateBook({ book, outputFolder, hasLiveReloading, Generator, reload }).then((output) => { lastOutput = output; return output; }) ]) .then(() => { console.log(`Serving book on http://localhost:${port}`); if (hasOpen) { (0, open_1.default)(`http://localhost:${port}`, { app: browser }); } }) .then(() => { if (!hasWatch) { return waitForCtrlC(); } // update book immutably. does not use book again return (0, watch_1.default)(book.getRoot(), (error, filepath) => { if (error) { console.error(error); return; } // If the file does not exist in file system, show a warning and skip // Probably, the file has been deleted if (!fs_1.default.existsSync(filepath)) { logger.warn.ok(`${filepath} does not exist in file system.`); return; } // set livereload path lrPath = filepath; // TODO: use parse extension // Incremental update for pages if (lastOutput && filepath.endsWith(".md")) { logger.warn.ok("Rebuild " + filepath); const changedOutput = lastOutput.reloadPage(lastOutput.book.getContentRoot(), filepath).merge({ incrementalChangeFileSet: immutable_1.default.Set([filepath]) }); return incrementalBuild({ output: changedOutput, Generator }).then(() => { if (lrPath && hasLiveReloading) { // trigger livereload lrServer.changed({ body: { files: [lrPath] } }); } }); } // Asciidoc files are not supported for incremental build logger.info.ok("Rebuild " + filepath); return generateBook({ book, outputFolder, hasLiveReloading, Generator, reload }).then((output) => { lastOutput = output; }); }); }); } function generateBook({ book, outputFolder, hasLiveReloading, Generator, reload }) { // Stop server if running if (reload) { book.getLogger().info.ok(`Clear cache`); (0, page_cache_1.clearCache)(); } return parse_1.default.parseBook(book).then((resultBook) => { if (hasLiveReloading) { // Enable livereload plugin let config = resultBook.getConfig(); // @ts-expect-error ts-migrate(2554) FIXME: Expected 3 arguments, but got 2. config = modifiers_1.default.Config.addPlugin(config, "livereload"); resultBook = resultBook.set("config", config); } return output_1.default.generate(Generator, resultBook, { root: outputFolder }); }); } function incrementalBuild({ output, Generator }) { return output_1.default.incrementalBuild(Generator, output); } exports.default = { name: "serve [book] [output]", description: "serve the book as a website for testing", options: [ { name: "port", description: "Port for server to listen on", defaults: 4000 }, { name: "lrport", description: "Port for livereload server to listen on", defaults: 35729 }, { name: "watch", description: "Enable file watcher and live reloading", defaults: true }, { name: "live", description: "Enable live reloading", defaults: true }, { name: "open", description: "Enable opening book in browser", defaults: false }, { name: "browser", description: "Specify browser for opening book", defaults: "" }, options_1.default.log, options_1.default.format, options_1.default.reload ], exec: function (args, kwargs) { server = new server_1.default(); const hasWatch = kwargs["watch"]; const hasLiveReloading = kwargs["live"]; return (0, promise_1.default)() .then(() => { if (!hasWatch || !hasLiveReloading) { return; } lrServer = (0, tiny_lr_1.default)({}); return promise_1.default.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport).then(() => { console.log("Live reload server started on port:", kwargs.lrport); console.log("Press CTRL+C to quit ..."); console.log(""); }); }) .then(() => { return startServer(args, kwargs); }); } };