├── .gitattributes ├── screenshot.png ├── .travis.yml ├── test ├── variables.js ├── loops.js ├── comments.js ├── conditionals.js └── nested-variables.js ├── src ├── api.js ├── helpers │ └── get-data.js ├── transforms │ ├── index.js │ ├── single-line-comments.js │ ├── multi-line-comments.js │ ├── variables.js │ ├── loops.js │ └── conditionals.js └── index.js ├── example ├── views │ └── solar-system.md ├── api.js ├── index.js └── static │ └── github-markdown.css ├── .gitignore ├── package.json ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | views linguist-documentation 2 | * linguist-language=JavaScript 3 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siddharthkp/markedup/HEAD/screenshot.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | cache: 5 | directories: 6 | - node_modules 7 | -------------------------------------------------------------------------------- /test/variables.js: -------------------------------------------------------------------------------- 1 | const {test} = require('ava'); 2 | const markedup = require('../src/api.js'); 3 | 4 | test('variables', t => { 5 | let input = markedup('Hello ', {name: 'sid'}); 6 | let output = '

Hello sid

\n'; 7 | t.deepEqual(input, output); 8 | }); 9 | -------------------------------------------------------------------------------- /src/api.js: -------------------------------------------------------------------------------- 1 | const marked = require('marked'); 2 | const transforms = require('./transforms'); 3 | 4 | const api = (content, options) => { 5 | for (let transform of transforms) content = transform(content, options); 6 | return marked(content); 7 | }; 8 | 9 | module.exports = api; 10 | -------------------------------------------------------------------------------- /test/loops.js: -------------------------------------------------------------------------------- 1 | const {test} = require('ava'); 2 | const markedup = require('../src/api.js'); 3 | 4 | test('loops', t => { 5 | let input = markedup('<* name in names>', {names: ['sid', 'duck']}); 6 | let output = '\n'; 7 | t.deepEqual(input, output); 8 | }); 9 | -------------------------------------------------------------------------------- /src/helpers/get-data.js: -------------------------------------------------------------------------------- 1 | let getData = (data, variable) => { 2 | if (!variable) return data; 3 | let variableParts = variable.split('.'); 4 | let value = data; 5 | for (let part of variableParts) { 6 | if (!value) return null; 7 | value = value[part]; 8 | } 9 | return value; 10 | }; 11 | 12 | module.exports = getData; 13 | -------------------------------------------------------------------------------- /src/transforms/index.js: -------------------------------------------------------------------------------- 1 | let loops = require('./loops'); 2 | let variables = require('./variables'); 3 | let conditionals = require('./conditionals'); 4 | let singleLineComments = require('./single-line-comments'); 5 | let multiLineComments = require('./multi-line-comments'); 6 | 7 | module.exports = [ 8 | singleLineComments, 9 | multiLineComments, 10 | loops, 11 | variables, 12 | conditionals 13 | ]; 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const api = require('./api'); 3 | 4 | const markedup = (filePath, options, callback) => { 5 | fs.readFile(filePath, (err, content) => { 6 | if (err) return callback(new Error(err)); 7 | content = content.toString(); 8 | let rendered = api(content, options); 9 | return callback(null, rendered); 10 | }); 11 | }; 12 | 13 | module.exports = markedup; 14 | -------------------------------------------------------------------------------- /example/views/solar-system.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## name: 4 | 5 | #### Planets 6 | <* planet.name in planets> 7 | 8 | 13 | 18 | 19 | 20 | 21 | // This is a single line comment 22 | 23 | /* This is a 24 | multi 25 | line 26 | comment 27 | */ 28 | -------------------------------------------------------------------------------- /src/transforms/single-line-comments.js: -------------------------------------------------------------------------------- 1 | const htmlTags = require('html-tags'); 2 | const getData = require('../helpers/get-data'); 3 | 4 | let transform = (content, data) => { 5 | let re = /\/\/(.*)/g; 6 | let matches = content.match(re); 7 | 8 | if (!matches) return content; 9 | for (let match of matches) { 10 | let htmlComments = match.replace('//', ''; 12 | content = content.replace(match, htmlComments); 13 | } 14 | 15 | return content; 16 | }; 17 | 18 | module.exports = transform; 19 | -------------------------------------------------------------------------------- /src/transforms/multi-line-comments.js: -------------------------------------------------------------------------------- 1 | const htmlTags = require('html-tags'); 2 | const getData = require('../helpers/get-data'); 3 | 4 | let transform = (content, data) => { 5 | let re = /\/\*((.||\n)*?)\*\//g; 6 | let matches = content.match(re); 7 | 8 | if (!matches) return content; 9 | for (let match of matches) { 10 | let htmlComments = match.replace('/*', ''); 12 | content = content.replace(match, htmlComments); 13 | } 14 | 15 | return content; 16 | }; 17 | 18 | module.exports = transform; 19 | -------------------------------------------------------------------------------- /src/transforms/variables.js: -------------------------------------------------------------------------------- 1 | const htmlTags = require('html-tags'); 2 | const getData = require('../helpers/get-data'); 3 | 4 | let transform = (content, data) => { 5 | let re = /<(.*?)>/g; 6 | let matches = content.match(re); 7 | 8 | if (!matches) return content; 9 | for (let match of matches) { 10 | let variable = match.substring(1).substring(0, match.length - 2); 11 | if (!htmlTags.includes(variable) && getData(data, variable)) { 12 | content = content.replace(match, getData(data, variable)); 13 | } 14 | } 15 | return content; 16 | }; 17 | 18 | module.exports = transform; 19 | -------------------------------------------------------------------------------- /test/comments.js: -------------------------------------------------------------------------------- 1 | const {test} = require('ava'); 2 | const markedup = require('../src/api.js'); 3 | 4 | test('single line', t => { 5 | let input = markedup('// This is a single line comment'); 6 | let output = ''; 7 | t.deepEqual(input, output); 8 | }); 9 | 10 | test('multi line', t => { 11 | let input = markedup(` 12 | /* This is a 13 | multi 14 | line 15 | comment 16 | */ 17 | `); 18 | let output = markedup(` 19 | 24 | `); 25 | 26 | t.deepEqual(input, output); 27 | }); 28 | 29 | -------------------------------------------------------------------------------- /example/api.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const markedup = require('../src/api.js'); 3 | 4 | let data = { 5 | star: 'Sun', 6 | planets: [ 7 | {name: 'Mercury', position: 1}, 8 | {name: 'Venus', position: 2}, 9 | {name: 'Earth', position: 3}, 10 | {name: 'Mars', position: 4}, 11 | {name: 'Jupiter', position: 5}, 12 | {name: 'Saturn', position: 6}, 13 | {name: 'Uranus', position: 7}, 14 | {name: 'Neptune', position: 8}, 15 | {name: 'Pluto :(', position: 9} 16 | ] 17 | }; 18 | 19 | fs.readFile('./views/solar-system.md', (err, content) => { 20 | content = content.toString(); 21 | let rendered = markedup(content, data); 22 | console.log(rendered); 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | .DS_Store 40 | -------------------------------------------------------------------------------- /test/conditionals.js: -------------------------------------------------------------------------------- 1 | const {test} = require('ava'); 2 | const markedup = require('../src/api.js'); 3 | 4 | test('if', t => { 5 | let input = markedup(``, {name: 'sid'}); 6 | let output = '

Hi sid

\n'; 7 | t.deepEqual(input, output); 8 | }); 9 | 10 | test('else if', t => { 11 | let input = markedup(``, {name: 'duck'}); 12 | let output = '

Hi duck

\n'; 13 | t.deepEqual(input, output); 14 | }); 15 | 16 | test('else', t => { 17 | let input = markedup(``, {name: 'rando'}); 18 | let output = '

Who are you?

\n'; 19 | t.deepEqual(input, output); 20 | }); 21 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const markedup = require('../src/index.js'); 4 | 5 | app.engine('md', markedup); 6 | app.set('view engine', 'markedup'); 7 | app.use(express.static('static')); 8 | 9 | app.get('/', function (req, res) { 10 | let data = { 11 | star: 'Sun', 12 | planets: [ 13 | {name: 'Mercury', position: 1}, 14 | {name: 'Venus', position: 2}, 15 | {name: 'Earth', position: 3}, 16 | {name: 'Mars', position: 4}, 17 | {name: 'Jupiter', position: 5}, 18 | {name: 'Saturn', position: 6}, 19 | {name: 'Uranus', position: 7}, 20 | {name: 'Neptune', position: 8}, 21 | {name: 'Pluto :(', position: 9} 22 | ] 23 | }; 24 | res.render('solar-system.md', data); 25 | }); 26 | 27 | app.listen(3000); 28 | 29 | -------------------------------------------------------------------------------- /test/nested-variables.js: -------------------------------------------------------------------------------- 1 | const {test} = require('ava'); 2 | const markedup = require('../src/api.js'); 3 | 4 | test('variables', t => { 5 | let input = markedup('Hello ', {user: {name: 'sid'}}); 6 | let output = '

Hello sid

\n'; 7 | t.deepEqual(input, output); 8 | }); 9 | 10 | test('loops', t => { 11 | let users = [ 12 | {name: 'sid'}, 13 | {name: 'duck'} 14 | ]; 15 | let input = markedup('<* user.name in users>', {users}); 16 | let output = '
    \n
  • sid
  • \n
  • duck
  • \n
\n'; 17 | t.deepEqual(input, output); 18 | }); 19 | 20 | test('conditional', t => { 21 | let user = {name: 'sid'}; 22 | let input = markedup(``, {user}); 23 | let output = '

Hi sid

\n'; 24 | t.deepEqual(input, output); 25 | }); 26 | 27 | 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "markedup", 3 | "version": "0.0.1", 4 | "description": "Markdown engine for express", 5 | "main": "index.js", 6 | "directories": { 7 | "example": "example" 8 | }, 9 | "scripts": { 10 | "test": "node node_modules/ava/cli.js --verbose" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/siddharthkp/markedup.git" 15 | }, 16 | "keywords": [ 17 | "markdown", 18 | "markedup", 19 | "md", 20 | "express", 21 | "engine" 22 | ], 23 | "author": "siddharthkp", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/siddharthkp/markedup/issues" 27 | }, 28 | "homepage": "https://github.com/siddharthkp/markedup#readme", 29 | "devDependencies": { 30 | "express": "4.14.0", 31 | "marked": "0.3.9" 32 | }, 33 | "dependencies": { 34 | "ava": "0.16.0", 35 | "html-tags": "1.1.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Siddharth Kshetrapal 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 | -------------------------------------------------------------------------------- /src/transforms/loops.js: -------------------------------------------------------------------------------- 1 | const getData = require('../helpers/get-data'); 2 | 3 | let transform = (content, data) => { 4 | let re = /<(.*?)>/g; 5 | let matches = content.match(re); 6 | 7 | if (!matches) return content; 8 | 9 | matches = matches.filter(match => match.includes(' in ')); 10 | for (let match of matches) { 11 | let phrase = match.substring(1).substring(0, match.length - 2); 12 | 13 | let listVariable = phrase.split(' in ')[1]; 14 | let list = getData(data, listVariable); 15 | 16 | let repeatee = phrase.split(' in ')[0]; 17 | let iterator = repeatee.split(' ').pop(); 18 | 19 | iteratorVariable = iterator.split('.'); 20 | iteratorVariable.shift(); 21 | iteratorVariable = iteratorVariable.join('.'); 22 | 23 | let loopOutput = []; 24 | for (let item of list) { 25 | let loopItem = repeatee.replace(iterator, getData(item, iteratorVariable)); 26 | loopOutput.push(loopItem); 27 | } 28 | content = content.replace(match, loopOutput.join('\n')); 29 | } 30 | return content; 31 | }; 32 | 33 | module.exports = transform; 34 | -------------------------------------------------------------------------------- /src/transforms/conditionals.js: -------------------------------------------------------------------------------- 1 | const getData = require('../helpers/get-data'); 2 | 3 | let transform = (content, data) => { 4 | let re = //g; 5 | let matches = content.match(re); 6 | 7 | if (!matches) return content; 8 | for (let match of matches) { 9 | let conditional = match.replace('', ''); 10 | let parts = conditional.split('>'); 11 | parts.pop(); 12 | for (let part of parts) { 13 | let condition = part.match(/<(.*?):/g)[0]; 14 | let text = part.replace(condition, '').replace(/ /g, ''); 15 | if (isConditionValid(condition, data)) { 16 | content = content.replace(match, text); 17 | break; 18 | } 19 | } 20 | } 21 | return content; 22 | }; 23 | 24 | let isConditionValid = (condition, data) => { 25 | if (condition.includes(' 17 | ``` 18 | 19 | 20 | - [x] Loops 21 | 22 | ```html 23 | <* planet in planets> 24 | ``` 25 | 26 | - [ ] Attributes 27 | - [x] Conditionals 28 | 29 | ```html 30 | 35 | 40 | 41 | 42 | ``` 43 | 44 | - [x] Nested variables 45 | 46 | ```html 47 | ## name: 48 | 49 | <* planet.name in planets> 50 | ``` 51 | 52 | - [ ] Includes 53 | - [ ] Attributes 54 | - [x] Comments 55 | 56 | ```js 57 | // This is a single line comment 58 | 59 | /* This is a 60 | multi 61 | line 62 | comment 63 | */ 64 | ``` 65 | 66 | - [ ] Escape code 67 | - [ ] Syntax errors 68 | -------------------------------------------------------------------------------- /example/static/github-markdown.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: octicons-link; 3 | src: url(data:font/woff;charset=utf-8;base64,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) format('woff'); 4 | } 5 | 6 | body { 7 | -ms-text-size-adjust: 100%; 8 | -webkit-text-size-adjust: 100%; 9 | line-height: 1.5; 10 | color: #333; 11 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 12 | font-size: 16px; 13 | line-height: 1.5; 14 | word-wrap: break-word; 15 | margin: 50px; 16 | } 17 | 18 | .pl-c { 19 | color: #969896; 20 | } 21 | 22 | .pl-c1, 23 | .pl-s .pl-v { 24 | color: #0086b3; 25 | } 26 | 27 | .pl-e, 28 | .pl-en { 29 | color: #795da3; 30 | } 31 | 32 | .pl-smi, 33 | .pl-s .pl-s1 { 34 | color: #333; 35 | } 36 | 37 | .pl-ent { 38 | color: #63a35c; 39 | } 40 | 41 | .pl-k { 42 | color: #a71d5d; 43 | } 44 | 45 | .pl-s, 46 | .pl-pds, 47 | .pl-s .pl-pse .pl-s1, 48 | .pl-sr, 49 | .pl-sr .pl-cce, 50 | .pl-sr .pl-sre, 51 | .pl-sr .pl-sra { 52 | color: #183691; 53 | } 54 | 55 | .pl-v { 56 | color: #ed6a43; 57 | } 58 | 59 | .pl-id { 60 | color: #b52a1d; 61 | } 62 | 63 | .pl-ii { 64 | color: #f8f8f8; 65 | background-color: #b52a1d; 66 | } 67 | 68 | .pl-sr .pl-cce { 69 | font-weight: bold; 70 | color: #63a35c; 71 | } 72 | 73 | .pl-ml { 74 | color: #693a17; 75 | } 76 | 77 | .pl-mh, 78 | .pl-mh .pl-en, 79 | .pl-ms { 80 | font-weight: bold; 81 | color: #1d3e81; 82 | } 83 | 84 | .pl-mq { 85 | color: #008080; 86 | } 87 | 88 | .pl-mi { 89 | font-style: italic; 90 | color: #333; 91 | } 92 | 93 | .pl-mb { 94 | font-weight: bold; 95 | color: #333; 96 | } 97 | 98 | .pl-md { 99 | color: #bd2c00; 100 | background-color: #ffecec; 101 | } 102 | 103 | .pl-mi1 { 104 | color: #55a532; 105 | background-color: #eaffea; 106 | } 107 | 108 | .pl-mdr { 109 | font-weight: bold; 110 | color: #795da3; 111 | } 112 | 113 | .pl-mo { 114 | color: #1d3e81; 115 | } 116 | 117 | .octicon { 118 | display: inline-block; 119 | vertical-align: text-top; 120 | fill: currentColor; 121 | } 122 | 123 | a { 124 | background-color: transparent; 125 | -webkit-text-decoration-skip: objects; 126 | } 127 | 128 | a:active, 129 | a:hover { 130 | outline-width: 0; 131 | } 132 | 133 | strong { 134 | font-weight: inherit; 135 | } 136 | 137 | strong { 138 | font-weight: bolder; 139 | } 140 | 141 | h1 { 142 | font-size: 2em; 143 | margin: 0.67em 0; 144 | } 145 | 146 | img { 147 | border-style: none; 148 | } 149 | 150 | svg:not(:root) { 151 | overflow: hidden; 152 | } 153 | 154 | code, 155 | kbd, 156 | pre { 157 | font-family: monospace, monospace; 158 | font-size: 1em; 159 | } 160 | 161 | hr { 162 | box-sizing: content-box; 163 | height: 0; 164 | overflow: visible; 165 | } 166 | 167 | input { 168 | font: inherit; 169 | margin: 0; 170 | } 171 | 172 | input { 173 | overflow: visible; 174 | } 175 | 176 | button:-moz-focusring, 177 | [type="button"]:-moz-focusring, 178 | [type="reset"]:-moz-focusring, 179 | [type="submit"]:-moz-focusring { 180 | outline: 1px dotted ButtonText; 181 | } 182 | 183 | [type="checkbox"] { 184 | box-sizing: border-box; 185 | padding: 0; 186 | } 187 | 188 | * { 189 | box-sizing: border-box; 190 | } 191 | 192 | input { 193 | font-family: inherit; 194 | font-size: inherit; 195 | line-height: inherit; 196 | } 197 | 198 | a { 199 | color: #4078c0; 200 | text-decoration: none; 201 | } 202 | 203 | a:hover, 204 | a:active { 205 | text-decoration: underline; 206 | } 207 | 208 | strong { 209 | font-weight: 600; 210 | } 211 | 212 | hr { 213 | height: 0; 214 | margin: 15px 0; 215 | overflow: hidden; 216 | background: transparent; 217 | border: 0; 218 | border-bottom: 1px solid #ddd; 219 | } 220 | 221 | hr::before { 222 | display: table; 223 | content: ""; 224 | } 225 | 226 | hr::after { 227 | display: table; 228 | clear: both; 229 | content: ""; 230 | } 231 | 232 | table { 233 | border-spacing: 0; 234 | border-collapse: collapse; 235 | } 236 | 237 | td, 238 | th { 239 | padding: 0; 240 | } 241 | 242 | h1, 243 | h2, 244 | h3, 245 | h4, 246 | h5, 247 | h6 { 248 | margin-top: 0; 249 | margin-bottom: 0; 250 | } 251 | 252 | h1 { 253 | font-size: 32px; 254 | font-weight: 600; 255 | } 256 | 257 | h2 { 258 | font-size: 24px; 259 | font-weight: 600; 260 | } 261 | 262 | h3 { 263 | font-size: 20px; 264 | font-weight: 600; 265 | } 266 | 267 | h4 { 268 | font-size: 16px; 269 | font-weight: 600; 270 | } 271 | 272 | h5 { 273 | font-size: 14px; 274 | font-weight: 600; 275 | } 276 | 277 | h6 { 278 | font-size: 12px; 279 | font-weight: 600; 280 | } 281 | 282 | p { 283 | margin-top: 0; 284 | margin-bottom: 10px; 285 | } 286 | 287 | blockquote { 288 | margin: 0; 289 | } 290 | 291 | ul, 292 | ol { 293 | padding-left: 0; 294 | margin-top: 0; 295 | margin-bottom: 0; 296 | } 297 | 298 | ol ol, 299 | ul ol { 300 | list-style-type: lower-roman; 301 | } 302 | 303 | ul ul ol, 304 | ul ol ol, 305 | ol ul ol, 306 | ol ol ol { 307 | list-style-type: lower-alpha; 308 | } 309 | 310 | dd { 311 | margin-left: 0; 312 | } 313 | 314 | code { 315 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 316 | font-size: 12px; 317 | } 318 | 319 | pre { 320 | margin-top: 0; 321 | margin-bottom: 0; 322 | font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace; 323 | } 324 | 325 | .octicon { 326 | vertical-align: text-bottom; 327 | } 328 | 329 | input { 330 | -webkit-font-feature-settings: "liga" 0; 331 | font-feature-settings: "liga" 0; 332 | } 333 | 334 | .form-select::-ms-expand { 335 | opacity: 0; 336 | } 337 | 338 | body::before { 339 | display: table; 340 | content: ""; 341 | } 342 | 343 | body::after { 344 | display: table; 345 | clear: both; 346 | content: ""; 347 | } 348 | 349 | body>*:first-child { 350 | margin-top: 0 !important; 351 | } 352 | 353 | body>*:last-child { 354 | margin-bottom: 0 !important; 355 | } 356 | 357 | a:not([href]) { 358 | color: inherit; 359 | text-decoration: none; 360 | } 361 | 362 | .anchor { 363 | float: left; 364 | padding-right: 4px; 365 | margin-left: -20px; 366 | line-height: 1; 367 | } 368 | 369 | .anchor:focus { 370 | outline: none; 371 | } 372 | 373 | p, 374 | blockquote, 375 | ul, 376 | ol, 377 | dl, 378 | table, 379 | pre { 380 | margin-top: 0; 381 | margin-bottom: 16px; 382 | } 383 | 384 | hr { 385 | height: 0.25em; 386 | padding: 0; 387 | margin: 24px 0; 388 | background-color: #e7e7e7; 389 | border: 0; 390 | } 391 | 392 | blockquote { 393 | padding: 0 1em; 394 | color: #777; 395 | border-left: 0.25em solid #ddd; 396 | } 397 | 398 | blockquote>:first-child { 399 | margin-top: 0; 400 | } 401 | 402 | blockquote>:last-child { 403 | margin-bottom: 0; 404 | } 405 | 406 | kbd { 407 | display: inline-block; 408 | padding: 3px 5px; 409 | font-size: 11px; 410 | line-height: 10px; 411 | color: #555; 412 | vertical-align: middle; 413 | background-color: #fcfcfc; 414 | border: solid 1px #ccc; 415 | border-bottom-color: #bbb; 416 | border-radius: 3px; 417 | box-shadow: inset 0 -1px 0 #bbb; 418 | } 419 | 420 | h1, 421 | h2, 422 | h3, 423 | h4, 424 | h5, 425 | h6 { 426 | margin-top: 24px; 427 | margin-bottom: 16px; 428 | font-weight: 600; 429 | line-height: 1.25; 430 | } 431 | 432 | h1 .octicon-link, 433 | h2 .octicon-link, 434 | h3 .octicon-link, 435 | h4 .octicon-link, 436 | h5 .octicon-link, 437 | h6 .octicon-link { 438 | color: #000; 439 | vertical-align: middle; 440 | visibility: hidden; 441 | } 442 | 443 | h1:hover .anchor, 444 | h2:hover .anchor, 445 | h3:hover .anchor, 446 | h4:hover .anchor, 447 | h5:hover .anchor, 448 | h6:hover .anchor { 449 | text-decoration: none; 450 | } 451 | 452 | h1:hover .anchor .octicon-link, 453 | h2:hover .anchor .octicon-link, 454 | h3:hover .anchor .octicon-link, 455 | h4:hover .anchor .octicon-link, 456 | h5:hover .anchor .octicon-link, 457 | h6:hover .anchor .octicon-link { 458 | visibility: visible; 459 | } 460 | 461 | h1 { 462 | padding-bottom: 0.3em; 463 | font-size: 2em; 464 | border-bottom: 1px solid #eee; 465 | } 466 | 467 | h2 { 468 | padding-bottom: 0.3em; 469 | font-size: 1.5em; 470 | border-bottom: 1px solid #eee; 471 | } 472 | 473 | h3 { 474 | font-size: 1.25em; 475 | } 476 | 477 | h4 { 478 | font-size: 1em; 479 | } 480 | 481 | h5 { 482 | font-size: 0.875em; 483 | } 484 | 485 | h6 { 486 | font-size: 0.85em; 487 | color: #777; 488 | } 489 | 490 | ul, 491 | ol { 492 | padding-left: 2em; 493 | } 494 | 495 | ul ul, 496 | ul ol, 497 | ol ol, 498 | ol ul { 499 | margin-top: 0; 500 | margin-bottom: 0; 501 | } 502 | 503 | li>p { 504 | margin-top: 16px; 505 | } 506 | 507 | li+li { 508 | margin-top: 0.25em; 509 | } 510 | 511 | dl { 512 | padding: 0; 513 | } 514 | 515 | dl dt { 516 | padding: 0; 517 | margin-top: 16px; 518 | font-size: 1em; 519 | font-style: italic; 520 | font-weight: bold; 521 | } 522 | 523 | dl dd { 524 | padding: 0 16px; 525 | margin-bottom: 16px; 526 | } 527 | 528 | table { 529 | display: block; 530 | width: 100%; 531 | overflow: auto; 532 | word-break: normal; 533 | word-break: keep-all; 534 | } 535 | 536 | table th { 537 | font-weight: bold; 538 | } 539 | 540 | table th, 541 | table td { 542 | padding: 6px 13px; 543 | border: 1px solid #ddd; 544 | } 545 | 546 | table tr { 547 | background-color: #fff; 548 | border-top: 1px solid #ccc; 549 | } 550 | 551 | table tr:nth-child(2n) { 552 | background-color: #f8f8f8; 553 | } 554 | 555 | img { 556 | max-width: 100%; 557 | box-sizing: content-box; 558 | background-color: #fff; 559 | } 560 | 561 | code { 562 | padding: 0; 563 | padding-top: 0.2em; 564 | padding-bottom: 0.2em; 565 | margin: 0; 566 | font-size: 85%; 567 | background-color: rgba(0,0,0,0.04); 568 | border-radius: 3px; 569 | } 570 | 571 | code::before, 572 | code::after { 573 | letter-spacing: -0.2em; 574 | content: "\00a0"; 575 | } 576 | 577 | pre { 578 | word-wrap: normal; 579 | } 580 | 581 | pre>code { 582 | padding: 0; 583 | margin: 0; 584 | font-size: 100%; 585 | word-break: normal; 586 | white-space: pre; 587 | background: transparent; 588 | border: 0; 589 | } 590 | 591 | .highlight { 592 | margin-bottom: 16px; 593 | } 594 | 595 | .highlight pre { 596 | margin-bottom: 0; 597 | word-break: normal; 598 | } 599 | 600 | .highlight pre, 601 | pre { 602 | padding: 16px; 603 | overflow: auto; 604 | font-size: 85%; 605 | line-height: 1.45; 606 | background-color: #f7f7f7; 607 | border-radius: 3px; 608 | } 609 | 610 | pre code { 611 | display: inline; 612 | max-width: auto; 613 | padding: 0; 614 | margin: 0; 615 | overflow: visible; 616 | line-height: inherit; 617 | word-wrap: normal; 618 | background-color: transparent; 619 | border: 0; 620 | } 621 | 622 | pre code::before, 623 | pre code::after { 624 | content: normal; 625 | } 626 | 627 | .pl-0 { 628 | padding-left: 0 !important; 629 | } 630 | 631 | .pl-1 { 632 | padding-left: 3px !important; 633 | } 634 | 635 | .pl-2 { 636 | padding-left: 6px !important; 637 | } 638 | 639 | .pl-3 { 640 | padding-left: 12px !important; 641 | } 642 | 643 | .pl-4 { 644 | padding-left: 24px !important; 645 | } 646 | 647 | .pl-5 { 648 | padding-left: 36px !important; 649 | } 650 | 651 | .pl-6 { 652 | padding-left: 48px !important; 653 | } 654 | 655 | .full-commit .btn-outline:not(:disabled):hover { 656 | color: #4078c0; 657 | border: 1px solid #4078c0; 658 | } 659 | 660 | kbd { 661 | display: inline-block; 662 | padding: 3px 5px; 663 | font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace; 664 | line-height: 10px; 665 | color: #555; 666 | vertical-align: middle; 667 | background-color: #fcfcfc; 668 | border: solid 1px #ccc; 669 | border-bottom-color: #bbb; 670 | border-radius: 3px; 671 | box-shadow: inset 0 -1px 0 #bbb; 672 | } 673 | 674 | :checked+.radio-label { 675 | position: relative; 676 | z-index: 1; 677 | border-color: #4078c0; 678 | } 679 | 680 | .task-list-item { 681 | list-style-type: none; 682 | } 683 | 684 | .task-list-item+.task-list-item { 685 | margin-top: 3px; 686 | } 687 | 688 | .task-list-item input { 689 | margin: 0 0.2em 0.25em -1.6em; 690 | vertical-align: middle; 691 | } 692 | 693 | hr { 694 | border-bottom-color: #eee; 695 | } 696 | --------------------------------------------------------------------------------