ustyle 1.15.3 → 1.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.nvmrc +1 -1
- data/Gruntfile.js +104 -82
- data/README.md +45 -21
- data/dist/ustyle-content.css +1 -1
- data/dist/ustyle-latest.css +1 -1
- data/dist/ustyle.js +148 -97
- data/dist/ustyle.json +1 -1
- data/dist/ustyle.min.js +1 -1
- data/grunt/modules/dss-helper.js +103 -105
- data/grunt/modules/file.js +11 -13
- data/grunt/modules/html-parser.js +12 -14
- data/grunt/modules/templates.js +38 -40
- data/grunt/tasks/browser-sync.js +20 -16
- data/grunt/tasks/builder.js +43 -48
- data/grunt/tasks/styleguide.js +187 -182
- data/index.js +31 -0
- data/lib/ustyle/version.rb +1 -1
- data/package-lock.json +9261 -0
- data/package.json +20 -22
- data/styleguide/assets/javascripts/app.js +83 -56
- data/styleguide/assets/javascripts/modules/stats.js +23 -24
- data/styleguide/assets/javascripts/vendor/highlight.js +1 -1
- data/styleguide/assets/javascripts/vendor/svg4everybody.js +1 -1
- data/styleguide/partials/_footer.tpl +1 -1
- data/styleguide/partials/_sidebar.tpl +1 -1
- data/vendor/assets/javascripts/ustyle/tabs.js +153 -102
- data/vendor/assets/stylesheets/ustyle/mixins/_media-query.scss +0 -2
- metadata +4 -5
- data/JAVASCRIPT_STANDARDS.md +0 -88
- data/config/.jscsrc +0 -76
- data/styleguide/assets/javascripts/modules/cleanWhiteSpace.js +0 -34
data/grunt/tasks/styleguide.js
CHANGED
@@ -1,49 +1,44 @@
|
|
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
|
-
templatePath = path.join(styleguidePath, "templates"),
|
31
|
-
cssStatsFile = this.data.statsFor,
|
32
|
-
tagStartVersion = this.data.tagStartVersion,
|
33
|
-
tagPlaceholder = this.data.tagPlaceholder,
|
34
|
-
styleguide = [];
|
1
|
+
const dss = require('dss')
|
2
|
+
const _ = require('lodash')
|
3
|
+
const async = require('async')
|
4
|
+
const path = require('path')
|
5
|
+
const fs = require('fs')
|
6
|
+
const dssHelper = require('../modules/dss-helper')
|
7
|
+
const fileHelper = require('../modules/file')
|
8
|
+
const parser = require('../modules/html-parser')
|
9
|
+
const humanize = require('underscore.string/humanize')
|
10
|
+
const underscored = require('underscore.string/underscored')
|
11
|
+
const slugify = require('underscore.string/slugify')
|
12
|
+
const matter = require('gray-matter')
|
13
|
+
const StyleStats = require('stylestats')
|
14
|
+
const marked = require('marked')
|
15
|
+
const semver = require('semver')
|
16
|
+
const exec = require('child_process').exec
|
17
|
+
const simpleGit = require('simple-git')(path.resolve('.'))
|
18
|
+
|
19
|
+
module.exports = function (grunt) {
|
20
|
+
grunt.registerMultiTask('styleguide', 'Parse DSS comment blocks', function () {
|
21
|
+
var promise = this.async()
|
22
|
+
var files = this.files
|
23
|
+
var outputFilePath = this.data.output
|
24
|
+
var styleguidePath = this.data.dir
|
25
|
+
var contentPath = path.join(styleguidePath, 'content')
|
26
|
+
var templatePath = path.join(styleguidePath, 'templates')
|
27
|
+
var cssStatsFile = this.data.statsFor
|
28
|
+
var tagStartVersion = this.data.tagStartVersion
|
29
|
+
var tagPlaceholder = this.data.tagPlaceholder
|
35
30
|
|
36
31
|
var options = this.options({
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
})
|
32
|
+
template: 'styleguide.tpl',
|
33
|
+
contentTemplate: 'simple.tpl',
|
34
|
+
parsers: {
|
35
|
+
variable: dssHelper.variableDssParser(),
|
36
|
+
partial: function (i, line, block) { return line },
|
37
|
+
page: function (i, line, block) { return line },
|
38
|
+
description: dssHelper.descriptionDssParser,
|
39
|
+
javascript: dssHelper.javascriptParser
|
40
|
+
}
|
41
|
+
})
|
47
42
|
|
48
43
|
async.waterfall([
|
49
44
|
init,
|
@@ -53,242 +48,252 @@ module.exports = function(grunt){
|
|
53
48
|
generateStyleguide,
|
54
49
|
generateStats,
|
55
50
|
writeFile
|
56
|
-
], completeTask)
|
51
|
+
], completeTask)
|
57
52
|
|
58
|
-
function completeTask(){
|
59
|
-
promise()
|
53
|
+
function completeTask () {
|
54
|
+
promise()
|
60
55
|
}
|
61
56
|
|
62
|
-
function init(callback){
|
63
|
-
dssHelper.addParsers(options.parsers)
|
64
|
-
callback(null)
|
57
|
+
function init (callback) {
|
58
|
+
dssHelper.addParsers(options.parsers)
|
59
|
+
callback(null)
|
65
60
|
}
|
66
61
|
|
67
|
-
function parseDSS(callback){
|
68
|
-
var styleguide = []
|
69
|
-
var srcFiles = files[0].src
|
70
|
-
|
71
|
-
srcFiles.forEach(function(file){
|
72
|
-
dss.parse(grunt.file.read(file), { file: file }, function(parsed) {
|
62
|
+
function parseDSS (callback) {
|
63
|
+
var styleguide = []
|
64
|
+
var srcFiles = files[0].src
|
73
65
|
|
66
|
+
srcFiles.forEach(function (file) {
|
67
|
+
dss.parse(grunt.file.read(file), { file: file }, function (parsed) {
|
74
68
|
// Continue only if file contains DSS annotation
|
75
69
|
if (parsed.blocks.length) {
|
76
70
|
// Add comment block to styleguide
|
77
|
-
parsed.blocks.map(function(block){
|
78
|
-
|
79
|
-
block['
|
80
|
-
block['file'] = path.basename(file);
|
71
|
+
parsed.blocks.map(function (block) {
|
72
|
+
block['path'] = file
|
73
|
+
block['file'] = path.basename(file)
|
81
74
|
block['link'] = underscored(slugify(block['name']));
|
82
75
|
|
83
76
|
// Normalize @state and @variable to array
|
84
|
-
['state', 'variable'].forEach(function(prop) {
|
77
|
+
['state', 'variable'].forEach(function (prop) {
|
85
78
|
if (block.hasOwnProperty(prop) && typeof block[prop].slice !== 'function') {
|
86
|
-
block[prop] = [block[prop]]
|
79
|
+
block[prop] = [block[prop]]
|
87
80
|
}
|
88
|
-
})
|
81
|
+
})
|
89
82
|
|
90
|
-
if(block.markup){
|
91
|
-
block.markup.escaped = dssHelper.removeModifiersFromMarkup(block.markup.escaped)
|
83
|
+
if (block.markup) {
|
84
|
+
block.markup.escaped = dssHelper.removeModifiersFromMarkup(block.markup.escaped)
|
92
85
|
}
|
93
86
|
|
94
|
-
if(block.hasOwnProperty('state')){
|
95
|
-
block.state.map(function(state){
|
87
|
+
if (block.hasOwnProperty('state')) {
|
88
|
+
block.state.map(function (state) {
|
96
89
|
state.markup = {
|
97
90
|
example: dssHelper.addStateToExample(block.markup.example, state.escaped)
|
98
91
|
}
|
99
92
|
})
|
100
93
|
}
|
101
|
-
})
|
102
|
-
styleguide.push(parsed.blocks)
|
94
|
+
})
|
95
|
+
styleguide.push(parsed.blocks)
|
103
96
|
}
|
104
|
-
})
|
105
|
-
})
|
106
|
-
callback(null, styleguide)
|
97
|
+
})
|
98
|
+
})
|
99
|
+
callback(null, styleguide)
|
107
100
|
}
|
108
101
|
|
109
|
-
function groupDSS(styleguide, callback){
|
102
|
+
function groupDSS (styleguide, callback) {
|
110
103
|
var sections = _.chain(styleguide).flatten().groupBy('page')
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
.filter(function(object) { return object.section != "undefined" }).compact().value();
|
127
|
-
callback(null, sections);
|
128
|
-
}
|
104
|
+
.map(function (value, key) {
|
105
|
+
const structure = key.split('/')
|
106
|
+
const section = slugify(structure[0])
|
107
|
+
const page = structure[1]
|
108
|
+
|
109
|
+
return {
|
110
|
+
name: page,
|
111
|
+
page: slugify(page) + '.html',
|
112
|
+
template: _getTemplate(options.template),
|
113
|
+
section: slugify(section),
|
114
|
+
blocks: value
|
115
|
+
}
|
116
|
+
})
|
117
|
+
// As it's iterating over files, we don't want files that aren't documented to come through
|
118
|
+
.filter(function (object) { return object.section !== 'undefined' }).compact().value()
|
129
119
|
|
130
|
-
|
120
|
+
callback(null, sections)
|
121
|
+
}
|
131
122
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
123
|
+
function generateStaticContent (sections, callback) {
|
124
|
+
var pages = grunt.file.expand(contentPath + '/**/*')
|
125
|
+
.filter(function (dir) {
|
126
|
+
var stats = fs.lstatSync(dir)
|
127
|
+
return !stats.isDirectory()
|
136
128
|
})
|
137
|
-
.map(function(file){
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
129
|
+
.map(function (file) {
|
130
|
+
const data = matter.read(file)
|
131
|
+
const html = parser.removeSubNav(data.content)
|
132
|
+
const extension = path.extname(file)
|
133
|
+
const subNavData = parser.extractSubNav(data.content)
|
134
|
+
const section = path.dirname(file).replace((new RegExp(contentPath + '/?', 'g')), '')
|
135
|
+
const filename = path.basename(file, extension)
|
144
136
|
|
145
137
|
return {
|
146
138
|
name: data.data.name || humanize(filename),
|
147
139
|
page: filename + '.html',
|
148
140
|
template: _getTemplate(data.data.template || options.contentTemplate),
|
149
|
-
section
|
141
|
+
section,
|
150
142
|
content: (fileHelper.isMarkdown(extension) ? marked(html) : html),
|
151
143
|
subNav: subNavData
|
152
144
|
}
|
153
|
-
})
|
145
|
+
})
|
154
146
|
|
155
|
-
var data = _sortyByIndex(pages).concat(sections)
|
147
|
+
var data = _sortyByIndex(pages).concat(sections)
|
156
148
|
|
157
|
-
callback(null, _sortyByIndex(data))
|
149
|
+
callback(null, _sortyByIndex(data))
|
158
150
|
}
|
159
151
|
|
160
|
-
function generateStyleguide(sections, callback){
|
152
|
+
function generateStyleguide (sections, callback) {
|
161
153
|
var model = {
|
162
154
|
pages: sections,
|
163
155
|
navigation: _getSection(sections),
|
164
156
|
project: grunt.file.readJSON('package.json')
|
165
157
|
}
|
166
158
|
|
167
|
-
callback(null, model)
|
159
|
+
callback(null, model)
|
168
160
|
}
|
169
161
|
|
170
|
-
function generateStats(model, callback) {
|
171
|
-
var
|
172
|
-
|
162
|
+
function generateStats (model, callback) {
|
163
|
+
var cssParser
|
164
|
+
var omitEntries
|
165
|
+
var statsPage
|
166
|
+
var cachedStatsFile
|
173
167
|
|
174
|
-
cachedStatsFile = 'tmp/.stats-cache'
|
168
|
+
cachedStatsFile = 'tmp/.stats-cache'
|
175
169
|
|
176
170
|
statsPage = {
|
177
171
|
name: 'Stats',
|
178
172
|
page: 'stats.html',
|
179
173
|
section: 'pattern-library',
|
180
174
|
content: {report: []},
|
181
|
-
template: 'styleguide/templates/stats.tpl'
|
182
|
-
}
|
175
|
+
template: 'styleguide/templates/stats.tpl'
|
176
|
+
}
|
183
177
|
|
184
|
-
//Get the latest tag, if the tag is different from the cached one
|
185
|
-
//fetch new data.
|
178
|
+
// Get the latest tag, if the tag is different from the cached one
|
179
|
+
// fetch new data.
|
186
180
|
exec('git describe --tags `git rev-list --tags --max-count=1`',
|
187
|
-
function(error, stdout, sterr) {
|
188
|
-
|
189
|
-
|
181
|
+
function (error, stdout, sterr) {
|
182
|
+
if (error) {
|
183
|
+
console.log(error)
|
184
|
+
}
|
185
|
+
|
186
|
+
var latestTag = semver.clean(stdout)
|
187
|
+
var data
|
190
188
|
|
191
189
|
try {
|
192
|
-
data = grunt.file.readJSON(cachedStatsFile)
|
193
|
-
var latestVersion = data[0].version
|
194
|
-
if(data[0] && data[0].version && semver.eq(latestVersion, latestTag)) {
|
195
|
-
statsPage.content.report = data
|
196
|
-
next()
|
197
|
-
}else {
|
198
|
-
fetchNewStatsData()
|
190
|
+
data = grunt.file.readJSON(cachedStatsFile)
|
191
|
+
var latestVersion = data[0].version
|
192
|
+
if (data[0] && data[0].version && semver.eq(latestVersion, latestTag)) {
|
193
|
+
statsPage.content.report = data
|
194
|
+
next()
|
195
|
+
} else {
|
196
|
+
fetchNewStatsData()
|
199
197
|
}
|
200
|
-
}
|
201
|
-
catch(err) {
|
198
|
+
} catch (err) {
|
202
199
|
// File does't exist or wrong format.
|
203
200
|
fetchNewStatsData()
|
204
201
|
}
|
205
202
|
}
|
206
|
-
)
|
203
|
+
)
|
207
204
|
|
208
|
-
function fetchNewStatsData() {
|
205
|
+
function fetchNewStatsData () {
|
209
206
|
async.waterfall([
|
210
207
|
getTags,
|
211
208
|
getStylesListing,
|
212
|
-
getStats
|
213
|
-
], next)
|
209
|
+
getStats
|
210
|
+
], next)
|
214
211
|
}
|
215
212
|
|
216
|
-
function getTags(callback) {
|
217
|
-
simpleGit.tags(function(err, tags) {
|
218
|
-
|
219
|
-
|
213
|
+
function getTags (callback) {
|
214
|
+
simpleGit.tags(function (err, tags) {
|
215
|
+
if (err) {
|
216
|
+
console.log(err)
|
217
|
+
}
|
218
|
+
|
219
|
+
callback(null, tags)
|
220
|
+
})
|
220
221
|
}
|
221
222
|
|
222
|
-
function getStylesListing(tags, callback) {
|
223
|
-
var styleListing = tags.all.map(function(tag){
|
224
|
-
var cleanTag = semver.clean(tag)
|
225
|
-
if(cleanTag!=null && semver.gt(cleanTag, tagStartVersion)) {
|
223
|
+
function getStylesListing (tags, callback) {
|
224
|
+
var styleListing = tags.all.map(function (tag) {
|
225
|
+
var cleanTag = semver.clean(tag)
|
226
|
+
if (cleanTag != null && semver.gt(cleanTag, tagStartVersion)) {
|
226
227
|
return {
|
227
|
-
|
228
|
-
|
229
|
-
|
228
|
+
version: cleanTag,
|
229
|
+
path: cssStatsFile.replace(tagPlaceholder, cleanTag)
|
230
|
+
}
|
230
231
|
}
|
231
|
-
})
|
232
|
-
callback(null, _.compact(styleListing))
|
232
|
+
})
|
233
|
+
callback(null, _.compact(styleListing))
|
233
234
|
}
|
234
235
|
|
235
|
-
function getStats(styleListing, callback) {
|
236
|
+
function getStats (styleListing, callback) {
|
236
237
|
omitEntries = [
|
237
|
-
'dataUriSize', 'ratioOfDataUriSize','lowestCohesion',
|
238
|
+
'dataUriSize', 'ratioOfDataUriSize', 'lowestCohesion',
|
238
239
|
'lowestCohesionSelector', 'uniqueFontSize', 'uniqueFontFamily',
|
239
240
|
'propertiesCount', 'published', 'paths', 'mostIdentifierSelector',
|
240
241
|
'totalUniqueFontSizes', 'mostIdentifier', 'totalUniqueFontFamilies',
|
241
242
|
'totalUniqueColors', 'unqualifiedAttributeSelectors', 'floatProperties',
|
242
243
|
'uniqueColor'
|
243
|
-
]
|
244
|
+
]
|
244
245
|
|
245
246
|
async.map(styleListing,
|
246
|
-
function(entry, cb){
|
247
|
-
cssParser = new StyleStats(entry.path, {})
|
248
|
-
cssParser.parse(function(err, styleStatsData){
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
247
|
+
function (entry, cb) {
|
248
|
+
cssParser = new StyleStats(entry.path, {})
|
249
|
+
cssParser.parse(function (err, styleStatsData) {
|
250
|
+
if (err) {
|
251
|
+
console.log(err)
|
252
|
+
}
|
253
|
+
|
254
|
+
var generalReport = _.omit(styleStatsData, omitEntries)
|
255
|
+
if (Object.keys(generalReport).length) {
|
256
|
+
generalReport.version = entry.version
|
257
|
+
statsPage.content.report.push(generalReport)
|
253
258
|
}
|
254
|
-
cb()
|
255
|
-
})
|
259
|
+
cb()
|
260
|
+
})
|
256
261
|
},
|
257
|
-
function(){
|
258
|
-
//Sort array
|
259
|
-
var sortedReport = statsPage.content.report.sort(function(a,b){
|
260
|
-
return semver.rcompare(a.version, b.version)
|
261
|
-
})
|
262
|
-
statsPage.content.report = sortedReport
|
263
|
-
fileHelper.writeFile(JSON.stringify(sortedReport), cachedStatsFile,
|
264
|
-
callback()
|
262
|
+
function () {
|
263
|
+
// Sort array
|
264
|
+
var sortedReport = statsPage.content.report.sort(function (a, b) {
|
265
|
+
return semver.rcompare(a.version, b.version)
|
266
|
+
})
|
267
|
+
statsPage.content.report = sortedReport
|
268
|
+
fileHelper.writeFile(JSON.stringify(sortedReport), cachedStatsFile, 'Cached stats')
|
269
|
+
callback()
|
265
270
|
}
|
266
|
-
)
|
271
|
+
)
|
267
272
|
}
|
268
273
|
|
269
|
-
function next(){
|
270
|
-
model.pages.push(statsPage)
|
271
|
-
callback(null, model)
|
274
|
+
function next () {
|
275
|
+
model.pages.push(statsPage)
|
276
|
+
callback(null, model)
|
272
277
|
}
|
273
278
|
}
|
274
279
|
|
275
|
-
function _getSection(sections){
|
276
|
-
return _.chain(sections).map(function(data){ return slugify(data.section) }).compact().uniq().value()
|
280
|
+
function _getSection (sections) {
|
281
|
+
return _.chain(sections).map(function (data) { return slugify(data.section) }).compact().uniq().value()
|
277
282
|
}
|
278
283
|
|
279
|
-
function _sortyByIndex(sections){
|
280
|
-
return sections.sort(function(a, b){
|
281
|
-
return (a.page
|
284
|
+
function _sortyByIndex (sections) {
|
285
|
+
return sections.sort(function (a, b) {
|
286
|
+
return (a.page === 'index.html' ? -1 : 1)
|
282
287
|
})
|
283
288
|
}
|
284
289
|
|
285
|
-
function _getTemplate(name){
|
286
|
-
return path.join(templatePath, name)
|
290
|
+
function _getTemplate (name) {
|
291
|
+
return path.join(templatePath, name)
|
287
292
|
}
|
288
293
|
|
289
|
-
function writeFile(model, callback){
|
290
|
-
fileHelper.writeFile(JSON.stringify(model), outputFilePath,
|
291
|
-
callback(null, 'done')
|
294
|
+
function writeFile (model, callback) {
|
295
|
+
fileHelper.writeFile(JSON.stringify(model), outputFilePath, 'Styleguide')
|
296
|
+
callback(null, 'done')
|
292
297
|
}
|
293
|
-
})
|
294
|
-
}
|
298
|
+
})
|
299
|
+
}
|
data/index.js
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
const types = require('node-sass').types
|
2
|
+
const path = require('path')
|
3
|
+
const fs = require('fs')
|
4
|
+
|
5
|
+
const base64encode = string => {
|
6
|
+
const stringBuffer = Buffer.from(string.getValue())
|
7
|
+
return types.String(stringBuffer.toString('base64'))
|
8
|
+
}
|
9
|
+
|
10
|
+
const inlineSVG = source => {
|
11
|
+
const sourcePath = path.join(__dirname, 'vendor', 'assets', 'images', source.getValue())
|
12
|
+
let svg = ''
|
13
|
+
|
14
|
+
try {
|
15
|
+
svg = fs.readFileSync(sourcePath).toString()
|
16
|
+
} catch (err) {
|
17
|
+
console.error('Error inlining SVG file', err)
|
18
|
+
}
|
19
|
+
|
20
|
+
const dataUrl = `url('data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}')`
|
21
|
+
return types.String(dataUrl)
|
22
|
+
}
|
23
|
+
|
24
|
+
const SassHelpers = {
|
25
|
+
'base64encode($string)': base64encode,
|
26
|
+
'inline-svg($source)': inlineSVG
|
27
|
+
}
|
28
|
+
|
29
|
+
module.exports = {
|
30
|
+
SassHelpers
|
31
|
+
}
|
data/lib/ustyle/version.rb
CHANGED