grunt-ngdocs
Advanced tools
Comparing version
@@ -0,1 +1,16 @@ | ||
# 0.1.9 (2014-01-09) | ||
## Features | ||
### ngdocs | ||
* update parser to angularjs 1.2.7 code ([7261eade](https://github.com/m7r/grunt-ngdocs/commit/7261eade)) | ||
markdown parser has switched from showdown to marked. | ||
* import parser unit tests from angularjs 1.2.7 ([fdeaddc1](https://github.com/m7r/grunt-ngdocs/commit/fdeaddc1)) | ||
* check broken links ([6d22869b](https://github.com/m7r/grunt-ngdocs/commit/6d22869b)) | ||
# 0.1.8 (2014-01-06) | ||
@@ -2,0 +17,0 @@ |
@@ -5,8 +5,22 @@ /*global module:false*/ | ||
grunt.loadNpmTasks('grunt-conventional-changelog'); | ||
grunt.loadNpmTasks('grunt-contrib-watch'); | ||
grunt.loadNpmTasks('grunt-jasmine-node'); | ||
grunt.initConfig({ | ||
pkg: grunt.file.readJSON('package.json'), | ||
changelog: { options: { dest: 'CHANGELOG.md' } } | ||
changelog: { options: { dest: 'CHANGELOG.md' } }, | ||
jasmine_node: { | ||
forceexit: true, | ||
captureExceptions: true | ||
}, | ||
watch: { | ||
parser: { | ||
files: ['src/*.js', 'spec/*Spec.js'], | ||
tasks: ['jasmine_node'] | ||
} | ||
} | ||
}); | ||
grunt.registerTask('test', 'Run tests for parser code', ['jasmine_node']); | ||
}; |
{ | ||
"name": "grunt-ngdocs", | ||
"version": "0.1.8", | ||
"version": "0.1.9", | ||
"description": "grunt plugin for angularjs documentation", | ||
@@ -20,3 +20,3 @@ "main": "tasks", | ||
"dependencies": { | ||
"showdown": "0.3.1" | ||
"marked": "0.2.9" | ||
}, | ||
@@ -28,4 +28,7 @@ "peerDependencies": { | ||
"grunt": "~0.4.1", | ||
"grunt-conventional-changelog": "~0.1.0" | ||
"grunt-conventional-changelog": "~0.1.0", | ||
"grunt-contrib-watch": "~0.5.0", | ||
"grunt-jasmine-node": "~0.1.0", | ||
"jasmine-node": "~1.12.0" | ||
} | ||
} |
@@ -7,2 +7,3 @@ /** | ||
exports.htmlEscape = htmlEscape; | ||
exports.normalizeHeaderToId = normalizeHeaderToId; | ||
@@ -12,9 +13,40 @@ ////////////////////////////////////////////////////////// | ||
function htmlEscape(text){ | ||
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); | ||
return text | ||
.replace(/&/g, '&') | ||
.replace(/</g, '<') | ||
.replace(/>/g, '>') | ||
.replace(/\{\{/g, '<span>{{</span>') | ||
.replace(/\}\}/g, '<span>}}</span>'); | ||
} | ||
function nonEmpty(header) { | ||
return !!header; | ||
} | ||
function idFromCurrentHeaders(headers) { | ||
if (headers.length === 1) return headers[0]; | ||
// Do not include the first level title, as that's the title of the page. | ||
return headers.slice(1).filter(nonEmpty).join('_'); | ||
} | ||
function normalizeHeaderToId(header) { | ||
if (typeof header !== 'string') { | ||
return ''; | ||
} | ||
return header.toLowerCase() | ||
.replace(/<.*>/g, '') // html tags | ||
.replace(/[\!\?\:\.\']/g, '') // special characters | ||
.replace(/&#\d\d;/g, '') // html entities | ||
.replace(/\(.*\)/mg, '') // stuff in parenthesis | ||
.replace(/\s$/, '') // trailing spaces | ||
.replace(/\s+/g, '-'); // replace whitespaces with dashes | ||
} | ||
function DOM() { | ||
this.out = []; | ||
this.headingDepth = 0; | ||
this.currentHeaders = []; | ||
this.anchors = []; | ||
} | ||
@@ -44,12 +76,24 @@ | ||
html: function(html) { | ||
if (html) { | ||
var headingDepth = this.headingDepth; | ||
for ( var i = 10; i > 0; --i) { | ||
html = html | ||
.replace(new RegExp('(<\/?h)' + i + '(>)', 'gm'), function(all, start, end){ | ||
return start + (i + headingDepth) + end; | ||
}); | ||
} | ||
this.out.push(html); | ||
} | ||
if (!html) return; | ||
var self = this; | ||
// rewrite header levels, add ids and collect the ids | ||
html = html.replace(/<h(\d)(.*?)>([\s\S]+?)<\/h\1>/gm, function(_, level, attrs, content) { | ||
level = parseInt(level, 10) + self.headingDepth; // change header level based on the context | ||
self.currentHeaders[level - 1] = normalizeHeaderToId(content); | ||
self.currentHeaders.length = level; | ||
var id = idFromCurrentHeaders(self.currentHeaders); | ||
self.anchors.push(id); | ||
return '<h' + level + attrs + ' id="' + id + '">' + content + '</h' + level + '>'; | ||
}); | ||
// collect anchors | ||
html = html.replace(/<a name="(\w*)">/g, function(match, anchor) { | ||
self.anchors.push(anchor); | ||
return match; | ||
}); | ||
this.out.push(html); | ||
}, | ||
@@ -85,13 +129,14 @@ | ||
if (content==undefined || (content instanceof Array && content.length == 0)) return; | ||
this.headingDepth++; | ||
this.currentHeaders[this.headingDepth - 1] = normalizeHeaderToId(heading); | ||
this.currentHeaders.length = this.headingDepth; | ||
var className = null, | ||
anchor = null; | ||
if (typeof heading == 'string') { | ||
var id = heading. | ||
replace(/\(.*\)/mg, ''). | ||
replace(/[^\d\w\$]/mg, '.'). | ||
replace(/-+/gm, '-'). | ||
replace(/-*$/gm, ''); | ||
var id = idFromCurrentHeaders(this.currentHeaders); | ||
this.anchors.push(id); | ||
anchor = {'id': id}; | ||
var classNameValue = id.toLowerCase().replace(/[._]/mg, '-'); | ||
var classNameValue = this.currentHeaders[this.headingDepth - 1] | ||
if(classNameValue == 'hide') classNameValue = ''; | ||
@@ -98,0 +143,0 @@ className = {'class': classNameValue}; |
@@ -23,2 +23,3 @@ var seqCount = 0; | ||
this.js = []; | ||
this.json = []; | ||
this.unit = []; | ||
@@ -92,2 +93,3 @@ this.scenario = []; | ||
out.push(' source-edit-js="' + ids(this.js) + '"'); | ||
out.push(' source-edit-json="' + ids(this.json) + '"'); | ||
out.push(' source-edit-unit="' + ids(this.unit) + '"'); | ||
@@ -107,2 +109,3 @@ out.push(' source-edit-scenario="' + ids(this.scenario) + '"'); | ||
htmlTabs(this.js); | ||
htmlTabs(this.json); | ||
htmlTabs(this.unit); | ||
@@ -120,3 +123,3 @@ htmlTabs(this.scenario); | ||
if (name === 'index.html') { | ||
wrap = ' ng-html-wrap-loaded="' + self.module + ' ' + self.deps.join(' ') + '"'; | ||
wrap = ' ng-html-wrap="' + self.module + ' ' + self.deps.join(' ') + '"'; | ||
} | ||
@@ -138,3 +141,3 @@ if (name == 'scenario.js') name = 'End to end test'; | ||
var out = []; | ||
out.push('<div class="well doc-example-live animator-container"'); | ||
out.push('<div class="well doc-example-live animate-container"'); | ||
if(this.animations) { | ||
@@ -141,0 +144,0 @@ out.push(" ng-class=\"{'animations-off':animationsOff == true}\""); |
605
src/ngdoc.js
/** | ||
* All parsing/transformation code goes here. All code here should be sync to ease testing. | ||
*/ | ||
var Showdown = require('showdown'); | ||
var DOM = require('./dom.js').DOM; | ||
@@ -13,3 +11,24 @@ var htmlEscape = require('./dom.js').htmlEscape; | ||
var fspath = require('path'); | ||
var errorsJson; | ||
var marked = require('marked'); | ||
marked.setOptions({ | ||
gfm: true, | ||
tables: true | ||
}); | ||
var lookupMinerrMsg = function (doc) { | ||
var code, namespace; | ||
if (errorsJson === undefined) { | ||
errorsJson = require(exports.errorFile).errors; | ||
} | ||
namespace = doc.getMinerrNamespace(); | ||
code = doc.getMinerrCode(); | ||
if (namespace === undefined) { | ||
return errorsJson[code]; | ||
} | ||
return errorsJson[namespace][code]; | ||
}; | ||
exports.trim = trim; | ||
@@ -19,2 +38,3 @@ exports.metadata = metadata; | ||
exports.merge = merge; | ||
exports.checkBrokenLinks = checkBrokenLinks; | ||
exports.Doc = Doc; | ||
@@ -46,5 +66,6 @@ | ||
this.links = this.links || []; | ||
this.anchors = this.anchors || []; | ||
} | ||
Doc.METADATA_IGNORE = (function() { | ||
var words = require('fs').readFileSync(__dirname + '/ignore.words', 'utf8'); | ||
var words = fs.readFileSync(__dirname + '/ignore.words', 'utf8'); | ||
return words.toString().split(/[,\s\n\r]+/gm); | ||
@@ -81,2 +102,6 @@ })(); | ||
}); | ||
if (this.ngdoc === 'error') { | ||
words.push(this.getMinerrNamespace()); | ||
words.push(this.getMinerrCode()); | ||
} | ||
words.sort(); | ||
@@ -86,2 +111,27 @@ return words.join(' '); | ||
shortDescription : function() { | ||
if (!this.description) return this.description; | ||
var text = this.description.split("\n")[0]; | ||
text = text.replace(/<.+?\/?>/g, ''); | ||
text = text.replace(/{/g,'{'); | ||
text = text.replace(/}/g,'}'); | ||
return text; | ||
}, | ||
getMinerrNamespace: function () { | ||
if (this.ngdoc !== 'error') { | ||
throw new Error('Tried to get the minErr namespace, but @ngdoc ' + | ||
this.ngdoc + ' was supplied. It should be @ngdoc error'); | ||
} | ||
return this.name.split(':')[0]; | ||
}, | ||
getMinerrCode: function () { | ||
if (this.ngdoc !== 'error') { | ||
throw new Error('Tried to get the minErr error code, but @ngdoc ' + | ||
this.ngdoc + ' was supplied. It should be @ngdoc error'); | ||
} | ||
return this.name.split(':')[1]; | ||
}, | ||
/** | ||
@@ -103,3 +153,11 @@ * Converts relative urls (without section) into absolute | ||
var prefix = this.options.html5Mode ? '' : '#/'; | ||
if (url.substr(-1) == '/') return url + 'index'; | ||
var hashIdx = url.indexOf('#'); | ||
// Lowercase hash parts of the links, | ||
// so that we can keep correct API names even when the urls are lowercased. | ||
if (hashIdx !== -1) { | ||
url = url.substr(0, hashIdx) + url.substr(hashIdx).toLowerCase(); | ||
} | ||
if (url.substr(-1) == '/') return prefix + url + 'index'; | ||
if (url.match(/\//)) return prefix + url; | ||
@@ -116,3 +174,3 @@ return prefix + this.section + '/' + url; | ||
IS_HASH = /^#/, | ||
parts = trim(text).split(/(<pre>[\s\S]*?<\/pre>|<doc:example(\S*).*?>[\s\S]*?<\/doc:example>|<example[^>]*>[\s\S]*?<\/example>)/), | ||
parts = trim(text).split(/(<pre.*?>[\s\S]*?<\/pre>|<doc:example(\S*).*?>[\s\S]*?<\/doc:example>|<example[^>]*>[\s\S]*?<\/example>)/), | ||
seq = 0, | ||
@@ -148,2 +206,3 @@ placeholderMap = {}; | ||
example.enableAnimations(); | ||
example.addDeps('angular-animate.js'); | ||
} | ||
@@ -157,3 +216,3 @@ | ||
content.replace(/<file\s+src="([^"]+)"(?:\s+tag="([^"]+)")?(?:\s+name="([^"]+)")?\s*\/?>/gmi, function(_, file, tag, name) { | ||
if(fspath.existsSync(file)) { | ||
if(fs.existsSync(file)) { | ||
var content = fs.readFileSync(file, 'utf8'); | ||
@@ -173,3 +232,3 @@ if(content && content.length > 0) { | ||
replace(/(?:\*\s+)?<file.+?src="([^"]+)"(?:\s+tag="([^"]+)")?\s*\/?>/i, function(_, file, tag) { | ||
if(fspath.existsSync(file)) { | ||
if(fs.existsSync(file)) { | ||
var content = fs.readFileSync(file, 'utf8'); | ||
@@ -206,5 +265,5 @@ if(tag && tag.length > 0) { | ||
}). | ||
replace(/^<pre>([\s\S]*?)<\/pre>/mi, function(_, content){ | ||
replace(/^<pre(.*?)>([\s\S]*?)<\/pre>/mi, function(_, attrs, content){ | ||
return placeholder( | ||
'<pre class="prettyprint linenums">' + | ||
'<pre'+attrs+' class="prettyprint linenums">' + | ||
content.replace(/</g, '<').replace(/>/g, '>') + | ||
@@ -229,9 +288,72 @@ '</pre>'); | ||
'</a>'; | ||
}). | ||
replace(/{@type\s+(\S+)(?:\s+(\S+))?}/g, function(_, type, url) { | ||
url = url || '#'; | ||
return '<a href="' + url + '" class="' + self.prepare_type_hint_class_name(type) + '">' + type + '</a>'; | ||
}). | ||
replace(/{@installModule\s+(\S+)?}/g, function(_, module) { | ||
return explainModuleInstallation(module); | ||
}); | ||
}); | ||
text = parts.join(''); | ||
text = new Showdown.converter({ extensions : ['table'] }).makeHtml(text); | ||
function prepareClassName(text) { | ||
return text.toLowerCase().replace(/[_\W]+/g, '-'); | ||
}; | ||
var pageClassName, suffix = '-page'; | ||
if(this.name) { | ||
var split = this.name.match(/^\s*(.+?)\s*:\s*(.+)/); | ||
if(split && split.length > 1) { | ||
var before = prepareClassName(split[1]); | ||
var after = prepareClassName(split[2]); | ||
pageClassName = before + suffix + ' ' + before + '-' + after + suffix; | ||
} | ||
} | ||
pageClassName = pageClassName || prepareClassName(this.name || 'docs') + suffix; | ||
text = '<div class="' + pageClassName + '">' + | ||
marked(text) + | ||
'</div>'; | ||
text = text.replace(/(?:<p>)?(REPLACEME\d+)(?:<\/p>)?/g, function(_, id) { | ||
return placeholderMap[id]; | ||
}); | ||
//!annotate CONTENT | ||
//!annotate="REGEX" CONTENT | ||
//!annotate="REGEX" TITLE|CONTENT | ||
text = text.replace(/\n?\/\/!annotate\s*(?:=\s*['"](.+?)['"])?\s+(.+?)\n\s*(.+?\n)/img, | ||
function(_, pattern, content, line) { | ||
var pattern = new RegExp(pattern || '.+'); | ||
var title, text, split = content.split(/\|/); | ||
if(split.length > 1) { | ||
text = split[1]; | ||
title = split[0]; | ||
} | ||
else { | ||
title = 'Info'; | ||
text = content; | ||
} | ||
return "\n" + line.replace(pattern, function(match) { | ||
return '<div class="nocode nocode-content" data-popover ' + | ||
'data-content="' + text + '" ' + | ||
'data-title="' + title + '">' + | ||
match + | ||
'</div>'; | ||
}); | ||
} | ||
); | ||
//!details /path/to/local/docs/file.html | ||
//!details="REGEX" /path/to/local/docs/file.html | ||
text = text.replace(/\/\/!details\s*(?:=\s*['"](.+?)['"])?\s+(.+?)\n\s*(.+?\n)/img, | ||
function(_, pattern, url, line) { | ||
url = '/notes/' + url; | ||
var pattern = new RegExp(pattern || '.+'); | ||
return line.replace(pattern, function(match) { | ||
return '<div class="nocode nocode-content" data-foldout data-url="' + url + '">' + match + '</div>'; | ||
}); | ||
} | ||
); | ||
return text; | ||
@@ -262,2 +384,3 @@ }, | ||
this.id = this.id || // if we have an id just use it | ||
(this.ngdoc === 'error' ? this.name : '') || | ||
(((this.file||'').match(/.*(\/|\\)([^(\/|\\)]*)\.ngdoc/)||{})[2]) || // try to extract it from file name | ||
@@ -291,11 +414,9 @@ this.name; // default to name | ||
optional: optional, | ||
'default':match[5] | ||
default: match[5] | ||
}; | ||
//if param name is a part of an object passed to a method | ||
//mark it, so it's not included in the rendering later | ||
// if param name is a part of an object passed to a method | ||
// mark it, so it's not included in the rendering later | ||
if(param.name.indexOf(".") > 0){ | ||
param.isProperty = true; | ||
param.isProperty = true; | ||
} | ||
self.param.push(param); | ||
@@ -342,7 +463,43 @@ } else if (atName == 'returns' || atName == 'return') { | ||
var dom = new DOM(), | ||
self = this; | ||
self = this, | ||
minerrMsg; | ||
dom.h(title(this.moduleName, this.name, this.ngdoc == 'overview'), function() { | ||
var gitTagFromFullVersion = function(version) { | ||
var match = version.match(/-(\w{7})/); | ||
if (match) { | ||
// git sha | ||
return match[1]; | ||
} | ||
// git tag | ||
return 'v' + version; | ||
}; | ||
/* | ||
if (this.section === 'api') { | ||
dom.tag('a', { | ||
href: 'http://github.com/angular/angular.js/tree/' + | ||
gitTagFromFullVersion(gruntUtil.getVersion().full) + '/' + self.file + '#L' + self.line, | ||
class: 'view-source btn btn-action' }, function(dom) { | ||
dom.tag('i', {class:'icon-zoom-in'}, ' '); | ||
dom.text(' View source'); | ||
}); | ||
} | ||
dom.tag('a', { | ||
href: 'http://github.com/angular/angular.js/edit/master/' + self.file, | ||
class: 'improve-docs btn btn-primary' }, function(dom) { | ||
dom.tag('i', {class:'icon-edit'}, ' '); | ||
dom.text(' Improve this doc'); | ||
}); | ||
*/ | ||
dom.h(title(this), function() { | ||
notice('deprecated', 'Deprecated API', self.deprecated); | ||
if (self.ngdoc === 'error') { | ||
minerrMsg = lookupMinerrMsg(self); | ||
dom.tag('pre', { | ||
class:'minerr-errmsg', | ||
'error-display': minerrMsg.replace(/"/g, '"') | ||
}, minerrMsg); | ||
} | ||
if (self.ngdoc != 'overview') { | ||
@@ -367,2 +524,4 @@ dom.h('Description', self.description, dom.html); | ||
self.anchors = dom.anchors; | ||
return dom.toString(); | ||
@@ -373,3 +532,3 @@ | ||
function notice(name, legend, msg){ | ||
if (self[name] == undefined) return; | ||
if (self[name] === undefined) return; | ||
dom.tag('fieldset', {'class':name}, function(dom){ | ||
@@ -383,24 +542,11 @@ dom.tag('legend', legend); | ||
prepare_type_hint_class_name : function(type) { | ||
var typeClass = type.toLowerCase().match(/^[-\w]+/) || []; | ||
typeClass = typeClass[0] ? typeClass[0] : 'object'; | ||
return 'label type-hint type-hint-' + typeClass; | ||
}, | ||
html_usage_parameters: function(dom) { | ||
dom.h('Parameters', this.param, function(param){ | ||
dom.tag('code', function() { | ||
dom.text(param.name); | ||
if (param.optional) { | ||
dom.tag('i', function() { | ||
dom.text('(optional'); | ||
if(param['default']) { | ||
dom.text('=' + param['default']); | ||
} | ||
dom.text(')'); | ||
}); | ||
} | ||
dom.text(' – {'); | ||
dom.text(param.type); | ||
if (param.optional) { | ||
dom.text('='); | ||
} | ||
dom.text('} – '); | ||
}); | ||
dom.html(param.description); | ||
}); | ||
var self = this; | ||
var params = this.param ? this.param : []; | ||
if(this.animations) { | ||
@@ -417,3 +563,54 @@ dom.h('Animations', this.animations, function(animations){ | ||
}); | ||
// dom.html('<a href="api/ngAnimate.$animate">Click here</a> to learn more about the steps involved in the animation.'); | ||
} | ||
if(params.length > 0) { | ||
dom.html('<h2>Parameters</h2>'); | ||
dom.html('<table class="variables-matrix table table-bordered table-striped">'); | ||
dom.html('<thead>'); | ||
dom.html('<tr>'); | ||
dom.html('<th>Param</th>'); | ||
dom.html('<th>Type</th>'); | ||
dom.html('<th>Details</th>'); | ||
dom.html('</tr>'); | ||
dom.html('</thead>'); | ||
dom.html('<tbody>'); | ||
for(var i=0;i<params.length;i++) { | ||
param = params[i]; | ||
var name = param.name; | ||
var types = param.type; | ||
if(types[0]=='(') { | ||
types = types.substr(1); | ||
} | ||
var limit = types.length - 1; | ||
if(types.charAt(limit) == ')' && types.charAt(limit-1) != '(') { | ||
types = types.substr(0,limit); | ||
} | ||
types = types.split(/\|(?![\(\)\w\|\s]+>)/); | ||
if (param.optional) { | ||
name += ' <div><em>(optional)</em></div>'; | ||
} | ||
dom.html('<tr>'); | ||
dom.html('<td>' + name + '</td>'); | ||
dom.html('<td>'); | ||
for(var j=0;j<types.length;j++) { | ||
var type = types[j]; | ||
dom.html('<a href="" class="' + self.prepare_type_hint_class_name(type) + '">'); | ||
dom.text(type); | ||
dom.html('</a>'); | ||
} | ||
dom.html('</td>'); | ||
var description = '<td>'; | ||
description += param.description; | ||
if (param.default) { | ||
description += ' <p><em>(default: ' + param.default + ')</em></p>'; | ||
} | ||
description += '</td>'; | ||
dom.html(description); | ||
dom.html('</tr>'); | ||
}; | ||
dom.html('</tbody>'); | ||
dom.html('</table>'); | ||
} | ||
}, | ||
@@ -424,7 +621,15 @@ | ||
if (self.returns) { | ||
dom.h('Returns', function() { | ||
dom.tag('code', '{' + self.returns.type + '}'); | ||
dom.text('– '); | ||
dom.html(self.returns.description); | ||
}); | ||
dom.html('<h2>Returns</h2>'); | ||
dom.html('<table class="variables-matrix">'); | ||
dom.html('<tr>'); | ||
dom.html('<td>'); | ||
dom.html('<a href="" class="' + self.prepare_type_hint_class_name(self.returns.type) + '">'); | ||
dom.text(self.returns.type); | ||
dom.html('</a>'); | ||
dom.html('</td>'); | ||
dom.html('<td>'); | ||
dom.html(self.returns.description); | ||
dom.html('</td>'); | ||
dom.html('</tr>'); | ||
dom.html('</table>'); | ||
} | ||
@@ -446,3 +651,3 @@ }, | ||
var self = this; | ||
var name = self.name.match(/^angular(\.mock)?\.(\w+)$/) ? self.name : self.name.split(/\./).pop(); | ||
var name = self.name.match(/^angular(\.mock)?\.(\w+)$/) ? self.name : self.name.split(/\./).pop() | ||
@@ -468,3 +673,3 @@ dom.h('Usage', function() { | ||
dom.code(function() { | ||
dom.text(self.name); | ||
dom.text(self.name.split(':').pop()); | ||
}); | ||
@@ -479,11 +684,13 @@ | ||
dom.h('Usage', function() { | ||
var restrict = self.restrict || 'AC'; | ||
var restrict = self.restrict || 'A'; | ||
/*if (restrict.match(/E/)) { | ||
/* | ||
if (restrict.match(/E/)) { | ||
dom.html('<p>'); | ||
dom.text('This directive can be used as custom element, but be aware of '); | ||
dom.tag('a', {href:'http://docs.angularjs.org/guide/ie'}, 'IE restrictions'); | ||
dom.tag('a', {href:'guide/ie'}, 'IE restrictions'); | ||
dom.text('.'); | ||
dom.html('</p>'); | ||
}*/ | ||
} | ||
*/ | ||
@@ -530,44 +737,2 @@ if (self.usage) { | ||
} | ||
if(self.animations) { | ||
var animations = [], matches = self.animations.split("\n"); | ||
matches.forEach(function(ani) { | ||
var name = ani.match(/^\s*(.+?)\s*-/)[1]; | ||
animations.push(name); | ||
}); | ||
dom.html('with <span id="animations">animations</span>'); | ||
var comment; | ||
if(animations.length == 1) { | ||
comment = 'The ' + animations[0] + ' animation is supported'; | ||
} | ||
else { | ||
var rhs = animations[animations.length-1]; | ||
var lhs = ''; | ||
for(var i=0;i<animations.length-1;i++) { | ||
if(i>0) { | ||
lhs += ', '; | ||
} | ||
lhs += animations[i]; | ||
} | ||
comment = 'The ' + lhs + ' and ' + rhs + ' animations are supported'; | ||
} | ||
var element = self.element || 'ANY'; | ||
dom.code(function() { | ||
dom.text('//' + comment + "\n"); | ||
dom.text('<' + element + ' '); | ||
dom.text(dashCase(self.shortName)); | ||
renderParams('\n ', '="', '"', true); | ||
dom.text(' ng-animate="{'); | ||
animations.forEach(function(ani, index) { | ||
if (index) { | ||
dom.text(', '); | ||
} | ||
dom.text(ani + ': \'' + ani + '-animation\''); | ||
}); | ||
dom.text('}">\n ...\n'); | ||
dom.text('</' + element + '>'); | ||
}); | ||
dom.html('<a href="api/ng.$animator#Methods">Click here</a> to learn more about the steps involved in the animation.'); | ||
} | ||
} | ||
@@ -587,3 +752,3 @@ self.html_usage_directiveInfo(dom); | ||
var parts = param.name.split('|'); | ||
dom.text(parts[skipSelf ? 0 : 1] || parts[0]); | ||
dom.text(dashCase(parts[skipSelf ? 0 : 1] || parts[0])); | ||
} | ||
@@ -678,2 +843,6 @@ if (BOOLEAN_ATTR[param.name]) { | ||
html_usage_error: function (dom) { | ||
dom.html(); | ||
}, | ||
html_usage_interface: function(dom){ | ||
@@ -685,3 +854,3 @@ var self = this; | ||
dom.code(function() { | ||
dom.text(self.name.split('.').pop()); | ||
dom.text(self.name.split('.').pop().split(':').pop()); | ||
dom.text('('); | ||
@@ -714,4 +883,3 @@ self.parameters(dom, ', '); | ||
//filters out .IsProperty parameters from the method signature | ||
var signature = (method.param || []).filter(function(e) { return e.isProperty !== true}).map(property('name')); | ||
var signature = (method.param || []).filter(function(e) { return e.isProperty !== true; }).map(property('name')); | ||
dom.h(method.shortName + '(' + signature.join(', ') + ')', method, function() { | ||
@@ -773,3 +941,3 @@ dom.html(method.description); | ||
if (!(skipFirst && i==0)) { | ||
if (param.isProperty) { return; } | ||
if (param.isProperty) { return; } | ||
if (param.optional) { | ||
@@ -800,64 +968,59 @@ dom.text('[' + sep + param.name + ']'); | ||
function title(module, text, overview) { | ||
if (!text) return text; | ||
function title(doc) { | ||
if (!doc.name) return doc.name; | ||
var match, | ||
module, | ||
type, | ||
name; | ||
module = doc.moduleName, | ||
overview = doc.ngdoc == 'overview', | ||
text = doc.name; | ||
if (text == 'angular.Module') { | ||
module = 'ng'; | ||
name = 'Module'; | ||
type = 'Type'; | ||
var makeTitle = function (name, type, componentType, component) { | ||
if (!module) { | ||
module = component; | ||
if (module == 'angular') { | ||
module = 'ng'; | ||
} | ||
doc.moduleName = module; | ||
} | ||
// Makes title markup. | ||
// makeTitle('Foo', 'directive', 'module', 'ng') -> | ||
// Foo is a directive in module ng | ||
return function () { | ||
this.tag('code', name); | ||
this.tag('div', function () { | ||
this.tag('span', {class: 'hint'}, function () { | ||
if (type && component) { | ||
this.text(type + ' in ' + componentType + ' '); | ||
this.tag('code', component); | ||
} | ||
}); | ||
}); | ||
}; | ||
}; | ||
if (doc.ngdoc === 'error') { | ||
return makeTitle(doc.fullName, 'error', 'component', doc.getMinerrNamespace()); | ||
} else if (text == 'angular.Module') { | ||
return makeTitle('Module', 'Type', 'module', 'ng'); | ||
} else if (match = text.match(GLOBALS)) { | ||
module = 'ng'; | ||
name = 'angular.' + match[1]; | ||
type = 'API'; | ||
return makeTitle('angular.' + match[1], 'API', 'module', 'ng'); | ||
} else if (match = text.match(MODULE)) { | ||
module = match[1]; | ||
if (!overview) { name = match[1]; } | ||
return makeTitle(overview ? '' : match[1], '', 'module', match[1]); | ||
} else if (match = text.match(MODULE_MOCK)) { | ||
module = 'ng'; | ||
name = 'angular.mock.' + match[1]; | ||
type = 'API'; | ||
return makeTitle('angular.mock.' + match[1], 'API', 'module', 'ng'); | ||
} else if (match = text.match(MODULE_DIRECTIVE)) { | ||
module = match[1]; | ||
name = match[2]; | ||
type = 'directive'; | ||
return makeTitle(match[2], 'directive', 'module', match[1]); | ||
} else if (match = text.match(MODULE_DIRECTIVE_INPUT)) { | ||
module = match[1]; | ||
name = 'input [' + match[2] + ']'; | ||
type = 'directive'; | ||
return makeTitle('input [' + match[2] + ']', 'directive', 'module', match[1]); | ||
} else if (match = text.match(MODULE_CUSTOM)) { | ||
module = match[1]; | ||
name = match[3]; | ||
type = match[2]; | ||
return makeTitle(match[3], match[2], 'module', match[1]); | ||
} else if (match = text.match(MODULE_TYPE)) { | ||
module = module || match[1]; | ||
name = match[2]; | ||
type = 'type'; | ||
return makeTitle(match[2], 'type', 'module', module || match[1]); | ||
} else if (match = text.match(MODULE_SERVICE)) { | ||
if (overview) { | ||
// module name with dots looks like a service | ||
module = text; | ||
} else { | ||
module = module || match[1]; | ||
name = match[2] + (match[3] || ''); | ||
type = 'service'; | ||
return makeTitle('', '', 'module', text); | ||
} | ||
} else { | ||
return text; | ||
return makeTitle(match[2] + (match[3] || ''), 'service', 'module', module || match[1]); | ||
} | ||
return function() { | ||
this.tag('code', name); | ||
this.tag('span', { class: 'hint'}, function() { | ||
if (type) { | ||
this.text('('); | ||
this.text(type); | ||
this.text(' in module '); | ||
this.tag('code', module); | ||
this.text(')'); | ||
} | ||
}); | ||
}; | ||
return text; | ||
} | ||
@@ -904,3 +1067,3 @@ | ||
docs.forEach(function(doc){ | ||
var path = (doc.name || '').split(/(\.|\:\s*)/); | ||
var path = (doc.name || '').split(/(\:\s*)/); | ||
for ( var i = 1; i < path.length; i++) { | ||
@@ -918,10 +1081,11 @@ path.splice(i, 1); | ||
id: doc.id, | ||
name: title(doc.moduleName, doc.name), | ||
moduleName: doc.moduleName, | ||
name: title(doc), | ||
shortName: shortName, | ||
type: doc.ngdoc, | ||
keywords:doc.keywords() | ||
moduleName: doc.moduleName, | ||
shortDescription: doc.shortDescription(), | ||
keywords: doc.keywords() | ||
}); | ||
}); | ||
pages.sort(keywordSort); | ||
pages.sort(sidebarSort); | ||
return pages; | ||
@@ -959,3 +1123,56 @@ } | ||
}; | ||
function keywordSort(a, b){ | ||
var GUIDE_PRIORITY = [ | ||
'introduction', | ||
'overview', | ||
'concepts', | ||
'dev_guide.mvc', | ||
'dev_guide.mvc.understanding_controller', | ||
'dev_guide.mvc.understanding_model', | ||
'dev_guide.mvc.understanding_view', | ||
'dev_guide.services.understanding_services', | ||
'dev_guide.services.managing_dependencies', | ||
'dev_guide.services.creating_services', | ||
'dev_guide.services.injecting_controllers', | ||
'dev_guide.services.testing_services', | ||
'dev_guide.services.$location', | ||
'dev_guide.services', | ||
'databinding', | ||
'dev_guide.templates.css-styling', | ||
'dev_guide.templates.filters.creating_filters', | ||
'dev_guide.templates.filters', | ||
'dev_guide.templates.filters.using_filters', | ||
'dev_guide.templates', | ||
'di', | ||
'providers', | ||
'module', | ||
'scope', | ||
'expression', | ||
'bootstrap', | ||
'directive', | ||
'compiler', | ||
'forms', | ||
'animations', | ||
'dev_guide.e2e-testing', | ||
'dev_guide.unit-testing', | ||
'i18n', | ||
'ie', | ||
'migration', | ||
]; | ||
function sidebarSort(a, b){ | ||
priorityA = GUIDE_PRIORITY.indexOf(a.id); | ||
priorityB = GUIDE_PRIORITY.indexOf(b.id); | ||
if (priorityA > -1 || priorityB > -1) { | ||
return priorityA < priorityB ? -1 : (priorityA > priorityB ? 1 : 0); | ||
} | ||
function mangleName(doc) { | ||
@@ -1041,18 +1258,3 @@ var path = doc.id.split(/\./); | ||
for(var i = 0; i < docs.length;) { | ||
var doc = docs[i]; | ||
// check links - do they exist ? | ||
doc.links.forEach(function(link) { | ||
// convert #id to path#id | ||
if (link[0] == '#') { | ||
link = doc.section + '/' + doc.id.split('#').shift() + link; | ||
} | ||
link = link.split('#').shift(); | ||
if (!byFullId[link]) { | ||
console.log('WARNING: In ' + doc.section + '/' + doc.id + ', non existing link: "' + link + '"'); | ||
} | ||
}); | ||
// merge into parents | ||
if (findParent(doc, 'method') || findParent(doc, 'property') || findParent(doc, 'event')) { | ||
if (findParent(docs[i], 'method') || findParent(docs[i], 'property') || findParent(docs[i], 'event')) { | ||
docs.splice(i, 1); | ||
@@ -1086,2 +1288,38 @@ } else { | ||
function checkBrokenLinks(docs, apis, options) { | ||
var byFullId = Object.create(null); | ||
docs.forEach(function(doc) { | ||
byFullId[doc.section + '/' + doc.id] = doc; | ||
if (apis[doc.section]) { | ||
doc.anchors.push('directive', 'service', 'filter', 'function'); | ||
} | ||
}); | ||
docs.forEach(function(doc) { | ||
doc.links.forEach(function(link) { | ||
if (options && !options.html5mode) { | ||
link = link.substring(2); | ||
} | ||
// convert #id to path#id | ||
if (link[0] == '#') { | ||
link = doc.section + '/' + doc.id.split('#').shift() + link; | ||
} | ||
var parts = link.split('#'); | ||
var pageLink = parts[0]; | ||
var anchorLink = parts[1]; | ||
var linkedPage = byFullId[pageLink]; | ||
if (!linkedPage) { | ||
console.log('WARNING: ' + doc.section + '/' + doc.id + ' (defined in ' + doc.file + ') points to a non existing page "' + link + '"!'); | ||
} else if (anchorLink && linkedPage.anchors.indexOf(anchorLink) === -1) { | ||
console.log('WARNING: ' + doc.section + '/' + doc.id + ' (defined in ' + doc.file + ') points to a non existing anchor "' + link + '"!'); | ||
} | ||
}); | ||
}); | ||
} | ||
function property(name) { | ||
@@ -1100,1 +1338,32 @@ return function(value){ | ||
} | ||
////////////////////////////////////////////////////////// | ||
function explainModuleInstallation(moduleName){ | ||
var ngMod = ngModule(moduleName), | ||
modulePackage = 'angular-' + moduleName, | ||
modulePackageFile = modulePackage + '.js'; | ||
return '<h1>Installation</h1>' + | ||
'<p>First include <code>' + modulePackageFile +'</code> in your HTML:</p><pre><code>' + | ||
' <script src="angular.js">\n' + | ||
' <script src="' + modulePackageFile + '"></pre></code>' + | ||
'<p>You can download this file from the following places:</p>' + | ||
'<ul>' + | ||
'<li>[Google CDN](https://developers.google.com/speed/libraries/devguide#angularjs)<br>' + | ||
'e.g. <code>"//ajax.googleapis.com/ajax/libs/angularjs/X.Y.Z/' + modulePackageFile + '"</code></li>' + | ||
'<li>[Bower](http://bower.io)<br>' + | ||
'e.g. <code>bower install ' + modulePackage + '@X.Y.Z</code></li>' + | ||
'<li><a href="http://code.angularjs.org/">code.angularjs.org</a><br>' + | ||
'e.g. <code>"//code.angularjs.org/X.Y.Z/' + modulePackageFile + '"</code></li>' + | ||
'</ul>' + | ||
'<p>where X.Y.Z is the AngularJS version you are running.</p>' + | ||
'<p>Then load the module in your application by adding it as a dependent module:</p><pre><code>' + | ||
' angular.module(\'app\', [\'' + ngMod + '\']);</pre></code>' + | ||
'<p>With that you\'re ready to get started!</p>'; | ||
} | ||
function ngModule(moduleName) { | ||
return 'ng' + moduleName[0].toUpperCase() + moduleName.substr(1); | ||
} |
@@ -94,2 +94,3 @@ /* | ||
ngdoc.merge(reader.docs); | ||
ngdoc.checkBrokenLinks(reader.docs, setup.apis, options); | ||
@@ -96,0 +97,0 @@ reader.docs.forEach(function(doc){ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
744461
6.54%28
7.69%10242
10.4%5
150%+ Added
+ Added
- Removed
- Removed