1path      = require 'path'
2async     = require 'async'
3fs        = require 'fs'
4minimatch = require 'minimatch'
5less      = require 'less'
6vm        = require 'vm'
7shelljs   = require 'shelljs'
8ejs       = require 'ejs'
9uglify    = require 'uglify-js'
10sass      = require 'node-sass'
11
12compressCss = (source, callback) ->
13  parser = new less.Parser optimization: 2
14  parser.parse source, (err, tree) ->
15    callback err, tree.toCSS(compress: true)
16
17compressJs = (source, callback) ->
18  {code, map} = uglify.minify source, fromString: true
19  callback null, code
20
21compileSass = (file, callback) ->
22  data = readFile file
23  sass.render data, callback, include_paths: [sourceSassDir], output_style: null
24
25isDirectory = (dir) ->
26  fs.existsSync(dir) and fs.statSync(dir).isDirectory()
27
28readFile = (filename) ->
29  fs.readFileSync filename, 'utf8'
30
31writeFile = (filename, content) ->
32  fs.writeFileSync filename, content, 'utf8'
33
34findFilesIn = (dir, pattern) ->
35  shelljs.find(dir)
36    .filter (file) ->
37      minimatch file, pattern, matchBase: true
38    .filter (file) ->
39      not isDirectory file
40
41loadFilesIntoVariables = (dir) ->
42  result = {}
43
44  for file in findFilesIn dir, '*.*'
45    varName = path.basename(file, path.extname(file))
46    result[varName] = readFile file
47
48  result
49
50baseDir       = __dirname
51sourceDir     = path.resolve baseDir, '..', 'src'
52outputDir     = path.resolve baseDir, '..', 'pkg'
53componentsDir = path.resolve baseDir, '..', 'components'
54includesDir   = path.resolve baseDir, 'includes'
55sourceJsDir   = path.resolve sourceDir, 'js'
56sourceSassDir = path.resolve sourceDir, 'sass'
57outputJsDir   = path.resolve outputDir, 'scripts'
58outputCssDir  = path.resolve outputDir, 'styles'
59
60variables         = loadFilesIntoVariables includesDir
61variables.version = JSON.parse(readFile path.resolve baseDir, '../package.json').version
62variables.date    = new Date().toUTCString()
63variables.about   = variables.about.replace(/\r|\n|\t/g, "").replace(/"/g, "\\\"")
64
65module.exports = (grunt) ->
66  grunt.registerTask 'build', 'clean compile_sass copy_misc_files build_core pack validate add_header'.split(/\s/g)
67
68  grunt.registerTask 'clean', 'Cleans the build folder', ->
69    shelljs.rm '-fr', outputDir
70    shelljs.mkdir '-p', outputJsDir, outputCssDir
71
72  grunt.registerTask 'compile_sass', ->
73    files = findFilesIn sourceSassDir, "**/*.scss"
74
75    jobs = files.map (sassFile) ->
76      (done) ->
77        cssFile = path.join(outputCssDir, path.basename sassFile).replace /\.scss$/, '.css'
78
79        # skip the theme template
80        return done() if /theme_template/.test sassFile
81
82        compileSass sassFile, (err, css) ->
83          writeFile cssFile, css
84          done()
85
86    async.parallel jobs, @async()
87
88  grunt.registerTask 'copy_misc_files', ->
89    shelljs.cp "#{baseDir}/index.html", outputDir
90    shelljs.cp "#{sourceJsDir}/sh*.js", outputJsDir
91
92  grunt.registerTask 'build_core', ->
93    variables.about = ejs.render variables.about, variables
94    corePath        = path.join outputJsDir, 'shCore.js'
95    xregexpSource   = readFile path.join(componentsDir, 'xregexp', 'src', 'xregexp.js')
96    coreSource      = ejs.render readFile(corePath), variables
97
98    writeFile corePath, xregexpSource + coreSource
99
100  grunt.registerTask 'pack', ->
101    addMinExt = (filename) ->
102      ext = path.extname filename
103      filename = path.basename filename, ext
104      "#{filename}.min#{ext}"
105
106    # this could be changed to minify all JS files, not just core
107    findFilesIn(outputJsDir, '**/shCore.js').forEach (file) ->
108      compressJs readFile(file), (err, source) ->
109        writeFile path.join(outputJsDir, path.basename(addMinExt file)), source
110
111    findFilesIn(outputCssDir, '**/*.css').forEach (file) ->
112      compressCss readFile(file), (err, source) ->
113        writeFile file, source
114
115  grunt.registerTask 'add_header', ->
116    files  = findFilesIn(outputDir, "**/*.js").concat(findFilesIn(outputDir, '**.css'))
117    header = ejs.render variables.header, variables
118
119    files.forEach (file) ->
120      writeFile file, header + readFile file
121
122  grunt.registerTask 'validate', ->
123    context = {}
124    coreFile = path.join(outputJsDir, 'shCore.js')
125    vm.runInNewContext readFile(coreFile), context, coreFile
126
127    findFilesIn(outputDir, "**.js").forEach (file) ->
128      return  if /shCore/.test(file)
129      vm.runInNewContext readFile(file), context, file
130
131