Comparing version 0.4.1 to 1.0.0-rc.1
{ | ||
"name": "sassdoc", | ||
"description": "Like JSDoc but for Sass files.", | ||
"author": "Hugo Giraudel", | ||
"version": "0.4.1", | ||
"author": "Hugo Giraudel <hugo.giraudel@gmail.com> http://hugogiraudel.com", | ||
"contributors": ["Fabrice Weinberg", "Valérian Galliat"], | ||
"version": "1.0.0rc.1", | ||
"license": "MIT", | ||
@@ -28,3 +29,4 @@ "repository": { | ||
"swig-extras": "0.0.1", | ||
"ncp": "^0.5.1" | ||
"ncp": "^0.5.1", | ||
"scsscommentparser": "0.0.14" | ||
}, | ||
@@ -31,0 +33,0 @@ "bin": { |
115
README.md
@@ -5,2 +5,4 @@ # SassDoc | ||
Currently only work for `.scss` files. Also, inline comments are not parsed (`//`). | ||
## Example | ||
@@ -11,18 +13,20 @@ | ||
```scss | ||
// Adds `$value` at `$index` in `$list`. | ||
// | ||
// @author Hugo Giraudel | ||
// | ||
// @ignore Documentation: http://sassylists.com/documentation/#insert-nth | ||
// | ||
// @requires is-true | ||
// | ||
// @param {List} $list - list to update | ||
// @param {Number} $index - index to add | ||
// @param {*} $value - value to add | ||
// | ||
// @throws List index $index is not a number for `insert-nth`. | ||
// @throws List index $index must be a non-zero integer for `insert-nth`. | ||
// | ||
// @return {List | Bool} | ||
/** | ||
* Adds `$value` at `$index` in `$list`. | ||
* | ||
* @author Hugo Giraudel | ||
* | ||
* @ignore Documentation: http://sassylists.com/documentation/#insert-nth | ||
* | ||
* @requires is-true | ||
* | ||
* @param {List} $list - list to update | ||
* @param {Number} $index - index to add | ||
* @param {*} $value - value to add | ||
* | ||
* @throws List index $index is not a number for `insert-nth`. | ||
* @throws List index $index must be a non-zero integer for `insert-nth`. | ||
* | ||
* @return {List | Null} | ||
*/ | ||
@@ -37,8 +41,10 @@ @function insert-nth($list, $index, $value) { | ||
```scss | ||
// @var {Bool} - Defines whether the library should support legacy browsers (e.g. IE8). | ||
// | ||
// @since 0.3.8 | ||
// | ||
// @access private | ||
/** | ||
* Defines whether the lib should support legacy browsers (e.g. `IE 8`). | ||
* --- | ||
* @since 0.3.9 | ||
* @todo Nothing. It's awesome. | ||
* @link https://github.com/HugoGiraudel/SassDoc SassDoc | ||
* @datatype Bool | ||
*/ | ||
$legacy-support: true !global; | ||
@@ -53,2 +59,4 @@ ``` | ||
### NPM | ||
```sh | ||
@@ -58,2 +66,6 @@ npm install -g sassdoc | ||
### Grunt | ||
See [grunt-sassdoc](https://github.com/pascalduez/grunt-sassdoc). | ||
## Usage | ||
@@ -88,60 +100,2 @@ | ||
Yielding a result like this: | ||
```js | ||
{ | ||
'functions': [], | ||
'mixins': [], | ||
'variables': [] | ||
} | ||
``` | ||
Where a function/mixin is like this: | ||
```js | ||
{ | ||
'parameters': [ | ||
{ 'type': 'List', 'name': 'list', 'default': undefined, 'description': 'list to update' }, | ||
{ 'type': 'Number', 'name': 'index', 'default': undefined, 'description': 'index to add' }, | ||
{ 'type': '*', 'name': 'value', 'default': undefined, 'description': 'value to add' } | ||
], | ||
'throws': [ | ||
'List index $index is not a number for `insert-nth`.', | ||
'List index $index must be a non-zero integer for `insert-nth`.' | ||
], | ||
'alias': false, | ||
'aliased': [], | ||
'links': [], | ||
'todos': [], | ||
'requires': ['is-true'], | ||
'description': 'Adds `$value` at `$index` in `$list`.', | ||
'access': 'public', | ||
'deprecated': false, | ||
'author': "Hugo Giraudel", | ||
'returns': { | ||
'type': [ | ||
'List', | ||
'Bool' | ||
], | ||
'description': '' | ||
}, | ||
'type': 'function', | ||
'name': 'insert-nth' | ||
} | ||
``` | ||
And a variable like this: | ||
```js | ||
{ | ||
type: 'variable', | ||
datatype: ['Bool'], | ||
description: 'Defines whether the lib should support legacy browsers (e.g. `IE 8`).', | ||
name: 'support-legacy', | ||
value: 'true', | ||
access: 'private', | ||
since: '0.3.8' | ||
} | ||
``` | ||
## Documentation | ||
@@ -167,2 +121,3 @@ | ||
* [Valérian Galliat](https://twitter.com/valeriangalliat) | ||
* [Fabrice Weinberg](https://twitter.com/fweinb) | ||
* [Hugo Giraudel](http://twitter.com/HugoGiraudel) |
@@ -13,6 +13,7 @@ 'use strict'; | ||
* documentize('examples/sass', 'examples/dist') | ||
* @return {Q.promise} | ||
*/ | ||
documentize: function (source, destination, config) { | ||
fs.folder.refresh(destination) | ||
.then(function () { | ||
return fs.folder.refresh(destination) | ||
.then(function () { | ||
logger.log('Folder `' + destination + '` successfully generated.'); | ||
@@ -34,2 +35,4 @@ return fs.getData(source); | ||
console.error(err); | ||
throw new Error(err) | ||
return err; | ||
}); | ||
@@ -36,0 +39,0 @@ }, |
238
src/file.js
@@ -16,33 +16,5 @@ 'use strict'; | ||
extras.useFilter(swig, 'nl2br'); | ||
extras.useFilter(swig, 'split'); | ||
ncp.limit = 16; | ||
/** | ||
* Data holder | ||
* @constructs | ||
*/ | ||
function Data() { | ||
this.data = []; | ||
this.index = {}; | ||
} | ||
/** | ||
* Push a value into Data | ||
* @param {Object} value | ||
*/ | ||
Data.prototype.push = function (value) { | ||
this.data.push(value); | ||
this.index[value.name] = value; | ||
}; | ||
/** | ||
* Create a data object from an array | ||
* @param {Array} array | ||
* @return {Data} | ||
*/ | ||
Data.fromArray = function (array) { | ||
var data = new Data(); | ||
array.forEach(data.push.bind(data)); | ||
return data; | ||
}; | ||
exports = module.exports = { | ||
@@ -74,3 +46,3 @@ | ||
copy: Q.denodeify(ncp), | ||
/** | ||
@@ -82,3 +54,3 @@ * Remove a folder | ||
remove: Q.denodeify(rimraf), | ||
/** | ||
@@ -105,3 +77,3 @@ * Remove then create a folder | ||
return exports.folder.read(folder).then(function (files) { | ||
var path, | ||
var path, | ||
promises = [], | ||
@@ -123,3 +95,5 @@ data = []; | ||
promises.push(exports.file.process(path).then(function (response) { | ||
data = data.concat(response); | ||
if (Object.keys(response).length > 0) { | ||
data = data.concat(response); | ||
} | ||
})); | ||
@@ -139,3 +113,4 @@ } | ||
}, function (err) { | ||
console.error(err); | ||
throw new Error(err) | ||
return err; | ||
}); | ||
@@ -177,3 +152,3 @@ } | ||
return exports.file.read(file, 'utf-8').then(function (data) { | ||
return parser.parseFile(data); | ||
return parser.parse(data); | ||
}); | ||
@@ -211,3 +186,3 @@ } | ||
options.data = data; | ||
return exports.file.create(destination, template(options)); | ||
@@ -222,155 +197,72 @@ }, | ||
response = response || []; | ||
logger.log(response.length + ' item' + (response.length > 1 ? 's' : '') + ' documented.'); | ||
var result = {}; | ||
var index = {}; | ||
var data = Data.fromArray(response); | ||
response.forEach(function (obj) { | ||
Object.keys(obj).forEach(function (key) { | ||
if (typeof result[key] === 'undefined' ) { | ||
result[key] = []; | ||
} | ||
exports.postTreatData(data); | ||
obj[key].forEach(function (item) { | ||
index[item.context.name] = item; | ||
result[key].push(item); | ||
}); | ||
}); | ||
}); | ||
return exports.splitData(data.data.sort(function (a, b) { | ||
if (a.name > b.name) { | ||
return 1; | ||
} | ||
// Resovle alias and requires | ||
Object.keys(index).forEach(function (key) { | ||
var item = index[key]; | ||
if (a.name < b.name) { | ||
return -1; | ||
if (!utils.isset(item.access)) { | ||
item.access = ['public']; | ||
} | ||
return 0; | ||
})); | ||
}); | ||
}, | ||
splitData: function (data) { | ||
var _data = { | ||
'functions': [], | ||
'mixins': [], | ||
'variables': [] | ||
}; | ||
// Alias | ||
if (utils.isset(item.alias)) { | ||
item.alias.forEach(function (alias) { | ||
if (utils.isset(index[alias])) { | ||
if (!Array.isArray(index[alias].aliased)) { | ||
index[alias].aliased = []; | ||
} | ||
data.forEach(function (item) { | ||
_data[item.type + 's'].push(item); | ||
}); | ||
index[alias].aliased.push(item.context.name); | ||
} | ||
return _data; | ||
}, | ||
/** | ||
* Post treat data to fill missing informations | ||
* @param {Object} data | ||
*/ | ||
postTreatData: function (data) { | ||
exports.compileAliases(data); | ||
exports.compileRequires(data); | ||
exports.raiseWarnings(data); | ||
}, | ||
/** | ||
* Compile aliases for each item | ||
* @param {Object} data | ||
*/ | ||
compileAliases: function (data) { | ||
var item, name; | ||
for (name in data.index) { | ||
item = data.index[name]; | ||
if (!item.alias) { | ||
continue; | ||
} | ||
if (utils.isset(data.index[item.alias])) { | ||
data.index[name].access = data.index[item.alias].access; | ||
data.index[item.alias].aliased.push(item.name); | ||
} | ||
// Incorrect @alias | ||
else { | ||
logger.log('Item `' + name + ' is an alias of `' + item.alias + '` but this item doesn\'t exist.'); | ||
} | ||
} | ||
}, | ||
/** | ||
* Compile requires for each item | ||
* @param {Object} data | ||
*/ | ||
compileRequires: function (data) { | ||
var item, name; | ||
for (name in data.index) { | ||
item = data.index[name]; | ||
if (!utils.isset(item.requires)) { | ||
continue; | ||
} | ||
for (var i = 0; i < item.requires.length; i++) { | ||
if (utils.isset(item.requires[i].type)) { | ||
continue; | ||
else { | ||
logger.log('Item `' + item.context.name + ' is an alias of `' + alias + '` but this item doesn\'t exist.'); | ||
} | ||
}); | ||
} | ||
if (utils.isset(data.index[item.requires[i].item])) { | ||
data.index[name].requires[i].type = data.index[item.requires[i].item].type; | ||
// Requires | ||
else if (utils.isset(item.requires)) { | ||
item.requires = item.requires.map(function (name) { | ||
if (utils.isset(index[name])) { | ||
var reqItem = index[name]; | ||
if (!Array.isArray(reqItem.usedBy)) { | ||
reqItem.usedBy = []; | ||
} | ||
// And fill `usedBy` key | ||
if (!utils.isset(data.index[item.requires[i].item].usedBy)) { | ||
data.index[item.requires[i].item].usedBy = []; | ||
} | ||
reqItem.usedBy.push({ | ||
item: item.context.name, | ||
type: item.context.type | ||
}); | ||
data.index[item.requires[i].item].usedBy.push({ 'item': item.name, 'type': item.type }); | ||
return reqItem.context; | ||
} | ||
}).filter(function (item) { | ||
return typeof item !== 'undefined'; | ||
}); | ||
} | ||
}); | ||
// Incorrect @requires | ||
else { | ||
logger.log('Item `' + name + ' requires `' + item.requires[i].item + '` but this item doesn\'t exist.'); | ||
} | ||
} | ||
} | ||
}, | ||
/** | ||
* Raise warning for incoherent or invalid things | ||
* @param {Object} data | ||
*/ | ||
raiseWarnings: function (data) { | ||
var name, item, i; | ||
var validTypes = ['*', 'arglist', 'bool', 'color', 'list', 'map', 'null', 'number', 'string']; | ||
if (logger.enabled === false) { | ||
return; | ||
} | ||
for (name in data.index) { | ||
item = data.index[name]; | ||
// Incorrect data type in @param | ||
if (utils.isset(item.parameters)) { | ||
for (i = 0; i < item.parameters.length; i++) { | ||
if (validTypes.indexOf(item.parameters[i].type.toLowerCase()) === -1) { | ||
logger.log('Parameter `' + item.parameters[i].name + '` from item `' + item.name + '` is from type `' + item.parameters[i].type + '` which is not a valid Sass type.'); | ||
} | ||
} | ||
} | ||
// Incorrect data type in @return | ||
if (utils.isset(item.returns) && item.returns.type) { | ||
for (i = 0; i < item.returns.type.length; i++) { | ||
if (validTypes.indexOf(item.returns.type[i].trim().toLowerCase()) === -1) { | ||
logger.log('Item `' + item.name + '` can return a `' + item.returns.type[i] + '` which is not a valid Sass type.'); | ||
} | ||
} | ||
} | ||
// Incorrect URL in @link | ||
if (utils.isset(item.links)) { | ||
for (i = 0; i < item.links.length; i++) { | ||
if (!item.links[i].url.match(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/)) { | ||
logger.log('Item `' + item.name + '` has a link leading to an invalid URL (`' + item.links[i].url + '`).'); | ||
} | ||
} | ||
} | ||
} | ||
return result; | ||
}); | ||
} | ||
}; |
'use strict'; | ||
var regex = require('./regex'); | ||
var utils = require('./utils'); | ||
var ScssCommentParser = require('scsscommentparser'); | ||
var annotations = require('./annotation'); | ||
exports = module.exports = { | ||
/** | ||
* Define a block of comments | ||
* @param {Number} index - index of line where function/mixin starts | ||
* @param {Array} array - file as an array of lines | ||
* @return {Array} array of lines | ||
*/ | ||
findCommentBlock: function (index, array) { | ||
var previousLine = index - 1, | ||
comments = []; | ||
// Loop back | ||
while (previousLine >= 0) { | ||
// If it's an empty line, break (unless it hasn't started yet) | ||
if (regex.isEmpty(array[previousLine]) !== null) { | ||
if (comments.length > 0) { | ||
break; | ||
} | ||
} | ||
// If it's not a comment, break | ||
else if (!regex.isComment(array[previousLine])) { | ||
break; | ||
} | ||
else { | ||
// Push the new comment line | ||
comments.unshift(array[previousLine]); | ||
} | ||
previousLine--; | ||
} | ||
return comments; | ||
}, | ||
/** | ||
* Parse a block of comments | ||
* @param {Array} comments - array of lines | ||
* @return {Object} function/mixin documentation | ||
*/ | ||
parseCommentBlock: function (comments) { | ||
var _line, doc = { | ||
'parameters': [], | ||
'throws': [], | ||
'todos': [], | ||
'alias': false, | ||
'aliased': [], | ||
'links': [], | ||
'requires': [], | ||
'description': '', | ||
'since': false, | ||
'access': 'public', | ||
'deprecated': false, | ||
'author': false, | ||
'returns': { | ||
'type': null, | ||
'description': false | ||
} | ||
}; | ||
comments.forEach(function (line) { | ||
_line = exports.parseLine(utils.uncomment(line)); | ||
// Separator or @ignore | ||
if (!_line) { | ||
return false; | ||
} | ||
// Array things (@throws, @parameters...) | ||
if (_line.array === true) { | ||
doc[_line.type].push(_line.value); | ||
} | ||
else if (_line.type === 'description') { | ||
if (doc.description.length === 0) { | ||
doc.description = _line.value; | ||
} | ||
else { | ||
doc.description += _line.value; | ||
} | ||
doc.description += '\n'; | ||
} | ||
// Anything else | ||
else { | ||
doc[_line.type] = _line.value; | ||
} | ||
}); | ||
return doc; | ||
}, | ||
/** | ||
* Parse a block of comments | ||
* @param {Array} comments - array of lines | ||
* @return {Object} function/mixin documentation | ||
*/ | ||
parseVariableBlock: function (comments) { | ||
var tmp, _line, doc = { | ||
'description': '', | ||
'datatype': '', | ||
'since': false, | ||
'deprecated': false, | ||
'links': [], | ||
'todos': [] | ||
}; | ||
comments.forEach(function (line) { | ||
_line = utils.uncomment(line); | ||
tmp = regex.isVar(_line); | ||
if (tmp) { | ||
doc.datatype = tmp[1]; | ||
doc.description = tmp[2]; | ||
} | ||
tmp = regex.isAccess(_line); | ||
if (tmp) { | ||
doc.access = tmp[1]; | ||
} | ||
tmp = regex.isSince(_line); | ||
if (tmp) { | ||
doc.since = tmp[1]; | ||
} | ||
tmp = regex.isDeprecated(_line); | ||
if (tmp) { | ||
doc.deprecated = tmp[1] || true; | ||
} | ||
tmp = regex.isTodo(_line); | ||
if (tmp) { | ||
doc.todos.push(tmp[1]); | ||
} | ||
tmp = regex.isLink(_line); | ||
if (tmp) { | ||
doc.links.push({ 'url': tmp[1], 'caption': tmp[2] }); | ||
} | ||
}); | ||
return doc; | ||
}, | ||
/** | ||
* Parse a file | ||
* @param {String} content - file content | ||
* @return {Array} array of documented functions/mixins | ||
*/ | ||
parseFile: function (content) { | ||
var array = content.split('\n'), | ||
tree = [], item; | ||
// Looping through the file | ||
array.forEach(function (line, index) { | ||
var isCallable = regex.isFunctionOrMixin(line); | ||
// If it's either a mixin or a function | ||
if (isCallable) { | ||
item = exports.parseCommentBlock(exports.findCommentBlock(index, array)); | ||
item.type = isCallable[1]; | ||
item.name = isCallable[2]; | ||
tree.push(item); | ||
} | ||
var isVariable = regex.isVariable(line); | ||
if (isVariable) { | ||
item = exports.parseVariableBlock(exports.findCommentBlock(index, array)); | ||
item.type = 'variable'; | ||
item.name = isVariable[1]; | ||
item.value = isVariable[2]; | ||
if (typeof item.access === 'undefined') { | ||
item.access = isVariable[3] === '!global' ? 'public' : 'private'; | ||
} | ||
tree.push(item); | ||
} | ||
}); | ||
return tree; | ||
}, | ||
/** | ||
* Parse a line to determine what it is | ||
* @param {String} line - line to be parsed | ||
* @return {Object|false} | ||
*/ | ||
parseLine: function (line) { | ||
var type, value, i, | ||
res = { array: false }, | ||
tokens = ['returns', 'parameters', 'deprecated', 'author', 'access', 'throws', 'todo', 'alias', 'link', 'requires', 'since']; | ||
// Useless line, skip | ||
if (line.length === 0 || regex.isSeparator(line) || regex.isIgnore(line)) { | ||
return false; | ||
} | ||
for (i = 0; i < tokens.length; i++) { | ||
value = regex['is' + tokens[i].capitalize()](line); | ||
if (value !== null) { | ||
type = tokens[i]; | ||
break; | ||
} | ||
} | ||
res.type = type; | ||
switch (type) { | ||
case 'returns': | ||
res.value = { 'type': value[1].split('|'), 'description': value[2] }; | ||
break; | ||
case 'parameters': | ||
res.value = { 'type': value[1], 'name': value[2], 'default': value[3], 'description': value[4] }; | ||
res.array = true; | ||
break; | ||
case 'deprecated': | ||
res.value = value[1] || true; | ||
break; | ||
case 'author': | ||
case 'access': | ||
case 'alias': | ||
case 'since': | ||
res.value = value[1]; | ||
break; | ||
case 'throws': | ||
case 'todos': | ||
res.value = value[1]; | ||
res.array = true; | ||
break; | ||
case 'requires': | ||
res.value = { 'type': value[1], 'item': value[2] }; | ||
res.array = true; | ||
break; | ||
case 'link': | ||
res.value = { 'url': value[1], 'caption': value[2] }; | ||
break; | ||
case 'description': | ||
res.value = line; | ||
res.type = 'description'; | ||
break; | ||
default: | ||
res.value = line; | ||
res.type = 'description'; | ||
} | ||
return res; | ||
} | ||
}; | ||
module.exports = new ScssCommentParser(annotations); |
{ | ||
"title": "SassDoc", | ||
"display": { | ||
"alias": true, | ||
"private": false | ||
} | ||
"display_access": ["public", "private"], | ||
"display_alias": false | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
75
128794
7
1005
116
3
1
+ Addedscsscommentparser@0.0.14
+ Addedcdocparser@0.0.8(transitive)
+ Addedscsscommentparser@0.0.14(transitive)