UNPKG

9.09 kBtext/coffeescriptView Raw
1util = require("./util.coffee")
2_ = require("lodash")
3wrench = require("wrench")
4cheerio = require("cheerio")
5pathModule = require("path")
6fs = require("fs")
7express = require("express")
8CoffeeScript = require("coffee-script")
9Less = require("less")
10commander = (require "commander")
11program = commander.usage("[options] <target widgetSource.coffee>")
12 .option("-p,--add-path <path>","add pathes other than CWD to search root")
13 .option("-r,--server-root <path>","change test server root other than CWD")
14 .option("-s,--test-style-sheet <path>","add an stylesheet to test page")
15 .option("-e,--test-entry <path>","path to your own test logic")
16 .option("-j,--jquery <path>","specify the jquery path")
17 .option("-l,--leafjs <path>","specify the leafjs path")
18 .option("-g,--test-page <path>","path to your own index.html of the test page")
19 .option("-b,--build-package","build the file into a single js package rather than run it in browser")
20 .option("-t,--temp-path <path>","path to temp file")
21 .option("--use-bare","don't add anything to the index.html of this test")
22 .option("--port <port>","port of the test server")
23 .option("--host <host>","host of the test server")
24 .parse(process.argv)
25server = express()
26defaultServerRoot = "./"
27defaultServerHost = "0.0.0.0"
28defaultServerPort = 8000
29defaultTempPath = "/tmp/"
30pathes = (program.addPath or "").split(",").map (item)->item.trim()
31if "./" not in pathes and "." not in pathes
32 pathes.unshift "./"
33
34serverRoot = program.serverRoot or defaultServerRoot
35serverPort = parseInt(program.port) or defaultServerPort
36serverHost = program.host or defaultServerHost
37tempPath = program.tempPath or defaultTempPath
38tempPath = pathModule.join tempPath,"leaf-tester"
39indexHtml = null
40server.get "/",(req,res,next)->
41 build()
42 res.end(indexHtml)
43server.get "*",(req,res,next)->
44 filePath = pathModule.join tempPath,req.url
45 console.log "try get",filePath
46 if fs.existsSync filePath
47 fs.createReadStream(filePath).pipe(res)
48 else
49 next()
50
51
52server.use "/",express.static(serverRoot)
53server.listen serverPort,serverHost
54
55
56testTargetPath = program.args[0]
57if not testTargetPath
58 commander.help()
59
60testIndexTemplate = fs.readFileSync(pathModule.join(__dirname,"asset/index.html"),"utf8");
61
62jqueryPath = program.jquery || pathModule.join(__dirname,"asset/jquery.js")
63leafJsPath = program.leafjs || pathModule.join(__dirname,"asset/leaf.js")
64testLogicPath = program.testEntry or pathModule.join(__dirname,"asset/testEntry.coffee")
65
66if program.buildPackage
67 dependencies = [
68 ]
69else
70 dependencies = [
71 jqueryPath
72 leafJsPath
73 testLogicPath
74 ]
75dependencies = dependencies.map (item)->
76 return {path:item}
77htmlDependencies = null
78build = ()->
79 if fs.existsSync tempPath
80 wrench.rmdirSyncRecursive tempPath
81 if not fs.existsSync tempPath
82 wrench.mkdirSyncRecursive tempPath
83 testDeps = resolve {path:testTargetPath,expand:true},[{path:testTargetPath,expand:true}]
84 htmlDependencies = dependencies.concat testDeps
85 if not program.buildPackage
86 console.log "solve dependencies",htmlDependencies
87 content = prepareFiles(htmlDependencies)
88 if program.buildPackage
89 console.log content
90 process.exit(0)
91 else
92 indexHtml = content
93
94
95resolve = (fileInfo,deps)->
96 file = fileInfo.path
97 if pathModule.extname(file) isnt ".coffee"
98 return deps
99 if not fileInfo.expand
100 return deps
101 content = util.getFileInSearchPath file,pathes
102 results = []
103 lines = content.split("\n").filter (line)->line.trim()
104 lines = lines.filter (line)->line.indexOf("## require ") is 0
105 lines.reverse()
106 for line in lines
107 asVar = false
108 if line[0] is "#" and line[1] isnt "#"
109 continue
110 if line.indexOf("## require ") isnt 0
111 break
112 params = line.substring(2).trim().split(" ").filter (item)->item
113 depPath = params[1]
114 if params[2] is "as" and params[3]
115 asVar = true
116 if pathModule.basename(depPath) in (deps.map (info)-> pathModule.basename(info.path))
117 continue
118 if not depPath
119 throw new Error "invalid require clause '#{line.trim()}', missing target file."
120 deps.unshift {path:depPath,asVar:asVar,varName:params[3]}
121 if pathModule.extname(depPath) is ".coffee"
122 resolve depPath,deps
123 return deps
124
125prepareFiles = (files)->
126 if program.buildPackage
127 processor = packager
128 else
129 processor = preparer
130 $ = cheerio.load testIndexTemplate
131 content = ""
132 for fileInfo in files
133 file = fileInfo.path
134 if fileInfo.asVar
135 if program.buildPackage
136 content = processor["#"](fileInfo,content)
137 else
138 processor["#"](fileInfo,$)
139 continue
140 ext = pathModule.extname(file)
141 if processor[ext]
142 if program.buildPackage
143 content = processor[ext](fileInfo,content)
144 else
145 processor[ext](fileInfo,$)
146 else
147 throw new Error "unkown ext type #{ext} of file #{file}"
148 if content
149 return content
150 html = $.html()
151 fs.writeFileSync pathModule.join(tempPath,"index.html"),html
152 return html
153preparer = {
154 ".html":(fileInfo,$)->
155 path = fileInfo.path
156 content = util.getFileInSearchPath path,pathes
157 $("body").append(content)
158
159 ".js":(fileInfo,$)->
160 path = fileInfo.path
161 src = path
162 target = pathModule.join tempPath,pathModule.basename path
163 util.copySync src,target
164 $("head").append("<script src='./#{pathModule.basename(path)}'></script>\n")
165 ".coffee":(fileInfo,$)->
166 path = fileInfo.path
167 content = CoffeeScript.compile util.getFileInSearchPath path,pathes
168 target = pathModule.join tempPath,pathModule.basename(path,".coffee")+".js"
169 fs.writeFileSync target,content
170 $("head").append("<script src='./#{pathModule.basename(target)}'></script>\n")
171 ".css":(fileInfo,$)->
172 path = fileInfo.path
173 src = path
174 target = pathModule.join tempPath,pathModule.basename path
175 util.copySync src,target
176 $("head").append("<link rel='stylesheet' href='./#{pathModule.basename(target)}' type='text/css' media='screen' />\n")
177
178 ".less":(fileInfo,$)->
179 path = fileInfo.path
180 content = null
181 Less.render (util.getFileInSearchPath path,pathes),(err,result)->
182 if err
183 throw err
184 content = result
185
186 target = pathModule.join tempPath,pathModule.basename(path,".less")+".css"
187 fs.writeFileSync target,content
188
189 $("head").append("<link rel='stylesheet' href='./#{pathModule.basename(target)}' type='text/css' media='screen' />\n")
190 "#":(fileInfo,$)->
191 path = fileInfo.path
192 varName = fileInfo.varName
193 if varName is "var"
194 varName = pathModule.basename path,pathModule.extname(path)
195 content = util.getFileInSearchPath path,pathes
196 jsContent = "window.#{varName} = #{JSON.stringify(content)}"
197 fileName = "import-var-#{varName}.js"
198 target = pathModule.join tempPath,fileName
199 fs.writeFileSync target,jsContent
200 $("head").append("<script src='./#{fileName}'></script>\n");
201
202}
203packager = {
204 ".html":(fileInfo,content)->
205 path = fileInfo.path
206 console.warn "//packge mode don't support include html #{fileInfo.path}"
207 return content
208 ".js":(fileInfo,content)->
209 path = fileInfo.path
210 js = util.getFileInSearchPath path,pathes
211 return content + ";;;\n#{js}"
212 ".coffee":(fileInfo,content)->
213 path = fileInfo.path
214 js = CoffeeScript.compile util.getFileInSearchPath path,pathes
215 return content + ";;;\n#{js}"
216 ".css":(fileInfo,content)->
217 path = fileInfo.path
218 css = util.getFileInSearchPath path,pathes
219 return content + "(function(){var style = document.createElement('style');style.setAttribute('data-debug-path',#{JSON.stringify('path')});style.innerHTML = #{JSON.stringify(css)};document.head.appendChild(style)})()"
220 ".less":(fileInfo,content)->
221 path = fileInfo.path
222 css = null
223 Less.render (util.getFileInSearchPath path,pathes),(err,result)->
224 if err
225 throw err
226 css = result
227 return content + "(function(){var style = document.createElement('style');style.setAttribute('data-debug-path',#{JSON.stringify('path')});style.innerHTML = #{JSON.stringify(css)};document.head.appendChild(style)})()"
228 "#":(fileInfo,content)->
229 path = fileInfo.path
230 varName = fileInfo.varName
231 if varName is "var"
232 varName = pathModule.basename path,pathModule.extname(path)
233 content = util.getFileInSearchPath path,pathes
234 jsContent = "window.#{varName} = #{JSON.stringify(content)}"
235 return content + jsContent
236
237}
238build()