UNPKG

learn-sass

Version:

Learn SASS and SCSS through a workshopper adventure.

141 lines (107 loc) 4.25 kB
// Based on workshopper-exercise/execute const spawn = require('child_process').spawn , path = require('path') , fs = require('fs') , after = require('after') , xtend = require('xtend') , postcss = require('postcss') , sorting = require('postcss-sorting') , through = require('through2') const sorter = postcss([sorting({ order: ['custom-properties', 'dollar-variables', 'declarations', 'rules', 'at-rules'], 'properties-order': 'alphabetical' })]) function execute (exercise, opts) { if (!opts) opts = {} exercise.addSetup(setup) exercise.addProcessor(processor) // override if you want to mess with stdout exercise.getStdout = function (type, child) { var buf = '' return child.stdout.pipe(through( function(chunk, enc, cb) { buf += chunk cb() }, function(cb) { const that = this sorter .process(buf.toString()) .then(function(result) { that.push(result.css) cb() }) })) } exercise.getSolutionFiles = function (callback) { var translated = path.join(this.dir, './solution_' + this.lang) var fallback = path.join(this.dir, './solution') checkPath(translated, function(err, list) { if (list && list.length > 0) return callback(null, list) checkPath(fallback, callback) }); function checkPath(dir, callback) { fs.exists(dir, function (exists) { if (!exists) return callback(null, []); fs.readdir(dir, function (err, list) { if (err) return callback(err) list = list .filter(function (f) { return (/\.js$/).test(f) }) .map(function (f) { return path.join(dir, f)}) callback(null, list) }) }) } } return exercise function setup (mode, callback) { this.submission = this.args[0] // first arg obviously // default args, override if you want to pass special args to the // solution and/or submission, override this.setup to do this this.submissionArgs = Array.prototype.slice.call(1, this.args) this.solutionArgs = Array.prototype.slice.call(1, this.args) // edit/override if you want to alter the child process environment this.env = xtend(process.env) // set this.solution if your solution is elsewhere if (!this.solution) { var localisedSolutionPath = path.join(this.dir, './solution_' + this.lang + '/solution.scss'); this.solution = fs.existsSync(localisedSolutionPath) ? localisedSolutionPath : path.join(this.dir, './solution/solution.scss') } process.nextTick(callback) } function kill () { ;[ this.submissionChild, this.solutionChild ].forEach(function (child) { if (child && typeof child.kill == 'function') child.kill() }) setTimeout(function () { this.emit('executeEnd') }.bind(this), 10) } function processor (mode, callback) { var ended = after(mode == 'verify' ? 2 : 1, kill.bind(this)) // backwards compat for workshops that use older custom setup functions if (!this.solutionCommand) this.solutionCommand = [ this.solution ].concat(this.solutionArgs) if (!this.submissionCommand) this.submissionCommand = [ this.submission ].concat(this.submissionArgs) this.sassExec = path.resolve(__dirname, './node_modules/node-sass/bin/node-sass'); this.submissionChild = spawn(this.sassExec, this.submissionCommand, { env: this.env }) this.submissionStdout = this.getStdout('submission', this.submissionChild) setImmediate(function () { // give other processors a chance to overwrite stdout this.submissionStdout.on('end', ended) }.bind(this)) if (mode == 'verify') { this.solutionChild = spawn(this.sassExec, this.solutionCommand, { env: this.env }) this.solutionStdout = this.getStdout('solution', this.solutionChild) setImmediate(function () { // give other processors a chance to overwrite stdout this.solutionStdout.on('end', ended) }.bind(this)) } process.nextTick(function () { callback(null, true) }) } } module.exports = execute