-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
115 lines (103 loc) · 3.23 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/usr/bin/env node
"use strict"
var adventure = require('adventure')
var msee = require('msee')
var fs = require('fs')
var path = require('path')
var inquirer = require('inquirer')
var wordwrap = require('wordwrap')
var assert = require('assertf')
module.exports = function(options) {
// Prevent automatic close of stdin, so that input is possible after showing the problem description.
options.autoclose = false
var shop = adventure(options)
shop.on('pass', function() {
console.log('Type `' + options.name+ '` to show the menu.\n')
})
var exercises = Object.keys(options.exercises).map(function(exerciseName) {
var dir = options.exercises[exerciseName]
var exercise = require(dir)
exercise.name = exerciseName
exercise.problemRaw = exercise.problem
exercise.problem = formatProblem(exercise.problem)
exercise.solutionRaw = exercise.solution
exercise.solution = formatSolution(exercise.solution)
exercise.dir = dir
exercise.cleanName = clean(exercise.name)
return exercise
})
exercises.forEach(function(exercise) {
assert(exercise.name, 'exercise needs name')
assert(exercise.problem, 'exercise %s needs problem', exercise.name)
assert(exercise.solution, 'exercise %s needs solution', exercise.name)
assert(exercise.boilerplate, 'exercise %s needs boilerplate', exercise.name)
assert(exercise.verify, 'exercise %s needs verify', exercise.name)
})
exercises.forEach(function(exercise) {
shop.add(exercise.name, function() {
setTimeout(function() {
setup(exercises)
}, 10)
return exercise;
})
})
return shop
}
function setup(exercises) {
var boilerPlateRequired = exercises.filter(function(exercise) {
return exercise.boilerplate
}).filter(function(exercise) {
return !fs.existsSync(process.cwd() + '/' + exercise.cleanName)
}).map(function(exercise) {
return {
boilerplate: exercise.boilerplate,
problem: exercise.problemRaw,
dir: process.cwd() + '/' + exercise.cleanName
}
})
if (boilerPlateRequired.length) {
console.log('\n' + process.cwd() + '\n')
inquirer.prompt([{
'type': 'confirm',
'name': 'ok',
'default': true,
'message': wordwrap(4, 80)(
"We're about to populate the above directory with some files needed for the exercises. " +
"If they've already been created then don't worry, " +
"they won't be replaced. Continue?"
).replace(/^\s+/, '')
}], function(result) {
if (!result.ok) return
boilerPlateRequired.forEach(function(item) {
try {
fs.mkdirSync(item.dir)
} catch(e) {
// probably already exists
}
fs.writeFileSync(item.dir + '/Readme.md', item.problem)
fs.writeFileSync(item.dir + '/index.js', item.boilerplate)
})
})
}
}
function formatProblem(md) {
var out = '\n' + msee.parse(md, {
paragraphStart: '',
paragraphEnd: '\n\n'
}).trimRight()
return out
}
function formatSolution(solution) {
return msee.parse([
'Here\'s the official solution so you can compare notes:',
'```js',
solution,
'```'
].join('\n'))
}
function clean(name) {
return name.trim()
.toLowerCase()
.replace(/[^\w]+/gm, '-')
.replace('/','-')
}