ustyle 1.15.3 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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