Skip to content
This repository
Browse code

Restored preview functionality after refactor. Also using a new, fast…

…er way of rebuilding during preview. NNeeds testing.
  • Loading branch information...
commit a04635ba1676cac2cbd296c3ef8032c03fb74b5b 1 parent cdc436e
Jarod Long authored October 04, 2012
137  bin/squire
@@ -13,75 +13,70 @@ lib =
13 13
 	path:   require "path"
14 14
 	fibers: require "fibers"
15 15
 
16  
-# Run everything inside of a fiber.
17  
-fiber = lib.fibers ->
18  
-	commands =
19  
-		new:     require "../commands/new"
20  
-		preview: require "../commands/preview"
21  
-		build:   require "../commands/build"
22  
-	
23  
-	# A little hack to print help when the command is run with no arguments.
24  
-	process.argv[2] = "-h" if process.argv.length < 3
25  
-	
26  
-	# A helper function to grab the list of available templates.
27  
-	getTemplateList = ->
28  
-		templatePath = lib.path.join __dirname, "../templates"
29  
-		templates    = (path for path in lib.fs.readdirSync(templatePath) when path[0] isnt ".")
30  
-		templates.join ", "
31  
-	
32  
-	# A helper function that will return the current version.
33  
-	getVersion = ->
34  
-		packagePath = lib.path.join __dirname, "../package.json"
35  
-		file        = lib.fs.readFileSync(packagePath).toString()
36  
-		"v" + JSON.parse(file).version
37  
-	
38  
-	# Configure nomnom and set up our commands.
39  
-	lib.nomnom.script("squire").colors()
40  
-	
41  
-	lib.nomnom.command("new").
42  
-		help("Create a new project.").
43  
-		options(
44  
-			path:
45  
-				position: 1
46  
-				help:     "The path in which to initialize the project."
47  
-				default:  "."
48  
-			template:
49  
-				abbr:    "t"
50  
-				help:    "The template to use for the project. Available templates: #{getTemplateList()}"
51  
-				default: "basic"
52  
-		).
53  
-		callback (options) -> commands.new.run options
54  
-	
55  
-	lib.nomnom.command("preview").
56  
-		help("Start a preview server.").
57  
-		options(
58  
-			port:
59  
-				abbr:    "p"
60  
-				help:    "The port number to use for the preview server."
61  
-				default: 6400
62  
-			verbose:
63  
-				abbr:    "v"
64  
-				help:    "A verboseness level between 0 and 2. 0 = no text, 1 = some text, 2 = lots of text."
65  
-				default: 0
66  
-		).
67  
-		callback (options) -> commands.preview.run options
68  
-	
69  
-	lib.nomnom.command("build").
70  
-		help("Build your project.").
71  
-		options(
72  
-			mode:
73  
-				abbr:    "m"
74  
-				help:    "Specifies the build mode, which affects which config values are used."
75  
-				default: "build"
76  
-		).
77  
-		callback (options) -> commands.build.run options
78  
-	
79  
-	lib.nomnom.command("version").
80  
-		help("Print the current version.").
81  
-		callback (options) -> console.log getVersion()
82  
-	
83  
-	# Parse the arguments.
84  
-	args = lib.nomnom.parse()
  16
+commands =
  17
+	new:     require "../commands/new"
  18
+	preview: require "../commands/preview"
  19
+	build:   require "../commands/build"
85 20
 
86  
-# Run the fiber.
87  
-fiber.run()
  21
+# A little hack to print help when the command is run with no arguments.
  22
+process.argv[2] = "-h" if process.argv.length < 3
  23
+
  24
+# A helper function to grab the list of available templates.
  25
+getTemplateList = ->
  26
+	templatePath = lib.path.join __dirname, "../templates"
  27
+	templates    = (path for path in lib.fs.readdirSync(templatePath) when path[0] isnt ".")
  28
+	templates.join ", "
  29
+
  30
+# A helper function that will return the current version.
  31
+getVersion = ->
  32
+	packagePath = lib.path.join __dirname, "../package.json"
  33
+	file        = lib.fs.readFileSync(packagePath).toString()
  34
+	"v" + JSON.parse(file).version
  35
+
  36
+# Configure nomnom and set up our commands.
  37
+lib.nomnom.script("squire").colors()
  38
+
  39
+lib.nomnom.command("new").
  40
+	help("Create a new project.").
  41
+	options(
  42
+		path:
  43
+			position: 1
  44
+			help:     "The path in which to initialize the project."
  45
+			default:  "."
  46
+		template:
  47
+			abbr:    "t"
  48
+			help:    "The template to use for the project. Available templates: #{getTemplateList()}"
  49
+			default: "basic"
  50
+	).
  51
+	callback (options) -> commands.new.run options
  52
+
  53
+lib.nomnom.command("preview").
  54
+	help("Start a preview server.").
  55
+	options(
  56
+		port:
  57
+			abbr:    "p"
  58
+			help:    "The port number to use for the preview server."
  59
+			default: 6400
  60
+		verbose:
  61
+			abbr:    "v"
  62
+			help:    "A verboseness level between 0 and 2. 0 = no text, 1 = some text, 2 = lots of text."
  63
+			default: 0
  64
+	).
  65
+	callback (options) -> commands.preview.run options
  66
+
  67
+lib.nomnom.command("build").
  68
+	help("Build your project.").
  69
+	options(
  70
+		mode:
  71
+			abbr:    "m"
  72
+			help:    "Specifies the build mode, which affects which config values are used."
  73
+			default: "build"
  74
+	).
  75
+	callback (options) -> commands.build.run options
  76
+
  77
+lib.nomnom.command("version").
  78
+	help("Print the current version.").
  79
+	callback (options) -> console.log getVersion()
  80
+
  81
+# Parse the arguments.
  82
+args = lib.nomnom.parse()
21  commands/build.coffee
@@ -5,6 +5,7 @@
5 5
 ##
6 6
 
7 7
 lib =
  8
+	fibers: require "fibers"
8 9
 	file:   require "file"
9 10
 	fs:     require "fs"
10 11
 	squire: require "../main"
@@ -13,6 +14,8 @@ lib =
13 14
 class BuildCommand extends lib.squire.Squire
14 15
 	# The entry point to the command.
15 16
 	run: (options) ->
  17
+		options.shouldLogErrors ?= true
  18
+		
16 19
 		# Make sure we've got our directories set up properly.
17 20
 		unless lib.fs.existsSync @appPath
18 21
 			lib.squire.Error.log "Configured application path #{@appPath} does not exist."
@@ -26,21 +29,25 @@ class BuildCommand extends lib.squire.Squire
26 29
 		@cleanBuildFolder()
27 30
 		
28 31
 		# Construct the app tree.
29  
-		@app = new lib.squire.Directory path: @appPath
  32
+		@app           = new lib.squire.Directory path: @appPath
  33
+		inputDirectory = @app.getPath @config.inputDirectory
30 34
 		
31 35
 		# Walk the input directory and spit out each file.
32  
-		@app.getPath(@config.inputDirectory).walk (directory) ->
  36
+		inputDirectory.walk (directory) ->
33 37
 			for name, file of directory.files
34 38
 				outputUrl = file.url.outputUrl
35 39
 				lib.file.mkdirsSync outputUrl.directory, 0o0755 # TODO: We only need to do this once per directory.
36 40
 				lib.fs.writeFileSync file.url.outputUrl.path, file.content
37 41
 		
38 42
 		# If there were any errors, log them, and clean out the build folder.
39  
-		errorMessage = @app.consolidateErrors()
  43
+		errorMessage = inputDirectory.consolidateErrors()
40 44
 		
41 45
 		if errorMessage.length > 0
42  
-			console.error errorMessage
  46
+			console.error errorMessage if options.shouldLogErrors
43 47
 			@cleanBuildFolder()
  48
+		
  49
+		# Call the callback.
  50
+		options.callback?()
44 51
 	
45 52
 	# Cleans out the build folder.
46 53
 	cleanBuildFolder: ->
@@ -49,4 +56,8 @@ class BuildCommand extends lib.squire.Squire
49 56
 		lib.wrench.rmdirSyncRecursive @outputPath, true if @outputPath.indexOf(@projectPath) is 0
50 57
 
51 58
 # We only expose the run function.
52  
-exports.run = (options) -> (new BuildCommand mode: options.mode).run options
  59
+exports.run = (options) ->
  60
+	# The command needs to be run inside of a fiber.
  61
+	(lib.fibers ->
  62
+		(new BuildCommand mode: options.mode).run options
  63
+	).run()
323  commands/preview.coffee
@@ -4,164 +4,215 @@
4 4
 ## This contains the implementation of the preview command.
5 5
 ##
6 6
 
7  
-# TEMP
8  
-exports.run = ->
  7
+lib =
  8
+	colors:    require "colors"
  9
+	fs:        require "fs"
  10
+	httpProxy: require "http-proxy"
  11
+	mime:      require "mime"
  12
+	path:      require "path"
  13
+	squire:    require "../main"
  14
+	watchr:    require "watchr"
9 15
 
10  
-# lib =
11  
-# 	squire:    require "../main"
12  
-# 	fs:        require "fs"
13  
-# 	httpProxy: require "http-proxy"
14  
-# 	path:      require "path"
15  
-# 	colors:    require "colors"
16  
-# 	mime:      require "mime"
  16
+commands =
  17
+	build: require "./build"
17 18
 
18  
-# commands =
19  
-# 	build: require "./build"
20  
-
21  
-# class PreviewCommand extends lib.squire.Squire
22  
-# 	# The entry point to the command.
23  
-# 	run: (options) ->
24  
-# 		@verboseLevel = options.verbose
  19
+class PreviewCommand extends lib.squire.Squire
  20
+	# Whether or not we're currently building. Requests that come in during building will wait
  21
+	# until building is done before responding.
  22
+	isBuilding: false
  23
+	
  24
+	# If files change while we're in the middle of building, this flag will be set so that we know
  25
+	# to rebuild after the end of the current build.
  26
+	needsRebuild: false
  27
+	
  28
+	# The error message returned from the most recent build. Whenever errors are present (that is,
  29
+	# when the length of the error message is > 0), all requests will return a 500 with the
  30
+	# message.
  31
+	errorMessage: ""
  32
+	
  33
+	# Requests that come in while we're building don't execute immediately -- we need to wait until
  34
+	# we're done building before we respond -- so we queue them up here so that we can respond when
  35
+	# we're done building.
  36
+	queuedRequestParams: []
  37
+	
  38
+	# The entry point into the command.
  39
+	run: (options) ->
  40
+		# Grab some goodies.
  41
+		@verboseLevel = options.verbose
  42
+		@port         = options.port
25 43
 		
26  
-# 		# Create the preview server.
27  
-# 		server = lib.httpProxy.createServer (request, response, proxy) =>
28  
-# 			params = {request, response, proxy}
29  
-			
30  
-# 			# There can be issues if the build folder doesn't exist, so we need to make sure the
31  
-# 			# project is built before a request is handled.
32  
-# 			if lib.fs.existsSync @outputPath
33  
-# 				params.urlInfo = @getRouteUrlInfo request.url
34  
-# 				@handleRequest params
35  
-# 			else
36  
-# 				commands.build.run mode: "preview", callback: (errors) =>
37  
-# 					params.urlInfo = @getRouteUrlInfo request.url
38  
-# 					@handleRequest params
  44
+		# Watch files and set up the file server.
  45
+		@build =>
  46
+			@watchFiles()
  47
+			@runServer()
39 48
 		
40  
-# 		server.listen options.port
  49
+		# Make some loggies.
  50
+		address = lib.colors.bold "http://localhost:#{options.port}/"
  51
+		console.log "\nRunning a local server at #{address}"
  52
+		console.log "Everything will be rebuilt each time the browser is refreshed.\n"
  53
+	
  54
+	# Set up a file watcher for input changes.
  55
+	watchFiles: ->
  56
+		lib.watchr.watch
  57
+			path:              @appPath
  58
+			ignoreHiddenFiles: @config.ignoreHiddenFiles
  59
+			
  60
+			# Rebuild whenever something changes. There's a lot of room for improvement here -- in
  61
+			# most cases we don't actually need to rebuild the entire app whenever a single file
  62
+			# changes. However, every file can potentially be dependent on any other file (many
  63
+			# plugins provide access to the app tree), and we don't have a way to get the
  64
+			# dependencies of a file, so we just rebuild the whole app to be safe.
  65
+			listener: (eventName, path, currentStat, previousStat) =>
  66
+				# If we're already building, we're going to need to rebuild again once the current
  67
+				# build is done. Otherwise we can initiate a build.
  68
+				if @isBuilding
  69
+					@needsRebuild = true
  70
+				else
  71
+					@log "[Build]", "Begin", 1, "yellow"
  72
+					
  73
+					@build =>
  74
+						@log "[Build]", "End", 1, "yellow"
  75
+						@handleRequest params for params in @queuedRequestParams
  76
+	
  77
+	# Sets up the file server.
  78
+	runServer: ->
  79
+		server = lib.httpProxy.createServer (request, response, proxy) =>
  80
+			params = { request, response, proxy, url: @getRouteUrl request.url }
  81
+			
  82
+			# If we're building, we need to queue up the request to respond after we're done
  83
+			# building. Otherwise we respond immediately.
  84
+			if @isBuilding
  85
+				@queuedRequestParams.push params
  86
+			else
  87
+				@handleRequest params
41 88
 		
42  
-# 		address = lib.colors.bold "http://localhost:#{options.port}/"
43  
-# 		console.log "\nRunning a local server at #{address}"
44  
-# 		console.log "Everything will be rebuilt each time the browser is refreshed.\n"
  89
+		server.listen @port
45 90
 	
46  
-# 	# Handles a request. If the request is for an index file, it will rebuild the project.
47  
-# 	handleRequest: (params) ->
48  
-# 		# Modify the URL to route to an index file if necessary.
49  
-# 		params.urlInfo = new lib.squire.UrlInfo "#{params.urlInfo.url}/index.html" if params.urlInfo.isDirectory
  91
+	# A little helper to build the project.
  92
+	build: (callback) ->
  93
+		# Reset stuff and build.
  94
+		@isBuilding   = true
  95
+		@errorMessage = ""
50 96
 		
51  
-# 		# Serve the response.
52  
-# 		if params.urlInfo.baseName is "index"
53  
-# 			@log "[Build]", "Begin", 1, "yellow"
  97
+		commands.build.run mode: "preview", shouldLogErrors: false, callback: =>
  98
+			# Start over if we need to rebuild.
  99
+			if @needsRebuild
  100
+				@needsRebuild = false
  101
+				@build callback
  102
+				return
  103
+			
  104
+			# Make note of errors and reset flags.
  105
+			@errorMessage = @app.getPath(@config.inputDirectory).consolidateErrors "plain"
  106
+			@isBuilding   = @needsRebuild = false
54 107
 			
55  
-# 			commands.build.run mode: "preview", callback: (errors) =>
56  
-# 				@log "[Build]", "End", 1, "yellow"
57  
-# 				params.errors = errors if errors.length > 0
58  
-# 				@serveResponse params
59  
-# 		else
60  
-# 			@serveResponse params
  108
+			# Call the callback.
  109
+			callback?()
61 110
 	
62  
-# 	# Serves a response based on the given parameters. Calls out to one of the helper functions
63  
-# 	# below depending on the content of the params.
64  
-# 	serveResponse: (params) ->
65  
-# 		if params.errors?
66  
-# 			@serveErrors params
67  
-# 		else if lib.fs.existsSync params.urlInfo.url
68  
-# 			@serveFile params
69  
-# 		else if @config.enableProxy
70  
-# 			@serveProxy params
71  
-# 		else
72  
-# 			@serve404 params
  111
+	# Handles a request. Calls out to one of the helper functions below depending on the content of
  112
+	# the params.
  113
+	handleRequest: (params) ->
  114
+		if @errorMessage?.length > 0
  115
+			@serveErrors params
  116
+		else if params.url.exists
  117
+			@serveFile params
  118
+		else if @config.enableProxy
  119
+			@serveProxy params
  120
+		else
  121
+			@serve404 params
73 122
 	
74  
-# 	# Serves a static file.
75  
-# 	serveFile: (params, delay = @config.simulatedFileDelay) ->
76  
-# 		{request, response, urlInfo} = params
  123
+	# Serves a static file.
  124
+	serveFile: (params, delay = @config.simulatedFileDelay) ->
  125
+		{request, response, url} = params
77 126
 		
78  
-# 		if delay > 0
79  
-# 			@log "[Delay]", "#{request.url} (#{delay}ms)", 2, "cyan"
80  
-# 			setTimeout (=> @serveFile params, 0), delay
81  
-# 		else
82  
-# 			@log "[Serve]", "#{request.url}", 2, "blue"
83  
-# 			response.writeHead 200, "Content-Type": lib.mime.lookup(urlInfo.url)
84  
-# 			response.write lib.fs.readFileSync(urlInfo.url), "binary"
85  
-# 			response.end()
  127
+		if delay > 0
  128
+			@log "[Delay]", "#{request.url} (#{delay}ms)", 2, "cyan"
  129
+			setTimeout (=> @serveFile params, 0), delay
  130
+		else
  131
+			@log "[Serve]", "#{request.url}", 2, "blue"
  132
+			response.writeHead 200, "Content-Type": lib.mime.lookup(url.path)
  133
+			response.write lib.fs.readFileSync(url.path), "binary"
  134
+			response.end()
86 135
 	
87  
-# 	# Serves a proxied route.
88  
-# 	serveProxy: (params, delay = @config.simulatedProxyDelay) ->
89  
-# 		{request, response, proxy, buffer} = params
  136
+	# Serves a proxied route.
  137
+	serveProxy: (params, delay = @config.simulatedProxyDelay) ->
  138
+		{request, response, proxy, buffer} = params
90 139
 		
91  
-# 		if delay > 0
92  
-# 			@log "[Delay]", "#{request.url} (#{delay}ms)", 2, "cyan"
93  
-# 			params.buffer = lib.httpProxy.buffer request
94  
-# 			setTimeout (=> @serveProxy params, 0), delay
95  
-# 		else
96  
-# 			@log "[Proxy]", "#{request.url}", 2, "green"
97  
-# 			proxy.proxyRequest request, response,
98  
-# 				host:   @config.proxyHost
99  
-# 				port:   @config.proxyPort
100  
-# 				buffer: buffer
  140
+		if delay > 0
  141
+			@log "[Delay]", "#{request.url} (#{delay}ms)", 2, "cyan"
  142
+			params.buffer = lib.httpProxy.buffer request
  143
+			setTimeout (=> @serveProxy params, 0), delay
  144
+		else
  145
+			@log "[Proxy]", "#{request.url}", 2, "green"
  146
+			proxy.proxyRequest request, response,
  147
+				host:   @config.proxyHost
  148
+				port:   @config.proxyPort
  149
+				buffer: buffer
101 150
 	
102  
-# 	# Takes in a list of errors generated during the build process and serves them with a 500.
103  
-# 	serveErrors: ({response, errors}) ->
104  
-# 		response.writeHead 500, "Content-Type": "text/plain"
105  
-# 		response.write @consolidateErrors errors, "plain"
106  
-# 		response.end()
  151
+	# Takes in a list of errors generated during the build process and serves them with a 500.
  152
+	serveErrors: ({response}) ->
  153
+		response.writeHead 500, "Content-Type": "text/plain"
  154
+		response.write @errorMessage
  155
+		response.end()
107 156
 	
108  
-# 	# Serves a 404 error.
109  
-# 	serve404: ({request, response, urlInfo}) ->
110  
-# 		@log "[Serve]", "#{request.url} (Not Found)", 2, "red"
111  
-# 		response.writeHead 404, "Content-Type": "text/plain"
112  
-# 		response.write "404: File #{urlInfo.url} not found."
113  
-# 		response.end()
  157
+	# Serves a 404 error.
  158
+	serve404: ({request, response, url}) ->
  159
+		@log "[Serve]", "#{request.url} (Not Found)", 2, "red"
  160
+		response.writeHead 404, "Content-Type": "text/plain"
  161
+		response.write "404: File #{url.path} not found."
  162
+		response.end()
114 163
 	
115  
-# 	# Does some processing of a given request URL and returns a URL info object.
116  
-# 	getRouteUrlInfo: (url) ->
117  
-# 		rewrites      = @config.routeRewrites or []
118  
-# 		urlComponents = url.split "/"
  164
+	# Does some processing of a given request path and returns a URL object.
  165
+	getRouteUrl: (path) ->
  166
+		rewrites       = @config.routeRewrites or []
  167
+		pathComponents = path.split "/"
119 168
 		
120  
-# 		for rewrite in rewrites
121  
-# 			{from, to}     = rewrite
122  
-# 			from           = from[0...from.length - 1] if from[from.length - 1] is "/"
123  
-# 			fromComponents = from.split "/"
124  
-# 			matches        = true
125  
-# 			keys           = {}
  169
+		# Handle route rewrites.
  170
+		for rewrite in rewrites
  171
+			{from, to}     = rewrite
  172
+			from           = from[0...from.length - 1] if from[from.length - 1] is "/"
  173
+			fromComponents = from.split "/"
  174
+			matches        = true
  175
+			keys           = {}
126 176
 			
127  
-# 			if fromComponents.length is urlComponents.length
128  
-# 				for fromComponent, index in fromComponents
129  
-# 					urlComponent = urlComponents[index]
  177
+			if fromComponents.length is pathComponents.length
  178
+				for fromComponent, index in fromComponents
  179
+					pathComponent = pathComponents[index]
130 180
 					
131  
-# 					if fromComponent[0] is ":"
132  
-# 						key       = fromComponent[1..]
133  
-# 						keys[key] = urlComponent
134  
-# 					else if fromComponent isnt urlComponent
135  
-# 						matches = false
136  
-# 						break
137  
-# 			else
138  
-# 				matches = false
  181
+					if fromComponent[0] is ":"
  182
+						key       = fromComponent[1..]
  183
+						keys[key] = pathComponent
  184
+					else if fromComponent isnt pathComponent
  185
+						matches = false
  186
+						break
  187
+			else
  188
+				matches = false
139 189
 			
140  
-# 			if matches
141  
-# 				url = to
142  
-# 				url = url.replace ":#{key}", value for key, value of keys
143  
-# 				break
  190
+			if matches
  191
+				path = to
  192
+				path = path.replace ":#{key}", value for key, value of keys
  193
+				break
144 194
 		
145  
-# 		url = lib.path.join @outputPath, url
146  
-# 		new lib.squire.UrlInfo url, @outputPath
  195
+		url = new lib.squire.Url lib.path.join(@outputPath, path)
  196
+		url = new lib.squire.Url "#{url.path}/index.html" if url.isDirectory
  197
+		url
147 198
 	
148  
-# 	# A log helper that filters messages based on a verbose level.
149  
-# 	log: (label, message, verboseThreshold = 1, labelColor = "white") ->
150  
-# 		timestamp = lib.colors.grey "<#{@getTimestamp()}>"
151  
-# 		label     = lib.colors[labelColor] label
152  
-# 		console.log "#{timestamp} #{label} #{message}" if @verboseLevel >= verboseThreshold
  199
+	# A log helper that filters messages based on a verbose level.
  200
+	log: (label, message, verboseThreshold = 1, labelColor = "white") ->
  201
+		timestamp = lib.colors.grey "<#{@getTimestamp()}>"
  202
+		label     = lib.colors[labelColor] label
  203
+		console.log "#{timestamp} #{label} #{message}" if @verboseLevel >= verboseThreshold
153 204
 	
154  
-# 	# Returns a formatted timestamp for the current time.
155  
-# 	getTimestamp: ->
156  
-# 		date    = new Date
157  
-# 		hours   = date.getHours()
158  
-# 		minutes = date.getMinutes()
159  
-# 		seconds = date.getSeconds()
160  
-# 		hours   = "0#{hours}"   if hours < 10
161  
-# 		minutes = "0#{minutes}" if minutes < 10
162  
-# 		seconds = "0#{seconds}" if seconds < 10
  205
+	# Returns a formatted timestamp for the current time.
  206
+	getTimestamp: ->
  207
+		date    = new Date
  208
+		hours   = date.getHours()
  209
+		minutes = date.getMinutes()
  210
+		seconds = date.getSeconds()
  211
+		hours   = "0#{hours}"   if hours < 10
  212
+		minutes = "0#{minutes}" if minutes < 10
  213
+		seconds = "0#{seconds}" if seconds < 10
163 214
 		
164  
-# 		"#{hours}:#{minutes}:#{seconds}"
  215
+		"#{hours}:#{minutes}:#{seconds}"
165 216
 
166  
-# # We only expose the run function.
167  
-# exports.run = (options) -> (new PreviewCommand mode: "preview").run options
  217
+# We only expose the run function.
  218
+exports.run = (options) -> (new PreviewCommand mode: "preview").run options
10  core/error.coffee
@@ -12,24 +12,24 @@ exports.Error = class Error
12 12
 	@log: (options) -> (new exports.Error options).log options.fancy
13 13
 	
14 14
 	constructor: ({message, details, path}) ->
15  
-		@message      = "\n#{message}"
  15
+		@plainMessage = "\n#{message}"
16 16
 		@fancyMessage = "\n" + lib.colors.red "\u2718 #{message}"
17 17
 		
18 18
 		if details?
19 19
 			details        = "\n#{details}"
20 20
 			details        = "\nIn #{path}:\n#{details}" if path?
21 21
 			details        = details.replace /\n/g, "\n    "
22  
-			@message      += "\n#{details}"
  22
+			@plainMessage += "\n#{details}"
23 23
 			@fancyMessage += "\n#{details}"
24 24
 		else if path?
25  
-			@message      += "\n\n    In #{path}"
  25
+			@plainMessage += "\n\n    In #{path}"
26 26
 			@fancyMessage += "\n\n    In #{path}"
27 27
 		
28  
-		@message      += "\n"
  28
+		@plainMessage += "\n"
29 29
 		@fancyMessage += "\n"
30 30
 	
31 31
 	log: (fancy = true) ->
32  
-		console.error if fancy then @fancyMessage else @message
  32
+		console.error if fancy then @fancyMessage else @plainMessage
33 33
 	
34 34
 	toString: -> @message
35 35
 
21  core/file.coffee
@@ -15,8 +15,7 @@ lib =
15 15
 class File extends lib.squire.Squire
16 16
 	constructor: ({path} = {}) ->
17 17
 		super
18  
-		@url    = new lib.squire.Url path
19  
-		@errors = []
  18
+		@url = new lib.squire.Url path
20 19
 	
21 20
 	# The raw content of the file before it gets processed.
22 21
 	Object.defineProperty @prototype, "rawContent", get: ->
@@ -39,6 +38,14 @@ class File extends lib.squire.Squire
39 38
 		
40 39
 		set: (@_data) ->
41 40
 	
  41
+	# Same thing but for errors.
  42
+	Object.defineProperty @prototype, "errors",
  43
+		get: ->
  44
+			@build() if @_errors is undefined
  45
+			@_errors
  46
+		
  47
+		set: (@_errors) ->
  48
+	
42 49
 	# The file's plugin. Just proxies to the URL's plugin for convenience.
43 50
 	Object.defineProperty @prototype, "plugin", get: -> @url?.plugin
44 51
 	
@@ -49,8 +56,16 @@ class File extends lib.squire.Squire
49 56
 		
50 57
 		plugin for plugin in @plugins when extension in (plugin.postProcessExtensions or [plugin.outputExtension])
51 58
 	
  59
+	# Returns the parent directory.
  60
+	Object.defineProperty @prototype, "parent", get: ->
  61
+		relativeDirectory = @url.directory[@app.url.path.length...]
  62
+		@app?.getPath(relativeDirectory).url.path
  63
+	
52 64
 	# Resets the content cache so that the next time content is requested it will be rebuilt.
53  
-	reloadContent: -> delete @_content
  65
+	reloadContent: ->
  66
+		delete @_content
  67
+		delete @_data
  68
+		delete @_errors
54 69
 	
55 70
 	# Builds the file at our path and returns the built content. This is only needed internally --
56 71
 	# generally you should use the "content" property to retrieve the content.
3  package.json
@@ -34,7 +34,8 @@
34 34
 		"uglifycss":     "0.0.x",
35 35
 		"http-proxy":    "0.8.x",
36 36
 		"eco":           "1.1.0-rc-3",
37  
-		"fibers":        "0.6.9"
  37
+		"fibers":        "0.6.9",
  38
+		"watchr":        "2.1.5"
38 39
 	},
39 40
 	
40 41
 	"devDependencies": {
4  plugins/coffeescript.coffee
@@ -96,8 +96,8 @@ class CoffeeScriptPlugin extends lib.squire.Plugin
96 96
 			super
97 97
 	
98 98
 	createCoffeeScriptError: (options) ->
99  
-		options.message     = "There was an error while compiling your CoffeeScript:"
100  
-		options.description = options.error.toString().split("\n")[0]
  99
+		options.message = "There was an error while compiling your CoffeeScript:"
  100
+		options.details = options.error.toString().split("\n")[0]
101 101
 		@createError options
102 102
 
103 103
 # Expose plugin.
1  plugins/jade.coffee
@@ -24,7 +24,6 @@ class JadePlugin extends lib.squire.Plugin
24 24
 			locals.config   = @config
25 25
 			html            = compileFunction locals
26 26
 		catch error
27  
-			# TODO: Is it possible to get a line number from the error?
28 27
 			callback null, null, [@createError message: "There was an error while compiling your Jade template.", details: error.toString(), path: options.path]
29 28
 			return
30 29
 		

0 notes on commit a04635b

Please sign in to comment.
Something went wrong with that request. Please try again.