mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-06 21:57:47 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1 @@
|
||||
node jsdoc/jsdoc.js -c conf.json
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"tags": {
|
||||
"allowUnknownTags" : true
|
||||
},
|
||||
"source": {
|
||||
"include": ["../src"],
|
||||
"exclude": [],
|
||||
"includePattern": ".+\\.js(doc)?$",
|
||||
"excludePattern": "(^|\\/|\\\\)_"
|
||||
},
|
||||
"opts": {
|
||||
"template": "./jaguar",
|
||||
"destination": "./out",
|
||||
"readme": "../README.md",
|
||||
"recurse": true
|
||||
},
|
||||
"plugins": [
|
||||
"plugins/markdown"
|
||||
],
|
||||
"templates": {
|
||||
"applicationName": "RobloxHybrid API",
|
||||
"disqus": "",
|
||||
"googleAnalytics": "",
|
||||
"openGraph": {
|
||||
"title": "",
|
||||
"type": "website",
|
||||
"image": "",
|
||||
"site_name": "",
|
||||
"url": ""
|
||||
},
|
||||
"meta": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"keyword": ""
|
||||
},
|
||||
"default": {
|
||||
"outputSourceFiles" : true
|
||||
},
|
||||
"linenums": true
|
||||
},
|
||||
"markdown": {
|
||||
"parser": "gfm",
|
||||
"hardwrap": true,
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* http://gruntjs.com/configuring-tasks
|
||||
*/
|
||||
module.exports = function (grunt) {
|
||||
var path = require('path');
|
||||
var DEMO_PATH = 'demo/dist';
|
||||
var DEMO_SAMPLE_PATH = 'demo/sample';
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
|
||||
connect: {
|
||||
options: {
|
||||
hostname: '*'
|
||||
},
|
||||
demo: {
|
||||
options: {
|
||||
port: 8000,
|
||||
base: DEMO_PATH,
|
||||
middleware: function (connect, options) {
|
||||
return [
|
||||
require('connect-livereload')(),
|
||||
connect.static(path.resolve(options.base))
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
options: {
|
||||
livereload: true
|
||||
},
|
||||
less: {
|
||||
files: ['less/**/*.less'],
|
||||
tasks: ['less']
|
||||
},
|
||||
|
||||
lesscopy: {
|
||||
files: ['static/styles/jaguar.css'],
|
||||
tasks: ['copy:css']
|
||||
},
|
||||
|
||||
jscopy: {
|
||||
files: ['static/scripts/main.js'],
|
||||
tasks: ['copy:js']
|
||||
},
|
||||
|
||||
jsdoc: {
|
||||
files: ['**/*.tmpl', '*.js'],
|
||||
tasks: ['jsdoc']
|
||||
},
|
||||
|
||||
demo: {
|
||||
files: ['demo/sample/**/*.js'],
|
||||
tasks: ['demo']
|
||||
}
|
||||
},
|
||||
|
||||
clean: {
|
||||
demo: {
|
||||
src: DEMO_PATH
|
||||
}
|
||||
},
|
||||
|
||||
jsdoc: {
|
||||
demo: {
|
||||
src: [
|
||||
DEMO_SAMPLE_PATH + '/**/*.js',
|
||||
|
||||
// You can add README.md file for index page at documentations.
|
||||
'README.md'
|
||||
],
|
||||
options: {
|
||||
verbose: true,
|
||||
destination: DEMO_PATH,
|
||||
configure: 'conf.json',
|
||||
template: './',
|
||||
'private': false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
less: {
|
||||
dist: {
|
||||
src: 'less/**/jaguar.less',
|
||||
dest: 'static/styles/jaguar.css'
|
||||
}
|
||||
},
|
||||
|
||||
copy: {
|
||||
css: {
|
||||
src: 'static/styles/jaguar.css',
|
||||
dest: DEMO_PATH + '/styles/jaguar.css'
|
||||
},
|
||||
|
||||
js: {
|
||||
src: 'static/scripts/main.js',
|
||||
dest: DEMO_PATH + '/scripts/main.js'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Load task libraries
|
||||
[
|
||||
'grunt-contrib-connect',
|
||||
'grunt-contrib-watch',
|
||||
'grunt-contrib-copy',
|
||||
'grunt-contrib-clean',
|
||||
'grunt-contrib-less',
|
||||
'grunt-jsdoc',
|
||||
].forEach(function (taskName) {
|
||||
grunt.loadNpmTasks(taskName);
|
||||
});
|
||||
|
||||
// Definitions of tasks
|
||||
grunt.registerTask('default', 'Watch project files', [
|
||||
'demo',
|
||||
'connect:demo',
|
||||
'watch'
|
||||
]);
|
||||
|
||||
grunt.registerTask('demo', 'Create documentations for demo', [
|
||||
'less',
|
||||
'clean:demo',
|
||||
'jsdoc:demo'
|
||||
]);
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 Sangmin, Shim
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,56 @@
|
||||
Jaguar.js template for JSDoc 3
|
||||
---
|
||||
- [Jaguar.js](http://davidshimjs.github.io/jaguarjs)
|
||||
- [Jaguar.js Documentations](http://davidshimjs.github.io/jaguarjs/doc)
|
||||
- [JSDoc3](https://github.com/jsdoc3/jsdoc)
|
||||
- [JSDoc3 API Documentations](http://usejsdoc.org)
|
||||
|
||||
Usage
|
||||
---
|
||||
1. If you want to create documentations with sample files, you can use commands below.
|
||||
```
|
||||
$ npm install
|
||||
$ grunt demo
|
||||
```
|
||||
|
||||
2. You can see any output related jsdoc process with a `--debug` flag.
|
||||
```
|
||||
$ grunt demo --debug
|
||||
```
|
||||
|
||||
3. If you already have jsdoc system, you can use this project as jsdoc template.
|
||||
```
|
||||
$ jsdoc -t `project folder` -c `configuration file` `source files` `README.md file`
|
||||
```
|
||||
|
||||
conf.json
|
||||
---
|
||||
You can set options for customizing your documentations.
|
||||
|
||||
```
|
||||
"templates": {
|
||||
"applicationName": "Demo",
|
||||
"disqus": "",
|
||||
"googleAnalytics": "",
|
||||
"openGraph": {
|
||||
"title": "",
|
||||
"type": "website",
|
||||
"image": "",
|
||||
"site_name": "",
|
||||
"url": ""
|
||||
},
|
||||
"meta": {
|
||||
"title": "",
|
||||
"description": "",
|
||||
"keyword": ""
|
||||
},
|
||||
"linenums": true
|
||||
}
|
||||
```
|
||||
|
||||
License
|
||||
---
|
||||
This project under the MIT License. and this project refered by default template for JSDoc 3.
|
||||
|
||||
[](https://bitdeli.com/free "Bitdeli Badge")
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"tags": {
|
||||
"allowUnknownTags" : true
|
||||
},
|
||||
"plugins": ["plugins/markdown"],
|
||||
"templates": {
|
||||
"cleverLinks": true,
|
||||
"monospaceLinks": true,
|
||||
"outputSourceFiles" : true,
|
||||
"default": {
|
||||
"outputSourceFiles" : true
|
||||
},
|
||||
"applicationName": "Demo",
|
||||
"disqus": "",
|
||||
"googleAnalytics": "",
|
||||
"openGraph": {
|
||||
"title": "",
|
||||
"type": "website",
|
||||
"image": "",
|
||||
"site_name": "",
|
||||
"url": ""
|
||||
},
|
||||
"meta": {
|
||||
"title": "Hey",
|
||||
"description": "No",
|
||||
"keyword": ""
|
||||
},
|
||||
"linenums": true
|
||||
},
|
||||
"markdown": {
|
||||
"parser": "gfm",
|
||||
"hardwrap": true,
|
||||
"tags": ["examples"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
@navWidth: 250px;
|
||||
@colorSubtitle: rgb(119, 156, 52);
|
||||
@colorRed: rgb(238, 125, 125);
|
||||
@colorLink: #2a6496;
|
||||
@colorBgNavi: #1a1a1a;
|
||||
|
||||
.font-description () {
|
||||
font-family: "freight-text-pro",Georgia,Cambria,"Times New Roman",Times,serif
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
@import "common.less";
|
||||
|
||||
footer {
|
||||
margin: 15px 0;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #e1e1e1;
|
||||
.font-description();
|
||||
font-size: 0.8em;
|
||||
color: gray;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
@import "common.less";
|
||||
|
||||
// normalize
|
||||
html, body {
|
||||
font: 1em "jaf-bernino-sans","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif;
|
||||
background-color: #fff;
|
||||
}
|
||||
ul, ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@import "navigation.less";
|
||||
@import "main.less";
|
||||
@import "footer.less";
|
||||
@@ -0,0 +1,302 @@
|
||||
@import "common.less";
|
||||
|
||||
.main {
|
||||
padding: 20px 20px;
|
||||
margin-left: @navWidth;
|
||||
.page-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
font-size: 1.6em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
dd {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
h4.name {
|
||||
span.type-signature {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: gray;
|
||||
color: #fff;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
span.type {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
span.glyphicon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
color: #e1e1e1;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
span.returnType {
|
||||
margin-left: 3px;
|
||||
background-color: transparent!important;
|
||||
color: gray!important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
span.static {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: @colorSubtitle!important;
|
||||
color: #fff;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span.number {
|
||||
background-color: gray!important;
|
||||
}
|
||||
|
||||
span.string {
|
||||
background-color: gray!important;
|
||||
}
|
||||
|
||||
span.object {
|
||||
background-color: @colorLink!important;
|
||||
}
|
||||
|
||||
span.array {
|
||||
background-color: @colorLink!important;
|
||||
}
|
||||
|
||||
span.boolean {
|
||||
background-color: @colorRed!important;
|
||||
}
|
||||
|
||||
.subsection-title {
|
||||
font-size: 14px;
|
||||
margin-top: 30px;
|
||||
color: @colorSubtitle;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-top: 10px;
|
||||
// .font-description();
|
||||
font-size: 13px;
|
||||
|
||||
ul, ol {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #efefef;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-source {
|
||||
font-size: 12px;
|
||||
}
|
||||
dt.tag-source {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
dt.tag-todo {
|
||||
font-size: 10px;
|
||||
display: inline-block;
|
||||
background-color: @colorLink;
|
||||
color: #fff;
|
||||
padding: 2px 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.type-signature {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tag-deprecated {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.important {
|
||||
background-color: @colorRed;
|
||||
color: #fff;
|
||||
padding: 2px 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.nameContainer {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
padding-top: 5px;
|
||||
border-top: 1px solid #e1e1e1;
|
||||
|
||||
.inherited {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: #888!important;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 5px;
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-source {
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
right: 0;
|
||||
font-size: 10px;
|
||||
a {
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
&.inherited {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-right: 150px;
|
||||
line-height: 1.3;
|
||||
|
||||
.signature {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
|
||||
}
|
||||
|
||||
.type-signature.type a {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
|
||||
th {
|
||||
padding: 3px 3px;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
padding: 5px 3px;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.type {
|
||||
width: 60px;
|
||||
color: #aaa;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.attributes {
|
||||
width: 80px;
|
||||
color: #aaa;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 12px;
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.optional {
|
||||
float: left;
|
||||
border-radius: 3px;
|
||||
background-color: #ddd!important;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 5px;
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
.readme {
|
||||
p {
|
||||
margin-top: 15px;
|
||||
line-height: 1.2;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 0.9em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
article {
|
||||
ol, ul {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
ol > li {
|
||||
list-style-type: decimal;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
ul > li {
|
||||
margin-bottom: 5px;
|
||||
list-style-type: disc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
@import "common.less";
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: gray;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
position: fixed;
|
||||
float: left;
|
||||
width: @navWidth;
|
||||
height: 100%;
|
||||
background-color: @colorBgNavi;
|
||||
|
||||
.applicationName {
|
||||
margin: 0;
|
||||
margin-top: 15px;
|
||||
padding: 10px 15px;
|
||||
font: bold 1.25em Helvetica;
|
||||
color: #fff;
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
padding: 10px 15px;
|
||||
|
||||
input {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
border-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
padding: 10px 15px 0 15px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
li.item {
|
||||
margin-bottom: 8px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #555;
|
||||
|
||||
a {
|
||||
color: #bbb;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.title {
|
||||
cursor: pointer;
|
||||
color: #ddd;
|
||||
position: relative;
|
||||
a {
|
||||
color: #e1e1e1;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
display: block;
|
||||
font-size: 1.1em;
|
||||
color:#fff;
|
||||
|
||||
.static {
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
background-color: @colorSubtitle;
|
||||
color: #000;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin-top: 10px;
|
||||
font: bold 0.8em Helvetica;
|
||||
color: @colorSubtitle;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
ul {
|
||||
& > li {
|
||||
font-size: 0.85em;
|
||||
padding-left: 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.itemMembers {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "jaguarjs-jsdoc",
|
||||
"version": "0.0.1",
|
||||
"description": "Jaguar.js template for JSDoc 3",
|
||||
"main": "Gruntfile.js",
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"connect-livereload": "~0.3.2",
|
||||
"grunt": "~0.4.2",
|
||||
"grunt-contrib-clean": "~0.5.0",
|
||||
"grunt-contrib-copy": "~0.5.0",
|
||||
"grunt-contrib-less": "~0.9.0",
|
||||
"grunt-contrib-uglify": "~0.2.7",
|
||||
"grunt-contrib-watch": "~0.5.3",
|
||||
"grunt-jsdoc": "~0.5.1",
|
||||
"grunt-contrib-connect": "~0.6.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/davidshimjs/jaguarjs-jsdoc.git"
|
||||
},
|
||||
"keywords": [
|
||||
"jsdoc",
|
||||
"jsdoc3",
|
||||
"jaguar.js",
|
||||
"template"
|
||||
],
|
||||
"author": "davidshimjs",
|
||||
"license": "MIT",
|
||||
"readmeFilename": "README.md",
|
||||
"bugs": {
|
||||
"url": "https://github.com/davidshimjs/jaguarjs-jsdoc/issues"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,545 @@
|
||||
/*global env: true */
|
||||
var template = require('jsdoc/template'),
|
||||
fs = require('jsdoc/fs'),
|
||||
path = require('jsdoc/path'),
|
||||
taffy = require('taffydb').taffy,
|
||||
handle = require('jsdoc/util/error').handle,
|
||||
helper = require('jsdoc/util/templateHelper'),
|
||||
_ = require('underscore'),
|
||||
htmlsafe = helper.htmlsafe,
|
||||
linkto = helper.linkto,
|
||||
resolveAuthorLinks = helper.resolveAuthorLinks,
|
||||
scopeToPunc = helper.scopeToPunc,
|
||||
hasOwnProp = Object.prototype.hasOwnProperty,
|
||||
data,
|
||||
view,
|
||||
outdir = env.opts.destination;
|
||||
|
||||
function find(spec) {
|
||||
return helper.find(data, spec);
|
||||
}
|
||||
|
||||
function tutoriallink(tutorial) {
|
||||
return helper.toTutorial(tutorial, null, { tag: 'em', classname: 'disabled', prefix: 'Tutorial: ' });
|
||||
}
|
||||
|
||||
function getAncestorLinks(doclet) {
|
||||
return helper.getAncestorLinks(data, doclet);
|
||||
}
|
||||
|
||||
function hashToLink(doclet, hash) {
|
||||
if ( !/^(#.+)/.test(hash) ) { return hash; }
|
||||
|
||||
var url = helper.createLink(doclet);
|
||||
|
||||
url = url.replace(/(#.+|$)/, hash);
|
||||
return '<a href="' + url + '">' + hash + '</a>';
|
||||
}
|
||||
|
||||
function needsSignature(doclet) {
|
||||
var needsSig = false;
|
||||
|
||||
// function and class definitions always get a signature
|
||||
if (doclet.kind === 'function' || doclet.kind === 'class') {
|
||||
needsSig = true;
|
||||
}
|
||||
// typedefs that contain functions get a signature, too
|
||||
else if (doclet.kind === 'typedef' && doclet.type && doclet.type.names &&
|
||||
doclet.type.names.length) {
|
||||
for (var i = 0, l = doclet.type.names.length; i < l; i++) {
|
||||
if (doclet.type.names[i].toLowerCase() === 'function') {
|
||||
needsSig = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return needsSig;
|
||||
}
|
||||
|
||||
function addSignatureParams(f) {
|
||||
var params = helper.getSignatureParams(f, 'optional');
|
||||
|
||||
f.signature = (f.signature || '') + '('+params.join(', ')+')';
|
||||
}
|
||||
|
||||
function addSignatureReturns(f) {
|
||||
var returnTypes = helper.getSignatureReturns(f);
|
||||
|
||||
f.signature = '<span class="signature">'+(f.signature || '') + '</span>';
|
||||
|
||||
if (returnTypes.length) {
|
||||
f.signature += '<span class="glyphicon glyphicon-circle-arrow-right"></span><span class="type-signature returnType">'+(returnTypes.length ? '{'+returnTypes.join('|')+'}' : '')+'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
function addSignatureTypes(f) {
|
||||
var types = helper.getSignatureTypes(f);
|
||||
|
||||
f.signature = (f.signature || '') + '<span class="type-signature">'+(types.length? ' :'+types.join('|') : '')+'</span>';
|
||||
}
|
||||
|
||||
function addAttribs(f) {
|
||||
var attribs = helper.getAttribs(f);
|
||||
|
||||
if (attribs.length) {
|
||||
f.attribs = '<span class="type-signature ' + (attribs[0] === 'static' ? 'static' : '') + '">' + htmlsafe(attribs.length ? attribs.join(',') : '') + '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
function shortenPaths(files, commonPrefix) {
|
||||
// always use forward slashes
|
||||
var regexp = new RegExp('\\\\', 'g');
|
||||
|
||||
Object.keys(files).forEach(function(file) {
|
||||
files[file].shortened = files[file].resolved.replace(commonPrefix, '')
|
||||
.replace(regexp, '/');
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
function resolveSourcePath(filepath) {
|
||||
return path.resolve(process.cwd(), filepath);
|
||||
}
|
||||
|
||||
function getPathFromDoclet(doclet) {
|
||||
if (!doclet.meta) {
|
||||
return;
|
||||
}
|
||||
|
||||
var filepath = doclet.meta.path && doclet.meta.path !== 'null' ?
|
||||
doclet.meta.path + '/' + doclet.meta.filename :
|
||||
doclet.meta.filename;
|
||||
|
||||
return filepath;
|
||||
}
|
||||
|
||||
function generate(title, docs, filename, resolveLinks) {
|
||||
resolveLinks = resolveLinks === false ? false : true;
|
||||
|
||||
var docData = {
|
||||
filename: filename,
|
||||
title: title,
|
||||
docs: docs
|
||||
};
|
||||
|
||||
var outpath = path.join(outdir, filename),
|
||||
html = view.render('container.tmpl', docData);
|
||||
|
||||
if (resolveLinks) {
|
||||
html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
|
||||
|
||||
// Add a link target for external links @davidshimjs
|
||||
html = html.toString().replace(/<a\s+([^>]*href\s*=\s*['"]*[^\s'"]*:\/\/)/ig, '<a target="_blank" $1');
|
||||
}
|
||||
|
||||
fs.writeFileSync(outpath, html, 'utf8');
|
||||
}
|
||||
|
||||
function generateSourceFiles(sourceFiles) {
|
||||
Object.keys(sourceFiles).forEach(function(file) {
|
||||
var source;
|
||||
// links are keyed to the shortened path in each doclet's `meta.filename` property
|
||||
var sourceOutfile = helper.getUniqueFilename(sourceFiles[file].shortened);
|
||||
helper.registerLink(sourceFiles[file].shortened, sourceOutfile);
|
||||
|
||||
try {
|
||||
source = {
|
||||
kind: 'source',
|
||||
code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, 'utf8') )
|
||||
};
|
||||
}
|
||||
catch(e) {
|
||||
handle(e);
|
||||
}
|
||||
|
||||
generate('Source: ' + sourceFiles[file].shortened, [source], sourceOutfile,
|
||||
false);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for classes or functions with the same name as modules (which indicates that the module
|
||||
* exports only that class or function), then attach the classes or functions to the `module`
|
||||
* property of the appropriate module doclets. The name of each class or function is also updated
|
||||
* for display purposes. This function mutates the original arrays.
|
||||
*
|
||||
* @private
|
||||
* @param {Array.<module:jsdoc/doclet.Doclet>} doclets - The array of classes and functions to
|
||||
* check.
|
||||
* @param {Array.<module:jsdoc/doclet.Doclet>} modules - The array of module doclets to search.
|
||||
*/
|
||||
function attachModuleSymbols(doclets, modules) {
|
||||
var symbols = {};
|
||||
|
||||
// build a lookup table
|
||||
doclets.forEach(function(symbol) {
|
||||
symbols[symbol.longname] = symbol;
|
||||
});
|
||||
|
||||
return modules.map(function(module) {
|
||||
if (symbols[module.longname]) {
|
||||
module.module = symbols[module.longname];
|
||||
module.module.name = module.module.name.replace('module:', 'require("') + '")';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the navigation sidebar.
|
||||
* @param {object} members The members that will be used to create the sidebar.
|
||||
* @param {array<object>} members.classes
|
||||
* @param {array<object>} members.externals
|
||||
* @param {array<object>} members.globals
|
||||
* @param {array<object>} members.mixins
|
||||
* @param {array<object>} members.modules
|
||||
* @param {array<object>} members.namespaces
|
||||
* @param {array<object>} members.tutorials
|
||||
* @param {array<object>} members.events
|
||||
* @return {string} The HTML for the navigation sidebar.
|
||||
*/
|
||||
function buildNav(members) {
|
||||
var nav = [];
|
||||
|
||||
if (members.namespaces.length) {
|
||||
_.each(members.namespaces, function (v) {
|
||||
nav.push({
|
||||
type: 'namespace',
|
||||
longname: v.longname,
|
||||
name: v.name,
|
||||
members: find({
|
||||
kind: 'member',
|
||||
memberof: v.longname
|
||||
}),
|
||||
methods: find({
|
||||
kind: 'function',
|
||||
memberof: v.longname
|
||||
}),
|
||||
typedefs: find({
|
||||
kind: 'typedef',
|
||||
memberof: v.longname
|
||||
}),
|
||||
events: find({
|
||||
kind: 'event',
|
||||
memberof: v.longname
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (members.classes.length) {
|
||||
_.each(members.classes, function (v) {
|
||||
nav.push({
|
||||
type: 'class',
|
||||
longname: v.longname,
|
||||
name: v.name,
|
||||
members: find({
|
||||
kind: 'member',
|
||||
memberof: v.longname
|
||||
}),
|
||||
methods: find({
|
||||
kind: 'function',
|
||||
memberof: v.longname
|
||||
}),
|
||||
typedefs: find({
|
||||
kind: 'typedef',
|
||||
memberof: v.longname
|
||||
}),
|
||||
events: find({
|
||||
kind: 'event',
|
||||
memberof: v.longname
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (members.modules.length) {
|
||||
_.each(members.modules, function (v) {
|
||||
nav.push({
|
||||
type: 'class',
|
||||
longname: v.name,
|
||||
name: v.name,
|
||||
members: find({
|
||||
kind: 'member',
|
||||
memberof: v.longname
|
||||
}),
|
||||
methods: find({
|
||||
kind: 'function',
|
||||
memberof: v.longname
|
||||
}),
|
||||
typedefs: find({
|
||||
kind: 'typedef',
|
||||
memberof: v.longname
|
||||
}),
|
||||
events: find({
|
||||
kind: 'event',
|
||||
memberof: v.longname
|
||||
})
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return nav;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@param {TAFFY} taffyData See <http://taffydb.com/>.
|
||||
@param {object} opts
|
||||
@param {Tutorial} tutorials
|
||||
*/
|
||||
exports.publish = function(taffyData, opts, tutorials) {
|
||||
data = taffyData;
|
||||
|
||||
var conf = env.conf.templates || {};
|
||||
conf['default'] = conf['default'] || {};
|
||||
|
||||
var templatePath = opts.template;
|
||||
view = new template.Template(templatePath + '/tmpl');
|
||||
|
||||
// claim some special filenames in advance, so the All-Powerful Overseer of Filename Uniqueness
|
||||
// doesn't try to hand them out later
|
||||
var indexUrl = helper.getUniqueFilename('index');
|
||||
// don't call registerLink() on this one! 'index' is also a valid longname
|
||||
|
||||
var globalUrl = helper.getUniqueFilename('global');
|
||||
helper.registerLink('global', globalUrl);
|
||||
|
||||
// set up templating
|
||||
view.layout = 'layout.tmpl';
|
||||
|
||||
// set up tutorials for helper
|
||||
helper.setTutorials(tutorials);
|
||||
|
||||
data = helper.prune(data);
|
||||
data.sort('longname, version, since');
|
||||
helper.addEventListeners(data);
|
||||
|
||||
var sourceFiles = {};
|
||||
var sourceFilePaths = [];
|
||||
data().each(function(doclet) {
|
||||
doclet.attribs = '';
|
||||
|
||||
if (doclet.examples) {
|
||||
doclet.examples = doclet.examples.map(function(example) {
|
||||
var caption, code;
|
||||
|
||||
if (example.match(/^\s*(?:<p>)?\s*<caption>([\s\S]+?)<\/caption>\s*(?:<\/p>)?[\s\r\n]*([\s\S]+)$/i)) {
|
||||
caption = RegExp.$1;
|
||||
code = RegExp.$2;
|
||||
}
|
||||
|
||||
return {
|
||||
caption: caption || '',
|
||||
code: code || example
|
||||
};
|
||||
});
|
||||
}
|
||||
if (doclet.see) {
|
||||
doclet.see.forEach(function(seeItem, i) {
|
||||
doclet.see[i] = hashToLink(doclet, seeItem);
|
||||
});
|
||||
}
|
||||
|
||||
// build a list of source files
|
||||
var sourcePath;
|
||||
var resolvedSourcePath;
|
||||
if (doclet.meta) {
|
||||
sourcePath = getPathFromDoclet(doclet);
|
||||
resolvedSourcePath = resolveSourcePath(sourcePath);
|
||||
sourceFiles[sourcePath] = {
|
||||
resolved: resolvedSourcePath,
|
||||
shortened: null
|
||||
};
|
||||
sourceFilePaths.push(resolvedSourcePath);
|
||||
}
|
||||
});
|
||||
|
||||
// update outdir if necessary, then create outdir
|
||||
var packageInfo = ( find({kind: 'package'}) || [] ) [0];
|
||||
if (packageInfo && packageInfo.name) {
|
||||
outdir = path.join(outdir, packageInfo.name, packageInfo.version);
|
||||
}
|
||||
fs.mkPath(outdir);
|
||||
|
||||
// copy the template's static files to outdir
|
||||
var fromDir = path.join(templatePath, 'static');
|
||||
var staticFiles = fs.ls(fromDir, 3);
|
||||
|
||||
staticFiles.forEach(function(fileName) {
|
||||
var toDir = fs.toDir( fileName.replace(fromDir, outdir) );
|
||||
fs.mkPath(toDir);
|
||||
fs.copyFileSync(fileName, toDir);
|
||||
});
|
||||
|
||||
// copy user-specified static files to outdir
|
||||
var staticFilePaths;
|
||||
var staticFileFilter;
|
||||
var staticFileScanner;
|
||||
if (conf['default'].staticFiles) {
|
||||
staticFilePaths = conf['default'].staticFiles.paths || [];
|
||||
staticFileFilter = new (require('jsdoc/src/filter')).Filter(conf['default'].staticFiles);
|
||||
staticFileScanner = new (require('jsdoc/src/scanner')).Scanner();
|
||||
|
||||
staticFilePaths.forEach(function(filePath) {
|
||||
var extraStaticFiles = staticFileScanner.scan([filePath], 10, staticFileFilter);
|
||||
|
||||
extraStaticFiles.forEach(function(fileName) {
|
||||
var sourcePath = fs.statSync(filePath).isDirectory() ? filePath :
|
||||
path.dirname(filePath);
|
||||
var toDir = fs.toDir( fileName.replace(sourcePath, outdir) );
|
||||
fs.mkPath(toDir);
|
||||
fs.copyFileSync(fileName, toDir);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (sourceFilePaths.length) {
|
||||
sourceFiles = shortenPaths( sourceFiles, path.commonPrefix(sourceFilePaths) );
|
||||
}
|
||||
data().each(function(doclet) {
|
||||
var url = helper.createLink(doclet);
|
||||
helper.registerLink(doclet.longname, url);
|
||||
|
||||
// replace the filename with a shortened version of the full path
|
||||
var docletPath;
|
||||
if (doclet.meta) {
|
||||
docletPath = getPathFromDoclet(doclet);
|
||||
docletPath = sourceFiles[docletPath].shortened;
|
||||
if (docletPath) {
|
||||
doclet.meta.filename = docletPath;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
data().each(function(doclet) {
|
||||
var url = helper.longnameToUrl[doclet.longname];
|
||||
|
||||
if (url.indexOf('#') > -1) {
|
||||
doclet.id = helper.longnameToUrl[doclet.longname].split(/#/).pop();
|
||||
}
|
||||
else {
|
||||
doclet.id = doclet.name;
|
||||
}
|
||||
|
||||
if ( needsSignature(doclet) ) {
|
||||
addSignatureParams(doclet);
|
||||
addSignatureReturns(doclet);
|
||||
addAttribs(doclet);
|
||||
}
|
||||
});
|
||||
|
||||
// do this after the urls have all been generated
|
||||
data().each(function(doclet) {
|
||||
doclet.ancestors = getAncestorLinks(doclet);
|
||||
|
||||
if (doclet.kind === 'member') {
|
||||
addSignatureTypes(doclet);
|
||||
addAttribs(doclet);
|
||||
}
|
||||
|
||||
if (doclet.kind === 'constant') {
|
||||
addSignatureTypes(doclet);
|
||||
addAttribs(doclet);
|
||||
doclet.kind = 'member';
|
||||
}
|
||||
});
|
||||
|
||||
var members = helper.getMembers(data);
|
||||
members.tutorials = tutorials.children;
|
||||
|
||||
// add template helpers
|
||||
view.find = find;
|
||||
view.linkto = linkto;
|
||||
view.resolveAuthorLinks = resolveAuthorLinks;
|
||||
view.tutoriallink = tutoriallink;
|
||||
view.htmlsafe = htmlsafe;
|
||||
view.members = members; //@davidshimjs: To make navigation for customizing
|
||||
|
||||
// once for all
|
||||
view.nav = buildNav(members);
|
||||
attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }),
|
||||
members.modules );
|
||||
|
||||
// only output pretty-printed source files if requested; do this before generating any other
|
||||
// pages, so the other pages can link to the source files
|
||||
if (conf['default'].outputSourceFiles) {
|
||||
generateSourceFiles(sourceFiles);
|
||||
}
|
||||
|
||||
if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); }
|
||||
|
||||
// index page displays information from package.json and lists files
|
||||
var files = find({kind: 'file'}),
|
||||
packages = find({kind: 'package'});
|
||||
|
||||
generate('Index',
|
||||
packages.concat(
|
||||
[{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}]
|
||||
).concat(files),
|
||||
indexUrl);
|
||||
|
||||
// set up the lists that we'll use to generate pages
|
||||
var classes = taffy(members.classes);
|
||||
var modules = taffy(members.modules);
|
||||
var namespaces = taffy(members.namespaces);
|
||||
var mixins = taffy(members.mixins);
|
||||
var externals = taffy(members.externals);
|
||||
|
||||
for (var longname in helper.longnameToUrl) {
|
||||
if ( hasOwnProp.call(helper.longnameToUrl, longname) ) {
|
||||
var myClasses = helper.find(classes, {longname: longname});
|
||||
if (myClasses.length) {
|
||||
generate('Class: ' + myClasses[0].name, myClasses, helper.longnameToUrl[longname]);
|
||||
}
|
||||
|
||||
var myModules = helper.find(modules, {longname: longname});
|
||||
if (myModules.length) {
|
||||
generate('Module: ' + myModules[0].name, myModules, helper.longnameToUrl[longname]);
|
||||
}
|
||||
|
||||
var myNamespaces = helper.find(namespaces, {longname: longname});
|
||||
if (myNamespaces.length) {
|
||||
generate('Namespace: ' + myNamespaces[0].name, myNamespaces, helper.longnameToUrl[longname]);
|
||||
}
|
||||
|
||||
var myMixins = helper.find(mixins, {longname: longname});
|
||||
if (myMixins.length) {
|
||||
generate('Mixin: ' + myMixins[0].name, myMixins, helper.longnameToUrl[longname]);
|
||||
}
|
||||
|
||||
var myExternals = helper.find(externals, {longname: longname});
|
||||
if (myExternals.length) {
|
||||
generate('External: ' + myExternals[0].name, myExternals, helper.longnameToUrl[longname]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: move the tutorial functions to templateHelper.js
|
||||
function generateTutorial(title, tutorial, filename) {
|
||||
var tutorialData = {
|
||||
title: title,
|
||||
header: tutorial.title,
|
||||
content: tutorial.parse(),
|
||||
children: tutorial.children
|
||||
};
|
||||
|
||||
var tutorialPath = path.join(outdir, filename),
|
||||
html = view.render('tutorial.tmpl', tutorialData);
|
||||
|
||||
// yes, you can use {@link} in tutorials too!
|
||||
html = helper.resolveLinks(html); // turn {@link foo} into <a href="foodoc.html">foo</a>
|
||||
|
||||
fs.writeFileSync(tutorialPath, html, 'utf8');
|
||||
}
|
||||
|
||||
// tutorials can have only one parent so there is no risk for loops
|
||||
function saveChildren(node) {
|
||||
node.children.forEach(function(child) {
|
||||
generateTutorial('Tutorial: ' + child.title, child, helper.tutorialToUrl(child.name));
|
||||
saveChildren(child);
|
||||
});
|
||||
}
|
||||
saveChildren(tutorials);
|
||||
};
|
||||
Binary file not shown.
@@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph />
|
||||
<glyph />
|
||||
<glyph unicode="
" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
|
||||
<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="434" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="163" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
|
||||
<glyph unicode="−" d="M200 400h900v300h-900v-300z" />
|
||||
<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
|
||||
<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
|
||||
<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
|
||||
<glyph unicode="" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
|
||||
<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q17 -55 85.5 -75.5t147.5 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
|
||||
<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
|
||||
<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
|
||||
<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
|
||||
<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
|
||||
<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 299q-120 -77 -261 -77q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
|
||||
<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
|
||||
<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
|
||||
<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
|
||||
<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
|
||||
<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
|
||||
<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
|
||||
<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
|
||||
<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
|
||||
<glyph unicode="" d="M0 25v475l200 700h800q199 -700 200 -700v-475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
|
||||
<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
|
||||
<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
|
||||
<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
|
||||
<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
|
||||
<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
|
||||
<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
|
||||
<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
|
||||
<glyph unicode="" d="M1 700v475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
|
||||
<glyph unicode="" d="M2 700v475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
|
||||
<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
|
||||
<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
|
||||
<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
|
||||
<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
|
||||
<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v70h471q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
|
||||
<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
|
||||
<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
|
||||
<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
|
||||
<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
|
||||
<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
|
||||
<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
|
||||
<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 138.5t-64 210.5zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l566 567l-136 137l-430 -431l-147 147z" />
|
||||
<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
|
||||
<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
|
||||
<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" />
|
||||
<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
|
||||
<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
|
||||
<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
|
||||
<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
|
||||
<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM300 500h600v200h-600v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM363 700h144q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5q19 0 30 -10t11 -26 q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-105 0 -172 -56t-67 -183zM500 300h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 500v200h194q15 60 36 104.5t55.5 86t88 69t126.5 40.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200 v-206q149 48 201 206h-201v200h200q-25 74 -76 127.5t-124 76.5v-204h-200v203q-75 -24 -130 -77.5t-79 -125.5h209v-200h-210z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
|
||||
<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" />
|
||||
<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
|
||||
<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
|
||||
<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" />
|
||||
<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
|
||||
<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-33 14.5h-207q-20 0 -32 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111v6t-1 15t-3 18l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6h-111v-100z M100 0h400v400h-400v-400zM200 900q-3 0 14 48t35 96l18 47l214 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
|
||||
<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
|
||||
<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
|
||||
<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 33 -48 36t-48 -29l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -21 -13 -29t-32 1l-94 78h-222l-94 -78q-19 -9 -32 -1t-13 29v64 q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
|
||||
<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
|
||||
<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
|
||||
<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
|
||||
<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
|
||||
<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
|
||||
<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
|
||||
<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
|
||||
<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
|
||||
<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
|
||||
<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
|
||||
<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM99 500v250v5q0 13 0.5 18.5t2.5 13t8 10.5t15 3h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35q-56 337 -56 351z M1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-22 -9 -63 -23t-167.5 -37 t-251.5 -23t-245.5 20.5t-178.5 41.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
|
||||
<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
|
||||
<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q123 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 212l100 213h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
|
||||
<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q123 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
|
||||
<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
|
||||
<glyph unicode="" d="M-101 651q0 72 54 110t139 37h302l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 16.5 -10.5t26 -26t16.5 -36.5v-526q0 -13 -85.5 -93.5t-93.5 -80.5h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l106 89v502l-342 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM999 201v600h200v-600h-200z" />
|
||||
<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6v7.5v7v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M1 585q-15 -31 7 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85l-1 -302q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM76 565l237 339h503l89 -100v-294l-340 -130 q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 500h300l-2 -194l402 294l-402 298v-197h-298v-201z" />
|
||||
<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l400 -294v194h302v201h-300v197z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -34 5.5 -93t7.5 -87q0 -9 17 -44t16 -60q12 0 23 -5.5 t23 -15t20 -13.5q20 -10 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55.5t-20 -57.5q12 -21 22.5 -34.5t28 -27t36.5 -17.5q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q101 -2 221 111q31 30 47 48t34 49t21 62q-14 9 -37.5 9.5t-35.5 7.5q-14 7 -49 15t-52 19 q-9 0 -39.5 -0.5t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q8 16 22 22q6 -1 26 -1.5t33.5 -4.5t19.5 -13q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5 t5.5 57.5q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 41 1 44q31 -13 58.5 -14.5t39.5 3.5l11 4q6 36 -17 53.5t-64 28.5t-56 23 q-19 -3 -37 0q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -46 0t-45 -3q-20 -6 -51.5 -25.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79zM518 915q3 12 16 30.5t16 25.5q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -18 8 -42.5t16.5 -44 t9.5 -23.5q-6 1 -39 5t-53.5 10t-36.5 16z" />
|
||||
<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
|
||||
<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
|
||||
<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM513 609q0 32 21 56.5t52 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-16 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5q-37 0 -62.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
|
||||
<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -79.5 -17t-67.5 -51l-388 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23q38 0 53 -36 q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60l517 511 q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
|
||||
<glyph unicode="" d="M79 784q0 131 99 229.5t230 98.5q144 0 242 -129q103 129 245 129q130 0 227 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100l-84.5 84.5t-68 74t-60 78t-33.5 70.5t-15 78z M250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-106 48.5q-73 0 -131 -83l-118 -171l-114 174q-51 80 -124 80q-59 0 -108.5 -49.5t-49.5 -118.5z" />
|
||||
<glyph unicode="" d="M57 353q0 -94 66 -160l141 -141q66 -66 159 -66q95 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-12 12 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141l19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -18q46 -46 77 -99l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
|
||||
<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
|
||||
<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
|
||||
<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335l-27 7q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5v-307l64 -14 q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5zM700 237 q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
|
||||
<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -11 2.5 -24.5t5.5 -24t9.5 -26.5t10.5 -25t14 -27.5t14 -25.5 t15.5 -27t13.5 -24h242v-100h-197q8 -50 -2.5 -115t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q32 1 102 -16t104 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10 t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5t-30 142.5h-221z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
|
||||
<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
|
||||
<glyph unicode="" d="M216 519q10 -19 32 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8l9 -1q13 0 26 16l538 630q15 19 6 36q-8 18 -32 16h-300q1 4 78 219.5t79 227.5q2 17 -6 27l-8 8h-9q-16 0 -25 -15q-4 -5 -98.5 -111.5t-228 -257t-209.5 -238.5q-17 -19 -7 -40z" />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 401h700v699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l248 -237v700h-699zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
|
||||
<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -117q-25 -16 -43.5 -50.5t-18.5 -65.5v-359z" />
|
||||
<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
|
||||
<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
|
||||
<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q16 17 13 40.5t-22 37.5l-192 136q-19 14 -45 12t-42 -19l-119 -118q-143 103 -267 227q-126 126 -227 268l118 118q17 17 20 41.5 t-11 44.5l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
|
||||
<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -15 -35.5t-35 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
|
||||
<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
|
||||
<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
|
||||
<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300 h200l-300 -300z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104t60.5 178q0 121 -85 207.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
|
||||
<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
|
||||
<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -12t1 -11q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,29 @@
|
||||
(function() {
|
||||
var counter = 0;
|
||||
var numbered;
|
||||
var source = document.getElementsByClassName('prettyprint source');
|
||||
|
||||
if (source && source[0]) {
|
||||
var linenums = config.linenums;
|
||||
|
||||
if (linenums) {
|
||||
source = source[0].getElementsByTagName('ol')[0];
|
||||
|
||||
numbered = Array.prototype.slice.apply(source.children);
|
||||
numbered = numbered.map(function(item) {
|
||||
counter++;
|
||||
item.id = 'line' + counter;
|
||||
});
|
||||
} else {
|
||||
source = source[0].getElementsByTagName('code')[0];
|
||||
|
||||
numbered = source.innerHTML.split('\n');
|
||||
numbered = numbered.map(function(item) {
|
||||
counter++;
|
||||
return '<span id="line' + counter + '"></span>' + item;
|
||||
});
|
||||
|
||||
source.innerHTML = numbered.join('\n');
|
||||
}
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,69 @@
|
||||
$(function () {
|
||||
// Search Items
|
||||
$('#search').on('keyup', function (e) {
|
||||
var value = $(this).val();
|
||||
var $el = $('.navigation');
|
||||
|
||||
if (value) {
|
||||
var regexp = new RegExp(value, 'i');
|
||||
$el.find('li, .itemMembers').hide();
|
||||
|
||||
$el.find('li').each(function (i, v) {
|
||||
var $item = $(v);
|
||||
|
||||
if ($item.data('name') && regexp.test($item.data('name'))) {
|
||||
$item.show();
|
||||
$item.closest('.itemMembers').show();
|
||||
$item.closest('.item').show();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$el.find('.item, .itemMembers').show();
|
||||
}
|
||||
|
||||
$el.find('.list').scrollTop(0);
|
||||
});
|
||||
|
||||
// Toggle when click an item element
|
||||
$('.navigation').on('click', '.title', function (e) {
|
||||
$(this).parent().find('.itemMembers').toggle();
|
||||
});
|
||||
|
||||
// Show an item related a current documentation automatically
|
||||
var filename = $('.page-title').data('filename').replace(/\.[a-z]+$/, '');
|
||||
var $currentItem = $('.navigation .item[data-name*="' + filename + '"]:eq(0)');
|
||||
|
||||
if ($currentItem.length) {
|
||||
$currentItem
|
||||
.remove()
|
||||
.prependTo('.navigation .list')
|
||||
.show()
|
||||
.find('.itemMembers')
|
||||
.show();
|
||||
}
|
||||
|
||||
// Auto resizing on navigation
|
||||
var _onResize = function () {
|
||||
var height = $(window).height();
|
||||
var $el = $('.navigation');
|
||||
|
||||
$el.height(height).find('.list').height(height - 133);
|
||||
};
|
||||
|
||||
$(window).on('resize', _onResize);
|
||||
_onResize();
|
||||
|
||||
// disqus code
|
||||
if (config.disqus) {
|
||||
$(window).on('load', function () {
|
||||
var disqus_shortname = config.disqus; // required: replace example with your forum shortname
|
||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
||||
dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
||||
var s = document.createElement('script'); s.async = true;
|
||||
s.type = 'text/javascript';
|
||||
s.src = 'http://' + disqus_shortname + '.disqus.com/count.js';
|
||||
document.getElementsByTagName('BODY')[0].appendChild(s);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,2 @@
|
||||
PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com",
|
||||
/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]);
|
||||
@@ -0,0 +1,28 @@
|
||||
var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
|
||||
(function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
|
||||
[],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
|
||||
f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
|
||||
(j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
|
||||
{b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
|
||||
t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
|
||||
"string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
|
||||
l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
|
||||
q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
|
||||
q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
|
||||
"");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
|
||||
a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
|
||||
for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
|
||||
m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
|
||||
a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
|
||||
j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
|
||||
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
|
||||
H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
|
||||
J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
|
||||
I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
|
||||
["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
|
||||
/^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
|
||||
["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
|
||||
hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
|
||||
!k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
|
||||
250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
|
||||
PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,354 @@
|
||||
html,
|
||||
body {
|
||||
font: 1em "jaf-bernino-sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
|
||||
background-color: #fff;
|
||||
}
|
||||
ul,
|
||||
ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
list-style-type: none;
|
||||
}
|
||||
#wrap {
|
||||
position: relative;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
background-color: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: gray;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.navigation {
|
||||
position: fixed;
|
||||
float: left;
|
||||
width: 250px;
|
||||
height: 100%;
|
||||
background-color: #1a1a1a;
|
||||
}
|
||||
.navigation .applicationName {
|
||||
margin: 0;
|
||||
margin-top: 15px;
|
||||
padding: 10px 15px;
|
||||
font: bold 1.25em Helvetica;
|
||||
color: #fff;
|
||||
}
|
||||
.navigation .applicationName a {
|
||||
color: #fff;
|
||||
}
|
||||
.navigation .search {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
.navigation .search input {
|
||||
background-color: #ddd;
|
||||
color: #333;
|
||||
border-color: #555;
|
||||
}
|
||||
.navigation .list {
|
||||
padding: 10px 15px 0 15px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
.navigation li.item {
|
||||
margin-bottom: 8px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #555;
|
||||
}
|
||||
.navigation li.item a {
|
||||
color: #bbb;
|
||||
}
|
||||
.navigation li.item a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
.navigation li.item .title {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display: block;
|
||||
font-size: 1.1em;
|
||||
color:#fff;
|
||||
}
|
||||
.navigation li.item .title a {
|
||||
color: #e1e1e1;
|
||||
}
|
||||
.navigation li.item .title a:hover {
|
||||
color: #fff;
|
||||
}
|
||||
.navigation li.item .title .static {
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
background-color: #779c34;
|
||||
color: #000;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
float: right;
|
||||
}
|
||||
.navigation li.item .subtitle {
|
||||
margin-top: 10px;
|
||||
font: bold 0.8em Helvetica;
|
||||
color: #779c34;
|
||||
display: block;
|
||||
}
|
||||
.navigation li.item ul > li {
|
||||
font-size: 0.85em;
|
||||
padding-left: 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.navigation li.item .itemMembers {
|
||||
display: none;
|
||||
}
|
||||
.main {
|
||||
padding: 20px 20px;
|
||||
margin-left: 250px;
|
||||
}
|
||||
.main .page-title {
|
||||
display: none;
|
||||
}
|
||||
.main h1 {
|
||||
font-weight: bold;
|
||||
font-size: 1.6em;
|
||||
margin: 0;
|
||||
}
|
||||
.main h2 {
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
margin: 0;
|
||||
}
|
||||
.main h3 {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
.main h4 {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
}
|
||||
.main h5 {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
}
|
||||
.main dd {
|
||||
font-size: 12px;
|
||||
}
|
||||
.main h4.name span.type-signature {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: gray;
|
||||
color: #fff;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
.main h4.name span.type {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.main h4.name span.glyphicon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
color: #e1e1e1;
|
||||
margin-left: 7px;
|
||||
}
|
||||
.main h4.name span.returnType {
|
||||
margin-left: 3px;
|
||||
background-color: transparent!important;
|
||||
color: gray!important;
|
||||
}
|
||||
.main span.static {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: #779c34 !important;
|
||||
color: #fff;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.main span.number {
|
||||
background-color: gray!important;
|
||||
}
|
||||
.main span.string {
|
||||
background-color: gray!important;
|
||||
}
|
||||
.main span.object {
|
||||
background-color: #2a6496 !important;
|
||||
}
|
||||
.main span.array {
|
||||
background-color: #2a6496 !important;
|
||||
}
|
||||
.main span.boolean {
|
||||
background-color: #ee7d7d !important;
|
||||
}
|
||||
.main .subsection-title {
|
||||
font-size: 14px;
|
||||
margin-top: 30px;
|
||||
color: #779c34;
|
||||
}
|
||||
.main .description {
|
||||
margin-top: 10px;
|
||||
font-size: 13px;
|
||||
}
|
||||
.main .description ul,
|
||||
.main .description ol {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.main .description p {
|
||||
font-size: 13px;
|
||||
}
|
||||
.main .description h2 {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #efefef;
|
||||
}
|
||||
.main .description pre {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.main .tag-source {
|
||||
font-size: 12px;
|
||||
}
|
||||
.main dt.tag-source {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.main dt.tag-todo {
|
||||
font-size: 10px;
|
||||
display: inline-block;
|
||||
background-color: #2a6496;
|
||||
color: #fff;
|
||||
padding: 2px 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.main .type-signature {
|
||||
font-size: 12px;
|
||||
}
|
||||
.main .tag-deprecated {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
}
|
||||
.main .important {
|
||||
background-color: #ee7d7d;
|
||||
color: #fff;
|
||||
padding: 2px 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.main .nameContainer {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
padding-top: 5px;
|
||||
border-top: 1px solid #e1e1e1;
|
||||
}
|
||||
.main .nameContainer .inherited {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: #888!important;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.main .nameContainer .inherited a {
|
||||
color: #fff;
|
||||
}
|
||||
.main .nameContainer .tag-source {
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
right: 0;
|
||||
font-size: 10px;
|
||||
}
|
||||
.main .nameContainer .tag-source a {
|
||||
color: gray;
|
||||
}
|
||||
.main .nameContainer.inherited {
|
||||
color: gray;
|
||||
}
|
||||
.main .nameContainer h4 {
|
||||
margin-right: 150px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.main .nameContainer h4 .signature {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
.main .nameContainer h4 .type-signature.type a {
|
||||
color: #fff;
|
||||
}
|
||||
.main pre {
|
||||
font-size: 11px;
|
||||
}
|
||||
.main table {
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.main table th {
|
||||
padding: 3px 3px;
|
||||
}
|
||||
.main table td {
|
||||
vertical-align: top;
|
||||
padding: 5px 3px;
|
||||
}
|
||||
.main table .name {
|
||||
width: 110px;
|
||||
}
|
||||
.main table .type {
|
||||
width: 60px;
|
||||
color: #aaa;
|
||||
font-size: 11px;
|
||||
}
|
||||
.main table .attributes {
|
||||
width: 80px;
|
||||
color: #aaa;
|
||||
font-size: 11px;
|
||||
}
|
||||
.main table .description {
|
||||
font-size: 12px;
|
||||
}
|
||||
.main table .description p {
|
||||
margin: 0;
|
||||
}
|
||||
.main table .optional {
|
||||
float: left;
|
||||
border-radius: 3px;
|
||||
background-color: #ddd!important;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 5px;
|
||||
color: gray;
|
||||
}
|
||||
.main .readme p {
|
||||
margin-top: 15px;
|
||||
line-height: 1.2;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
.main .readme h1 {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
.main .readme h2 {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
}
|
||||
.main .readme li {
|
||||
font-size: 0.9em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.main article ol,
|
||||
.main article ul {
|
||||
margin-left: 25px;
|
||||
}
|
||||
.main article ol > li {
|
||||
list-style-type: decimal;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.main article ul > li {
|
||||
margin-bottom: 5px;
|
||||
list-style-type: disc;
|
||||
}
|
||||
footer {
|
||||
margin: 15px 0;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #e1e1e1;
|
||||
font-family: "freight-text-pro", Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
font-size: 0.8em;
|
||||
color: gray;
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/* JSDoc prettify.js theme */
|
||||
|
||||
/* plain text */
|
||||
.pln {
|
||||
color: #000000;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* string content */
|
||||
.str {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a keyword */
|
||||
.kwd {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a comment */
|
||||
.com {
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* a type name */
|
||||
.typ {
|
||||
color: #000000;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a literal value */
|
||||
.lit {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* punctuation */
|
||||
.pun {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* lisp open bracket */
|
||||
.opn {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* lisp close bracket */
|
||||
.clo {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a markup tag name */
|
||||
.tag {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a markup attribute name */
|
||||
.atn {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a markup attribute value */
|
||||
.atv {
|
||||
color: #006400;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a declaration */
|
||||
.dec {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a variable name */
|
||||
.var {
|
||||
color: #000000;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* a function name */
|
||||
.fun {
|
||||
color: #000000;
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/* Tomorrow Theme */
|
||||
/* Original theme - https://github.com/chriskempson/tomorrow-theme */
|
||||
/* Pretty printing styles. Used with prettify.js. */
|
||||
/* SPAN elements with the classes below are added by prettyprint. */
|
||||
/* plain text */
|
||||
.pln {
|
||||
color: #4d4d4c; }
|
||||
|
||||
@media screen {
|
||||
/* string content */
|
||||
.str {
|
||||
color: #718c00; }
|
||||
|
||||
/* a keyword */
|
||||
.kwd {
|
||||
color: #8959a8; }
|
||||
|
||||
/* a comment */
|
||||
.com {
|
||||
color: #8e908c; }
|
||||
|
||||
/* a type name */
|
||||
.typ {
|
||||
color: #4271ae; }
|
||||
|
||||
/* a literal value */
|
||||
.lit {
|
||||
color: #f5871f; }
|
||||
|
||||
/* punctuation */
|
||||
.pun {
|
||||
color: #4d4d4c; }
|
||||
|
||||
/* lisp open bracket */
|
||||
.opn {
|
||||
color: #4d4d4c; }
|
||||
|
||||
/* lisp close bracket */
|
||||
.clo {
|
||||
color: #4d4d4c; }
|
||||
|
||||
/* a markup tag name */
|
||||
.tag {
|
||||
color: #c82829; }
|
||||
|
||||
/* a markup attribute name */
|
||||
.atn {
|
||||
color: #f5871f; }
|
||||
|
||||
/* a markup attribute value */
|
||||
.atv {
|
||||
color: #3e999f; }
|
||||
|
||||
/* a declaration */
|
||||
.dec {
|
||||
color: #f5871f; }
|
||||
|
||||
/* a variable name */
|
||||
.var {
|
||||
color: #c82829; }
|
||||
|
||||
/* a function name */
|
||||
.fun {
|
||||
color: #4271ae; } }
|
||||
/* Use higher contrast and text-weight for printable form. */
|
||||
@media print, projection {
|
||||
.str {
|
||||
color: #060; }
|
||||
|
||||
.kwd {
|
||||
color: #006;
|
||||
font-weight: bold; }
|
||||
|
||||
.com {
|
||||
color: #600;
|
||||
font-style: italic; }
|
||||
|
||||
.typ {
|
||||
color: #404;
|
||||
font-weight: bold; }
|
||||
|
||||
.lit {
|
||||
color: #044; }
|
||||
|
||||
.pun, .opn, .clo {
|
||||
color: #440; }
|
||||
|
||||
.tag {
|
||||
color: #006;
|
||||
font-weight: bold; }
|
||||
|
||||
.atn {
|
||||
color: #404; }
|
||||
|
||||
.atv {
|
||||
color: #060; } }
|
||||
/* Style */
|
||||
/*
|
||||
pre.prettyprint {
|
||||
background: white;
|
||||
font-family: Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
border: 1px solid #ccc;
|
||||
padding: 10px; }
|
||||
*/
|
||||
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0; }
|
||||
|
||||
/* IE indents via margin-left */
|
||||
li.L0,
|
||||
li.L1,
|
||||
li.L2,
|
||||
li.L3,
|
||||
li.L4,
|
||||
li.L5,
|
||||
li.L6,
|
||||
li.L7,
|
||||
li.L8,
|
||||
li.L9 {
|
||||
/* */ }
|
||||
|
||||
/* Alternate shading for lines */
|
||||
li.L1,
|
||||
li.L3,
|
||||
li.L5,
|
||||
li.L7,
|
||||
li.L9 {
|
||||
/* */ }
|
||||
@@ -0,0 +1,154 @@
|
||||
<?js
|
||||
var self = this;
|
||||
docs.forEach(function(doc, i) {
|
||||
?>
|
||||
|
||||
<?js if (doc.kind === 'mainpage' || (doc.kind === 'package')) { ?>
|
||||
<?js= self.partial('mainpage.tmpl', doc) ?>
|
||||
<?js } else if (doc.kind === 'source') { ?>
|
||||
<?js= self.partial('source.tmpl', doc) ?>
|
||||
<?js } else { ?>
|
||||
|
||||
<section>
|
||||
|
||||
<header>
|
||||
<h2><?js if (doc.ancestors && doc.ancestors.length) { ?>
|
||||
<span class="ancestors"><?js= doc.ancestors.join('') ?></span>
|
||||
<?js } ?>
|
||||
<?js= doc.name ?>
|
||||
<?js if (doc.variation) { ?>
|
||||
<sup class="variation"><?js= doc.variation ?></sup>
|
||||
<?js } ?></h2>
|
||||
<?js if (doc.classdesc) { ?>
|
||||
<div class="class-description"><?js= doc.classdesc ?></div>
|
||||
<?js } ?>
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<div class="container-overview">
|
||||
<?js if (doc.kind === 'module' && doc.module) { ?>
|
||||
<?js= self.partial('method.tmpl', doc.module) ?>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (doc.kind === 'class') { ?>
|
||||
<?js= self.partial('method.tmpl', doc) ?>
|
||||
<?js } else { ?>
|
||||
<?js if (doc.description) { ?>
|
||||
<div class="description"><?js= doc.description ?></div>
|
||||
<?js } ?>
|
||||
|
||||
<?js= self.partial('details.tmpl', doc) ?>
|
||||
|
||||
<?js if (doc.examples && doc.examples.length) { ?>
|
||||
<h3>Example<?js= doc.examples.length > 1? 's':'' ?></h3>
|
||||
<?js= self.partial('examples.tmpl', doc.examples) ?>
|
||||
<?js } ?>
|
||||
<?js } ?>
|
||||
</div>
|
||||
|
||||
<?js if (doc.augments && doc.augments.length) { ?>
|
||||
<h3 class="subsection-title">Extends</h3>
|
||||
|
||||
<ul><?js doc.augments.forEach(function(a) { ?>
|
||||
<li><?js= self.linkto(a, a) ?></li>
|
||||
<?js }); ?></ul>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (doc.mixes && doc.mixes.length) { ?>
|
||||
<h3 class="subsection-title">Mixes In</h3>
|
||||
|
||||
<ul><?js doc.mixes.forEach(function(a) { ?>
|
||||
<li><?js= self.linkto(a, a) ?></li>
|
||||
<?js }); ?></ul>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (doc.requires && doc.requires.length) { ?>
|
||||
<h3 class="subsection-title">Requires</h3>
|
||||
|
||||
<ul><?js doc.requires.forEach(function(r) { ?>
|
||||
<li><?js= self.linkto(r, r) ?></li>
|
||||
<?js }); ?></ul>
|
||||
<?js } ?>
|
||||
|
||||
<?js
|
||||
var classes = self.find({kind: 'class', memberof: doc.longname});
|
||||
if (doc.kind !== 'globalobj' && classes && classes.length) {
|
||||
?>
|
||||
<h3 class="subsection-title">Classes</h3>
|
||||
|
||||
<dl><?js classes.forEach(function(c) { ?>
|
||||
<dt><?js= self.linkto(c.longname, c.name) ?></dt>
|
||||
<dd><?js if (c.summary) { ?><?js= c.summary ?><?js } ?></dd>
|
||||
<?js }); ?></dl>
|
||||
<?js } ?>
|
||||
|
||||
<?js
|
||||
var namespaces = self.find({kind: 'namespace', memberof: doc.longname});
|
||||
if (doc.kind !== 'globalobj' && namespaces && namespaces.length) {
|
||||
?>
|
||||
<h3 class="subsection-title">Namespaces</h3>
|
||||
|
||||
<dl><?js namespaces.forEach(function(n) { ?>
|
||||
<dt><a href="namespaces.html#<?js= n.longname ?>"><?js= self.linkto(n.longname, n.name) ?></a></dt>
|
||||
<dd><?js if (n.summary) { ?><?js= n.summary ?><?js } ?></dd>
|
||||
<?js }); ?></dl>
|
||||
<?js } ?>
|
||||
|
||||
<?js
|
||||
var members = self.find({kind: 'member', memberof: title === 'Global' ? {isUndefined: true} : doc.longname});
|
||||
if (members && members.length && members.forEach) {
|
||||
?>
|
||||
<h3 class="subsection-title">Members</h3>
|
||||
|
||||
<dl><?js members.forEach(function(p) { ?>
|
||||
<?js= self.partial('members.tmpl', p) ?>
|
||||
<?js }); ?></dl>
|
||||
<?js } ?>
|
||||
|
||||
<?js
|
||||
var methods = self.find({kind: 'function', memberof: title === 'Global' ? {isUndefined: true} : doc.longname});
|
||||
if (methods && methods.length && methods.forEach) {
|
||||
?>
|
||||
<h3 class="subsection-title">Methods</h3>
|
||||
|
||||
<dl><?js methods.forEach(function(m) { ?>
|
||||
<?js= self.partial('method.tmpl', m) ?>
|
||||
<?js }); ?></dl>
|
||||
<?js } ?>
|
||||
|
||||
<?js
|
||||
var typedefs = self.find({kind: 'typedef', memberof: title === 'Global' ? {isUndefined: true} : doc.longname});
|
||||
if (typedefs && typedefs.length && typedefs.forEach) {
|
||||
?>
|
||||
<h3 class="subsection-title">Type Definitions</h3>
|
||||
|
||||
<dl><?js typedefs.forEach(function(e) {
|
||||
if (e.signature) {
|
||||
?>
|
||||
<?js= self.partial('method.tmpl', e) ?>
|
||||
<?js
|
||||
}
|
||||
else {
|
||||
?>
|
||||
<?js= self.partial('members.tmpl', e) ?>
|
||||
<?js
|
||||
}
|
||||
}); ?></dl>
|
||||
<?js } ?>
|
||||
|
||||
<?js
|
||||
var events = self.find({kind: 'event', memberof: title === 'Global' ? {isUndefined: true} : doc.longname});
|
||||
if (events && events.length && events.forEach) {
|
||||
?>
|
||||
<h3 class="subsection-title">Events</h3>
|
||||
|
||||
<dl><?js events.forEach(function(e) { ?>
|
||||
<?js= self.partial('method.tmpl', e) ?>
|
||||
<?js }); ?></dl>
|
||||
<?js } ?>
|
||||
</article>
|
||||
|
||||
</section>
|
||||
<?js } ?>
|
||||
|
||||
<?js }); ?>
|
||||
@@ -0,0 +1,93 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
var self = this;
|
||||
?>
|
||||
<dl class="details">
|
||||
<?js
|
||||
var properties = data.properties;
|
||||
if (properties && properties.length && properties.forEach) {
|
||||
?>
|
||||
|
||||
<h5 class="subsection-title">Properties:</h5>
|
||||
|
||||
<dl><?js= this.partial('properties.tmpl', properties) ?></dl>
|
||||
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.version) {?>
|
||||
<dt class="tag-version">Version:</dt>
|
||||
<dd class="tag-version"><ul class="dummy"><li><?js= version ?></li></ul></dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.since) {?>
|
||||
<dt class="tag-since">Since:</dt>
|
||||
<dd class="tag-since"><ul class="dummy"><li><?js= since ?></dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.deprecated) { ?>
|
||||
<dt class="important tag-deprecated">Deprecated</dt><?js
|
||||
if (data.deprecated === true) { ?><dd class="yes-def tag-deprecated"><ul class="dummy"><li>Yes</li></ul></dd><?js }
|
||||
else { ?><dd><ul class="dummy"><li><?js= data.deprecated ?></li><ul></dd><?js }
|
||||
?>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.author && author.length) {?>
|
||||
<dt class="tag-author">Author:</dt>
|
||||
<dd class="tag-author">
|
||||
<ul><?js author.forEach(function(a) { ?>
|
||||
<li><?js= self.resolveAuthorLinks(a) ?></li>
|
||||
<?js }); ?></ul>
|
||||
</dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.copyright) {?>
|
||||
<dt class="tag-copyright">Copyright:</dt>
|
||||
<dd class="tag-copyright"><ul class="dummy"><li><?js= copyright ?></li></ul></dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.license) {?>
|
||||
<dt class="tag-license">License:</dt>
|
||||
<dd class="tag-license"><ul class="dummy"><li><?js= license ?></li></ul></dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.defaultvalue) {?>
|
||||
<dt class="tag-default">Default Value:</dt>
|
||||
<dd class="tag-default"><ul class="dummy"><li><?js= data.defaultvalue ?></li></ul></dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.tutorials && tutorials.length) {?>
|
||||
<dt class="tag-tutorial">Tutorials:</dt>
|
||||
<dd class="tag-tutorial">
|
||||
<ul><?js tutorials.forEach(function(t) { ?>
|
||||
<li><?js= self.tutoriallink(t) ?></li>
|
||||
<?js }); ?></ul>
|
||||
</dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.see && see.length) {?>
|
||||
<dt class="tag-see">See:</dt>
|
||||
<dd class="tag-see">
|
||||
<ul><?js see.forEach(function(s) { ?>
|
||||
<li><?js= self.linkto(s) ?></li>
|
||||
<?js }); ?></ul>
|
||||
</dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.platforms && platforms.length) {?>
|
||||
<dt class="tag-see">Supported platforms</dt>
|
||||
<dd class="tag-see">
|
||||
<ul><?js platforms.forEach(function(t) { ?>
|
||||
<li><?js= t ?></li>
|
||||
<?js }); ?></ul>
|
||||
</dd>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.todo && todo.length) {?>
|
||||
<dt class="tag-todo">TODO</dt>
|
||||
<dd class="tag-todo">
|
||||
<ul><?js todo.forEach(function(t) { ?>
|
||||
<li><?js= t ?></li>
|
||||
<?js }); ?></ul>
|
||||
</dd>
|
||||
<?js } ?>
|
||||
</dl>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?js var data = obj; ?>
|
||||
<pre class="prettyprint"><code><?js= data ?></code></pre>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
data.forEach(function(example) {
|
||||
if (example.caption) {
|
||||
?>
|
||||
<p class="code-caption"><?js= example.caption ?></p>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (example.code.toString().indexOf('<pre>') === -1) { ?>
|
||||
<pre class="prettyprint"><code><?js= example.code ?></code></pre>
|
||||
<?js } else { ?>
|
||||
<?js= example.code.replace(/<pre>/g, '<pre class="prettyprint">') ?>
|
||||
<?js } ?>
|
||||
<?js
|
||||
});
|
||||
?>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
?>
|
||||
<?js if (data.description && data.type && data.type.names) { ?>
|
||||
<dl>
|
||||
<dt>
|
||||
<div class="param-desc">
|
||||
<?js= data.description ?>
|
||||
</div>
|
||||
</dt>
|
||||
<dt>
|
||||
<dl>
|
||||
<dt>
|
||||
Type
|
||||
</dt>
|
||||
<dd>
|
||||
<?js= this.partial('type.tmpl', data.type.names) ?>
|
||||
</dd>
|
||||
</dl>
|
||||
</dt>
|
||||
</dl>
|
||||
<?js } else { ?>
|
||||
<div class="param-desc">
|
||||
<?js if (data.description) { ?>
|
||||
<?js= data.description ?>
|
||||
<?js } else if (data.type && data.type.names) { ?>
|
||||
<?js= this.partial('type.tmpl', data.type.names) ?>
|
||||
<?js } ?>
|
||||
</div>
|
||||
<?js } ?>
|
||||
@@ -0,0 +1,74 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?js= ((env.conf.templates.meta && env.conf.templates.meta.title) || title) ?></title>
|
||||
<?js if (env.conf.templates.meta) { ?>
|
||||
<?js if (env.conf.templates.meta.description) { ?><meta name="description" content="<?js= env.conf.templates.meta.description ?>" /><?js } ?>
|
||||
<?js if (env.conf.templates.meta.keyword) { ?>
|
||||
<meta name="keywords" content="<?js= env.conf.templates.meta.keyword ?>" />
|
||||
<meta name="keyword" content="<?js= env.conf.templates.meta.keyword ?>" />
|
||||
<?js } ?>
|
||||
<?js } ?>
|
||||
<?js if (env.conf.templates.openGraph) { ?>
|
||||
<meta property="og:title" content="<?js= env.conf.templates.openGraph.title ?>"/>
|
||||
<meta property="og:type" content="<?js= env.conf.templates.openGraph.type ?>"/>
|
||||
<meta property="og:image" content="<?js= env.conf.templates.openGraph.image ?>"/>
|
||||
<?js if (env.conf.templates.openGraph.site_name) { ?><meta property="og:site_name" content="<?js= env.conf.templates.openGraph.site_name ?>"/><?js } ?>
|
||||
<meta property="og:url" content="<?js= env.conf.templates.openGraph.url ?>"/>
|
||||
<?js } ?>
|
||||
<script src="scripts/prettify/prettify.js"></script>
|
||||
<script src="scripts/prettify/lang-css.js"></script>
|
||||
<script src="scripts/jquery.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jaguar.css">
|
||||
|
||||
<?js if (env.conf.templates) { ?>
|
||||
<script>
|
||||
var config = <?js= JSON.stringify(env.conf.templates) ?>;
|
||||
</script>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (env.conf.templates.googleAnalytics) { ?>
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', config.googleAnalytics]);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
<?js } ?>
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrap" class="clearfix">
|
||||
<?js= this.partial('navigation.tmpl', this) ?>
|
||||
<div class="main">
|
||||
<h1 class="page-title" data-filename="<?js= filename ?>"><?js= title ?></h1>
|
||||
<?js= content ?>
|
||||
|
||||
<?js if (env.conf.templates.disqus) { ?>
|
||||
<!-- disqus code -->
|
||||
<div id="disqus_thread"></div>
|
||||
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
|
||||
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
|
||||
<!-- // disqus code -->
|
||||
<?js } ?>
|
||||
|
||||
<footer>
|
||||
RobloxHybrid - Documentation generated on <?js= (new Date()).toLocaleDateString("en-US") ?>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<script>prettyPrint();</script>
|
||||
<script src="scripts/linenumber.js"></script>
|
||||
<script src="scripts/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
var self = this;
|
||||
?>
|
||||
|
||||
<?js if (data.kind === 'package') { ?>
|
||||
<h3><?js= data.name ?> <?js= data.version ?></h3>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.readme) { ?>
|
||||
<section>
|
||||
<article class="readme"><?js= data.readme ?></article>
|
||||
</section>
|
||||
<?js } ?>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
var self = this;
|
||||
var typeSignature = '';
|
||||
|
||||
if (data.type && data.type.names) {
|
||||
data.type.names.forEach(function (name) {
|
||||
typeSignature += '<span class="type-signature type ' + name.toLowerCase() + '">' + self.linkto(name, self.htmlsafe(name)) + '</span> ';
|
||||
});
|
||||
}
|
||||
?>
|
||||
<dt>
|
||||
<div class="nameContainer">
|
||||
<h4 class="name" id="<?js= id ?>"><?js= data.attribs + (data.scope === 'static' ? longname : name) + typeSignature ?></h4>
|
||||
</div>
|
||||
|
||||
<?js if (data.summary) { ?>
|
||||
<p class="summary"><?js= summary ?></p>
|
||||
<?js } ?>
|
||||
</dt>
|
||||
<dd>
|
||||
<?js if (data.description) { ?>
|
||||
<div class="description">
|
||||
<?js= data.description ?>
|
||||
</div>
|
||||
<?js } ?>
|
||||
|
||||
<?js= this.partial('details.tmpl', data) ?>
|
||||
|
||||
<?js if (data.examples && examples.length) { ?>
|
||||
<h5>Example<?js= examples.length > 1? 's':'' ?></h5>
|
||||
<?js= this.partial('examples.tmpl', examples) ?>
|
||||
<?js } ?>
|
||||
</dd>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
var self = this;
|
||||
?>
|
||||
<dt>
|
||||
<div class="nameContainer<?js if (data.inherited) { ?> inherited<?js } ?>">
|
||||
<h4 class="name" id="<?js= id ?>">
|
||||
<?js if (data.inherited || data.inherits) { ?>
|
||||
<span class="inherited"><?js= this.linkto(data.inherits, 'inherited') ?></span>
|
||||
<?js } ?>
|
||||
<?js= data.attribs + (kind === 'class' ? 'new ' : '') + (data.scope === 'static' ? name : name) + (kind !== 'event' ? data.signature : '') ?>
|
||||
</h4>
|
||||
|
||||
<?js if (data.meta) {?>
|
||||
<div class="tag-source">
|
||||
<?js= self.linkto(meta.filename) ?>, <?js= self.linkto(meta.filename, 'line ' + meta.lineno, null, 'line' + meta.lineno) ?>
|
||||
</div>
|
||||
<?js } ?>
|
||||
</div>
|
||||
|
||||
<?js if (data.summary) { ?>
|
||||
<p class="summary"><?js= summary ?></p>
|
||||
<?js } ?>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
<?js if (data.description) { ?>
|
||||
<div class="description">
|
||||
<?js= data.description ?>
|
||||
</div>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (kind === 'event' && data.type && data.type.names) {?>
|
||||
<h5>Type:</h5>
|
||||
<ul>
|
||||
<li>
|
||||
<?js= self.partial('type.tmpl', data.type.names) ?>
|
||||
</li>
|
||||
</ul>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data['this']) { ?>
|
||||
<h5>This:</h5>
|
||||
<ul><li><?js= this.linkto(data['this'], data['this']) ?></li></ul>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.params && params.length) { ?>
|
||||
<?js= this.partial('params.tmpl', params) ?>
|
||||
<?js } ?>
|
||||
|
||||
<?js= this.partial('details.tmpl', data) ?>
|
||||
|
||||
<?js if (data.fires && fires.length) { ?>
|
||||
<h5>Fires:</h5>
|
||||
<ul><?js fires.forEach(function(f) { ?>
|
||||
<li><?js= self.linkto(f) ?></li>
|
||||
<?js }); ?></ul>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.listens && listens.length) { ?>
|
||||
<h5>Listens to Events:</h5>
|
||||
<ul><?js listens.forEach(function(f) { ?>
|
||||
<li><?js= self.linkto(f) ?></li>
|
||||
<?js }); ?></ul>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.listeners && listeners.length) { ?>
|
||||
<h5>Listeners of This Event:</h5>
|
||||
<ul><?js listeners.forEach(function(f) { ?>
|
||||
<li><?js= self.linkto(f) ?></li>
|
||||
<?js }); ?></ul>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.exceptions && exceptions.length) { ?>
|
||||
<h5>Throws:</h5>
|
||||
<?js if (exceptions.length > 1) { ?><ul><?js
|
||||
exceptions.forEach(function(r) { ?>
|
||||
<li><?js= self.partial('exceptions.tmpl', r) ?></li>
|
||||
<?js });
|
||||
?></ul><?js } else {
|
||||
exceptions.forEach(function(r) { ?>
|
||||
<?js= self.partial('exceptions.tmpl', r) ?>
|
||||
<?js });
|
||||
} } ?>
|
||||
|
||||
<?js if (data.returns && returns.length) { ?>
|
||||
<h5>Returns:</h5>
|
||||
<?js= self.partial('returns.tmpl', data.returns) ?>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (data.examples && examples.length) { ?>
|
||||
<h5>Example<?js= examples.length > 1? 's':'' ?></h5>
|
||||
<?js= this.partial('examples.tmpl', examples) ?>
|
||||
<?js } ?>
|
||||
</dd>
|
||||
@@ -0,0 +1,81 @@
|
||||
<?js
|
||||
var self = this;
|
||||
?>
|
||||
<div class="navigation">
|
||||
<h3 class="applicationName"><a href="index.html"><?js= env.conf.templates.applicationName ?></a></h3>
|
||||
|
||||
<div class="search">
|
||||
<input id="search" type="text" class="form-control input-sm" placeholder="Search Documentations">
|
||||
</div>
|
||||
<ul class="list">
|
||||
<?js
|
||||
this.nav.forEach(function (item) {
|
||||
?>
|
||||
<li class="item" data-name="<?js= item.longname ?>">
|
||||
<span class="title">
|
||||
<?js= self.linkto(item.longname, item.longname) ?>
|
||||
<?js if (item.type === 'namespace') { ?>
|
||||
<span class="static">static</span>
|
||||
<?js } ?>
|
||||
</span>
|
||||
<ul class="members itemMembers">
|
||||
<?js
|
||||
if (item.members.length) {
|
||||
?>
|
||||
<span class="subtitle">Members</span>
|
||||
<?js
|
||||
item.members.forEach(function (v) {
|
||||
?>
|
||||
<li data-name="<?js= v.longname ?>"><?js= self.linkto(v.longname, v.name) ?></li>
|
||||
<?js
|
||||
});
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="typedefs itemMembers">
|
||||
<?js
|
||||
if (item.typedefs.length) {
|
||||
?>
|
||||
<span class="subtitle">Typedefs</span>
|
||||
<?js
|
||||
item.typedefs.forEach(function (v) {
|
||||
?>
|
||||
<li data-name="<?js= v.longname ?>"><?js= self.linkto(v.longname, v.name) ?></li>
|
||||
<?js
|
||||
});
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="methods itemMembers">
|
||||
<?js
|
||||
if (item.methods.length) {
|
||||
?>
|
||||
<span class="subtitle">Methods</span>
|
||||
<?js
|
||||
|
||||
item.methods.forEach(function (v) {
|
||||
?>
|
||||
<li data-name="<?js= v.longname ?>"><?js= self.linkto(v.longname, v.name) ?></li>
|
||||
<?js
|
||||
});
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="events itemMembers">
|
||||
<?js
|
||||
if (item.events.length) {
|
||||
?>
|
||||
<span class="subtitle">Events</span>
|
||||
<?js
|
||||
item.events.forEach(function (v) {
|
||||
?>
|
||||
<li data-name="<?js= v.longname ?>"><?js= self.linkto(v.longname, v.name) ?></li>
|
||||
<?js
|
||||
});
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</li>
|
||||
<?js }); ?>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -0,0 +1,104 @@
|
||||
<?js
|
||||
var params = obj;
|
||||
|
||||
/* sort subparams under their parent params (like opts.classname) */
|
||||
var parentParam = null;
|
||||
params.forEach(function(param, i) {
|
||||
if (!param) { return; }
|
||||
if ( parentParam && param.name && param.name.indexOf(parentParam.name + '.') === 0 ) {
|
||||
param.name = param.name.substr(parentParam.name.length+1);
|
||||
parentParam.subparams = parentParam.subparams || [];
|
||||
parentParam.subparams.push(param);
|
||||
params[i] = null;
|
||||
}
|
||||
else {
|
||||
parentParam = param;
|
||||
}
|
||||
});
|
||||
|
||||
/* determine if we need extra columns, "attributes" and "default" */
|
||||
params.hasAttributes = false;
|
||||
params.hasDefault = false;
|
||||
params.hasName = false;
|
||||
|
||||
params.forEach(function(param) {
|
||||
if (!param) { return; }
|
||||
|
||||
if (param.optional || param.nullable || param.variable) {
|
||||
params.hasAttributes = true;
|
||||
}
|
||||
|
||||
if (param.name) {
|
||||
params.hasName = true;
|
||||
}
|
||||
|
||||
if (typeof param.defaultvalue !== 'undefined') {
|
||||
params.hasDefault = true;
|
||||
}
|
||||
});
|
||||
?>
|
||||
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
<?js if (params.hasName) {?>
|
||||
<th>Name</th>
|
||||
<?js } ?>
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
<?js if (params.hasDefault) {?>
|
||||
<th>Default</th>
|
||||
<?js } ?>
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?js
|
||||
var self = this;
|
||||
params.forEach(function(param) {
|
||||
if (!param) { return; }
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<?js if (params.hasName) {?>
|
||||
<td class="name"><code><?js= param.name ?></code></td>
|
||||
<?js } ?>
|
||||
|
||||
<td class="type">
|
||||
<?js if (param.type && param.type.names) {?>
|
||||
<?js= self.partial('type.tmpl', param.type.names) ?>
|
||||
<?js } ?>
|
||||
</td>
|
||||
|
||||
<?js if (params.hasDefault) {?>
|
||||
<td class="default">
|
||||
<?js if (typeof param.defaultvalue !== 'undefined') { ?>
|
||||
<?js= self.htmlsafe(param.defaultvalue) ?>
|
||||
<?js } ?>
|
||||
</td>
|
||||
<?js } ?>
|
||||
|
||||
<td class="description last">
|
||||
<?js if (params.hasAttributes) {?>
|
||||
<?js if (param.optional) { ?>
|
||||
<span class="optional">optional</span>
|
||||
<?js } ?>
|
||||
<?js if (param.nullable) { ?>
|
||||
<span class="nullable">nullable</span>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (param.variable) { ?>
|
||||
<span class="repeatable">repeatable</span>
|
||||
<?js } ?>
|
||||
<?js } ?>
|
||||
<?js= param.description ?><?js if (param.subparams) { ?>
|
||||
<?js= self.partial('params.tmpl', param.subparams) ?>
|
||||
<?js } ?></td>
|
||||
</tr>
|
||||
|
||||
<?js }); ?>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -0,0 +1,107 @@
|
||||
<?js
|
||||
var props = obj;
|
||||
|
||||
/* sort subprops under their parent props (like opts.classname) */
|
||||
var parentProp = null;
|
||||
props.forEach(function(prop, i) {
|
||||
if (!prop) { return; }
|
||||
if ( parentProp && prop.name && prop.name.indexOf(parentProp.name + '.') === 0 ) {
|
||||
prop.name = prop.name.substr(parentProp.name.length+1);
|
||||
parentProp.subprops = parentProp.subprops || [];
|
||||
parentProp.subprops.push(prop);
|
||||
props[i] = null;
|
||||
}
|
||||
else {
|
||||
parentProp = prop;
|
||||
}
|
||||
});
|
||||
|
||||
/* determine if we need extra columns, "attributes" and "default" */
|
||||
props.hasAttributes = false;
|
||||
props.hasDefault = false;
|
||||
props.hasName = false;
|
||||
|
||||
props.forEach(function(prop) {
|
||||
if (!prop) { return; }
|
||||
|
||||
if (prop.optional || prop.nullable) {
|
||||
props.hasAttributes = true;
|
||||
}
|
||||
|
||||
if (prop.name) {
|
||||
props.hasName = true;
|
||||
}
|
||||
|
||||
if (typeof prop.defaultvalue !== 'undefined') {
|
||||
props.hasDefault = true;
|
||||
}
|
||||
});
|
||||
?>
|
||||
|
||||
<table class="props">
|
||||
<thead>
|
||||
<tr>
|
||||
<?js if (props.hasName) {?>
|
||||
<th>Name</th>
|
||||
<?js } ?>
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
<?js if (props.hasAttributes) {?>
|
||||
<th>Argument</th>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (props.hasDefault) {?>
|
||||
<th>Default</th>
|
||||
<?js } ?>
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?js
|
||||
var self = this;
|
||||
props.forEach(function(prop) {
|
||||
if (!prop) { return; }
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<?js if (props.hasName) {?>
|
||||
<td class="name"><code><?js= prop.name ?></code></td>
|
||||
<?js } ?>
|
||||
|
||||
<td class="type">
|
||||
<?js if (prop.type && prop.type.names) {?>
|
||||
<?js= self.partial('type.tmpl', prop.type.names) ?>
|
||||
<?js } ?>
|
||||
</td>
|
||||
|
||||
<?js if (props.hasAttributes) {?>
|
||||
<td class="attributes">
|
||||
<?js if (prop.optional) { ?>
|
||||
<optional><br>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (prop.nullable) { ?>
|
||||
<nullable><br>
|
||||
<?js } ?>
|
||||
</td>
|
||||
<?js } ?>
|
||||
|
||||
<?js if (props.hasDefault) {?>
|
||||
<td class="default">
|
||||
<?js if (typeof prop.defaultvalue !== 'undefined') { ?>
|
||||
<?js= self.htmlsafe(prop.defaultvalue) ?>
|
||||
<?js } ?>
|
||||
</td>
|
||||
<?js } ?>
|
||||
|
||||
<td class="description last"><?js= prop.description ?><?js if (prop.subprops) { ?>
|
||||
<h6>Properties</h6><?js= self.partial('properties.tmpl', prop.subprops) ?>
|
||||
<?js } ?></td>
|
||||
</tr>
|
||||
|
||||
<?js }); ?>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -0,0 +1,86 @@
|
||||
<?js
|
||||
var returns = obj;
|
||||
var parentReturn = null;
|
||||
var hasName = false;
|
||||
var hasType = false;
|
||||
|
||||
returns.forEach(function (ret, i) {
|
||||
if (ret && (ret.description || ret.name)) {
|
||||
ret.description = ret.description.toString().replace(/<\/?p>/g, '');
|
||||
|
||||
var isNamed = ret.name ? true : false;
|
||||
var name = ret.name || ret.description;
|
||||
var startSpacePos = name.indexOf(' ');
|
||||
|
||||
if (parentReturn !== null && name.indexOf(parentReturn.name + '.') === 0) {
|
||||
ret.name = isNamed ? name.substr(parentReturn.name.length + 1) : name.substr(parentReturn.name.length + 1, startSpacePos - (parentReturn.name.length + 1));
|
||||
|
||||
if (!isNamed) {
|
||||
ret.description = ret.description.substr(startSpacePos + 1);
|
||||
}
|
||||
|
||||
ret.isSubReturns = true;
|
||||
parentReturn.subReturns = parentReturn.subReturns || [];
|
||||
parentReturn.subReturns.push(ret);
|
||||
returns[i] = null;
|
||||
} else if (returns.length > 1 || ret.isSubReturns) {
|
||||
if (!isNamed) {
|
||||
ret.name = ret.description.substr(0, startSpacePos !== -1 ? startSpacePos : ret.description.length);
|
||||
ret.description = startSpacePos !== -1 ? ret.description.substr(startSpacePos + 1) : '';
|
||||
}
|
||||
|
||||
parentReturn = ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret.name) {
|
||||
hasName = true;
|
||||
}
|
||||
|
||||
if (ret.type) {
|
||||
hasType = true;
|
||||
}
|
||||
});
|
||||
?>
|
||||
|
||||
<?js if (hasType) { ?>
|
||||
<table class="params">
|
||||
<thead>
|
||||
<tr>
|
||||
<?js if (hasName) { ?><th>Name</th><?js } ?>
|
||||
<th>Type</th>
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?js
|
||||
var self = this;
|
||||
returns.forEach(function(ret) {
|
||||
if (!ret) {
|
||||
return false;
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<?js if (ret.name) { ?><td class="name"><code><?js= ret.name ?></code></td><?js } ?>
|
||||
<td class="type">
|
||||
<?js
|
||||
if (ret.type && ret.type.names) {
|
||||
ret.type.names.forEach(function(name, i) { ?>
|
||||
<?js= self.linkto(name, self.htmlsafe(name)) ?>
|
||||
<?js if (i < ret.type.names.length-1) { ?> | <?js } ?>
|
||||
<?js });
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="description last"><?js= ret.description ?><?js if (ret.subReturns) { ?>
|
||||
<?js= self.partial('returns.tmpl', ret.subReturns) ?>
|
||||
<?js } ?></td>
|
||||
</tr>
|
||||
<?js }); ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?js } else { ?>
|
||||
<?js if (returns[0].description) { ?>
|
||||
<?js= returns[0].description ?>
|
||||
<?js } ?>
|
||||
<?js } ?>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
?>
|
||||
<section>
|
||||
<article>
|
||||
<pre class="prettyprint source <?js= env.conf.templates.linenums ? 'linenums' : '' ?>"><code><?js= data.code ?></code></pre>
|
||||
</article>
|
||||
</section>
|
||||
@@ -0,0 +1,19 @@
|
||||
<section>
|
||||
|
||||
<header>
|
||||
<?js if (children.length > 0) { ?>
|
||||
<ul><?js
|
||||
var self = this;
|
||||
children.forEach(function(t) { ?>
|
||||
<li><?js= self.tutoriallink(t.name) ?></li>
|
||||
<?js }); ?></ul>
|
||||
<?js } ?>
|
||||
|
||||
<h2><?js= header ?></h2>
|
||||
</header>
|
||||
|
||||
<article>
|
||||
<?js= content ?>
|
||||
</article>
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
var self = this;
|
||||
data.forEach(function(name, i) { ?>
|
||||
<span class="param-type"><?js= self.linkto(name, self.htmlsafe(name)) ?></span>
|
||||
<?js if (i < data.length-1) { ?>|<?js } ?>
|
||||
<?js }); ?>
|
||||
@@ -0,0 +1,14 @@
|
||||
# development-related files
|
||||
.eslintignore
|
||||
.eslintrc
|
||||
.gitignore
|
||||
.travis.yml
|
||||
gulpfile.js
|
||||
|
||||
# scripts for launching JSDoc with Mozilla Rhino
|
||||
/jsdoc*
|
||||
!/jsdoc.js
|
||||
|
||||
# Rhino and test directories
|
||||
rhino/
|
||||
test/
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,69 @@
|
||||
Pull Requests
|
||||
-------------
|
||||
|
||||
If you're thinking about making some changes, maybe fixing a bug, or adding a
|
||||
snazzy new feature, first, thank you. Contributions are very welcome. Things
|
||||
need to be manageable for the maintainers, however. So below you'll find **The
|
||||
fastest way to get your pull request merged in.** Some things, particularly how
|
||||
you set up your branches and work with git, are just suggestions, but pretty good
|
||||
ones.
|
||||
|
||||
1. **Create a remote to track the base jsdoc3/jsdoc repository**
|
||||
This is just a convenience to make it easier to update your ```<tracking branch>```
|
||||
(more on that shortly). You would execute something like:
|
||||
|
||||
git remote add base git://github.com/jsdoc3/jsdoc.git
|
||||
|
||||
Here 'base' is the name of the remote. Feel free to use whatever you want.
|
||||
|
||||
2. **Set up a tracking branch for the base repository**
|
||||
We're gonna call this your ```<tracking branch>```. You will only ever update
|
||||
this branch by pulling from the 'base' remote. (as opposed to 'origin')
|
||||
|
||||
git branch --track pullpost base/master
|
||||
git checkout pullpost
|
||||
|
||||
Here 'pullpost' is the name of the branch. Fell free to use whatever you want.
|
||||
|
||||
3. **Create your change branch**
|
||||
Once you are in ```<tracking branch>```, make sure it's up to date, then create
|
||||
a branch for your changes off of that one.
|
||||
|
||||
git branch fix-for-issue-395
|
||||
git checkout fix-for-issue-395
|
||||
|
||||
Here 'fix-for-issue-395' is the name of the branch. Feel free to use whatever
|
||||
you want. We'll call this the ```<change branch>```. This is the branch that
|
||||
you will eventually issue your pull request from.
|
||||
|
||||
The purpose of these first three steps is to make sure that your merge request
|
||||
has a nice clean diff that only involves the changes related to your fix/feature.
|
||||
|
||||
4. **Make your changes**
|
||||
On your ```<change branch>``` make any changes relevant to your fix/feature. Don't
|
||||
group fixes for multiple unrelated issues or multiple unrelated features together.
|
||||
Create a separate branch for each unrelated changeset. For instance, if you're
|
||||
fixing a bug in the parser and adding some new UI to the default template, those
|
||||
should be separate branches and merge requests.
|
||||
|
||||
5. **Add tests**
|
||||
Add tests for your change. If you are submitting a bugfix, include a test that
|
||||
verifies the existence of the bug along with your fix. If you are submitting
|
||||
a new feature, include tests that verify proper feature function, if applicable.
|
||||
See the readme in the 'test' directory for more information
|
||||
|
||||
6. **Commit and publish**
|
||||
Commit your changes and publish your branch (or push it if it's already published)
|
||||
|
||||
7. **Issue your pull request**
|
||||
On github.com, switch to your ```<change branch>``` and click the 'Pull Request'
|
||||
button. Enter some meaningful information about the pull request. If it's a bugfix,
|
||||
that doesn't already have an issue associated with it, provide some info on what
|
||||
situations that bug occurs in and a sense of it's severity. If it does already have
|
||||
an issue, make sure the include the hash and issue number (e.g. '#100') so github
|
||||
links it.
|
||||
|
||||
If it's a feature, provide some context about the motivations behind the feature,
|
||||
why it's important/useful/cool/necessary and what it does/how it works. Don't
|
||||
worry about being too verbose. Folks will be much more amenable to reading through
|
||||
your code if they know what its supposed to be about.
|
||||
@@ -0,0 +1,380 @@
|
||||
# License #
|
||||
|
||||
JSDoc 3 is free software, licensed under the Apache License, Version 2.0 (the
|
||||
"License"). Commercial and non-commercial use are permitted in compliance with
|
||||
the License.
|
||||
|
||||
Copyright (c) 2011-2014 Michael Mathews <micmath@gmail.com> and the
|
||||
[contributors to JSDoc](https://github.com/jsdoc3/jsdoc/graphs/contributors).
|
||||
All rights reserved.
|
||||
|
||||
You may obtain a copy of the License at:
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
In addition, a copy of the License is included with this distribution.
|
||||
|
||||
As stated in Section 7, "Disclaimer of Warranty," of the License:
|
||||
|
||||
> Licensor provides the Work (and each Contributor provides its Contributions)
|
||||
> on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
||||
> express or implied, including, without limitation, any warranties or
|
||||
> conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
> PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
> appropriateness of using or redistributing the Work and assume any risks
|
||||
> associated with Your exercise of permissions under this License.
|
||||
|
||||
The source code for JSDoc 3 is available at:
|
||||
https://github.com/jsdoc3/jsdoc
|
||||
|
||||
# Third-Party Software #
|
||||
|
||||
JSDoc 3 includes or depends upon the following third-party software, either in
|
||||
whole or in part. Each third-party software package is provided under its own
|
||||
license.
|
||||
|
||||
## MIT License ##
|
||||
|
||||
Several of the following software packages are distributed under the MIT
|
||||
license, which is reproduced below:
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in all
|
||||
> copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
> SOFTWARE.
|
||||
|
||||
## Acorn ##
|
||||
|
||||
Portions of the Acorn source code are incorporated into the following files:
|
||||
|
||||
- `lib/jsdoc/src/walker.js`
|
||||
|
||||
Acorn is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (C) 2012 Marijn Haverbeke <marijnh@gmail.com>.
|
||||
|
||||
The source code for Acorn is available at:
|
||||
https://github.com/marijnh/acorn
|
||||
|
||||
## Async.js ##
|
||||
|
||||
Async.js is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (c) 2010 Caolan McMahon.
|
||||
|
||||
The source code for Async.js is available at:
|
||||
https://github.com/caolan/async
|
||||
|
||||
## Catharsis ##
|
||||
|
||||
Catharsis is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (c) 2012-2014 Jeff Williams.
|
||||
|
||||
The source code for Catharsis is available at:
|
||||
https://github.com/hegemonic/catharsis
|
||||
|
||||
## crypto-browserify ##
|
||||
|
||||
crypto-browserify is distributed under the MIT license, which is reproduced
|
||||
above.
|
||||
|
||||
Copyright (c) 2013 Dominic Tarr.
|
||||
|
||||
The source code for crypto-browserify is available at:
|
||||
https://github.com/dominictarr/crypto-browserify
|
||||
|
||||
## escape-string-regexp ##
|
||||
|
||||
escape-string-regexp is distributed under the MIT License, which is reproduced
|
||||
above.
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com>.
|
||||
|
||||
The source code for escape-string-regexp is available at:
|
||||
https://github.com/sindresorhus/escape-string-regexp
|
||||
|
||||
## Esprima ##
|
||||
|
||||
Esprima is distributed under the BSD 2-clause license:
|
||||
|
||||
> Redistribution and use in source and binary forms, with or without
|
||||
> modification, are permitted provided that the following conditions are met:
|
||||
>
|
||||
> - Redistributions of source code must retain the above copyright notice,
|
||||
> this list of conditions and the following disclaimer.
|
||||
> - Redistributions in binary form must reproduce the above copyright notice,
|
||||
> this list of conditions and the following disclaimer in the documentation
|
||||
> and/or other materials provided with the distribution.
|
||||
>
|
||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
> ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
> DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
> (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
> ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
> (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
> THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (c) 2011-2013 Ariya Hidayat and other Esprima contributors.
|
||||
|
||||
The source code for Esprima is available at:
|
||||
https://github.com/ariya/esprima
|
||||
|
||||
## events ##
|
||||
|
||||
Portions of the events source code are incorporated into the following files:
|
||||
|
||||
+ `rhino/events.js`
|
||||
|
||||
events is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
||||
The source code for events is available at:
|
||||
https://github.com/Gozala/events
|
||||
|
||||
## github-flavored-markdown ##
|
||||
|
||||
github-flavored-markdown is distributed under the BSD 3-clause license:
|
||||
|
||||
> Copyright (c) 2007, John Fraser <http://www.attacklab.net/> All rights
|
||||
> reserved.
|
||||
>
|
||||
> Original Markdown copyright (c) 2004, John Gruber <http://daringfireball.net/>
|
||||
> All rights reserved.
|
||||
>
|
||||
> Redistribution and use in source and binary forms, with or without
|
||||
> modification, are permitted provided that the following conditions are met:
|
||||
>
|
||||
> - Redistributions of source code must retain the above copyright notice,
|
||||
> this list of conditions and the following disclaimer.
|
||||
>
|
||||
> - Redistributions in binary form must reproduce the above copyright notice,
|
||||
> this list of conditions and the following disclaimer in the documentation
|
||||
> and/or other materials provided with the distribution.
|
||||
|
||||
> - Neither the name "Markdown" nor the names of its contributors may be used
|
||||
> to endorse or promote products derived from this software without specific
|
||||
> prior written permission.
|
||||
>
|
||||
> This software is provided by the copyright holders and contributors "as is"
|
||||
> and any express or implied warranties, including, but not limited to, the
|
||||
> implied warranties of merchantability and fitness for a particular purpose are
|
||||
> disclaimed. In no event shall the copyright owner or contributors be liable
|
||||
> for any direct, indirect, incidental, special, exemplary, or consequential
|
||||
> damages (including, but not limited to, procurement of substitute goods or
|
||||
> services; loss of use, data, or profits; or business interruption) however
|
||||
> caused and on any theory of liability, whether in contract, strict liability,
|
||||
> or tort (including negligence or otherwise) arising in any way out of the use
|
||||
> of this software, even if advised of the possibility of such damage.
|
||||
|
||||
The source code for github-flavored-markdown is available at:
|
||||
https://github.com/hegemonic/github-flavored-markdown
|
||||
|
||||
## Google Code Prettify ##
|
||||
|
||||
Google Code Prettify is distributed under the Apache License 2.0, which is
|
||||
included with this package.
|
||||
|
||||
Copyright (c) 2006 Google Inc.
|
||||
|
||||
The source code for Google Code Prettify is available at:
|
||||
https://code.google.com/p/google-code-prettify/
|
||||
|
||||
## Jasmine ##
|
||||
|
||||
Jasmine is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (c) 2008-2011 Pivotal Labs.
|
||||
|
||||
The source code for Jasmine is available at:
|
||||
https://github.com/pivotal/jasmine
|
||||
|
||||
## jasmine-node ##
|
||||
|
||||
jasmine-node is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (c) 2010 Adam Abrons and Misko Hevery (http://getangular.com).
|
||||
|
||||
The source code for jasmine-node is available at:
|
||||
https://github.com/mhevery/jasmine-node
|
||||
|
||||
## js2xmlparser ##
|
||||
|
||||
js2xmlparser is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (c) 2012 Michael Kourlas.
|
||||
|
||||
The source code for js2xmlparser is available at:
|
||||
https://github.com/michaelkourlas/node-js2xmlparser
|
||||
|
||||
## Node.js ##
|
||||
|
||||
Portions of the Node.js source code are incorporated into the following files:
|
||||
|
||||
- `rhino/fs.js`
|
||||
- `rhino/path.js`
|
||||
- `rhino/querystring.js`
|
||||
- `rhino/util.js`
|
||||
|
||||
Node.js is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
||||
The source code for Node.js is available at:
|
||||
https://github.com/joyent/node
|
||||
|
||||
## node-browser-builtins ##
|
||||
|
||||
Portions of the node-browser-builtins source code are incorporated into the
|
||||
following files:
|
||||
|
||||
- `rhino/assert.js`
|
||||
- `rhino/rhino-shim.js`
|
||||
|
||||
node-browser-builtins is distributed under the MIT license, which is reproduced
|
||||
above.
|
||||
|
||||
The source code for node-browser-builtins is available at:
|
||||
https://github.com/alexgorbatchev/node-browser-builtins
|
||||
|
||||
## Open Sans ##
|
||||
|
||||
Open Sans is distributed under the Apache License 2.0, which is
|
||||
included with this package.
|
||||
|
||||
Copyright (c) 2010-2011, Google Inc.
|
||||
|
||||
This typeface, including the complete set of variations, are available at:
|
||||
http://www.google.com/fonts/specimen/Open+Sans
|
||||
|
||||
## Requizzle ##
|
||||
|
||||
Requizzle is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (c) 2014 Google Inc. All rights reserved.
|
||||
Copyright (c) 2012-2013 Johannes Ewald.
|
||||
|
||||
The source code for Requizzle is available at:
|
||||
https://github.com/hegemonic/requizzle
|
||||
|
||||
## Rhino ##
|
||||
|
||||
Rhino is distributed under the following licenses:
|
||||
|
||||
### MPL 2.0 License ###
|
||||
The majority of the source code for Rhino is available under the Mozilla Public
|
||||
License (MPL) 2.0, which is included in this distribution.
|
||||
|
||||
### License for portions of the Rhino debugger ###
|
||||
Additionally, some files are available under the BSD 3-clause license:
|
||||
|
||||
> Copyright 1997, 1998 Sun Microsystems, Inc. All Rights Reserved.
|
||||
>
|
||||
> Redistribution and use in source and binary forms, with or without
|
||||
> modification, are permitted provided that the following conditions are met:
|
||||
>
|
||||
> - Redistributions of source code must retain the above copyright notice,
|
||||
> this list of conditions and the following disclaimer.
|
||||
> - Redistributions in binary form must reproduce the above copyright
|
||||
> notice, this list of conditions and the following disclaimer in the
|
||||
> documentation and/or other materials provided with the distribution.
|
||||
> - Neither the name of Sun Microsystems nor the names of its contributors
|
||||
> may be used to endorse or promote products derived from this software
|
||||
> without specific prior written permission.
|
||||
>
|
||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
> DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
> FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
> DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
> SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
> OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
> OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
### Source Code ###
|
||||
The source code for Rhino is available at:
|
||||
https://github.com/jsdoc3/rhino
|
||||
|
||||
## TaffyDB ##
|
||||
|
||||
TaffyDB is distributed under a modified BSD license:
|
||||
|
||||
> All rights reserved.
|
||||
>
|
||||
> Redistribution and use of this software in source and binary forms, with or
|
||||
> without modification, are permitted provided that the following condition is
|
||||
> met:
|
||||
>
|
||||
> Redistributions of source code must retain the above copyright notice, this
|
||||
> list of conditions and the following disclaimer.
|
||||
>
|
||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
> AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
> IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
> ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
> LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
> CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
> SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
> INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
> CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
> ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
> POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The source code for TaffyDB is available at:
|
||||
https://github.com/hegemonic/taffydb
|
||||
|
||||
## Tomorrow Theme for Google Code Prettify ##
|
||||
|
||||
License information for the Tomorrow Theme for Google Code Prettify is not
|
||||
available. It is assumed that the package is distributed under an open source
|
||||
license that is compatible with the Apache License 2.0.
|
||||
|
||||
Copyright (c) Yoshihide Jimbo.
|
||||
|
||||
The source code for the Tomorrow Theme is available at:
|
||||
https://github.com/jmblog/color-themes-for-google-code-prettify
|
||||
|
||||
## tv4 ##
|
||||
|
||||
tv4 is in the public domain. It is also distributed under the MIT license, which
|
||||
is reproduced above.
|
||||
|
||||
The source code for tv4 is available at:
|
||||
https://github.com/geraintluff/tv4
|
||||
|
||||
## Underscore.js ##
|
||||
|
||||
Underscore.js is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative
|
||||
Reporters & Editors.
|
||||
|
||||
The source code for Underscore.js is available at:
|
||||
https://github.com/jashkenas/underscore
|
||||
|
||||
## wrench-js ##
|
||||
|
||||
wrench-js is distributed under the MIT license, which is reproduced above.
|
||||
|
||||
Copyright (c) 2010 Ryan McGrath.
|
||||
|
||||
The source code for wrench-js is available at:
|
||||
https://github.com/ryanmcgrath/wrench-js
|
||||
@@ -0,0 +1,135 @@
|
||||
JSDoc 3
|
||||
=======
|
||||
[](http://travis-ci.org/jsdoc3/jsdoc)
|
||||
|
||||
An API documentation generator for JavaScript.
|
||||
|
||||
Want to contribute to JSDoc? Please read `CONTRIBUTING.md`.
|
||||
|
||||
Installation and Usage
|
||||
----------------------
|
||||
|
||||
You can run JSDoc on either Node.js or Mozilla Rhino.
|
||||
|
||||
### Node.js
|
||||
|
||||
Native support for Node.js is available in JSDoc 3.3.0 and later. JSDoc
|
||||
supports Node.js 0.10 and later.
|
||||
|
||||
#### Installing JSDoc for Node.js
|
||||
|
||||
You can install JSDoc in your project's `node_modules` folder, or you can
|
||||
install it globally.
|
||||
|
||||
To install the latest alpha version:
|
||||
|
||||
npm install jsdoc@"<=3.3.0"
|
||||
|
||||
To install the latest development version:
|
||||
|
||||
npm install git+https://github.com/jsdoc3/jsdoc.git
|
||||
|
||||
#### Running JSDoc with Node.js
|
||||
|
||||
If you installed JSDoc locally, the JSDoc command-line tool is available in
|
||||
`./node_modules/.bin`. To generate documentation for the file
|
||||
`yourJavaScriptFile.js`:
|
||||
|
||||
./node_modules/.bin/jsdoc yourJavaScriptFile.js
|
||||
|
||||
Or if you installed JSDoc globally, simply run the `jsdoc` command:
|
||||
|
||||
jsdoc yourJavaScriptFile.js
|
||||
|
||||
By default, the generated documentation is saved in a directory named `out`. You
|
||||
can use the `--destination` (`-d`) option to specify another directory.
|
||||
|
||||
Run `jsdoc --help` for a complete list of command-line options.
|
||||
|
||||
### Mozilla Rhino
|
||||
|
||||
All versions of JSDoc 3 run on a customized version of Mozilla Rhino, which
|
||||
requires Java. You can run JSDoc 3 on Java 1.6 and later.
|
||||
|
||||
#### Installing JSDoc for Mozilla Rhino
|
||||
|
||||
To install JSDoc, download a .zip file for the
|
||||
[latest development version](https://github.com/jsdoc3/jsdoc/archive/master.zip)
|
||||
or a [previous release](https://github.com/jsdoc3/jsdoc/tags).
|
||||
|
||||
You can also use git to clone the
|
||||
[JSDoc repository](https://github.com/jsdoc3/jsdoc):
|
||||
|
||||
git clone git+https://github.com/jsdoc3/jsdoc.git
|
||||
|
||||
The JSDoc repository includes a
|
||||
[customized version of Mozilla Rhino](https://github.com/jsdoc3/rhino). Make
|
||||
sure your Java classpath does not include any other versions of Rhino. (On OS X,
|
||||
you may need to remove the file `~/Library/Java/Extensions/js.jar`.)
|
||||
|
||||
**Note**: In JSDoc 3.3.0 and later, if you need to run JSDoc on Mozilla Rhino,
|
||||
do not install JSDoc with npm. Use one of the methods described above.
|
||||
|
||||
#### Running JSDoc with Mozilla Rhino
|
||||
|
||||
On OS X, Linux, and other POSIX systems, to generate documentation for the file
|
||||
`yourJavaScriptFile.js`:
|
||||
|
||||
./jsdoc yourJavaScriptFile.js
|
||||
|
||||
Or on Windows:
|
||||
|
||||
jsdoc yourJavaScriptFile.js
|
||||
|
||||
By default, the generated documentation is saved in a directory named `out`. You
|
||||
can use the `--destination` (`-d`) option to specify another directory.
|
||||
|
||||
Run `jsdoc --help` for a complete list of command-line options.
|
||||
|
||||
|
||||
Templates and Build Tools
|
||||
-------------------------
|
||||
|
||||
The JSDoc community has created numerous templates and other tools to help you
|
||||
generate and customize your documentation. Here are just a few:
|
||||
|
||||
### Templates
|
||||
|
||||
+ [jaguarjs-jsdoc](https://github.com/davidshimjs/jaguarjs-jsdoc)
|
||||
([example](http://davidshimjs.github.io/jaguarjs/doc))
|
||||
+ [DocStrap](https://github.com/terryweiss/docstrap)
|
||||
+ [jsdoc3Template](https://github.com/DBCDK/jsdoc3Template)
|
||||
([example](https://github.com/danyg/jsdoc3Template/wiki#wiki-screenshots))
|
||||
|
||||
### Build Tools
|
||||
|
||||
+ [JSDoc Grunt plugin](https://github.com/krampstudio/grunt-jsdoc)
|
||||
+ [JSDoc ant task](https://github.com/jannon/jsdoc3-ant-task)
|
||||
|
||||
### Generating Typeface Fonts
|
||||
|
||||
JSDoc 3 uses the [OpenSans](https://www.google.com/fonts/specimen/Open+Sans) typeface, the fonts for which can be re-generated as follows:
|
||||
|
||||
1. Open the [OpenSans page at Font Squirrel](<http://www.fontsquirrel.com/fonts/open-sans>).
|
||||
2. Click on the 'Webfont Kit' tab.
|
||||
3. Either leave the subset drop-down as 'Western Latin (Default)', or if we decide we need more glyphs than change it to 'No Subsetting'.
|
||||
4. Click the 'DOWNLOAD @FONT-FACE KIT' button.
|
||||
5. For each typeface variant we plan to use, copy the 'eot', 'svg' and 'woff' files into the 'templates/default/static/fonts' directory.
|
||||
|
||||
For More Information
|
||||
--------------------
|
||||
|
||||
+ Documentation is available at [Use JSDoc](http://usejsdoc.org).
|
||||
+ Contribute to the docs at [jsdoc3/jsdoc3.github.com](https://github.com/jsdoc3/jsdoc3.github.com).
|
||||
+ Ask for help on the [JSDoc Users mailing list](http://groups.google.com/group/jsdoc-users).
|
||||
+ Post questions tagged `jsdoc` to [Stack
|
||||
Overflow](http://stackoverflow.com/questions/tagged/jsdoc).
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
JSDoc 3 is copyright (c) 2011-2014 Michael Mathews <micmath@gmail.com> and the
|
||||
[contributors to JSDoc](https://github.com/jsdoc3/jsdoc/graphs/contributors).
|
||||
|
||||
JSDoc 3 is free software, licensed under the Apache License, Version 2.0. See
|
||||
the file `LICENSE.md` in this distribution for more details.
|
||||
@@ -0,0 +1,240 @@
|
||||
# JSDoc 3 change history
|
||||
|
||||
This file describes notable changes in each version of JSDoc 3. To download a specific version of JSDoc 3, see [GitHub's tags page](https://github.com/jsdoc3/jsdoc/tags).
|
||||
|
||||
## 3.2.2 (November 2013)
|
||||
|
||||
### Bug fixes
|
||||
+ Addressed a regression in JSDoc 3.2.1 that could prevent a function declaration from shadowing a declaration with the same name in an outer scope. (#513)
|
||||
+ If a child class overrides a method in a parent class without documenting the overridden method, the method's documentation is now copied from the parent class. (#503)
|
||||
+ You can now use inline HTML tags in Markdown-formatted text. In addition, JSDoc now uses only the [marked Markdown parser](https://github.com/chjj/marked); the markdown-js parser has been removed. (#510)
|
||||
+ Type expressions can now include a much broader range of repeatable types. In addition, you can now use Closure Compiler's nullable and non-nullable modifiers with repeatable types. For example, the type expression `...!string` (a repeatable, non-nullable string) is now parsed correctly. (#502)
|
||||
+ If a function accepts a parameter named `prototype`, the parameter is no longer renamed during parsing. (#505)
|
||||
+ If the list of input files includes relative paths, the paths are now resolved relative to the user's working directory. (a3d33842)
|
||||
|
||||
## 3.2.1 (October 2013)
|
||||
|
||||
### Enhancements
|
||||
+ JSDoc's parser now fires a `processingComplete` event after JSDoc has completed all post-processing of the parse results. This event has a `doclets` property containing an array of doclets. (#421)
|
||||
+ When JSDoc's parser fires a `parseComplete` event, the event now includes a `doclets` property containing an array of doclets. (#431)
|
||||
+ You can now use relative paths in the JSDoc configuration file's `source.exclude` option. Relative paths will be resolved relative to the current working directory. (#405)
|
||||
+ If a symbol uses the `@default` tag, and its default value is an object literal, this value is now stored as a string, and the doclet will have a `defaultvaluetype` property containing the string `object`. This change enables templates to show the default value with appropriate syntax highlighting. (#419)
|
||||
+ Inline `{@link}` tags can now contain newlines. (#441)
|
||||
|
||||
### Bug fixes
|
||||
+ Inherited symbols now indicate that they were inherited from the ancestor that defined the symbol, rather than the direct parent. (#422)
|
||||
+ If the first line of a JavaScript file contains a hashbang (for example, `#!/usr/bin/env node`), the hashbang is now ignored when the file is parsed. (#499)
|
||||
+ Resolved a crash when a JavaScript file contains a [JavaScript 1.8](https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.8) keyword, such as `let`. (#477)
|
||||
+ The type expression `function[]` is now parsed correctly. (#493)
|
||||
+ If a module is tagged incorrectly, the module's output file now has a valid filename. (#440, #458)
|
||||
+ For tags that accept names, such as `@module` and `@param`, if a hyphen is used to separate the name and description, the hyphen must appear on the same line as the name. This change prevents a Markdown bullet on the followng line from being interpreted as a separator. (#459)
|
||||
+ When lenient mode is enabled, a `@param` tag with an invalid type expression no longer causes a crash. (#448)
|
||||
+ The `@requires` tag can now contain an inline tag in its tag text. (#486)
|
||||
+ The `@returns` tag can now contain inline tags even if a type is not specified. (#444)
|
||||
+ When lenient mode is enabled, a `@returns` tag with no value no longer causes a crash. (#451)
|
||||
+ The `@type` tag now works correctly with type expressions that span multiple lines. (#427)
|
||||
+ If a string contains inline `{@link}` tags preceded by bracketed link text (for example, `[test]{@link Test#test}`), HTML links are now generated correctly even if the string contains other bracketed text. (#470)
|
||||
+ On POSIX systems, if you run JSDoc using a symlink to the startup script, JSDoc now works correctly. (#492)
|
||||
|
||||
### Default template
|
||||
+ Pretty-printed source files are now generated by default. To disable this feature, add the property `templates.default.outputSourceFiles: false` to your `conf.json` file. (#454)
|
||||
+ Links to a specific line in a source file now work correctly. (#475)
|
||||
+ Pretty-printed source files are now generated using the encoding specified in the `-e/--encoding` option. (#496)
|
||||
+ If a `@default` tag is added to a symbol whose default value is an object, the value is now displayed in the output file. (#419)
|
||||
+ Output files now identify symbols as "abstract" rather than "virtual." (#432)
|
||||
|
||||
## 3.2.0 (May 2013)
|
||||
|
||||
### Major changes
|
||||
+ JSDoc can now parse any valid [Google Closure Compiler type expression](https://developers.google.com/closure/compiler/docs/js-for-compiler#types). **Note**: As a result of this change, JSDoc quits if a file contains an invalid type expression. To prevent JSDoc from quitting, run JSDoc with the `--lenient` (`-l`) command-line option. (Multiple issues)
|
||||
+ You can now use the new `@listens` tag to indicate that a symbol listens for an event. (#273)
|
||||
|
||||
### Enhancements
|
||||
+ The parser now fires a `parseBegin` event before it starts parsing files, as well as a `parseComplete` event after all files have been parsed. Plugins can define event handlers for these events, and `parseBegin` handlers can modify the list of files to parse. (#299)
|
||||
+ Event handlers for `jsdocCommentFound` events can now modify the JSDoc comment. (#228)
|
||||
+ You can now exclude tags from Markdown processing using the new option `markdown.excludeTags` in the configuration file. (#337)
|
||||
+ You can now use the [marked](https://github.com/chjj/marked) Markdown parser by setting the configuration property `markdown.parser` to `marked`. In addition, if `markdown.parser` is set to `gfm`, JSDoc will now use the "marked" parser instead. (#385)
|
||||
+ The `@typedef` tag no longer requires a name when used with a Closure Compiler-style type definition. For example, the following type definition will automatically get the name `Foo.Bar`:
|
||||
|
||||
```javascript
|
||||
/** @typedef {string} */
|
||||
Foo.Bar;
|
||||
```
|
||||
|
||||
(#391)
|
||||
+ You can now use an inline `{@type}` tag in a parameter's description. If this tag is present, JSDoc will assume that the parameter uses the type specified in the inline `{@type}` tag. For example, the following `@param` tag would cause `myParam`'s type to be documented as `Foo`:
|
||||
|
||||
```
|
||||
@param {(boolean|string)} myParam - My special parameter. {@type Foo}
|
||||
```
|
||||
|
||||
(#152)
|
||||
+ The `console.log` function now behaves the same way as on Node.js. In addition, the functions `console.info`, `console.error`, `console.warn`, and `console.trace` have been implemented. (#298)
|
||||
+ You can now use npm to install JSDoc globally by running `npm install -g`. **Note**: JSDoc will still run under Mozilla Rhino, not Node.js. (#374)
|
||||
+ The `jsVersion` configuration property has been removed. (#390)
|
||||
|
||||
### Bug fixes
|
||||
+ JSDoc now quits if the configuration file cannot be loaded. (#407)
|
||||
+ JSDoc's `--explain` (`-X`) option now runs much more quickly, and it outputs valid JSON to the console. (#298)
|
||||
+ JSDoc's `--lenient` (`-l`) option now prints warnings on STDERR rather than STDOUT. (#298)
|
||||
+ The parser now assigns the correct scope to object properties whose names include single quotes. (#386)
|
||||
+ The parser now recognizes CommonJS modules that export a single function rather than an object. (#384)
|
||||
+ The inline `{@link}` tag now works correctly when `@link` is followed by a tab. (#359)
|
||||
+ On POSIX systems, quoted command-line arguments are no longer split on spaces. (#397)
|
||||
|
||||
### Plugins
|
||||
+ The new `overloadHelper` plugin makes it easier to link to overloaded methods. (#179)
|
||||
+ The `markdown` plugin now converts Markdown links in the `@see` tag. (#297)
|
||||
|
||||
### Default template enhancements
|
||||
+ You can now use the configuration property `templates.default.staticFiles` to copy additional static files to the output directory. (#393)
|
||||
+ All output files now use human-readable filenames. (#339)
|
||||
+ The documentation for events now lists the symbols that listen to that event. (#273)
|
||||
+ Links to source files now allow you to jump to the line where a symbol is defined. (#316)
|
||||
+ The output files now link to individual types within a Closure Compiler type expression. (Multiple issues)
|
||||
+ CommonJS modules that export a single function, rather than an object, are now documented more clearly. (#384)
|
||||
+ Functions that can throw multiple types of errors are now documented more clearly. (#389)
|
||||
+ If a `@property` tag does not identify the property's name, the template no longer throws an error. (#373)
|
||||
+ The type of each `@typedef` is now displayed. (#391)
|
||||
+ If a `@see` tag contains a URL (for example, `@see http://example.com` or `@see <http://example.com>`), the tag text is now converted to a link. (#371)
|
||||
+ Repeatable parameters are now identified. (#381)
|
||||
+ The "Classes" header is no longer repeated in the navigation bar. (#361)
|
||||
+ When the only documented symbols in global scope are type definitions, you can now click the "Global" header to view their documentation. (#261)
|
||||
|
||||
## 3.1.1 (February 2013)
|
||||
|
||||
+ Resolved a crash when no input files contain JSDoc comments. (#329)
|
||||
+ Resolved a crash when JSDoc cannot identify the common prefix of several paths. (#330)
|
||||
+ Resolved a crash when the full path to JSDoc contained at least one space. (#347)
|
||||
+ Files named `README.md` or `package.json` will now be processed when they are specified on the command line. (#350)
|
||||
+ You can now use `@emits` as a synonym for `@fires`. (#324)
|
||||
+ The module `jsdoc/util/templateHelper` now allows you to specify the CSS class for links that are generated by the following methods: (#331)
|
||||
+ `getAncestorLinks`
|
||||
+ `getSignatureReturns`
|
||||
+ `getSignatureTypes`
|
||||
+ `linkto`
|
||||
|
||||
## 3.1.0 (January 2013)
|
||||
|
||||
### Major changes
|
||||
+ You can now use the new `@callback` tag to provide information about a callback function's signature. To document a callback function, create a standalone JSDoc comment, as shown in the following example:
|
||||
|
||||
```javascript
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
function MyClass() {}
|
||||
|
||||
/**
|
||||
* Send a request.
|
||||
*
|
||||
* @param {MyClass~responseCb} cb - Called after a response is received.
|
||||
*/
|
||||
MyClass.prototype.sendRequest = function(cb) {
|
||||
// code
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for sending a request.
|
||||
*
|
||||
* @callback MyClass~responseCb
|
||||
* @param {?string} error - Information about the error.
|
||||
* @param {?string} response - Body of the response.
|
||||
*/
|
||||
```
|
||||
+ The inline link tag, `{@link}`, has been improved:
|
||||
+ You can now use a space as the delimiter between the link target and link text.
|
||||
+ In your `conf.json` file, you can now enable the option `templates.cleverLinks` to display code links in a monospace font and URL links in plain text. You can also enable the option `templates.monospaceLinks` to display all links in a monospace font. **Note**: JSDoc templates must be updated to respect these options.
|
||||
+ You can now use the new inline tags `{@linkplain}`, which forces a plain-text link, and `{@linkcode}`, which forces a monospace link. These tags always override the settings in your `conf.json` file. (#250)
|
||||
+ JSDoc now provides a `-l/--lenient` option that tells JSDoc to continue running if it encounters a non-fatal error. (Multiple issues)
|
||||
+ A template's `publish.js` file should now assign its `publish` function to `exports.publish`, rather than defining a global `publish` function. The global `publish` function is deprecated and may not be supported in future versions. JSDoc's built-in templates reflect this change. (#166)
|
||||
+ The template helper (`templateHelper.js`) exports a variety of new functions for finding information within a parse tree. These functions were previously contained within the default template. (#186)
|
||||
+ Updated the `fs` and `path` modules to make their behavior more consistent with Node.js. In addition, created extended versions of these modules with additional functionality. (Multiple commits)
|
||||
+ Updated or replaced numerous third-party modules. (Multiple commits)
|
||||
+ Reorganized the JSDoc codebase in preparation for future enhancements. (Multiple commits)
|
||||
+ JSDoc now embeds a version of Mozilla Rhino that recognizes Node.js packages, including `package.json` files. (Multiple commits)
|
||||
+ Node.js' `npm` utility can now install JSDoc from its GitHub repository. **Note**: JSDoc is not currently compatible with Node.js. However, this change allows JSDoc to be installed as a dependency of a Node.js project. In this version, global installation with `npm` is not supported. (Multiple commits)
|
||||
|
||||
### Enhancements
|
||||
+ If a `README.md` file is passed to JSDoc, its contents will be included on the `index.html` page of the generated documentation. (#128)
|
||||
+ The `@augments` tag can now refer to an undocumented member, such as `window.XMLHTTPRequest`. (#160)
|
||||
+ The `@extends` tag can now refer to an undocumented member, such as `window.XMLHttpRequest`. In addition, you can now use `@host` as a synonym for `@extends`. (#145)
|
||||
+ The `@lends` tag is now supported in multiline JSDoc comments. (#163)
|
||||
+ On Windows, `jsdoc.cmd` now provides the same options as the `jsdoc` shell script. (#127)
|
||||
+ JSDoc now provides `setTimeout()`, `clearTimeout()`, `setInterval()`, and `clearInterval()` functions. (Multiple commits)
|
||||
+ JSDoc no longer provides a global `exit()` function. Use `process.exit()` instead. (1228a8f7)
|
||||
+ JSDoc now includes additional shims for Node.js' built-in modules. **Note**: Many of these shims implement only the functions that JSDoc uses, and they may not be consistent with Node.js' behavior in edge cases. (Multiple commits)
|
||||
+ JSDoc now provides a `-v/--version` option to display information about the current version. (#303)
|
||||
+ When running tests, you can now use the `--nocolor` option to disable colored output. On Windows, colored output is always disabled. (e17601fe, 8bc33541)
|
||||
|
||||
### Bug fixes
|
||||
+ When using the `@event` tag to define an event within a class or namespace, the event's longname is now set correctly regardless of tag order. (#280)
|
||||
+ The `@property` tag no longer results in malformed parse trees. (20f87094)
|
||||
+ The `jsdoc` and `jsdoc.cmd` scripts now work correctly with paths that include spaces. (#127, #130)
|
||||
+ The `jsdoc` script now works correctly on Cygwin and MinGW, and with the `dash` shell. (#182, #184, #187)
|
||||
+ The `-d/--destination` option is no longer treated as a path relative to the JSDoc directory. Instead, it can contain an absolute path, or a path relative to the current working directory. (f5e3f0f3)
|
||||
+ JSDoc now provides default options for the values in `conf.json`. (#129)
|
||||
+ If the `conf.json` file does not exist, JSDoc no longer tries to create it, which prevents errors if the current user does not have write access to the JSDoc directory. (d2d05fcb)
|
||||
+ Doclets for getters and setters are now parsed appropriately. (#150)
|
||||
+ Only the first asterisk is removed from each line of a JSDoc comment. (#172)
|
||||
+ If a child member overrides an ancestor member, the ancestor member is no longer documented. (#158)
|
||||
+ If a member of a namespace has the same name as a namespace, the member is now documented correctly. (#214)
|
||||
+ The parse tree now uses a single set of properties to track both JSDoc-style type information and Closure Compiler-style type information. (#118)
|
||||
+ If a type has a leading `!`, indicating that it is non-nullable, the leading `!` is now removed from the type name. (#226)
|
||||
+ When Markdown formatting is enabled, underscores in inline `{@link}` tags are no longer treated as Markdown formatting characters. (#259)
|
||||
+ Markdown links now work correctly when a JavaScript reserved word, such as `constructor`, is used as the link text. (#249)
|
||||
+ Markdown files for tutorials are now parsed based on the settings in `conf.json`, rather than using the "evilstreak" Markdown parser in all cases. (#220)
|
||||
+ If a folder contains both tutorial source files and `.js` files, JSDoc no longer attempts to parse the `.js` files as JSON files. (#222)
|
||||
+ The "evilstreak" Markdown parser now works correctly with files that use Windows-style line endings. (#223)
|
||||
+ JSDoc no longer fails unit tests when the `conf.json` file is not present. (#206)
|
||||
+ On Windows, JSDoc now passes all unit tests. (Multiple commits)
|
||||
|
||||
### Plugins
|
||||
+ The new `partial` plugin adds support for a `@partial` tag, which links to an external file that contains JSDoc comments. (#156)
|
||||
+ The new `commentsOnly` plugin removes everything in a file except JSDoc-style comments. You can use this plugin to document source files that are not valid JavaScript, including source files for other languages. (#304)
|
||||
+ The new `eventDumper` plugin logs information about parser events to the console. (#242)
|
||||
+ The new `verbose` plugin logs the name of each input file to the console. (#157)
|
||||
|
||||
### Template enhancements
|
||||
|
||||
#### Default template
|
||||
+ The template output now includes pretty-printed versions of source files. This feature is enabled by default. To disable this feature, add the property `templates.default.outputSourceFiles: false` to your `conf.json` file. (#208)
|
||||
+ You can now use the template if it is placed outside of the JSDoc directory. (#198)
|
||||
+ The template no longer throws an error when a parameter does not have a name. (#175)
|
||||
+ The navigation bar now includes an "Events" section if any events are documented. (#280)
|
||||
+ Pages no longer include a "Classes" header when no classes are documented. (eb0186b9)
|
||||
+ Member details now include "Inherited From" section when a member is inherited from another member. (#154)
|
||||
+ If an `@author` tag contains text in the format "Jane Doe <jdoe@example.com>", the value is now converted to an HTML `mailto:` link. (#326)
|
||||
+ Headings for functions now include the function's signature. (#253)
|
||||
+ Type information is now displayed for events. (#192)
|
||||
+ Functions now link to their return type when appropriate. (#192)
|
||||
+ Type definitions that contain functions are now displayed correctly. (#292)
|
||||
+ Tutorial output is now generated correctly. (#188)
|
||||
+ Output files now use Google Code Prettify with the Tomorrow theme as a syntax highlighter. (#193)
|
||||
+ The `index.html` output file is no longer overwritten if a namespace called `index` has been documented. (#244)
|
||||
+ The current JSDoc version number is now displayed in the footer. (#321)
|
||||
|
||||
#### Haruki template
|
||||
+ Members are now contained in arrays rather than objects, allowing overloaded members to be documented. (#153)
|
||||
+ A clearer error message is now provided when the output destination is not specified correctly. (#174)
|
||||
|
||||
## 3.0.1 (June 2012)
|
||||
|
||||
### Enhancements
|
||||
+ The `conf.json` file may now contain `source.include` and `source.exclude` properties. (#56)
|
||||
+ `source.include` specifies files or directories that JSDoc should _always_ check for documentation.
|
||||
+ `source.exclude` specifies files or directories that JSDoc should _never_ check for documentation.
|
||||
These settings take precedence over the `source.includePattern` and `source.excludePattern` properties, which contain regular expressions that JSDoc uses to search for source files.
|
||||
+ The `-t/--template` option may now specify the absolute path to a template. (#122)
|
||||
|
||||
### Bug fixes
|
||||
+ JSDoc no longer throws exceptions when a symbol has a special name, such as `hasOwnProperty`. (1ef37251)
|
||||
+ The `@alias` tag now works correctly when documenting inner classes as globals. (810dd7f7)
|
||||
|
||||
### Template improvements
|
||||
+ The default template now sorts classes by name correctly when the classes come from several modules. (4ce17195)
|
||||
+ The Haruki template now correctly supports `@example`, `@members`, and `@returns` tags. (6580e176, 59655252, 31c8554d)
|
||||
|
||||
## 3.0.0 (May 2012)
|
||||
|
||||
Initial release.
|
||||
@@ -0,0 +1,468 @@
|
||||
/*global java */
|
||||
/*eslint no-process-exit:0 */
|
||||
/**
|
||||
* Helper methods for running JSDoc on the command line.
|
||||
*
|
||||
* A few critical notes for anyone who works on this module:
|
||||
*
|
||||
* + The module should really export an instance of `cli`, and `props` should be properties of a
|
||||
* `cli` instance. However, Rhino interpreted `this` as a reference to `global` within the
|
||||
* prototype's methods, so we couldn't do that.
|
||||
* + On Rhino, for unknown reasons, the `jsdoc/fs` and `jsdoc/path` modules can fail in some cases
|
||||
* when they are required by this module. You may need to use `fs` and `path` instead.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
module.exports = (function() {
|
||||
'use strict';
|
||||
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var stripJsonComments = require('strip-json-comments');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
var props = {
|
||||
docs: [],
|
||||
packageJson: null,
|
||||
shouldExitWithError: false,
|
||||
tmpdir: null
|
||||
};
|
||||
|
||||
var app = global.app;
|
||||
var env = global.env;
|
||||
|
||||
var FATAL_ERROR_MESSAGE = 'Exiting JSDoc because an error occurred. See the previous log ' +
|
||||
'messages for details.';
|
||||
var cli = {};
|
||||
|
||||
// TODO: docs
|
||||
cli.setVersionInfo = function() {
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
// allow this to throw--something is really wrong if we can't read our own package file
|
||||
var info = JSON.parse( fs.readFileSync(path.join(env.dirname, 'package.json'), 'utf8') );
|
||||
|
||||
env.version = {
|
||||
number: info.version,
|
||||
revision: new Date( parseInt(info.revision, 10) ).toUTCString()
|
||||
};
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.loadConfig = function() {
|
||||
var _ = require('underscore');
|
||||
var args = require('jsdoc/opts/args');
|
||||
var Config = require('jsdoc/config');
|
||||
var fs = require('jsdoc/fs');
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
var confPath;
|
||||
var isFile;
|
||||
|
||||
var defaultOpts = {
|
||||
destination: './out/',
|
||||
encoding: 'utf8'
|
||||
};
|
||||
|
||||
try {
|
||||
env.opts = args.parse(env.args);
|
||||
}
|
||||
catch (e) {
|
||||
console.error(e.message + '\n');
|
||||
cli.printHelp(function() {
|
||||
cli.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
confPath = env.opts.configure || path.join(env.dirname, 'conf.json');
|
||||
try {
|
||||
isFile = fs.statSync(confPath).isFile();
|
||||
}
|
||||
catch(e) {
|
||||
isFile = false;
|
||||
}
|
||||
|
||||
if ( !isFile && !env.opts.configure ) {
|
||||
confPath = path.join(env.dirname, 'conf.json.EXAMPLE');
|
||||
}
|
||||
|
||||
try {
|
||||
env.conf = new Config( stripJsonComments(fs.readFileSync(confPath, 'utf8')) )
|
||||
.get();
|
||||
}
|
||||
catch (e) {
|
||||
cli.exit(1, 'Cannot parse the config file ' + confPath + ': ' + e + '\n' +
|
||||
FATAL_ERROR_MESSAGE);
|
||||
}
|
||||
|
||||
// look for options on the command line, in the config file, and in the defaults, in that order
|
||||
env.opts = _.defaults(env.opts, env.conf.opts, defaultOpts);
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.configureLogger = function() {
|
||||
function recoverableError() {
|
||||
props.shouldExitWithError = true;
|
||||
}
|
||||
|
||||
function fatalError() {
|
||||
cli.exit(1);
|
||||
}
|
||||
|
||||
if (env.opts.debug) {
|
||||
logger.setLevel(logger.LEVELS.DEBUG);
|
||||
}
|
||||
else if (env.opts.verbose) {
|
||||
logger.setLevel(logger.LEVELS.INFO);
|
||||
}
|
||||
|
||||
if (env.opts.pedantic) {
|
||||
logger.once('logger:warn', recoverableError);
|
||||
logger.once('logger:error', fatalError);
|
||||
}
|
||||
else {
|
||||
logger.once('logger:error', recoverableError);
|
||||
}
|
||||
|
||||
logger.once('logger:fatal', fatalError);
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.logStart = function() {
|
||||
logger.debug( cli.getVersion() );
|
||||
|
||||
logger.debug('Environment info: %j', {
|
||||
env: {
|
||||
conf: env.conf,
|
||||
opts: env.opts
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.logFinish = function() {
|
||||
var delta;
|
||||
var deltaSeconds;
|
||||
|
||||
if (env.run.finish && env.run.start) {
|
||||
delta = env.run.finish.getTime() - env.run.start.getTime();
|
||||
}
|
||||
|
||||
if (delta !== undefined) {
|
||||
deltaSeconds = (delta / 1000).toFixed(2);
|
||||
logger.info('Finished running in %s seconds.', deltaSeconds);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.runCommand = function(cb) {
|
||||
var cmd;
|
||||
|
||||
var opts = env.opts;
|
||||
|
||||
function done(errorCode) {
|
||||
if (!errorCode && props.shouldExitWithError) {
|
||||
cb(1);
|
||||
}
|
||||
else {
|
||||
cb(errorCode);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.help) {
|
||||
cmd = cli.printHelp;
|
||||
}
|
||||
else if (opts.test) {
|
||||
cmd = cli.runTests;
|
||||
}
|
||||
else if (opts.version) {
|
||||
cmd = cli.printVersion;
|
||||
}
|
||||
else {
|
||||
cmd = cli.main;
|
||||
}
|
||||
|
||||
cmd(done);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.printHelp = function(cb) {
|
||||
cli.printVersion();
|
||||
console.log( '\n' + require('jsdoc/opts/args').help() + '\n' );
|
||||
console.log('Visit http://usejsdoc.org for more information.');
|
||||
cb(0);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.runTests = function(cb) {
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
var runner = require( path.join(env.dirname, 'test/runner') );
|
||||
|
||||
console.log('Running tests...');
|
||||
runner(function(failCount) {
|
||||
cb(failCount);
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.getVersion = function() {
|
||||
return 'JSDoc ' + env.version.number + ' (' + env.version.revision + ')';
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.printVersion = function(cb) {
|
||||
console.log( cli.getVersion() );
|
||||
|
||||
if (cb) {
|
||||
cb(0);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.main = function(cb) {
|
||||
cli.scanFiles();
|
||||
|
||||
if (env.sourceFiles.length) {
|
||||
cli.createParser()
|
||||
.parseFiles()
|
||||
.processParseResults();
|
||||
}
|
||||
else {
|
||||
console.log('There are no input files to process.\n');
|
||||
cli.printHelp(cb);
|
||||
}
|
||||
|
||||
env.run.finish = new Date();
|
||||
cb(0);
|
||||
};
|
||||
|
||||
function readPackageJson(filepath) {
|
||||
var fs = require('jsdoc/fs');
|
||||
|
||||
try {
|
||||
return stripJsonComments( fs.readFileSync(filepath, 'utf8') );
|
||||
}
|
||||
catch (e) {
|
||||
logger.error('Unable to read the package file "%s"', filepath);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function buildSourceList() {
|
||||
var fs = require('jsdoc/fs');
|
||||
var Readme = require('jsdoc/readme');
|
||||
|
||||
var packageJson;
|
||||
var readmeHtml;
|
||||
var sourceFile;
|
||||
var sourceFiles = env.opts._ ? env.opts._.slice(0) : [];
|
||||
|
||||
if (env.conf.source && env.conf.source.include) {
|
||||
sourceFiles = sourceFiles.concat(env.conf.source.include);
|
||||
}
|
||||
|
||||
// load the user-specified package/README files, if any
|
||||
if (env.opts.package) {
|
||||
packageJson = readPackageJson(env.opts.package);
|
||||
}
|
||||
if (env.opts.readme) {
|
||||
readmeHtml = new Readme(env.opts.readme).html;
|
||||
}
|
||||
|
||||
// source files named `package.json` or `README.md` get special treatment, unless the user
|
||||
// explicitly specified a package and/or README file
|
||||
for (var i = 0, l = sourceFiles.length; i < l; i++) {
|
||||
sourceFile = sourceFiles[i];
|
||||
|
||||
if ( !env.opts.package && /\bpackage\.json$/i.test(sourceFile) ) {
|
||||
packageJson = readPackageJson(sourceFile);
|
||||
sourceFiles.splice(i--, 1);
|
||||
}
|
||||
|
||||
if ( !env.opts.readme && /(\bREADME|\.md)$/i.test(sourceFile) ) {
|
||||
readmeHtml = new Readme(sourceFile).html;
|
||||
sourceFiles.splice(i--, 1);
|
||||
}
|
||||
}
|
||||
|
||||
props.packageJson = packageJson;
|
||||
env.opts.readme = readmeHtml;
|
||||
|
||||
return sourceFiles;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
cli.scanFiles = function() {
|
||||
var Filter = require('jsdoc/src/filter').Filter;
|
||||
|
||||
var filter;
|
||||
|
||||
env.opts._ = buildSourceList();
|
||||
|
||||
// are there any files to scan and parse?
|
||||
if (env.conf.source && env.opts._.length) {
|
||||
filter = new Filter(env.conf.source);
|
||||
|
||||
env.sourceFiles = app.jsdoc.scanner.scan(env.opts._, (env.opts.recurse ? 10 : undefined),
|
||||
filter);
|
||||
}
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
function resolvePluginPaths(paths) {
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
var pluginPaths = [];
|
||||
|
||||
paths.forEach(function(plugin) {
|
||||
var basename = path.basename(plugin);
|
||||
var dirname = path.dirname(plugin);
|
||||
var pluginPath = path.getResourcePath(dirname);
|
||||
|
||||
if (!pluginPath) {
|
||||
logger.error('Unable to find the plugin "%s"', plugin);
|
||||
return;
|
||||
}
|
||||
|
||||
pluginPaths.push( path.join(pluginPath, basename) );
|
||||
});
|
||||
|
||||
return pluginPaths;
|
||||
}
|
||||
|
||||
cli.createParser = function() {
|
||||
var handlers = require('jsdoc/src/handlers');
|
||||
var parser = require('jsdoc/src/parser');
|
||||
var path = require('jsdoc/path');
|
||||
var plugins = require('jsdoc/plugins');
|
||||
|
||||
app.jsdoc.parser = parser.createParser(env.conf.parser);
|
||||
|
||||
if (env.conf.plugins) {
|
||||
env.conf.plugins = resolvePluginPaths(env.conf.plugins);
|
||||
plugins.installPlugins(env.conf.plugins, app.jsdoc.parser);
|
||||
}
|
||||
|
||||
handlers.attachTo(app.jsdoc.parser);
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
cli.parseFiles = function() {
|
||||
var augment = require('jsdoc/augment');
|
||||
var borrow = require('jsdoc/borrow');
|
||||
var Package = require('jsdoc/package').Package;
|
||||
|
||||
var docs;
|
||||
var packageDocs;
|
||||
|
||||
props.docs = docs = app.jsdoc.parser.parse(env.sourceFiles, env.opts.encoding);
|
||||
|
||||
// If there is no package.json, just create an empty package
|
||||
packageDocs = new Package(props.packageJson);
|
||||
packageDocs.files = env.sourceFiles || [];
|
||||
docs.push(packageDocs);
|
||||
|
||||
logger.debug('Indexing doclets...');
|
||||
borrow.indexAll(docs);
|
||||
logger.debug('Adding inherited symbols, mixins, and interface implementations...');
|
||||
augment.augmentAll(docs);
|
||||
logger.debug('Adding borrowed doclets...');
|
||||
borrow.resolveBorrows(docs);
|
||||
logger.debug('Post-processing complete.');
|
||||
|
||||
app.jsdoc.parser.fireProcessingComplete(docs);
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
cli.processParseResults = function() {
|
||||
if (env.opts.explain) {
|
||||
cli.dumpParseResults();
|
||||
}
|
||||
else {
|
||||
cli.resolveTutorials();
|
||||
cli.generateDocs();
|
||||
}
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
cli.dumpParseResults = function() {
|
||||
global.dump(props.docs);
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
cli.resolveTutorials = function() {
|
||||
var resolver = require('jsdoc/tutorial/resolver');
|
||||
|
||||
if (env.opts.tutorials) {
|
||||
resolver.load(env.opts.tutorials);
|
||||
resolver.resolve();
|
||||
}
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
cli.generateDocs = function() {
|
||||
var path = require('jsdoc/path');
|
||||
var resolver = require('jsdoc/tutorial/resolver');
|
||||
var taffy = require('taffydb').taffy;
|
||||
|
||||
var template;
|
||||
|
||||
env.opts.template = (function() {
|
||||
var publish = env.opts.template || 'templates/default';
|
||||
var templatePath = path.getResourcePath(publish);
|
||||
|
||||
// if we didn't find the template, keep the user-specified value so the error message is
|
||||
// useful
|
||||
return templatePath || env.opts.template;
|
||||
})();
|
||||
|
||||
try {
|
||||
template = require(env.opts.template + '/publish');
|
||||
}
|
||||
catch(e) {
|
||||
logger.fatal('Unable to load template: ' + e.message || e);
|
||||
}
|
||||
|
||||
// templates should include a publish.js file that exports a "publish" function
|
||||
if (template.publish && typeof template.publish === 'function') {
|
||||
logger.printInfo('Generating output files...');
|
||||
template.publish(
|
||||
taffy(props.docs),
|
||||
env.opts,
|
||||
resolver.root
|
||||
);
|
||||
logger.info('complete.');
|
||||
}
|
||||
else {
|
||||
logger.fatal(env.opts.template + ' does not export a "publish" function. Global ' +
|
||||
'"publish" functions are no longer supported.');
|
||||
}
|
||||
|
||||
return cli;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
cli.exit = function(exitCode, message) {
|
||||
if (message && exitCode > 0) {
|
||||
console.error(message);
|
||||
}
|
||||
|
||||
process.exit(exitCode || 0);
|
||||
};
|
||||
|
||||
return cli;
|
||||
})();
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"tags": {
|
||||
"allowUnknownTags": true
|
||||
},
|
||||
"source": {
|
||||
"includePattern": ".+\\.js(doc)?$",
|
||||
"excludePattern": "(^|\\/|\\\\)_"
|
||||
},
|
||||
"plugins": [],
|
||||
"templates": {
|
||||
"cleverLinks": false,
|
||||
"monospaceLinks": false,
|
||||
"default": {
|
||||
"outputSourceFiles": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env node
|
||||
/*global arguments, require: true */
|
||||
/**
|
||||
* @project jsdoc
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @license See LICENSE.md file included in this distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Data representing the environment in which this app is running.
|
||||
*
|
||||
* @namespace
|
||||
* @name env
|
||||
*/
|
||||
global.env = {
|
||||
/**
|
||||
* Running start and finish times.
|
||||
*
|
||||
* @memberof env
|
||||
*/
|
||||
run: {
|
||||
start: new Date(),
|
||||
finish: null
|
||||
},
|
||||
|
||||
/**
|
||||
* The command-line arguments passed into JSDoc.
|
||||
*
|
||||
* @type Array
|
||||
* @memberof env
|
||||
*/
|
||||
args: [],
|
||||
|
||||
/**
|
||||
* The parsed JSON data from the configuration file.
|
||||
*
|
||||
* @type Object
|
||||
* @memberof env
|
||||
*/
|
||||
conf: {},
|
||||
|
||||
/**
|
||||
* The absolute path to the base directory of the JSDoc application.
|
||||
*
|
||||
* @private
|
||||
* @type string
|
||||
* @memberof env
|
||||
*/
|
||||
dirname: '.',
|
||||
|
||||
/**
|
||||
* The user's working directory at the time that JSDoc was started.
|
||||
*
|
||||
* @private
|
||||
* @type string
|
||||
* @memberof env
|
||||
*/
|
||||
pwd: null,
|
||||
|
||||
/**
|
||||
* The command-line options, parsed into a key/value hash.
|
||||
*
|
||||
* @type Object
|
||||
* @memberof env
|
||||
* @example if (global.env.opts.help) { console.log('Helpful message.'); }
|
||||
*/
|
||||
opts: {},
|
||||
|
||||
/**
|
||||
* The source files that JSDoc will parse.
|
||||
* @type Array
|
||||
* @memberof env
|
||||
*/
|
||||
sourceFiles: [],
|
||||
|
||||
/**
|
||||
* The JSDoc version number and revision date.
|
||||
*
|
||||
* @type Object
|
||||
* @memberof env
|
||||
*/
|
||||
version: {}
|
||||
};
|
||||
|
||||
// initialize the environment for the current JavaScript VM
|
||||
(function(args) {
|
||||
'use strict';
|
||||
|
||||
var path;
|
||||
|
||||
if (args[0] && typeof args[0] === 'object') {
|
||||
// we should be on Node.js
|
||||
args = [__dirname, process.cwd()];
|
||||
path = require('path');
|
||||
|
||||
// Create a custom require method that adds `lib/jsdoc` and `node_modules` to the module
|
||||
// lookup path. This makes it possible to `require('jsdoc/foo')` from external templates and
|
||||
// plugins, and within JSDoc itself. It also allows external templates and plugins to
|
||||
// require JSDoc's module dependencies without installing them locally.
|
||||
require = require('requizzle')({
|
||||
requirePaths: {
|
||||
before: [path.join(__dirname, 'lib')],
|
||||
after: [path.join(__dirname, 'node_modules')]
|
||||
},
|
||||
infect: true
|
||||
});
|
||||
}
|
||||
|
||||
require('./lib/jsdoc/util/runtime').initialize(args);
|
||||
})( Array.prototype.slice.call(arguments, 0) );
|
||||
|
||||
/**
|
||||
* Data that must be shared across the entire application.
|
||||
*
|
||||
* @namespace
|
||||
* @name app
|
||||
*/
|
||||
global.app = {
|
||||
jsdoc: {
|
||||
name: require('./lib/jsdoc/name'),
|
||||
parser: null,
|
||||
scanner: new (require('./lib/jsdoc/src/scanner').Scanner)()
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively print an object's properties to stdout. This method is safe to use with objects that
|
||||
* contain circular references. In addition, on Mozilla Rhino, this method is safe to use with
|
||||
* native Java objects.
|
||||
*
|
||||
* @global
|
||||
* @name dump
|
||||
* @private
|
||||
* @param {Object} obj - Object(s) to print to stdout.
|
||||
*/
|
||||
global.dump = function() {
|
||||
'use strict';
|
||||
|
||||
var _dump = require('./lib/jsdoc/util/dumper').dump;
|
||||
|
||||
for (var i = 0, l = arguments.length; i < l; i++) {
|
||||
console.log( _dump(arguments[i]) );
|
||||
}
|
||||
};
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var logger = require('./lib/jsdoc/util/logger');
|
||||
var runtime = require('./lib/jsdoc/util/runtime');
|
||||
var cli = require('./cli');
|
||||
|
||||
function cb(errorCode) {
|
||||
cli.logFinish();
|
||||
cli.exit(errorCode || 0);
|
||||
}
|
||||
|
||||
cli.setVersionInfo()
|
||||
.loadConfig();
|
||||
|
||||
if (!global.env.opts.test) {
|
||||
cli.configureLogger();
|
||||
}
|
||||
|
||||
cli.logStart();
|
||||
|
||||
// On Rhino, we use a try/catch block so we can log the Java exception (if available)
|
||||
if ( runtime.isRhino() ) {
|
||||
try {
|
||||
cli.runCommand(cb);
|
||||
}
|
||||
catch(e) {
|
||||
if (e.rhinoException) {
|
||||
logger.fatal( e.rhinoException.printStackTrace() );
|
||||
} else {
|
||||
console.trace(e);
|
||||
cli.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
cli.runCommand(cb);
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,492 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Provides methods for augmenting the parse results based on their content.
|
||||
* @module jsdoc/augment
|
||||
*/
|
||||
|
||||
var doop = require('jsdoc/util/doop');
|
||||
var name = require('jsdoc/name');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
function mapDependencies(index, propertyName) {
|
||||
var dependencies = {};
|
||||
var doc;
|
||||
var doclets;
|
||||
var kinds = ['class', 'external', 'mixin'];
|
||||
var len = 0;
|
||||
|
||||
Object.keys(index).forEach(function(name) {
|
||||
doclets = index[name];
|
||||
for (var i = 0, ii = doclets.length; i < ii; i++) {
|
||||
doc = doclets[i];
|
||||
if (kinds.indexOf(doc.kind) !== -1) {
|
||||
dependencies[name] = {};
|
||||
if (hasOwnProp.call(doc, propertyName)) {
|
||||
len = doc[propertyName].length;
|
||||
for (var j = 0; j < len; j++) {
|
||||
dependencies[name][doc[propertyName][j]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
function Sorter(dependencies) {
|
||||
this.dependencies = dependencies;
|
||||
this.visited = {};
|
||||
this.sorted = [];
|
||||
}
|
||||
|
||||
Sorter.prototype.visit = function(key) {
|
||||
var self = this;
|
||||
|
||||
if (!(key in this.visited)) {
|
||||
this.visited[key] = true;
|
||||
|
||||
if (this.dependencies[key]) {
|
||||
Object.keys(this.dependencies[key]).forEach(function(path) {
|
||||
self.visit(path);
|
||||
});
|
||||
}
|
||||
|
||||
this.sorted.push(key);
|
||||
}
|
||||
};
|
||||
|
||||
Sorter.prototype.sort = function() {
|
||||
var self = this;
|
||||
|
||||
Object.keys(this.dependencies).forEach(function(key) {
|
||||
self.visit(key);
|
||||
});
|
||||
|
||||
return this.sorted;
|
||||
};
|
||||
|
||||
function sort(dependencies) {
|
||||
var sorter = new Sorter(dependencies);
|
||||
return sorter.sort();
|
||||
}
|
||||
|
||||
function getMembers(longname, docs, scopes) {
|
||||
var candidate;
|
||||
var members = [];
|
||||
|
||||
for (var i = 0, l = docs.length; i < l; i++) {
|
||||
candidate = docs[i];
|
||||
|
||||
if (candidate.memberof === longname &&
|
||||
(!scopes || !scopes.length || scopes.indexOf(candidate.scope) !== -1)) {
|
||||
members.push(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
function addDocletProperty(doclets, propName, value) {
|
||||
for (var i = 0, l = doclets.length; i < l; i++) {
|
||||
doclets[i][propName] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function reparentDoclet(parent, child) {
|
||||
var parts = name.shorten(child.longname);
|
||||
|
||||
parts.memberof = parent.longname;
|
||||
child.memberof = parent.longname;
|
||||
child.longname = name.combine(parts);
|
||||
}
|
||||
|
||||
function parentIsClass(parent) {
|
||||
return parent.kind === 'class';
|
||||
}
|
||||
|
||||
function staticToInstance(doclet) {
|
||||
var parts = name.shorten(doclet.longname);
|
||||
|
||||
parts.scope = name.SCOPE.PUNC.INSTANCE;
|
||||
doclet.longname = name.combine(parts);
|
||||
doclet.scope = name.SCOPE.NAMES.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the list of doclets to be added to another symbol.
|
||||
*
|
||||
* We add only one doclet per longname. For example: If `ClassA` inherits from two classes that both
|
||||
* use the same method name, `ClassA` gets docs for one method rather than two.
|
||||
*
|
||||
* Also, the last symbol wins for any given longname. For example: If you write `@extends Class1
|
||||
* @extends Class2`, and both classes have an instance method called `myMethod`, you get the docs
|
||||
* from `Class2#myMethod`.
|
||||
*
|
||||
* @private
|
||||
* @param {Array.<module:jsdoc/doclet.Doclet>} additions - An array of doclets that will be added to
|
||||
* another symbol.
|
||||
* @param {Object.<string, number>} indexes - A dictionary of indexes into the `additions` array.
|
||||
* Each key is a longname, and each value is the index of the longname's doclet.
|
||||
* @return {void}
|
||||
*/
|
||||
function updateAddedDoclets(doclet, additions, indexes) {
|
||||
if (typeof indexes[doclet.longname] !== 'undefined') {
|
||||
// replace the existing doclet
|
||||
additions[indexes[doclet.longname]] = doclet;
|
||||
}
|
||||
else {
|
||||
// add the doclet to the array, and track its index
|
||||
additions.push(doclet);
|
||||
indexes[doclet.longname] = additions.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
function explicitlyInherits(doclets) {
|
||||
var doclet;
|
||||
var inherits = false;
|
||||
|
||||
for (var i = 0, l = doclets.length; i < l; i++) {
|
||||
doclet = doclets[i];
|
||||
if (typeof doclet.inheritdoc !== 'undefined' || typeof doclet.override !== 'undefined') {
|
||||
inherits = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return inherits;
|
||||
}
|
||||
|
||||
function getInheritedAdditions(doclets, docs, documented) {
|
||||
var additionIndexes;
|
||||
var additions = [];
|
||||
var doc;
|
||||
var parents;
|
||||
var members;
|
||||
var member;
|
||||
var parts;
|
||||
|
||||
// doclets will be undefined if the inherited symbol isn't documented
|
||||
doclets = doclets || [];
|
||||
|
||||
for (var i = 0, ii = doclets.length; i < ii; i++) {
|
||||
doc = doclets[i];
|
||||
parents = doc.augments;
|
||||
|
||||
if (parents && doc.kind === 'class') {
|
||||
// reset the lookup table of added doclet indexes by longname
|
||||
additionIndexes = {};
|
||||
|
||||
for (var j = 0, jj = parents.length; j < jj; j++) {
|
||||
members = getMembers(parents[j], docs, ['instance']);
|
||||
|
||||
for (var k = 0, kk = members.length; k < kk; k++) {
|
||||
member = doop(members[k]);
|
||||
|
||||
if (!member.inherited) {
|
||||
member.inherits = member.longname;
|
||||
}
|
||||
member.inherited = true;
|
||||
|
||||
// TODO: this will fail on longnames like: MyClass#"quoted#Longname"
|
||||
// and nested instance members like: MyClass#MyOtherClass#myMethod;
|
||||
// switch to updateLongname()!
|
||||
member.memberof = doc.longname;
|
||||
parts = member.longname.split('#');
|
||||
parts[0] = doc.longname;
|
||||
member.longname = parts.join('#');
|
||||
|
||||
// Indicate what the descendant is overriding. (We only care about the closest
|
||||
// ancestor. For classes A > B > C, if B#a overrides A#a, and C#a inherits B#a,
|
||||
// we don't want the doclet for C#a to say that it overrides A#a.)
|
||||
addDocletProperty([member], 'overrides', members[k].longname);
|
||||
|
||||
// Add the ancestor's docs unless the descendant overrides the ancestor AND
|
||||
// documents the override.
|
||||
if ( !hasOwnProp.call(documented, member.longname) ) {
|
||||
updateAddedDoclets(member, additions, additionIndexes);
|
||||
}
|
||||
// If the descendant used an @inheritdoc or @override tag, add the ancestor's
|
||||
// docs, and ignore the existing doclets.
|
||||
else if ( explicitlyInherits(documented[member.longname]) ) {
|
||||
// Ignore any existing doclets. (This is safe because we only get here if
|
||||
// `member.longname` is an own property of `documented`.)
|
||||
addDocletProperty(documented[member.longname], 'ignore', true);
|
||||
|
||||
updateAddedDoclets(member, additions, additionIndexes);
|
||||
|
||||
// Remove property that's no longer accurate.
|
||||
if (member.virtual) {
|
||||
delete member.virtual;
|
||||
}
|
||||
// Remove properties that we no longer need.
|
||||
if (member.inheritdoc) {
|
||||
delete member.inheritdoc;
|
||||
}
|
||||
if (member.override) {
|
||||
delete member.override;
|
||||
}
|
||||
}
|
||||
// If the descendant overrides the ancestor and documents the override,
|
||||
// update the doclets to indicate what the descendant is overriding.
|
||||
else {
|
||||
addDocletProperty(documented[member.longname], 'overrides',
|
||||
members[k].longname);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return additions;
|
||||
}
|
||||
|
||||
function updateMixes(mixedDoclet, mixedLongname) {
|
||||
var idx;
|
||||
var mixedName;
|
||||
var names;
|
||||
|
||||
// take the fast path if there's no array of mixed-in longnames
|
||||
if (!mixedDoclet.mixes) {
|
||||
mixedDoclet.mixes = [mixedLongname];
|
||||
}
|
||||
else {
|
||||
// find the short name of the longname we're mixing in
|
||||
mixedName = name.shorten(mixedLongname).name;
|
||||
// find the short name of each previously mixed-in symbol
|
||||
names = mixedDoclet.mixes.map(function(m) {
|
||||
return name.shorten(mixedDoclet.longname).name;
|
||||
});
|
||||
|
||||
// if we're mixing `myMethod` into `MixinC` from `MixinB`, and `MixinB` had the method mixed
|
||||
// in from `MixinA`, don't show `MixinA.myMethod` in the `mixes` list
|
||||
idx = names.indexOf(mixedName);
|
||||
if (idx !== -1) {
|
||||
mixedDoclet.mixes.splice(idx, 1);
|
||||
}
|
||||
|
||||
mixedDoclet.mixes.push(mixedLongname);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: try to reduce overlap with getInheritedAdditions
|
||||
function getMixedInAdditions(mixinDoclets, allDoclets, commentedDoclets) {
|
||||
var additionIndexes;
|
||||
var additions = [];
|
||||
var doclet;
|
||||
var idx;
|
||||
var mixedDoclet;
|
||||
var mixedDoclets;
|
||||
var mixes;
|
||||
|
||||
// mixinDoclets will be undefined if the mixed-in symbol isn't documented
|
||||
mixinDoclets = mixinDoclets || [];
|
||||
|
||||
for (var i = 0, ii = mixinDoclets.length; i < ii; i++) {
|
||||
doclet = mixinDoclets[i];
|
||||
mixes = doclet.mixes;
|
||||
|
||||
if (mixes) {
|
||||
// reset the lookup table of added doclet indexes by longname
|
||||
additionIndexes = {};
|
||||
|
||||
for (var j = 0, jj = mixes.length; j < jj; j++) {
|
||||
mixedDoclets = getMembers(mixes[j], allDoclets, ['static']);
|
||||
|
||||
for (var k = 0, kk = mixedDoclets.length; k < kk; k++) {
|
||||
mixedDoclet = doop(mixedDoclets[k]);
|
||||
|
||||
updateMixes(mixedDoclet, mixedDoclet.longname);
|
||||
mixedDoclet.mixed = true;
|
||||
|
||||
reparentDoclet(doclet, mixedDoclet);
|
||||
|
||||
// if we're mixing into a class, treat the mixed-in symbol as an instance member
|
||||
if (parentIsClass(doclet)) {
|
||||
staticToInstance(mixedDoclet);
|
||||
}
|
||||
|
||||
updateAddedDoclets(mixedDoclet, additions, additionIndexes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return additions;
|
||||
}
|
||||
|
||||
function augment(doclets, propertyName, docletFinder) {
|
||||
var index = doclets.index.longname;
|
||||
var dependencies = sort( mapDependencies(index, propertyName) );
|
||||
|
||||
dependencies.forEach(function(name) {
|
||||
var additions = docletFinder.call(null, index[name], doclets, doclets.index.documented);
|
||||
|
||||
additions.forEach(function(addition) {
|
||||
var longname = addition.longname;
|
||||
|
||||
if ( !hasOwnProp.call(index, longname) ) {
|
||||
index[longname] = [];
|
||||
}
|
||||
index[longname].push(addition);
|
||||
doclets.push(addition);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add doclets to reflect class inheritance.
|
||||
*
|
||||
* For example, if `ClassA` has the instance method `myMethod`, and `ClassB` inherits from `ClassA`,
|
||||
* calling this method creates a new doclet for `ClassB#myMethod`.
|
||||
*
|
||||
* @param {!Array.<module:jsdoc/doclet.Doclet>} doclets - The doclets generated by JSDoc.
|
||||
* @param {!Object} doclets.index - The doclet index added by {@link module:jsdoc/borrow.indexAll}.
|
||||
* @return {void}
|
||||
*/
|
||||
exports.addInherited = function(doclets) {
|
||||
augment(doclets, 'augments', getInheritedAdditions);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add doclets to reflect mixins. When a symbol is mixed into a class, the class' version of the
|
||||
* mixed-in symbol is treated as an instance member.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* + If `MixinA` has the static method `myMethod`, and `MixinB` mixes `MixinA`, calling this method
|
||||
* creates a new doclet for the static method `MixinB.myMethod`.
|
||||
* + If `MixinA` has the static method `myMethod`, and `ClassA` mixes `MixinA`, calling this method
|
||||
* creates a new doclet for the instance method `ClassA#myMethod`.
|
||||
*
|
||||
* @param {!Array.<module:jsdoc/doclet.Doclet>} doclets - The doclets generated by JSDoc.
|
||||
* @param {!Object} doclets.index - The doclet index added by {@link module:jsdoc/borrow.indexAll}.
|
||||
* @return {void}
|
||||
*/
|
||||
exports.addMixedIn = function(doclets) {
|
||||
augment(doclets, 'mixes', getMixedInAdditions);
|
||||
};
|
||||
|
||||
// TODO: move as much of this as possible to jsdoc/borrow.indexAll
|
||||
/**
|
||||
* Update doclets to reflect implementations of interfaces.
|
||||
*
|
||||
* For example, if `InterfaceA` has the instance method `myMethod`, and `ClassA` implements
|
||||
* `InterfaceA`, calling this method does the following:
|
||||
*
|
||||
* + Updates `InterfaceA` to indicate that it is implemented by `ClassA`
|
||||
* + Updates `InterfaceA#myMethod` to indicate that it is implemented by `ClassA#myMethod`
|
||||
* + Updates `ClassA#myMethod` to indicate that it implements `InterfaceA#myMethod`
|
||||
*
|
||||
* @param {!Array.<module:jsdoc/doclet.Doclet>} docs - The doclets generated by JSDoc.
|
||||
* @param {!Object} doclets.index - The doclet index added by {@link module:jsdoc/borrow.indexAll}.
|
||||
* @return {void}
|
||||
*/
|
||||
exports.addImplemented = function(docs) {
|
||||
var docMap = {};
|
||||
var interfaces = {};
|
||||
var implemented = {};
|
||||
var memberInfo = {};
|
||||
|
||||
docs.forEach(function(doc) {
|
||||
var memberof = doc.memberof || doc.name;
|
||||
|
||||
if (!hasOwnProp.call(docMap, memberof)) {
|
||||
docMap[memberof] = [];
|
||||
}
|
||||
docMap[memberof].push(doc);
|
||||
|
||||
if (doc.kind === 'interface') {
|
||||
interfaces[doc.longname] = doc;
|
||||
}
|
||||
else if (doc.implements && doc.implements.length) {
|
||||
if (!hasOwnProp.call(implemented, doc.memberof)) {
|
||||
implemented[memberof] = [];
|
||||
}
|
||||
implemented[memberof].push(doc);
|
||||
}
|
||||
});
|
||||
|
||||
// create an dictionary of interface doclets
|
||||
Object.keys(interfaces).forEach(function(ifaceName) {
|
||||
var iface = interfaces[ifaceName];
|
||||
if (hasOwnProp.call(docMap, iface.name)) {
|
||||
docMap[iface.name].forEach(function(doc) {
|
||||
var members = memberInfo[doc.memberof];
|
||||
|
||||
if (!members) {
|
||||
members = memberInfo[doc.memberof] = {};
|
||||
}
|
||||
members[doc.name] = doc;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(implemented).forEach(function(key) {
|
||||
// implemented classes namespace.
|
||||
var owner = implemented[key];
|
||||
|
||||
owner.forEach(function(klass) {
|
||||
// class's interfaces
|
||||
klass.implements.forEach(function(impl) {
|
||||
var interfaceMember;
|
||||
var interfaceMembers = memberInfo[impl];
|
||||
var member;
|
||||
var members;
|
||||
|
||||
// mark the interface as being implemented by the class
|
||||
if (hasOwnProp.call(interfaces, impl)) {
|
||||
interfaces[impl].implementations = interfaces[impl].implementations || [];
|
||||
interfaces[impl].implementations.push(klass.longname);
|
||||
}
|
||||
|
||||
// if the interface has no members, skip to the next owner
|
||||
if (!interfaceMembers) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasOwnProp.call(docMap, klass.longname)) {
|
||||
docMap[klass.longname] = [];
|
||||
}
|
||||
members = docMap[klass.longname];
|
||||
|
||||
for (var i = 0, len = members.length; i < len; i++) {
|
||||
member = members[i];
|
||||
interfaceMember = interfaceMembers && interfaceMembers[member.name];
|
||||
|
||||
// if we didn't find the member name in the interface, skip to the next member
|
||||
if (!interfaceMember) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// mark members that implement an interface
|
||||
member.implements = member.implements || [];
|
||||
member.implements.push(interfaceMember.longname);
|
||||
|
||||
// mark interface members that the symbol implements
|
||||
interfaceMember.implementations = interfaceMember.implementations || [];
|
||||
interfaceMember.implementations.push(member.longname);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Add and update doclets to reflect all of the following:
|
||||
*
|
||||
* + Inherited classes
|
||||
* + Mixins
|
||||
* + Interface implementations
|
||||
*
|
||||
* Calling this method is equivalent to calling all other methods exported by this module.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
exports.augmentAll = function(doclets) {
|
||||
exports.addInherited(doclets);
|
||||
exports.addMixedIn(doclets);
|
||||
exports.addImplemented(doclets);
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
A collection of functions relating to resolving @borrows tags in JSDoc symbols.
|
||||
@module jsdoc/borrow
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var doop = require('jsdoc/util/doop');
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var SCOPE = require('jsdoc/name').SCOPE;
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
// TODO: add the index at parse time, so we don't have to iterate over all the doclets again
|
||||
exports.indexAll = function(doclets) {
|
||||
var borrowed = [];
|
||||
var doclet;
|
||||
var documented = {};
|
||||
var longname = {};
|
||||
|
||||
for (var i = 0, l = doclets.length; i < l; i++) {
|
||||
doclet = doclets[i];
|
||||
|
||||
// track all doclets by longname
|
||||
if ( !hasOwnProp.call(longname, doclet.longname) ) {
|
||||
longname[doclet.longname] = [];
|
||||
}
|
||||
longname[doclet.longname].push(doclet);
|
||||
|
||||
// track longnames of documented symbols
|
||||
if (!doclet.undocumented) {
|
||||
if ( !hasOwnProp.call(documented, doclet.longname) ) {
|
||||
documented[doclet.longname] = [];
|
||||
}
|
||||
documented[doclet.longname].push(doclet);
|
||||
}
|
||||
|
||||
// track doclets with a `borrowed` property
|
||||
if ( hasOwnProp.call(doclet, 'borrowed') ) {
|
||||
borrowed.push(doclet);
|
||||
}
|
||||
}
|
||||
|
||||
doclets.index = {
|
||||
borrowed: borrowed,
|
||||
documented: documented,
|
||||
longname: longname
|
||||
};
|
||||
};
|
||||
|
||||
function cloneBorrowedDoclets(doclet, doclets) {
|
||||
doclet.borrowed.forEach(function(borrowed) {
|
||||
var borrowedDoclets = doclets.index.longname[borrowed.from];
|
||||
var borrowedAs = borrowed.as || borrowed.from;
|
||||
var clonedDoclets;
|
||||
var parts;
|
||||
var scopePunc;
|
||||
|
||||
if (borrowedDoclets) {
|
||||
borrowedAs = borrowedAs.replace(/^prototype\./, SCOPE.PUNC.INSTANCE);
|
||||
clonedDoclets = doop(borrowedDoclets).forEach(function(clone) {
|
||||
// TODO: this will fail on longnames like '"Foo#bar".baz'
|
||||
parts = borrowedAs.split(SCOPE.PUNC.INSTANCE);
|
||||
|
||||
if (parts.length === 2) {
|
||||
clone.scope = SCOPE.NAMES.INSTANCE;
|
||||
scopePunc = SCOPE.PUNC.INSTANCE;
|
||||
}
|
||||
else {
|
||||
clone.scope = SCOPE.NAMES.STATIC;
|
||||
scopePunc = SCOPE.PUNC.STATIC;
|
||||
}
|
||||
|
||||
clone.name = parts.pop();
|
||||
clone.memberof = doclet.longname;
|
||||
clone.longname = clone.memberof + scopePunc + clone.name;
|
||||
doclets.push(clone);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// requires docs to have been indexed: docs.index must be defined here
|
||||
/**
|
||||
Take a copy of the docs for borrowed symbols and attach them to the
|
||||
docs for the borrowing symbol. This process changes the symbols involved,
|
||||
moving docs from the "borrowed" array and into the general docs, then
|
||||
deleting the "borrowed" array.
|
||||
*/
|
||||
exports.resolveBorrows = function(doclets) {
|
||||
var doclet;
|
||||
|
||||
if (!doclets.index) {
|
||||
logger.error('Unable to resolve borrowed symbols, because the docs have not been indexed.');
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0, l = doclets.index.borrowed.length; i < l; i++) {
|
||||
doclet = doclets.index.borrowed[i];
|
||||
|
||||
cloneBorrowedDoclets(doclet, doclets);
|
||||
delete doclet.borrowed;
|
||||
}
|
||||
|
||||
doclets.index.borrowed = [];
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
@overview
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
|
||||
/**
|
||||
@module jsdoc/config
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
function mergeRecurse(target, source) {
|
||||
Object.keys(source).forEach(function(p) {
|
||||
if ( source[p].constructor === Object ) {
|
||||
if ( !target[p] ) { target[p] = {}; }
|
||||
mergeRecurse(target[p], source[p]);
|
||||
}
|
||||
else {
|
||||
target[p] = source[p];
|
||||
}
|
||||
});
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
// required config values, override these defaults in your config.json if necessary
|
||||
var defaults = {
|
||||
tags: {
|
||||
allowUnknownTags: true,
|
||||
dictionaries: ['jsdoc', 'closure']
|
||||
},
|
||||
templates: {
|
||||
monospaceLinks: false,
|
||||
cleverLinks: false
|
||||
},
|
||||
source: {
|
||||
includePattern: '.+\\.js(doc)?$',
|
||||
excludePattern: ''
|
||||
},
|
||||
plugins: []
|
||||
};
|
||||
|
||||
/**
|
||||
@class
|
||||
@classdesc Represents a JSDoc application configuration.
|
||||
@param {string} [json] - The contents of config.json.
|
||||
*/
|
||||
function Config(json) {
|
||||
json = JSON.parse( (json || '{}') );
|
||||
this._config = mergeRecurse(defaults, json);
|
||||
}
|
||||
|
||||
module.exports = Config;
|
||||
|
||||
/**
|
||||
Get the merged configuration values.
|
||||
*/
|
||||
Config.prototype.get = function() {
|
||||
return this._config;
|
||||
};
|
||||
@@ -0,0 +1,416 @@
|
||||
/**
|
||||
* @overview
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module jsdoc/doclet
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
var jsdoc = {
|
||||
name: require('jsdoc/name'),
|
||||
src: {
|
||||
astnode: require('jsdoc/src/astnode'),
|
||||
Syntax: require('jsdoc/src/syntax').Syntax
|
||||
},
|
||||
tag: {
|
||||
Tag: require('jsdoc/tag').Tag,
|
||||
dictionary: require('jsdoc/tag/dictionary')
|
||||
}
|
||||
};
|
||||
var path = require('jsdoc/path');
|
||||
var Syntax = jsdoc.src.Syntax;
|
||||
var util = require('util');
|
||||
|
||||
function applyTag(doclet, tag) {
|
||||
if (tag.title === 'name') {
|
||||
doclet.name = tag.value;
|
||||
}
|
||||
|
||||
if (tag.title === 'kind') {
|
||||
doclet.kind = tag.value;
|
||||
}
|
||||
|
||||
if (tag.title === 'description') {
|
||||
doclet.description = tag.value;
|
||||
}
|
||||
}
|
||||
|
||||
// use the meta info about the source code to guess what the doclet kind should be
|
||||
function codeToKind(code) {
|
||||
var parent;
|
||||
|
||||
var isFunction = jsdoc.src.astnode.isFunction;
|
||||
|
||||
// default
|
||||
var kind = 'member';
|
||||
|
||||
if (code.type === Syntax.FunctionDeclaration || code.type === Syntax.FunctionExpression) {
|
||||
kind = 'function';
|
||||
}
|
||||
else if (code.node && code.node.parent) {
|
||||
parent = code.node.parent;
|
||||
if ( isFunction(parent) ) {
|
||||
kind = 'param';
|
||||
}
|
||||
}
|
||||
|
||||
return kind;
|
||||
}
|
||||
|
||||
function unwrap(docletSrc) {
|
||||
if (!docletSrc) { return ''; }
|
||||
|
||||
// note: keep trailing whitespace for @examples
|
||||
// extra opening/closing stars are ignored
|
||||
// left margin is considered a star and a space
|
||||
// use the /m flag on regex to avoid having to guess what this platform's newline is
|
||||
docletSrc =
|
||||
docletSrc.replace(/^\/\*\*+/, '') // remove opening slash+stars
|
||||
.replace(/\**\*\/$/, '\\Z') // replace closing star slash with end-marker
|
||||
.replace(/^\s*(\* ?|\\Z)/gm, '') // remove left margin like: spaces+star or spaces+end-marker
|
||||
.replace(/\s*\\Z$/g, ''); // remove end-marker
|
||||
|
||||
return docletSrc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the raw source of the doclet comment into an array of pseudo-Tag objects.
|
||||
* @private
|
||||
*/
|
||||
function toTags(docletSrc) {
|
||||
var parsedTag;
|
||||
var tagData = [];
|
||||
var tagText;
|
||||
var tagTitle;
|
||||
|
||||
// split out the basic tags, keep surrounding whitespace
|
||||
// like: @tagTitle tagBody
|
||||
docletSrc
|
||||
// replace splitter ats with an arbitrary sequence
|
||||
.replace(/^(\s*)@(\S)/gm, '$1\\@$2')
|
||||
// then split on that arbitrary sequence
|
||||
.split('\\@')
|
||||
.forEach(function($) {
|
||||
if ($) {
|
||||
parsedTag = $.match(/^(\S+)(?:\s+(\S[\s\S]*))?/);
|
||||
|
||||
if (parsedTag) {
|
||||
tagTitle = parsedTag[1];
|
||||
tagText = parsedTag[2];
|
||||
|
||||
if (tagTitle) {
|
||||
tagData.push({
|
||||
title: tagTitle,
|
||||
text: tagText
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return tagData;
|
||||
}
|
||||
|
||||
function fixDescription(docletSrc) {
|
||||
if (!/^\s*@/.test(docletSrc) && docletSrc.replace(/\s/g, '').length) {
|
||||
docletSrc = '@description ' + docletSrc;
|
||||
}
|
||||
return docletSrc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the existing tag dictionary with a new tag dictionary.
|
||||
*
|
||||
* Used for testing only.
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary.
|
||||
*/
|
||||
exports._replaceDictionary = function _replaceDictionary(dict) {
|
||||
jsdoc.tag.dictionary = dict;
|
||||
require('jsdoc/tag')._replaceDictionary(dict);
|
||||
require('jsdoc/util/templateHelper')._replaceDictionary(dict);
|
||||
};
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Represents a single JSDoc comment.
|
||||
* @param {string} docletSrc - The raw source code of the jsdoc comment.
|
||||
* @param {object=} meta - Properties describing the code related to this comment.
|
||||
*/
|
||||
var Doclet = exports.Doclet = function(docletSrc, meta) {
|
||||
var newTags = [];
|
||||
|
||||
/** The original text of the comment from the source code. */
|
||||
this.comment = docletSrc;
|
||||
this.setMeta(meta);
|
||||
|
||||
docletSrc = unwrap(docletSrc);
|
||||
docletSrc = fixDescription(docletSrc);
|
||||
|
||||
newTags = toTags.call(this, docletSrc);
|
||||
|
||||
for (var i = 0, l = newTags.length; i < l; i++) {
|
||||
this.addTag(newTags[i].title, newTags[i].text);
|
||||
}
|
||||
|
||||
this.postProcess();
|
||||
};
|
||||
|
||||
/** Called once after all tags have been added. */
|
||||
Doclet.prototype.postProcess = function() {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
if (!this.preserveName) {
|
||||
jsdoc.name.resolve(this);
|
||||
}
|
||||
if (this.name && !this.longname) {
|
||||
this.setLongname(this.name);
|
||||
}
|
||||
if (this.memberof === '') {
|
||||
delete this.memberof;
|
||||
}
|
||||
|
||||
if (!this.kind && this.meta && this.meta.code) {
|
||||
this.addTag( 'kind', codeToKind(this.meta.code) );
|
||||
}
|
||||
|
||||
if (this.variation && this.longname && !/\)$/.test(this.longname) ) {
|
||||
this.longname += '(' + this.variation + ')';
|
||||
}
|
||||
|
||||
// add in any missing param names
|
||||
if (this.params && this.meta && this.meta.code && this.meta.code.paramnames) {
|
||||
for (i = 0, l = this.params.length; i < l; i++) {
|
||||
if (!this.params[i].name) {
|
||||
this.params[i].name = this.meta.code.paramnames[i] || '';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a tag to the doclet.
|
||||
*
|
||||
* @param {string} title - The title of the tag being added.
|
||||
* @param {string} [text] - The text of the tag being added.
|
||||
*/
|
||||
Doclet.prototype.addTag = function(title, text) {
|
||||
var tagDef = jsdoc.tag.dictionary.lookUp(title),
|
||||
newTag = new jsdoc.tag.Tag(title, text, this.meta);
|
||||
|
||||
if (tagDef && tagDef.onTagged) {
|
||||
tagDef.onTagged(this, newTag);
|
||||
}
|
||||
|
||||
if (!tagDef) {
|
||||
this.tags = this.tags || [];
|
||||
this.tags.push(newTag);
|
||||
}
|
||||
|
||||
applyTag(this, newTag);
|
||||
};
|
||||
|
||||
function removeGlobal(longname) {
|
||||
var globalRegexp = new RegExp('^' + jsdoc.name.LONGNAMES.GLOBAL + '\\.?');
|
||||
|
||||
return longname.replace(globalRegexp, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the doclet's `memberof` property.
|
||||
*
|
||||
* @param {string} sid - The longname of the doclet's parent symbol.
|
||||
*/
|
||||
Doclet.prototype.setMemberof = function(sid) {
|
||||
/**
|
||||
* The longname of the symbol that contains this one, if any.
|
||||
* @type string
|
||||
*/
|
||||
this.memberof = removeGlobal(sid)
|
||||
.replace(/\.prototype/g, jsdoc.name.SCOPE.PUNC.INSTANCE);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the doclet's `longname` property.
|
||||
*
|
||||
* @param {string} name - The longname for the doclet.
|
||||
*/
|
||||
Doclet.prototype.setLongname = function(name) {
|
||||
/**
|
||||
* The fully resolved symbol name.
|
||||
* @type string
|
||||
*/
|
||||
this.longname = removeGlobal(name);
|
||||
if (jsdoc.tag.dictionary.isNamespace(this.kind)) {
|
||||
this.longname = jsdoc.name.applyNamespace(this.longname, this.kind);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the full path to the source file that is associated with a doclet.
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/doclet.Doclet} The doclet to check for a filepath.
|
||||
* @return {string} The path to the doclet's source file, or an empty string if the path is not
|
||||
* available.
|
||||
*/
|
||||
function getFilepath(doclet) {
|
||||
if (!doclet || !doclet.meta || !doclet.meta.filename) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return path.join(doclet.meta.path || '', doclet.meta.filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the doclet's `scope` property. Must correspond to a scope name that is defined in
|
||||
* {@link module:jsdoc/name.SCOPE.NAMES}.
|
||||
*
|
||||
* @param {module:jsdoc/name.SCOPE.NAMES} scope - The scope for the doclet relative to the symbol's
|
||||
* parent.
|
||||
* @throws {Error} If the scope name is not recognized.
|
||||
*/
|
||||
Doclet.prototype.setScope = function(scope) {
|
||||
var errorMessage;
|
||||
var filepath;
|
||||
var scopeNames = _.values(jsdoc.name.SCOPE.NAMES);
|
||||
|
||||
if (scopeNames.indexOf(scope) === -1) {
|
||||
filepath = getFilepath(this);
|
||||
|
||||
errorMessage = util.format('The scope name "%s" is not recognized. Use one of the ' +
|
||||
'following values: %j', scope, scopeNames);
|
||||
if (filepath) {
|
||||
errorMessage += util.format(' (Source file: %s)', filepath);
|
||||
}
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
this.scope = scope;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a symbol to this doclet's `borrowed` array.
|
||||
*
|
||||
* @param {string} source - The longname of the symbol that is the source.
|
||||
* @param {string} target - The name the symbol is being assigned to.
|
||||
*/
|
||||
Doclet.prototype.borrow = function(source, target) {
|
||||
var about = { from: source };
|
||||
if (target) {
|
||||
about.as = target;
|
||||
}
|
||||
|
||||
if (!this.borrowed) {
|
||||
/**
|
||||
* A list of symbols that are borrowed by this one, if any.
|
||||
* @type Array.<string>
|
||||
*/
|
||||
this.borrowed = [];
|
||||
}
|
||||
this.borrowed.push(about);
|
||||
};
|
||||
|
||||
Doclet.prototype.mix = function(source) {
|
||||
/**
|
||||
* A list of symbols that are mixed into this one, if any.
|
||||
* @type Array.<string>
|
||||
*/
|
||||
this.mixes = this.mixes || [];
|
||||
this.mixes.push(source);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a symbol to the doclet's `augments` array.
|
||||
*
|
||||
* @param {string} base - The longname of the base symbol.
|
||||
*/
|
||||
Doclet.prototype.augment = function(base) {
|
||||
/**
|
||||
* A list of symbols that are augmented by this one, if any.
|
||||
* @type Array.<string>
|
||||
*/
|
||||
this.augments = this.augments || [];
|
||||
this.augments.push(base);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the `meta` property of this doclet.
|
||||
*
|
||||
* @param {object} meta
|
||||
*/
|
||||
Doclet.prototype.setMeta = function(meta) {
|
||||
/**
|
||||
* Information about the source code associated with this doclet.
|
||||
* @namespace
|
||||
*/
|
||||
this.meta = this.meta || {};
|
||||
|
||||
if (meta.range) {
|
||||
/**
|
||||
* The positions of the first and last characters of the code associated with this doclet.
|
||||
* @type Array.<number>
|
||||
*/
|
||||
this.meta.range = meta.range.slice(0);
|
||||
}
|
||||
|
||||
if (meta.lineno) {
|
||||
/**
|
||||
* The name of the file containing the code associated with this doclet.
|
||||
* @type string
|
||||
*/
|
||||
this.meta.filename = path.basename(meta.filename);
|
||||
/**
|
||||
* The line number of the code associated with this doclet.
|
||||
* @type number
|
||||
*/
|
||||
this.meta.lineno = meta.lineno;
|
||||
|
||||
var pathname = path.dirname(meta.filename);
|
||||
if (pathname && pathname !== '.') {
|
||||
this.meta.path = pathname;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about the code symbol.
|
||||
* @namespace
|
||||
*/
|
||||
this.meta.code = this.meta.code || {};
|
||||
if (meta.id) { this.meta.code.id = meta.id; }
|
||||
if (meta.code) {
|
||||
if (meta.code.name) {
|
||||
/** The name of the symbol in the source code. */
|
||||
this.meta.code.name = meta.code.name;
|
||||
}
|
||||
if (meta.code.type) {
|
||||
/** The type of the symbol in the source code. */
|
||||
this.meta.code.type = meta.code.type;
|
||||
}
|
||||
// the AST node is only enumerable in debug mode, which reduces clutter for the
|
||||
// --explain/-X option
|
||||
if (meta.code.node) {
|
||||
Object.defineProperty(this.meta.code, 'node', {
|
||||
value: meta.code.node,
|
||||
enumerable: global.env.opts.debug ? true : false
|
||||
});
|
||||
}
|
||||
if (meta.code.funcscope) {
|
||||
this.meta.code.funcscope = meta.code.funcscope;
|
||||
}
|
||||
if (meta.code.value) {
|
||||
/** The value of the symbol in the source code. */
|
||||
this.meta.code.value = meta.code.value;
|
||||
}
|
||||
if (meta.code.paramnames) {
|
||||
this.meta.code.paramnames = meta.code.paramnames.slice(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Extended version of the standard `fs` module.
|
||||
* @module jsdoc/fs
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var runtime = require('jsdoc/util/runtime');
|
||||
|
||||
var ls = exports.ls = function(dir, recurse, _allFiles, _path) {
|
||||
var file;
|
||||
var files;
|
||||
var isFile;
|
||||
|
||||
// first pass
|
||||
if (_path === undefined) {
|
||||
_allFiles = [];
|
||||
_path = [dir];
|
||||
}
|
||||
|
||||
if (!_path.length) {
|
||||
return _allFiles;
|
||||
}
|
||||
|
||||
if (recurse === undefined) {
|
||||
recurse = 1;
|
||||
}
|
||||
|
||||
try {
|
||||
isFile = fs.statSync(dir).isFile();
|
||||
}
|
||||
catch (e) {
|
||||
isFile = false;
|
||||
}
|
||||
if (isFile) {
|
||||
files = [dir];
|
||||
}
|
||||
else {
|
||||
files = fs.readdirSync(dir);
|
||||
}
|
||||
|
||||
for (var i = 0, l = files.length; i < l; i++) {
|
||||
file = String(files[i]);
|
||||
|
||||
// skip dot files
|
||||
if (file.match(/^\.[^\.\/\\]/)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( fs.statSync(path.join(_path.join('/'), file)).isDirectory() ) {
|
||||
// it's a directory
|
||||
_path.push(file);
|
||||
|
||||
if (_path.length - 1 < recurse) {
|
||||
ls(_path.join('/'), recurse, _allFiles, _path);
|
||||
}
|
||||
_path.pop();
|
||||
}
|
||||
else {
|
||||
// it's a file
|
||||
_allFiles.push( path.normalize(path.join(_path.join('/'), file)) );
|
||||
}
|
||||
}
|
||||
|
||||
return _allFiles;
|
||||
};
|
||||
|
||||
// export the VM-specific implementations of the extra methods
|
||||
// TODO: document extra methods here
|
||||
var extras = require( runtime.getModulePath('fs') );
|
||||
Object.keys(extras).forEach(function(extra) {
|
||||
exports[extra] = extras[extra];
|
||||
});
|
||||
@@ -0,0 +1,432 @@
|
||||
/**
|
||||
A collection of functions relating to JSDoc symbol name manipulation.
|
||||
@module jsdoc/name
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
var escape = require('escape-string-regexp');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* Longnames that have a special meaning in JSDoc.
|
||||
*
|
||||
* @enum {string}
|
||||
* @static
|
||||
* @memberof module:jsdoc/name
|
||||
*/
|
||||
var LONGNAMES = exports.LONGNAMES = {
|
||||
/** Longname used for doclets that do not have a longname, such as anonymous functions. */
|
||||
ANONYMOUS: '<anonymous>',
|
||||
/** Longname that represents global scope. */
|
||||
GLOBAL: '<global>'
|
||||
};
|
||||
|
||||
// Module namespace prefix.
|
||||
var MODULE_NAMESPACE = 'module:';
|
||||
|
||||
/**
|
||||
* Names and punctuation marks that identify doclet scopes.
|
||||
*
|
||||
* @enum {string}
|
||||
* @static
|
||||
* @memberof module:jsdoc/name
|
||||
*/
|
||||
var SCOPE = exports.SCOPE = {
|
||||
NAMES: {
|
||||
GLOBAL: 'global',
|
||||
INNER: 'inner',
|
||||
INSTANCE: 'instance',
|
||||
STATIC: 'static'
|
||||
},
|
||||
PUNC: {
|
||||
INNER: '~',
|
||||
INSTANCE: '#',
|
||||
STATIC: '.'
|
||||
}
|
||||
};
|
||||
|
||||
// For backwards compatibility, this enum must use lower-case keys
|
||||
var scopeToPunc = exports.scopeToPunc = {
|
||||
'inner': SCOPE.PUNC.INNER,
|
||||
'instance': SCOPE.PUNC.INSTANCE,
|
||||
'static': SCOPE.PUNC.STATIC
|
||||
};
|
||||
var puncToScope = exports.puncToScope = _.invert(scopeToPunc);
|
||||
|
||||
var DEFAULT_SCOPE = SCOPE.NAMES.STATIC;
|
||||
var SCOPE_PUNC = _.values(SCOPE.PUNC);
|
||||
var SCOPE_PUNC_STRING = '[' + SCOPE_PUNC.join() + ']';
|
||||
var REGEXP_LEADING_SCOPE = new RegExp('^(' + SCOPE_PUNC_STRING + ')');
|
||||
var REGEXP_TRAILING_SCOPE = new RegExp('(' + SCOPE_PUNC_STRING + ')$');
|
||||
|
||||
var DESCRIPTION = '(?:(?:[ \\t]*\\-\\s*|\\s+)(\\S[\\s\\S]*))?$';
|
||||
var REGEXP_DESCRIPTION = new RegExp(DESCRIPTION);
|
||||
var REGEXP_NAME_DESCRIPTION = new RegExp('^(\\[[^\\]]+\\]|\\S+)' + DESCRIPTION);
|
||||
|
||||
function nameIsLongname(name, memberof) {
|
||||
var regexp = new RegExp('^' + escape(memberof) + SCOPE_PUNC_STRING);
|
||||
|
||||
return regexp.test(name);
|
||||
}
|
||||
|
||||
function prototypeToPunc(name) {
|
||||
return name.replace(/(?:^|\.)prototype\.?/g, SCOPE.PUNC.INSTANCE);
|
||||
}
|
||||
|
||||
// TODO: deprecate exports.resolve in favor of a better name
|
||||
/**
|
||||
Resolves the longname, memberof, variation and name values of the given doclet.
|
||||
@param {module:jsdoc/doclet.Doclet} doclet
|
||||
*/
|
||||
exports.resolve = function(doclet) {
|
||||
var about = {};
|
||||
var memberof = doclet.memberof || '';
|
||||
var name = doclet.name ? String(doclet.name) : '';
|
||||
|
||||
var parentDoc;
|
||||
|
||||
// change MyClass.prototype.instanceMethod to MyClass#instanceMethod
|
||||
// (but not in function params, which lack doclet.kind)
|
||||
// TODO: check for specific doclet.kind values (probably function, class, and module)
|
||||
if (name && doclet.kind) {
|
||||
name = prototypeToPunc(name);
|
||||
}
|
||||
doclet.name = name;
|
||||
|
||||
// member of a var in an outer scope?
|
||||
if (name && !memberof && doclet.meta.code && doclet.meta.code.funcscope) {
|
||||
name = doclet.longname = doclet.meta.code.funcscope + SCOPE.PUNC.INNER + name;
|
||||
}
|
||||
|
||||
if (memberof || doclet.forceMemberof) { // @memberof tag given
|
||||
memberof = prototypeToPunc(memberof);
|
||||
|
||||
// the name is a complete longname, like @name foo.bar, @memberof foo
|
||||
if (name && nameIsLongname(name, memberof) && name !== memberof) {
|
||||
about = exports.shorten(name, (doclet.forceMemberof ? memberof : undefined));
|
||||
}
|
||||
// the name and memberof are identical and refer to a module,
|
||||
// like @name module:foo, @memberof module:foo (probably a member like 'var exports')
|
||||
else if (name && name === memberof && name.indexOf(MODULE_NAMESPACE) === 0) {
|
||||
about = exports.shorten(name, (doclet.forceMemberof ? memberof : undefined));
|
||||
}
|
||||
// the name and memberof are identical, like @name foo, @memberof foo
|
||||
else if (name && name === memberof) {
|
||||
doclet.scope = doclet.scope || DEFAULT_SCOPE;
|
||||
name = memberof + scopeToPunc[doclet.scope] + name;
|
||||
about = exports.shorten(name, (doclet.forceMemberof ? memberof : undefined));
|
||||
}
|
||||
// like @memberof foo# or @memberof foo~
|
||||
else if (name && REGEXP_TRAILING_SCOPE.test(memberof) ) {
|
||||
about = exports.shorten(memberof + name, (doclet.forceMemberof ? memberof : undefined));
|
||||
}
|
||||
else if (name && doclet.scope) {
|
||||
about = exports.shorten(memberof + (scopeToPunc[doclet.scope] || '') + name,
|
||||
(doclet.forceMemberof ? memberof : undefined));
|
||||
}
|
||||
}
|
||||
else { // no @memberof
|
||||
about = exports.shorten(name);
|
||||
}
|
||||
|
||||
if (about.name) {
|
||||
doclet.name = about.name;
|
||||
}
|
||||
|
||||
if (about.memberof) {
|
||||
doclet.setMemberof(about.memberof);
|
||||
}
|
||||
|
||||
if (about.longname && (!doclet.longname || doclet.longname === doclet.name)) {
|
||||
doclet.setLongname(about.longname);
|
||||
}
|
||||
|
||||
if (doclet.scope === SCOPE.NAMES.GLOBAL) { // via @global tag?
|
||||
doclet.setLongname(doclet.name);
|
||||
delete doclet.memberof;
|
||||
}
|
||||
else if (about.scope) {
|
||||
if (about.memberof === LONGNAMES.GLOBAL) { // via @memberof <global> ?
|
||||
doclet.scope = SCOPE.NAMES.GLOBAL;
|
||||
}
|
||||
else {
|
||||
doclet.scope = puncToScope[about.scope];
|
||||
}
|
||||
}
|
||||
else if (doclet.name && doclet.memberof && !doclet.longname) {
|
||||
if ( REGEXP_LEADING_SCOPE.test(doclet.name) ) {
|
||||
doclet.scope = puncToScope[RegExp.$1];
|
||||
doclet.name = doclet.name.substr(1);
|
||||
}
|
||||
else {
|
||||
doclet.scope = DEFAULT_SCOPE;
|
||||
}
|
||||
|
||||
doclet.setLongname(doclet.memberof + scopeToPunc[doclet.scope] + doclet.name);
|
||||
}
|
||||
|
||||
if (about.variation) {
|
||||
doclet.variation = about.variation;
|
||||
}
|
||||
|
||||
// if we never found a longname, just use an empty string
|
||||
if (!doclet.longname) {
|
||||
doclet.longname = '';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@method module:jsdoc/name.applyNamespace
|
||||
@param {string} longname The full longname of the symbol.
|
||||
@param {string} ns The namespace to be applied.
|
||||
@returns {string} The longname with the namespace applied.
|
||||
*/
|
||||
exports.applyNamespace = function(longname, ns) {
|
||||
var nameParts = exports.shorten(longname),
|
||||
name = nameParts.name;
|
||||
longname = nameParts.longname;
|
||||
|
||||
if ( !/^[a-zA-Z]+?:.+$/i.test(name) ) {
|
||||
longname = longname.replace( new RegExp(escape(name) + '$'), ns + ':' + name );
|
||||
}
|
||||
|
||||
return longname;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
function atomize(longname, sliceChars, forcedMemberof) {
|
||||
var i;
|
||||
var memberof = '';
|
||||
var name = '';
|
||||
var parts;
|
||||
var partsRegExp;
|
||||
var scopePunc = '';
|
||||
var token;
|
||||
var tokens = [];
|
||||
var variation;
|
||||
|
||||
// quoted strings in a longname are atomic, so we convert them to tokens
|
||||
longname = longname.replace(/(\[?["'].+?["']\]?)/g, function($) {
|
||||
var dot = '';
|
||||
if ( /^\[/.test($) ) {
|
||||
dot = '.';
|
||||
$ = $.replace( /^\[/g, '' ).replace( /\]$/g, '' );
|
||||
}
|
||||
|
||||
token = '@{' + tokens.length + '}@';
|
||||
tokens.push($);
|
||||
|
||||
return dot + token; // foo["bar"] => foo.@{1}@
|
||||
});
|
||||
|
||||
longname = prototypeToPunc(longname);
|
||||
|
||||
if (forcedMemberof !== undefined) {
|
||||
partsRegExp = new RegExp('^(.*?)([' + sliceChars.join() + ']?)$');
|
||||
name = longname.substr(forcedMemberof.length);
|
||||
parts = forcedMemberof.match(partsRegExp);
|
||||
|
||||
if (parts[1]) {
|
||||
memberof = parts[1] || forcedMemberof;
|
||||
}
|
||||
if (parts[2]) {
|
||||
scopePunc = parts[2];
|
||||
}
|
||||
}
|
||||
else if (longname) {
|
||||
parts = (longname.match(new RegExp('^(:?(.+)([' + sliceChars.join() + ']))?(.+?)$')) || [])
|
||||
.reverse();
|
||||
name = parts[0] || '';
|
||||
scopePunc = parts[1] || '';
|
||||
memberof = parts[2] || '';
|
||||
}
|
||||
|
||||
// like /** @name foo.bar(2) */
|
||||
if ( /(.+)\(([^)]+)\)$/.test(name) ) {
|
||||
name = RegExp.$1;
|
||||
variation = RegExp.$2;
|
||||
}
|
||||
|
||||
// restore quoted strings
|
||||
i = tokens.length;
|
||||
while (i--) {
|
||||
longname = longname.replace('@{' + i + '}@', tokens[i]);
|
||||
memberof = memberof.replace('@{' + i + '}@', tokens[i]);
|
||||
scopePunc = scopePunc.replace('@{' + i + '}@', tokens[i]);
|
||||
name = name.replace('@{' + i + '}@', tokens[i]);
|
||||
}
|
||||
|
||||
return {
|
||||
longname: longname,
|
||||
memberof: memberof,
|
||||
scope: scopePunc,
|
||||
name: name,
|
||||
variation: variation
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: deprecate exports.shorten in favor of a better name
|
||||
/**
|
||||
Given a longname like "a.b#c(2)", slice it up into an object
|
||||
containing the memberof, the scope, the name, and variation.
|
||||
@param {string} longname
|
||||
@param {string} forcedMemberof
|
||||
@returns {object} Representing the properties of the given name.
|
||||
*/
|
||||
exports.shorten = function(longname, forcedMemberof) {
|
||||
return atomize(longname, SCOPE_PUNC, forcedMemberof);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
exports.combine = function(parts) {
|
||||
return '' +
|
||||
(parts.memberof || '') +
|
||||
(parts.scope || '') +
|
||||
(parts.name || '') +
|
||||
(parts.variation || '');
|
||||
};
|
||||
|
||||
function stripVariation(name) {
|
||||
return name.replace(/\([^)]\)$/, '');
|
||||
}
|
||||
|
||||
function splitLongname(longname, options) {
|
||||
var chunks = [];
|
||||
var currentNameInfo;
|
||||
var nameInfo = {};
|
||||
var previousName = longname;
|
||||
var splitters = SCOPE_PUNC.concat('/');
|
||||
|
||||
options = _.defaults(options || {}, {
|
||||
includeVariation: true
|
||||
});
|
||||
|
||||
do {
|
||||
if (!options.includeVariation) {
|
||||
previousName = stripVariation(previousName);
|
||||
}
|
||||
currentNameInfo = nameInfo[previousName] = atomize(previousName, splitters);
|
||||
previousName = currentNameInfo.memberof;
|
||||
chunks.push(currentNameInfo.scope + currentNameInfo.name);
|
||||
} while (previousName);
|
||||
|
||||
return {
|
||||
chunks: chunks.reverse(),
|
||||
nameInfo: nameInfo
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
exports.longnamesToTree = function longnamesToTree(longnames, doclets) {
|
||||
var splitOptions = { includeVariation: false };
|
||||
var tree = {};
|
||||
|
||||
longnames.forEach(function(longname) {
|
||||
var chunk;
|
||||
var currentLongname = '';
|
||||
var currentNavItem = tree;
|
||||
var nameInfo;
|
||||
var processed;
|
||||
|
||||
// don't try to add empty longnames to the tree
|
||||
if (!longname) {
|
||||
return;
|
||||
}
|
||||
|
||||
processed = splitLongname(longname, splitOptions);
|
||||
nameInfo = processed.nameInfo;
|
||||
|
||||
processed.chunks.forEach(function(chunk) {
|
||||
currentLongname += chunk;
|
||||
|
||||
if (!hasOwnProp.call(currentNavItem, chunk)) {
|
||||
currentNavItem[chunk] = nameInfo[currentLongname];
|
||||
}
|
||||
|
||||
if (currentNavItem[chunk]) {
|
||||
currentNavItem[chunk].doclet = doclets ? doclets[currentLongname] : null;
|
||||
currentNavItem[chunk].children = currentNavItem[chunk].children || {};
|
||||
currentNavItem = currentNavItem[chunk].children;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return tree;
|
||||
};
|
||||
|
||||
/**
|
||||
Split a string that starts with a name and ends with a description into its parts.
|
||||
Allows the defaultvalue (if present) to contain brackets. If the name is found to have
|
||||
mismatched brackets, null is returned.
|
||||
@param {string} nameDesc
|
||||
@returns {object} Hash with "name" and "description" properties.
|
||||
*/
|
||||
function splitNameMatchingBrackets(nameDesc) {
|
||||
var buffer = [];
|
||||
var c;
|
||||
var stack = 0;
|
||||
var stringEnd = null;
|
||||
|
||||
for (var i = 0; i < nameDesc.length; ++i) {
|
||||
c = nameDesc[i];
|
||||
buffer.push(c);
|
||||
|
||||
if (stringEnd) {
|
||||
if (c === '\\' && i + 1 < nameDesc.length) {
|
||||
buffer.push(nameDesc[++i]);
|
||||
} else if (c === stringEnd) {
|
||||
stringEnd = null;
|
||||
}
|
||||
} else if (c === '"' || c === "'") {
|
||||
stringEnd = c;
|
||||
} else if (c === '[') {
|
||||
++stack;
|
||||
} else if (c === ']') {
|
||||
if (--stack === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack || stringEnd) {
|
||||
return null;
|
||||
}
|
||||
|
||||
nameDesc.substr(i).match(REGEXP_DESCRIPTION);
|
||||
return {
|
||||
name: buffer.join(''),
|
||||
description: RegExp.$1
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// TODO: deprecate exports.splitName in favor of a better name
|
||||
/**
|
||||
Split a string that starts with a name and ends with a description into its parts.
|
||||
@param {string} nameDesc
|
||||
@returns {object} Hash with "name" and "description" properties.
|
||||
*/
|
||||
exports.splitName = function(nameDesc) {
|
||||
// like: name, [name], name text, [name] text, name - text, or [name] - text
|
||||
// the hyphen must be on the same line as the name; this prevents us from treating a Markdown
|
||||
// dash as a separator
|
||||
|
||||
// optional values get special treatment
|
||||
var result = null;
|
||||
if (nameDesc[0] === '[') {
|
||||
result = splitNameMatchingBrackets(nameDesc);
|
||||
if (result !== null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
nameDesc.match(REGEXP_NAME_DESCRIPTION);
|
||||
return {
|
||||
name: RegExp.$1,
|
||||
description: RegExp.$2
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,302 @@
|
||||
/**
|
||||
* Parse the command line arguments.
|
||||
* @module jsdoc/opts/argparser
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
var util = require('util');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* Create an instance of the parser.
|
||||
* @classdesc A parser to interpret the key-value pairs entered on the command line.
|
||||
* @constructor
|
||||
* @alias module:jsdoc/opts/argparser
|
||||
*/
|
||||
var ArgParser = function() {
|
||||
this._options = [];
|
||||
this._shortNameIndex = {};
|
||||
this._longNameIndex = {};
|
||||
};
|
||||
|
||||
ArgParser.prototype._getOptionByShortName = function(name) {
|
||||
if (hasOwnProp.call(this._shortNameIndex, name)) {
|
||||
return this._options[this._shortNameIndex[name]];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
ArgParser.prototype._getOptionByLongName = function(name) {
|
||||
if (hasOwnProp.call(this._longNameIndex, name)) {
|
||||
return this._options[this._longNameIndex[name]];
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
ArgParser.prototype._addOption = function(option) {
|
||||
var currentIndex;
|
||||
|
||||
var longName = option.longName;
|
||||
var shortName = option.shortName;
|
||||
|
||||
this._options.push(option);
|
||||
currentIndex = this._options.length - 1;
|
||||
|
||||
if (shortName) {
|
||||
this._shortNameIndex[shortName] = currentIndex;
|
||||
}
|
||||
if (longName) {
|
||||
this._longNameIndex[longName] = currentIndex;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Provide information about a legal option.
|
||||
* @param {character} shortName The short name of the option, entered like: -T.
|
||||
* @param {string} longName The equivalent long name of the option, entered like: --test.
|
||||
* @param {boolean} hasValue Does this option require a value? Like: -t templatename
|
||||
* @param {string} helpText A brief description of the option.
|
||||
* @param {boolean} [canHaveMultiple=false] Set to `true` if the option can be provided more than once.
|
||||
* @param {function} [coercer] A function to coerce the given value to a specific type.
|
||||
* @return {this}
|
||||
* @example
|
||||
* myParser.addOption('t', 'template', true, 'The path to the template.');
|
||||
* myParser.addOption('h', 'help', false, 'Show the help message.');
|
||||
*/
|
||||
ArgParser.prototype.addOption = function(shortName, longName, hasValue, helpText, canHaveMultiple, coercer) {
|
||||
var option = {
|
||||
shortName: shortName,
|
||||
longName: longName,
|
||||
hasValue: hasValue,
|
||||
helpText: helpText,
|
||||
canHaveMultiple: (canHaveMultiple || false),
|
||||
coercer: coercer
|
||||
};
|
||||
|
||||
return this._addOption(option);
|
||||
};
|
||||
|
||||
// TODO: refactor addOption to accept objects, then get rid of this method
|
||||
/**
|
||||
* Provide information about an option that should not cause an error if present, but that is always
|
||||
* ignored (for example, an option that was used in previous versions but is no longer supported).
|
||||
*
|
||||
* @private
|
||||
* @param {string} shortName - The short name of the option with a leading hyphen (for example,
|
||||
* `-v`).
|
||||
* @param {string} longName - The long name of the option with two leading hyphens (for example,
|
||||
* `--version`).
|
||||
*/
|
||||
ArgParser.prototype.addIgnoredOption = function(shortName, longName) {
|
||||
var option = {
|
||||
shortName: shortName,
|
||||
longName: longName,
|
||||
ignore: true
|
||||
};
|
||||
|
||||
return this._addOption(option);
|
||||
};
|
||||
|
||||
function padding(length) {
|
||||
return new Array(length + 1).join(' ');
|
||||
}
|
||||
|
||||
function padLeft(str, length) {
|
||||
return padding(length) + str;
|
||||
}
|
||||
|
||||
function padRight(str, length) {
|
||||
return str + padding(length);
|
||||
}
|
||||
|
||||
function findMaxLength(arr) {
|
||||
var max = 0;
|
||||
|
||||
arr.forEach(function(item) {
|
||||
if (item.length > max) {
|
||||
max = item.length;
|
||||
}
|
||||
});
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
function concatWithMaxLength(items, maxLength) {
|
||||
var result = '';
|
||||
// to prevent endless loops, always use the first item, regardless of length
|
||||
result += items.shift();
|
||||
|
||||
while ( items.length && (result.length + items[0].length < maxLength) ) {
|
||||
result += ' ' + items.shift();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// we want to format names and descriptions like this:
|
||||
// | -f, --foo Very long description very long description very long |
|
||||
// | description very long description. |
|
||||
function formatHelpInfo(options) {
|
||||
var MARGIN_LENGTH = 4;
|
||||
var results = [];
|
||||
|
||||
var maxLength = process.stdout.columns;
|
||||
var maxNameLength = findMaxLength(options.names);
|
||||
var maxDescriptionLength = findMaxLength(options.descriptions);
|
||||
|
||||
var wrapDescriptionAt = maxLength - (MARGIN_LENGTH * 3) - maxNameLength;
|
||||
// build the string for each option
|
||||
options.names.forEach(function(name, i) {
|
||||
var result;
|
||||
var partialDescription;
|
||||
var words;
|
||||
|
||||
// add a left margin to the name
|
||||
result = padLeft(options.names[i], MARGIN_LENGTH);
|
||||
// and a right margin, with extra padding so the descriptions line up with one another
|
||||
result = padRight(result, maxNameLength - options.names[i].length + MARGIN_LENGTH);
|
||||
|
||||
// split the description on spaces
|
||||
words = options.descriptions[i].split(' ');
|
||||
// add as much of the description as we can fit on the first line
|
||||
result += concatWithMaxLength(words, wrapDescriptionAt);
|
||||
// if there's anything left, keep going until we've consumed the description
|
||||
while (words.length) {
|
||||
partialDescription = padding( maxNameLength + (MARGIN_LENGTH * 2) );
|
||||
partialDescription += concatWithMaxLength(words, wrapDescriptionAt);
|
||||
result += '\n' + partialDescription;
|
||||
}
|
||||
|
||||
results.push(result);
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a summary of all the options with corresponding help text.
|
||||
* @returns {string}
|
||||
*/
|
||||
ArgParser.prototype.help = function() {
|
||||
var options = {
|
||||
names: [],
|
||||
descriptions: []
|
||||
};
|
||||
|
||||
this._options.forEach(function(option) {
|
||||
var name = '';
|
||||
|
||||
// don't show ignored options
|
||||
if (option.ignore) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (option.shortName) {
|
||||
name += '-' + option.shortName + (option.longName ? ', ' : '');
|
||||
}
|
||||
|
||||
if (option.longName) {
|
||||
name += '--' + option.longName;
|
||||
}
|
||||
|
||||
if (option.hasValue) {
|
||||
name += ' <value>';
|
||||
}
|
||||
|
||||
options.names.push(name);
|
||||
options.descriptions.push(option.helpText);
|
||||
});
|
||||
|
||||
return 'Options:\n' + formatHelpInfo(options).join('\n');
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the options.
|
||||
* @param {Array.<string>} args An array, like ['-x', 'hello']
|
||||
* @param {Object} [defaults={}] An optional collection of default values.
|
||||
* @returns {Object} The keys will be the longNames, or the shortName if no longName is defined for
|
||||
* that option. The values will be the values provided, or `true` if the option accepts no value.
|
||||
*/
|
||||
ArgParser.prototype.parse = function(args, defaults) {
|
||||
var result = defaults && _.defaults({}, defaults) || {};
|
||||
|
||||
result._ = [];
|
||||
for (var i = 0, leni = args.length; i < leni; i++) {
|
||||
var arg = '' + args[i],
|
||||
next = (i < leni - 1) ? '' + args[i + 1] : null,
|
||||
option,
|
||||
shortName = null,
|
||||
longName,
|
||||
name,
|
||||
value = null;
|
||||
|
||||
// like -t
|
||||
if (arg.charAt(0) === '-') {
|
||||
// like --template
|
||||
if (arg.charAt(1) === '-') {
|
||||
name = longName = arg.slice(2);
|
||||
option = this._getOptionByLongName(longName);
|
||||
}
|
||||
else {
|
||||
name = shortName = arg.slice(1);
|
||||
option = this._getOptionByShortName(shortName);
|
||||
}
|
||||
|
||||
if (option === null) {
|
||||
throw new Error( util.format('Unknown command-line option "%s".', name) );
|
||||
}
|
||||
|
||||
if (option.hasValue) {
|
||||
value = next;
|
||||
i++;
|
||||
|
||||
if (value === null || value.charAt(0) === '-') {
|
||||
throw new Error( util.format('The command-line option "%s" requires a value.', name) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = true;
|
||||
}
|
||||
|
||||
// skip ignored options now that we've consumed the option text
|
||||
if (option.ignore) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (option.longName && shortName) {
|
||||
name = option.longName;
|
||||
}
|
||||
|
||||
if (typeof option.coercer === 'function') {
|
||||
value = option.coercer(value);
|
||||
}
|
||||
|
||||
// Allow for multiple options of the same type to be present
|
||||
if (option.canHaveMultiple && hasOwnProp.call(result, name)) {
|
||||
var val = result[name];
|
||||
|
||||
if (val instanceof Array) {
|
||||
val.push(value);
|
||||
} else {
|
||||
result[name] = [val, value];
|
||||
}
|
||||
}
|
||||
else {
|
||||
result[name] = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result._.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
module.exports = ArgParser;
|
||||
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @module jsdoc/opts/args
|
||||
* @requires jsdoc/opts/argparser
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ArgParser = require('jsdoc/opts/argparser');
|
||||
var querystring = require('querystring');
|
||||
var util = require('util');
|
||||
|
||||
var ourOptions;
|
||||
|
||||
var argParser = new ArgParser();
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
// cast strings to booleans or integers where appropriate
|
||||
function castTypes(item) {
|
||||
var integer;
|
||||
|
||||
var result = item;
|
||||
|
||||
switch (result) {
|
||||
case 'true':
|
||||
result = true;
|
||||
break;
|
||||
|
||||
case 'false':
|
||||
result = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
// might be an integer
|
||||
integer = parseInt(result, 10);
|
||||
if (String(integer) === result && integer !== 'NaN') {
|
||||
result = integer;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// check for strings that we need to cast to other types
|
||||
function fixTypes(item) {
|
||||
var result = item;
|
||||
|
||||
// recursively process arrays and objects
|
||||
if ( util.isArray(result) ) {
|
||||
for (var i = 0, l = result.length; i < l; i++) {
|
||||
result[i] = fixTypes(result[i]);
|
||||
}
|
||||
}
|
||||
else if (typeof result === 'object') {
|
||||
Object.keys(result).forEach(function(prop) {
|
||||
result[prop] = fixTypes(result[prop]);
|
||||
});
|
||||
}
|
||||
else {
|
||||
result = castTypes(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseQuery(str) {
|
||||
var result = querystring.parse(str);
|
||||
|
||||
Object.keys(result).forEach(function(prop) {
|
||||
result[prop] = fixTypes(result[prop]);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
argParser.addOption('t', 'template', true, 'The path to the template to use. Default: path/to/jsdoc/templates/default');
|
||||
argParser.addOption('c', 'configure', true, 'The path to the configuration file. Default: path/to/jsdoc/conf.json');
|
||||
argParser.addOption('e', 'encoding', true, 'Assume this encoding when reading all source files. Default: utf8');
|
||||
argParser.addOption('T', 'test', false, 'Run all tests and quit.');
|
||||
argParser.addOption('d', 'destination', true, 'The path to the output folder. Use "console" to dump data to the console. Default: ./out/');
|
||||
argParser.addOption('p', 'private', false, 'Display symbols marked with the @private tag. Default: false');
|
||||
argParser.addOption('r', 'recurse', false, 'Recurse into subdirectories when scanning for source code files.');
|
||||
argParser.addOption('h', 'help', false, 'Print this message and quit.');
|
||||
argParser.addOption('X', 'explain', false, 'Dump all found doclet internals to console and quit.');
|
||||
argParser.addOption('q', 'query', true, 'A query string to parse and store in env.opts.query. Example: foo=bar&baz=true', false, parseQuery);
|
||||
argParser.addOption('u', 'tutorials', true, 'Directory in which JSDoc should search for tutorials.');
|
||||
argParser.addOption('P', 'package', true, 'The path to the project\'s package file. Default: path/to/sourcefiles/package.json');
|
||||
argParser.addOption('R', 'readme', true, 'The path to the project\'s README file. Default: path/to/sourcefiles/README.md');
|
||||
argParser.addOption('v', 'version', false, 'Display the version number and quit.');
|
||||
argParser.addOption('', 'debug', false, 'Log information for debugging JSDoc. On Rhino, launches the debugger when passed as the first option.');
|
||||
argParser.addOption('', 'verbose', false, 'Log detailed information to the console as JSDoc runs.');
|
||||
argParser.addOption('', 'pedantic', false, 'Treat errors as fatal errors, and treat warnings as errors. Default: false');
|
||||
|
||||
// Options specific to tests
|
||||
argParser.addOption(null, 'match', true, 'Only run tests containing <value>.', true);
|
||||
argParser.addOption(null, 'nocolor', false, 'Do not use color in console output from tests.');
|
||||
|
||||
// Options that are no longer supported and should be ignored
|
||||
argParser.addIgnoredOption('l', 'lenient'); // removed in JSDoc 3.3.0
|
||||
|
||||
/**
|
||||
* Set the options for this app.
|
||||
* @throws {Error} Illegal arguments will throw errors.
|
||||
* @param {string|String[]} args The command line arguments for this app.
|
||||
*/
|
||||
exports.parse = function(args) {
|
||||
args = args || [];
|
||||
|
||||
if (typeof args === 'string' || args.constructor === String) {
|
||||
args = String(args).split(/\s+/g);
|
||||
}
|
||||
|
||||
ourOptions = argParser.parse(args);
|
||||
|
||||
return ourOptions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve help message for options.
|
||||
*/
|
||||
exports.help = function() {
|
||||
return argParser.help();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a named option.
|
||||
* @variation (name)
|
||||
* @param {string} name The name of the option.
|
||||
* @return {string} The value associated with the given name.
|
||||
*//**
|
||||
* Get all the options for this app.
|
||||
* @return {Object} A collection of key/values representing all the options.
|
||||
*/
|
||||
exports.get = function(name) {
|
||||
if (typeof name === 'undefined') {
|
||||
return ourOptions;
|
||||
}
|
||||
else if ( hasOwnProp.call(ourOptions, name) ) {
|
||||
return ourOptions[name];
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,254 @@
|
||||
'use strict';
|
||||
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
/**
|
||||
* Provides access to information about a JavaScript package.
|
||||
*
|
||||
* @module jsdoc/package
|
||||
* @see https://www.npmjs.org/doc/files/package.json.html
|
||||
*/
|
||||
|
||||
// Collect all of the license information from a `package.json` file.
|
||||
function getLicenses(packageInfo) {
|
||||
var licenses = packageInfo.licenses ? packageInfo.licenses.slice(0) : [];
|
||||
|
||||
if (packageInfo.license) {
|
||||
licenses.push({ type: packageInfo.license });
|
||||
}
|
||||
|
||||
return licenses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about where to report bugs in the package.
|
||||
*
|
||||
* @typedef {Object} module:jsdoc/package.Package~BugInfo
|
||||
* @property {string} email - The email address for reporting bugs.
|
||||
* @property {string} url - The URL for reporting bugs.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Information about a package's software license.
|
||||
*
|
||||
* @typedef {Object} module:jsdoc/package.Package~LicenseInfo
|
||||
* @property {string} type - An identifier for the type of license.
|
||||
* @property {string} url - The URL for the complete text of the license.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Information about a package author or contributor.
|
||||
*
|
||||
* @typedef {Object} module:jsdoc/package.Package~PersonInfo
|
||||
* @property {string} name - The person's full name.
|
||||
* @property {string} email - The person's email address.
|
||||
* @property {string} url - The URL of the person's website.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Information about a package's version-control repository.
|
||||
*
|
||||
* @typedef {Object} module:jsdoc/package.Package~RepositoryInfo
|
||||
* @property {string} type - The type of version-control system that the repository uses (for
|
||||
* example, `git` or `svn`).
|
||||
* @property {string} url - The URL for the repository.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Information about a JavaScript package. JSDoc can extract package information from
|
||||
* `package.json` files that follow the
|
||||
* [npm specification](https://www.npmjs.org/doc/files/package.json.html).
|
||||
*
|
||||
* **Note**: JSDoc does not validate or normalize the contents of `package.json` files. If your
|
||||
* `package.json` file does not follow the npm specification, some properties of the `Package`
|
||||
* object may not use the format documented here.
|
||||
*
|
||||
* @class
|
||||
* @param {string} json - The contents of the `package.json` file.
|
||||
*/
|
||||
exports.Package = function(json) {
|
||||
var packageInfo;
|
||||
|
||||
/**
|
||||
* The string identifier that is shared by all `Package` objects.
|
||||
*
|
||||
* @readonly
|
||||
* @default
|
||||
* @type {string}
|
||||
*/
|
||||
this.kind = 'package';
|
||||
|
||||
try {
|
||||
packageInfo = JSON.parse(json || '{}');
|
||||
}
|
||||
catch (e) {
|
||||
logger.error('Unable to parse the package file: %s', e.message);
|
||||
packageInfo = {};
|
||||
}
|
||||
|
||||
if (packageInfo.name) {
|
||||
/**
|
||||
* The package name.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = packageInfo.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The unique longname for this `Package` object.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.longname = this.kind + ':' + this.name;
|
||||
|
||||
if (packageInfo.author) {
|
||||
/**
|
||||
* The author of this package. Contains either a
|
||||
* {@link module:jsdoc/package.Package~PersonInfo PersonInfo} object or a string with
|
||||
* information about the author.
|
||||
*
|
||||
* @type {(module:jsdoc/package.Package~PersonInfo|string)}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.author = packageInfo.author;
|
||||
}
|
||||
|
||||
if (packageInfo.bugs) {
|
||||
/**
|
||||
* Information about where to report bugs in the project. May contain a URL, as a string, or
|
||||
* an object with more detailed information.
|
||||
*
|
||||
* @type {(string|module:jsdoc/package.Package~BugInfo)}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.bugs = packageInfo.bugs;
|
||||
}
|
||||
|
||||
if (packageInfo.contributors) {
|
||||
/**
|
||||
* The contributors to this package.
|
||||
*
|
||||
* @type {Array.<(module:jsdoc/package.Package~PersonInfo|string)>}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.contributors = packageInfo.contributors;
|
||||
}
|
||||
|
||||
if (packageInfo.dependencies) {
|
||||
/**
|
||||
* The dependencies for this package.
|
||||
*
|
||||
* @type {Object}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.dependencies = packageInfo.dependencies;
|
||||
}
|
||||
|
||||
if (packageInfo.description) {
|
||||
/**
|
||||
* A brief description of the package.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = packageInfo.description;
|
||||
}
|
||||
|
||||
if (packageInfo.devDependencies) {
|
||||
/**
|
||||
* The development dependencies for this package.
|
||||
*
|
||||
* @type {Object}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.devDependencies = packageInfo.devDependencies;
|
||||
}
|
||||
|
||||
if (packageInfo.engines) {
|
||||
/**
|
||||
* The JavaScript engines that this package supports. Each key is a string that identifies the
|
||||
* engine (for example, `node`). Each value is a
|
||||
* [semver](https://www.npmjs.org/doc/misc/semver.html)-compliant version number for the engine.
|
||||
*
|
||||
* @type {Object}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.engines = packageInfo.engines;
|
||||
}
|
||||
|
||||
/**
|
||||
* The source files associated with the package.
|
||||
*
|
||||
* New `Package` objects always contain an empty array, regardless of whether the `package.json`
|
||||
* file includes a `files` property.
|
||||
*
|
||||
* After JSDoc parses your input files, it sets this property to a list of paths to your input
|
||||
* files.
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.files = [];
|
||||
|
||||
if (packageInfo.homepage) {
|
||||
/**
|
||||
* The URL for the package's homepage.
|
||||
*
|
||||
* @type {string}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.homepage = packageInfo.homepage;
|
||||
}
|
||||
|
||||
if (packageInfo.keywords) {
|
||||
/**
|
||||
* Keywords to help users find the package.
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.keywords = packageInfo.keywords;
|
||||
}
|
||||
|
||||
if (packageInfo.license || packageInfo.licenses) {
|
||||
/**
|
||||
* The licenses used by this package. Combines information from the `package.json` file's
|
||||
* `license` property and the deprecated `licenses` property.
|
||||
*
|
||||
* @type {Array.<module:jsdoc/package.Package~LicenseInfo>}
|
||||
*/
|
||||
this.licenses = getLicenses(packageInfo);
|
||||
}
|
||||
|
||||
if (packageInfo.main) {
|
||||
/**
|
||||
* The module ID that provides the primary entry point to the package. For example, if your
|
||||
* package is a CommonJS module, and the value of this property is `foo`, users should be able
|
||||
* to load your module with `require('foo')`.
|
||||
*
|
||||
* @type {string}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.main = packageInfo.main;
|
||||
}
|
||||
|
||||
if (packageInfo.repository) {
|
||||
/**
|
||||
* The version-control repository for the package.
|
||||
*
|
||||
* @type {module:jsdoc/package.Package~RepositoryInfo}
|
||||
* @since 3.3.0
|
||||
*/
|
||||
this.repository = packageInfo.repository;
|
||||
}
|
||||
|
||||
if (packageInfo.version) {
|
||||
/**
|
||||
* The [semver](https://www.npmjs.org/doc/misc/semver.html)-compliant version number of the
|
||||
* package.
|
||||
*
|
||||
* @type {string}
|
||||
* @since 3.2.0
|
||||
*/
|
||||
this.version = packageInfo.version;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,134 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
* Extended version of the standard `path` module.
|
||||
* @module jsdoc/path
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var runtime = require('jsdoc/util/runtime');
|
||||
|
||||
function prefixReducer(previousPath, current) {
|
||||
var currentPath = [];
|
||||
|
||||
// if previousPath is defined, but has zero length, there's no common prefix; move along
|
||||
if (previousPath && !previousPath.length) {
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
currentPath = path.resolve(global.env.pwd, current).split(path.sep) || [];
|
||||
|
||||
if (previousPath && currentPath.length) {
|
||||
// remove chunks that exceed the previous path's length
|
||||
currentPath = currentPath.slice(0, previousPath.length);
|
||||
|
||||
// if a chunk doesn't match the previous path, remove everything from that chunk on
|
||||
for (var i = 0, l = currentPath.length; i < l; i++) {
|
||||
if (currentPath[i] !== previousPath[i]) {
|
||||
currentPath.splice(i, currentPath.length - i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the common prefix for an array of paths. If there is a common prefix, a trailing separator
|
||||
* is appended to the prefix. Relative paths are resolved relative to the current working directory.
|
||||
*
|
||||
* For example, assuming that the current working directory is `/Users/jsdoc`:
|
||||
*
|
||||
* + For the single path `foo/bar/baz/qux.js`, the common prefix is `foo/bar/baz/`.
|
||||
* + For paths `foo/bar/baz/qux.js`, `foo/bar/baz/quux.js`, and `foo/bar/baz.js`, the common prefix
|
||||
* is `/Users/jsdoc/foo/bar/`.
|
||||
* + For paths `../jsdoc/foo/bar/baz/qux/quux/test.js`, `/Users/jsdoc/foo/bar/bazzy.js`, and
|
||||
* `../../Users/jsdoc/foo/bar/foobar.js`, the common prefix is `/Users/jsdoc/foo/bar/`.
|
||||
* + For paths `foo/bar/baz/qux.js` and `../../Library/foo/bar/baz.js`, there is no common prefix,
|
||||
* and an empty string is returned.
|
||||
*
|
||||
* @param {Array.<string>} paths - The paths to search for a common prefix.
|
||||
* @return {string} The common prefix, or an empty string if there is no common prefix.
|
||||
*/
|
||||
exports.commonPrefix = function(paths) {
|
||||
var segments;
|
||||
|
||||
var prefix = '';
|
||||
|
||||
paths = paths || [];
|
||||
|
||||
// if there's only one path, its resolved dirname (plus a trailing slash) is the common prefix
|
||||
if (paths.length === 1) {
|
||||
prefix = path.resolve(global.env.pwd, paths[0]);
|
||||
if ( path.extname(prefix) ) {
|
||||
prefix = path.dirname(prefix);
|
||||
}
|
||||
|
||||
prefix += path.sep;
|
||||
}
|
||||
else {
|
||||
segments = paths.reduce(prefixReducer, undefined) || [];
|
||||
|
||||
// if there's anything left (other than a placeholder for a leading slash), add a
|
||||
// placeholder for a trailing slash
|
||||
if ( segments.length && (segments.length > 1 || segments[0] !== '') ) {
|
||||
segments.push('');
|
||||
}
|
||||
|
||||
prefix = segments.join(path.sep);
|
||||
}
|
||||
|
||||
return prefix;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the fully qualified path to the requested resource.
|
||||
*
|
||||
* If the resource path is specified as a relative path, JSDoc searches for the path in the
|
||||
* directory where the JSDoc configuration file is located, then in the current working directory,
|
||||
* and finally in the JSDoc directory.
|
||||
*
|
||||
* If the resource path is specified as a fully qualified path, JSDoc uses the path as-is.
|
||||
*
|
||||
* @param {string} filepath - The path to the requested resource. May be an absolute path; a path
|
||||
* relative to the JSDoc directory; or a path relative to the current working directory.
|
||||
* @param {string} [filename] - The filename of the requested resource.
|
||||
* @return {string} The fully qualified path (or, on Rhino, a URI) to the requested resource.
|
||||
* Includes the filename if one was provided.
|
||||
*/
|
||||
exports.getResourcePath = function(filepath, filename) {
|
||||
var result = null;
|
||||
|
||||
function pathExists(_path) {
|
||||
try {
|
||||
fs.readdirSync(_path);
|
||||
}
|
||||
catch(e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// absolute paths are normalized by path.resolve on the first pass
|
||||
[path.dirname(global.env.opts.configure || ''), env.pwd, env.dirname].forEach(function(_path) {
|
||||
if (!result && _path) {
|
||||
_path = path.resolve(_path, filepath);
|
||||
if ( pathExists(_path) ) {
|
||||
result = _path;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (result) {
|
||||
result = filename ? path.join(result, filename) : result;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Object.keys(path).forEach(function(member) {
|
||||
exports[member] = path[member];
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
/*global app: true */
|
||||
/**
|
||||
* Utility functions to support the JSDoc plugin framework.
|
||||
* @module jsdoc/plugins
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
function addHandlers(handlers, parser) {
|
||||
Object.keys(handlers).forEach(function(eventName) {
|
||||
parser.on(eventName, handlers[eventName]);
|
||||
});
|
||||
}
|
||||
|
||||
exports.installPlugins = function(plugins, parser) {
|
||||
var dictionary = require('jsdoc/tag/dictionary');
|
||||
|
||||
var eventName;
|
||||
var plugin;
|
||||
|
||||
for (var i = 0, l = plugins.length; i < l; i++) {
|
||||
plugin = require(plugins[i]);
|
||||
|
||||
// allow user-defined plugins to...
|
||||
// ...register event handlers
|
||||
if (plugin.handlers) {
|
||||
addHandlers(plugin.handlers, parser);
|
||||
}
|
||||
|
||||
// ...define tags
|
||||
if (plugin.defineTags) {
|
||||
plugin.defineTags(dictionary);
|
||||
}
|
||||
|
||||
// ...add a Rhino node visitor (deprecated in JSDoc 3.3)
|
||||
if (plugin.nodeVisitor) {
|
||||
if ( !parser.addNodeVisitor ) {
|
||||
logger.error('Unable to add the Rhino node visitor from %s, because JSDoc ' +
|
||||
'is not using the Rhino JavaScript parser.', plugins[i]);
|
||||
}
|
||||
else {
|
||||
parser.addNodeVisitor(plugin.nodeVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
// ...add a Mozilla Parser API node visitor
|
||||
if (plugin.astNodeVisitor) {
|
||||
parser.addAstNodeVisitor(plugin.astNodeVisitor);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
/*global env: true */
|
||||
|
||||
/**
|
||||
* Make the contents of a README file available to include in the output.
|
||||
* @module jsdoc/readme
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @author Ben Blank <ben.blank@gmail.com>
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var fs = require('jsdoc/fs'),
|
||||
markdown = require('jsdoc/util/markdown');
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Represents a README file.
|
||||
* @param {string} path - The filepath to the README.
|
||||
*/
|
||||
function ReadMe(path) {
|
||||
var content = fs.readFileSync(path, env.opts.encoding),
|
||||
parse = markdown.getParser();
|
||||
|
||||
this.html = parse(content);
|
||||
}
|
||||
|
||||
module.exports = ReadMe;
|
||||
@@ -0,0 +1,759 @@
|
||||
/**
|
||||
* @overview Schema for validating JSDoc doclets.
|
||||
*
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @author Jeff Williams <jeffrey.l.williams@gmail.com>
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
* @see <http://tools.ietf.org/html/draft-zyp-json-schema-03>
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// JSON schema types
|
||||
var ARRAY = 'array';
|
||||
var BOOLEAN = 'boolean';
|
||||
var INTEGER = 'integer';
|
||||
var NULL = 'null';
|
||||
var NUMBER = 'number';
|
||||
var OBJECT = 'object';
|
||||
var STRING = 'string';
|
||||
var UNDEFINED = 'undefined';
|
||||
|
||||
var BOOLEAN_OPTIONAL = [BOOLEAN, NULL, UNDEFINED];
|
||||
var STRING_OPTIONAL = [STRING, NULL, UNDEFINED];
|
||||
|
||||
var EVENT_REGEXP = /event\:[\S]+/;
|
||||
var PACKAGE_REGEXP = /package\:[\S]+/;
|
||||
|
||||
// information about the code associated with a doclet
|
||||
var META_SCHEMA = exports.META_SCHEMA = {
|
||||
type: OBJECT,
|
||||
optional: true,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
code: {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
funcscope: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
id: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
name: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
node: {
|
||||
type: OBJECT,
|
||||
optional: true
|
||||
},
|
||||
paramnames: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
type: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
value: {
|
||||
optional: true
|
||||
}
|
||||
}
|
||||
},
|
||||
filename: {
|
||||
title: 'The name of the file that contains the code associated with this doclet.',
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
lineno: {
|
||||
title: 'The line number of the code associated with this doclet.',
|
||||
type: NUMBER,
|
||||
optional: true
|
||||
},
|
||||
path: {
|
||||
title: 'The path in which the code associated with this doclet is located.',
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
range: {
|
||||
title: 'The positions of the first and last characters of the code associated with ' +
|
||||
'this doclet.',
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 2,
|
||||
maxItems: 2,
|
||||
items: {
|
||||
type: NUMBER
|
||||
}
|
||||
},
|
||||
vars: {
|
||||
type: OBJECT
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// type property containing type names
|
||||
var TYPE_PROPERTY_SCHEMA = exports.TYPE_PROPERTY_SCHEMA = {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
names: {
|
||||
type: ARRAY,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
// type parser output
|
||||
parsedType: {
|
||||
type: OBJECT,
|
||||
additionalProperties: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// enumeration properties
|
||||
var ENUM_PROPERTY_SCHEMA = exports.ENUM_PROPERTY_SCHEMA = {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
comment: {
|
||||
type: STRING
|
||||
},
|
||||
defaultvalue: {
|
||||
type: STRING_OPTIONAL,
|
||||
optional: true
|
||||
},
|
||||
description: {
|
||||
type: STRING_OPTIONAL,
|
||||
optional: true
|
||||
},
|
||||
kind: {
|
||||
type: STRING,
|
||||
// TODO: get this from a real enum somewhere
|
||||
enum: ['member']
|
||||
},
|
||||
longname: {
|
||||
type: STRING
|
||||
},
|
||||
memberof: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
meta: META_SCHEMA,
|
||||
name: {
|
||||
type: STRING
|
||||
},
|
||||
// is this member nullable? (derived from the type expression)
|
||||
nullable: {
|
||||
type: BOOLEAN_OPTIONAL
|
||||
},
|
||||
// is this member optional? (derived from the type expression)
|
||||
optional: {
|
||||
type: BOOLEAN_OPTIONAL
|
||||
},
|
||||
scope: {
|
||||
type: STRING,
|
||||
// TODO: get this from a real enum somewhere
|
||||
enum: ['static']
|
||||
},
|
||||
type: TYPE_PROPERTY_SCHEMA,
|
||||
// can this member be provided more than once? (derived from the type expression)
|
||||
variable: {
|
||||
type: BOOLEAN_OPTIONAL
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// function parameter, or object property defined with @property tag
|
||||
var PARAM_SCHEMA = exports.PARAM_SCHEMA = {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
// what is the default value for this parameter?
|
||||
defaultvalue: {
|
||||
type: STRING_OPTIONAL,
|
||||
optional: true
|
||||
},
|
||||
// a description of the parameter
|
||||
description: {
|
||||
type: STRING_OPTIONAL,
|
||||
optional: true
|
||||
},
|
||||
// what name does this parameter have within the function?
|
||||
name: {
|
||||
type: STRING
|
||||
},
|
||||
// can the value for this parameter be null?
|
||||
nullable: {
|
||||
type: BOOLEAN_OPTIONAL,
|
||||
optional: true
|
||||
},
|
||||
// is a value for this parameter optional?
|
||||
optional: {
|
||||
type: BOOLEAN_OPTIONAL,
|
||||
optional: true
|
||||
},
|
||||
// what are the types of value expected for this parameter?
|
||||
type: TYPE_PROPERTY_SCHEMA,
|
||||
// can this parameter be repeated?
|
||||
variable: {
|
||||
type: BOOLEAN_OPTIONAL,
|
||||
optional: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var DOCLET_SCHEMA = exports.DOCLET_SCHEMA = {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
// what access privileges are allowed
|
||||
access: {
|
||||
type: STRING,
|
||||
optional: true,
|
||||
// TODO: define this as an enumeration elsewhere
|
||||
enum: [
|
||||
'private',
|
||||
'protected'
|
||||
]
|
||||
},
|
||||
alias: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
augments: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
author: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
borrowed: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
// name of the target
|
||||
as: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
// name of the source
|
||||
from: {
|
||||
type: STRING
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
// a description of the class that this constructor belongs to
|
||||
classdesc: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
comment: {
|
||||
type: STRING
|
||||
},
|
||||
copyright: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
defaultvalue: {
|
||||
optional: true
|
||||
},
|
||||
defaultvaluetype: {
|
||||
type: STRING,
|
||||
optional: true,
|
||||
enum: [OBJECT, ARRAY]
|
||||
},
|
||||
// is usage of this symbol deprecated?
|
||||
deprecated: {
|
||||
type: [STRING, BOOLEAN],
|
||||
optional: true
|
||||
},
|
||||
// a description
|
||||
description: {
|
||||
type: STRING_OPTIONAL,
|
||||
optional: true
|
||||
},
|
||||
// something else to consider
|
||||
examples: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
exceptions: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
items: PARAM_SCHEMA
|
||||
},
|
||||
// the path to another constructor
|
||||
extends: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
// the path to another doc object
|
||||
fires: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: STRING,
|
||||
pattern: EVENT_REGEXP
|
||||
}
|
||||
},
|
||||
forceMemberof: {
|
||||
type: BOOLEAN_OPTIONAL,
|
||||
optional: true
|
||||
},
|
||||
ignore: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
implementations: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
implements: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
inheritdoc: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
inherited: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
inherits: {
|
||||
type: STRING,
|
||||
optional: true,
|
||||
dependency: {
|
||||
inherited: true
|
||||
}
|
||||
},
|
||||
isEnum: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
// what kind of symbol is this?
|
||||
kind: {
|
||||
type: STRING,
|
||||
// TODO: define this as an enumeration elsewhere
|
||||
enum: [
|
||||
'class',
|
||||
'constant',
|
||||
'event',
|
||||
'external',
|
||||
'file',
|
||||
'function',
|
||||
'interface',
|
||||
'member',
|
||||
'mixin',
|
||||
'module',
|
||||
'namespace',
|
||||
'package',
|
||||
'param',
|
||||
'typedef'
|
||||
]
|
||||
},
|
||||
license: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
listens: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: STRING,
|
||||
pattern: EVENT_REGEXP
|
||||
}
|
||||
},
|
||||
longname: {
|
||||
type: STRING
|
||||
},
|
||||
// probably a leading substring of the path
|
||||
memberof: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
// information about this doc
|
||||
meta: META_SCHEMA,
|
||||
// was this doclet mixed in?
|
||||
mixed: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
mixes: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
// probably a trailing substring of the path
|
||||
name: {
|
||||
type: STRING
|
||||
},
|
||||
// is this member nullable? (derived from the type expression)
|
||||
nullable: {
|
||||
type: BOOLEAN_OPTIONAL
|
||||
},
|
||||
// is this member optional? (derived from the type expression)
|
||||
optional: {
|
||||
type: BOOLEAN_OPTIONAL
|
||||
},
|
||||
// does this member explicitly override the parent?
|
||||
override: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
overrides: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
// are there function parameters associated with this doc?
|
||||
params: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
items: PARAM_SCHEMA
|
||||
},
|
||||
preserveName: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
properties: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
anyOf: [ENUM_PROPERTY_SCHEMA, PARAM_SCHEMA]
|
||||
}
|
||||
},
|
||||
readonly: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
// the symbol being documented requires another symbol
|
||||
requires: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
uniqueItems: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
returns: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 1,
|
||||
items: PARAM_SCHEMA
|
||||
},
|
||||
// what sort of parent scope does this symbol have?
|
||||
scope: {
|
||||
type: STRING,
|
||||
enum: [
|
||||
// TODO: make these an enumeration
|
||||
'global',
|
||||
'inner',
|
||||
'instance',
|
||||
'static'
|
||||
]
|
||||
},
|
||||
// something else to consider
|
||||
see: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
// at what previous version was this doc added?
|
||||
since: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
summary: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
// arbitrary tags associated with this doc
|
||||
tags: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
originalTitle: {
|
||||
type: STRING
|
||||
},
|
||||
text: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
title: {
|
||||
type: STRING
|
||||
},
|
||||
value: {
|
||||
type: [STRING, OBJECT],
|
||||
optional: true,
|
||||
properties: PARAM_SCHEMA
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'this': {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
todo: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
// extended tutorials
|
||||
tutorials: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
// what type is the value that this doc is associated with, like `number`
|
||||
type: TYPE_PROPERTY_SCHEMA,
|
||||
undocumented: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
// can this member be provided more than once? (derived from the type expression)
|
||||
variable: {
|
||||
type: BOOLEAN_OPTIONAL
|
||||
},
|
||||
variation: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
// what is the version of this doc
|
||||
version: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
// is a member left to be implemented during inheritance?
|
||||
virtual: {
|
||||
type: BOOLEAN,
|
||||
optional: true
|
||||
},
|
||||
// Platform support
|
||||
platforms: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var CONTACT_INFO_SCHEMA = exports.CONTACT_INFO_SCHEMA = {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
email: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
name: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
url: {
|
||||
type: STRING,
|
||||
optional: true,
|
||||
format: 'uri'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var BUGS_SCHEMA = exports.BUGS_SCHEMA = {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
email: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
url: {
|
||||
type: STRING,
|
||||
optional: true,
|
||||
format: 'uri'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var PACKAGE_SCHEMA = exports.PACKAGE_SCHEMA = {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
author: {
|
||||
anyOf: [STRING, CONTACT_INFO_SCHEMA],
|
||||
optional: true
|
||||
},
|
||||
bugs: {
|
||||
anyOf: [STRING, BUGS_SCHEMA],
|
||||
optional: true
|
||||
},
|
||||
contributors: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 0,
|
||||
items: {
|
||||
anyOf: [STRING, CONTACT_INFO_SCHEMA]
|
||||
}
|
||||
},
|
||||
dependencies: {
|
||||
type: OBJECT,
|
||||
optional: true
|
||||
},
|
||||
description: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
devDependencies: {
|
||||
type: OBJECT,
|
||||
optional: true
|
||||
},
|
||||
engines: {
|
||||
type: OBJECT,
|
||||
optional: true
|
||||
},
|
||||
files: {
|
||||
type: ARRAY,
|
||||
uniqueItems: true,
|
||||
minItems: 0,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
homepage: {
|
||||
type: STRING,
|
||||
optional: true,
|
||||
format: 'uri'
|
||||
},
|
||||
keywords: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 0,
|
||||
items: {
|
||||
type: STRING
|
||||
}
|
||||
},
|
||||
kind: {
|
||||
type: STRING,
|
||||
enum: ['package']
|
||||
},
|
||||
licenses: {
|
||||
type: ARRAY,
|
||||
optional: true,
|
||||
minItems: 1,
|
||||
items: {
|
||||
type: OBJECT,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
type: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
url: {
|
||||
type: STRING,
|
||||
optional: true,
|
||||
format: 'uri'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
longname: {
|
||||
type: STRING,
|
||||
optional: true,
|
||||
pattern: PACKAGE_REGEXP
|
||||
},
|
||||
main: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
name: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
repository: {
|
||||
type: OBJECT,
|
||||
optional: true,
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
type: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
},
|
||||
// we don't use `format: 'uri'` here because repo URLs are atypical
|
||||
url: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
}
|
||||
}
|
||||
},
|
||||
version: {
|
||||
type: STRING,
|
||||
optional: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var DOCLETS_SCHEMA = exports.DOCLETS_SCHEMA = {
|
||||
type: ARRAY,
|
||||
items: {
|
||||
anyOf: [DOCLET_SCHEMA, PACKAGE_SCHEMA]
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,419 @@
|
||||
'use strict';
|
||||
|
||||
var esprima = require('esprima');
|
||||
var jsdoc = {
|
||||
src: {
|
||||
syntax: require('jsdoc/src/syntax'),
|
||||
Walker: require('jsdoc/src/walker').Walker
|
||||
},
|
||||
util: {
|
||||
logger: require('jsdoc/util/logger')
|
||||
}
|
||||
};
|
||||
var Syntax = jsdoc.src.syntax.Syntax;
|
||||
|
||||
// TODO: should set e.stopPropagation == true for consistency with Rhino, right?
|
||||
var VISITOR_CONTINUE = true;
|
||||
var VISITOR_STOP = false;
|
||||
|
||||
// TODO: docs; empty array means any node type, otherwise only the node types in the array
|
||||
var acceptsLeadingComments = (function() {
|
||||
var accepts = {};
|
||||
|
||||
// these nodes always accept leading comments
|
||||
var commentable = [
|
||||
Syntax.AssignmentExpression,
|
||||
Syntax.CallExpression,
|
||||
Syntax.FunctionDeclaration,
|
||||
Syntax.FunctionExpression,
|
||||
Syntax.MemberExpression,
|
||||
Syntax.Property,
|
||||
Syntax.TryStatement,
|
||||
Syntax.VariableDeclaration,
|
||||
Syntax.VariableDeclarator,
|
||||
Syntax.WithStatement
|
||||
];
|
||||
for (var i = 0, l = commentable.length; i < l; i++) {
|
||||
accepts[commentable[i]] = [];
|
||||
}
|
||||
|
||||
// these nodes accept leading comments if they have specific types of parent nodes
|
||||
// like: function foo(/** @type {string} */ bar) {}
|
||||
accepts[Syntax.Identifier] = [
|
||||
Syntax.CatchClause,
|
||||
Syntax.FunctionDeclaration,
|
||||
Syntax.FunctionExpression
|
||||
];
|
||||
// like: var Foo = Class.create(/** @lends Foo */{ // ... })
|
||||
accepts[Syntax.ObjectExpression] = [
|
||||
Syntax.CallExpression,
|
||||
Syntax.Property,
|
||||
Syntax.ReturnStatement
|
||||
];
|
||||
|
||||
return accepts;
|
||||
})();
|
||||
|
||||
// TODO: docs
|
||||
function canAcceptComment(node) {
|
||||
var canAccept = false;
|
||||
var spec = acceptsLeadingComments[node.type];
|
||||
|
||||
if (spec) {
|
||||
// empty array means we don't care about the parent type
|
||||
if (spec.length === 0) {
|
||||
canAccept = true;
|
||||
}
|
||||
// we can accept the comment if the spec contains the type of the node's parent
|
||||
else if (node.parent) {
|
||||
canAccept = spec.indexOf(node.parent.type) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
return canAccept;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
// check whether node1 is before node2
|
||||
function isBefore(beforeRange, afterRange) {
|
||||
return beforeRange[1] <= afterRange[0];
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function isWithin(innerRange, outerRange) {
|
||||
return innerRange[0] >= outerRange[0] && innerRange[1] <= outerRange[1];
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function isJsdocComment(comment) {
|
||||
return comment && (comment.type === 'Block') && (comment.value[0] === '*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the raw comment string to a block comment node.
|
||||
*
|
||||
* @private
|
||||
* @param {!Object} comment - A comment node with `type` and `value` properties.
|
||||
*/
|
||||
function addRawComment(comment) {
|
||||
comment.raw = comment.raw || ('/*' + comment.value + '*/');
|
||||
return comment;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function scrubComments(comments) {
|
||||
var comment;
|
||||
|
||||
var scrubbed = [];
|
||||
|
||||
for (var i = 0, l = comments.length; i < l; i++) {
|
||||
comment = comments[i];
|
||||
if ( isJsdocComment(comment) ) {
|
||||
scrubbed.push( addRawComment(comment) );
|
||||
}
|
||||
}
|
||||
|
||||
return scrubbed;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
var AstBuilder = exports.AstBuilder = function() {};
|
||||
|
||||
function parse(source, filename, esprimaOpts) {
|
||||
var ast;
|
||||
|
||||
try {
|
||||
ast = esprima.parse(source, esprimaOpts);
|
||||
}
|
||||
catch (e) {
|
||||
jsdoc.util.logger.error('Unable to parse %s: %s', filename, e.message);
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
AstBuilder.prototype.build = function(source, filename) {
|
||||
var ast;
|
||||
|
||||
var esprimaOpts = {
|
||||
comment: true,
|
||||
loc: true,
|
||||
range: true,
|
||||
tokens: true
|
||||
};
|
||||
|
||||
ast = parse(source, filename, esprimaOpts);
|
||||
|
||||
if (ast) {
|
||||
this._postProcess(filename, ast);
|
||||
}
|
||||
|
||||
return ast;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
function atomSorter(a, b) {
|
||||
var aRange = a.range;
|
||||
var bRange = b.range;
|
||||
var result = 0;
|
||||
|
||||
// does a end before b starts?
|
||||
if ( isBefore(aRange, bRange) ) {
|
||||
result = -1;
|
||||
}
|
||||
// does a enclose b?
|
||||
else if ( isWithin(bRange, aRange) ) {
|
||||
result = -1;
|
||||
}
|
||||
// does a start before b?
|
||||
else if (aRange[0] < bRange[0]) {
|
||||
result = -1;
|
||||
}
|
||||
// are the ranges non-identical? if so, b must be first
|
||||
else if ( aRange[0] !== bRange[0] || aRange[1] !== bRange[1] ) {
|
||||
result = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
// TODO: export?
|
||||
function CommentAttacher(comments, tokens) {
|
||||
this._comments = comments || [];
|
||||
this._tokens = tokens || [];
|
||||
|
||||
this._tokenIndex = 0;
|
||||
this._previousNode = null;
|
||||
this._astRoot = null;
|
||||
|
||||
this._resetPendingComments()
|
||||
._resetCandidates();
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype._resetPendingComments = function() {
|
||||
this._pendingComments = [];
|
||||
this._pendingCommentRange = null;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype._resetCandidates = function() {
|
||||
this._candidates = [];
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype._nextComment = function() {
|
||||
return this._comments[0] || null;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype._nextToken = function() {
|
||||
return this._tokens[this._tokenIndex] || null;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
// find the index of the atom whose end position is closest to (but not after) the specified
|
||||
// position
|
||||
CommentAttacher.prototype._nextIndexBefore = function(atoms, startIndex, position) {
|
||||
var atom;
|
||||
|
||||
var newIndex = startIndex;
|
||||
|
||||
for (var i = newIndex, l = atoms.length; i < l; i++) {
|
||||
atom = atoms[i];
|
||||
|
||||
if (atom.range[1] > position) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
newIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
return newIndex;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype._advanceTokenIndex = function(node) {
|
||||
var position = node.range[0];
|
||||
|
||||
this._tokenIndex = this._nextIndexBefore(this._tokens, this._tokenIndex, position);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype._fastForwardComments = function(node) {
|
||||
var position = node.range[0];
|
||||
var commentIndex = this._nextIndexBefore(this._comments, 0, position);
|
||||
|
||||
// all comments before the node (except the last one) are pended
|
||||
if (commentIndex > 0) {
|
||||
this._pendingComments = this._pendingComments.concat( this._comments.splice(0,
|
||||
commentIndex) );
|
||||
}
|
||||
};
|
||||
|
||||
CommentAttacher.prototype._attachPendingCommentsAsLeading = function(target) {
|
||||
target.leadingComments = (target.leadingComments || []).concat(this._pendingComments);
|
||||
};
|
||||
|
||||
CommentAttacher.prototype._attachPendingCommentsAsTrailing = function(target) {
|
||||
target.trailingComments = (target.trailingComments || []).concat(this._pendingComments);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype._attachPendingComments = function(currentNode) {
|
||||
var target;
|
||||
|
||||
if (!this._pendingComments.length) {
|
||||
return this;
|
||||
}
|
||||
|
||||
// if there are one or more candidate nodes, attach the pending comments before the last
|
||||
// candidate node
|
||||
if (this._candidates.length > 0) {
|
||||
target = this._candidates[this._candidates.length - 1];
|
||||
this._attachPendingCommentsAsLeading(target);
|
||||
}
|
||||
// if we don't have a previous node, attach pending comments before the AST root; this should
|
||||
// mean that we haven't encountered any other nodes yet, or that the source file contains
|
||||
// JSDoc comments but not code
|
||||
else if (!this._previousNode) {
|
||||
target = this._astRoot;
|
||||
this._attachPendingCommentsAsLeading(target);
|
||||
}
|
||||
// otherwise, the comments must come after the current node (or the last node of the AST, if
|
||||
// we've run out of nodes)
|
||||
else {
|
||||
this._attachPendingCommentsAsTrailing(currentNode || this._previousNode);
|
||||
}
|
||||
|
||||
// update the previous node
|
||||
this._previousNode = currentNode;
|
||||
|
||||
this._resetPendingComments()
|
||||
._resetCandidates();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype._isEligible = function(node) {
|
||||
var atoms;
|
||||
var token;
|
||||
|
||||
var isEligible = false;
|
||||
|
||||
var comment = this._nextComment();
|
||||
if (comment) {
|
||||
atoms = [node, comment];
|
||||
token = this._nextToken();
|
||||
if (token) {
|
||||
atoms.push(token);
|
||||
}
|
||||
|
||||
atoms.sort(atomSorter);
|
||||
|
||||
// a candidate node must immediately follow the comment
|
||||
if (atoms.indexOf(node) === atoms.indexOf(comment) + 1) {
|
||||
isEligible = true;
|
||||
}
|
||||
}
|
||||
|
||||
return isEligible;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
// TODO: do we ever get multiple candidate nodes?
|
||||
CommentAttacher.prototype.visit = function(node) {
|
||||
var isEligible;
|
||||
|
||||
// bail if we're out of comments
|
||||
if ( !this._nextComment() ) {
|
||||
return VISITOR_STOP;
|
||||
}
|
||||
|
||||
// set the AST root if necessary
|
||||
this._astRoot = this._astRoot || node;
|
||||
|
||||
// move to the next token, and fast-forward past comments that can no longer be attached
|
||||
this._advanceTokenIndex(node);
|
||||
this._fastForwardComments(node);
|
||||
// now we can check whether the current node is in the right position to accept the next comment
|
||||
isEligible = this._isEligible(node);
|
||||
|
||||
// attach the pending comments, if any
|
||||
this._attachPendingComments(node);
|
||||
|
||||
// okay, now that we've done all that bookkeeping, we can check whether the current node accepts
|
||||
// leading comments and add it to the candidate list if needed
|
||||
if ( isEligible && canAcceptComment(node) ) {
|
||||
// make sure we don't go past the end of the outermost target node
|
||||
if (!this._pendingCommentRange) {
|
||||
this._pendingCommentRange = node.range.slice(0);
|
||||
}
|
||||
this._candidates.push(node);
|
||||
|
||||
// we have a candidate node, so pend the current comment
|
||||
this._pendingComments.push(this._comments.splice(0, 1)[0]);
|
||||
}
|
||||
|
||||
return VISITOR_CONTINUE;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
CommentAttacher.prototype.finish = function() {
|
||||
var length = this._comments.length;
|
||||
|
||||
// any leftover comments are pended
|
||||
if (length) {
|
||||
this._pendingComments = this._pendingComments.concat( this._comments.splice(0, length) );
|
||||
}
|
||||
|
||||
// attach the pending comments, if any
|
||||
this._attachPendingComments();
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
// TODO: refactor to make this extensible
|
||||
/**
|
||||
* @private
|
||||
* @param {string} filename - The full path to the source file.
|
||||
* @param {Object} ast - An abstract syntax tree that conforms to the Mozilla Parser API.
|
||||
*/
|
||||
AstBuilder.prototype._postProcess = function(filename, ast) {
|
||||
var attachComments = !!ast.comments && !!ast.comments.length;
|
||||
var commentAttacher;
|
||||
var scrubbed;
|
||||
var visitor;
|
||||
var walker;
|
||||
|
||||
if (!attachComments) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrubbed = scrubComments(ast.comments.slice(0));
|
||||
commentAttacher = new CommentAttacher(scrubbed.slice(0), ast.tokens);
|
||||
visitor = {
|
||||
visit: function(node) {
|
||||
return commentAttacher.visit(node);
|
||||
}
|
||||
};
|
||||
walker = new jsdoc.src.Walker();
|
||||
|
||||
walker.recurse(ast, visitor, filename);
|
||||
|
||||
commentAttacher.finish();
|
||||
|
||||
// replace the comments with the filtered comments
|
||||
ast.comments = scrubbed;
|
||||
// we no longer need the tokens
|
||||
ast.tokens = [];
|
||||
};
|
||||
@@ -0,0 +1,299 @@
|
||||
// TODO: docs
|
||||
'use strict';
|
||||
|
||||
var Syntax = require('jsdoc/src/syntax').Syntax;
|
||||
var util = require('util');
|
||||
|
||||
// Counter for generating unique node IDs.
|
||||
var uid = 100000000;
|
||||
|
||||
/**
|
||||
* Check whether an AST node represents a function.
|
||||
*
|
||||
* @param {Object} node - The AST node to check.
|
||||
* @return {boolean} Set to `true` if the node is a function or `false` in all other cases.
|
||||
*/
|
||||
var isFunction = exports.isFunction = function(node) {
|
||||
return node.type === Syntax.FunctionDeclaration || node.type === Syntax.FunctionExpression;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether an AST node creates a new scope.
|
||||
*
|
||||
* @param {Object} node - The AST node to check.
|
||||
* @return {Boolean} Set to `true` if the node creates a new scope, or `false` in all other cases.
|
||||
*/
|
||||
var isScope = exports.isScope = function(node) {
|
||||
// TODO: handle blocks with "let" declarations
|
||||
return !!node && typeof node === 'object' && ( node.type === Syntax.CatchClause ||
|
||||
isFunction(node) );
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
var addNodeProperties = exports.addNodeProperties = function(node) {
|
||||
var debugEnabled = !!global.env.opts.debug;
|
||||
var newProperties = {};
|
||||
|
||||
if (!node || typeof node !== 'object') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!node.nodeId) {
|
||||
newProperties.nodeId = {
|
||||
value: 'astnode' + uid++,
|
||||
enumerable: debugEnabled
|
||||
};
|
||||
}
|
||||
|
||||
if (!node.parent && node.parent !== null) {
|
||||
newProperties.parent = {
|
||||
// `null` means 'no parent', so use `undefined` for now
|
||||
value: undefined,
|
||||
writable: true
|
||||
};
|
||||
}
|
||||
|
||||
if (!node.enclosingScope && node.enclosingScope !== null) {
|
||||
newProperties.enclosingScope = {
|
||||
// `null` means 'no enclosing scope', so use `undefined` for now
|
||||
value: undefined,
|
||||
writable: true
|
||||
};
|
||||
}
|
||||
|
||||
if (debugEnabled && !node.parentId) {
|
||||
newProperties.parentId = {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.parent ? this.parent.nodeId : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (debugEnabled && !node.enclosingScopeId) {
|
||||
newProperties.enclosingScopeId = {
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return this.enclosingScope ? this.enclosingScope.nodeId : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Object.defineProperties(node, newProperties);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
var nodeToString = exports.nodeToString = function(node) {
|
||||
var tempObject;
|
||||
|
||||
var str = '';
|
||||
|
||||
switch (node.type) {
|
||||
case Syntax.ArrayExpression:
|
||||
tempObject = [];
|
||||
node.elements.forEach(function(el, i) {
|
||||
// handle sparse arrays. use `null` to represent missing values, consistent with
|
||||
// JSON.stringify([,]).
|
||||
if (!el) {
|
||||
tempObject[i] = null;
|
||||
}
|
||||
// preserve literal values so that the JSON form shows the correct type
|
||||
else if (el.type === Syntax.Literal) {
|
||||
tempObject[i] = el.value;
|
||||
}
|
||||
else {
|
||||
tempObject[i] = nodeToString(el);
|
||||
}
|
||||
});
|
||||
|
||||
str = JSON.stringify(tempObject);
|
||||
break;
|
||||
|
||||
case Syntax.AssignmentExpression:
|
||||
str = nodeToString(node.left);
|
||||
break;
|
||||
|
||||
case Syntax.FunctionDeclaration:
|
||||
// falls through
|
||||
|
||||
case Syntax.FunctionExpression:
|
||||
str = 'function';
|
||||
break;
|
||||
|
||||
case Syntax.Identifier:
|
||||
str = node.name;
|
||||
break;
|
||||
|
||||
case Syntax.Literal:
|
||||
str = String(node.value);
|
||||
break;
|
||||
|
||||
case Syntax.MemberExpression:
|
||||
// could be computed (like foo['bar']) or not (like foo.bar)
|
||||
str = nodeToString(node.object);
|
||||
if (node.computed) {
|
||||
str += util.format('[%s]', node.property.raw);
|
||||
}
|
||||
else {
|
||||
str += '.' + nodeToString(node.property);
|
||||
}
|
||||
break;
|
||||
|
||||
case Syntax.ObjectExpression:
|
||||
tempObject = {};
|
||||
node.properties.forEach(function(prop) {
|
||||
var key = prop.key.name;
|
||||
// preserve literal values so that the JSON form shows the correct type
|
||||
if (prop.value.type === Syntax.Literal) {
|
||||
tempObject[key] = prop.value.value;
|
||||
}
|
||||
else {
|
||||
tempObject[key] = nodeToString(prop);
|
||||
}
|
||||
});
|
||||
|
||||
str = JSON.stringify(tempObject);
|
||||
break;
|
||||
|
||||
case Syntax.ThisExpression:
|
||||
str = 'this';
|
||||
break;
|
||||
|
||||
case Syntax.UnaryExpression:
|
||||
// like -1. in theory, operator can be prefix or postfix. in practice, any value with a
|
||||
// valid postfix operator (such as -- or ++) is not a UnaryExpression.
|
||||
str = nodeToString(node.argument);
|
||||
|
||||
// workaround for https://code.google.com/p/esprima/issues/detail?id=526
|
||||
if (node.prefix === true || node.prefix === undefined) {
|
||||
str = node.operator + str;
|
||||
}
|
||||
else {
|
||||
// this shouldn't happen
|
||||
throw new Error( util.format('Found a UnaryExpression with a postfix operator: %j',
|
||||
node) );
|
||||
}
|
||||
break;
|
||||
|
||||
case Syntax.VariableDeclarator:
|
||||
str = nodeToString(node.id);
|
||||
break;
|
||||
|
||||
default:
|
||||
str = '';
|
||||
}
|
||||
|
||||
return str;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
var getParamNames = exports.getParamNames = function(node) {
|
||||
if (!node || !node.params) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return node.params.map(function(param) {
|
||||
return nodeToString(param);
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
var isAccessor = exports.isAccessor = function(node) {
|
||||
return !!node && typeof node === 'object' && node.type === Syntax.Property &&
|
||||
(node.kind === 'get' || node.kind === 'set');
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
var isAssignment = exports.isAssignment = function(node) {
|
||||
return !!node && typeof node === 'object' && (node.type === Syntax.AssignmentExpression ||
|
||||
node.type === Syntax.VariableDeclarator);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
/**
|
||||
* Retrieve information about the node, including its name and type.
|
||||
*/
|
||||
var getInfo = exports.getInfo = function(node) {
|
||||
var info = {};
|
||||
|
||||
switch (node.type) {
|
||||
// like: "foo = 'bar'" (after declaring foo)
|
||||
// like: "MyClass.prototype.myMethod = function() {}" (after declaring MyClass)
|
||||
case Syntax.AssignmentExpression:
|
||||
info.node = node.right;
|
||||
info.name = nodeToString(node.left);
|
||||
info.type = info.node.type;
|
||||
info.value = nodeToString(info.node);
|
||||
// if the assigned value is a function, we need to capture the parameter names here
|
||||
info.paramnames = getParamNames(node.right);
|
||||
break;
|
||||
|
||||
// like: "function foo() {}"
|
||||
case Syntax.FunctionDeclaration:
|
||||
info.node = node;
|
||||
info.name = nodeToString(node.id);
|
||||
info.type = info.node.type;
|
||||
info.paramnames = getParamNames(node);
|
||||
break;
|
||||
|
||||
// like the function in: "var foo = function() {}"
|
||||
case Syntax.FunctionExpression:
|
||||
info.node = node;
|
||||
// TODO: should we add a name for, e.g., "var foo = function bar() {}"?
|
||||
info.name = '';
|
||||
info.type = info.node.type;
|
||||
info.paramnames = getParamNames(node);
|
||||
break;
|
||||
|
||||
// like the param "bar" in: "function foo(bar) {}"
|
||||
case Syntax.Identifier:
|
||||
info.node = node;
|
||||
info.name = nodeToString(info.node);
|
||||
info.type = info.node.type;
|
||||
break;
|
||||
|
||||
// like "a.b.c"
|
||||
case Syntax.MemberExpression:
|
||||
info.node = node;
|
||||
info.name = nodeToString(info.node);
|
||||
info.type = info.node.type;
|
||||
break;
|
||||
|
||||
// like "a: 0" in "var foo = {a: 0}"
|
||||
case Syntax.Property:
|
||||
info.node = node.value;
|
||||
info.name = nodeToString(node.key);
|
||||
info.value = nodeToString(info.node);
|
||||
|
||||
if ( isAccessor(node) ) {
|
||||
info.type = nodeToString(info.node);
|
||||
info.paramnames = getParamNames(info.node);
|
||||
}
|
||||
else {
|
||||
info.type = info.node.type;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// like: "var i = 0" (has init property)
|
||||
// like: "var i" (no init property)
|
||||
case Syntax.VariableDeclarator:
|
||||
info.node = node.init || node.id;
|
||||
info.name = node.id.name;
|
||||
|
||||
if (node.init) {
|
||||
info.type = info.node.type;
|
||||
info.value = nodeToString(info.node);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
info.node = node;
|
||||
info.type = info.node.type;
|
||||
}
|
||||
|
||||
return info;
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
@module jsdoc/src/filter
|
||||
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
var pwd = env.pwd;
|
||||
|
||||
function makeRegExp(config) {
|
||||
var regExp = null;
|
||||
|
||||
if (config) {
|
||||
regExp = (typeof config === 'string') ? new RegExp(config) : config;
|
||||
}
|
||||
|
||||
return regExp;
|
||||
}
|
||||
|
||||
/**
|
||||
@constructor
|
||||
@param {object} opts
|
||||
@param {string[]} opts.exclude - Specific files to exclude.
|
||||
@param {string|RegExp} opts.includePattern
|
||||
@param {string|RegExp} opts.excludePattern
|
||||
*/
|
||||
exports.Filter = function(opts) {
|
||||
this.exclude = opts.exclude && Array.isArray(opts.exclude) ?
|
||||
opts.exclude.map(function($) {
|
||||
return path.resolve(pwd, $);
|
||||
}) :
|
||||
null;
|
||||
this.includePattern = makeRegExp(opts.includePattern);
|
||||
this.excludePattern = makeRegExp(opts.excludePattern);
|
||||
};
|
||||
|
||||
/**
|
||||
@param {string} filepath - The filepath to check.
|
||||
@returns {boolean} Should the given file be included?
|
||||
*/
|
||||
exports.Filter.prototype.isIncluded = function(filepath) {
|
||||
var included = true;
|
||||
|
||||
filepath = path.resolve(pwd, filepath);
|
||||
|
||||
if ( this.includePattern && !this.includePattern.test(filepath) ) {
|
||||
included = false;
|
||||
}
|
||||
|
||||
if ( this.excludePattern && this.excludePattern.test(filepath) ) {
|
||||
included = false;
|
||||
}
|
||||
|
||||
if (this.exclude) {
|
||||
this.exclude.forEach(function(exclude) {
|
||||
if ( filepath.indexOf(exclude) === 0 ) {
|
||||
included = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return included;
|
||||
};
|
||||
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* @module jsdoc/src/handlers
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var escape = require('escape-string-regexp');
|
||||
var jsdoc = {
|
||||
doclet: require('jsdoc/doclet'),
|
||||
name: require('jsdoc/name'),
|
||||
util: {
|
||||
logger: require('jsdoc/util/logger')
|
||||
}
|
||||
};
|
||||
var util = require('util');
|
||||
|
||||
var currentModule = null;
|
||||
var SCOPE_NAMES = jsdoc.name.SCOPE.NAMES;
|
||||
var SCOPE_PUNC = jsdoc.name.SCOPE.PUNC;
|
||||
var unresolvedName = /^((?:module.)?exports|this)(\.|$)/;
|
||||
|
||||
function CurrentModule(doclet) {
|
||||
this.doclet = doclet;
|
||||
this.longname = doclet.longname;
|
||||
this.originalName = doclet.meta.code.name || '';
|
||||
}
|
||||
|
||||
function filterByLongname(doclet) {
|
||||
// you can't document prototypes
|
||||
if ( /#$/.test(doclet.longname) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function createDoclet(comment, e) {
|
||||
var doclet;
|
||||
var err;
|
||||
|
||||
try {
|
||||
doclet = new jsdoc.doclet.Doclet(comment, e);
|
||||
}
|
||||
catch (error) {
|
||||
err = new Error( util.format('cannot create a doclet for the comment "%s": %s',
|
||||
comment.replace(/[\r\n]/g, ''), error.message) );
|
||||
jsdoc.util.logger.error(err);
|
||||
doclet = new jsdoc.doclet.Doclet('', e);
|
||||
}
|
||||
|
||||
return doclet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a doclet for a `symbolFound` event. The doclet represents an actual symbol that is defined
|
||||
* in the code.
|
||||
*
|
||||
* Here's why this function is useful. A JSDoc comment can define a symbol name by including:
|
||||
*
|
||||
* + A `@name` tag
|
||||
* + Another tag that accepts a name, such as `@function`
|
||||
*
|
||||
* When the JSDoc comment defines a symbol name, we treat it as a "virtual comment" for a symbol
|
||||
* that isn't actually present in the code. And if a virtual comment is attached to a symbol, it's
|
||||
* possible that the comment and symbol have nothing to do with one another.
|
||||
*
|
||||
* To handle this case, this function checks the new doclet to see if we've already added a name
|
||||
* property by parsing the JSDoc comment. If so, this method creates a replacement doclet that
|
||||
* ignores the attached JSDoc comment and only looks at the code.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
function createSymbolDoclet(comment, e) {
|
||||
var doclet = createDoclet(comment, e);
|
||||
|
||||
if (doclet.name) {
|
||||
// try again, without the comment
|
||||
e.comment = '@undocumented';
|
||||
doclet = createDoclet(e.comment, e);
|
||||
}
|
||||
|
||||
return doclet;
|
||||
}
|
||||
|
||||
function setCurrentModule(doclet) {
|
||||
if (doclet.kind === 'module') {
|
||||
currentModule = new CurrentModule(doclet);
|
||||
}
|
||||
}
|
||||
|
||||
function setModuleScopeMemberOf(doclet) {
|
||||
// handle module symbols that are _not_ assigned to module.exports
|
||||
if (currentModule && currentModule.longname !== doclet.name) {
|
||||
// if we don't already know the scope, it must be an inner member
|
||||
if (!doclet.scope) {
|
||||
doclet.addTag('inner');
|
||||
}
|
||||
|
||||
// if the doclet isn't a memberof anything yet, and it's not a global, it must be a memberof
|
||||
// the current module
|
||||
if (!doclet.memberof && doclet.scope !== SCOPE_NAMES.GLOBAL) {
|
||||
doclet.addTag('memberof', currentModule.longname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setDefaultScope(doclet) {
|
||||
// module doclets don't get a default scope
|
||||
if (!doclet.scope && doclet.kind !== 'module') {
|
||||
doclet.setScope(SCOPE_NAMES.GLOBAL);
|
||||
}
|
||||
}
|
||||
|
||||
function addDoclet(parser, newDoclet) {
|
||||
var e;
|
||||
if (newDoclet) {
|
||||
setCurrentModule(newDoclet);
|
||||
e = { doclet: newDoclet };
|
||||
parser.emit('newDoclet', e);
|
||||
|
||||
if ( !e.defaultPrevented && !filterByLongname(e.doclet) ) {
|
||||
parser.addResult(e.doclet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processAlias(parser, doclet, astNode) {
|
||||
var memberofName;
|
||||
|
||||
if (doclet.alias === '{@thisClass}') {
|
||||
memberofName = parser.resolveThis(astNode);
|
||||
|
||||
// "class" refers to the owner of the prototype, not the prototype itself
|
||||
if ( /^(.+?)(\.prototype|#)$/.test(memberofName) ) {
|
||||
memberofName = RegExp.$1;
|
||||
}
|
||||
doclet.alias = memberofName;
|
||||
}
|
||||
|
||||
doclet.addTag('name', doclet.alias);
|
||||
doclet.postProcess();
|
||||
}
|
||||
|
||||
// TODO: separate code that resolves `this` from code that resolves the module object
|
||||
function findSymbolMemberof(parser, doclet, astNode, nameStartsWith, trailingPunc) {
|
||||
var memberof = '';
|
||||
var nameAndPunc = nameStartsWith + (trailingPunc || '');
|
||||
var scopePunc = '';
|
||||
|
||||
// remove stuff that indicates module membership (but don't touch the name `module.exports`,
|
||||
// which identifies the module object itself)
|
||||
if (doclet.name !== 'module.exports') {
|
||||
doclet.name = doclet.name.replace(nameAndPunc, '');
|
||||
}
|
||||
|
||||
// like `bar` in:
|
||||
// exports.bar = 1;
|
||||
// module.exports.bar = 1;
|
||||
// module.exports = MyModuleObject; MyModuleObject.bar = 1;
|
||||
if (nameStartsWith !== 'this' && currentModule && doclet.name !== 'module.exports') {
|
||||
memberof = currentModule.longname;
|
||||
scopePunc = SCOPE_PUNC.STATIC;
|
||||
}
|
||||
// like: module.exports = 1;
|
||||
else if (doclet.name === 'module.exports' && currentModule) {
|
||||
doclet.addTag('name', currentModule.longname);
|
||||
doclet.postProcess();
|
||||
}
|
||||
else {
|
||||
memberof = parser.resolveThis(astNode);
|
||||
|
||||
// like the following at the top level of a module:
|
||||
// this.foo = 1;
|
||||
if (nameStartsWith === 'this' && currentModule && !memberof) {
|
||||
memberof = currentModule.longname;
|
||||
scopePunc = SCOPE_PUNC.STATIC;
|
||||
}
|
||||
else {
|
||||
scopePunc = SCOPE_PUNC.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
memberof: memberof,
|
||||
scopePunc: scopePunc
|
||||
};
|
||||
}
|
||||
|
||||
function addSymbolMemberof(parser, doclet, astNode) {
|
||||
var basename;
|
||||
var memberof;
|
||||
var memberofInfo;
|
||||
var moduleOriginalName = '';
|
||||
var resolveTargetRegExp;
|
||||
var scopePunc;
|
||||
var unresolved;
|
||||
|
||||
if (!astNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check to see if the doclet name is an unresolved reference to the module object, or to `this`
|
||||
// TODO: handle cases where the module object is shadowed in the current scope
|
||||
if (currentModule) {
|
||||
moduleOriginalName = '|' + currentModule.originalName;
|
||||
}
|
||||
resolveTargetRegExp = new RegExp('^((?:module.)?exports|this' + moduleOriginalName +
|
||||
')(\\.|$)');
|
||||
unresolved = resolveTargetRegExp.exec(doclet.name);
|
||||
|
||||
if (unresolved) {
|
||||
memberofInfo = findSymbolMemberof(parser, doclet, astNode, unresolved[1], unresolved[2]);
|
||||
memberof = memberofInfo.memberof;
|
||||
scopePunc = memberofInfo.scopePunc;
|
||||
|
||||
if (memberof) {
|
||||
doclet.name = doclet.name ?
|
||||
memberof + scopePunc + doclet.name :
|
||||
memberof;
|
||||
}
|
||||
}
|
||||
else {
|
||||
memberofInfo = parser.astnodeToMemberof(astNode);
|
||||
if ( Array.isArray(memberofInfo) ) {
|
||||
basename = memberofInfo[1];
|
||||
memberof = memberofInfo[0];
|
||||
}
|
||||
else {
|
||||
memberof = memberofInfo;
|
||||
}
|
||||
}
|
||||
|
||||
// if we found a memberof name, apply it to the doclet
|
||||
if (memberof) {
|
||||
doclet.addTag('memberof', memberof);
|
||||
if (basename) {
|
||||
doclet.name = (doclet.name || '')
|
||||
.replace(new RegExp('^' + escape(basename) + '.'), '');
|
||||
}
|
||||
}
|
||||
// otherwise, add the defaults for a module (if we're currently in a module)
|
||||
else {
|
||||
setModuleScopeMemberOf(doclet);
|
||||
}
|
||||
}
|
||||
|
||||
function newSymbolDoclet(parser, docletSrc, e) {
|
||||
var memberofName = null;
|
||||
var newDoclet = createSymbolDoclet(docletSrc, e);
|
||||
|
||||
// if there's an alias, use that as the symbol name
|
||||
if (newDoclet.alias) {
|
||||
processAlias(parser, newDoclet, e.astnode);
|
||||
}
|
||||
// otherwise, get the symbol name from the code
|
||||
else if (e.code && e.code.name) {
|
||||
newDoclet.addTag('name', e.code.name);
|
||||
if (!newDoclet.memberof) {
|
||||
addSymbolMemberof(parser, newDoclet, e.astnode);
|
||||
}
|
||||
|
||||
newDoclet.postProcess();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the scope to global unless any of the following are true:
|
||||
// a) the doclet is a memberof something
|
||||
// b) the doclet represents a module
|
||||
// c) we're in a module that exports only this symbol
|
||||
if ( !newDoclet.memberof && newDoclet.kind !== 'module' &&
|
||||
(!currentModule || currentModule.longname !== newDoclet.name) ) {
|
||||
newDoclet.scope = SCOPE_NAMES.GLOBAL;
|
||||
}
|
||||
|
||||
addDoclet(parser, newDoclet);
|
||||
e.doclet = newDoclet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach these event handlers to a particular instance of a parser.
|
||||
* @param parser
|
||||
*/
|
||||
exports.attachTo = function(parser) {
|
||||
// Handle JSDoc "virtual comments" that include one of the following:
|
||||
// + A `@name` tag
|
||||
// + Another tag that accepts a name, such as `@function`
|
||||
parser.on('jsdocCommentFound', function(e) {
|
||||
var comments = e.comment.split(/@also\b/g);
|
||||
var newDoclet;
|
||||
|
||||
for (var i = 0, l = comments.length; i < l; i++) {
|
||||
newDoclet = createDoclet(comments[i], e);
|
||||
|
||||
// we're only interested in virtual comments here
|
||||
if (!newDoclet.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the default scope/memberof for a module (if we're in a module)
|
||||
setModuleScopeMemberOf(newDoclet);
|
||||
newDoclet.postProcess();
|
||||
|
||||
// if we _still_ don't have a scope, use the default
|
||||
setDefaultScope(newDoclet);
|
||||
|
||||
addDoclet(parser, newDoclet);
|
||||
|
||||
e.doclet = newDoclet;
|
||||
}
|
||||
});
|
||||
|
||||
// Handle named symbols in the code. May or may not have a JSDoc comment attached.
|
||||
parser.on('symbolFound', function(e) {
|
||||
var comments = e.comment.split(/@also\b/g);
|
||||
|
||||
for (var i = 0, l = comments.length; i < l; i++) {
|
||||
newSymbolDoclet(parser, comments[i], e);
|
||||
}
|
||||
});
|
||||
|
||||
parser.on('fileComplete', function(e) {
|
||||
currentModule = null;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,524 @@
|
||||
/**
|
||||
* @module jsdoc/src/parser
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var events = require('events');
|
||||
var fs = require('jsdoc/fs');
|
||||
var jsdoc = {
|
||||
doclet: require('jsdoc/doclet'),
|
||||
name: require('jsdoc/name'),
|
||||
src: {
|
||||
astnode: require('jsdoc/src/astnode'),
|
||||
syntax: require('jsdoc/src/syntax')
|
||||
},
|
||||
util: {
|
||||
doop: require('jsdoc/util/doop'),
|
||||
runtime: require('jsdoc/util/runtime')
|
||||
}
|
||||
};
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var path = require('jsdoc/path');
|
||||
var util = require('util');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var Syntax = jsdoc.src.syntax.Syntax;
|
||||
|
||||
// TODO: docs
|
||||
var PARSERS = exports.PARSERS = {
|
||||
esprima: 'jsdoc/src/parser',
|
||||
rhino: 'rhino/jsdoc/src/parser'
|
||||
};
|
||||
/*eslint-disable no-script-url */
|
||||
// Prefix for JavaScript strings that were provided in lieu of a filename.
|
||||
var SCHEMA = 'javascript:';
|
||||
/*eslint-enable no-script-url */
|
||||
|
||||
// TODO: docs
|
||||
exports.createParser = function(type) {
|
||||
var modulePath;
|
||||
|
||||
if (!type) {
|
||||
type = jsdoc.util.runtime.isRhino() ? 'rhino' : 'esprima';
|
||||
}
|
||||
|
||||
if (PARSERS[type]) {
|
||||
modulePath = PARSERS[type];
|
||||
}
|
||||
else {
|
||||
modulePath = path.join( path.getResourcePath(path.dirname(type)), path.basename(type) );
|
||||
}
|
||||
|
||||
try {
|
||||
return new ( require(modulePath) ).Parser();
|
||||
}
|
||||
catch (e) {
|
||||
logger.fatal('Unable to create the parser type "' + type + '": ' + e);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
/**
|
||||
* @class
|
||||
* @alias module:jsdoc/src/parser.Parser
|
||||
* @mixes module:events.EventEmitter
|
||||
*
|
||||
* @example <caption>Create a new parser.</caption>
|
||||
* var jsdocParser = new (require('jsdoc/src/parser').Parser)();
|
||||
*/
|
||||
var Parser = exports.Parser = function(builderInstance, visitorInstance, walkerInstance) {
|
||||
this.clear();
|
||||
|
||||
this._astBuilder = builderInstance || new (require('jsdoc/src/astbuilder')).AstBuilder();
|
||||
this._visitor = visitorInstance || new (require('jsdoc/src/visitor')).Visitor(this);
|
||||
this._walker = walkerInstance || new (require('jsdoc/src/walker')).Walker();
|
||||
|
||||
Object.defineProperties(this, {
|
||||
astBuilder: {
|
||||
get: function() {
|
||||
return this._astBuilder;
|
||||
}
|
||||
},
|
||||
visitor: {
|
||||
get: function() {
|
||||
return this._visitor;
|
||||
}
|
||||
},
|
||||
walker: {
|
||||
get: function() {
|
||||
return this._walker;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
util.inherits(Parser, events.EventEmitter);
|
||||
|
||||
// TODO: docs
|
||||
Parser.prototype.clear = function() {
|
||||
this._resultBuffer = [];
|
||||
this.refs = {};
|
||||
this.refs[jsdoc.name.LONGNAMES.GLOBAL] = {};
|
||||
this.refs[jsdoc.name.LONGNAMES.GLOBAL].meta = {};
|
||||
};
|
||||
|
||||
// TODO: update docs
|
||||
/**
|
||||
* Parse the given source files for JSDoc comments.
|
||||
* @param {Array.<string>} sourceFiles An array of filepaths to the JavaScript sources.
|
||||
* @param {string} [encoding=utf8]
|
||||
*
|
||||
* @fires module:jsdoc/src/parser.Parser.parseBegin
|
||||
* @fires module:jsdoc/src/parser.Parser.fileBegin
|
||||
* @fires module:jsdoc/src/parser.Parser.jsdocCommentFound
|
||||
* @fires module:jsdoc/src/parser.Parser.symbolFound
|
||||
* @fires module:jsdoc/src/parser.Parser.newDoclet
|
||||
* @fires module:jsdoc/src/parser.Parser.fileComplete
|
||||
* @fires module:jsdoc/src/parser.Parser.parseComplete
|
||||
*
|
||||
* @example <caption>Parse two source files.</caption>
|
||||
* var myFiles = ['file1.js', 'file2.js'];
|
||||
* var docs = jsdocParser.parse(myFiles);
|
||||
*/
|
||||
Parser.prototype.parse = function(sourceFiles, encoding) {
|
||||
encoding = encoding || global.env.conf.encoding || 'utf8';
|
||||
|
||||
var filename = '';
|
||||
var sourceCode = '';
|
||||
var parsedFiles = [];
|
||||
var e = {};
|
||||
|
||||
if (typeof sourceFiles === 'string') {
|
||||
sourceFiles = [sourceFiles];
|
||||
}
|
||||
|
||||
e.sourcefiles = sourceFiles;
|
||||
logger.debug('Parsing source files: %j', sourceFiles);
|
||||
|
||||
this.emit('parseBegin', e);
|
||||
|
||||
for (var i = 0, l = sourceFiles.length; i < l; i++) {
|
||||
sourceCode = '';
|
||||
|
||||
if (sourceFiles[i].indexOf(SCHEMA) === 0) {
|
||||
sourceCode = sourceFiles[i].substr(SCHEMA.length);
|
||||
filename = '[[string' + i + ']]';
|
||||
}
|
||||
else {
|
||||
filename = sourceFiles[i];
|
||||
try {
|
||||
sourceCode = fs.readFileSync(filename, encoding);
|
||||
}
|
||||
catch(e) {
|
||||
logger.error('Unable to read and parse the source file %s: %s', filename, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (sourceCode.length) {
|
||||
this._parseSourceCode(sourceCode, filename);
|
||||
parsedFiles.push(filename);
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('parseComplete', {
|
||||
sourcefiles: parsedFiles,
|
||||
doclets: this._resultBuffer
|
||||
});
|
||||
logger.debug('Finished parsing source files.');
|
||||
|
||||
return this._resultBuffer;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Parser.prototype.fireProcessingComplete = function(doclets) {
|
||||
this.emit('processingComplete', { doclets: doclets });
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Parser.prototype.results = function() {
|
||||
return this._resultBuffer;
|
||||
};
|
||||
|
||||
// TODO: update docs
|
||||
/**
|
||||
* @param {Object} o The parse result to add to the result buffer.
|
||||
*/
|
||||
Parser.prototype.addResult = function(o) {
|
||||
this._resultBuffer.push(o);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Parser.prototype.addAstNodeVisitor = function(visitor) {
|
||||
this._visitor.addAstNodeVisitor(visitor);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Parser.prototype.getAstNodeVisitors = function() {
|
||||
return this._visitor.getAstNodeVisitors();
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
function pretreat(code) {
|
||||
return code
|
||||
// comment out hashbang at the top of the file, like: #!/usr/bin/env node
|
||||
.replace(/^(\#\![\S \t]+\r?\n)/, '// $1')
|
||||
|
||||
// to support code minifiers that preserve /*! comments, treat /*!* as equivalent to /**
|
||||
.replace(/\/\*\!\*/g, '/**')
|
||||
// merge adjacent doclets
|
||||
.replace(/\*\/\/\*\*+/g, '@also');
|
||||
}
|
||||
|
||||
/** @private */
|
||||
Parser.prototype._parseSourceCode = function(sourceCode, sourceName) {
|
||||
var ast;
|
||||
var globalScope;
|
||||
|
||||
var e = {
|
||||
filename: sourceName
|
||||
};
|
||||
|
||||
this.emit('fileBegin', e);
|
||||
logger.printInfo('Parsing %s ...', sourceName);
|
||||
|
||||
if (!e.defaultPrevented) {
|
||||
e = {
|
||||
filename: sourceName,
|
||||
source: sourceCode
|
||||
};
|
||||
this.emit('beforeParse', e);
|
||||
sourceCode = e.source;
|
||||
sourceName = e.filename;
|
||||
|
||||
sourceCode = pretreat(e.source);
|
||||
|
||||
ast = this._astBuilder.build(sourceCode, sourceName);
|
||||
if (ast) {
|
||||
this._walkAst(ast, this._visitor, sourceName);
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('fileComplete', e);
|
||||
logger.info('complete.');
|
||||
};
|
||||
|
||||
/** @private */
|
||||
Parser.prototype._walkAst = function(ast, visitor, sourceName) {
|
||||
this._walker.recurse(ast, visitor, sourceName);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Parser.prototype.addDocletRef = function(e) {
|
||||
var node;
|
||||
|
||||
if (e && e.code && e.code.node) {
|
||||
node = e.code.node;
|
||||
// allow lookup from value => doclet
|
||||
if (e.doclet) {
|
||||
this.refs[node.nodeId] = e.doclet;
|
||||
}
|
||||
// keep references to undocumented anonymous functions, too, as they might have scoped vars
|
||||
else if (
|
||||
(node.type === Syntax.FunctionDeclaration || node.type === Syntax.FunctionExpression) &&
|
||||
!this.refs[node.nodeId] ) {
|
||||
this.refs[node.nodeId] = {
|
||||
longname: jsdoc.name.LONGNAMES.ANONYMOUS,
|
||||
meta: {
|
||||
code: e.code
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Parser.prototype._getDoclet = function(id) {
|
||||
if ( hasOwnProp.call(this.refs, id) ) {
|
||||
return this.refs[id];
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
/**
|
||||
* @param {string} name - The symbol's longname.
|
||||
* @return {string} The symbol's basename.
|
||||
*/
|
||||
Parser.prototype.getBasename = function(name) {
|
||||
if (name !== undefined) {
|
||||
return name.replace(/^([$a-z_][$a-z_0-9]*).*?$/i, '$1');
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
function definedInScope(doclet, basename) {
|
||||
return !!doclet && !!doclet.meta && !!doclet.meta.vars && !!basename &&
|
||||
hasOwnProp.call(doclet.meta.vars, basename);
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
/**
|
||||
* Given a node, determine what the node is a member of.
|
||||
* @param {node} node
|
||||
* @returns {string} The long name of the node that this is a member of.
|
||||
*/
|
||||
Parser.prototype.astnodeToMemberof = function(node) {
|
||||
var basename;
|
||||
var doclet;
|
||||
var scope;
|
||||
|
||||
var result = '';
|
||||
var type = node.type;
|
||||
|
||||
if ( (type === Syntax.FunctionDeclaration || type === Syntax.FunctionExpression ||
|
||||
type === Syntax.VariableDeclarator) && node.enclosingScope ) {
|
||||
doclet = this._getDoclet(node.enclosingScope.nodeId);
|
||||
|
||||
if (!doclet) {
|
||||
result = jsdoc.name.LONGNAMES.ANONYMOUS + jsdoc.name.SCOPE.PUNC.INNER;
|
||||
}
|
||||
else {
|
||||
result = (doclet.longname || doclet.name) + jsdoc.name.SCOPE.PUNC.INNER;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// check local references for aliases
|
||||
scope = node;
|
||||
basename = this.getBasename( jsdoc.src.astnode.nodeToString(node) );
|
||||
|
||||
// walk up the scope chain until we find the scope in which the node is defined
|
||||
while (scope.enclosingScope) {
|
||||
doclet = this._getDoclet(scope.enclosingScope.nodeId);
|
||||
if ( doclet && definedInScope(doclet, basename) ) {
|
||||
result = [doclet.meta.vars[basename], basename];
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// move up
|
||||
scope = scope.enclosingScope;
|
||||
}
|
||||
}
|
||||
|
||||
// do we know that it's a global?
|
||||
doclet = this.refs[jsdoc.name.LONGNAMES.GLOBAL];
|
||||
if ( doclet && definedInScope(doclet, basename) ) {
|
||||
result = [doclet.meta.vars[basename], basename];
|
||||
}
|
||||
|
||||
// have we seen the node's parent? if so, use that
|
||||
else if (node.parent) {
|
||||
doclet = this._getDoclet(node.parent.nodeId);
|
||||
|
||||
// set the result if we found a doclet. (if we didn't, the AST node may describe a
|
||||
// global symbol.)
|
||||
if (doclet) {
|
||||
result = doclet.longname || doclet.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
/**
|
||||
* Resolve what "this" refers to relative to a node.
|
||||
* @param {node} node - The "this" node
|
||||
* @returns {string} The longname of the enclosing node.
|
||||
*/
|
||||
Parser.prototype.resolveThis = function(node) {
|
||||
var doclet;
|
||||
var result;
|
||||
|
||||
// In general, if there's an enclosing scope, we use the enclosing scope to resolve `this`.
|
||||
// For object properties, we use the node's parent (the object) instead.
|
||||
if (node.type !== Syntax.Property && node.enclosingScope) {
|
||||
doclet = this._getDoclet(node.enclosingScope.nodeId);
|
||||
|
||||
if (!doclet) {
|
||||
result = jsdoc.name.LONGNAMES.ANONYMOUS; // TODO handle global this?
|
||||
}
|
||||
else if (doclet['this']) {
|
||||
result = doclet['this'];
|
||||
}
|
||||
// like: Foo.constructor = function(n) { /** blah */ this.name = n; }
|
||||
else if (doclet.kind === 'function' && doclet.memberof) {
|
||||
result = doclet.memberof;
|
||||
}
|
||||
// like: var foo = function(n) { /** blah */ this.bar = n; }
|
||||
else if ( doclet.kind === 'member' && jsdoc.src.astnode.isAssignment(node) ) {
|
||||
result = doclet.longname || doclet.name;
|
||||
}
|
||||
// walk up to the closest class we can find
|
||||
else if (doclet.kind === 'class' || doclet.kind === 'module') {
|
||||
result = doclet.longname || doclet.name;
|
||||
}
|
||||
else if (node.enclosingScope) {
|
||||
result = this.resolveThis(node.enclosingScope);
|
||||
}
|
||||
}
|
||||
else if (node.parent) {
|
||||
doclet = this.refs[node.parent.nodeId];
|
||||
|
||||
// TODO: is this behavior correct? when do we get here?
|
||||
if (!doclet) {
|
||||
result = ''; // global?
|
||||
}
|
||||
else {
|
||||
result = doclet.longname || doclet.name;
|
||||
}
|
||||
}
|
||||
// TODO: is this behavior correct? when do we get here?
|
||||
else {
|
||||
result = ''; // global?
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given an AST node representing an object property, find the doclets for the parent object or
|
||||
* objects.
|
||||
*
|
||||
* If the object is part of a simple assignment (for example, `var foo = { x: 1 }`), this method
|
||||
* returns a single doclet (in this case, the doclet for `foo`).
|
||||
*
|
||||
* If the object is part of a chained assignment (for example, `var foo = exports.FOO = { x: 1 }`,
|
||||
* this method returns multiple doclets (in this case, the doclets for `foo` and `exports.FOO`).
|
||||
*
|
||||
* @param {Object} node - An AST node representing an object property.
|
||||
* @return {Array.<jsdoc/doclet.Doclet>} An array of doclets for the parent object or objects, or
|
||||
* an empty array if no doclets are found.
|
||||
*/
|
||||
Parser.prototype.resolvePropertyParents = function(node) {
|
||||
var currentAncestor = node.parent;
|
||||
var nextAncestor = currentAncestor ? currentAncestor.parent : null;
|
||||
var doclet;
|
||||
var doclets = [];
|
||||
|
||||
while (currentAncestor) {
|
||||
doclet = this._getDoclet(currentAncestor.nodeId);
|
||||
if (doclet) {
|
||||
doclets.push(doclet);
|
||||
}
|
||||
|
||||
// if the next ancestor is an assignment expression (for example, `exports.FOO` in
|
||||
// `var foo = exports.FOO = { x: 1 }`, keep walking upwards
|
||||
if (nextAncestor && nextAncestor.type === Syntax.AssignmentExpression) {
|
||||
nextAncestor = nextAncestor.parent;
|
||||
currentAncestor = currentAncestor.parent;
|
||||
}
|
||||
// otherwise, we're done
|
||||
else {
|
||||
currentAncestor = null;
|
||||
}
|
||||
}
|
||||
|
||||
return doclets;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
/**
|
||||
* Resolve what function a var is limited to.
|
||||
* @param {astnode} node
|
||||
* @param {string} basename The leftmost name in the long name: in foo.bar.zip the basename is foo.
|
||||
*/
|
||||
Parser.prototype.resolveVar = function(node, basename) {
|
||||
var doclet;
|
||||
var result;
|
||||
var scope = node.enclosingScope;
|
||||
|
||||
// HACK: return an empty string for function declarations so they don't end up in anonymous
|
||||
// scope (see #685 and #693)
|
||||
if (node.type === Syntax.FunctionDeclaration) {
|
||||
result = '';
|
||||
}
|
||||
else if (!scope) {
|
||||
result = ''; // global
|
||||
}
|
||||
else {
|
||||
doclet = this._getDoclet(scope.nodeId);
|
||||
if ( definedInScope(doclet, basename) ) {
|
||||
result = doclet.longname;
|
||||
}
|
||||
else {
|
||||
result = this.resolveVar(scope, basename);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Parser.prototype.resolveEnum = function(e) {
|
||||
var doclets = this.resolvePropertyParents(e.code.node.parent);
|
||||
|
||||
doclets.forEach(function(doclet) {
|
||||
if (doclet && doclet.isEnum) {
|
||||
doclet.properties = doclet.properties || [];
|
||||
|
||||
// members of an enum inherit the enum's type
|
||||
if (doclet.type && !e.doclet.type) {
|
||||
// clone the type to prevent circular refs
|
||||
e.doclet.type = jsdoc.util.doop(doclet.type);
|
||||
}
|
||||
|
||||
delete e.doclet.undocumented;
|
||||
e.doclet.defaultvalue = e.doclet.meta.code.value;
|
||||
|
||||
// add the doclet to the parent's properties
|
||||
doclet.properties.push(e.doclet);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: document other events
|
||||
/**
|
||||
* Fired once for each JSDoc comment in the current source code.
|
||||
* @event jsdocCommentFound
|
||||
* @memberof module:jsdoc/src/parser.Parser
|
||||
* @type {Object}
|
||||
* @property {string} comment The text content of the JSDoc comment
|
||||
* @property {number} lineno The line number associated with the found comment.
|
||||
* @property {string} filename The file name associated with the found comment.
|
||||
*/
|
||||
@@ -0,0 +1,70 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
@module jsdoc/src/scanner
|
||||
@requires module:fs
|
||||
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var fs = require('jsdoc/fs');
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var path = require('jsdoc/path');
|
||||
|
||||
/**
|
||||
@constructor
|
||||
@mixes module:events
|
||||
*/
|
||||
exports.Scanner = function() {};
|
||||
exports.Scanner.prototype = Object.create( require('events').EventEmitter.prototype );
|
||||
|
||||
/**
|
||||
Recursively searches the given searchPaths for js files.
|
||||
@param {Array.<string>} searchPaths
|
||||
@param {number} [depth=1]
|
||||
@fires sourceFileFound
|
||||
*/
|
||||
exports.Scanner.prototype.scan = function(searchPaths, depth, filter) {
|
||||
var currentFile;
|
||||
var isFile;
|
||||
|
||||
var filePaths = [];
|
||||
var pwd = env.pwd;
|
||||
var self = this;
|
||||
|
||||
searchPaths = searchPaths || [];
|
||||
depth = depth || 1;
|
||||
|
||||
searchPaths.forEach(function($) {
|
||||
var filepath = path.resolve( pwd, decodeURIComponent($) );
|
||||
|
||||
try {
|
||||
currentFile = fs.statSync(filepath);
|
||||
}
|
||||
catch (e) {
|
||||
logger.error('Unable to find the source file or directory %s', filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
if ( currentFile.isFile() ) {
|
||||
filePaths.push(filepath);
|
||||
}
|
||||
else {
|
||||
filePaths = filePaths.concat( fs.ls(filepath, depth) );
|
||||
}
|
||||
});
|
||||
|
||||
filePaths = filePaths.filter(function($) {
|
||||
return filter.isIncluded($);
|
||||
});
|
||||
|
||||
filePaths = filePaths.filter(function($) {
|
||||
var e = { fileName: $ };
|
||||
self.emit('sourceFileFound', e);
|
||||
|
||||
return !e.defaultPrevented;
|
||||
});
|
||||
|
||||
return filePaths;
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
'use strict';
|
||||
|
||||
// TODO: docs
|
||||
exports.Syntax = {
|
||||
ArrayExpression: 'ArrayExpression',
|
||||
ArrayPattern: 'ArrayPattern',
|
||||
ArrowFunctionExpression: 'ArrowFunctionExpression',
|
||||
AssignmentExpression: 'AssignmentExpression',
|
||||
BinaryExpression: 'BinaryExpression',
|
||||
BlockStatement: 'BlockStatement',
|
||||
BreakStatement: 'BreakStatement',
|
||||
CallExpression: 'CallExpression',
|
||||
CatchClause: 'CatchClause',
|
||||
ClassBody: 'ClassBody',
|
||||
ClassDeclaration: 'ClassDeclaration',
|
||||
ClassExpression: 'ClassExpression',
|
||||
ComprehensionBlock: 'ComprehensionBlock',
|
||||
ComprehensionExpression: 'ComprehensionExpression',
|
||||
ConditionalExpression: 'ConditionalExpression',
|
||||
ContinueStatement: 'ContinueStatement',
|
||||
DebuggerStatement: 'DebuggerStatement',
|
||||
DoWhileStatement: 'DoWhileStatement',
|
||||
EmptyStatement: 'EmptyStatement',
|
||||
ExportBatchSpecifier: 'ExportBatchSpecifier',
|
||||
ExportDeclaration: 'ExportDeclaration',
|
||||
ExportSpecifier: 'ExportSpecifier',
|
||||
ExpressionStatement: 'ExpressionStatement',
|
||||
ForInStatement: 'ForInStatement',
|
||||
ForOfStatement: 'ForOfStatement',
|
||||
ForStatement: 'ForStatement',
|
||||
FunctionDeclaration: 'FunctionDeclaration',
|
||||
FunctionExpression: 'FunctionExpression',
|
||||
Identifier: 'Identifier',
|
||||
IfStatement: 'IfStatement',
|
||||
ImportDeclaration: 'ImportDeclaration',
|
||||
ImportSpecifier: 'ImportSpecifier',
|
||||
LabeledStatement: 'LabeledStatement',
|
||||
LetStatement: 'LetStatement', // TODO: update Rhino to use VariableDeclaration
|
||||
Literal: 'Literal',
|
||||
LogicalExpression: 'LogicalExpression',
|
||||
MemberExpression: 'MemberExpression',
|
||||
MethodDefinition: 'MethodDefinition',
|
||||
ModuleDeclaration: 'ModuleDeclaration',
|
||||
NewExpression: 'NewExpression',
|
||||
ObjectExpression: 'ObjectExpression',
|
||||
ObjectPattern: 'ObjectPattern',
|
||||
Program: 'Program',
|
||||
Property: 'Property',
|
||||
ReturnStatement: 'ReturnStatement',
|
||||
SequenceExpression: 'SequenceExpression',
|
||||
SpreadElement: 'SpreadElement',
|
||||
SwitchCase: 'SwitchCase',
|
||||
SwitchStatement: 'SwitchStatement',
|
||||
TaggedTemplateExpression: 'TaggedTemplateExpression',
|
||||
TemplateElement: 'TemplateElement',
|
||||
TemplateLiteral: 'TemplateLiteral',
|
||||
ThisExpression: 'ThisExpression',
|
||||
ThrowStatement: 'ThrowStatement',
|
||||
TryStatement: 'TryStatement',
|
||||
UnaryExpression: 'UnaryExpression',
|
||||
UpdateExpression: 'UpdateExpression',
|
||||
VariableDeclaration: 'VariableDeclaration',
|
||||
VariableDeclarator: 'VariableDeclarator',
|
||||
WhileStatement: 'WhileStatement',
|
||||
WithStatement: 'WithStatement',
|
||||
YieldExpression: 'YieldExpression'
|
||||
};
|
||||
@@ -0,0 +1,426 @@
|
||||
/**
|
||||
* @module jsdoc/src/visitor
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
// TODO: consider exporting more stuff so users can override it
|
||||
|
||||
var jsdoc = {
|
||||
doclet: require('jsdoc/doclet'),
|
||||
name: require('jsdoc/name'),
|
||||
src: {
|
||||
astnode: require('jsdoc/src/astnode'),
|
||||
syntax: require('jsdoc/src/syntax')
|
||||
},
|
||||
util: {
|
||||
logger: require('jsdoc/util/logger')
|
||||
}
|
||||
};
|
||||
var util = require('util');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var Syntax = jsdoc.src.syntax.Syntax;
|
||||
|
||||
// TODO: docs
|
||||
function getLeadingComment(node) {
|
||||
var comment = null;
|
||||
var leadingComments = node.leadingComments;
|
||||
|
||||
if (Array.isArray(leadingComments) && leadingComments.length && leadingComments[0].raw) {
|
||||
comment = leadingComments[0].raw;
|
||||
}
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function makeVarsFinisher(scopeDoclet) {
|
||||
return function(e) {
|
||||
// no need to evaluate all things related to scopeDoclet again, just use it
|
||||
if (scopeDoclet && e.doclet && e.doclet.alias) {
|
||||
scopeDoclet.meta.vars[e.code.name] = e.doclet.longname;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* For function parameters that have inline documentation, create a function that will merge the
|
||||
* inline documentation into the function's doclet. If the parameter is already documented in the
|
||||
* function's doclet, the inline documentation will be ignored.
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/src/parser.Parser} parser - The JSDoc parser.
|
||||
* @return {function} A function that merges a parameter's inline documentation into the function's
|
||||
* doclet.
|
||||
*/
|
||||
function makeInlineParamsFinisher(parser) {
|
||||
return function(e) {
|
||||
var documentedParams;
|
||||
var knownParams;
|
||||
var param;
|
||||
var parentDoclet;
|
||||
|
||||
var i = 0;
|
||||
|
||||
if (e.doclet && e.doclet.meta && e.doclet.meta.code && e.doclet.meta.code.node &&
|
||||
e.doclet.meta.code.node.parent) {
|
||||
parentDoclet = parser._getDoclet(e.doclet.meta.code.node.parent.nodeId);
|
||||
}
|
||||
if (!parentDoclet) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we only want to use the doclet if it's param-specific (but not, for example, if it's
|
||||
// a param tagged with `@exports` in an AMD module)
|
||||
if (e.doclet.kind !== 'param') {
|
||||
return;
|
||||
}
|
||||
|
||||
parentDoclet.params = parentDoclet.params || [];
|
||||
documentedParams = parentDoclet.params;
|
||||
knownParams = parentDoclet.meta.code.paramnames;
|
||||
|
||||
while (true) {
|
||||
param = documentedParams[i];
|
||||
|
||||
// is the param already documented? if so, we don't need to use the doclet
|
||||
if (param && param.name === e.doclet.name) {
|
||||
e.doclet.undocumented = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// if we ran out of documented params, or we're at the parameter's actual position,
|
||||
// splice in the param at the current index
|
||||
if ( !param || i === knownParams.indexOf(e.doclet.name) ) {
|
||||
documentedParams.splice(i, 0, {
|
||||
type: e.doclet.type,
|
||||
description: '',
|
||||
name: e.doclet.name
|
||||
});
|
||||
|
||||
// the doclet is no longer needed
|
||||
e.doclet.undocumented = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function SymbolFound(node, filename, extras) {
|
||||
var self = this;
|
||||
extras = extras || {};
|
||||
|
||||
this.id = extras.id || node.nodeId;
|
||||
this.comment = extras.comment || getLeadingComment(node) || '@undocumented';
|
||||
this.lineno = extras.lineno || node.loc.start.line;
|
||||
this.range = extras.range || node.range;
|
||||
this.filename = extras.filename || filename;
|
||||
this.astnode = extras.astnode || node;
|
||||
this.code = extras.code;
|
||||
this.event = extras.event || 'symbolFound';
|
||||
this.finishers = extras.finishers || [];
|
||||
|
||||
// make sure the event includes properties that don't have default values
|
||||
Object.keys(extras).forEach(function(key) {
|
||||
self[key] = extras[key];
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function JsdocCommentFound(comment, filename) {
|
||||
this.comment = comment.raw;
|
||||
this.lineno = comment.loc.start.line;
|
||||
this.filename = filename;
|
||||
this.range = comment.range;
|
||||
|
||||
Object.defineProperty(this, 'event', {
|
||||
value: 'jsdocCommentFound'
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
var Visitor = exports.Visitor = function(parser) {
|
||||
this._parser = parser;
|
||||
|
||||
// Mozilla Parser API node visitors added by plugins
|
||||
this._nodeVisitors = [];
|
||||
// built-in visitors
|
||||
this._visitors = [
|
||||
this.visitNodeComments,
|
||||
this.visitNode
|
||||
];
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Visitor.prototype.addAstNodeVisitor = function(visitor) {
|
||||
this._nodeVisitors.push(visitor);
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Visitor.prototype.removeAstNodeVisitor = function(visitor) {
|
||||
var idx = this._nodeVisitors.indexOf(visitor);
|
||||
if (idx !== -1) {
|
||||
this._nodeVisitors.splice(idx, 1);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Visitor.prototype.getAstNodeVisitors = function() {
|
||||
return this._nodeVisitors;
|
||||
};
|
||||
|
||||
// TODO: docs; visitor signature is (node, parser, filename)
|
||||
Visitor.prototype.visit = function(node, filename) {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
for (i = 0, l = this._visitors.length; i < l; i++) {
|
||||
this._visitors[i].call(this, node, this._parser, filename);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
/**
|
||||
* Verify that a block comment exists and that its leading delimiter does not contain three or more
|
||||
* asterisks.
|
||||
*
|
||||
* @private
|
||||
* @memberof module:jsdoc/src/parser.Parser
|
||||
*/
|
||||
function isValidJsdoc(commentSrc) {
|
||||
return commentSrc && commentSrc.indexOf('/***') !== 0;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function hasJsdocComments(node) {
|
||||
return (node && node.leadingComments && node.leadingComments.length) ||
|
||||
(node && node.trailingComments && node.trailingComments.length);
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function removeCommentDelimiters(comment) {
|
||||
return comment.substring(2, comment.length - 2);
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function updateCommentNode(commentNode, comment) {
|
||||
commentNode.raw = comment;
|
||||
commentNode.value = removeCommentDelimiters(comment);
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
Visitor.prototype.visitNodeComments = function(node, parser, filename) {
|
||||
var comment;
|
||||
var comments;
|
||||
var e;
|
||||
|
||||
var BLOCK_COMMENT = 'Block';
|
||||
|
||||
if ( !hasJsdocComments(node) && (!node.type || node.type !== BLOCK_COMMENT) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
comments = (node.type === BLOCK_COMMENT) ? [node] : [];
|
||||
|
||||
if (node.leadingComments && node.leadingComments.length) {
|
||||
comments = comments.concat( node.leadingComments.slice(0) );
|
||||
}
|
||||
|
||||
if (node.trailingComments && node.trailingComments.length) {
|
||||
comments = comments.concat( node.trailingComments.slice(0) );
|
||||
}
|
||||
|
||||
for (var i = 0, l = comments.length; i < l; i++) {
|
||||
comment = comments[i];
|
||||
if ( isValidJsdoc(comment.raw) ) {
|
||||
e = new JsdocCommentFound(comment, filename);
|
||||
|
||||
parser.emit(e.event, e, parser);
|
||||
|
||||
if (e.comment !== comment.raw) {
|
||||
updateCommentNode(comment, e.comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Visitor.prototype.visitNode = function(node, parser, filename) {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
var e = this.makeSymbolFoundEvent(node, parser, filename);
|
||||
|
||||
if (this._nodeVisitors && this._nodeVisitors.length) {
|
||||
for (i = 0, l = this._nodeVisitors.length; i < l; i++) {
|
||||
this._nodeVisitors[i].visitNode(node, e, parser, filename);
|
||||
if (e.stopPropagation) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!e.preventDefault && e.comment && isValidJsdoc(e.comment)) {
|
||||
parser.emit(e.event, e, parser);
|
||||
}
|
||||
|
||||
// add the node to the parser's lookup table
|
||||
parser.addDocletRef(e);
|
||||
|
||||
for (i = 0, l = e.finishers.length; i < l; i++) {
|
||||
e.finishers[i].call(parser, e);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
// TODO: note that it's essential to call this function before you try to resolve names!
|
||||
function trackVars(parser, node, e) {
|
||||
var enclosingScopeId = node.enclosingScope ? node.enclosingScope.nodeId :
|
||||
jsdoc.name.LONGNAMES.GLOBAL;
|
||||
var doclet = parser.refs[enclosingScopeId];
|
||||
|
||||
if (doclet) {
|
||||
doclet.meta.vars = doclet.meta.vars || {};
|
||||
doclet.meta.vars[e.code.name] = null;
|
||||
e.finishers.push( makeVarsFinisher(doclet) );
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
Visitor.prototype.makeSymbolFoundEvent = function(node, parser, filename) {
|
||||
var logger = jsdoc.util.logger;
|
||||
|
||||
var e;
|
||||
var basename;
|
||||
var i;
|
||||
var l;
|
||||
var parent;
|
||||
|
||||
var extras = {
|
||||
code: jsdoc.src.astnode.getInfo(node)
|
||||
};
|
||||
|
||||
switch (node.type) {
|
||||
// like: i = 0;
|
||||
case Syntax.AssignmentExpression:
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
trackVars(parser, node, e);
|
||||
|
||||
basename = parser.getBasename(e.code.name);
|
||||
if (basename !== 'this') {
|
||||
e.code.funcscope = parser.resolveVar(node, basename);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// like: function foo() {}
|
||||
case Syntax.FunctionDeclaration:
|
||||
// falls through
|
||||
|
||||
// like: var foo = function() {};
|
||||
case Syntax.FunctionExpression:
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
trackVars(parser, node, e);
|
||||
|
||||
basename = parser.getBasename(e.code.name);
|
||||
e.code.funcscope = parser.resolveVar(node, basename);
|
||||
|
||||
break;
|
||||
|
||||
// like "bar" in: function foo(/** @type {string} */ bar) {}
|
||||
// or "module" in: define("MyModule", function(/** @exports MyModule */ module) {}
|
||||
// This is an extremely common type of node; we only care about function parameters with
|
||||
// inline comments. No need to fire an event unless the node is already commented.
|
||||
case Syntax.Identifier:
|
||||
parent = node.parent;
|
||||
if ( node.leadingComments && parent && jsdoc.src.astnode.isFunction(parent) ) {
|
||||
extras.finishers = [makeInlineParamsFinisher(parser)];
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
trackVars(parser, node, e);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// like "obj.prop" in: /** @typedef {string} */ obj.prop;
|
||||
// Closure Compiler uses this pattern extensively for enums.
|
||||
// No need to fire an event unless the node is already commented.
|
||||
case Syntax.MemberExpression:
|
||||
if (node.leadingComments) {
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
// like the object literal in: function Foo = Class.create(/** @lends Foo */ {});
|
||||
case Syntax.ObjectExpression:
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
break;
|
||||
|
||||
// like "bar: true" in: var foo = { bar: true };
|
||||
// like "get bar() {}" in: var foo = { get bar() {} };
|
||||
case Syntax.Property:
|
||||
if ( node.kind !== ('get' || 'set') ) {
|
||||
extras.finishers = [parser.resolveEnum];
|
||||
}
|
||||
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
break;
|
||||
|
||||
// like: var i = 0;
|
||||
case Syntax.VariableDeclarator:
|
||||
e = new SymbolFound(node, filename, extras);
|
||||
|
||||
trackVars(parser, node, e);
|
||||
|
||||
basename = parser.getBasename(e.code.name);
|
||||
|
||||
break;
|
||||
|
||||
// for now, log a warning for all ES6 nodes, since we don't do anything useful with them
|
||||
case Syntax.ArrowFunctionExpression:
|
||||
case Syntax.ClassBody:
|
||||
case Syntax.ClassDeclaration:
|
||||
case Syntax.ClassExpression:
|
||||
case Syntax.ExportBatchSpecifier:
|
||||
case Syntax.ExportDeclaration:
|
||||
case Syntax.ExportSpecifier:
|
||||
case Syntax.ImportDeclaration:
|
||||
case Syntax.ImportSpecifier:
|
||||
case Syntax.MethodDefinition:
|
||||
case Syntax.ModuleDeclaration:
|
||||
case Syntax.SpreadElement:
|
||||
case Syntax.TaggedTemplateExpression:
|
||||
case Syntax.TemplateElement:
|
||||
case Syntax.TemplateLiteral:
|
||||
logger.warn('JSDoc does not currently handle %s nodes. Source file: %s, line %s',
|
||||
node.type, filename, (node.loc && node.loc.start) ? node.loc.start.line : '??');
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// ignore
|
||||
}
|
||||
|
||||
if (!e) {
|
||||
e = {
|
||||
finishers: []
|
||||
};
|
||||
}
|
||||
|
||||
return e;
|
||||
};
|
||||
@@ -0,0 +1,539 @@
|
||||
/**
|
||||
* Traversal utilities for ASTs that are compatible with the Mozilla Parser API. Adapted from
|
||||
* [Acorn](http://marijnhaverbeke.nl/acorn/).
|
||||
*
|
||||
* @module jsdoc/src/walker
|
||||
* @license MIT
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var astnode = require('jsdoc/src/astnode');
|
||||
var doclet = require('jsdoc/doclet');
|
||||
var Syntax = require('jsdoc/src/syntax').Syntax;
|
||||
|
||||
/**
|
||||
* Check whether an AST node creates a new scope.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} node - The AST node to check.
|
||||
* @return {Boolean} Set to `true` if the node creates a new scope, or `false` in all other cases.
|
||||
*/
|
||||
function isScopeNode(node) {
|
||||
// TODO: handle blocks with "let" declarations
|
||||
return node && typeof node === 'object' && (node.type === Syntax.CatchClause ||
|
||||
node.type === Syntax.FunctionDeclaration || node.type === Syntax.FunctionExpression);
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function getCurrentScope(scopes) {
|
||||
return scopes[scopes.length - 1] || null;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
function moveComments(source, target) {
|
||||
if (source.leadingComments) {
|
||||
target.leadingComments = source.leadingComments.slice(0);
|
||||
source.leadingComments = [];
|
||||
}
|
||||
}
|
||||
|
||||
function leafNode(node, parent, state, cb) {}
|
||||
|
||||
// TODO: docs
|
||||
var walkers = exports.walkers = {};
|
||||
|
||||
walkers[Syntax.ArrayExpression] = function arrayExpression(node, parent, state, cb) {
|
||||
for (var i = 0, l = node.elements.length; i < l; i++) {
|
||||
var e = node.elements[i];
|
||||
if (e) {
|
||||
cb(e, node, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: verify correctness
|
||||
walkers[Syntax.ArrayPattern] = function arrayPattern(node, parent, state, cb) {
|
||||
for (var i = 0, l = node.elements.length; i < l; i++) {
|
||||
var e = node.elements[i];
|
||||
// must be an identifier or an expression
|
||||
if (e && e.type !== Syntax.Identifier) {
|
||||
cb(e, node, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ArrowFunctionExpression] =
|
||||
function arrowFunctionExpression(node, parent, state, cb) {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
// used for function declarations, so we include it here
|
||||
if (node.id) {
|
||||
cb(node.id, node, state);
|
||||
}
|
||||
|
||||
for (i = 0, l = node.params.length; i < l; i++) {
|
||||
cb(node.params[i], node, state);
|
||||
}
|
||||
|
||||
for (i = 0, l = node.defaults.length; i < l; i++) {
|
||||
cb(node.defaults[i], node, state);
|
||||
}
|
||||
|
||||
cb(node.body, node, state);
|
||||
|
||||
if (node.rest) {
|
||||
cb(node.rest, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.AssignmentExpression] = function assignmentExpression(node, parent, state, cb) {
|
||||
cb(node.left, node, state);
|
||||
cb(node.right, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.BinaryExpression] = function binaryExpression(node, parent, state, cb) {
|
||||
cb(node.left, node, state);
|
||||
cb(node.right, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.BlockStatement] = function blockStatement(node, parent, state, cb) {
|
||||
for (var i = 0, l = node.body.length; i < l; i++) {
|
||||
cb(node.body[i], node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.BreakStatement] = leafNode;
|
||||
|
||||
walkers[Syntax.CallExpression] = function callExpression(node, parent, state, cb) {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
cb(node.callee, node, state);
|
||||
if (node.arguments) {
|
||||
for (i = 0, l = node.arguments.length; i < l; i++) {
|
||||
cb(node.arguments[i], node, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.CatchClause] = leafNode;
|
||||
|
||||
walkers[Syntax.ClassBody] = walkers[Syntax.BlockStatement];
|
||||
|
||||
walkers[Syntax.ClassDeclaration] = function classDeclaration(node, parent, state, cb) {
|
||||
if (node.id) {
|
||||
cb(node.id, node, state);
|
||||
}
|
||||
|
||||
if (node.superClass) {
|
||||
cb(node.superClass, node, state);
|
||||
}
|
||||
|
||||
if (node.body) {
|
||||
cb(node.body, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ClassExpression] = walkers[Syntax.ClassDeclaration];
|
||||
|
||||
// TODO: verify correctness
|
||||
walkers[Syntax.ComprehensionBlock] = walkers[Syntax.AssignmentExpression];
|
||||
|
||||
// TODO: verify correctness
|
||||
walkers[Syntax.ComprehensionExpression] =
|
||||
function comprehensionExpression(node, parent, state, cb) {
|
||||
cb(node.body, node, state);
|
||||
|
||||
if (node.filter) {
|
||||
cb(node.filter, node, state);
|
||||
}
|
||||
|
||||
for (var i = 0, l = node.blocks.length; i < l; i++) {
|
||||
cb(node.blocks[i], node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ConditionalExpression] = function conditionalExpression(node, parent, state, cb) {
|
||||
cb(node.test, node, state);
|
||||
cb(node.consequent, node, state);
|
||||
cb(node.alternate, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.ContinueStatement] = leafNode;
|
||||
|
||||
walkers[Syntax.DebuggerStatement] = leafNode;
|
||||
|
||||
walkers[Syntax.DoWhileStatement] = function doWhileStatement(node, parent, state, cb) {
|
||||
cb(node.test, node, state);
|
||||
cb(node.body, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.EmptyStatement] = leafNode;
|
||||
|
||||
walkers[Syntax.ExportBatchSpecifier] = leafNode;
|
||||
|
||||
walkers[Syntax.ExportDeclaration] = function exportDeclaration(node, parent, state, cb) {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
if (node.declaration) {
|
||||
for (i = 0, l = node.declaration.length; i < l; i++) {
|
||||
cb(node.declaration[i], node, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.specifiers) {
|
||||
for (i = 0, l = node.specifiers.length; i < l; i++) {
|
||||
cb(node.specifiers[i], node, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.source) {
|
||||
cb(node.source, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ExportSpecifier] = function exportSpecifier(node, parent, state, cb) {
|
||||
if (node.id) {
|
||||
cb(node.id, node, state);
|
||||
}
|
||||
|
||||
if (node.name) {
|
||||
cb(node.name, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ExpressionStatement] = function expressionStatement(node, parent, state, cb) {
|
||||
cb(node.expression, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.ForInStatement] = function forInStatement(node, parent, state, cb) {
|
||||
cb(node.left, node, state);
|
||||
cb(node.right, node, state);
|
||||
cb(node.body, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.ForOfStatement] = walkers[Syntax.ForInStatement];
|
||||
|
||||
walkers[Syntax.ForStatement] = function forStatement(node, parent, state, cb) {
|
||||
if (node.init) {
|
||||
cb(node.init, node, state);
|
||||
}
|
||||
|
||||
if (node.test) {
|
||||
cb(node.test, node, state);
|
||||
}
|
||||
|
||||
if (node.update) {
|
||||
cb(node.update, node, state);
|
||||
}
|
||||
|
||||
cb(node.body, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.FunctionDeclaration] = walkers[Syntax.ArrowFunctionExpression];
|
||||
|
||||
walkers[Syntax.FunctionExpression] = walkers[Syntax.ArrowFunctionExpression];
|
||||
|
||||
walkers[Syntax.Identifier] = leafNode;
|
||||
|
||||
walkers[Syntax.IfStatement] = function ifStatement(node, parent, state, cb) {
|
||||
cb(node.test, node, state);
|
||||
cb(node.consequent, node, state);
|
||||
if (node.alternate) {
|
||||
cb(node.alternate, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ImportDeclaration] = function importDeclaration(node, parent, state, cb) {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
if (node.specifiers) {
|
||||
for (i = 0, l = node.specifiers.length; i < l; i++) {
|
||||
cb(node.specifiers[i], node, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.source) {
|
||||
cb(node.source, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ImportSpecifier] = walkers[Syntax.ExportSpecifier];
|
||||
|
||||
walkers[Syntax.LabeledStatement] = function labeledStatement(node, parent, state, cb) {
|
||||
cb(node.body, node, state);
|
||||
};
|
||||
|
||||
// TODO: add scope info??
|
||||
walkers[Syntax.LetStatement] = function letStatement(node, parent, state, cb) {
|
||||
for (var i = 0, l = node.head.length; i < l; i++) {
|
||||
var head = node.head[i];
|
||||
cb(head.id, node, state);
|
||||
if (head.init) {
|
||||
cb(head.init, node, state);
|
||||
}
|
||||
}
|
||||
|
||||
cb(node.body, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.Literal] = leafNode;
|
||||
|
||||
walkers[Syntax.LogicalExpression] = walkers[Syntax.BinaryExpression];
|
||||
|
||||
walkers[Syntax.MemberExpression] = function memberExpression(node, parent, state, cb) {
|
||||
cb(node.object, node, state);
|
||||
if (node.property) {
|
||||
cb(node.property, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.MethodDefinition] = function methodDefinition(node, parent, state, cb) {
|
||||
if (node.key) {
|
||||
cb(node.key, node, state);
|
||||
}
|
||||
|
||||
if (node.value) {
|
||||
cb(node.value, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ModuleDeclaration] = function moduleDeclaration(node, parent, state, cb) {
|
||||
if (node.id) {
|
||||
cb(node.id, node, state);
|
||||
}
|
||||
|
||||
if (node.source) {
|
||||
cb(node.source, node, state);
|
||||
}
|
||||
|
||||
if (node.body) {
|
||||
cb(node.body, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.NewExpression] = walkers[Syntax.CallExpression];
|
||||
|
||||
walkers[Syntax.ObjectExpression] = function objectExpression(node, parent, state, cb) {
|
||||
for (var i = 0, l = node.properties.length; i < l; i++) {
|
||||
cb(node.properties[i], node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ObjectPattern] = walkers[Syntax.ObjectExpression];
|
||||
|
||||
walkers[Syntax.Program] = walkers[Syntax.BlockStatement];
|
||||
|
||||
walkers[Syntax.Property] = function property(node, parent, state, cb) {
|
||||
// move leading comments from key to property node
|
||||
moveComments(node.key, node);
|
||||
|
||||
cb(node.value, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.ReturnStatement] = function returnStatement(node, parent, state, cb) {
|
||||
if (node.argument) {
|
||||
cb(node.argument, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.SequenceExpression] = function sequenceExpression(node, parent, state, cb) {
|
||||
for (var i = 0, l = node.expressions.length; i < l; i++) {
|
||||
cb(node.expressions[i], node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.SpreadElement] = function spreadElement(node, parent, state, cb) {
|
||||
if (node.argument) {
|
||||
cb(node.argument, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.SwitchCase] = function switchCase(node, parent, state, cb) {
|
||||
if (node.test) {
|
||||
cb(node.test, node, state);
|
||||
}
|
||||
|
||||
for (var i = 0, l = node.consequent.length; i < l; i++) {
|
||||
cb(node.consequent[i], node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.SwitchStatement] = function switchStatement(node, parent, state, cb) {
|
||||
cb(node.discriminant, node, state);
|
||||
|
||||
for (var i = 0, l = node.cases.length; i < l; i++) {
|
||||
cb(node.cases[i], node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.TaggedTemplateExpression] =
|
||||
function taggedTemplateExpression(node, parent, state, cb) {
|
||||
if (node.tag) {
|
||||
cb(node.tag, node, state);
|
||||
}
|
||||
if (node.quasi) {
|
||||
cb(node.quasi, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.TemplateElement] = leafNode;
|
||||
|
||||
walkers[Syntax.TemplateLiteral] = function templateLiteral(node, parent, state, cb) {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
if (node.quasis && node.quasis.length) {
|
||||
for (i = 0, l = node.quasis.length; i < l; i++) {
|
||||
cb(node.quasis[i], node, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.expressions && node.expressions.length) {
|
||||
for (i = 0, l = node.expressions.length; i < l; i++) {
|
||||
cb(node.expressions[i], node, state);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.ThisExpression] = leafNode;
|
||||
|
||||
walkers[Syntax.ThrowStatement] = function throwStatement(node, parent, state, cb) {
|
||||
cb(node.argument, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.TryStatement] = function tryStatement(node, parent, state, cb) {
|
||||
var i;
|
||||
var l;
|
||||
|
||||
cb(node.block, node, state);
|
||||
|
||||
// handle Esprima ASTs, which deviate from the spec a bit
|
||||
if ( node.handlers && Array.isArray(node.handlers) && node.handlers[0] ) {
|
||||
cb(node.handlers[0].body, node, state);
|
||||
}
|
||||
else if (node.handler) {
|
||||
cb(node.handler.body, node, state);
|
||||
}
|
||||
|
||||
if (node.guardedHandlers) {
|
||||
for (i = 0, l = node.guardedHandlers.length; i < l; i++) {
|
||||
cb(node.guardedHandlers[i].body, node, state);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.finalizer) {
|
||||
cb(node.finalizer, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.UnaryExpression] = function unaryExpression(node, parent, state, cb) {
|
||||
cb(node.argument, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.UpdateExpression] = walkers[Syntax.UnaryExpression];
|
||||
|
||||
walkers[Syntax.VariableDeclaration] = function variableDeclaration(node, parent, state, cb) {
|
||||
// move leading comments to first declarator
|
||||
moveComments(node, node.declarations[0]);
|
||||
|
||||
for (var i = 0, l = node.declarations.length; i < l; i++) {
|
||||
cb(node.declarations[i], node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.VariableDeclarator] = function variableDeclarator(node, parent, state, cb) {
|
||||
cb(node.id, node, state);
|
||||
|
||||
if (node.init) {
|
||||
cb(node.init, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
walkers[Syntax.WhileStatement] = walkers[Syntax.DoWhileStatement];
|
||||
|
||||
walkers[Syntax.WithStatement] = function withStatement(node, parent, state, cb) {
|
||||
cb(node.object, node, state);
|
||||
cb(node.body, node, state);
|
||||
};
|
||||
|
||||
walkers[Syntax.YieldExpression] = function(node, parent, state, cb) {
|
||||
if (node.argument) {
|
||||
cb(node.argument, node, state);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a walker that can traverse an AST that is consistent with the Mozilla Parser API.
|
||||
*
|
||||
* @todo docs
|
||||
* @memberof module:jsdoc/src/walker
|
||||
*/
|
||||
var Walker = exports.Walker = function(walkerFuncs) {
|
||||
this._walkers = walkerFuncs || walkers;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
Walker.prototype._recurse = function(filename, ast) {
|
||||
var self = this;
|
||||
var state = {
|
||||
filename: filename,
|
||||
nodes: [],
|
||||
scopes: []
|
||||
};
|
||||
|
||||
function cb(node, parent, state) {
|
||||
var currentScope;
|
||||
|
||||
var isScope = astnode.isScope(node);
|
||||
|
||||
// for efficiency, if the node has a `parent` property, assume that we've already
|
||||
// added the required properties
|
||||
if (typeof node.parent !== 'undefined') {
|
||||
astnode.addNodeProperties(node);
|
||||
}
|
||||
|
||||
node.parent = parent || null;
|
||||
|
||||
currentScope = getCurrentScope(state.scopes);
|
||||
if (currentScope) {
|
||||
node.enclosingScope = currentScope;
|
||||
}
|
||||
|
||||
if (isScope) {
|
||||
state.scopes.push(node);
|
||||
}
|
||||
state.nodes.push(node);
|
||||
|
||||
self._walkers[node.type](node, parent, state, cb);
|
||||
|
||||
if (isScope) {
|
||||
state.scopes.pop();
|
||||
}
|
||||
}
|
||||
|
||||
cb(ast, null, state);
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
// TODO: skip the AST root node to be consistent with Rhino?
|
||||
Walker.prototype.recurse = function(ast, visitor, filename) {
|
||||
var shouldContinue;
|
||||
var state = this._recurse(filename, ast);
|
||||
|
||||
if (visitor) {
|
||||
for (var i = 0, l = state.nodes.length; i < l; i++) {
|
||||
shouldContinue = visitor.visit.call(visitor, state.nodes[i], filename);
|
||||
if (!shouldContinue) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ast;
|
||||
};
|
||||
@@ -0,0 +1,196 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
@overview
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
|
||||
/**
|
||||
Functionality related to JSDoc tags.
|
||||
@module jsdoc/tag
|
||||
@requires jsdoc/tag/dictionary
|
||||
@requires jsdoc/tag/validator
|
||||
@requires jsdoc/tag/type
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var jsdoc = {
|
||||
tag: {
|
||||
dictionary: require('jsdoc/tag/dictionary'),
|
||||
validator: require('jsdoc/tag/validator'),
|
||||
type: require('jsdoc/tag/type')
|
||||
},
|
||||
util: {
|
||||
logger: require('jsdoc/util/logger')
|
||||
}
|
||||
};
|
||||
var path = require('jsdoc/path');
|
||||
var util = require('util');
|
||||
|
||||
// Check whether the text is the same as a symbol name with leading or trailing whitespace. If so,
|
||||
// the whitespace must be preserved, and the text cannot be trimmed.
|
||||
function mustPreserveWhitespace(text, meta) {
|
||||
return meta && meta.code && meta.code.name === text && text.match(/(?:^\s+)|(?:\s+$)/);
|
||||
}
|
||||
|
||||
function trim(text, opts, meta) {
|
||||
var indentMatcher;
|
||||
var match;
|
||||
|
||||
opts = opts || {};
|
||||
text = text || '';
|
||||
|
||||
if ( mustPreserveWhitespace(text, meta) ) {
|
||||
text = util.format('"%s"', text);
|
||||
}
|
||||
else if (opts.keepsWhitespace) {
|
||||
text = text.replace(/^[\n\r\f]+|[\n\r\f]+$/g, '');
|
||||
if (opts.removesIndent) {
|
||||
match = text.match(/^([ \t]+)/);
|
||||
if (match && match[1]) {
|
||||
indentMatcher = new RegExp('^' + match[1], 'gm');
|
||||
text = text.replace(indentMatcher, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
text = text.replace(/^\s+|\s+$/g, '');
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
function addHiddenProperty(obj, propName, propValue) {
|
||||
Object.defineProperty(obj, propName, {
|
||||
value: propValue,
|
||||
writable: true,
|
||||
enumerable: !!global.env.opts.debug,
|
||||
configurable: true
|
||||
});
|
||||
}
|
||||
|
||||
function parseType(tag, tagDef, meta) {
|
||||
try {
|
||||
return jsdoc.tag.type.parse(tag.text, tagDef.canHaveName, tagDef.canHaveType);
|
||||
}
|
||||
catch (e) {
|
||||
jsdoc.util.logger.error(
|
||||
'Unable to parse a tag\'s type expression%s with tag title "%s" and text "%s": %s',
|
||||
meta.filename ? ( ' for source file ' + path.join(meta.path, meta.filename) ) : '',
|
||||
tag.originalTitle,
|
||||
tag.text,
|
||||
e.message
|
||||
);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function processTagText(tag, tagDef, meta) {
|
||||
var tagType;
|
||||
|
||||
if (tagDef.onTagText) {
|
||||
tag.text = tagDef.onTagText(tag.text);
|
||||
}
|
||||
|
||||
if (tagDef.canHaveType || tagDef.canHaveName) {
|
||||
/** The value property represents the result of parsing the tag text. */
|
||||
tag.value = {};
|
||||
|
||||
tagType = parseType(tag, tagDef, meta);
|
||||
|
||||
// It is possible for a tag to *not* have a type but still have
|
||||
// optional or defaultvalue, e.g. '@param [foo]'.
|
||||
// Although tagType.type.length == 0 we should still copy the other properties.
|
||||
if (tagType.type) {
|
||||
if (tagType.type.length) {
|
||||
tag.value.type = {
|
||||
names: tagType.type
|
||||
};
|
||||
addHiddenProperty(tag.value.type, 'parsedType', tagType.parsedType);
|
||||
}
|
||||
|
||||
['optional', 'nullable', 'variable', 'defaultvalue'].forEach(function(prop) {
|
||||
if (typeof tagType[prop] !== 'undefined') {
|
||||
tag.value[prop] = tagType[prop];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (tagType.text && tagType.text.length) {
|
||||
tag.value.description = tagType.text;
|
||||
}
|
||||
|
||||
if (tagDef.canHaveName) {
|
||||
// note the dash is a special case: as a param name it means "no name"
|
||||
if (tagType.name && tagType.name !== '-') { tag.value.name = tagType.name; }
|
||||
}
|
||||
}
|
||||
else {
|
||||
tag.value = tag.text;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the existing tag dictionary with a new tag dictionary.
|
||||
*
|
||||
* Used for testing only. Do not call this method directly. Instead, call
|
||||
* {@link module:jsdoc/doclet._replaceDictionary}, which also updates this module's tag dictionary.
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary.
|
||||
*/
|
||||
exports._replaceDictionary = function _replaceDictionary(dict) {
|
||||
jsdoc.tag.dictionary = dict;
|
||||
};
|
||||
|
||||
/**
|
||||
Constructs a new tag object. Calls the tag validator.
|
||||
@class
|
||||
@classdesc Represents a single doclet tag.
|
||||
@param {string} tagTitle
|
||||
@param {string=} tagBody
|
||||
@param {object=} meta
|
||||
*/
|
||||
var Tag = exports.Tag = function(tagTitle, tagBody, meta) {
|
||||
var tagDef;
|
||||
var trimOpts;
|
||||
|
||||
meta = meta || {};
|
||||
|
||||
this.originalTitle = trim(tagTitle);
|
||||
|
||||
/** The title of the tag (for example, `title` in `@title text`). */
|
||||
this.title = jsdoc.tag.dictionary.normalise(this.originalTitle);
|
||||
|
||||
tagDef = jsdoc.tag.dictionary.lookUp(this.title);
|
||||
trimOpts = {
|
||||
keepsWhitespace: tagDef.keepsWhitespace,
|
||||
removesIndent: tagDef.removesIndent
|
||||
};
|
||||
|
||||
/**
|
||||
* The text following the tag (for example, `text` in `@title text`).
|
||||
*
|
||||
* Whitespace is trimmed from the tag text as follows:
|
||||
*
|
||||
* + If the tag's `keepsWhitespace` option is falsy, all leading and trailing whitespace are
|
||||
* removed.
|
||||
* + If the tag's `keepsWhitespace` option is set to `true`, leading and trailing whitespace are
|
||||
* not trimmed, unless the `removesIndent` option is also enabled.
|
||||
* + If the tag's `removesIndent` option is set to `true`, any indentation that is shared by
|
||||
* every line in the string is removed. This option is ignored unless `keepsWhitespace` is set
|
||||
* to `true`.
|
||||
*
|
||||
* **Note**: If the tag text is the name of a symbol, and the symbol's name includes leading or
|
||||
* trailing whitespace (for example, the property names in `{ ' ': true, ' foo ': false }`),
|
||||
* the tag text is not trimmed. Instead, the tag text is wrapped in double quotes to prevent the
|
||||
* whitespace from being trimmed.
|
||||
*/
|
||||
this.text = trim(tagBody, trimOpts, meta);
|
||||
|
||||
if (this.text) {
|
||||
processTagText(this, tagDef, meta);
|
||||
}
|
||||
|
||||
jsdoc.tag.validator.validate(this, tagDef, meta);
|
||||
};
|
||||
@@ -0,0 +1,119 @@
|
||||
/** @module jsdoc/tag/dictionary */
|
||||
'use strict';
|
||||
|
||||
var definitions = require('jsdoc/tag/dictionary/definitions');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
var dictionary;
|
||||
|
||||
/** @private */
|
||||
function TagDefinition(dictionary, title, etc) {
|
||||
var self = this;
|
||||
etc = etc || {};
|
||||
|
||||
this.title = dictionary.normalise(title);
|
||||
|
||||
Object.defineProperty(this, '_dictionary', {
|
||||
value: dictionary
|
||||
});
|
||||
|
||||
Object.keys(etc).forEach(function(p) {
|
||||
self[p] = etc[p];
|
||||
});
|
||||
}
|
||||
|
||||
/** @private */
|
||||
TagDefinition.prototype.synonym = function(synonymName) {
|
||||
this._dictionary.defineSynonym(this.title, synonymName);
|
||||
return this; // chainable
|
||||
};
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @alias module:jsdoc/tag/dictionary.Dictionary
|
||||
*/
|
||||
function Dictionary() {
|
||||
this._tags = {};
|
||||
this._tagSynonyms = {};
|
||||
// The longnames for `Package` objects include a `package` namespace. There's no `package` tag,
|
||||
// though, so we declare the namespace here.
|
||||
this._namespaces = ['package'];
|
||||
}
|
||||
|
||||
/** @function */
|
||||
Dictionary.prototype._defineNamespace = function defineNamespace(title) {
|
||||
title = this.normalise(title || '');
|
||||
|
||||
if (title && this._namespaces.indexOf(title) === -1) {
|
||||
this._namespaces.push(title);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/** @function */
|
||||
Dictionary.prototype.defineTag = function defineTag(title, opts) {
|
||||
var tagDef = new TagDefinition(this, title, opts);
|
||||
this._tags[tagDef.title] = tagDef;
|
||||
|
||||
if (opts && opts.isNamespace) {
|
||||
this._defineNamespace(tagDef.title);
|
||||
}
|
||||
|
||||
return this._tags[tagDef.title];
|
||||
};
|
||||
|
||||
/** @function */
|
||||
Dictionary.prototype.defineSynonym = function defineSynonym(title, synonym) {
|
||||
this._tagSynonyms[synonym.toLowerCase()] = this.normalise(title);
|
||||
};
|
||||
|
||||
/** @function */
|
||||
Dictionary.prototype.getNamespaces = function getNamespaces() {
|
||||
return this._namespaces.slice(0);
|
||||
};
|
||||
|
||||
/** @function */
|
||||
Dictionary.prototype.lookUp = function lookUp(title) {
|
||||
title = this.normalise(title);
|
||||
|
||||
if ( hasOwnProp.call(this._tags, title) ) {
|
||||
return this._tags[title];
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/** @function */
|
||||
Dictionary.prototype.isNamespace = function isNamespace(kind) {
|
||||
if (kind) {
|
||||
kind = this.normalise(kind);
|
||||
if (this._namespaces.indexOf(kind) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/** @function */
|
||||
Dictionary.prototype.normalise = function normalise(title) {
|
||||
var canonicalName = title.toLowerCase();
|
||||
|
||||
if ( hasOwnProp.call(this._tagSynonyms, canonicalName) ) {
|
||||
return this._tagSynonyms[canonicalName];
|
||||
}
|
||||
|
||||
return canonicalName;
|
||||
};
|
||||
|
||||
// initialize the default dictionary
|
||||
dictionary = new Dictionary();
|
||||
definitions.defineTags(dictionary);
|
||||
|
||||
// make the constructor available for unit-testing purposes
|
||||
dictionary.Dictionary = Dictionary;
|
||||
|
||||
/** @type {module:jsdoc/tag/dictionary.Dictionary} */
|
||||
module.exports = dictionary;
|
||||
@@ -0,0 +1,900 @@
|
||||
/**
|
||||
Define tags that are known in JSDoc.
|
||||
@module jsdoc/tag/dictionary/definitions
|
||||
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
var jsdoc = {
|
||||
name: require('jsdoc/name'),
|
||||
src: {
|
||||
astnode: require('jsdoc/src/astnode')
|
||||
},
|
||||
tag: {
|
||||
type: require('jsdoc/tag/type')
|
||||
},
|
||||
util: {
|
||||
doop: require('jsdoc/util/doop'),
|
||||
logger: require('jsdoc/util/logger')
|
||||
}
|
||||
};
|
||||
var path = require('jsdoc/path');
|
||||
var Syntax = require('jsdoc/src/syntax').Syntax;
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
var DEFINITIONS = {
|
||||
closure: 'closureTags',
|
||||
jsdoc: 'jsdocTags'
|
||||
};
|
||||
var MODULE_NAMESPACE = 'module:';
|
||||
|
||||
// Clone a tag definition, excluding synonyms.
|
||||
function cloneTagDef(tagDef, extras) {
|
||||
var newTagDef = jsdoc.util.doop(tagDef);
|
||||
delete newTagDef.synonyms;
|
||||
|
||||
return (extras ? _.extend(newTagDef, extras) : newTagDef);
|
||||
}
|
||||
|
||||
function getSourcePaths() {
|
||||
var sourcePaths = global.env.sourceFiles.slice(0) || [];
|
||||
|
||||
if (global.env.opts._) {
|
||||
global.env.opts._.forEach(function(sourcePath) {
|
||||
var resolved = path.resolve(global.env.pwd, sourcePath);
|
||||
if (sourcePaths.indexOf(resolved) === -1) {
|
||||
sourcePaths.push(resolved);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return sourcePaths;
|
||||
}
|
||||
|
||||
function filepathMinusPrefix(filepath) {
|
||||
var sourcePaths = getSourcePaths();
|
||||
var commonPrefix = path.commonPrefix(sourcePaths);
|
||||
var result = '';
|
||||
|
||||
if (filepath) {
|
||||
filepath = path.normalize(filepath);
|
||||
// always use forward slashes in the result
|
||||
result = (filepath + path.sep).replace(commonPrefix, '')
|
||||
.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
if (result.length > 0 && result[result.length - 1] !== '/') {
|
||||
result += '/';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function setDocletKindToTitle(doclet, tag) {
|
||||
doclet.addTag( 'kind', tag.title );
|
||||
}
|
||||
|
||||
function setDocletScopeToTitle(doclet, tag) {
|
||||
try {
|
||||
doclet.setScope(tag.title);
|
||||
}
|
||||
catch(e) {
|
||||
jsdoc.util.logger.error(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletNameToValue(doclet, tag) {
|
||||
if (tag.value && tag.value.description) { // as in a long tag
|
||||
doclet.addTag('name', tag.value.description);
|
||||
}
|
||||
else if (tag.text) { // or a short tag
|
||||
doclet.addTag('name', tag.text);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletNameToValueName(doclet, tag) {
|
||||
if (tag.value && tag.value.name) {
|
||||
doclet.addTag('name', tag.value.name);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletDescriptionToValue(doclet, tag) {
|
||||
if (tag.value) {
|
||||
doclet.addTag('description', tag.value);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletTypeToValueType(doclet, tag) {
|
||||
if (tag.value && tag.value.type) {
|
||||
// Add the type names and other type properties (such as `optional`).
|
||||
// Don't overwrite existing properties.
|
||||
Object.keys(tag.value).forEach(function(prop) {
|
||||
if ( !hasOwnProp.call(doclet, prop) ) {
|
||||
doclet[prop] = tag.value[prop];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setNameToFile(doclet, tag) {
|
||||
var name;
|
||||
|
||||
if (doclet.meta.filename) {
|
||||
name = filepathMinusPrefix(doclet.meta.path) + doclet.meta.filename;
|
||||
doclet.addTag('name', name);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletMemberof(doclet, tag) {
|
||||
if (tag.value && tag.value !== '<global>') {
|
||||
doclet.setMemberof(tag.value);
|
||||
}
|
||||
}
|
||||
|
||||
function applyNamespace(docletOrNs, tag) {
|
||||
if (typeof docletOrNs === 'string') { // ns
|
||||
tag.value = jsdoc.name.applyNamespace(tag.value, docletOrNs);
|
||||
}
|
||||
else { // doclet
|
||||
if (!docletOrNs.name) {
|
||||
return; // error?
|
||||
}
|
||||
|
||||
docletOrNs.longname = jsdoc.name.applyNamespace(docletOrNs.name, tag.title);
|
||||
}
|
||||
}
|
||||
|
||||
function setDocletNameToFilename(doclet, tag) {
|
||||
var name = '';
|
||||
|
||||
if (doclet.meta.path) {
|
||||
name = filepathMinusPrefix(doclet.meta.path);
|
||||
}
|
||||
name += doclet.meta.filename.replace(/\.js$/i, '');
|
||||
|
||||
doclet.name = name;
|
||||
}
|
||||
|
||||
function parseTypeText(text) {
|
||||
var tagType = jsdoc.tag.type.parse(text, false, true);
|
||||
return tagType.typeExpression || text;
|
||||
}
|
||||
|
||||
function parseBorrows(doclet, tag) {
|
||||
var m = /^(\S+)(?:\s+as\s+(\S+))?$/.exec(tag.text);
|
||||
if (m) {
|
||||
if (m[1] && m[2]) {
|
||||
return { target: m[1], source: m[2] };
|
||||
}
|
||||
else if (m[1]) {
|
||||
return { target: m[1] };
|
||||
}
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function stripModuleNamespace(name) {
|
||||
return name.replace(/^module\:/, '');
|
||||
}
|
||||
|
||||
function firstWordOf(string) {
|
||||
var m = /^(\S+)/.exec(string);
|
||||
if (m) { return m[1]; }
|
||||
else { return ''; }
|
||||
}
|
||||
|
||||
|
||||
// Core JSDoc tags that are shared with other tag dictionaries.
|
||||
var baseTags = exports.baseTags = {
|
||||
abstract: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
// we call this `virtual` because `abstract` is a reserved word
|
||||
doclet.virtual = true;
|
||||
},
|
||||
synonyms: ['virtual']
|
||||
},
|
||||
access: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
// only valid values are private and protected, public is default
|
||||
if ( /^(private|protected)$/i.test(tag.value) ) {
|
||||
doclet.access = tag.value.toLowerCase();
|
||||
}
|
||||
else {
|
||||
delete doclet.access;
|
||||
}
|
||||
}
|
||||
},
|
||||
alias: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.alias = tag.value;
|
||||
}
|
||||
},
|
||||
// Special separator tag indicating that multiple doclets should be generated for the same
|
||||
// comment. Used internally (and by some JSDoc users, although it's not officially supported).
|
||||
// In the following example, the parser will replace `//**` with an `@also` tag:
|
||||
// /**
|
||||
// * Foo.
|
||||
// *//**
|
||||
// * Foo with a param.
|
||||
// * @param {string} bar
|
||||
// */
|
||||
// function foo(bar) {}
|
||||
also: {
|
||||
onTagged: function(doclet, tag) {
|
||||
// let the parser handle it; we define the tag here to avoid "not a known tag" errors
|
||||
}
|
||||
},
|
||||
augments: {
|
||||
mustHaveValue: true,
|
||||
// Allow augments value to be specified as a normal type, e.g. {Type}
|
||||
onTagText: parseTypeText,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.augment( firstWordOf(tag.value) );
|
||||
},
|
||||
synonyms: ['extends']
|
||||
},
|
||||
author: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.author = doclet.author || [];
|
||||
doclet.author.push(tag.value);
|
||||
}
|
||||
},
|
||||
// this symbol has a member that should use the same docs as another symbol
|
||||
borrows: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
var borrows = parseBorrows(doclet, tag);
|
||||
doclet.borrow(borrows.target, borrows.source);
|
||||
}
|
||||
},
|
||||
class: {
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.addTag('kind', 'class');
|
||||
|
||||
// We treat the @class tag as a @classdesc tag if all of the following are true:
|
||||
// - Both @class and @constructor tags are present
|
||||
// - There's no @classdesc tag
|
||||
// - There are multiple words after @class
|
||||
if (tag.value &&
|
||||
tag.originalTitle === 'class' &&
|
||||
/@construct(?:s|or)\b/i.test(doclet.comment) &&
|
||||
!/@classdesc\b/i.test(doclet.comment) &&
|
||||
tag.value.match(/\S+\s+\S+/)) {
|
||||
doclet.addTag('classdesc', tag.value);
|
||||
}
|
||||
else {
|
||||
setDocletNameToValue(doclet, tag);
|
||||
}
|
||||
},
|
||||
synonyms: ['constructor']
|
||||
},
|
||||
classdesc: {
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.classdesc = tag.value;
|
||||
}
|
||||
},
|
||||
constant: {
|
||||
canHaveType: true,
|
||||
canHaveName: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
setDocletNameToValueName(doclet, tag);
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
},
|
||||
synonyms: ['const']
|
||||
},
|
||||
constructs: {
|
||||
onTagged: function(doclet, tag) {
|
||||
var ownerClassName;
|
||||
if (!tag.value) {
|
||||
// this can be resolved later in the handlers
|
||||
ownerClassName = '{@thisClass}';
|
||||
}
|
||||
else {
|
||||
ownerClassName = firstWordOf(tag.value);
|
||||
}
|
||||
doclet.addTag('alias', ownerClassName);
|
||||
doclet.addTag('kind', 'class');
|
||||
}
|
||||
},
|
||||
copyright: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.copyright = tag.value;
|
||||
}
|
||||
},
|
||||
default: {
|
||||
onTagged: function(doclet, tag) {
|
||||
var type;
|
||||
var value;
|
||||
|
||||
var nodeToString = jsdoc.src.astnode.nodeToString;
|
||||
|
||||
if (tag.value) {
|
||||
doclet.defaultvalue = tag.value;
|
||||
}
|
||||
else if (doclet.meta && doclet.meta.code && doclet.meta.code.value) {
|
||||
type = doclet.meta.code.type;
|
||||
value = doclet.meta.code.value;
|
||||
|
||||
switch (type) {
|
||||
case Syntax.ArrayExpression:
|
||||
doclet.defaultvalue = nodeToString(doclet.meta.code.node);
|
||||
doclet.defaultvaluetype = 'array';
|
||||
break;
|
||||
|
||||
case Syntax.Literal:
|
||||
doclet.defaultvalue = String(value);
|
||||
break;
|
||||
|
||||
case Syntax.ObjectExpression:
|
||||
doclet.defaultvalue = nodeToString(doclet.meta.code.node);
|
||||
doclet.defaultvaluetype = 'object';
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
synonyms: ['defaultvalue']
|
||||
},
|
||||
deprecated: {
|
||||
// value is optional
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.deprecated = tag.value || true;
|
||||
}
|
||||
},
|
||||
description: {
|
||||
mustHaveValue: true,
|
||||
synonyms: ['desc']
|
||||
},
|
||||
enum: {
|
||||
canHaveType: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.kind = 'member';
|
||||
doclet.isEnum = true;
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
event: {
|
||||
isNamespace: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
setDocletNameToValue(doclet, tag);
|
||||
}
|
||||
},
|
||||
example: {
|
||||
keepsWhitespace: true,
|
||||
removesIndent: true,
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.examples = doclet.examples || [];
|
||||
doclet.examples.push(tag.value);
|
||||
}
|
||||
},
|
||||
exports: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
var modName = firstWordOf(tag.value);
|
||||
|
||||
// in case the user wrote something like `/** @exports module:foo */`:
|
||||
doclet.addTag( 'alias', stripModuleNamespace(modName) );
|
||||
doclet.addTag('kind', 'module');
|
||||
}
|
||||
},
|
||||
external: {
|
||||
canHaveType: true,
|
||||
isNamespace: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
if (tag.value && tag.value.type) {
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
doclet.addTag('name', doclet.type.names[0]);
|
||||
}
|
||||
else {
|
||||
setDocletNameToValue(doclet, tag);
|
||||
}
|
||||
},
|
||||
synonyms: ['host']
|
||||
},
|
||||
file: {
|
||||
onTagged: function(doclet, tag) {
|
||||
setNameToFile(doclet, tag);
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
setDocletDescriptionToValue(doclet, tag);
|
||||
|
||||
doclet.preserveName = true;
|
||||
},
|
||||
synonyms: ['fileoverview', 'overview']
|
||||
},
|
||||
fires: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.fires = doclet.fires || [];
|
||||
applyNamespace('event', tag);
|
||||
doclet.fires.push(tag.value);
|
||||
},
|
||||
synonyms: ['emits']
|
||||
},
|
||||
function: {
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
setDocletNameToValue(doclet, tag);
|
||||
},
|
||||
synonyms: ['func', 'method']
|
||||
},
|
||||
global: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.scope = jsdoc.name.SCOPE.NAMES.GLOBAL;
|
||||
delete doclet.memberof;
|
||||
}
|
||||
},
|
||||
ignore: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.ignore = true;
|
||||
}
|
||||
},
|
||||
implements: {
|
||||
mustHaveValue: true,
|
||||
onTagText: parseTypeText,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.implements = doclet.implements || [];
|
||||
doclet.implements.push(tag.value);
|
||||
}
|
||||
},
|
||||
inheritdoc: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
// use an empty string so JSDoc can support `@inheritdoc Foo#bar` in the future
|
||||
doclet.inheritdoc = '';
|
||||
}
|
||||
},
|
||||
inner: {
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletScopeToTitle(doclet, tag);
|
||||
}
|
||||
},
|
||||
instance: {
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletScopeToTitle(doclet, tag);
|
||||
}
|
||||
},
|
||||
interface: {
|
||||
canHaveName: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.addTag('kind', 'interface');
|
||||
if (tag.value) {
|
||||
setDocletNameToValueName(doclet, tag);
|
||||
}
|
||||
}
|
||||
},
|
||||
kind: {
|
||||
mustHaveValue: true
|
||||
},
|
||||
lends: {
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.alias = tag.value || jsdoc.name.LONGNAMES.GLOBAL;
|
||||
doclet.addTag('undocumented');
|
||||
}
|
||||
},
|
||||
license: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.license = tag.value;
|
||||
}
|
||||
},
|
||||
listens: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function (doclet, tag) {
|
||||
doclet.listens = doclet.listens || [];
|
||||
applyNamespace('event', tag);
|
||||
doclet.listens.push(tag.value);
|
||||
}
|
||||
},
|
||||
member: {
|
||||
canHaveType: true,
|
||||
canHaveName: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
setDocletNameToValueName(doclet, tag);
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
},
|
||||
synonyms: ['var']
|
||||
},
|
||||
memberof: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
if (tag.originalTitle === 'memberof!') {
|
||||
doclet.forceMemberof = true;
|
||||
if (tag.value === jsdoc.name.LONGNAMES.GLOBAL) {
|
||||
doclet.addTag('global');
|
||||
delete doclet.memberof;
|
||||
}
|
||||
}
|
||||
setDocletMemberof(doclet, tag);
|
||||
},
|
||||
synonyms: ['memberof!']
|
||||
},
|
||||
// this symbol mixes in all of the specified object's members
|
||||
mixes: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
var source = firstWordOf(tag.value);
|
||||
doclet.mix(source);
|
||||
}
|
||||
},
|
||||
mixin: {
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
setDocletNameToValue(doclet, tag);
|
||||
}
|
||||
},
|
||||
module: {
|
||||
canHaveType: true,
|
||||
isNamespace: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
setDocletNameToValue(doclet, tag);
|
||||
if (!doclet.name) {
|
||||
setDocletNameToFilename(doclet, tag);
|
||||
}
|
||||
// in case the user wrote something like `/** @module module:foo */`:
|
||||
doclet.name = stripModuleNamespace(doclet.name);
|
||||
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
name: {
|
||||
mustHaveValue: true
|
||||
},
|
||||
namespace: {
|
||||
canHaveType: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
setDocletNameToValue(doclet, tag);
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
param: {
|
||||
canHaveType: true,
|
||||
canHaveName: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.params = doclet.params || [];
|
||||
doclet.params.push(tag.value || {});
|
||||
},
|
||||
synonyms: ['arg', 'argument']
|
||||
},
|
||||
private: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.access = 'private';
|
||||
}
|
||||
},
|
||||
property: {
|
||||
mustHaveValue: true,
|
||||
canHaveType: true,
|
||||
canHaveName: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.properties = doclet.properties || [];
|
||||
doclet.properties.push(tag.value);
|
||||
},
|
||||
synonyms: ['prop']
|
||||
},
|
||||
protected: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.access = 'protected';
|
||||
}
|
||||
},
|
||||
public: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
delete doclet.access; // public is default
|
||||
}
|
||||
},
|
||||
readonly: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.readonly = true;
|
||||
}
|
||||
},
|
||||
requires: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
var requiresName;
|
||||
|
||||
// inline link tags are passed through as-is so that `@requires {@link foo}` works
|
||||
if ( require('jsdoc/tag/inline').isInlineTag(tag.value, 'link\\S*') ) {
|
||||
requiresName = tag.value;
|
||||
}
|
||||
// otherwise, assume it's a module
|
||||
else {
|
||||
requiresName = firstWordOf(tag.value);
|
||||
if (requiresName.indexOf(MODULE_NAMESPACE) !== 0) {
|
||||
requiresName = MODULE_NAMESPACE + requiresName;
|
||||
}
|
||||
}
|
||||
|
||||
doclet.requires = doclet.requires || [];
|
||||
doclet.requires.push(requiresName);
|
||||
}
|
||||
},
|
||||
returns: {
|
||||
mustHaveValue: true,
|
||||
canHaveType: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.returns = doclet.returns || [];
|
||||
doclet.returns.push(tag.value);
|
||||
},
|
||||
synonyms: ['return']
|
||||
},
|
||||
see: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.see = doclet.see || [];
|
||||
doclet.see.push(tag.value);
|
||||
}
|
||||
},
|
||||
since: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.since = tag.value;
|
||||
}
|
||||
},
|
||||
static: {
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletScopeToTitle(doclet, tag);
|
||||
}
|
||||
},
|
||||
summary: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.summary = tag.value;
|
||||
}
|
||||
},
|
||||
'this': {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet['this'] = firstWordOf(tag.value);
|
||||
}
|
||||
},
|
||||
todo: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.todo = doclet.todo || [];
|
||||
doclet.todo.push(tag.value);
|
||||
}
|
||||
},
|
||||
platforms: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.platforms = doclet.platforms || [];
|
||||
doclet.platforms = doclet.platforms.concat(tag.value.split(' '));
|
||||
}
|
||||
},
|
||||
throws: {
|
||||
mustHaveValue: true,
|
||||
canHaveType: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.exceptions = doclet.exceptions || [];
|
||||
doclet.exceptions.push(tag.value);
|
||||
},
|
||||
synonyms: ['exception']
|
||||
},
|
||||
tutorial: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.tutorials = doclet.tutorials || [];
|
||||
doclet.tutorials.push(tag.value);
|
||||
}
|
||||
},
|
||||
type: {
|
||||
mustHaveValue: true,
|
||||
mustNotHaveDescription: true,
|
||||
canHaveType: true,
|
||||
onTagText: function(text) {
|
||||
var closeIdx;
|
||||
var openIdx;
|
||||
|
||||
var OPEN_BRACE = '{';
|
||||
var CLOSE_BRACE = '}';
|
||||
|
||||
// remove line breaks
|
||||
text = text.replace(/[\f\n\r]/g, '');
|
||||
|
||||
// Text must be a type expression; for backwards compatibility, we add braces if they're
|
||||
// missing. But do NOT add braces to things like `@type {string} some pointless text`.
|
||||
openIdx = text.indexOf(OPEN_BRACE);
|
||||
closeIdx = text.indexOf(CLOSE_BRACE);
|
||||
|
||||
// a type expression is at least one character long
|
||||
if ( openIdx !== 0 || closeIdx <= openIdx + 1) {
|
||||
text = OPEN_BRACE + text + CLOSE_BRACE;
|
||||
}
|
||||
|
||||
return text;
|
||||
},
|
||||
onTagged: function(doclet, tag) {
|
||||
if (tag.value && tag.value.type) {
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
|
||||
// for backwards compatibility, we allow @type for functions to imply return type
|
||||
if (doclet.kind === 'function') {
|
||||
doclet.addTag('returns', tag.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
typedef: {
|
||||
canHaveType: true,
|
||||
canHaveName: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
setDocletKindToTitle(doclet, tag);
|
||||
|
||||
if (tag.value) {
|
||||
setDocletNameToValueName(doclet, tag);
|
||||
|
||||
// callbacks are always type {function}
|
||||
if (tag.originalTitle === 'callback') {
|
||||
doclet.type = {
|
||||
names: [
|
||||
'function'
|
||||
]
|
||||
};
|
||||
}
|
||||
else {
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
}
|
||||
},
|
||||
synonyms: ['callback']
|
||||
},
|
||||
undocumented: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.undocumented = true;
|
||||
doclet.comment = '';
|
||||
}
|
||||
},
|
||||
variation: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.variation = tag.value;
|
||||
}
|
||||
},
|
||||
version: {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.version = tag.value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Tag dictionary for JSDoc.
|
||||
var jsdocTags = exports.jsdocTags = baseTags;
|
||||
|
||||
// Tag dictionary for Google Closure Compiler.
|
||||
var closureTags = exports.closureTags = {
|
||||
const: cloneTagDef(baseTags.constant),
|
||||
constructor: cloneTagDef(baseTags.class),
|
||||
deprecated: cloneTagDef(baseTags.deprecated),
|
||||
enum: cloneTagDef(baseTags.enum),
|
||||
extends: cloneTagDef(baseTags.augments),
|
||||
final: cloneTagDef(baseTags.readonly),
|
||||
implements: cloneTagDef(baseTags.implements),
|
||||
inheritdoc: cloneTagDef(baseTags.inheritdoc),
|
||||
interface: cloneTagDef(baseTags.interface, {
|
||||
canHaveName: false,
|
||||
mustNotHaveValue: true
|
||||
}),
|
||||
lends: cloneTagDef(baseTags.lends),
|
||||
license: cloneTagDef(baseTags.license),
|
||||
// Closure Compiler only
|
||||
override: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.override = true;
|
||||
}
|
||||
},
|
||||
param: cloneTagDef(baseTags.param),
|
||||
private: {
|
||||
canHaveType: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.access = 'private';
|
||||
|
||||
if (tag.value && tag.value.type) {
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
}
|
||||
},
|
||||
protected: {
|
||||
canHaveType: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
doclet.access = 'protected';
|
||||
|
||||
if (tag.value && tag.value.type) {
|
||||
setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
}
|
||||
},
|
||||
return: cloneTagDef(baseTags.returns),
|
||||
'this': cloneTagDef(baseTags['this']),
|
||||
throws: cloneTagDef(baseTags.throws),
|
||||
type: cloneTagDef(baseTags.type, {
|
||||
mustNotHaveDescription: false
|
||||
}),
|
||||
typedef: cloneTagDef(baseTags.typedef)
|
||||
};
|
||||
|
||||
function addTagDefinitions(dictionary, tagDefs) {
|
||||
Object.keys(tagDefs).forEach(function(tagName) {
|
||||
var tagDef;
|
||||
|
||||
tagDef = tagDefs[tagName];
|
||||
dictionary.defineTag(tagName, tagDef);
|
||||
|
||||
if (tagDef.synonyms) {
|
||||
tagDef.synonyms.forEach(function(synonym) {
|
||||
dictionary.defineSynonym(tagName, synonym);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the given dictionary with the appropriate JSDoc tag definitions.
|
||||
*
|
||||
* If the `tagDefinitions` parameter is omitted, JSDoc uses its configuration settings to decide
|
||||
* which tags to add to the dictionary.
|
||||
*
|
||||
* If the `tagDefinitions` parameter is included, JSDoc adds only the tag definitions from the
|
||||
* `tagDefinitions` object. The configuration settings are ignored.
|
||||
*
|
||||
* @param {module:jsdoc/tag/dictionary} dictionary
|
||||
* @param {Object} [tagDefinitions] - A dictionary whose values define the rules for a JSDoc tag.
|
||||
*/
|
||||
exports.defineTags = function(dictionary, tagDefinitions) {
|
||||
var dictionaries;
|
||||
|
||||
if (!tagDefinitions) {
|
||||
dictionaries = global.env.conf.tags.dictionaries;
|
||||
|
||||
if (!dictionaries) {
|
||||
jsdoc.util.logger.error('The configuration setting "tags.dictionaries" is undefined. ' +
|
||||
'Unable to load tag definitions.');
|
||||
return;
|
||||
}
|
||||
else {
|
||||
dictionaries = dictionaries.slice(0).reverse();
|
||||
}
|
||||
|
||||
dictionaries.forEach(function(dictName) {
|
||||
var tagDefs = exports[DEFINITIONS[dictName]];
|
||||
|
||||
if (!tagDefs) {
|
||||
jsdoc.util.logger.error('The configuration setting "tags.dictionaries" contains ' +
|
||||
'the unknown dictionary name %s. Ignoring the dictionary.', dictName);
|
||||
return;
|
||||
}
|
||||
|
||||
addTagDefinitions(dictionary, tagDefs);
|
||||
});
|
||||
}
|
||||
else {
|
||||
addTagDefinitions(dictionary, tagDefinitions);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,141 @@
|
||||
/**
|
||||
* @module jsdoc/tag/inline
|
||||
*
|
||||
* @author Jeff Williams <jeffrey.l.williams@gmail.com>
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Information about an inline tag that was found within a string.
|
||||
*
|
||||
* @typedef {Object} InlineTagInfo
|
||||
* @memberof module:jsdoc/tag/inline
|
||||
* @property {?string} completeTag - The entire inline tag, including its enclosing braces.
|
||||
* @property {?string} tag - The tag whose text was found.
|
||||
* @property {?string} text - The tag text that was found.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Information about the results of replacing inline tags within a string.
|
||||
*
|
||||
* @typedef {Object} InlineTagResult
|
||||
* @memberof module:jsdoc/tag/inline
|
||||
* @property {Array.<module:jsdoc/tag/inline.InlineTagInfo>} tags - The inline tags that were found.
|
||||
* @property {string} newString - The updated text string after extracting or replacing the inline
|
||||
* tags.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Text-replacing function for strings that contain an inline tag.
|
||||
*
|
||||
* @callback InlineTagReplacer
|
||||
* @memberof module:jsdoc/tag/inline
|
||||
* @param {string} string - The complete string containing the inline tag.
|
||||
* @param {module:jsdoc/tag/inline.InlineTagInfo} tagInfo - Information about the inline tag.
|
||||
* @return {string} An updated version of the complete string.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a regexp that matches a specific inline tag, or all inline tags.
|
||||
*
|
||||
* @private
|
||||
* @memberof module:jsdoc/tag/inline
|
||||
* @param {?string} tagName - The inline tag that the regexp will match. May contain regexp
|
||||
* characters. If omitted, matches any string.
|
||||
* @param {?string} prefix - A prefix for the regexp. Defaults to an empty string.
|
||||
* @param {?string} suffix - A suffix for the regexp. Defaults to an empty string.
|
||||
* @returns {RegExp} A regular expression that matches the requested inline tag.
|
||||
*/
|
||||
function regExpFactory(tagName, prefix, suffix) {
|
||||
tagName = tagName || '\\S+';
|
||||
prefix = prefix || '';
|
||||
suffix = suffix || '';
|
||||
|
||||
return new RegExp(prefix + '\\{@' + tagName + '\\s+((?:.|\n)+?)\\}' + suffix, 'gi');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a string is an inline tag. You can check for a specific inline tag or for any valid
|
||||
* inline tag.
|
||||
*
|
||||
* @param {string} string - The string to check.
|
||||
* @param {?string} tagName - The inline tag to match. May contain regexp characters. If this
|
||||
* parameter is omitted, this method returns `true` for any valid inline tag.
|
||||
* @returns {boolean} Set to `true` if the string is a valid inline tag or `false` in all other
|
||||
* cases.
|
||||
*/
|
||||
exports.isInlineTag = function(string, tagName) {
|
||||
return regExpFactory(tagName, '^', '$').test(string);
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace all instances of multiple inline tags with other text.
|
||||
*
|
||||
* @param {string} string - The string in which to replace the inline tags.
|
||||
* @param {Object} replacers - The functions that are used to replace text in the string. The keys
|
||||
* must contain tag names (for example, `link`), and the values must contain functions with the
|
||||
* type {@link module:jsdoc/tag/inline.InlineTagReplacer}.
|
||||
* @return {module:jsdoc/tag/inline.InlineTagResult} The updated string, as well as information
|
||||
* about the inline tags that were found.
|
||||
*/
|
||||
exports.replaceInlineTags = function(string, replacers) {
|
||||
var tagInfo = [];
|
||||
|
||||
function replaceMatch(replacer, tag, match, text) {
|
||||
var matchedTag = {
|
||||
completeTag: match,
|
||||
tag: tag,
|
||||
text: text
|
||||
};
|
||||
tagInfo.push(matchedTag);
|
||||
|
||||
return replacer(string, matchedTag);
|
||||
}
|
||||
|
||||
string = string || '';
|
||||
Object.keys(replacers).forEach(function(replacer) {
|
||||
var tagRegExp = regExpFactory(replacer);
|
||||
var matches;
|
||||
// call the replacer once for each match
|
||||
while ( (matches = tagRegExp.exec(string)) !== null ) {
|
||||
string = replaceMatch(replacers[replacer], replacer, matches[0], matches[1]);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
tags: tagInfo,
|
||||
newString: string.trim()
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace all instances of an inline tag with other text.
|
||||
*
|
||||
* @param {string} string - The string in which to replace the inline tag.
|
||||
* @param {string} tag - The name of the inline tag to replace.
|
||||
* @param {module:jsdoc/tag/inline.InlineTagReplacer} replacer - The function that is used to
|
||||
* replace text in the string.
|
||||
* @return {module:jsdoc/tag/inline.InlineTagResult} The updated string, as well as information
|
||||
* about the inline tags that were found.
|
||||
*/
|
||||
exports.replaceInlineTag = function(string, tag, replacer) {
|
||||
var replacers = {};
|
||||
replacers[tag] = replacer;
|
||||
|
||||
return exports.replaceInlineTags(string, replacers);
|
||||
};
|
||||
|
||||
/**
|
||||
* Extract inline tags from a string, replacing them with an empty string.
|
||||
*
|
||||
* @param {string} string - The string from which to extract text.
|
||||
* @param {?string} tag - The inline tag to extract.
|
||||
* @return {module:jsdoc/tag/inline.InlineTagResult} The updated string, as well as information
|
||||
* about the inline tags that were found.
|
||||
*/
|
||||
exports.extractInlineTag = function(string, tag) {
|
||||
return exports.replaceInlineTag(string, tag, function(str, tagInfo) {
|
||||
return str.replace(tagInfo.completeTag, '');
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,308 @@
|
||||
/**
|
||||
* @module jsdoc/tag/type
|
||||
*
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @author Jeff Williams <jeffrey.l.williams@gmail.com>
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var catharsis = require('catharsis');
|
||||
var jsdoc = {
|
||||
name: require('jsdoc/name'),
|
||||
tag: {
|
||||
inline: require('jsdoc/tag/inline')
|
||||
}
|
||||
};
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* Information about a type expression extracted from tag text.
|
||||
*
|
||||
* @typedef TypeExpressionInfo
|
||||
* @memberof module:jsdoc/tag/type
|
||||
* @property {string} expression - The type expression.
|
||||
* @property {string} text - The updated tag text.
|
||||
*/
|
||||
|
||||
/** @private */
|
||||
function unescapeBraces(text) {
|
||||
return text.replace(/\\\{/g, '{')
|
||||
.replace(/\\\}/g, '}');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a type expression from the tag text.
|
||||
*
|
||||
* @private
|
||||
* @param {string} string - The tag text.
|
||||
* @return {module:jsdoc/tag/type.TypeExpressionInfo} The type expression and updated tag text.
|
||||
*/
|
||||
function extractTypeExpression(string) {
|
||||
var completeExpression;
|
||||
var count = 0;
|
||||
var position = 0;
|
||||
var expression = '';
|
||||
var startIndex = string.search(/\{[^@]/);
|
||||
var textStartIndex;
|
||||
|
||||
if (startIndex !== -1) {
|
||||
// advance to the first character in the type expression
|
||||
position = textStartIndex = startIndex + 1;
|
||||
count++;
|
||||
|
||||
while (position < string.length) {
|
||||
switch (string[position]) {
|
||||
case '\\':
|
||||
// backslash is an escape character, so skip the next character
|
||||
position++;
|
||||
break;
|
||||
case '{':
|
||||
count++;
|
||||
break;
|
||||
case '}':
|
||||
count--;
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
}
|
||||
|
||||
if (count === 0) {
|
||||
completeExpression = string.slice(startIndex, position + 1);
|
||||
expression = string.slice(textStartIndex, position).trim();
|
||||
break;
|
||||
}
|
||||
|
||||
position++;
|
||||
}
|
||||
}
|
||||
|
||||
string = completeExpression ? string.replace(completeExpression, '') : string;
|
||||
|
||||
return {
|
||||
expression: unescapeBraces(expression),
|
||||
newString: string.trim()
|
||||
};
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function getTagInfo(tagValue, canHaveName, canHaveType) {
|
||||
var name = '';
|
||||
var typeExpression = '';
|
||||
var text = tagValue;
|
||||
var expressionAndText;
|
||||
var nameAndDescription;
|
||||
var typeOverride;
|
||||
|
||||
if (canHaveType) {
|
||||
expressionAndText = extractTypeExpression(text);
|
||||
typeExpression = expressionAndText.expression;
|
||||
text = expressionAndText.newString;
|
||||
}
|
||||
|
||||
if (canHaveName) {
|
||||
nameAndDescription = jsdoc.name.splitName(text);
|
||||
name = nameAndDescription.name;
|
||||
text = nameAndDescription.description;
|
||||
}
|
||||
|
||||
// an inline @type tag, like {@type Foo}, overrides the type expression
|
||||
if (canHaveType) {
|
||||
typeOverride = jsdoc.tag.inline.extractInlineTag(text, 'type');
|
||||
if (typeOverride.tags && typeOverride.tags[0]) {
|
||||
typeExpression = typeOverride.tags[0].text;
|
||||
}
|
||||
text = typeOverride.newString;
|
||||
}
|
||||
|
||||
return {
|
||||
name: name,
|
||||
typeExpression: typeExpression,
|
||||
text: text
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Information provided in a JSDoc tag.
|
||||
*
|
||||
* @typedef {Object} TagInfo
|
||||
* @memberof module:jsdoc/tag/type
|
||||
* @property {string} TagInfo.defaultvalue - The default value of the member.
|
||||
* @property {string} TagInfo.name - The name of the member (for example, `myParamName`).
|
||||
* @property {boolean} TagInfo.nullable - Indicates whether the member can be set to `null` or
|
||||
* `undefined`.
|
||||
* @property {boolean} TagInfo.optional - Indicates whether the member is optional.
|
||||
* @property {string} TagInfo.text - Descriptive text for the member (for example, `The user's email
|
||||
* address.`).
|
||||
* @property {Array.<string>} TagInfo.type - The type or types that the member can contain (for
|
||||
* example, `string` or `MyNamespace.MyClass`).
|
||||
* @property {string} TagInfo.typeExpression - The type expression that was parsed to identify the
|
||||
* types.
|
||||
* @property {boolean} TagInfo.variable - Indicates whether the number of members that are provided
|
||||
* can vary (for example, in a function that accepts any number of parameters).
|
||||
*/
|
||||
|
||||
// TODO: move to module:jsdoc/name?
|
||||
/**
|
||||
* Extract JSDoc-style type information from the name specified in the tag info, including the
|
||||
* member name; whether the member is optional; and the default value of the member.
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/tag/type.TagInfo} tagInfo - Information contained in the tag.
|
||||
* @return {module:jsdoc/tag/type.TagInfo} Updated information from the tag.
|
||||
*/
|
||||
function parseName(tagInfo) {
|
||||
// like '[foo]' or '[ foo ]' or '[foo=bar]' or '[ foo=bar ]' or '[ foo = bar ]'
|
||||
// or 'foo=bar' or 'foo = bar'
|
||||
if ( /^(\[)?\s*(.+?)\s*(\])?$/.test(tagInfo.name) ) {
|
||||
tagInfo.name = RegExp.$2;
|
||||
// were the "optional" brackets present?
|
||||
if (RegExp.$1 && RegExp.$3) {
|
||||
tagInfo.optional = true;
|
||||
}
|
||||
|
||||
// like 'foo=bar' or 'foo = bar'
|
||||
if ( /^(.+?)\s*=\s*(.+)$/.test(tagInfo.name) ) {
|
||||
tagInfo.name = RegExp.$1;
|
||||
tagInfo.defaultvalue = RegExp.$2;
|
||||
}
|
||||
}
|
||||
|
||||
return tagInfo;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function getTypeStrings(parsedType, isOutermostType) {
|
||||
var applications;
|
||||
var typeString;
|
||||
|
||||
var types = [];
|
||||
|
||||
var TYPES = catharsis.Types;
|
||||
|
||||
switch (parsedType.type) {
|
||||
case TYPES.AllLiteral:
|
||||
types.push('*');
|
||||
break;
|
||||
case TYPES.FunctionType:
|
||||
types.push('function');
|
||||
break;
|
||||
case TYPES.NameExpression:
|
||||
types.push(parsedType.name);
|
||||
break;
|
||||
case TYPES.NullLiteral:
|
||||
types.push('null');
|
||||
break;
|
||||
case TYPES.RecordType:
|
||||
types.push('Object');
|
||||
break;
|
||||
case TYPES.TypeApplication:
|
||||
// if this is the outermost type, we strip the modifiers; otherwise, we keep them
|
||||
if (isOutermostType) {
|
||||
applications = parsedType.applications.map(function(application) {
|
||||
return catharsis.stringify(application);
|
||||
}).join(', ');
|
||||
typeString = util.format( '%s.<%s>', getTypeStrings(parsedType.expression),
|
||||
applications );
|
||||
|
||||
types.push(typeString);
|
||||
}
|
||||
else {
|
||||
types.push( catharsis.stringify(parsedType) );
|
||||
}
|
||||
break;
|
||||
case TYPES.TypeUnion:
|
||||
parsedType.elements.forEach(function(element) {
|
||||
types = types.concat( getTypeStrings(element) );
|
||||
});
|
||||
break;
|
||||
case TYPES.UndefinedLiteral:
|
||||
types.push('undefined');
|
||||
break;
|
||||
case TYPES.UnknownLiteral:
|
||||
types.push('?');
|
||||
break;
|
||||
default:
|
||||
// this shouldn't happen
|
||||
throw new Error( util.format('unrecognized type %s in parsed type: %j', parsedType.type,
|
||||
parsedType) );
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract JSDoc-style and Closure Compiler-style type information from the type expression
|
||||
* specified in the tag info.
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/tag/type.TagInfo} tagInfo - Information contained in the tag.
|
||||
* @return {module:jsdoc/tag/type.TagInfo} Updated information from the tag.
|
||||
*/
|
||||
function parseTypeExpression(tagInfo) {
|
||||
var errorMessage;
|
||||
var parsedType;
|
||||
|
||||
// don't try to parse empty type expressions
|
||||
if (!tagInfo.typeExpression) {
|
||||
return tagInfo;
|
||||
}
|
||||
|
||||
try {
|
||||
parsedType = catharsis.parse(tagInfo.typeExpression, {jsdoc: true});
|
||||
}
|
||||
catch (e) {
|
||||
// always re-throw so the caller has a chance to report which file was bad
|
||||
throw new Error( util.format('Invalid type expression "%s": %s', tagInfo.typeExpression,
|
||||
e.message) );
|
||||
}
|
||||
|
||||
tagInfo.type = tagInfo.type.concat( getTypeStrings(parsedType, true) );
|
||||
tagInfo.parsedType = parsedType;
|
||||
|
||||
// Catharsis and JSDoc use the same names for 'optional' and 'nullable'...
|
||||
['optional', 'nullable'].forEach(function(key) {
|
||||
if (parsedType[key] !== null && parsedType[key] !== undefined) {
|
||||
tagInfo[key] = parsedType[key];
|
||||
}
|
||||
});
|
||||
|
||||
// ...but not 'variable'.
|
||||
if (parsedType.repeatable !== null && parsedType.repeatable !== undefined) {
|
||||
tagInfo.variable = parsedType.repeatable;
|
||||
}
|
||||
|
||||
return tagInfo;
|
||||
}
|
||||
|
||||
// TODO: allow users to add/remove type parsers (perhaps via plugins)
|
||||
var typeParsers = [parseName, parseTypeExpression];
|
||||
|
||||
/**
|
||||
* Parse the value of a JSDoc tag.
|
||||
*
|
||||
* @param {string} tagValue - The value of the tag. For example, the tag `@param {string} name` has
|
||||
* a value of `{string} name`.
|
||||
* @param {boolean} canHaveName - Indicates whether the value can include a symbol name.
|
||||
* @param {boolean} canHaveType - Indicates whether the value can include a type expression that
|
||||
* describes the symbol.
|
||||
* @return {module:jsdoc/tag/type.TagInfo} Information obtained from the tag.
|
||||
* @throws {Error} Thrown if a type expression cannot be parsed.
|
||||
*/
|
||||
exports.parse = function(tagValue, canHaveName, canHaveType) {
|
||||
if (typeof tagValue !== 'string') { tagValue = ''; }
|
||||
|
||||
var tagInfo = getTagInfo(tagValue, canHaveName, canHaveType);
|
||||
tagInfo.type = tagInfo.type || [];
|
||||
|
||||
typeParsers.forEach(function(parser) {
|
||||
tagInfo = parser.call(this, tagInfo);
|
||||
});
|
||||
|
||||
// if we wanted a type, but the parsers didn't add any type names, use the type expression
|
||||
if (canHaveType && !tagInfo.type.length && tagInfo.typeExpression) {
|
||||
tagInfo.type = [tagInfo.typeExpression];
|
||||
}
|
||||
|
||||
return tagInfo;
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
@module jsdoc/tag/validator
|
||||
@requires jsdoc/tag/dictionary
|
||||
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var dictionary = require('jsdoc/tag/dictionary');
|
||||
var format = require('util').format;
|
||||
var logger = require('jsdoc/util/logger');
|
||||
|
||||
function buildMessage(tagName, meta, desc) {
|
||||
var result = format('The @%s tag %s. File: %s, line: %s', tagName, desc, meta.filename,
|
||||
meta.lineno);
|
||||
if (meta.comment) {
|
||||
result += '\n' + meta.comment;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the given tag.
|
||||
*/
|
||||
exports.validate = function(tag, tagDef, meta) {
|
||||
// handle cases where the tag definition does not exist
|
||||
if (!tagDef) {
|
||||
// log an error if unknown tags are not allowed
|
||||
if (!env.conf.tags.allowUnknownTags) {
|
||||
logger.error( buildMessage(tag.title, meta, 'is not a known tag') );
|
||||
}
|
||||
|
||||
// stop validation, since there's nothing to validate against
|
||||
return;
|
||||
}
|
||||
|
||||
// check for errors that make the tag useless
|
||||
if (!tagDef && !env.conf.tags.allowUnknownTags) {
|
||||
logger.error( buildMessage(tag.title, meta, 'is not a known tag') );
|
||||
}
|
||||
else if (!tag.text && tagDef.mustHaveValue) {
|
||||
logger.error( buildMessage(tag.title, meta, 'requires a value') );
|
||||
}
|
||||
|
||||
// check for minor issues that are usually harmless
|
||||
else if (tag.text && tagDef.mustNotHaveValue) {
|
||||
logger.warn( buildMessage(tag.title, meta,
|
||||
'does not permit a value; the value will be ignored') );
|
||||
}
|
||||
else if (tag.value && tag.value.description && tagDef.mustNotHaveDescription) {
|
||||
logger.warn( buildMessage(tag.title, meta,
|
||||
'does not permit a description; the description will be ignored') );
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* @file Wrapper for underscore's template utility to allow loading templates from files.
|
||||
* @author Rafał Wrzeszcz <rafal.wrzeszcz@wrzasq.pl>
|
||||
* @author <a href="mailto:matthewkastor@gmail.com">Matthew Christopher Kastor-Inare III</a>
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore'),
|
||||
fs = require('jsdoc/fs'),
|
||||
path = require('path');
|
||||
|
||||
/**
|
||||
@module jsdoc/template
|
||||
*/
|
||||
|
||||
/**
|
||||
@class
|
||||
@classdesc Underscore template helper.
|
||||
@param {string} path - Templates directory.
|
||||
*/
|
||||
exports.Template = function(path) {
|
||||
this.path = path;
|
||||
this.layout = null;
|
||||
this.cache = {};
|
||||
// override default template tag settings
|
||||
this.settings = {
|
||||
evaluate: /<\?js([\s\S]+?)\?>/g,
|
||||
interpolate: /<\?js=([\s\S]+?)\?>/g,
|
||||
escape: /<\?js~([\s\S]+?)\?>/g
|
||||
};
|
||||
};
|
||||
|
||||
/** Loads template from given file.
|
||||
@param {string} file - Template filename.
|
||||
@return {function} Returns template closure.
|
||||
*/
|
||||
exports.Template.prototype.load = function(file) {
|
||||
return _.template(fs.readFileSync(file, 'utf8'), null, this.settings);
|
||||
};
|
||||
|
||||
/**
|
||||
Renders template using given data.
|
||||
|
||||
This is low-level function, for rendering full templates use {@link Template.render()}.
|
||||
|
||||
@param {string} file - Template filename.
|
||||
@param {object} data - Template variables (doesn't have to be object, but passing variables dictionary is best way and most common use).
|
||||
@return {string} Rendered template.
|
||||
*/
|
||||
exports.Template.prototype.partial = function(file, data) {
|
||||
file = path.resolve(this.path, file);
|
||||
|
||||
// load template into cache
|
||||
if (!(file in this.cache)) {
|
||||
this.cache[file] = this.load(file);
|
||||
}
|
||||
|
||||
// keep template helper context
|
||||
return this.cache[file].call(this, data);
|
||||
};
|
||||
|
||||
/**
|
||||
Renders template with given data.
|
||||
|
||||
This method automaticaly applies layout if set.
|
||||
|
||||
@param {string} file - Template filename.
|
||||
@param {object} data - Template variables (doesn't have to be object, but passing variables dictionary is best way and most common use).
|
||||
@return {string} Rendered template.
|
||||
*/
|
||||
exports.Template.prototype.render = function(file, data) {
|
||||
// main content
|
||||
var content = this.partial(file, data);
|
||||
|
||||
// apply layout
|
||||
if (this.layout) {
|
||||
data.content = content;
|
||||
content = this.partial(this.layout, data);
|
||||
}
|
||||
|
||||
return content;
|
||||
};
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
@overview
|
||||
@author Rafał Wrzeszcz <rafal.wrzeszcz@wrzasq.pl>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var markdown = require('jsdoc/util/markdown');
|
||||
var util = require('util');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
/** Removes child tutorial from the parent. Does *not* unset child.parent though.
|
||||
@param {Tutorial} parent - parent tutorial.
|
||||
@param {Tutorial} child - Old child.
|
||||
@private
|
||||
*/
|
||||
function removeChild(parent, child) {
|
||||
var index = parent.children.indexOf(child);
|
||||
if (index !== -1) {
|
||||
parent.children.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a child to the parent tutorial. Does *not* set child.parent though.
|
||||
@param {Tutorial} parent - parent tutorial.
|
||||
@param {Tutorial} child - New child.
|
||||
@private
|
||||
*/
|
||||
function addChild(parent, child) {
|
||||
parent.children.push(child);
|
||||
}
|
||||
|
||||
/**
|
||||
@module jsdoc/tutorial
|
||||
*/
|
||||
|
||||
/**
|
||||
@class
|
||||
@classdesc Represents a single JSDoc tutorial.
|
||||
@param {string} name - Tutorial name.
|
||||
@param {string} content - Text content.
|
||||
@param {number} type - Source formating.
|
||||
*/
|
||||
exports.Tutorial = function(name, content, type) {
|
||||
this.title = this.name = name;
|
||||
this.content = content;
|
||||
this.type = type;
|
||||
|
||||
// default values
|
||||
this.parent = null;
|
||||
this.children = [];
|
||||
};
|
||||
|
||||
/** Moves children from current parent to different one.
|
||||
@param {?Tutorial} parent - New parent. If null, the tutorial has no parent.
|
||||
*/
|
||||
exports.Tutorial.prototype.setParent = function(parent) {
|
||||
// removes node from old parent
|
||||
if (this.parent) {
|
||||
removeChild(this.parent, this);
|
||||
}
|
||||
|
||||
this.parent = parent;
|
||||
if (parent) {
|
||||
addChild(parent, this);
|
||||
}
|
||||
};
|
||||
|
||||
/** Removes children from current node.
|
||||
@param {Tutorial} child - Old child.
|
||||
*/
|
||||
exports.Tutorial.prototype.removeChild = function(child) {
|
||||
child.setParent(null);
|
||||
};
|
||||
|
||||
/** Adds new children to current node.
|
||||
@param {Tutorial} child - New child.
|
||||
*/
|
||||
exports.Tutorial.prototype.addChild = function(child) {
|
||||
child.setParent(this);
|
||||
};
|
||||
|
||||
/** Prepares source.
|
||||
@return {string} HTML source.
|
||||
*/
|
||||
exports.Tutorial.prototype.parse = function() {
|
||||
switch (this.type) {
|
||||
// nothing to do
|
||||
case exports.TYPES.HTML:
|
||||
return this.content;
|
||||
|
||||
// markdown
|
||||
case exports.TYPES.MARKDOWN:
|
||||
var mdParse = markdown.getParser();
|
||||
return mdParse(this.content);
|
||||
|
||||
// uhm... should we react somehow?
|
||||
// if not then this case can be merged with TYPES.HTML
|
||||
default:
|
||||
return this.content;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc Represents the root tutorial.
|
||||
* @extends {module:jsdoc/tutorial.Tutorial}
|
||||
*/
|
||||
exports.RootTutorial = function() {
|
||||
exports.RootTutorial.super_.call(this, '', '');
|
||||
|
||||
this._tutorials = {};
|
||||
};
|
||||
util.inherits(exports.RootTutorial, exports.Tutorial);
|
||||
|
||||
/**
|
||||
* Retrieve a tutorial by name.
|
||||
* @param {string} name - Tutorial name.
|
||||
* @return {module:jsdoc/tutorial.Tutorial} Tutorial instance.
|
||||
*/
|
||||
exports.RootTutorial.prototype.getByName = function(name) {
|
||||
return hasOwnProp.call(this._tutorials, name) && this._tutorials[name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a child tutorial to the root.
|
||||
* @param {module:jsdoc/tutorial.Tutorial} child - Child tutorial.
|
||||
*/
|
||||
exports.RootTutorial.prototype._addTutorial = function(child) {
|
||||
this._tutorials[child.name] = child;
|
||||
};
|
||||
|
||||
/** Tutorial source types.
|
||||
@enum {number}
|
||||
*/
|
||||
exports.TYPES = {
|
||||
HTML: 1,
|
||||
MARKDOWN: 2
|
||||
};
|
||||
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
@overview
|
||||
@author Rafał Wrzeszcz <rafal.wrzeszcz@wrzasq.pl>
|
||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
|
||||
/**
|
||||
@module jsdoc/tutorial/resolver
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var fs = require('jsdoc/fs');
|
||||
var path = require('path');
|
||||
var tutorial = require('jsdoc/tutorial');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
// TODO: make this an instance member of `RootTutorial`?
|
||||
var conf = {};
|
||||
var finder = /^(.*)\.(x(?:ht)?ml|html?|md|markdown|json)$/i;
|
||||
|
||||
/** checks if `conf` is the metadata for a single tutorial.
|
||||
* A tutorial's metadata has a property 'title' and/or a property 'children'.
|
||||
* @param {object} json - the object we want to test (typically from JSON.parse)
|
||||
* @returns {boolean} whether `json` could be the metadata for a tutorial.
|
||||
*/
|
||||
function isTutorialJSON(json) {
|
||||
// if conf.title exists or conf.children exists, it is metadata for a tutorial
|
||||
return (hasOwnProp.call(json, 'title') || hasOwnProp.call(json, 'children'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Root tutorial.
|
||||
* @type {module:jsdoc/tutorial.Root}
|
||||
*/
|
||||
exports.root = new tutorial.RootTutorial();
|
||||
|
||||
/** Helper function that adds tutorial configuration to the `conf` variable.
|
||||
* This helps when multiple tutorial configurations are specified in one object,
|
||||
* or when a tutorial's children are specified as tutorial configurations as
|
||||
* opposed to an array of tutorial names.
|
||||
*
|
||||
* Recurses as necessary to ensure all tutorials are added.
|
||||
*
|
||||
* @param {string} name - if `meta` is a configuration for a single tutorial,
|
||||
* this is that tutorial's name.
|
||||
* @param {object} meta - object that contains tutorial information.
|
||||
* Can either be for a single tutorial, or for multiple
|
||||
* (where each key in `meta` is the tutorial name and each
|
||||
* value is the information for a single tutorial).
|
||||
* Additionally, a tutorial's 'children' property may
|
||||
* either be an array of strings (names of the child tutorials),
|
||||
* OR an object giving the configuration for the child tutorials.
|
||||
*/
|
||||
function addTutorialConf(name, meta) {
|
||||
var i;
|
||||
var l;
|
||||
var names;
|
||||
|
||||
if (isTutorialJSON(meta)) {
|
||||
// if the children are themselves tutorial defintions as opposed to an
|
||||
// array of strings, add each child.
|
||||
if (hasOwnProp.call(meta, 'children') && !Array.isArray(meta.children)) {
|
||||
names = Object.keys(meta.children);
|
||||
for (i = 0, l = names.length; i < l; ++i) {
|
||||
addTutorialConf(names[i], meta.children[names[i]]);
|
||||
}
|
||||
// replace with an array of names.
|
||||
meta.children = names;
|
||||
}
|
||||
// check if the tutorial has already been defined...
|
||||
if (hasOwnProp.call(conf, name)) {
|
||||
logger.warn('Metadata for the tutorial %s is defined more than once. Only the first definition will be used.', name );
|
||||
} else {
|
||||
conf[name] = meta;
|
||||
}
|
||||
} else {
|
||||
// keys are tutorial names, values are `Tutorial` instances
|
||||
names = Object.keys(meta);
|
||||
for (i = 0, l = names.length; i < l; ++i) {
|
||||
addTutorialConf(names[i], meta[names[i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a tutorial.
|
||||
* @param {module:jsdoc/tutorial.Tutorial} current - Tutorial to add.
|
||||
*/
|
||||
exports.addTutorial = function(current) {
|
||||
if (exports.root.getByName(current.name)) {
|
||||
logger.warn('The tutorial %s is defined more than once. Only the first definition will be used.', current.name);
|
||||
} else {
|
||||
// by default, the root tutorial is the parent
|
||||
current.setParent(exports.root);
|
||||
|
||||
exports.root._addTutorial(current);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Load tutorials from the given path.
|
||||
* @param {string} filepath - Tutorials directory.
|
||||
*/
|
||||
exports.load = function(filepath) {
|
||||
var content;
|
||||
var current;
|
||||
var files = fs.ls(filepath, global.env.opts.recurse ? 10 : undefined);
|
||||
var name;
|
||||
var match;
|
||||
var type;
|
||||
|
||||
// tutorials handling
|
||||
files.forEach(function(file) {
|
||||
match = file.match(finder);
|
||||
|
||||
// any filetype that can apply to tutorials
|
||||
if (match) {
|
||||
name = path.basename(match[1]);
|
||||
content = fs.readFileSync(file, global.env.opts.encoding);
|
||||
|
||||
switch (match[2].toLowerCase()) {
|
||||
// HTML type
|
||||
case 'xml':
|
||||
case 'xhtml':
|
||||
case 'html':
|
||||
case 'htm':
|
||||
type = tutorial.TYPES.HTML;
|
||||
break;
|
||||
|
||||
// Markdown typs
|
||||
case 'md':
|
||||
case 'markdown':
|
||||
type = tutorial.TYPES.MARKDOWN;
|
||||
break;
|
||||
|
||||
// configuration file
|
||||
case 'json':
|
||||
var meta = JSON.parse(content);
|
||||
addTutorialConf(name, meta);
|
||||
// don't add this as a tutorial
|
||||
return;
|
||||
|
||||
// how can it be? check `finder' regexp
|
||||
default:
|
||||
// not a file we want to work with
|
||||
return;
|
||||
}
|
||||
|
||||
current = new tutorial.Tutorial(name, content, type);
|
||||
exports.addTutorial(current);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/** Resolves hierarchical structure.
|
||||
*/
|
||||
exports.resolve = function() {
|
||||
var item;
|
||||
var current;
|
||||
|
||||
Object.keys(conf).forEach(function(name) {
|
||||
current = exports.root.getByName(name);
|
||||
|
||||
// TODO: should we complain about this?
|
||||
if (!current) {
|
||||
return;
|
||||
}
|
||||
|
||||
item = conf[name];
|
||||
|
||||
// set title
|
||||
if (item.title) {
|
||||
current.title = item.title;
|
||||
}
|
||||
|
||||
// add children
|
||||
if (item.children) {
|
||||
item.children.forEach(function(child) {
|
||||
var childTutorial = exports.root.getByName(child);
|
||||
|
||||
if (!childTutorial) {
|
||||
logger.error('Missing child tutorial: %s', child);
|
||||
}
|
||||
else {
|
||||
childTutorial.setParent(current);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
/*global Set */
|
||||
|
||||
/**
|
||||
Deep clone a simple object. Ignores non-enumerable properties.
|
||||
@private
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var setDefined = typeof Set !== 'undefined';
|
||||
|
||||
function addItem(set, item) {
|
||||
if (setDefined) {
|
||||
set.add(item);
|
||||
}
|
||||
else if (set.indexOf(item) === -1) {
|
||||
set.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
function hasItem(set, item) {
|
||||
if (setDefined) {
|
||||
return set.has(item);
|
||||
}
|
||||
else {
|
||||
return set.indexOf(item) !== -1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: can we remove the circular-ref checking? pretty sure it's not needed anymore...
|
||||
// if we need this here for some reason I'm forgetting, we should share code with jsdoc/util/dumper
|
||||
function doop(o, seen) {
|
||||
var clone;
|
||||
var descriptor;
|
||||
var props;
|
||||
var i;
|
||||
var l;
|
||||
|
||||
if (!seen) {
|
||||
seen = setDefined ? new Set() : [];
|
||||
}
|
||||
|
||||
if (o instanceof Object && o.constructor !== Function) {
|
||||
if ( hasItem(seen, o) ) {
|
||||
clone = '<CircularRef>';
|
||||
}
|
||||
else {
|
||||
addItem(seen, o);
|
||||
|
||||
if ( Array.isArray(o) ) {
|
||||
clone = [];
|
||||
for (i = 0, l = o.length; i < l; i++) {
|
||||
clone[i] = (o[i] instanceof Object) ? doop(o[i], seen) : o[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
clone = Object.create( Object.getPrototypeOf(o) );
|
||||
props = Object.keys(o);
|
||||
for (i = 0, l = props.length; i < l; i++) {
|
||||
descriptor = Object.getOwnPropertyDescriptor(o, props[i]);
|
||||
if (descriptor.value) {
|
||||
descriptor.value = doop(descriptor.value, seen);
|
||||
}
|
||||
|
||||
Object.defineProperty(clone, props[i], descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
// Wrapper to avoid exposing the 'seen' parameter outside of this module.
|
||||
function doopWrapper(o) {
|
||||
return doop(o);
|
||||
}
|
||||
|
||||
// for backwards compatibility
|
||||
doopWrapper.doop = doopWrapper;
|
||||
|
||||
module.exports = doopWrapper;
|
||||
@@ -0,0 +1,139 @@
|
||||
/*global Set */
|
||||
/**
|
||||
* Recursively print out all names and values in a data structure.
|
||||
* @module jsdoc/util/dumper
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
var OBJECT_WALKER_KEY = 'hasBeenSeenByWalkerDumper';
|
||||
var SET_DEFINED = (typeof Set !== 'undefined');
|
||||
|
||||
function ObjectWalker() {
|
||||
this.seenItems = SET_DEFINED ? new Set() : [];
|
||||
}
|
||||
|
||||
ObjectWalker.prototype.seen = function(object) {
|
||||
var result;
|
||||
|
||||
if (SET_DEFINED) {
|
||||
result = this.seenItems.has(object);
|
||||
}
|
||||
else {
|
||||
result = object[OBJECT_WALKER_KEY];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
ObjectWalker.prototype.markAsSeen = function(object) {
|
||||
if (SET_DEFINED) {
|
||||
this.seenItems.add(object);
|
||||
}
|
||||
else {
|
||||
object[OBJECT_WALKER_KEY] = true;
|
||||
this.seenItems.push(object);
|
||||
}
|
||||
};
|
||||
|
||||
ObjectWalker.prototype.removeSeenFlag = function(obj) {
|
||||
if (SET_DEFINED) {
|
||||
this.seenItems.delete(obj);
|
||||
}
|
||||
else {
|
||||
delete obj[OBJECT_WALKER_KEY];
|
||||
}
|
||||
};
|
||||
|
||||
// some objects are unwalkable, like Java native objects
|
||||
ObjectWalker.prototype.isUnwalkable = function(o) {
|
||||
return (o && typeof o === 'object' && typeof o.constructor === 'undefined');
|
||||
};
|
||||
|
||||
ObjectWalker.prototype.isFunction = function(o) {
|
||||
return (o && typeof o === 'function' || o instanceof Function);
|
||||
};
|
||||
|
||||
ObjectWalker.prototype.isObject = function(o) {
|
||||
return o && o instanceof Object ||
|
||||
(o && typeof o.constructor !== 'undefined' && o.constructor.name === 'Object');
|
||||
};
|
||||
|
||||
ObjectWalker.prototype.checkCircularRefs = function(o, func) {
|
||||
if ( this.seen(o) ) {
|
||||
return '<CircularRef>';
|
||||
}
|
||||
else {
|
||||
this.markAsSeen(o);
|
||||
return func(o);
|
||||
}
|
||||
};
|
||||
|
||||
ObjectWalker.prototype.walk = function(o) {
|
||||
var result;
|
||||
|
||||
var self = this;
|
||||
|
||||
if ( this.isUnwalkable(o) ) {
|
||||
result = '<Object>';
|
||||
}
|
||||
else if ( o === undefined ) {
|
||||
result = null;
|
||||
}
|
||||
else if ( Array.isArray(o) ) {
|
||||
result = this.checkCircularRefs(o, function(arr) {
|
||||
var newArray = [];
|
||||
|
||||
arr.forEach(function(item) {
|
||||
newArray.push( self.walk(item) );
|
||||
});
|
||||
|
||||
self.removeSeenFlag(arr);
|
||||
|
||||
return newArray;
|
||||
});
|
||||
}
|
||||
else if ( util.isRegExp(o) ) {
|
||||
result = '<RegExp ' + o + '>';
|
||||
}
|
||||
else if ( util.isDate(o) ) {
|
||||
result = '<Date ' + o.toUTCString() + '>';
|
||||
}
|
||||
else if ( util.isError(o) ) {
|
||||
result = { message: o.message };
|
||||
}
|
||||
else if ( this.isFunction(o) ) {
|
||||
result = '<Function' + (o.name ? ' ' + o.name : '') + '>';
|
||||
}
|
||||
else if ( this.isObject(o) && o !== null ) {
|
||||
result = this.checkCircularRefs(o, function(obj) {
|
||||
var newObj = {};
|
||||
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
if (!SET_DEFINED && key === OBJECT_WALKER_KEY) { return; }
|
||||
newObj[key] = self.walk(obj[key]);
|
||||
});
|
||||
|
||||
self.removeSeenFlag(obj);
|
||||
|
||||
return newObj;
|
||||
});
|
||||
}
|
||||
// should be safe to JSON.stringify() everything else
|
||||
else {
|
||||
result = o;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} object
|
||||
*/
|
||||
exports.dump = function(object) {
|
||||
var walker = new ObjectWalker();
|
||||
|
||||
return JSON.stringify(walker.walk(object), null, 4);
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
* Helper functions for handling errors.
|
||||
*
|
||||
* @deprecated As of JSDoc 3.3.0. This module may be removed in a future release. Use the module
|
||||
* {@link module:jsdoc/util/logger} to log warnings and errors.
|
||||
* @module jsdoc/util/error
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Log an exception as an error.
|
||||
*
|
||||
* Prior to JSDoc 3.3.0, this method would either log the exception (if lenient mode was enabled) or
|
||||
* re-throw the exception (default).
|
||||
*
|
||||
* In JSDoc 3.3.0 and later, lenient mode has been replaced with strict mode, which is disabled by
|
||||
* default. If strict mode is enabled, calling the `handle` method causes JSDoc to exit immediately,
|
||||
* just as if the exception had been re-thrown.
|
||||
*
|
||||
* @deprecated As of JSDoc 3.3.0. This module may be removed in a future release.
|
||||
* @param {Error} e - The exception to log.
|
||||
* @memberof module:jsdoc/util/error
|
||||
*/
|
||||
exports.handle = function(e) {
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var msg = e ? ( e.message || JSON.stringify(e) ) : '';
|
||||
|
||||
// include the error type if it's an Error object
|
||||
if (e instanceof Error) {
|
||||
msg = e.name + ': ' + msg;
|
||||
}
|
||||
|
||||
logger.error(msg);
|
||||
};
|
||||
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* Logging tools for JSDoc.
|
||||
*
|
||||
* Log messages are printed to the console based on the current logging level. By default, messages
|
||||
* at level `{@link module:jsdoc/util/logger.LEVELS.ERROR}` or above are logged; all other messages
|
||||
* are ignored.
|
||||
*
|
||||
* In addition, the module object emits an event whenever a logger method is called, regardless of
|
||||
* the current logging level. The event's name is the string `logger:` followed by the logger's name
|
||||
* (for example, `logger:error`). The event handler receives an array of arguments that were passed
|
||||
* to the logger method.
|
||||
*
|
||||
* Each logger method accepts a `message` parameter that may contain zero or more placeholders. Each
|
||||
* placeholder is replaced by the corresponding argument following the message. If the placeholder
|
||||
* does not have a corresponding argument, the placeholder is not replaced.
|
||||
*
|
||||
* The following placeholders are supported:
|
||||
*
|
||||
* + `%s`: String.
|
||||
* + `%d`: Number.
|
||||
* + `%j`: JSON.
|
||||
*
|
||||
* @module jsdoc/util/logger
|
||||
* @extends module:events.EventEmitter
|
||||
* @example
|
||||
* var logger = require('jsdoc/util/logger');
|
||||
*
|
||||
* var data = {
|
||||
* foo: 'bar'
|
||||
* };
|
||||
* var name = 'baz';
|
||||
*
|
||||
* logger.warn('%j %s', data, name); // prints '{"foo":"bar"} baz'
|
||||
* @see http://nodejs.org/api/util.html#util_util_format_format
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var runtime = require('jsdoc/util/runtime');
|
||||
var util = require('util');
|
||||
|
||||
function Logger() {}
|
||||
util.inherits(Logger, require('events').EventEmitter);
|
||||
|
||||
var logger = module.exports = new Logger();
|
||||
|
||||
/**
|
||||
* Logging levels for the JSDoc logger. The default logging level is
|
||||
* {@link module:jsdoc/util/logger.LEVELS.ERROR}.
|
||||
*
|
||||
* @enum
|
||||
* @type {number}
|
||||
*/
|
||||
var LEVELS = logger.LEVELS = {
|
||||
/** Do not log any messages. */
|
||||
SILENT: 0,
|
||||
/** Log fatal errors that prevent JSDoc from running. */
|
||||
FATAL: 10,
|
||||
/** Log all errors, including errors from which JSDoc can recover. */
|
||||
ERROR: 20,
|
||||
/**
|
||||
* Log the following messages:
|
||||
*
|
||||
* + Warnings
|
||||
* + Errors
|
||||
*/
|
||||
WARN: 30,
|
||||
/**
|
||||
* Log the following messages:
|
||||
*
|
||||
* + Informational messages
|
||||
* + Warnings
|
||||
* + Errors
|
||||
*/
|
||||
INFO: 40,
|
||||
/**
|
||||
* Log the following messages:
|
||||
*
|
||||
* + Debugging messages
|
||||
* + Informational messages
|
||||
* + Warnings
|
||||
* + Errors
|
||||
*/
|
||||
DEBUG: 50,
|
||||
/** Log all messages. */
|
||||
VERBOSE: 1000
|
||||
};
|
||||
|
||||
var DEFAULT_LEVEL = LEVELS.WARN;
|
||||
var logLevel = DEFAULT_LEVEL;
|
||||
|
||||
var PREFIXES = {
|
||||
DEBUG: 'DEBUG: ',
|
||||
ERROR: 'ERROR: ',
|
||||
FATAL: 'FATAL: ',
|
||||
WARN: 'WARNING: '
|
||||
};
|
||||
|
||||
// Add a prefix to a log message if necessary.
|
||||
function addPrefix(args, prefix) {
|
||||
var updatedArgs;
|
||||
|
||||
if (prefix && typeof args[0] === 'string') {
|
||||
updatedArgs = args.slice(0);
|
||||
updatedArgs[0] = prefix + updatedArgs[0];
|
||||
}
|
||||
|
||||
return updatedArgs || args;
|
||||
}
|
||||
|
||||
// TODO: document events
|
||||
function wrapLogFunction(name, func) {
|
||||
var eventName = 'logger:' + name;
|
||||
var upperCaseName = name.toUpperCase();
|
||||
var level = LEVELS[upperCaseName];
|
||||
var prefix = PREFIXES[upperCaseName];
|
||||
|
||||
return function() {
|
||||
var loggerArgs;
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
|
||||
if (logLevel >= level) {
|
||||
loggerArgs = addPrefix(args, prefix);
|
||||
func.apply(null, loggerArgs);
|
||||
}
|
||||
|
||||
args.unshift(eventName);
|
||||
logger.emit.apply(logger, args);
|
||||
};
|
||||
}
|
||||
|
||||
// Print a message to STDOUT without a terminating newline.
|
||||
function printToStdout() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
|
||||
process.stdout.write( util.format.apply(util, args) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.DEBUG}.
|
||||
*
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.debug = wrapLogFunction('debug', console.info);
|
||||
/**
|
||||
* Print a string at log level {@link module:jsdoc/util/logger.LEVELS.DEBUG}. The string is not
|
||||
* terminated by a newline.
|
||||
*
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.printDebug = wrapLogFunction('debug', printToStdout);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.ERROR}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.error
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.error = wrapLogFunction('error', console.error);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.FATAL}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.fatal
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.fatal = wrapLogFunction('fatal', console.error);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.INFO}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.info
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.info = wrapLogFunction('info', console.info);
|
||||
/**
|
||||
* Print a string at log level {@link module:jsdoc/util/logger.LEVELS.INFO}. The string is not
|
||||
* terminated by a newline.
|
||||
*
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.printInfo = wrapLogFunction('info', printToStdout);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.VERBOSE}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.verbose
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.verbose = wrapLogFunction('verbose', console.info);
|
||||
/**
|
||||
* Print a string at log level {@link module:jsdoc/util/logger.LEVELS.VERBOSE}. The string is not
|
||||
* terminated by a newline.
|
||||
*
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.printVerbose = wrapLogFunction('verbose', printToStdout);
|
||||
/**
|
||||
* Log a message at log level {@link module:jsdoc/util/logger.LEVELS.WARN}.
|
||||
*
|
||||
* @name module:jsdoc/util/logger.warn
|
||||
* @function
|
||||
* @param {string} message - The message to log.
|
||||
* @param {...*=} values - The values that will replace the message's placeholders.
|
||||
*/
|
||||
logger.warn = wrapLogFunction('warn', console.warn);
|
||||
|
||||
/**
|
||||
* Set the log level.
|
||||
*
|
||||
* @param {module:jsdoc/util/logger.LEVELS} level - The log level to use.
|
||||
*/
|
||||
logger.setLevel = function setLevel(level) {
|
||||
logLevel = (level !== undefined) ? level : DEFAULT_LEVEL;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current log level.
|
||||
*
|
||||
* @return {module:jsdoc/util/logger.LEVELS} The current log level.
|
||||
*/
|
||||
logger.getLevel = function getLevel() {
|
||||
return logLevel;
|
||||
};
|
||||
@@ -0,0 +1,156 @@
|
||||
/*global env */
|
||||
|
||||
/**
|
||||
* Provides access to Markdown-related functions.
|
||||
* @module jsdoc/util/markdown
|
||||
* @author Michael Mathews <micmath@gmail.com>
|
||||
* @author Ben Blank <ben.blank@gmail.com>
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
|
||||
/**
|
||||
* Enumeration of Markdown parsers that are available.
|
||||
* @enum {String}
|
||||
*/
|
||||
var parserNames = {
|
||||
/**
|
||||
* The "[markdown-js](https://github.com/evilstreak/markdown-js)" (aka "evilstreak") parser.
|
||||
*
|
||||
* @deprecated Replaced by "marked," as markdown-js does not support inline HTML.
|
||||
*/
|
||||
evilstreak: 'marked',
|
||||
/**
|
||||
* The "GitHub-flavored Markdown" parser.
|
||||
* @deprecated Replaced by "marked."
|
||||
*/
|
||||
gfm: 'marked',
|
||||
/**
|
||||
* The "[Marked](https://github.com/chjj/marked)" parser.
|
||||
*/
|
||||
marked: 'marked'
|
||||
};
|
||||
|
||||
/**
|
||||
* Escape underscores that occur within {@ ... } in order to protect them
|
||||
* from the markdown parser(s).
|
||||
* @param {String} source the source text to sanitize.
|
||||
* @returns {String} `source` where underscores within {@ ... } have been
|
||||
* protected with a preceding backslash (i.e. \_) -- the markdown parsers
|
||||
* will strip the backslash and protect the underscore.
|
||||
*/
|
||||
function escapeUnderscores(source) {
|
||||
return source.replace(/\{@[^}\r\n]+\}/g, function (wholeMatch) {
|
||||
return wholeMatch.replace(/(^|[^\\])_/g, '$1\\_');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape HTTP/HTTPS URLs so that they are not automatically converted to HTML links.
|
||||
*
|
||||
* @param {string} source - The source text to escape.
|
||||
* @return {string} The source text with escape characters added to HTTP/HTTPS URLs.
|
||||
*/
|
||||
function escapeUrls(source) {
|
||||
return source.replace(/(https?)\:\/\//g, '$1:\\/\\/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescape HTTP/HTTPS URLs after Markdown parsing is complete.
|
||||
*
|
||||
* @param {string} source - The source text to unescape.
|
||||
* @return {string} The source text with escape characters removed from HTTP/HTTPS URLs.
|
||||
*/
|
||||
function unescapeUrls(source) {
|
||||
return source.replace(/(https?)\:\\\/\\\//g, '$1://');
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape characters in text within a code block.
|
||||
*
|
||||
* @param {string} source - The source text to escape.
|
||||
* @return {string} The escaped source text.
|
||||
*/
|
||||
function escapeCode(source) {
|
||||
return source.replace(/</g, '<')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a function that accepts a single parameter containing Markdown source. The function uses
|
||||
* the specified parser to transform the Markdown source to HTML, then returns the HTML as a string.
|
||||
*
|
||||
* @private
|
||||
* @param {String} parserName The name of the selected parser.
|
||||
* @param {Object} [conf] Configuration for the selected parser, if any.
|
||||
* @returns {Function} A function that accepts Markdown source, feeds it to the selected parser, and
|
||||
* returns the resulting HTML.
|
||||
*/
|
||||
function getParseFunction(parserName, conf) {
|
||||
var logger = require('jsdoc/util/logger');
|
||||
var marked = require('marked');
|
||||
|
||||
var markedRenderer;
|
||||
var parserFunction;
|
||||
|
||||
conf = conf || {};
|
||||
|
||||
if (parserName === parserNames.marked) {
|
||||
// Marked generates an "id" attribute for headers; this custom renderer suppresses it
|
||||
markedRenderer = new marked.Renderer();
|
||||
|
||||
markedRenderer.heading = function(text, level) {
|
||||
return util.format('<h%s>%s</h%s>', level, text, level);
|
||||
};
|
||||
|
||||
// Allow prettyprint to work on inline code samples
|
||||
markedRenderer.code = function(code, language) {
|
||||
var langClass = language ? ' lang-' + language : '';
|
||||
|
||||
return util.format( '<pre class="prettyprint source%s"><code>%s</code></pre>',
|
||||
langClass, escapeCode(code) );
|
||||
};
|
||||
|
||||
parserFunction = function(source) {
|
||||
var result;
|
||||
|
||||
source = escapeUnderscores(source);
|
||||
source = escapeUrls(source);
|
||||
|
||||
result = marked(source, { renderer: markedRenderer })
|
||||
.replace(/\s+$/, '')
|
||||
.replace(/'/g, "'");
|
||||
result = unescapeUrls(result);
|
||||
|
||||
return result;
|
||||
};
|
||||
parserFunction._parser = parserNames.marked;
|
||||
return parserFunction;
|
||||
}
|
||||
else {
|
||||
logger.error('Unrecognized Markdown parser "%s". Markdown support is disabled.',
|
||||
parserName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a Markdown parsing function based on the value of the `conf.json` file's
|
||||
* `env.conf.markdown` property. The parsing function accepts a single parameter containing Markdown
|
||||
* source. The function uses the parser specified in `conf.json` to transform the Markdown source to
|
||||
* HTML, then returns the HTML as a string.
|
||||
*
|
||||
* @returns {function} A function that accepts Markdown source, feeds it to the selected parser, and
|
||||
* returns the resulting HTML.
|
||||
*/
|
||||
exports.getParser = function() {
|
||||
var conf = env.conf.markdown;
|
||||
if (conf && conf.parser) {
|
||||
return getParseFunction(parserNames[conf.parser], conf);
|
||||
}
|
||||
else {
|
||||
// marked is the default parser
|
||||
return getParseFunction(parserNames.marked, conf);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,117 @@
|
||||
/*global env, java */
|
||||
/**
|
||||
* Helper functions to enable JSDoc to run on multiple JavaScript runtimes.
|
||||
*
|
||||
* @module jsdoc/util/runtime
|
||||
* @private
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var os = require('os');
|
||||
|
||||
// These strings represent directory names; do not modify them!
|
||||
/** @private */
|
||||
var RHINO = exports.RHINO = 'rhino';
|
||||
/** @private */
|
||||
var NODE = exports.NODE = 'node';
|
||||
|
||||
/**
|
||||
* The JavaScript runtime that is executing JSDoc:
|
||||
*
|
||||
* + `module:jsdoc/util/runtime~RHINO`: Mozilla Rhino.
|
||||
* + `module:jsdoc/util/runtime~NODE`: Node.js.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
var runtime = (function() {
|
||||
if (global.Packages && typeof global.Packages === 'object' &&
|
||||
Object.prototype.toString.call(global.Packages) === '[object JavaPackage]') {
|
||||
return RHINO;
|
||||
} else if (require && require.main && module) {
|
||||
return NODE;
|
||||
} else {
|
||||
// unknown runtime
|
||||
throw new Error('Unable to identify the current JavaScript runtime.');
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* Check whether Mozilla Rhino is running JSDoc.
|
||||
* @return {boolean} Set to `true` if the current runtime is Mozilla Rhino.
|
||||
*/
|
||||
exports.isRhino = function() {
|
||||
return runtime === RHINO;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether Node.js is running JSDoc.
|
||||
* @return {boolean} Set to `true` if the current runtime is Node.js.
|
||||
*/
|
||||
exports.isNode = function() {
|
||||
return runtime === NODE;
|
||||
};
|
||||
|
||||
function initializeRhino(args) {
|
||||
// the JSDoc dirname is the main module URI, minus the filename, converted to a path
|
||||
var uriParts = require.main.uri.split('/');
|
||||
uriParts.pop();
|
||||
|
||||
env.dirname = String( new java.io.File(new java.net.URI(uriParts.join('/'))) );
|
||||
env.pwd = String( java.lang.System.getenv().get('PWD') );
|
||||
env.args = args;
|
||||
|
||||
require(env.dirname + '/rhino/rhino-shim.js');
|
||||
}
|
||||
|
||||
function initializeNode(args) {
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var jsdocPath = args[0];
|
||||
var pwd = args[1];
|
||||
|
||||
// resolve the path if it's a symlink
|
||||
if ( fs.statSync(jsdocPath).isSymbolicLink() ) {
|
||||
jsdocPath = path.resolve( path.dirname(jsdocPath), fs.readlinkSync(jsdocPath) );
|
||||
}
|
||||
|
||||
env.dirname = jsdocPath;
|
||||
env.pwd = pwd;
|
||||
env.args = process.argv.slice(2);
|
||||
}
|
||||
|
||||
exports.initialize = function(args) {
|
||||
switch (runtime) {
|
||||
case RHINO:
|
||||
initializeRhino(args);
|
||||
break;
|
||||
case NODE:
|
||||
initializeNode(args);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Cannot initialize the unknown JavaScript runtime "' + runtime + '"!');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the identifier for the current JavaScript runtime.
|
||||
*
|
||||
* @private
|
||||
* @return {string} The runtime identifier.
|
||||
*/
|
||||
exports.getRuntime = function() {
|
||||
return runtime;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the require path for the runtime-specific implementation of a module.
|
||||
*
|
||||
* @param {string} partialPath - The partial path to the module. Use the same format as when calling
|
||||
* `require()`.
|
||||
* @return {object} The require path for the runtime-specific implementation of the module.
|
||||
*/
|
||||
exports.getModulePath = function(partialPath) {
|
||||
var path = require('path');
|
||||
|
||||
return path.join(env.dirname, runtime, partialPath);
|
||||
};
|
||||
@@ -0,0 +1,920 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
* @module jsdoc/util/templateHelper
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var catharsis = require('catharsis');
|
||||
var dictionary = require('jsdoc/tag/dictionary');
|
||||
var name = require('jsdoc/name');
|
||||
var util = require('util');
|
||||
|
||||
var hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
|
||||
var MODULE_NAMESPACE = 'module:';
|
||||
|
||||
var files = {};
|
||||
var ids = {};
|
||||
|
||||
// each container gets its own html file
|
||||
var containers = ['class', 'module', 'external', 'namespace', 'mixin', 'interface'];
|
||||
|
||||
var tutorials;
|
||||
|
||||
/** Sets tutorials map.
|
||||
@param {jsdoc.tutorial.Tutorial} root - Root tutorial node.
|
||||
*/
|
||||
exports.setTutorials = function(root) {
|
||||
tutorials = root;
|
||||
};
|
||||
|
||||
exports.globalName = name.SCOPE.NAMES.GLOBAL;
|
||||
exports.fileExtension = '.html';
|
||||
exports.scopeToPunc = name.scopeToPunc;
|
||||
|
||||
var linkMap = {
|
||||
// two-way lookup
|
||||
longnameToUrl: {},
|
||||
urlToLongname: {},
|
||||
|
||||
// one-way lookup (IDs are only unique per file)
|
||||
longnameToId: {}
|
||||
};
|
||||
|
||||
// two-way lookup
|
||||
var tutorialLinkMap = {
|
||||
nameToUrl: {},
|
||||
urlToName: {}
|
||||
};
|
||||
|
||||
var longnameToUrl = exports.longnameToUrl = linkMap.longnameToUrl;
|
||||
var longnameToId = exports.longnameToId = linkMap.longnameToId;
|
||||
|
||||
var registerLink = exports.registerLink = function(longname, fileUrl) {
|
||||
linkMap.longnameToUrl[longname] = fileUrl;
|
||||
linkMap.urlToLongname[fileUrl] = longname;
|
||||
};
|
||||
|
||||
var registerId = exports.registerId = function(longname, fragment) {
|
||||
linkMap.longnameToId[longname] = fragment;
|
||||
};
|
||||
|
||||
function getNamespace(kind) {
|
||||
if (dictionary.isNamespace(kind)) {
|
||||
return kind + ':';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function formatNameForLink(doclet, options) {
|
||||
var newName = getNamespace(doclet.kind) + (doclet.name || '') + (doclet.variation || '');
|
||||
var scopePunc = exports.scopeToPunc[doclet.scope] || '';
|
||||
|
||||
// Only prepend the scope punctuation if it's not the same character that marks the start of a
|
||||
// fragment ID. Using `#` in HTML5 fragment IDs is legal, but URLs like `foo.html##bar` are
|
||||
// just confusing.
|
||||
if (scopePunc !== '#') {
|
||||
newName = scopePunc + newName;
|
||||
}
|
||||
|
||||
return newName;
|
||||
}
|
||||
|
||||
function makeUniqueFilename(filename, str) {
|
||||
var key = filename.toLowerCase();
|
||||
var nonUnique = true;
|
||||
|
||||
// don't allow filenames to begin with an underscore
|
||||
if (!filename.length || filename[0] === '_') {
|
||||
filename = '-' + filename;
|
||||
key = filename.toLowerCase();
|
||||
}
|
||||
|
||||
// append enough underscores to make the filename unique
|
||||
while (nonUnique) {
|
||||
if ( hasOwnProp.call(files, key) ) {
|
||||
filename += '_';
|
||||
key = filename.toLowerCase();
|
||||
} else {
|
||||
nonUnique = false;
|
||||
}
|
||||
}
|
||||
|
||||
files[key] = str;
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a string to a unique filename, including an extension.
|
||||
*
|
||||
* Filenames are cached to ensure that they are used only once. For example, if the same string is
|
||||
* passed in twice, two different filenames will be returned.
|
||||
*
|
||||
* Also, filenames are not considered unique if they are capitalized differently but are otherwise
|
||||
* identical.
|
||||
* @param {string} str The string to convert.
|
||||
* @return {string} The filename to use for the string.
|
||||
*/
|
||||
var getUniqueFilename = exports.getUniqueFilename = function(str) {
|
||||
var namespaces = dictionary.getNamespaces().join('|');
|
||||
var basename = (str || '')
|
||||
// use - instead of : in namespace prefixes
|
||||
.replace(new RegExp('^(' + namespaces + '):'), '$1-')
|
||||
// replace characters that can cause problems on some filesystems
|
||||
.replace(/[\\\/?*:|'"<>]/g, '_')
|
||||
// use - instead of ~ to denote 'inner'
|
||||
.replace(/~/g, '-')
|
||||
// use _ instead of # to denote 'instance'
|
||||
.replace(/\#/g, '_')
|
||||
// use _ instead of / (for example, in module names)
|
||||
.replace(/\//g, '_')
|
||||
// remove the variation, if any
|
||||
.replace(/\([\s\S]*\)$/, '')
|
||||
// make sure we don't create hidden files, or files whose names start with a dash
|
||||
.replace(/^[\.\-]/, '');
|
||||
|
||||
// in case we've now stripped the entire basename (uncommon, but possible):
|
||||
basename = basename.length ? basename : '_';
|
||||
|
||||
return makeUniqueFilename(basename, str) + exports.fileExtension;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a longname's filename if one has been registered; otherwise, generate a unique filename, then
|
||||
* register the filename.
|
||||
* @private
|
||||
*/
|
||||
function getFilename(longname) {
|
||||
var fileUrl;
|
||||
|
||||
if ( hasOwnProp.call(longnameToUrl, longname) ) {
|
||||
fileUrl = longnameToUrl[longname];
|
||||
}
|
||||
else {
|
||||
fileUrl = getUniqueFilename(longname);
|
||||
registerLink(longname, fileUrl);
|
||||
}
|
||||
|
||||
return fileUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a symbol is the only symbol exported by a module (as in
|
||||
* `module.exports = function() {};`).
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/doclet.Doclet} doclet - The doclet for the symbol.
|
||||
* @return {boolean} `true` if the symbol is the only symbol exported by a module; otherwise,
|
||||
* `false`.
|
||||
*/
|
||||
function isModuleExports(doclet) {
|
||||
return doclet.longname && doclet.longname === doclet.name &&
|
||||
doclet.longname.indexOf(MODULE_NAMESPACE) === 0 && doclet.kind !== 'module';
|
||||
}
|
||||
|
||||
function makeUniqueId(filename, id) {
|
||||
var key;
|
||||
var nonUnique = true;
|
||||
|
||||
key = id.toLowerCase();
|
||||
|
||||
// HTML5 IDs cannot contain whitespace characters
|
||||
id = id.replace(/\s/g, '');
|
||||
|
||||
// append enough underscores to make the identifier unique
|
||||
while (nonUnique) {
|
||||
if ( hasOwnProp.call(ids, filename) && hasOwnProp.call(ids[filename], key) ) {
|
||||
id += '_';
|
||||
key = id.toLowerCase();
|
||||
}
|
||||
else {
|
||||
nonUnique = false;
|
||||
}
|
||||
}
|
||||
|
||||
ids[filename] = ids[filename] || {};
|
||||
ids[filename][key] = id;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a doclet's ID if one has been registered; otherwise, generate a unique ID, then register
|
||||
* the ID.
|
||||
* @private
|
||||
*/
|
||||
function getId(longname, id) {
|
||||
if ( hasOwnProp.call(longnameToId, longname) ) {
|
||||
id = longnameToId[longname];
|
||||
}
|
||||
else if (!id) {
|
||||
// no ID required
|
||||
return '';
|
||||
}
|
||||
else {
|
||||
id = makeUniqueId(longname, id);
|
||||
registerId(longname, id);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a doclet to an identifier that is unique for a specified filename.
|
||||
*
|
||||
* Identifiers are not considered unique if they are capitalized differently but are otherwise
|
||||
* identical.
|
||||
*
|
||||
* @method
|
||||
* @param {string} filename - The file in which the identifier will be used.
|
||||
* @param {string} doclet - The doclet to convert.
|
||||
* @return {string} A unique identifier based on the file and doclet.
|
||||
*/
|
||||
var getUniqueId = exports.getUniqueId = makeUniqueId;
|
||||
|
||||
var htmlsafe = exports.htmlsafe = function(str) {
|
||||
return str.replace(/&/g, '&')
|
||||
.replace(/</g, '<');
|
||||
};
|
||||
|
||||
function parseType(longname) {
|
||||
var err;
|
||||
|
||||
try {
|
||||
return catharsis.parse(longname, {jsdoc: true});
|
||||
}
|
||||
catch (e) {
|
||||
err = new Error('unable to parse ' + longname + ': ' + e.message);
|
||||
require('jsdoc/util/logger').error(err);
|
||||
return longname;
|
||||
}
|
||||
}
|
||||
|
||||
function stringifyType(parsedType, cssClass, linkMap) {
|
||||
return require('catharsis').stringify(parsedType, {
|
||||
cssClass: cssClass,
|
||||
htmlSafe: true,
|
||||
links: linkMap
|
||||
});
|
||||
}
|
||||
|
||||
function hasUrlPrefix(text) {
|
||||
return (/^(http|ftp)s?:\/\//).test(text);
|
||||
}
|
||||
|
||||
function isComplexTypeExpression(expr) {
|
||||
// record types, type unions, and type applications all count as "complex"
|
||||
return expr.search(/[{(|]/) !== -1 || expr.search(/</) > 0;
|
||||
}
|
||||
|
||||
function fragmentHash(fragmentId) {
|
||||
if (!fragmentId) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '#' + fragmentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an HTML link to the symbol with the specified longname. If the longname is not
|
||||
* associated with a URL, this method simply returns the link text, if provided, or the longname.
|
||||
*
|
||||
* The `longname` parameter can also contain a URL rather than a symbol's longname.
|
||||
*
|
||||
* This method supports type applications that can contain one or more types, such as
|
||||
* `Array.<MyClass>` or `Array.<(MyClass|YourClass)>`. In these examples, the method attempts to
|
||||
* replace `Array`, `MyClass`, and `YourClass` with links to the appropriate types. The link text
|
||||
* is ignored for type applications.
|
||||
*
|
||||
* @param {string} longname - The longname (or URL) that is the target of the link.
|
||||
* @param {string=} linkText - The text to display for the link, or `longname` if no text is
|
||||
* provided.
|
||||
* @param {Object} options - Options for building the link.
|
||||
* @param {string=} options.cssClass - The CSS class (or classes) to include in the link's `<a>`
|
||||
* tag.
|
||||
* @param {string=} options.fragmentId - The fragment identifier (for example, `name` in
|
||||
* `foo.html#name`) to append to the link target.
|
||||
* @param {string=} options.linkMap - The link map in which to look up the longname.
|
||||
* @param {boolean=} options.monospace - Indicates whether to display the link text in a monospace
|
||||
* font.
|
||||
* @return {string} The HTML link, or the link text if the link is not available.
|
||||
*/
|
||||
function buildLink(longname, linkText, options) {
|
||||
var classString = options.cssClass ? util.format(' class="%s"', options.cssClass) : '';
|
||||
var fileUrl;
|
||||
var fragmentString = fragmentHash(options.fragmentId);
|
||||
var stripped;
|
||||
var text;
|
||||
|
||||
var parsedType;
|
||||
|
||||
// handle cases like:
|
||||
// @see <http://example.org>
|
||||
// @see http://example.org
|
||||
stripped = longname ? longname.replace(/^<|>$/g, '') : '';
|
||||
if ( hasUrlPrefix(stripped) ) {
|
||||
fileUrl = stripped;
|
||||
text = linkText || stripped;
|
||||
}
|
||||
// handle complex type expressions that may require multiple links
|
||||
// (but skip anything that looks like an inline tag)
|
||||
else if (longname && isComplexTypeExpression(longname) && /\{\@.+\}/.test(longname) === false) {
|
||||
parsedType = parseType(longname);
|
||||
return stringifyType(parsedType, options.cssClass, options.linkMap);
|
||||
}
|
||||
else {
|
||||
fileUrl = hasOwnProp.call(options.linkMap, longname) ? options.linkMap[longname] : '';
|
||||
text = linkText || longname;
|
||||
}
|
||||
|
||||
text = options.monospace ? '<code>' + text + '</code>' : text;
|
||||
|
||||
if (!fileUrl) {
|
||||
return text;
|
||||
}
|
||||
else {
|
||||
return util.format('<a href="%s"%s>%s</a>', encodeURI(fileUrl + fragmentString),
|
||||
classString, text);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an HTML link to the symbol with the specified longname. If the longname is not
|
||||
* associated with a URL, this method simply returns the link text, if provided, or the longname.
|
||||
*
|
||||
* The `longname` parameter can also contain a URL rather than a symbol's longname.
|
||||
*
|
||||
* This method supports type applications that can contain one or more types, such as
|
||||
* `Array.<MyClass>` or `Array.<(MyClass|YourClass)>`. In these examples, the method attempts to
|
||||
* replace `Array`, `MyClass`, and `YourClass` with links to the appropriate types. The link text
|
||||
* is ignored for type applications.
|
||||
*
|
||||
* @param {string} longname - The longname (or URL) that is the target of the link.
|
||||
* @param {string=} linkText - The text to display for the link, or `longname` if no text is
|
||||
* provided.
|
||||
* @param {string=} cssClass - The CSS class (or classes) to include in the link's `<a>` tag.
|
||||
* @param {string=} fragmentId - The fragment identifier (for example, `name` in `foo.html#name`) to
|
||||
* append to the link target.
|
||||
* @return {string} The HTML link, or a plain-text string if the link is not available.
|
||||
*/
|
||||
var linkto = exports.linkto = function(longname, linkText, cssClass, fragmentId) {
|
||||
return buildLink(longname, linkText, {
|
||||
cssClass: cssClass,
|
||||
fragmentId: fragmentId,
|
||||
linkMap: longnameToUrl
|
||||
});
|
||||
};
|
||||
|
||||
function useMonospace(tag, text) {
|
||||
var cleverLinks;
|
||||
var monospaceLinks;
|
||||
var result;
|
||||
|
||||
if ( hasUrlPrefix(text) ) {
|
||||
result = false;
|
||||
}
|
||||
else if (tag === 'linkplain') {
|
||||
result = false;
|
||||
}
|
||||
else if (tag === 'linkcode') {
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
cleverLinks = env.conf.templates.cleverLinks;
|
||||
monospaceLinks = env.conf.templates.monospaceLinks;
|
||||
|
||||
if (monospaceLinks || cleverLinks) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
return result || false;
|
||||
}
|
||||
|
||||
function splitLinkText(text) {
|
||||
var linkText;
|
||||
var target;
|
||||
var splitIndex;
|
||||
|
||||
// if a pipe is not present, we split on the first space
|
||||
splitIndex = text.indexOf('|');
|
||||
if (splitIndex === -1) {
|
||||
splitIndex = text.search(/\s/);
|
||||
}
|
||||
|
||||
if (splitIndex !== -1) {
|
||||
linkText = text.substr(splitIndex + 1);
|
||||
// Normalize subsequent newlines to a single space.
|
||||
linkText = linkText.replace(/\n+/, ' ');
|
||||
target = text.substr(0, splitIndex);
|
||||
}
|
||||
|
||||
return {
|
||||
linkText: linkText,
|
||||
target: target || text
|
||||
};
|
||||
}
|
||||
|
||||
var tutorialToUrl = exports.tutorialToUrl = function(tutorial) {
|
||||
var fileUrl;
|
||||
var node = tutorials.getByName(tutorial);
|
||||
|
||||
// no such tutorial
|
||||
if (!node) {
|
||||
require('jsdoc/util/logger').error( new Error('No such tutorial: ' + tutorial) );
|
||||
return null;
|
||||
}
|
||||
|
||||
// define the URL if necessary
|
||||
if (!hasOwnProp.call(tutorialLinkMap.nameToUrl, node.name)) {
|
||||
fileUrl = 'tutorial-' + getUniqueFilename(node.name);
|
||||
tutorialLinkMap.nameToUrl[node.name] = fileUrl;
|
||||
tutorialLinkMap.urlToName[fileUrl] = node.name;
|
||||
}
|
||||
|
||||
return tutorialLinkMap.nameToUrl[node.name];
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve a link to a tutorial, or the name of the tutorial if the tutorial is missing. If the
|
||||
* `missingOpts` parameter is supplied, the names of missing tutorials will be prefixed by the
|
||||
* specified text and wrapped in the specified HTML tag and CSS class.
|
||||
*
|
||||
* @todo Deprecate missingOpts once we have a better error-reporting mechanism.
|
||||
* @param {string} tutorial The name of the tutorial.
|
||||
* @param {string} content The link text to use.
|
||||
* @param {object} [missingOpts] Options for displaying the name of a missing tutorial.
|
||||
* @param {string} missingOpts.classname The CSS class to wrap around the tutorial name.
|
||||
* @param {string} missingOpts.prefix The prefix to add to the tutorial name.
|
||||
* @param {string} missingOpts.tag The tag to wrap around the tutorial name.
|
||||
* @return {string} An HTML link to the tutorial, or the name of the tutorial with the specified
|
||||
* options.
|
||||
*/
|
||||
var toTutorial = exports.toTutorial = function(tutorial, content, missingOpts) {
|
||||
if (!tutorial) {
|
||||
require('jsdoc/util/logger').error( new Error('Missing required parameter: tutorial') );
|
||||
return null;
|
||||
}
|
||||
|
||||
var node = tutorials.getByName(tutorial);
|
||||
// no such tutorial
|
||||
if (!node) {
|
||||
missingOpts = missingOpts || {};
|
||||
var tag = missingOpts.tag;
|
||||
var classname = missingOpts.classname;
|
||||
|
||||
var link = tutorial;
|
||||
if (missingOpts.prefix) {
|
||||
link = missingOpts.prefix + link;
|
||||
}
|
||||
if (tag) {
|
||||
link = '<' + tag + (classname ? (' class="' + classname + '">') : '>') + link;
|
||||
link += '</' + tag + '>';
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
content = content || node.title;
|
||||
|
||||
return '<a href="' + tutorialToUrl(tutorial) + '">' + content + '</a>';
|
||||
};
|
||||
|
||||
/** Find symbol {@link ...} and {@tutorial ...} strings in text and turn into html links */
|
||||
exports.resolveLinks = function(str) {
|
||||
var replaceInlineTags = require('jsdoc/tag/inline').replaceInlineTags;
|
||||
|
||||
function extractLeadingText(string, completeTag) {
|
||||
var tagIndex = string.indexOf(completeTag);
|
||||
var leadingText = null;
|
||||
var leadingTextRegExp = /\[(.+?)\]/g;
|
||||
var leadingTextInfo = leadingTextRegExp.exec(string);
|
||||
|
||||
// did we find leading text, and if so, does it immediately precede the tag?
|
||||
while (leadingTextInfo && leadingTextInfo.length) {
|
||||
if (leadingTextInfo.index + leadingTextInfo[0].length === tagIndex) {
|
||||
string = string.replace(leadingTextInfo[0], '');
|
||||
leadingText = leadingTextInfo[1];
|
||||
break;
|
||||
}
|
||||
|
||||
leadingTextInfo = leadingTextRegExp.exec(string);
|
||||
}
|
||||
|
||||
return {
|
||||
leadingText: leadingText,
|
||||
string: string
|
||||
};
|
||||
}
|
||||
|
||||
function processLink(string, tagInfo) {
|
||||
var leading = extractLeadingText(string, tagInfo.completeTag);
|
||||
var linkText = leading.leadingText;
|
||||
var monospace;
|
||||
var split;
|
||||
var target;
|
||||
string = leading.string;
|
||||
|
||||
split = splitLinkText(tagInfo.text);
|
||||
target = split.target;
|
||||
linkText = linkText || split.linkText;
|
||||
|
||||
monospace = useMonospace(tagInfo.tag, tagInfo.text);
|
||||
|
||||
return string.replace( tagInfo.completeTag, buildLink(target, linkText, {
|
||||
linkMap: longnameToUrl,
|
||||
monospace: monospace
|
||||
}) );
|
||||
}
|
||||
|
||||
function processTutorial(string, tagInfo) {
|
||||
var leading = extractLeadingText(string, tagInfo.completeTag);
|
||||
string = leading.string;
|
||||
|
||||
return string.replace( tagInfo.completeTag, toTutorial(tagInfo.text, leading.leadingText) );
|
||||
}
|
||||
|
||||
var replacers = {
|
||||
link: processLink,
|
||||
linkcode: processLink,
|
||||
linkplain: processLink,
|
||||
tutorial: processTutorial
|
||||
};
|
||||
|
||||
return replaceInlineTags(str, replacers).newString;
|
||||
};
|
||||
|
||||
/** Convert tag text like "Jane Doe <jdoe@example.org>" into a mailto link */
|
||||
exports.resolveAuthorLinks = function(str) {
|
||||
var author;
|
||||
var matches = str.match(/^\s?([\s\S]+)\b\s+<(\S+@\S+)>\s?$/);
|
||||
if (matches && matches.length === 3) {
|
||||
author = '<a href="mailto:' + matches[2] + '">' + htmlsafe(matches[1]) + '</a>';
|
||||
}
|
||||
else {
|
||||
author = htmlsafe(str);
|
||||
}
|
||||
|
||||
return author;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find items in a TaffyDB database that match the specified key-value pairs.
|
||||
* @param {TAFFY} data The TaffyDB database to search.
|
||||
* @param {object|function} spec Key-value pairs to match against (for example,
|
||||
* `{ longname: 'foo' }`), or a function that returns `true` if a value matches or `false` if it
|
||||
* does not match.
|
||||
* @return {array<object>} The matching items.
|
||||
*/
|
||||
var find = exports.find = function(data, spec) {
|
||||
return data(spec).get();
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve all of the following types of members from a set of doclets:
|
||||
*
|
||||
* + Classes
|
||||
* + Externals
|
||||
* + Globals
|
||||
* + Mixins
|
||||
* + Modules
|
||||
* + Namespaces
|
||||
* + Events
|
||||
* @param {TAFFY} data The TaffyDB database to search.
|
||||
* @return {object} An object with `classes`, `externals`, `globals`, `mixins`, `modules`,
|
||||
* `events`, and `namespaces` properties. Each property contains an array of objects.
|
||||
*/
|
||||
exports.getMembers = function(data) {
|
||||
var members = {
|
||||
classes: find( data, {kind: 'class'} ),
|
||||
externals: find( data, {kind: 'external'} ),
|
||||
events: find( data, {kind: 'event'} ),
|
||||
globals: find(data, {
|
||||
kind: ['member', 'function', 'constant', 'typedef'],
|
||||
memberof: { isUndefined: true }
|
||||
}),
|
||||
mixins: find( data, {kind: 'mixin'} ),
|
||||
modules: find( data, {kind: 'module'} ),
|
||||
namespaces: find( data, {kind: 'namespace'} ),
|
||||
interfaces: find( data, {kind: 'interface'} )
|
||||
};
|
||||
|
||||
// strip quotes from externals, since we allow quoted names that would normally indicate a
|
||||
// namespace hierarchy (as in `@external "jquery.fn"`)
|
||||
// TODO: we should probably be doing this for other types of symbols, here or elsewhere; see
|
||||
// jsdoc3/jsdoc#396
|
||||
members.externals = members.externals.map(function(doclet) {
|
||||
doclet.name = doclet.name.replace(/(^"|"$)/g, '');
|
||||
return doclet;
|
||||
});
|
||||
|
||||
// functions that are also modules (as in `module.exports = function() {};`) are not globals
|
||||
members.globals = members.globals.filter(function(doclet) {
|
||||
return !isModuleExports(doclet);
|
||||
});
|
||||
|
||||
return members;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the member attributes for a doclet (for example, `virtual`, `static`, and
|
||||
* `readonly`).
|
||||
* @param {object} d The doclet whose attributes will be retrieved.
|
||||
* @return {array<string>} The member attributes for the doclet.
|
||||
*/
|
||||
exports.getAttribs = function(d) {
|
||||
var attribs = [];
|
||||
|
||||
if (!d) {
|
||||
return attribs;
|
||||
}
|
||||
|
||||
if (d.virtual) {
|
||||
attribs.push('abstract');
|
||||
}
|
||||
|
||||
if (d.access && d.access !== 'public') {
|
||||
attribs.push(d.access);
|
||||
}
|
||||
|
||||
if (d.scope && d.scope !== 'instance' && d.scope !== name.SCOPE.NAMES.GLOBAL) {
|
||||
if (d.kind === 'function' || d.kind === 'member' || d.kind === 'constant') {
|
||||
attribs.push(d.scope);
|
||||
}
|
||||
}
|
||||
|
||||
if (d.readonly === true) {
|
||||
if (d.kind === 'member') {
|
||||
attribs.push('readonly');
|
||||
}
|
||||
}
|
||||
|
||||
if (d.kind === 'constant') {
|
||||
attribs.push('constant');
|
||||
}
|
||||
|
||||
if (d.nullable === true) {
|
||||
attribs.push('nullable');
|
||||
}
|
||||
else if (d.nullable === false) {
|
||||
attribs.push('non-null');
|
||||
}
|
||||
|
||||
return attribs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve links to allowed types for the member.
|
||||
*
|
||||
* @param {Object} d - The doclet whose types will be retrieved.
|
||||
* @param {string} [cssClass] - The CSS class to include in the `class` attribute for each link.
|
||||
* @return {Array.<string>} HTML links to allowed types for the member.
|
||||
*/
|
||||
exports.getSignatureTypes = function(d, cssClass) {
|
||||
var types = [];
|
||||
|
||||
if (d.type && d.type.names) {
|
||||
types = d.type.names;
|
||||
}
|
||||
|
||||
if (types && types.length) {
|
||||
types = types.map(function(t) {
|
||||
return linkto(t, htmlsafe(t), cssClass);
|
||||
});
|
||||
}
|
||||
|
||||
return types;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve names of the parameters that the member accepts. If a value is provided for `optClass`,
|
||||
* the names of optional parameters will be wrapped in a `<span>` tag with that class.
|
||||
* @param {object} d The doclet whose parameter names will be retrieved.
|
||||
* @param {string} [optClass] The class to assign to the `<span>` tag that is wrapped around the
|
||||
* names of optional parameters. If a value is not provided, optional parameter names will not be
|
||||
* wrapped with a `<span>` tag. Must be a legal value for a CSS class name.
|
||||
* @return {array<string>} An array of parameter names, with or without `<span>` tags wrapping the
|
||||
* names of optional parameters.
|
||||
*/
|
||||
exports.getSignatureParams = function(d, optClass) {
|
||||
var pnames = [];
|
||||
|
||||
if (d.params) {
|
||||
d.params.forEach(function(p) {
|
||||
if (p.name && p.name.indexOf('.') === -1) {
|
||||
if (p.optional && optClass) {
|
||||
pnames.push('<span class="' + optClass + '">' + p.name + '</span>');
|
||||
}
|
||||
else {
|
||||
pnames.push(p.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return pnames;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve links to types that the member can return.
|
||||
*
|
||||
* @param {Object} d - The doclet whose types will be retrieved.
|
||||
* @param {string} [cssClass] - The CSS class to include in the `class` attribute for each link.
|
||||
* @return {Array.<string>} HTML links to types that the member can return.
|
||||
*/
|
||||
exports.getSignatureReturns = function(d, cssClass) {
|
||||
var returnTypes = [];
|
||||
|
||||
if (d.returns) {
|
||||
d.returns.forEach(function(r) {
|
||||
if (r && r.type && r.type.names) {
|
||||
if (!returnTypes.length) {
|
||||
returnTypes = r.type.names;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (returnTypes && returnTypes.length) {
|
||||
returnTypes = returnTypes.map(function(r) {
|
||||
return linkto(r, htmlsafe(r), cssClass);
|
||||
});
|
||||
}
|
||||
|
||||
return returnTypes;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve an ordered list of doclets for a symbol's ancestors.
|
||||
*
|
||||
* @param {TAFFY} data - The TaffyDB database to search.
|
||||
* @param {Object} doclet - The doclet whose ancestors will be retrieved.
|
||||
* @return {Array.<module:jsdoc/doclet.Doclet>} A array of ancestor doclets, sorted from most to
|
||||
* least distant.
|
||||
*/
|
||||
exports.getAncestors = function(data, doclet) {
|
||||
var ancestors = [];
|
||||
var doc = doclet;
|
||||
|
||||
while (doc) {
|
||||
doc = find(data, {longname: doc.memberof})[0];
|
||||
|
||||
if (doc) {
|
||||
ancestors.unshift(doc);
|
||||
}
|
||||
}
|
||||
|
||||
return ancestors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve links to a member's ancestors.
|
||||
*
|
||||
* @param {TAFFY} data - The TaffyDB database to search.
|
||||
* @param {Object} doclet - The doclet whose ancestors will be retrieved.
|
||||
* @param {string} [cssClass] - The CSS class to include in the `class` attribute for each link.
|
||||
* @return {Array.<string>} HTML links to a member's ancestors.
|
||||
*/
|
||||
exports.getAncestorLinks = function(data, doclet, cssClass) {
|
||||
var ancestors = exports.getAncestors(data, doclet);
|
||||
var links = [];
|
||||
|
||||
ancestors.forEach(function(ancestor) {
|
||||
var linkText = (exports.scopeToPunc[ancestor.scope] || '') + ancestor.name;
|
||||
var link = linkto(ancestor.longname, linkText, cssClass);
|
||||
links.push(link);
|
||||
});
|
||||
|
||||
if (links.length) {
|
||||
links[links.length - 1] += (exports.scopeToPunc[doclet.scope] || '');
|
||||
}
|
||||
|
||||
return links;
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates through all the doclets in `data`, ensuring that if a method
|
||||
* @listens to an event, then that event has a 'listeners' array with the
|
||||
* longname of the listener in it.
|
||||
*
|
||||
* @param {TAFFY} data - The TaffyDB database to search.
|
||||
*/
|
||||
exports.addEventListeners = function(data) {
|
||||
// TODO: do this on the *pruned* data
|
||||
// find all doclets that @listen to something.
|
||||
var listeners = find(data, function () { return this.listens && this.listens.length; });
|
||||
|
||||
if (!listeners.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var doc,
|
||||
l,
|
||||
_events = {}; // just a cache to prevent me doing so many lookups
|
||||
|
||||
listeners.forEach(function (listener) {
|
||||
l = listener.listens;
|
||||
l.forEach(function (eventLongname) {
|
||||
doc = _events[eventLongname] || find(data, {longname: eventLongname, kind: 'event'})[0];
|
||||
if (doc) {
|
||||
if (!doc.listeners) {
|
||||
doc.listeners = [listener.longname];
|
||||
} else {
|
||||
doc.listeners.push(listener.longname);
|
||||
}
|
||||
_events[eventLongname] = _events[eventLongname] || doc;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove members that will not be included in the output, including:
|
||||
*
|
||||
* + Undocumented members.
|
||||
* + Members tagged `@ignore`.
|
||||
* + Members of anonymous classes.
|
||||
* + Members tagged `@private`, unless the `private` option is enabled.
|
||||
* @param {TAFFY} data The TaffyDB database to prune.
|
||||
* @return {TAFFY} The pruned database.
|
||||
*/
|
||||
exports.prune = function(data) {
|
||||
data({undocumented: true}).remove();
|
||||
data({ignore: true}).remove();
|
||||
if (!env.opts.private) { data({access: 'private'}).remove(); }
|
||||
data({memberof: '<anonymous>'}).remove();
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a URL that points to the generated documentation for the doclet.
|
||||
*
|
||||
* If a doclet corresponds to an output file (for example, if the doclet represents a class), the
|
||||
* URL will consist of a filename.
|
||||
*
|
||||
* If a doclet corresponds to a smaller portion of an output file (for example, if the doclet
|
||||
* represents a method), the URL will consist of a filename and a fragment ID.
|
||||
*
|
||||
* @param {module:jsdoc/doclet.Doclet} doclet - The doclet that will be used to create the URL.
|
||||
* @return {string} The URL to the generated documentation for the doclet.
|
||||
*/
|
||||
exports.createLink = function(doclet) {
|
||||
var fakeContainer;
|
||||
var filename;
|
||||
var fileUrl;
|
||||
var fragment = '';
|
||||
var longname = doclet.longname;
|
||||
var match;
|
||||
|
||||
// handle doclets in which doclet.longname implies that the doclet gets its own HTML file, but
|
||||
// doclet.kind says otherwise. this happens due to mistagged JSDoc (for example, a module that
|
||||
// somehow has doclet.kind set to `member`).
|
||||
// TODO: generate a warning (ideally during parsing!)
|
||||
if (containers.indexOf(doclet.kind) === -1) {
|
||||
match = /(\S+):/.exec(longname);
|
||||
if (match && containers.indexOf(match[1]) !== -1) {
|
||||
fakeContainer = match[1];
|
||||
}
|
||||
}
|
||||
|
||||
// the doclet gets its own HTML file
|
||||
if ( containers.indexOf(doclet.kind) !== -1 || isModuleExports(doclet) ) {
|
||||
filename = getFilename(longname);
|
||||
}
|
||||
// mistagged version of a doclet that gets its own HTML file
|
||||
else if ( containers.indexOf(doclet.kind) === -1 && fakeContainer ) {
|
||||
filename = getFilename(doclet.memberof || longname);
|
||||
if (doclet.name !== doclet.longname) {
|
||||
fragment = formatNameForLink(doclet);
|
||||
fragment = getId(longname, fragment);
|
||||
}
|
||||
}
|
||||
// the doclet is within another HTML file
|
||||
else {
|
||||
filename = getFilename(doclet.memberof || exports.globalName);
|
||||
if ( (doclet.name !== doclet.longname) || (doclet.scope === name.SCOPE.NAMES.GLOBAL) ) {
|
||||
fragment = formatNameForLink(doclet);
|
||||
fragment = getId(longname, fragment);
|
||||
}
|
||||
}
|
||||
|
||||
fileUrl = encodeURI( filename + fragmentHash(fragment) );
|
||||
|
||||
return fileUrl;
|
||||
};
|
||||
|
||||
// TODO: docs
|
||||
exports.longnamesToTree = name.longnamesToTree;
|
||||
|
||||
/**
|
||||
* Replace the existing tag dictionary with a new tag dictionary.
|
||||
*
|
||||
* Used for testing only. Do not call this method directly. Instead, call
|
||||
* {@link module:jsdoc/doclet._replaceDictionary}, which also updates this module's tag dictionary.
|
||||
*
|
||||
* @private
|
||||
* @param {module:jsdoc/tag/dictionary.Dictionary} dict - The new tag dictionary.
|
||||
*/
|
||||
exports._replaceDictionary = function _replaceDictionary(dict) {
|
||||
dictionary = dict;
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var stream = require('stream');
|
||||
var wrench = require('wrench');
|
||||
|
||||
var toDir = exports.toDir = function(_path) {
|
||||
var isDirectory;
|
||||
|
||||
_path = path.normalize(_path);
|
||||
|
||||
try {
|
||||
isDirectory = fs.statSync(_path).isDirectory();
|
||||
}
|
||||
catch(e) {
|
||||
isDirectory = false;
|
||||
}
|
||||
|
||||
if (isDirectory) {
|
||||
return _path;
|
||||
} else {
|
||||
return path.dirname(_path);
|
||||
}
|
||||
};
|
||||
|
||||
exports.mkPath = function(/**Array*/ _path) {
|
||||
if ( Array.isArray(_path) ) {
|
||||
_path = _path.join('');
|
||||
}
|
||||
|
||||
wrench.mkdirSyncRecursive(_path);
|
||||
};
|
||||
|
||||
// adapted from http://procbits.com/2011/11/15/synchronous-file-copy-in-node-js
|
||||
exports.copyFileSync = function(inFile, outDir, fileName) {
|
||||
var BUF_LENGTH = 64 * 1024;
|
||||
|
||||
var read;
|
||||
var write;
|
||||
|
||||
var buffer = new Buffer(BUF_LENGTH);
|
||||
var bytesRead = 1;
|
||||
var outFile = path.join( outDir, fileName || path.basename(inFile) );
|
||||
var pos = 0;
|
||||
|
||||
wrench.mkdirSyncRecursive(outDir);
|
||||
read = fs.openSync(inFile, 'r');
|
||||
write = fs.openSync(outFile, 'w');
|
||||
|
||||
while (bytesRead > 0) {
|
||||
bytesRead = fs.readSync(read, buffer, 0, BUF_LENGTH, pos);
|
||||
fs.writeSync(write, buffer, 0, bytesRead);
|
||||
pos += bytesRead;
|
||||
}
|
||||
|
||||
fs.closeSync(read);
|
||||
return fs.closeSync(write);
|
||||
};
|
||||
|
||||
Object.keys(fs).forEach(function(key) {
|
||||
exports[key] = fs[key];
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "jsdoc",
|
||||
"version": "3.3.0-alpha13",
|
||||
"revision": "1419376892674",
|
||||
"description": "An API documentation generator for JavaScript.",
|
||||
"keywords": [
|
||||
"documentation",
|
||||
"javascript"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jsdoc3/jsdoc"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.1.22",
|
||||
"catharsis": "~0.8.5",
|
||||
"escape-string-regexp": "~1.0.0",
|
||||
"esprima": "https://github.com/ariya/esprima/tarball/49a2eccb243f29bd653b11e9419241a9d726af7c",
|
||||
"js2xmlparser": "~0.1.0",
|
||||
"marked": "~0.3.1",
|
||||
"requizzle": "~0.2.0",
|
||||
"strip-json-comments": "~0.1.3",
|
||||
"taffydb": "https://github.com/hegemonic/taffydb/tarball/master",
|
||||
"underscore": "~1.6.0",
|
||||
"wrench": "~1.3.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "~0.10.2",
|
||||
"gulp": "~3.8.5",
|
||||
"gulp-eslint": "~0.1.7",
|
||||
"gulp-json-editor": "~2.0.2",
|
||||
"istanbul": "~0.2.1",
|
||||
"tv4": "https://github.com/hegemonic/tv4/tarball/own-properties"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "gulp test"
|
||||
},
|
||||
"bin": {
|
||||
"jsdoc": "./jsdoc.js"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/jsdoc3/jsdoc/issues"
|
||||
},
|
||||
"author": {
|
||||
"name": "Michael Mathews",
|
||||
"email": "micmath@gmail.com"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"url": "https://github.com/jsdoc3/jsdoc/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "kzh",
|
||||
"email": "kaleb@hornsby.ws"
|
||||
},
|
||||
{
|
||||
"name": "hegemonic",
|
||||
"email": "jeffrey.l.williams@gmail.com"
|
||||
}
|
||||
],
|
||||
"gitHead": "3d17a1642a105d854ffad9758d43661b3b6e17f2",
|
||||
"homepage": "https://github.com/jsdoc3/jsdoc",
|
||||
"_id": "jsdoc@3.3.0-alpha13",
|
||||
"_shasum": "ad64b989a4f6fbef3112ab1ee80908328a4ebfd2",
|
||||
"_from": "jsdoc@<=3.3.0",
|
||||
"_npmVersion": "1.4.28",
|
||||
"_npmUser": {
|
||||
"name": "hegemonic",
|
||||
"email": "jeffrey.l.williams@gmail.com"
|
||||
},
|
||||
"dist": {
|
||||
"shasum": "ad64b989a4f6fbef3112ab1ee80908328a4ebfd2",
|
||||
"tarball": "http://registry.npmjs.org/jsdoc/-/jsdoc-3.3.0-alpha13.tgz"
|
||||
},
|
||||
"directories": {},
|
||||
"_resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.3.0-alpha13.tgz",
|
||||
"readme": "ERROR: No README data found!"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
@overview Demonstrate how to modify the source code before the parser sees it.
|
||||
@module plugins/commentConvert
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
/*eslint spaced-line-comment: 0 */
|
||||
|
||||
exports.handlers = {
|
||||
///
|
||||
/// Convert ///-style comments into jsdoc comments.
|
||||
/// @param e
|
||||
/// @param e.filename
|
||||
/// @param e.source
|
||||
///
|
||||
beforeParse: function(e) {
|
||||
e.source = e.source.replace(/(\n[ \t]*\/\/\/[^\n]*)+/g, function($) {
|
||||
var replacement = '\n/**' + $.replace(/^[ \t]*\/\/\//mg, '').replace(/(\n$|$)/, '*/$1');
|
||||
return replacement;
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @overview Remove everything in a file except JSDoc-style comments. By enabling this plugin, you
|
||||
* can document source files that are not valid JavaScript (including source files for other
|
||||
* languages).
|
||||
* @module plugins/commentsOnly
|
||||
* @author Jeff Williams <jeffrey.l.williams@gmail.com>
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
exports.handlers = {
|
||||
beforeParse: function(e) {
|
||||
// a JSDoc comment looks like: /**[one or more chars]*/
|
||||
var comments = e.source.match(/\/\*\*[\s\S]+?\*\//g);
|
||||
if (comments) {
|
||||
e.source = comments.join('\n\n');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
@overview Escape HTML tags in descriptions.
|
||||
@module plugins/escapeHtml
|
||||
@author Michael Mathews <micmath@gmail.com>
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
exports.handlers = {
|
||||
/**
|
||||
Translate HTML tags in descriptions into safe entities.
|
||||
Replaces <, & and newlines
|
||||
*/
|
||||
newDoclet: function(e) {
|
||||
if (e.doclet.description) {
|
||||
e.doclet.description = e.doclet.description
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/\r\n|\n|\r/g, '<br>');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,115 @@
|
||||
/*global env: true */
|
||||
/**
|
||||
* @overview Dump information about parser events to the console.
|
||||
* @module plugins/eventDumper
|
||||
* @author Jeff Williams <jeffrey.l.williams@gmail.com>
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var _ = require('underscore');
|
||||
var util = require('util');
|
||||
|
||||
var conf = env.conf.eventDumper || {};
|
||||
var isRhino = require('jsdoc/util/runtime').isRhino();
|
||||
|
||||
// Dump the included parser events (defaults to all events)
|
||||
var events = conf.include || [
|
||||
'parseBegin',
|
||||
'fileBegin',
|
||||
'beforeParse',
|
||||
'jsdocCommentFound',
|
||||
'symbolFound',
|
||||
'newDoclet',
|
||||
'fileComplete',
|
||||
'parseComplete',
|
||||
'processingComplete'
|
||||
];
|
||||
// Don't dump the excluded parser events
|
||||
if (conf.exclude) {
|
||||
events = _.difference(events, conf.exclude);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a variable appears to be a Java native object.
|
||||
*
|
||||
* @param {*} o - The variable to check.
|
||||
* @return {boolean} Set to `true` for Java native objects and `false` in all other cases.
|
||||
*/
|
||||
function isJavaNativeObject(o) {
|
||||
if (!isRhino) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return o && typeof o === 'object' && typeof o.getClass === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace AST node objects in events with a placeholder.
|
||||
*
|
||||
* @param {Object} o - An object whose properties may contain AST node objects.
|
||||
* @return {Object} The modified object.
|
||||
*/
|
||||
function replaceNodeObjects(o) {
|
||||
var doop = require('jsdoc/util/doop');
|
||||
|
||||
var OBJECT_PLACEHOLDER = '<Object>';
|
||||
|
||||
if (o.code && o.code.node) {
|
||||
// don't break the original object!
|
||||
o.code = doop(o.code);
|
||||
o.code.node = OBJECT_PLACEHOLDER;
|
||||
}
|
||||
|
||||
if (o.doclet && o.doclet.meta && o.doclet.meta.code && o.doclet.meta.code.node) {
|
||||
// don't break the original object!
|
||||
o.doclet.meta.code = doop(o.doclet.meta.code);
|
||||
o.doclet.meta.code.node = OBJECT_PLACEHOLDER;
|
||||
}
|
||||
|
||||
if (o.astnode) {
|
||||
o.astnode = OBJECT_PLACEHOLDER;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rid of unwanted crud in an event object.
|
||||
*
|
||||
* @param {object} e The event object.
|
||||
* @return {object} The fixed-up object.
|
||||
*/
|
||||
function cleanse(e) {
|
||||
var result = {};
|
||||
|
||||
Object.keys(e).forEach(function(prop) {
|
||||
// by default, don't stringify properties that contain an array of functions
|
||||
if (!conf.includeFunctions && util.isArray(e[prop]) && e[prop][0] &&
|
||||
String(typeof e[prop][0]) === 'function') {
|
||||
result[prop] = 'function[' + e[prop].length + ']';
|
||||
}
|
||||
// never include functions that belong to the object
|
||||
else if (typeof e[prop] !== 'function') {
|
||||
// don't call JSON.stringify() on Java native objects--Rhino will throw an exception
|
||||
result[prop] = isJavaNativeObject(e[prop]) ? String(e[prop]) : e[prop];
|
||||
}
|
||||
});
|
||||
|
||||
// allow users to omit node objects, which can be enormous
|
||||
if (conf.omitNodes) {
|
||||
result = replaceNodeObjects(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
exports.handlers = {};
|
||||
|
||||
events.forEach(function(eventType) {
|
||||
exports.handlers[eventType] = function(e) {
|
||||
console.log( JSON.stringify({
|
||||
type: eventType,
|
||||
content: cleanse(e)
|
||||
}, null, 4) );
|
||||
};
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user