不要怂,就是干,撸起袖子干!

Commit 22f0f451 by Jan Aagaard Meier

Restructured docs generator

1 parent 576b9555
......@@ -16,7 +16,6 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
indent_size = 4
......@@ -90,3 +90,9 @@ coveralls: sqlite-cover mysql-cover postgres-cover postgres-native-cover mariadb
codeclimate: sqlite-cover mysql-cover postgres-cover postgres-native-cover mariadb-cover merge-coverage codeclimate-send
.PHONY: sqlite mysql postgres pgsql postgres-native postgresn all test
api-docs:
node docs/docs-generator.js
clean:
node docs/docs-generator.js --clean
"use strict";
var dox = require('dox')
, program = require('commander')
, fs = require('fs')
, path = require('path')
, git = require('git')
, _ = require('lodash');
program
.version('0.0.2')
.option('-f, --file [file]', 'Process a single file', '')
.option('-a, --all', 'Process all files, generate index etc. (default if no options are specified')
.option('-c, --clean', 'Remove all generated markdown and HTML files')
.option('-o --out [dir]', '', path.dirname(__filename))
.parse(process.argv);
if (program.clean) {
fs.readdirSync('docs/').forEach(function (file) {
if (file !== 'index.md' && path.extname(file) === '.md') {
fs.unlinkSync ('docs/' + file);
}
});
return;
}
var files;
if (program.file) {
files = [{file: program.file, output: 'tmp'}];
} else {
files = [
{file:'lib/errors.js', output: 'errors'},
{file:'lib/sequelize.js', output: 'sequelize'},
{file:'lib/instance.js', output: 'instance'},
{file:'lib/model.js', output: 'model'},
{file:'lib/hooks.js', output: 'hooks'},
{file:'lib/associations/mixin.js', output: 'associations'},
{file:'lib/promise.js', output: 'promise'},
{file:'lib/transaction.js', output: 'transaction'},
{file:'lib/data-types.js', output: 'datatypes'}
];
}
var Comment = function(data, file) {
this.data = data;
this.file = file;
this.string = '';
};
Comment.prototype.getTag = function(tagName) {
return _.find(this.data.tags, function (tag) {
return tag.type === tagName;
});
};
Comment.prototype.getTags = function(tagName) {
return _.where(this.data.tags, function (tag) {
return tag.type === tagName;
});
};
Comment.prototype.hasTag = function(tagName) {
return this.getTag(tagName) !== undefined;
};
Comment.prototype.getName = function () {
var tag;
tag = this.getTag('name');
if (tag) {
return tag.string;
}
tag = this.getTag('class');
if (tag) {
return tag.string;
}
tag = this.getTag('property');
if (tag) {
return tag.types[0];
}
tag = this.getTag('method');
if (tag) {
return tag.string;
}
return this.data.ctx.name;
};
Comment.prototype.getParams = function () {
if (this.isProperty()) {
return '';
}
// Only show params without a dot in them (dots means attributes of object, so no need to clutter the signature too much)
var params = [] ;
this.getTags('param').forEach(function (paramTag) {
if (paramTag.name.indexOf('.') === -1) {
params.push(paramTag.name);
}
});
return '(' + params.join(', ') + ')';
};
Comment.prototype.isProperty = function () {
return !this.hasTag('method') && this.data.ctx && this.data.ctx.type === 'property';
};
Comment.prototype.putString = function(str) {
this.string += str;
};
Comment.prototype.putLine = function(str) {
str = str || '';
this.putString(str + "\n");
};
Comment.prototype.putLines = function(lines) {
lines.forEach(function (line) {
this.putLine(line);
}, this);
};
Comment.prototype.toString = function () {
return this.string + "\n";
};
['class', 'mixin', 'constructor'].forEach(function (prop) {
Comment.prototype['is' + prop.charAt(0).toUpperCase() + prop.slice(1)] = function () {
return this.hasTag(prop);
};
});
Comment.prototype.githubLink = function() {
return 'https://github.com/sequelize/sequelize/blob/' + Comment.commit + '/' + this.file + '#L' + this.data.codeStart;
};
Comment.concatTypes = function (types, convertEntities) {
if (convertEntities === undefined) {
convertEntities = true;
}
var type = types.join('|');
if (type.indexOf('<') !== -1 && type.indexOf('>') === -1) {
// If the string is Array<something|somethingelse> the closing > disappears...
type += '>';
}
if (convertEntities) {
// Convert a couple of things to their HTML-entities
// The spacing around | is intentional, in order to introduce some linebreaks in the params table
type = type.replace('|', ' &#124; ')
.replace('>', '&gt;')
.replace('<', '&lt;');
}
return type;
};
var parseComments = function (comments, file) {
var output = ''
, comment
, name
, returns
, mixes
, deprecated
, see
, params
, extend
, aliases;
comments.forEach(function (data) {
if (data.tags.length) {
comment = new Comment(data, file);
name = comment.getName();
comment.putLine('<a name="' + name.toLowerCase() + '"></a>');
if (comment.isClass()) {
comment.putLine('# Class ' + name);
} else if (comment.isMixin()) {
comment.putLine('# Mixin ' + name);
} else if (comment.isConstructor()) {
comment.putLine('## `new ' + name + comment.getParams() + '`');
} else {
comment.putString('## `' + name + comment.getParams() + '`');
if (comment.hasTag('return')) {
returns = comment.getTag('return');
var returnType = Comment.concatTypes(returns.types, false); // We don't convert HTML entities since tihs is displayed in a literal block
comment.putString(' -> `' + returnType + '`');
}
comment.putLine();
}
comment.putLine('[View code](' + comment.githubLink() + ')');
comment.putLine(comment.data.description.full);
if ((mixes = comment.getTags('mixes')).length) {
comment.putLine('### Mixes:');
mixes.forEach(function (mixin) {
comment.putLine('* ' + mixin.string);
});
}
if (deprecated = comment.getTag('deprecated')) {
comment.putLine('**Deprecated** ' + deprecated.string);
}
if ((see = comment.getTags('see')).length) {
comment.putLine();
comment.putLine('**See:**');
comment.putLine();
var link;
see.forEach(function (see) {
if (see.local) {
link = see.local.match(/{(.*?(?:|#.*?))}/)[1];
comment.putLine('* [' + link + '](' + link.toLowerCase() + ')');
} else {
comment.putLine('* [' + see.title | see.url + '](' + see.url + ')');
}
});
comment.putLine();
}
if (comment.hasTag('param')) {
params = comment.getTags('param');
comment.putLines([
'',
'**Params:**',
'',
'| Name | Type | Description |',
'| ---- | ---- | ----------- |'
]);
var type;
params.forEach(function (param) {
type = Comment.concatTypes(param.types);
comment.putLine('| ' + param.name + ' | ' + type + ' | ' + param.description + ' |');
});
comment.putLine();
}
if (returns && returns.description) {
comment.putLine('__Returns:__ ' + returns.description);
}
if ((aliases = comment.getTags('alias')).length) {
comment.putLine('__Aliases:__ ' + aliases.map(function (a) {
return a.string;
}).join(', '));
}
if (extend = comment.getTag('extends')) {
comment.putLine();
comment.putLine('__Extends:__ ' + extend.otherClass);
}
comment.putLine();
comment.putLine('***');
output += comment.toString();
}
});
output += '_This document is automatically generated based on source code comments. Please do not edit it directly, as your changes will be ignored. Please write on <a href="irc://irc.freenode.net/#sequelizejs">IRC</a>, open an issue or a create a pull request if you feel something can be improved. For help on how to write source code documentation see [JSDoc](http://usejsdoc.org) and [dox](https://github.com/tj/dox)_';
return output;
};
var code, obj, output, path;
new git.Repo(path.dirname(__filename) + '/..', function (err, repo) {
repo.head(function (err, status) {
Comment.commit = status.commit;
files.forEach(function (file) {
fs.readFile(file.file, function (err, code) {
obj = dox.parseComments(code.toString(), { raw: true});
path = program.out + '/' + file.output + '.md';
console.log(path)
var output = parseComments(obj, file.file);
fs.writeFile(path, output);
});
});
});
});
"use strict";
var markdox = require('markdox')
, program = require('commander')
, fs = require('fs')
, _ = require('lodash');
program
.version('0.0.1')
.option('-f, --file [file]', 'Process a single file', '')
.option('-a, --all', 'Process all files, generate index etc. (default if no options are specified')
.option('-c, --clean', 'Remove all generated markdown and HTML files')
.option('--html', 'Generate html files from the markdown ones (requires manual installation of the github-flavored-markdown package')
.parse(process.argv);
if (program.clean) {
fs.readdirSync('docs/').forEach(function (file) {
if (file.indexOf('.ejs') === -1 && file.indexOf('.js') === -1) {
fs.unlinkSync ('docs/' + file);
}
});
return ;
}
if (program.html) {
var ghm = require('github-flavored-markdown');
}
var getTag = function(tags, tagName) {
return _.find(tags, function (tag) {
return tag.type === tagName;
});
};
var getTags = function(tags, tagName) {
return _.where(tags, function (tag) {
return tag.type === tagName;
});
};
var options = {
formatter: function (docfile) {
docfile = markdox.defaultFormatter(docfile);
docfile.members = [];
docfile.javadoc.forEach(function(javadoc){
javadoc.isConstructor = getTag(javadoc.raw.tags, 'constructor') !== undefined;
javadoc.isMixin = getTag(javadoc.raw.tags, 'mixin') !== undefined;
javadoc.isProperty = getTag(javadoc.raw.tags, 'property') !== undefined;
javadoc.private = getTag(javadoc.raw.tags, 'private') !== undefined;
javadoc.since = getTag(javadoc.raw.tags, 'since');
javadoc.extends = getTag(javadoc.raw.tags, 'extends');
// Find constructor tags
// Only show params without a dot in them (dots means attributes of object, so no need to clutter the signature too much)
var params = [] ;
javadoc.paramTags.forEach(function (paramTag) {
if (paramTag.name.indexOf('.') === -1) {
params.push(paramTag.name);
}
});
javadoc.paramStr = (javadoc.isMethod || javadoc.isFunction) ? '(' + params.join(', ') + ')' : '';
// Convert | to &#124; to be able to use github flavored md tables
if (javadoc.paramTags) {
javadoc.paramTags.forEach(function (paramTag) {
paramTag.joinedTypes = paramTag.joinedTypes.replace(/\|/g, '&#124;');
});
}
// Handle aliases
javadoc.aliases = getTags(javadoc.raw.tags, 'alias').map(function (a) {
return a.string;
}).join(', ');
// Handle deprecation text
if (javadoc.deprecated) {
var deprecation = getTag(javadoc.raw.tags, 'deprecated');
javadoc.deprecated = deprecation.string;
}
// Handle linking in comments
javadoc.see = getTags(javadoc.raw.tags, 'see');
javadoc.see.forEach(function (see, i, collection) {
collection[i] = {};
if (see.local) {
collection[i].external = false;
if (see.local.indexOf('{') === 0){
var _see = see.local.split('}');
_see[0] = _see[0].substring(1);
collection[i].url = 'API-Reference-' + _see[0];
collection[i].text = see.local.replace(/{|}/g, '');
} else {
collection[i].url = false;
collection[i].text = see.local;
}
} else {
see.external = true;
see.text = see.url;
collection[i] = see;
}
});
// Set a name for properties
if (!javadoc.name) {
var property = getTag(javadoc.raw.tags, 'property');
if (property) {
javadoc.name = property.types[0];
}
}
if (javadoc.isMixin) {
javadoc.name = getTag(javadoc.raw.tags, 'mixin').string;
}
javadoc.mixes = getTags(javadoc.raw.tags, 'mixes').map(function (mix) {
return {
text: mix.string,
link: (mix.string.indexOf('www') !== -1 || mix.string.indexOf('http') !== -1) ? mix.string: 'API-Reference-' + mix.string
};
});
if (!javadoc.isClass) {
if (!javadoc.isProperty) {
docfile.members.push({
text: javadoc.name + javadoc.paramStr,
link: '#' + javadoc.name
});
} else {
docfile.members.push({
text: javadoc.name,
link: '#' + javadoc.name
});
}
}
});
return docfile;
},
template: 'docs/output.md.ejs'
};
var files;
if (program.file) {
files = [{file: program.file, output: 'tmp'}];
} else {
files = [
{file:'lib/errors.js', output: 'API-Reference-Errors'},
{file:'lib/sequelize.js', output: 'API-Reference-Sequelize'},
{file:'lib/instance.js', output: 'API-Reference-Instance'},
{file:'lib/model.js', output: 'API-Reference-Model'},
{file:'lib/query-chainer.js', output: 'API-Reference-QueryChainer'},
{file:'lib/hooks.js', output: 'API-Reference-Hooks'},
{file:'lib/associations/mixin.js', output: 'API-Reference-Associations'},
{file:'lib/promise.js', output: 'API-Reference-Promise'},
{file:'lib/transaction.js', output: 'API-Reference-Transaction'},
{file:'lib/data-types.js', output: 'API-Reference-DataTypes'}
];
}
files.forEach(function (file) {
var opts = _.clone(options)
, output = 'docs/' + file.output + '.md';
opts.output = output;
markdox.process(file.file, opts, function(){
if (program.html) {
var md = fs.readFileSync(output).toString();
fs.writeFileSync(output.replace('md', 'html'), ghm.parse(md));
}
});
});
<? docfiles.forEach(function(doc) { ?>
<? doc.javadoc.forEach(function(comment) { ?>
<? if (comment.name && comment.private !== true) { -?>
<? if (!comment.ignore) { ?>
<a name="<?= comment.name ?>" />
<? if (comment.isConstructor) { ?>
### `new <?= comment.name ?><?= comment.paramStr ?>`
<? } else if (comment.isMixin) { ?>
### Mixin <?= comment.name ?>
<? } else if (comment.isClass) { ?>
### Class <?= comment.name ?>
<? } else { ?>
#### `<?= comment.name ?><?= comment.paramStr ?>` <? if (comment.returnTags.length > 0) { ?> -> `<?= comment.returnTags[0].joinedTypes ?>` <? } ?>
<? } ?>
<? } ?>
<?= comment.description ?>
<? if (comment.mixes.length) { ?>
### Mixes:
<? comment.mixes.forEach(function (mix) { -?>
* [<?=mix.text ?>](<?=mix.link ?>)
<? }) ?>
<? } ?>
<? if (comment.isClass) { ?>
### Members:
<? doc.members.forEach(function (member) { -?>
* [<?= member.text ?>](<?= member.link ?>)
<? }) -?>
<? } ?>
<? if (comment.deprecated) { ?>
**Deprecated** <?- comment.deprecated ?>
<? } ?>
<? if (comment.version) { ?>
Version: <?= comment.version ?>
<? } ?>
<? if (comment.see.length) { ?>See:<? } ?>
<? comment.see.forEach(function (see) { -?>
<? if (see.url !== false) { -?>
* [<?= see.text ?>](<?= see.url ?>)
<? } else { -?>
* <?= see.text ?>
<? } -?>
<? }) -?>
<? if (comment.paramTags.length > 0) { ?>
##### Params:
| Name | Type | Description |
| ---- | ---- | ----------- |
<? comment.paramTags.forEach(function(paramTag) { -?>
| <?= paramTag.name ?> | <?= paramTag.joinedTypes ?> | <?= paramTag.description ?> |
<? }) ?>
<? } ?>
<? if (comment.returnTags.length > 0 && comment.returnTags[0].description.length > 0) { ?>
__Returns:__ <?= comment.returnTags[0].description ?>
<? } ?>
<? if (comment.aliases) { ?>
__Aliases:__ *<?= comment.aliases ?>*
<? } ?>
<? if (comment.since) { ?>
__Since:__ *<?= comment.since.string ?>*
<? } ?>
<? if (comment.extends) { ?>
__Extends:__ *<?= comment.extends.otherClass ?>*
<? } ?>
======
<? } ?>
<? }) ?>
_This document is automatically generated based on source code comments. Please do not edit it directly, as your changes will be ignored. Please write on <a href="irc://irc.freenode.net/#sequelizejs">IRC</a>, open an issue or a create a pull request if you feel something can be improved. For help on how to write source code documentation see [JSDoc](http://usejsdoc.org) and [markdox](https://github.com/cbou/markdox)_
_This documentation was automagically created on <?= new Date().toString() ?>_
<? }) ?>
......@@ -131,6 +131,7 @@ var singleLinked = function (Type) {
*
* All methods return a promise
*
* @method hasOne
* @param {Model} target
* @param {object} [options]
* @param {boolean} [options.hooks=false] Set to true to run before-/afterDestroy hooks when an associated model is deleted because of a cascade. For example if `User.hasOne(Profile, {onDelete: 'cascade', hooks:true})`, the before-/afterDestroy hooks for profile will be called when a user is deleted. Otherwise the profile will be deleted without invoking any hooks
......@@ -155,6 +156,7 @@ Mixin.hasOne = singleLinked(HasOne);
*
* All methods return a promise
*
* @method belongsTo
* @param {Model} target
* @param {object} [options]
* @param {boolean} [options.hooks=false] Set to true to run before-/afterDestroy hooks when an associated model is deleted because of a cascade. For example if `User.hasOne(Profile, {onDelete: 'cascade', hooks:true})`, the before-/afterDestroy hooks for profile will be called when a user is deleted. Otherwise the profile will be deleted without invoking any hooks
......
......@@ -60,8 +60,8 @@
"istanbul": "~0.3.0",
"async": "~0.9.0",
"coffee-script": "~1.7.1",
"markdox": "0.1.4",
"sinon-chai": "~2.6.0",
"dox": "0.5.0",
"jshint": ">=2.4.2"
},
"keywords": [
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!