1 | coffee = require 'coffee-script'
|
2 | cp = require 'child_process'
|
3 | fs = require 'fs'
|
4 | _ = require 'underscore'
|
5 | moment = require 'moment'
|
6 | less = require 'less'
|
7 | jade = require 'jade'
|
8 | ejs = require 'ejs'
|
9 | mkdir_p = require( './mkdir_p' ).mkdir_p
|
10 | coffeescript = require 'coffee-script'
|
11 |
|
12 | jade.filters.plain = ( b, c ) ->
|
13 | return b.toString()
|
14 |
|
15 | SRC_DELIM = '---\n'
|
16 |
|
17 | renderers = {}
|
18 | innerContent = ( meta ) ->
|
19 | type = meta.extension
|
20 | switch type
|
21 | when '.md'
|
22 | meta.preprocessed = ejs.render( meta.src, locals: meta )
|
23 | renderers[type] ?= require( 'node-markdown' ).Markdown
|
24 | return renderers[type]( meta.preprocessed )
|
25 | when '.jade'
|
26 | renderers[type] ?= jade
|
27 | return renderers[type].compile( meta.src )(meta)
|
28 | when '.ejs'
|
29 | return ejs.render( meta.src, locals: meta )
|
30 |
|
31 | class GenericContent
|
32 | constructor: ( @site, @srcPath ) ->
|
33 | @kind = @constructor.name.toLowerCase()
|
34 | process: ( cb ) ->
|
35 | pathParts = @srcPath.split('.')
|
36 | if pathParts.length > 1
|
37 | @extension = ".#{pathParts.pop()}"
|
38 | pathParts = pathParts.join('.').split('/')
|
39 | else
|
40 | @extension = ""
|
41 | pathParts = @srcPath.split('/')
|
42 |
|
43 | @filename = pathParts.pop()
|
44 | @path = pathParts.join('/')
|
45 | @path += '/' if @path
|
46 | @permalink = "#{@path}#{@filename}"
|
47 | @fullPath = "#{@site.root}/_#{@kind}s/#{@srcPath}"
|
48 |
|
49 | @thing = "#{@permalink}#{@extension}"
|
50 |
|
51 | Logger.debug "Processing #{@kind}/#{@permalink}..."
|
52 | if cb then cb( null, @ ) else @
|
53 |
|
54 | render: ( cb ) ->
|
55 | Logger.debug "Rendering #{@kind}/#{@permalink}..."
|
56 | if cb then cb( null, @ ) else @
|
57 |
|
58 | class PageOrPost extends GenericContent
|
59 | constructor: ( @site, @srcPath, @kind ) ->
|
60 | super( @site, @srcPath )
|
61 | @index = false
|
62 | @draft = false
|
63 | process: ( cb ) ->
|
64 | super()
|
65 | fs.readFile @fullPath, ( err, src ) =>
|
66 | if err
|
67 | Logger.error "Error reading source of #{@kind}/#{@srcPath} - #{err}"
|
68 | cb( err, @ )
|
69 | return
|
70 |
|
71 | src = src.toString().split( SRC_DELIM )
|
72 | meta = eval coffee.compile( src[0], { bare: true } )
|
73 |
|
74 | for k, v of meta
|
75 | @[k] = v
|
76 | @scripts ?= []
|
77 | @styles ?= []
|
78 | @src = src.splice(1).join( SRC_DELIM )
|
79 |
|
80 | if @kind == 'post'
|
81 | @timestamp = moment( meta.date, @site.config.dateFormat || "DD.MM.YYYY" )
|
82 |
|
83 | cb( null, @ )
|
84 | render: ( cb ) ->
|
85 | super()
|
86 | dir = "#{@site.root}/build/#{@permalink}"
|
87 | mkdir_p dir, 0777, ( err ) =>
|
88 | if err
|
89 | Logger.error "Error in mkdir_p - #{dir} - #{err}"
|
90 | cb( err, null )
|
91 | return
|
92 |
|
93 | @posts = @site.posts()
|
94 | @pages = @site.pages()
|
95 |
|
96 | @config = @site.config
|
97 | @_ = _
|
98 |
|
99 | self = @
|
100 | @h = _.reduce(
|
101 | _.keys( Config.helpers||{} ),
|
102 | (
|
103 | (uh, key) ->
|
104 | uh[key] = _.bind( Config.helpers[key], self )
|
105 | return uh
|
106 | ),
|
107 | {
|
108 | _: _,
|
109 | moment: moment
|
110 | innerContent: innerContent
|
111 | }
|
112 | )
|
113 |
|
114 | try
|
115 | @content = innerContent( @ )
|
116 | catch e
|
117 | Logger.error "Could not process file: #{@permalink} - #{e}, #{e.stack}"
|
118 | return
|
119 |
|
120 | writeFile = ( dest, html, cb ) ->
|
121 | fs.writeFile dest, html.toString(), ( err ) ->
|
122 | Logger.error "Error writing final render #{err}" if err
|
123 | cb( err )
|
124 |
|
125 | dest = "#{@site.root}/build/#{@permalink}/index.html"
|
126 |
|
127 | if @layout == false
|
128 | writeFile( dest, @content, cb )
|
129 | else
|
130 | fs.readFile "#{@site.root}/_inc/#{@layout||'layout'}.jade", ( err, layoutSrc ) =>
|
131 | Logger.error( @permalink, err, err.stack ) if err
|
132 | tmpl = jade.compile layoutSrc.toString()
|
133 | html = tmpl( @, (err) -> Logger.error("OMG#{err}") if err )
|
134 | writeFile( dest, html, ( err ) =>
|
135 | if @index
|
136 | writeFile( "#{@site.root}/build/index.html", html, (err) -> cb(err, true) )
|
137 | else
|
138 | cb( err, true )
|
139 | )
|
140 |
|
141 | class Page extends PageOrPost
|
142 | constructor: ( @site, @srcPath ) ->
|
143 | super( @site, @srcPath, 'page' )
|
144 | class Post extends PageOrPost
|
145 | constructor: ( @site, @srcPath ) ->
|
146 | super( @site, @srcPath, 'post' )
|
147 |
|
148 |
|
149 | class Script extends GenericContent
|
150 | render: ( cb ) ->
|
151 | super()
|
152 | fs.readFile @fullPath, ( err, coffee ) =>
|
153 | fs.mkdir "#{@site.root}/build/js", 0777, ( err ) =>
|
154 | src = if @extension == '.coffee'
|
155 | coffeescript.compile( coffee+"" )
|
156 | else
|
157 | coffee+""
|
158 | fs.writeFile "#{@site.root}/build/js/#{@thing.replace(/coffee$/, 'js')}", src.toString(), ( err ) ->
|
159 | Logger.error "Error in script done callback #{err}" if err
|
160 | cb( null, true )
|
161 |
|
162 | class Style extends GenericContent
|
163 | render: ( cb ) ->
|
164 | super()
|
165 | parser = new(less.Parser)(
|
166 | paths: [ "#{@site.root}/_styles" ]
|
167 | )
|
168 | fs.readFile @fullPath, ( err, css ) =>
|
169 | return cb( err ) if err
|
170 | fs.mkdir "#{@site.root}/build/css", 0777, () =>
|
171 | done = ( err, src ) =>
|
172 | if err
|
173 | Logger.error "Could not process style: #{@permalink}, #{JSON.stringify(err,undefined,2)}"
|
174 | cb( err )
|
175 | return
|
176 | fs.writeFile "#{@site.root}/build/css/#{@thing.replace(/less$/, 'css')}", src.toString(), ( err ) ->
|
177 | Logger.error "Error in style done callback #{err}" if err
|
178 | cb( null, true )
|
179 |
|
180 | if @extension == '.less'
|
181 | parser.parse( css.toString(), ( err, src ) ->
|
182 | if err
|
183 | done( err, src )
|
184 | return
|
185 | try
|
186 | result = src.toCSS( compress: true )
|
187 | done( null, result )
|
188 | catch err2
|
189 | done( err2, src )
|
190 | )
|
191 | else
|
192 | done( null, css+"" )
|
193 |
|
194 | class Static extends GenericContent
|
195 | render: ( cb ) ->
|
196 |
|
197 |
|
198 |
|
199 |
|
200 | super()
|
201 | cp.exec "rm -rf #{@site.root}/build/#{@thing}", ( err ) =>
|
202 | if err
|
203 | Logger.error "Error in static copy #{err}"
|
204 | cb( err )
|
205 | return
|
206 |
|
207 | src = "#{@site.root}/_static/#{@thing}"
|
208 | dest = "#{@site.root}/build/#{@thing}"
|
209 |
|
210 | if !@site.config.DEV
|
211 | cp.exec "cp -R #{src} #{dest}", ( err ) =>
|
212 | if err
|
213 | Logger.error "Could not write build/#{@thing} during generation. #{arguments}, #{err}"
|
214 | cb( err )
|
215 | else
|
216 | cb( null, true )
|
217 |
|
218 | else
|
219 | fs.symlink src, dest, ( err ) ->
|
220 | if err
|
221 | Logger.error "Error symlinking statics #{err}"
|
222 | cb( err )
|
223 | else
|
224 | cb( null, true )
|
225 |
|
226 | module.exports =
|
227 | Page: Page
|
228 | Post: Post
|
229 | Script: Script
|
230 | Style: Style
|
231 | Static: Static
|