UNPKG

3.72 kBJavaScriptView Raw
1'use strict'
2
3const ware = require('ware')
4const fs = require('fs')
5const jade = require('jade')
6const join = require('path').join
7const assign = Object.assign
8
9const buildJs = require('./lib/build_js')
10const buildCss = require('./lib/build_css')
11const hash = require('./lib/hash')
12const eachCons = require('./lib/helpers/each_cons')
13const toArray = require('./lib/helpers/to_array')
14
15/**
16 * Metalsmith middleware
17 */
18
19module.exports = function base (options) {
20 const ctx = {
21 styles: [],
22 scripts: [],
23 stylusImports: []
24 }
25
26 var app = ware()
27 .use(sortCss.bind(ctx))
28 .use(addJs.bind(ctx))
29 .use(addCss.bind(ctx))
30 .use(relayout.bind(ctx))
31
32 return function (files, ms, done) {
33 app.run(files, ms, done)
34 }
35}
36
37/*
38 * Sorts out CSS into `styles` (local/external styles) and `stylusImports`
39 */
40
41function sortCss (files, ms, done) {
42 const list = toArray(ms.metadata().css)
43 const sources = files['_docpress.json'].sources
44
45 list.forEach((item) => {
46 if (item.match(/\.styl$/)) {
47 const path = join(ms.source(), item)
48 this.stylusImports.push(path)
49 } else if (item.match(/^https?:\/\//)) {
50 this.styles.push(item)
51 } else {
52 const local = sources[item]
53 if (!local) throw new Error(`css: can't find '#{item}'`)
54 this.styles.push(local)
55 }
56 })
57
58 done()
59}
60
61/**
62 * Assets
63 */
64
65function addCss (files, ms, done) {
66 buildCss({ imports: this.stylusImports }, (err, contents) => {
67 if (err) return done(err)
68 files['assets/style.css'] = { contents }
69 this.styles.unshift('assets/style.css?t=' + hash(contents))
70 done()
71 })
72}
73
74/**
75 * Add JavaScript
76 */
77
78function addJs (files, ms, done) {
79 buildJs((err, contents) => {
80 if (err) return done(err)
81 if (!files['assets/script.js']) {
82 files['assets/script.js'] = { contents }
83 } else {
84 files['assets/script.js'].contents = contents + '\n' +
85 files['assets/script.js'].contents
86 }
87 this.scripts.push('assets/script.js?t=' +
88 hash(files['assets/script.js'].contents))
89 done()
90 })
91}
92
93/**
94 * Layout jade.
95 * Passes these template options:
96 *
97 * * `base` — prefix.
98 * * `toc` — the table of contents, as per toc.json.
99 * * `index` — the index, as per index.json.
100 * * `meta` — metalsmith metadata.
101 * * `prev.title` — previous page title.
102 * * `prev.url` — previous page url.
103 * * `next.title` — next page title.
104 * * `next.url` — next page url.
105 * * `active` — the filename of the active file (eg, `foo/index.html`)
106 * * `styles` — array of CSS files
107 * * `scripts` — array of JavaScript files
108 *
109 * `meta` typically has:
110 *
111 * * `github` (Optional)
112 * * `docs`
113 */
114
115function relayout (files, ms, done) {
116 const toc = files['_docpress.json'].toc
117 const index = files['_docpress.json'].index
118
119 const path = fs.readFileSync(join(__dirname, 'data/layout.jade'), 'utf-8')
120 const layout = jade.compile(path, { pretty: true })
121 const meta = ms.metadata()
122
123 eachCons(index, (_, fname, __, prevName, ___, nextName) => {
124 if (!fname.match(/\.html$/)) return
125 const file = files[fname]
126 const base = Array(fname.split('/').length).join('../')
127 const styles = this.styles.map(relativize(base))
128 const scripts = this.scripts.map(relativize(base))
129
130 file.contents = layout(assign({}, file, {
131 base, toc, index, meta, styles, scripts,
132 prev: prevName && assign({}, index[prevName], { url: base + prevName }),
133 next: nextName && assign({}, index[nextName], { url: base + nextName }),
134 active: fname
135 }))
136 })
137
138 done()
139}
140
141function relativize (base) {
142 return function (url) {
143 if (url.substr(0, 1) === '/' || url.match(/^https?:\/\//)) {
144 return url
145 }
146
147 return base + url
148 }
149}