Repository: kt3k/remarker Branch: main Commit: a3698e754e9b Files: 44 Total size: 1.2 MB Directory structure: gitextract_o9ditkzz/ ├── .bmp.yml ├── .editorconfig ├── .github/ │ └── workflows/ │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── assets/ │ ├── default.css │ └── help-message.txt ├── examples/ │ ├── add-scripts/ │ │ ├── bar.css │ │ ├── baz.js │ │ ├── foo.css │ │ ├── qux.js │ │ ├── remarker.yml │ │ └── slides.md │ ├── favicon/ │ │ ├── remarker.yml │ │ └── slides.md │ ├── has-assets/ │ │ └── slides.md │ ├── latex-mathjax/ │ │ ├── remarker.yml │ │ └── slides.md │ ├── livereload-false/ │ │ ├── remarker.yml │ │ └── slides.md │ ├── livereload-port/ │ │ ├── remarker.yml │ │ └── slides.md │ ├── metatags/ │ │ ├── README.md │ │ ├── my-slides-2.md │ │ ├── my-slides.md │ │ ├── remarker.yml │ │ └── slides.md │ ├── remark/ │ │ ├── README.md │ │ ├── remarker.yml │ │ └── slides.md │ ├── replace-remark/ │ │ ├── my-own-remark.js │ │ ├── remarker.yml │ │ └── slides.md │ └── simple/ │ ├── README.md │ ├── my-slides-2.md │ ├── my-slides.md │ └── slides.md ├── index.js ├── layout.njk ├── package.json ├── test.js └── vendor/ ├── livereload.js └── remark.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .bmp.yml ================================================ version: 1.15.0 commit: Bump to version v%.%.% files: README.md: remarker v%.%.% package.json: '"version": "%.%.%"' ================================================ FILE: .editorconfig ================================================ root=true [*] indent_style=space indent_size=2 trim_trailing_whitespace=true insert_final_newline=true ================================================ FILE: .github/workflows/ci.yml ================================================ name: ci on: push: branches: [main] pull_request: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v4 - run: npm install - run: npm run cov - uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} ================================================ FILE: .gitignore ================================================ # npm /node_modules # Sorry, npm. We prefer yarn.lock /package-lock.json # coverage /coverage /.nyc_output ================================================ FILE: LICENSE ================================================ The MIT License Copyright © 2016 Yoshiya Hinosawa ( @kt3k ) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # remarker v1.15.0 [![ci](https://github.com/kt3k/remarker/actions/workflows/ci.yml/badge.svg)](https://github.com/kt3k/remarker/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/kt3k/remarker/branch/master/graph/badge.svg)](https://codecov.io/gh/kt3k/remarker) > [Remark][remark] cli [remark][remark] is a simple, in-browser, markdown-driven slideshow tool. `remarker` is a command line tool for building a remark-based slideshow page very easily. # Usage Install via npm: ```console $ npm install --save remarker ``` Write your slide in markdown: ```md # My Slide --- # My Slide 2 ??? Presenter notes here --- ``` save the above as `slides.md` Invoke `remarker` command. ```console $ ./node_modules/.bin/remarker ``` Or if you have `npx` command, then hit: ```console $ npx remarker ``` This starts a local server at port 6275 (this is configurable) and you can see your slides at [http://localhost:6275/](http://localhost:6275/). See remark's [slide](https://remarkjs.com/) and [documentation](https://github.com/gnab/remark#remark) for more details about its syntax, features etc. ## Build slides You can build your slides as static page as `remarker build` command. ```console $ ./node_modules/.bin/remarker build ``` This builds your slides as html page under `build/` directory. The output directory is configurable. See the below for details. ## Installing globally You can instead install it globally, in one of these two ways: ```bash sudo npm i -g remarker # from the npm repository sudo npm i -g . # if there's a clone in the current directory ``` After that, you should be able to invoke it this way from any directory in your system: ```bash remarker [build] ``` # Configuration You can configure remarker with the configuration file `remarker.yml`: (Note: remarker.yml should be put in the current directory.) Default settings are as follows: ```yml port: 6275 dest: build out: index.html source: slides.md title: '' assets: ['assets'] css: '' cssFiles: [] script: '' scriptFiles: [] remarkConfig: {} remarkPath: moduleDir + '/vendor/remark.js' scriptFilesAfterCreate: [] livereload: true livereloadPort: 35729 ``` ## Basic options - `port` is the port number of remarker server. Default is `6275`. - `dest` is the destination of `remarker build` command. Default is `build` - `out` is the filename of the result html page. Default is `index.html` - `source` is the source markdown filename. Default is `slides.md`. - `title` is the page title of the slides. Default is an empty string. - `css` is css text you want to add to slides' html page. - `cssFiles` is the list of additional stylesheet files (URL or the file path relative to your current working director) you want to add to slides' html page. If you provide file paths, these files are copied/served statically. Default is an empty array. ## Advanced options - `assets` is the list of assets directory. These directories are copied/served statically. - `scriptFiles` is the list of additional JavaScript files (URL or the file path relative to your current working director) appended after the remark.js. If you provide file paths, these files are copied/served statically. Default is an empty array. - `script` is additional JavaScript code appended after the remark.js and `scriptFiles`. Default is an empty string. - `remarkConfig` is the config object which is passed to remark.create(options). Default is an empty object. - See [the remark source code](https://github.com/gnab/remark/blob/develop/src/remark/models/slideshow.js#L41-L48) for what option is available. - `remarkPath` is the path to remark.js. This replaces the original remark.js with specified one. - `scriptFilesAfterCreate` is the list of additional JavaScript files (URL or the file path relative to your current working director) appended after the `remark.create()`. If you provide file paths, these files are copied/served statically. Default is an empty array. - `livereload` is the flag to toggle livereloading feature. Default is true. - `livereloadPort` is the port number for livereloading websocket connection. Default is 35729. ## CLI Usage ``` Usage: remarker [options] serve Serves all the assets at localhost remarker [options] build Builds all the assets to the dest Options: -h, --help Shows the help message and exits -v, --version Shows the version number and exits -s, --source Specifies the slide's markdown file. This overrides 'source' property of the config file. -o, --out The output filename of the slides. Default is index.html. -d, --dest The destination directory for built slides. -p, --port The port number for dev server. -b, --open-browser Open the browser to the page when server starts. Default is false. ``` # Examples - [simple example](https://github.com/kt3k/remarker/tree/master/examples/simple) - [remark slides](https://github.com/kt3k/remarker/tree/master/examples/remark) - The original `remark` slides in `remarker` configuration. - [LaTeX and Mathjax](https://github.com/kt3k/remarker/tree/master/examples/latex-mathjax) - Usage of LaTeX and Mathjax in remarker. Contributed by @michaelliebling. # Motivation of `remarker` `remark` is a great presentation tool and you can write your slide's contents in markdown. The problem is when you simply use remark, you need to maintain the html, css and scripts as well as markdown. If you care the details of design and style of the slides, that's fine. However if you don't care the design of the slides that much and want to focus only on the contents, then the settings of css, html, scripts seem quite messy. `remarker` solves this problem. `remarker` separates the contents (= markdown) from the settings (css, html, scripts). So you can only focus on and keep maintaining the contents of the slides and let `remarker` do the rest of the work. This is easier than using `remark` directly. # How-tos ## How to use images in slides Put the images under `./assets` directory and they are automatically served/copied and you can reference it like `` in your slides. The directory name of `assets` can be configured in `remarker.yml`. See the configuration section for details. # Who uses this tool? See [this search](https://github.com/search?q=filename%3Aremarker.yml). # History - 2022-11-24 v1.15.0 Added loading indicator. - 2022-02-13 v1.14.0 Fixed error while changing slides.md - 2020-05-11 v1.12.0 Added scriptFilesAfterCreate option. - 2019-10-18 v1.11.1 Fix dependency. - 2019-10-18 v1.11.0 Added `-b, --open-browser` option. - 2019-05-14 v1.10.0 Added `--dest`, `--out`, and `--port` CLI options. - 2018-08-06 v1.9.0 Added :emoji: transformation. Modify `cssFiles` option handling (#11). - 2018-06-10 v1.8.1 Fixed help and version options. - 2018-06-10 v1.8.0 Added livereloading feature. - 2018-01-29 v1.7.0 Enabled file asset (#8). - 2018-01-13 v1.6.1 Fixed -s option. - 2018-01-12 v1.6.0 Added --source cli option. - 2017-08-05 v1.3.0 Added remarkConfig prop. # License MIT [remark]: https://github.com/gnab/remark ================================================ FILE: assets/default.css ================================================ body { font-family: 'Avenir Next', 'Hiragino Kaku Gothic ProN', 'Meiryo', 'メイリオ', sans-serif; } h1, h2, h3 { font-weight: bold; } .remark-code, .remark-inline-code { font-family: 'Menlo', 'Monaco', 'Courier new', monospace; } .remark-slide-content.inverse { color: #f3f3f3; background-color: #272822; } ================================================ FILE: assets/help-message.txt ================================================ Usage: remarker [options] serve Serves all the assets at localhost remarker [options] build Builds all the assets to the dest Options: -h, --help Shows the help message and exits -v, --version Shows the version number and exits -s, --source Specifies the slide's markdown file. This overrides 'source' property of the config file. -o, --out The output filename of the slides. Default is index.html. -d, --dest The destination directory for built slides. -p, --port The port number for dev server. -b, --open-browser Open the browser to the page when server starts. Default is false. See https://npm.im/remarker for more details. ================================================ FILE: examples/add-scripts/bar.css ================================================ ================================================ FILE: examples/add-scripts/baz.js ================================================ ================================================ FILE: examples/add-scripts/foo.css ================================================ ================================================ FILE: examples/add-scripts/qux.js ================================================ ================================================ FILE: examples/add-scripts/remarker.yml ================================================ cssFiles: - foo.css - bar.css - https://example.com/style.css scriptFiles: - baz.js - qux.js - https://example.com/script.js ================================================ FILE: examples/add-scripts/slides.md ================================================ # add script example ================================================ FILE: examples/favicon/remarker.yml ================================================ assets: - favicon.ico ================================================ FILE: examples/favicon/slides.md ================================================ class: center, middle # My Awesome Presentation This is my-slides.md --- # Agenda 1. Introduction 2. Deep-dive 3. ... ## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection. # Introduction ================================================ FILE: examples/has-assets/slides.md ================================================ class: center, middle # My Awesome Presentation ??? Notes for the _first_ slide! --- # Agenda 1. Introduction 2. Deep-dive 3. ... ## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection. # Introduction ================================================ FILE: examples/latex-mathjax/remarker.yml ================================================ scriptFiles: - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML&delayStartupUntil=configured script: - "MathJax.Hub.Config({ tex2jax: { skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'] } }); MathJax.Hub.Configured();" ================================================ FILE: examples/latex-mathjax/slides.md ================================================ class: center, middle # Configuring remarker to display LaTeX via MathJax Michael Liebling 26 September 2019 This is an example [Remark](https://github.com/gnab/remark) presentation that demonstrates the configuration of [Remarker](https://www.npmjs.com/package/remarker) for the use of LaTeX math via [MathJax](https://www.mathjax.org). --- # LaTeX, Mathjax, & Remark The use of MathJax with Remark is documented on a [Remark wiki page](https://github.com/gnab/remark/wiki/LaTeX-using-MathJax). Specifically, the syntax requires that LaTeX math commands be placed between a pair of backticks: ```markdown `\(\LaTeX{}\)` 1. This is an inline integral: `\(\int_a^bf(x)dx\)` 2. More `\(x={a \over b}\)` formulae. Display formula: $$e^{i\pi} + 1 = 0$$ ``` _Note:_ this is different from the syntax used in [marked2app](https://marked2app.com/help/MathJax.html), where LaTeX math is indicated with an extra backslash: ```markdown \\( x^2+y^2 \\) ``` --- # LaTeX and Mathjax with Remarker In order for the presentation to be properly generated, one creates a `remarker.yml` configuration file (at the same level as the `slides.md` file) with the following content: ```YML scriptFiles: - https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS_HTML&delayStartupUntil=configured script: - "MathJax.Hub.Config({ tex2jax: { skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'] } }); MathJax.Hub.Configured();" ``` --- # Math example `\(\LaTeX{}\)` 1. This is an inline integral: `\(\int_a^bf(x)dx\)` 2. More `\(x={a \over b}\)` formulae. Display formula: $$e^{i\pi} + 1 = 0$$ ================================================ FILE: examples/livereload-false/remarker.yml ================================================ livereload: false ================================================ FILE: examples/livereload-false/slides.md ================================================ # hey ================================================ FILE: examples/livereload-port/remarker.yml ================================================ livereloadPort: 12345 ================================================ FILE: examples/livereload-port/slides.md ================================================ # demo of livereloading in different port test test ================================================ FILE: examples/metatags/README.md ================================================ run: node ../../index.js and slides are up at `http://localhost:6275/` ================================================ FILE: examples/metatags/my-slides-2.md ================================================ class: center, middle # My Awesome Presentation This is my-slides-2.md --- # Agenda 1. Introduction 2. Deep-dive 3. ... ## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection. # Introduction ================================================ FILE: examples/metatags/my-slides.md ================================================ class: center, middle # My Awesome Presentation This is my-slides.md --- # Agenda 1. Introduction 2. Deep-dive 3. ... ## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection. # Introduction ================================================ FILE: examples/metatags/remarker.yml ================================================ title: Example slides description: This is example slides ogImage: https://avatars.githubusercontent.com/kt3k ogImageWidth: 400 ogImageHeight: 400 twitter: kt3k favicon: https://avatars.githubusercontent.com/kt3k url: https://github.com/kt3k/remarker ================================================ FILE: examples/metatags/slides.md ================================================ class: center, middle # My Awesome Presentation ??? Notes for the _first_ slide! --- # Agenda 1. Introduction :mag: 2. Deep-dive :swimmer: 3. ... ## [NOTE]: Note that you need remark.js alongside this html file, but no internet connection. # Introduction ================================================ FILE: examples/remark/README.md ================================================ run: node ../../index.js and slides are up at `http://localhost:6275/` ================================================ FILE: examples/remark/remarker.yml ================================================ remarkConfig: highlightStyle: monokai highlightLanguage: remark highlightLines: true assets: - unknown-assets - symlink-asset - fifo-asset css: | @import url(https://fonts.googleapis.com/css?family=Droid+Serif); @import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz); @import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic); body { font-family: 'Droid Serif'; } h1, h2, h3 { font-family: 'Yanone Kaffeesatz'; font-weight: 400; margin-bottom: 0; } .remark-slide-content h1 { font-size: 3em; } .remark-slide-content h2 { font-size: 2em; } .remark-slide-content h3 { font-size: 1.6em; } .footnote { position: absolute; bottom: 3em; } li p { line-height: 1.25em; } .red { color: #fa0000; } .large { font-size: 2em; } a, a > code { color: rgb(249, 38, 114); text-decoration: none; } code { background: #e7e8e2; border-radius: 5px; } .remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; } .remark-code-line-highlighted { background-color: #373832; } .pull-left { float: left; width: 47%; } .pull-right { float: right; width: 47%; } .pull-right ~ p { clear: both; } #slideshow .slide .content code { font-size: 0.8em; } #slideshow .slide .content pre code { font-size: 0.9em; padding: 15px; } .inverse { background: #272822; color: #777872; text-shadow: 0 0 20px #333; } .inverse h1, .inverse h2 { color: #f3f3f3; line-height: 0.8em; } /* Slide-specific styling */ #slide-inverse .footnote { bottom: 12px; left: 20px; } #slide-how .slides { font-size: 0.9em; position: absolute; top: 151px; right: 140px; } #slide-how .slides h3 { margin-top: 0.2em; } #slide-how .slides .first, #slide-how .slides .second { padding: 1px 20px; height: 90px; width: 120px; -moz-box-shadow: 0 0 10px #777; -webkit-box-shadow: 0 0 10px #777; box-shadow: 0 0 10px #777; } #slide-how .slides .first { background: #fff; position: absolute; top: 20%; left: 20%; z-index: 1; } #slide-how .slides .second { position: relative; background: #fff; z-index: 0; } /* Two-column layout */ .left-column { color: #777; width: 20%; height: 92%; float: left; } .left-column h2:last-of-type, .left-column h3:last-child { color: #000; } .right-column { width: 75%; float: right; padding-top: 1em; } ================================================ FILE: examples/remark/slides.md ================================================ name: inverse ## layout: true class: center, middle, inverse ## #remark [ri-mahrk] .footnote[Go directly to [project site](https://github.com/gnab/remark)] ## What is it and why should I be using it? --- layout: false .left-column[ ## What is it? ] .right-column[ A simple, in-browser, Markdown-driven slideshow tool targeted at people who know their way around HTML and CSS, featuring: - Markdown formatting, with smart extensions - Presenter mode, with cloned slideshow view - Syntax highlighting, supporting a range of languages - Slide scaling, thus similar appearance on all devices / resolutions .red[*] - Touch support for smart phones and pads, i.e. swipe to navigate slides ## .footnote[.red[*] At least browsers try their best] ] .left-column[ ## What is it? ## Why use it? ] .right-column[ If your ideal slideshow creation workflow contains any of the following steps: - Just write what's on your mind - Do some basic styling - Easily collaborate with others - Share with and show to everyone Then remark might be perfect for your next.red[*] slideshow! ## .footnote[.red[*] You probably want to convert existing slideshows as well] ] .left-column[ ## What is it? ## Why use it? ] .right-column[ As the slideshow is expressed using Markdown, you may: - Focus on the content, expressing yourself in next to plain text not worrying what flashy graphics and disturbing effects to put where As the slideshow is actually an HTML document, you may: - Display it in any decent browser - Style it using regular CSS, just like any other HTML content - Use it offline! As the slideshow is contained in a plain file, you may: - Store it wherever you like; on your computer, hosted from your Dropbox, hosted on Github Pages alongside the stuff you're presenting... - Easily collaborate with others, keeping track of changes using your favourite SCM tool, like Git or Mercurial ] --- template: inverse ## How does it work, then? --- name: how .left-column[ ## How does it work? ### - Markdown ] .right-column[ A Markdown-formatted chunk of text is transformed into individual slides by JavaScript running in the browser: ```remark # Slide 1 This is slide 1 --- # Slide 2 This is slide 2 ``` .slides[ .first[ ### Slide 1 This is slide 1 ] .second[ ### Slide 2 This is slide 2 ] ] Regular Markdown rules apply with only a single exception: - A line containing three dashes constitutes a new slide (not a horizontal rule, `<hr />`) ## Have a look at the [Markdown website](http://daringfireball.net/projects/markdown/) if you're not familiar with Markdown formatting. ] .left-column[ ## How does it work? ### - Markdown ### - Inside HTML ] .right-column[ A simple HTML document is needed for hosting the styles, Markdown and the generated slides themselves: ```xml *
loading...
{% for file in scriptFiles %} {% endfor %} {% for file in scriptFilesAfterCreate %} {% endfor %} ================================================ FILE: package.json ================================================ { "name": "remarker", "version": "1.15.0", "description": "Remark cli", "main": "index.js", "bin": "index.js", "files": [ "index.js", "assets", "vendor", "layout.njk" ], "scripts": { "test": "kocha test", "cov": "nyc --reporter=lcov --reporter=text-summary npm test", "codecov": "npm run cov && codecov", "precommit": "lint-staged" }, "repository": { "type": "git", "url": "git+https://github.com/kt3k/remarker.git" }, "keywords": [ "remark", "markdown", "cli", "slides" ], "author": "Yoshiya Hinosawa", "license": "MIT", "bugs": { "url": "https://github.com/kt3k/remarker/issues" }, "homepage": "https://github.com/kt3k/remarker#readme", "dependencies": { "berber": "^1.4.1", "connect-livereload": "^0.6.0", "gulp-livereload": "^3.8.1", "gulp-rename": "^1.2.2", "layout1": "^1.1.0", "map-stream": "0.0.7", "minimisted": "^2.0.0", "node-emoji": "^1.8.1", "nunjucks": "^3.0.1", "openurl": "^1.1.1", "vinyl-transform": "^1.0.0", "yaml-hook": "^1.0.0" }, "devDependencies": { "axios": "^1.6.0", "chai": "^4.1.0", "codecov": "^3.6.5", "kocha": "^1.8.0", "nyc": "^13.0.0", "rimraf": "^2.6.1", "touch": "^3.1.0", "ws": "^7.4.6" } } ================================================ FILE: test.js ================================================ const { before, after, describe, it, context, timeout } = require("kocha"); const { expect } = require("chai"); const { spawn, execSync } = require("child_process"); const { readFileSync, existsSync } = require("fs"); const { join } = require("path"); const rimraf = require("rimraf"); const touch = require("touch"); const WebSocket = require("ws"); const axios = require("axios"); const examples = { simple: join(__dirname, "examples/simple"), replaceRemark: join(__dirname, "examples/replace-remark"), hasAssets: join(__dirname, "examples/has-assets"), favicon: join(__dirname, "examples/favicon"), remark: join(__dirname, "examples/remark"), addScripts: join(__dirname, "examples/add-scripts"), }; const processes = []; before((done) => { rimraf("examples/*/build", done); }); after((done) => { processes.forEach((child) => child.kill()); rimraf("examples/*/{build,build2}", done); }); describe("remarker", () => { it("creates index.html from slides.md", () => { execSync("node ../../index.js build", { cwd: examples.simple }); expect( readFileSync(join(examples.simple, "build", "index.html")).toString(), ).to.include("My Awesome Presentation"); }); it("replaces :emoji: notations", () => { execSync("node ../../index.js build", { cwd: examples.simple }); const result = readFileSync( join(examples.simple, "build", "index.html"), ).toString(); expect(result).to.include("🏊"); expect(result).to.not.include(":swimmer:"); }); it("replaces stylesheets by remarker.yml's css property", () => { execSync("node ../../index.js build", { cwd: examples.remark }); expect( readFileSync(join(examples.remark, "build", "index.html")).toString(), ).to.include( "@import url(https://fonts.googleapis.com/css?family=Droid+Serif);", ); }); it("replaces remark.js by remarker.yml's remarkPath", () => { execSync("node ../../index.js build", { cwd: examples.replaceRemark }); expect( readFileSync( join(examples.replaceRemark, "build", "remark.js"), ).toString(), ).to.include('console.log("remark.js")'); }); it("injects scripts by remarker.yml's script", () => { execSync("node ../../index.js build", { cwd: examples.replaceRemark, }); expect( readFileSync( join(examples.replaceRemark, "build", "index.html"), ).toString(), ).to.include('console.log("injected script")'); }); describe("-s, --source option", () => { it("specifies the slide's markdown path", () => { execSync("node ../../index.js build --source my-slides.md", { cwd: examples.simple, }); expect( readFileSync(join(examples.simple, "build", "index.html")).toString(), ).to.include("This is my-slides.md"); execSync("node ../../index.js build -s my-slides-2.md", { cwd: examples.simple, }); expect( readFileSync(join(examples.simple, "build", "index.html")).toString(), ).to.include("This is my-slides-2.md"); }); }); describe("-d, --dest option", () => { it("specifies destination directory", () => { execSync("node ../../index.js build --dest build2", { cwd: examples.simple, }); expect( readFileSync(join(examples.simple, "build2", "index.html")).toString(), ).to.include("My Awesome Presentation"); }); }); describe("-o, --out option", () => { it("specifies destination directory", () => { execSync("node ../../index.js build --out slides.html", { cwd: examples.simple, }); expect( readFileSync(join(examples.simple, "build", "slides.html")).toString(), ).to.include("My Awesome Presentation"); }); }); describe("contents in assets directory", () => { it("are copied to build directory", () => { execSync("node ../../index.js build", { cwd: examples.hasAssets }); expect(existsSync("examples/has-assets/build/assets/degu.png")).to.equal( true, ); }); }); describe("file asset entry", () => { it("builds the given file to build dir", () => { execSync("node ../../index.js build", { cwd: examples.favicon }); expect(existsSync("examples/favicon/build/favicon.ico")).to.equal(true); }); }); describe("scriptFiles option", () => { it("adds script files", () => { execSync("node ../../index.js build", { cwd: examples.addScripts }); const html = readFileSync( join(examples.addScripts, "build", "index.html"), ).toString(); expect(html).to.include("baz.js"); expect(html).to.include("qux.js"); }); }); describe("cssFiles option", () => { it("adds css files", () => { execSync("node ../../index.js build", { cwd: examples.addScripts }); const html = readFileSync( join(examples.addScripts, "build", "index.html"), ).toString(); expect(html).to.include("foo.css"); expect(html).to.include("bar.css"); }); }); context("when serving", () => { it("starts livereload server by default", (done) => { timeout(8000); const child = spawn("node", ["../../index.js"], { cwd: examples.remark }); processes.push(child); setTimeout(() => { const ws = new WebSocket("http://localhost:35729/livereload"); ws.on("message", (data) => { expect(JSON.parse(data).command).to.equal("reload"); child.kill(); done(); }); touch(join(examples.remark, "slides.md")); }, 2000); }); it("responses livereload.js at /livereload.js", (done) => { timeout(8000); const child = spawn("node", ["../../index.js"], { cwd: examples.remark }); processes.push(child); setTimeout(() => { axios.get("http://localhost:6275/index.html"); axios.get("http://localhost:6275/livereload.js").then((res) => { expect(res.data).to.include("livereload"); done(); }); }, 2000); }); }); }); ================================================ FILE: vendor/livereload.js ================================================ (function e(t, n, r) { function s(o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require == "function" && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = "MODULE_NOT_FOUND", f; } var l = n[o] = { exports: {} }; t[o][0].call( l.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e); }, l, l.exports, e, t, n, r, ); } return n[o].exports; } var i = typeof require == "function" && require; for (var o = 0; o < r.length; o++) s(r[o]); return s; })( { 1: [function (require, module, exports) { (function () { var Connector, PROTOCOL_6, PROTOCOL_7, Parser, Version, _ref; _ref = require("./protocol"), Parser = _ref.Parser, PROTOCOL_6 = _ref.PROTOCOL_6, PROTOCOL_7 = _ref.PROTOCOL_7; Version = "2.2.2"; exports.Connector = Connector = (function () { function Connector(options, WebSocket, Timer, handlers) { var path; this.options = options; this.WebSocket = WebSocket; this.Timer = Timer; this.handlers = handlers; path = this.options.path ? "" + this.options.path : "livereload"; this._uri = "ws" + (this.options.https ? "s" : "") + "://" + this.options.host + ":" + this.options.port + "/" + path; this._nextDelay = this.options.mindelay; this._connectionDesired = false; this.protocol = 0; this.protocolParser = new Parser({ connected: (function (_this) { return function (protocol) { _this.protocol = protocol; _this._handshakeTimeout.stop(); _this._nextDelay = _this.options.mindelay; _this._disconnectionReason = "broken"; return _this.handlers.connected(protocol); }; })(this), error: (function (_this) { return function (e) { _this.handlers.error(e); return _this._closeOnError(); }; })(this), message: (function (_this) { return function (message) { return _this.handlers.message(message); }; })(this), }); this._handshakeTimeout = new Timer((function (_this) { return function () { if (!_this._isSocketConnected()) { return; } _this._disconnectionReason = "handshake-timeout"; return _this.socket.close(); }; })(this)); this._reconnectTimer = new Timer((function (_this) { return function () { if (!_this._connectionDesired) { return; } return _this.connect(); }; })(this)); this.connect(); } Connector.prototype._isSocketConnected = function () { return this.socket && this.socket.readyState === this.WebSocket.OPEN; }; Connector.prototype.connect = function () { this._connectionDesired = true; if (this._isSocketConnected()) { return; } this._reconnectTimer.stop(); this._disconnectionReason = "cannot-connect"; this.protocolParser.reset(); this.handlers.connecting(); this.socket = new this.WebSocket(this._uri); this.socket.onopen = (function (_this) { return function (e) { return _this._onopen(e); }; })(this); this.socket.onclose = (function (_this) { return function (e) { return _this._onclose(e); }; })(this); this.socket.onmessage = (function (_this) { return function (e) { return _this._onmessage(e); }; })(this); return this.socket.onerror = (function (_this) { return function (e) { return _this._onerror(e); }; })(this); }; Connector.prototype.disconnect = function () { this._connectionDesired = false; this._reconnectTimer.stop(); if (!this._isSocketConnected()) { return; } this._disconnectionReason = "manual"; return this.socket.close(); }; Connector.prototype._scheduleReconnection = function () { if (!this._connectionDesired) { return; } if (!this._reconnectTimer.running) { this._reconnectTimer.start(this._nextDelay); return this._nextDelay = Math.min( this.options.maxdelay, this._nextDelay * 2, ); } }; Connector.prototype.sendCommand = function (command) { if (this.protocol == null) { return; } return this._sendCommand(command); }; Connector.prototype._sendCommand = function (command) { return this.socket.send(JSON.stringify(command)); }; Connector.prototype._closeOnError = function () { this._handshakeTimeout.stop(); this._disconnectionReason = "error"; return this.socket.close(); }; Connector.prototype._onopen = function (e) { var hello; this.handlers.socketConnected(); this._disconnectionReason = "handshake-failed"; hello = { command: "hello", protocols: [PROTOCOL_6, PROTOCOL_7], }; hello.ver = Version; if (this.options.ext) { hello.ext = this.options.ext; } if (this.options.extver) { hello.extver = this.options.extver; } if (this.options.snipver) { hello.snipver = this.options.snipver; } this._sendCommand(hello); return this._handshakeTimeout.start(this.options.handshake_timeout); }; Connector.prototype._onclose = function (e) { this.protocol = 0; this.handlers.disconnected( this._disconnectionReason, this._nextDelay, ); return this._scheduleReconnection(); }; Connector.prototype._onerror = function (e) {}; Connector.prototype._onmessage = function (e) { return this.protocolParser.process(e.data); }; return Connector; })(); }).call(this); }, { "./protocol": 6 }], 2: [function (require, module, exports) { (function () { var CustomEvents; CustomEvents = { bind: function (element, eventName, handler) { if (element.addEventListener) { return element.addEventListener(eventName, handler, false); } else if (element.attachEvent) { element[eventName] = 1; return element.attachEvent("onpropertychange", function (event) { if (event.propertyName === eventName) { return handler(); } }); } else { throw new Error( "Attempt to attach custom event " + eventName + " to something which isn't a DOMElement", ); } }, fire: function (element, eventName) { var event; if (element.addEventListener) { event = document.createEvent("HTMLEvents"); event.initEvent(eventName, true, true); return document.dispatchEvent(event); } else if (element.attachEvent) { if (element[eventName]) { return element[eventName]++; } } else { throw new Error( "Attempt to fire custom event " + eventName + " on something which isn't a DOMElement", ); } }, }; exports.bind = CustomEvents.bind; exports.fire = CustomEvents.fire; }).call(this); }, {}], 3: [function (require, module, exports) { (function () { var LessPlugin; module.exports = LessPlugin = (function () { LessPlugin.identifier = "less"; LessPlugin.version = "1.0"; function LessPlugin(window, host) { this.window = window; this.host = host; } LessPlugin.prototype.reload = function (path, options) { if (this.window.less && this.window.less.refresh) { if (path.match(/\.less$/i)) { return this.reloadLess(path); } if (options.originalPath.match(/\.less$/i)) { return this.reloadLess(options.originalPath); } } return false; }; LessPlugin.prototype.reloadLess = function (path) { var link, links, _i, _len; links = (function () { var _i, _len, _ref, _results; _ref = document.getElementsByTagName("link"); _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; if ( link.href && link.rel.match(/^stylesheet\/less$/i) || (link.rel.match(/stylesheet/i) && link.type.match(/^text\/(x-)?less$/i)) ) { _results.push(link); } } return _results; })(); if (links.length === 0) { return false; } for (_i = 0, _len = links.length; _i < _len; _i++) { link = links[_i]; link.href = this.host.generateCacheBustUrl(link.href); } this.host.console.log( "LiveReload is asking LESS to recompile all stylesheets", ); this.window.less.refresh(true); return true; }; LessPlugin.prototype.analyze = function () { return { disable: !!(this.window.less && this.window.less.refresh), }; }; return LessPlugin; })(); }).call(this); }, {}], 4: [function (require, module, exports) { (function () { var Connector, LiveReload, Options, ProtocolError, Reloader, Timer, __hasProp = {}.hasOwnProperty; Connector = require("./connector").Connector; Timer = require("./timer").Timer; Options = require("./options").Options; Reloader = require("./reloader").Reloader; ProtocolError = require("./protocol").ProtocolError; exports.LiveReload = LiveReload = (function () { function LiveReload(window) { var k, v, _ref; this.window = window; this.listeners = {}; this.plugins = []; this.pluginIdentifiers = {}; this.console = this.window.console && this.window.console.log && this.window.console.error ? this.window.location.href.match(/LR-verbose/) ? this.window.console : { log: function () {}, error: this.window.console.error.bind(this.window.console), } : { log: function () {}, error: function () {}, }; if ( !(this.WebSocket = this.window.WebSocket || this.window.MozWebSocket) ) { this.console.error( "LiveReload disabled because the browser does not seem to support web sockets", ); return; } if ("LiveReloadOptions" in window) { this.options = new Options(); _ref = window["LiveReloadOptions"]; for (k in _ref) { if (!__hasProp.call(_ref, k)) continue; v = _ref[k]; this.options.set(k, v); } } else { this.options = Options.extract(this.window.document); if (!this.options) { this.console.error( "LiveReload disabled because it could not find its own