1 | 'use strict'
|
2 |
|
3 | const fs = require('fs')
|
4 | const path = require('path')
|
5 | const async = require('async')
|
6 | const stream = require('stream')
|
7 | const Showdown = require('showdown')
|
8 |
|
9 | class Recommendation {
|
10 | constructor (settings) {
|
11 | Object.assign(this, settings)
|
12 | }
|
13 |
|
14 |
|
15 | [Symbol.iterator] () {
|
16 | const files = []
|
17 |
|
18 | files.push({
|
19 | type: 'summary',
|
20 | filepath: this.summary
|
21 | })
|
22 |
|
23 | if (this.readMore) {
|
24 | files.push({
|
25 | type: 'read-more',
|
26 | filepath: this.readMore
|
27 | })
|
28 | }
|
29 |
|
30 | return files[Symbol.iterator]()
|
31 | }
|
32 | }
|
33 |
|
34 |
|
35 | const recommendations = [
|
36 | new Recommendation({
|
37 | category: 'gc',
|
38 | issue: true,
|
39 | title: 'a potential Garbage Collection issue',
|
40 | menu: 'Garbage Collection',
|
41 | order: 1,
|
42 | summary: path.resolve(__dirname, 'gc-summary.md'),
|
43 | readMore: path.resolve(__dirname, 'gc-readmore.md')
|
44 | }),
|
45 | new Recommendation({
|
46 | category: 'event-loop',
|
47 | issue: true,
|
48 | title: 'a potential Event Loop issue',
|
49 | menu: 'Event Loop',
|
50 | order: 2,
|
51 | summary: path.resolve(__dirname, 'event-loop-summary.md'),
|
52 | readMore: path.resolve(__dirname, 'event-loop-readmore.md')
|
53 | }),
|
54 | new Recommendation({
|
55 | category: 'io',
|
56 | issue: true,
|
57 | title: 'a potential I/O issue',
|
58 | menu: 'I/O',
|
59 | order: 3,
|
60 | summary: path.resolve(__dirname, 'io-summary.md'),
|
61 | readMore: path.resolve(__dirname, 'io-readmore.md')
|
62 | }),
|
63 | new Recommendation({
|
64 | category: 'data',
|
65 | issue: true,
|
66 | title: 'data analysis issue',
|
67 | menu: 'Bad data',
|
68 | order: 4,
|
69 | summary: path.resolve(__dirname, 'data-summary.md'),
|
70 | readMore: null
|
71 | }),
|
72 | new Recommendation({
|
73 | category: 'unknown',
|
74 | issue: true,
|
75 | title: 'an unknown issue',
|
76 | menu: 'Unknown issue',
|
77 | order: 5,
|
78 | summary: path.resolve(__dirname, 'unknown-summary.md'),
|
79 | readMore: path.resolve(__dirname, 'unknown-readmore.md')
|
80 | }),
|
81 | new Recommendation({
|
82 | category: 'none',
|
83 | issue: false,
|
84 | title: 'no issue',
|
85 | menu: 'No issue',
|
86 | order: 6,
|
87 | summary: path.resolve(__dirname, 'none-summary.md'),
|
88 | readMore: null
|
89 | })
|
90 | ]
|
91 |
|
92 | const md = new Showdown.Converter({
|
93 | noHeaderId: true,
|
94 | simplifiedAutoLink: true,
|
95 | excludeTrailingPunctuationFromURLs: true,
|
96 | strikethrough: true,
|
97 | tables: true,
|
98 | ghCodeBlocks: true,
|
99 | simpleLineBreaks: false
|
100 | })
|
101 |
|
102 | class RenderRecommendations extends stream.Readable {
|
103 | constructor (options) {
|
104 | super(options)
|
105 |
|
106 |
|
107 | this._readingQueue = recommendations[Symbol.iterator]()
|
108 | }
|
109 |
|
110 | _read (size) {
|
111 | const self = this
|
112 | const read = this._readingQueue.next()
|
113 | if (read.done) return this.push(null)
|
114 |
|
115 |
|
116 | const recommendation = read.value
|
117 | async.map(
|
118 | recommendation,
|
119 | function (file, done) {
|
120 | fs.readFile(file.filepath, 'utf-8', function (err, content) {
|
121 | if (err) return done(err)
|
122 | const template =
|
123 | '<template class="recommendation-text"' +
|
124 | ` data-issue="${recommendation.issue ? 'yes' : 'no'}"` +
|
125 | ` data-type="${file.type}"` +
|
126 | ` data-category="${recommendation.category}"` +
|
127 | ` data-menu="${recommendation.menu}"` +
|
128 | ` data-title="${recommendation.title}"` +
|
129 | ` data-order="${recommendation.order}"` +
|
130 | '>\n' +
|
131 | `${md.makeHtml(content)}\n` +
|
132 | '</template>'
|
133 |
|
134 | done(null, template)
|
135 | })
|
136 | },
|
137 | function (err, result) {
|
138 | if (err) return self.emit('error', err)
|
139 |
|
140 |
|
141 | const output = result.join('\n') + '\n'
|
142 |
|
143 |
|
144 | self.push(output)
|
145 | }
|
146 | )
|
147 | }
|
148 | }
|
149 |
|
150 | module.exports = RenderRecommendations
|