UNPKG

4.53 kBtext/coffeescriptView Raw
1fs = require 'fs'
2_ = require 'underscore'
3async = require 'async'
4
5Watcher = require './watcher'
6Finder = require './finder'
7Server = require './server'
8
9class Site
10 constructor: ( @root=process.cwd() ) ->
11 @config = Config
12 @info = _.inject( Site.KINDS, (( h, k ) -> h[k] = {}; h ), {} )
13 Logger.debug "SITE #{@}"
14 determineIndex: () ->
15 if @config.index?
16 if (item = @info.pages[@config.index])?
17 item.index = true
18 Logger.debug "As index: #{item.kind}/#{item.permalink}"
19 else
20 # determine newest/index post
21 newestThing = _.reject( @posts(), (p) -> p.draft )[0]
22 newestThing.index = true
23 Logger.debug "As index: #{newestThing.kind}/#{newestThing.permalink}"
24 populateInfo: ( kind, items ) ->
25 items.forEach ( item ) =>
26 if !item.draft || @config.drafts
27 @info[kind][item.permalink] = item
28 else
29 Logger.debug "Skipping #{item.kind}/#{item.permalink}"
30 renderAll: ( kind, cb ) ->
31 renderTasks = []
32 for permalink, item of @info[kind]
33 renderTasks.push( { item: item, fn: ( item ) -> ( cb ) -> item.render( cb ) } )
34
35 renderFuncs = _.map( renderTasks, ( task ) -> task.fn(task.item) )
36 async.parallel( renderFuncs, cb )
37 watchContent: () ->
38 again = @watchContent
39 Site.WATCH_KINDS.forEach ( kind ) =>
40 for permalink, item of @info[kind]
41 toWatch = "_#{item.kind}s/#{item.srcPath}"
42 Watcher.onChange toWatch, "#{@root}/#{toWatch}", (( itemToProcess ) ->
43 () ->
44 itemToProcess.process ( err, processed ) ->
45 if err
46 Logger.error "Could not re-process watched #{itemToProcess.kind}, #{err}"
47 return
48
49 itemToProcess.render ( err ) =>
50 if err
51 Logger.error "Clould not re-render watched #{itemToProcess.kind}, #{err}"
52 return
53 )(item)
54 processContent: ( kind, cb ) ->
55 cb ?= ( err ) -> Logger.error( "Could not reload content! #{err}" ) if err
56 new Finder @, kind, ( err, items ) =>
57 @populateInfo( kind, items )
58 @determineIndex()
59 cb( err )
60 processStyles: ( cb ) ->
61 new Finder @, 'styles', ( err, styles ) =>
62 @populateInfo( 'styles', styles )
63 @renderAll( 'styles', cb )
64
65 compileScripts: ( cb ) ->
66 new Finder @, 'scripts', ( err, scripts ) =>
67 @populateInfo( 'scripts', scripts )
68 @renderAll( 'scripts', cb )
69 copyStatics: ( cb ) ->
70 new Finder @, 'statics', ( err, statics ) =>
71 @populateInfo( 'statics', statics )
72 @renderAll( 'statics', cb )
73 posts: () ->
74 _(@info.posts).chain()
75 .values()
76 .sortBy( (v) -> return v.timestamp )
77 .reverse()
78 .value()
79 pages: () ->
80 _(@info.pages).values()
81 build: ( cb ) ->
82 cb ?= ( err ) ->
83 if err
84 Logger.error "Site build failed! #{e}"
85 return
86 else
87 Logger.info "Build complete."
88 s = @
89 async.parallel(
90 [
91 ( cb ) ->
92 s.processContent 'posts', ( err ) ->
93 cb( err, 'posts' )
94 ( cb ) ->
95 s.processContent 'pages', ( err ) ->
96 cb( err, 'pages' )
97 ( cb ) ->
98 s.processStyles ( err ) ->
99 cb( err, 'styles' )
100 ( cb ) ->
101 s.compileScripts ( err ) ->
102 cb( err, 'scripts' )
103 ( cb ) ->
104 s.copyStatics ( err ) ->
105 cb( err, 'statics' )
106 ],
107 ( err, loaded ) ->
108 async.parallel(
109 [
110 ( cb ) -> s.renderAll( 'posts', cb )
111 ( cb ) -> s.renderAll( 'pages', cb )
112 ],
113 cb
114 )
115 )
116 developmentMode: () ->
117 @build ( err ) =>
118 site = @
119 if err
120 Logger.error err
121 return
122 else
123 Logger.info "Initial build complete!"
124 @watchContent()
125 # watch for new files in top level ^_.* directories
126 # and re-do the whole site if they change
127 fs.readdir @root, ( err, items ) ->
128 items.forEach ( item ) ->
129 return unless item.match( /^_/ )
130 Watcher.onChange item, () ->
131 site.build( () ->
132 site.watchContent()
133 )
134 # watch config file
135 Watcher.onChange 'config.coffee', () ->
136 site.config._reload()
137 site.build()
138 Watcher.onChange '_inc/layout.jade', () ->
139 site.build()
140
141Site.WATCH_KINDS = [ 'pages', 'posts', 'styles', 'scripts' ]
142Site.KINDS = _.clone( Site.WATCH_KINDS ).concat( ['statics'] )
143
144module.exports = Site