├── .gitignore ├── .jsbeautifyrc ├── .jsdoccerrc ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── README.md ├── bin ├── doc.js └── stub.js ├── package.json ├── src ├── jsdoccer.js ├── parsers │ ├── ast-to-json-pre.js │ ├── js-to-ast.js │ ├── json-api-to-docs.js │ ├── json-pre-to-yaml-stubbed.js │ └── yaml-documented-to-json-api.js ├── syntax-targets │ ├── class │ │ ├── linter.js │ │ ├── matcher.js │ │ ├── templateHtml.js │ │ ├── templateYaml.js │ │ └── templates │ │ │ ├── html.hbs │ │ │ └── yaml.tpl │ ├── constructor │ ├── docs-index.hbs │ ├── events │ │ ├── linter.js │ │ ├── matcher.js │ │ ├── templateHtml.js │ │ ├── templateYaml.js │ │ └── templates │ │ │ ├── html.hbs │ │ │ └── yaml.tpl │ ├── functions │ │ ├── linter.js │ │ ├── matcher.js │ │ ├── templateHtml.js │ │ ├── templateYaml.js │ │ └── templates │ │ │ ├── html.hbs │ │ │ └── yaml.tpl │ ├── name │ │ ├── linter.js │ │ ├── matcher.js │ │ ├── templateHtml.js │ │ ├── templateYaml.js │ │ └── templates │ │ │ ├── html.hbs │ │ │ └── yaml.tpl │ └── properties │ │ ├── linter.js │ │ ├── matcher.js │ │ ├── templateHtml.js │ │ ├── templateYaml.js │ │ └── templates │ │ ├── html.hbs │ │ └── yaml.tpl └── util │ ├── config-loader.js │ ├── file-globber.js │ ├── html-template-loader.js │ ├── json-walker.js │ ├── node-stack-tracer.js │ ├── registry.js │ └── yaml-template-loader.js ├── styles └── api.css ├── stylesheets ├── api.scss └── api │ └── _highlight_tomorrow.scss └── test ├── .jsdoccerrc-test ├── mocha.opts ├── mock-files ├── ast │ └── application.json ├── docs │ └── application.html ├── js │ ├── application.js │ └── test.js ├── json-api │ └── application.json ├── json-pre │ └── application.json ├── yaml-documented │ └── application.yaml └── yaml-stubbed │ └── application.yaml └── specs └── src ├── jsdoccer-spec.js └── parsers ├── ast-to-json-pre-spec.js ├── js-to-ast-spec.js ├── json-api-to-docs-spec.js ├── json-pre-to-yaml-stubbed-spec.js └── yaml-documented-to-json-api-spec.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *.swo 4 | *.orig 5 | tmp/ 6 | ext/ 7 | node_modules/ 8 | coverage/ 9 | .grunt/ 10 | npm-debug.log 11 | bower_components/ 12 | .grunt 13 | reports 14 | jsdoccer/ 15 | doccer/ 16 | api/ 17 | pad.js 18 | .sass-cache 19 | -------------------------------------------------------------------------------- /.jsbeautifyrc: -------------------------------------------------------------------------------- 1 | { 2 | // Details: https://github.com/victorporof/Sublime-HTMLPrettify#using-your-own-jsbeautifyrc-options 3 | // Documentation: https://github.com/einars/js-beautify/ 4 | 5 | "js": { 6 | "allowed_file_extensions": ["js", "json", "jshintrc", "jsbeautifyrc"], 7 | "brace_style": "collapse", // "expand", "end-expand", "expand-strict" 8 | "break_chained_methods": false, 9 | "e4x": false, 10 | "eval_code": false, 11 | "indent_char": " ", 12 | "indent_level": 0, 13 | "indent_size": 4, 14 | "indent_with_tabs": true, 15 | "jslint_happy": true, 16 | "keep_array_indentation": true, 17 | "keep_function_indentation": false, 18 | "max_preserve_newlines": 10, 19 | "preserve_newlines": true, 20 | "space_before_conditional": true, 21 | "space_in_paren": false, 22 | "unescape_strings": false, 23 | "wrap_line_length": 0 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.jsdoccerrc: -------------------------------------------------------------------------------- 1 | { 2 | // Note: all comments are striped before this file is parsed. 3 | // if null the project name will be pulled from the root dir name 4 | "projectName": null, 5 | 6 | "js": { 7 | // glob paths to the js you want to document 8 | "src": ["./src/jsdoccer.js", "./src/parsers/*.js"] 9 | }, 10 | 11 | "documentedYaml": { 12 | // Glob paths to your documented yaml. 13 | "src": ["./doccer/intermediate/yaml-documented/*.yaml"] 14 | }, 15 | 16 | // All generated intermediate files will be placed under this path. 17 | "dest": "./doccer/", 18 | 19 | // Syntax targets 20 | "targets": { 21 | "default": { 22 | "name": true, 23 | "class": true, 24 | "constructor": true, 25 | "events": true, 26 | "properties": true, 27 | "functions": true 28 | }, 29 | "custom": { 30 | // Add custom targets here. Example: 31 | // "customTarget1": true, 32 | // "customTarget2": true 33 | }, 34 | "customTargetsPath": "./customSyntaxTargets/" 35 | } 36 | } -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "sub": true, 3 | "node": true, 4 | "browser": true, 5 | "esnext": true, 6 | "bitwise": true, 7 | "camelcase": false, 8 | "curly": true, 9 | "eqeqeq": true, 10 | "immed": false, 11 | "indent": false, 12 | "latedef": true, 13 | "newcap": true, 14 | "noarg": true, 15 | "quotmark": "single", 16 | "regexp": true, 17 | "undef": true, 18 | "unused": false, 19 | "strict": true, 20 | "trailing": true, 21 | "smarttabs": true, 22 | "jquery": true, 23 | "globals": { 24 | "define": true, 25 | "Backbone": true, 26 | "_": true, 27 | "Marionette": true, 28 | "NimbleChef": true, 29 | "waitsFor": true, 30 | "it": true, 31 | "describe": true, 32 | "expect": true, 33 | "beforeEach": true, 34 | "afterEach": true, 35 | "spyOn": true, 36 | "done": true, 37 | "module": true, 38 | "require": true, 39 | "console": true 40 | } 41 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.11" 4 | - "0.10" 5 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt) { 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | 7 | jshint: { 8 | files: ['./src/**/*.js'], 9 | // configure JSHint (documented at http://www.jshint.com/docs/) 10 | options: { 11 | jshintrc: '.jshintrc', 12 | reporter: require('jshint-stylish') 13 | } 14 | }, 15 | 16 | watch: { 17 | files: ['<%= jshint.files %>'], 18 | tasks: ['jshint', 'jasmine_node'] 19 | }, 20 | 21 | clean: { 22 | build: ['./ast/*', './jsdoc/*', './json/*', './yaml/*'] 23 | }, 24 | 25 | jasmine_node: { 26 | coverage: {}, 27 | options: { 28 | forceExit: true, 29 | match: '.', 30 | matchall: false, 31 | extensions: 'js', 32 | specNameMatcher: 'spec', 33 | jUnit: { 34 | report: true, 35 | savePath: './build/reports/jasmine/', 36 | useDotNotation: true, 37 | consolidate: true 38 | } 39 | }, 40 | all: ['tests/specs/'] 41 | }, 42 | 43 | plato: { 44 | report: { 45 | options: { 46 | jshint: grunt.file.readJSON('.jshintrc') 47 | }, 48 | files: { 49 | reports: ['syntax-matchers.js', '<%= jshint.files %>'] 50 | } 51 | } 52 | }, 53 | 54 | sass: { 55 | options: { 56 | compass: true 57 | }, 58 | dist: { 59 | files: { 60 | 'styles/api.css': 'stylesheets/api.scss' 61 | } 62 | } 63 | }, 64 | 65 | 'jsDoccerYaml': { 66 | doc: { 67 | options: { 68 | filesToFilter: [ 69 | '.DS_Store', 70 | 'filter-this.js' 71 | ] 72 | }, 73 | files: [{ 74 | expand: true, 75 | src: 'js/*.js', 76 | }] 77 | } 78 | } 79 | }); 80 | 81 | grunt.loadTasks('tasks'); 82 | grunt.loadNpmTasks('grunt-contrib-jshint'); 83 | grunt.loadNpmTasks('grunt-contrib-watch'); 84 | grunt.loadNpmTasks('grunt-jasmine-node-coverage'); 85 | grunt.loadNpmTasks('grunt-jasmine-node'); 86 | grunt.loadNpmTasks('grunt-plato'); 87 | grunt.loadNpmTasks('grunt-contrib-clean'); 88 | grunt.loadNpmTasks('grunt-contrib-sass'); 89 | 90 | grunt.registerTask('test', 'Lint, hint, test, coverage, and complexity.', ['jshint', 'jasmine_node']); 91 | grunt.registerTask('default', 'Run test suite.', ['jasmine_node']); 92 | grunt.registerTask('build', 'build sass', ['sass']); 93 | }; 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/ChetHarrison/jsdoccer.svg?branch=master)](https://travis-ci.org/ChetHarrison/jsdoccer) 2 | 3 | #### Goals: 4 | - [x] generate stubbed YAML documentation template 5 | - [x] build document webpages from JSDoc 6 | - [ ] lint existing documents 7 | 8 | **There have been some major changes between 1.0, 1.1, 1.2 and 1.3. This is a pure Node.js tool. If you are looking for a Grunt task you can find it at [grunt-jsdoccer](https://github.com/ChetHarrison/grunt-jsdoccer). 9 | 10 | A collaboration with [@jasonLaster](https://github.com/jasonLaster) 11 | 12 | # JsDoccer 13 | 14 | (OK a tool that documents your code should have some **REALLY** good docs right?. But I'm working on getting that live so, imagine that icon with the man shoveling stuff) 15 | 16 | A collection of Node.js tasks to: 17 | 18 | * Auto-document your ECMAScript (Java Script) using [Esprima](http://esprima.org/) It converts your code into YAML templates that allows you to fill in stubbed examples and descriptions using [JSDoc 3](https://github.com/jsdoc3/jsdoc3.github.com) sintax. 19 | * Convert the those YAML files to HTML docs. 20 | * Lint those docs to keep them up to date. 21 | 22 | 23 | ### Basic Usage 24 | 25 | Setup 26 | 27 | ``` 28 | $ npm install jsdoccer 29 | ``` 30 | 31 | 1) Create stubbed YAML document templates. 32 | 33 | ``` 34 | $ ./node_modules/.bin/stub [] 35 | ``` 36 | 37 | This will generate 'ast', 'json-pre', and 'yaml-stubbed' files in the `intermediate` directory under the the `dest` argument in your `.jsdoccerrc` config file. At the moment you will want to copy your YAML stubs to a different directory __before you add examples and descriptions__ so you don't overwrite your files if you rerun the stub task. You will want to place them in the directory configured in the `.jsdoccerrc` file under the `documentedYaml` arg. The default is `yaml-documented`. *I am working on removing this step and auto augmenting existing documentation in a non-destructive fashion.* 38 | 39 | 2) Generate documents. 40 | 41 | ``` 42 | $ ./node_modules/.bin/doc [] 43 | ``` 44 | 45 | Generated documents can be found in the `doccer/docs` folder (or where ever you configured the destination). *At the moment the default styles are messed up so you will get naked HTML.* 46 | 47 | ### Configuration 48 | 49 | The `./jsdoccerrc` file contains configuration for the tool. If no files are provided on the command line the tool will glob the files listed in the `js` directory for target files. In the generate documentation phase the tool will look for your augmented YAML in the globs configured under the `documentedYaml` argument. All intermediate files are saved under the `dest` path. These are useful for debug. 50 | 51 | Syntax targets are specific types of code you would like to document like *functions* or *properties*. JsDoccer comes with the following targets that you include or ignore based on a boolean under the `targets/defaut` in your `.jsdoccerrc` file. They are: 52 | 53 | * name 54 | * class 55 | * constructors 56 | * events 57 | * functions 58 | * properties 59 | 60 | ### Extention 61 | 62 | JsDoccer uses a collection of templates and functions designed to find syntax targets and render them to both YAML stubbed templates and HTML documents. You can use what ever templating library you are comfortable with, however with nested templates I recomend [Handelbars](http://handlebarsjs.com/) for it's support of partials. 63 | 64 | Each syntax target requires a YAML template for creating the document stubs and an HTML template for creating the documentation as well as functions to render them. You will also need to provide a matcher function that can parse an AST node looking for the target. You may optionally provide a linter function if you would like to use the linter. All of the default target code can be found under `scr/syntax-targets` for examples. This is also where the documentation website index template `docs-index.hbs` lives. 65 | 66 | There are 2 ways to extend the doccer with custom targets. 1) Add arguments and a path to your `.jsdoccerrc` file under `targets/custom` and `targets/customTargetsPath`. To choose this route you will need to set up a folder with an identical name to the target argument in your `.jsdoccerrc` file. in that folder you will need to provide the following 6 files and they must be named as follows 67 | 68 | * `linter.js` a lint function that will be passed old and new verison you your YAML 69 | * `matcher.js` a matching fuction that will search an AST and return the pertinate information about that target. 70 | * `templateYaml.js` a function that will populate a template with the YAML stub of your syntax target. 71 | * `templateHtml.js` a function that will populate a template with the HTML documentation of your syntax target. 72 | 73 | 74 | 2) Add the functions to the `jsdoccer` object. 75 | 76 | ```js 77 | jsdoccer.addSyntaxTargets({ 78 | target: name, 79 | linter: aLinterFunction, 80 | matcher: aMatcherFunction, 81 | yamlTemplater: aYamlTemplaterFunction, 82 | htmlTemplater: aHtmlTemplaterFunction 83 | }); 84 | ``` 85 | 86 | You can pass several targets in an array as well. 87 | 88 | 89 | 90 | ### What You Need To Know About ASTs 91 | 92 | An AST or Abstract Syntax Tree is a typed representation of valid code. Esprima will parse valid ECMAScript and generate an AST. ESCodeGen provides an "inverse" operation that will generate valid ECMAScript from Esprima ASTs. 93 | 94 | Esprima will parse this Javascript: 95 | 96 | ``` 97 | var answer = 42; 98 | ``` 99 | 100 | and generate this AST: 101 | 102 | ``` 103 | { 104 | "type": "Program", 105 | "body": [ 106 | { 107 | "type": "VariableDeclaration", 108 | "declarations": [ 109 | { 110 | "type": "VariableDeclarator", 111 | "id": { 112 | "type": "Identifier", 113 | "name": "answer" 114 | }, 115 | "init": { 116 | "type": "Literal", 117 | "value": 42, 118 | "raw": "42" 119 | } 120 | } 121 | ], 122 | "kind": "var" 123 | } 124 | ] 125 | } 126 | ``` 127 | 128 | AST types are defined by the [Spider Monkey Parser API](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API#Functions). 129 | 130 | #### Target Syntax Matchers 131 | 132 | In order to find syntax targets you can create a custom document "type" by adding a type attribute and associated matching function to the `jsdoccer/syntax-matchers.js` hash for example: 133 | 134 | 135 | ``` 136 | module.exports = { 137 | functions: function(ast) { 138 | var json = [ast]. 139 | filter(function (ast) { 140 | return ast.type === 'Property' && 141 | ast.value.type === 'FunctionExpression' && 142 | ast.key.type === 'Identifier' && 143 | ast.key.name !== 'constructor'; // filter named constructors 144 | }). 145 | map(function(property) { 146 | return { 147 | name: property.key.name, 148 | tags: [property.key.name.indexOf('_') === 0 ? ['@api private'] : ['@api public'], 149 | property.value.params. 150 | filter(function (param) { 151 | return param.type === 'Identifier'; 152 | }). 153 | map(function (param) { 154 | return '@param {} ' + param.name + ' - '; 155 | }), 156 | _hasReturn(property.value.body.body) ? ['@returns {} -'] : [] 157 | ].mergeAll() 158 | }; 159 | }); 160 | 161 | if (json.length > 0) { 162 | return json.pop(); 163 | } 164 | 165 | return false; 166 | } 167 | }; 168 | ``` 169 | **Note**: I am using map/reduce to produce exactly the JSON I need here. You could just as easily use regex or even string matching to identify a target case and return the current unfiltered AST node containing all the data your template requires. 170 | 171 | The script will recursively walk the ASTs of each file passing every node to each match function. Each match function should return `false` or a valid JSON object containing all of the data the associated YAML template requires. While you can certainly return the raw AST node, I recommend you filter and organize your JSON here rather than in the template. 172 | 173 | To find out the AST conditions that match the code you would like to document compare your code with the ASTs saved in the `ast` directory. Then you will have a predictable AST JSON structure to query in an associated template for each document type. 174 | 175 | #### Parse JSON like a champ 176 | 177 | Map/Reduce is your friend when you need to pull deeply nested targets out of a large amount of JSON. I use a modified Array with the 5 magic RX methods attached. I highly recommend you spend a little time with [this excellent tutorial](http://reactive-extensions.github.io/learnrx/) from Jafar Husain of Netflix **Note: Do it in Chrome. It doesn't work in Firefox.** Then you will be able to inspect the generated AST files in the `ast` directory and write your own custom matchers in the `syntax-matchers.js` file. 178 | 179 | Example: 180 | 181 | `functions.tpl` referenced in the `syntax-matchers.js` hash above will search for this template in the `jsdoccer/templates/yaml` dir specified in the `.jsdoccerrc` file above. **Note the indentation of the loop to populate the template with `param` values.** 182 | 183 | ``` 184 | <%- id %> 185 | description: | <% params.forEach(function(param) {%> 186 | @param {type} <%= param %> - <%}); %> 187 | 188 | examples: 189 | - 190 | name: Function Body 191 | example: | 192 | ``` 193 | 194 | Here is a sample of the yaml produced: 195 | 196 | ``` 197 | unbindFromStrings 198 | description: | 199 | @param {type} target - 200 | @param {type} entity - 201 | @param {type} evt - 202 | @param {type} methods - 203 | 204 | examples: 205 | - 206 | name: 207 | example: | 208 | ``` 209 | 210 | -------------------------------------------------------------------------------- /bin/doc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var jsDoccer = require('../src/jsdoccer.js'), 6 | configLoader = require('../src/util/config-loader.js'), 7 | nodeStackTracer = require('../src/util/node-stack-tracer.js'), 8 | minimist = require('minimist'), 9 | glob = require('glob'), 10 | path = require('path'), 11 | args = Array.prototype.slice.call(process.argv, 2), 12 | filesDocumented = 0, // a count of the documented files 13 | src, output; 14 | 15 | var parsedArgs = minimist(args); 16 | 17 | jsDoccer.init(configLoader('.jsdoccerrc')); 18 | 19 | 20 | if (parsedArgs.src) { 21 | src = path.join(process.cwd(), parsedArgs.src); 22 | } 23 | 24 | if (parsedArgs.output) { 25 | output = path.join(process.cwd(), parsedArgs.output); 26 | } 27 | 28 | filesDocumented = jsDoccer.doc( 29 | glob.sync(src || jsDoccer.config.documentedYaml.src), output 30 | ); 31 | 32 | console.log('Done: Generated ' + filesDocumented + ' file documents at'); 33 | 34 | -------------------------------------------------------------------------------- /bin/stub.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var path = require('path'), 6 | jsDoccer = require('../src/jsdoccer.js'), 7 | configLoader = require('../src/util/config-loader.js'), 8 | nodeStackTracer = require('../src/util/node-stack-tracer.js'), 9 | 10 | args = Array.prototype.slice.call(process.argv, 2), 11 | destPath, srcPath, 12 | filesStubbed = 0; // a count of the stubbed files 13 | 14 | jsDoccer.init(configLoader('.jsdoccerrc')); 15 | 16 | try { 17 | // if no args were passed in pull from the config file 18 | args = !!args.length ? args : jsDoccer.config.js.src; 19 | destPath = path.resolve(jsDoccer.config.dest + 'yaml-stubbed'); 20 | srcPath = path.resolve(jsDoccer.config.dest + 'yaml-documented'); 21 | filesStubbed = jsDoccer.stub(args); 22 | console.log('Done: Generated ' + filesStubbed + ' YAML document stubs at'); 23 | console.log(destPath); 24 | console.log('Remember to copy them into ' + srcPath + ' path defined in your .jsdoccerrc config.'); 25 | console.log('directory BEFORE augmenting them with examples.'); 26 | } catch (err) { 27 | console.warn('Unable to generate YAML templates.'); 28 | console.log('Usage: node stub "./path/to/target/file.js". Or set up your "js.src" default targets in the ".jsdoccerrc" config file to run it with out arguments.'); 29 | nodeStackTracer(err); 30 | } 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsdoccer", 3 | "version": "2.0.1", 4 | "private": false, 5 | "description": "A Node.js tool to auto document your ECMAScript (Java Script) in JSDoc 3 using Esprima.", 6 | "main": "./src/jsdoccer", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/ChetHarrison/jsdoccer.git" 10 | }, 11 | "bin": { 12 | "stub": "./bin/stub.js", 13 | "doc": "./bin/doc.js" 14 | }, 15 | "keywords": [ 16 | "jsdoc", 17 | "auto", 18 | "documentation" 19 | ], 20 | "scripts": { 21 | "test": "mocha" 22 | }, 23 | "author": "Chet Harrison", 24 | "license": "ISC", 25 | "bugs": { 26 | "url": "https://github.com/ChetHarrison/jsdoccer/issues" 27 | }, 28 | "homepage": "https://github.com/ChetHarrison/jsdoccer", 29 | "devDependencies": { 30 | "chai": "^1.10.0", 31 | "grunt": "^0.4.5", 32 | "grunt-contrib-clean": "^0.6.0", 33 | "grunt-contrib-copy": "^0.5.0", 34 | "grunt-contrib-jade": "^0.12.0", 35 | "grunt-contrib-jasmine": "^0.8.0", 36 | "grunt-contrib-less": "^0.11.4", 37 | "grunt-contrib-sass": "^0.8.1", 38 | "grunt-contrib-watch": "^0.6.1", 39 | "grunt-jasmine-node": "^0.2.1", 40 | "grunt-jasmine-node-coverage": "^0.1.11", 41 | "grunt-plato": "^1.3.0", 42 | "jshint-stylish": "^1.0.0", 43 | "load-grunt-tasks": "^0.6.0", 44 | "mkdirp": "^0.5.0", 45 | "morgan": "^1.1.1", 46 | "prettyjson": "^1.0.0", 47 | "rimraf": "^2.2.8" 48 | }, 49 | "dependencies": { 50 | "bluebird": "^2.1.3", 51 | "dox": "git://github.com/jasonLaster/dox.git#marked", 52 | "escodegen": "^1.4.1", 53 | "esprima": "^1.2.2", 54 | "fs-extra": "^0.12.0", 55 | "glob": "^4.0.6", 56 | "handlebars": "^2.0.0", 57 | "highlight.js": "^8.2.0", 58 | "indent-string": "^1.1.0", 59 | "js-yaml": "^3.1.0", 60 | "lodash": "^2.4.1", 61 | "marked": "^0.3.2", 62 | "mocha": "^2.1.0", 63 | "prettyjson": "^1.0.0", 64 | "rx-array": "0.0.3", 65 | "shelljs": "^0.3.0", 66 | "strip-json-comments": "^1.0.2", 67 | "underscore.string": "^2.3.3", 68 | "minimist": "~1.1.0" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/jsdoccer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'), 4 | path = require('path'), 5 | _ = require('lodash'), 6 | glob = require('glob'), 7 | // parsers 8 | jsToAst = require('./parsers/js-to-ast'), 9 | astToJsonPre = require('./parsers/ast-to-json-pre.js'), 10 | jsonPreToYamlStubbed = require('./parsers/json-pre-to-yaml-stubbed.js'), 11 | yamlDocumentedToJsonApi = require('./parsers/yaml-documented-to-json-api.js'), 12 | jsonApiToDocs = require('./parsers/json-api-to-docs.js'); 13 | 14 | module.exports = { 15 | 16 | _globToFileList: function(fileGlobs) { 17 | var files = []; 18 | fileGlobs.forEach(function(fileGlob) { files.push(glob.sync(fileGlob)); }); 19 | files = files.mergeAll(); 20 | return files; 21 | }, 22 | 23 | 24 | _buildJsonNav: function (fileGlobs) { 25 | var files = this._globToFileList(fileGlobs), 26 | jsonNav = {files: []}; 27 | _.each(files, function (file) { 28 | jsonNav.files.push({name: this._fileName(file)}); 29 | }, this); 30 | 31 | return jsonNav; 32 | }, 33 | 34 | 35 | _fileName: function(filePath) { 36 | return path.basename(filePath, path.extname(filePath)); 37 | }, 38 | 39 | 40 | _setupWorkingDir: function(dest) { 41 | // set up local working directory 42 | var intermediate = 'intermediate/'; 43 | 44 | this.paths = { 45 | dest: path.resolve(dest), 46 | intermediate: path.resolve(path.resolve(dest, intermediate)), 47 | ast: path.resolve(dest, intermediate + 'ast'), 48 | jsonPre: path.resolve(dest, intermediate + 'json-pre'), 49 | yamlStubbed: path.resolve(dest + 'yaml-stubbed'), 50 | jsonApi: path.resolve(dest, intermediate + 'json-api'), 51 | docs: path.resolve(dest, 'docs') 52 | }; 53 | 54 | _.each(this.paths, function(aPath) { 55 | if (!fs.existsSync(aPath)) { 56 | fs.mkdirSync(aPath); 57 | } 58 | }); 59 | }, 60 | 61 | 62 | _duplicateTargets: function(defaultTargets, customTargets) { 63 | var targetCount = defaultTargets.length + customTargets.length, 64 | uniqueCount = _.union(defaultTargets, customTargets).length; 65 | 66 | return targetCount !== uniqueCount; 67 | }, 68 | 69 | 70 | _getFile: function(target, targetPath, file) { 71 | return require(path.resolve(path.join(__dirname, targetPath, '/', target, '/', file))); 72 | }, 73 | 74 | 75 | _addSyntaxTargetByName: function(target, targetPath) { 76 | this.addSyntaxTargets({ 77 | target: target, 78 | linter: this._getFile(target, targetPath, 'linter.js'), 79 | matcher: this._getFile(target, targetPath, 'matcher.js'), 80 | yamlTemplater: this._getFile(target, targetPath, 'templateYaml.js'), 81 | htmlTemplater: this._getFile(target, targetPath, 'templateHtml.js') 82 | }); 83 | }, 84 | 85 | 86 | _addSyntaxTarget: function(options) { 87 | // TODO: check for name collisions 88 | var target = options.target; 89 | this.targets.push(target); 90 | this.linters[target] = options.linter; 91 | this.matchers[target] = options.matcher; 92 | this.yamlTemplaters[target] = options.yamlTemplater; 93 | this.htmlTemplaters[target] = options.yamlTemplater; 94 | }, 95 | 96 | 97 | addSyntaxTargets: function(options) { 98 | if (_.isArray(options)) { 99 | _.each(options, function(option) { 100 | this._addSyntaxTarget(option); 101 | }); 102 | } 103 | 104 | this._addSyntaxTarget(options); 105 | }, 106 | 107 | 108 | init: function(options) { 109 | var dest, intermediate, 110 | defaultTargets, 111 | customTargets, 112 | targets; 113 | 114 | options = options || {}; 115 | this.config = options; 116 | this.targets = []; 117 | this.linters = {}; 118 | this.matchers = {}; 119 | this.yamlTemplaters = {}; 120 | this.htmlTemplaters = {}; 121 | this.config.projectName = this.config.projectName || 122 | path.basename(process.cwd()); 123 | 124 | 125 | this._setupWorkingDir(this.config.dest); 126 | 127 | 128 | // configure targets 129 | defaultTargets = Object.keys(this.config.targets.default) 130 | .filter(function(target) { 131 | return this.config.targets.default[target]; // filter false values in config 132 | }, this); 133 | 134 | customTargets = Object.keys(this.config.targets.custom) 135 | .filter(function(target) { 136 | return this.config.targets.custom[target]; // filter false values in config 137 | }, this); 138 | 139 | if (this._duplicateTargets(defaultTargets, customTargets)) { 140 | throw 'Syntax target names must be unique.'; 141 | } 142 | 143 | _.each(defaultTargets, function(target) { 144 | this._addSyntaxTargetByName(target, './syntax-targets/'); 145 | }, this); 146 | 147 | _.each(customTargets, function(target) { 148 | this._addSyntaxTargetByName(target, this.config.targets.customTargetsPath); 149 | }, this); 150 | 151 | 152 | // init parsers 153 | astToJsonPre.init({ matchers: this.matchers }); 154 | jsonPreToYamlStubbed.init({ yamlTemplaters: this.yamlTemplaters }); 155 | jsonApiToDocs.init({ 156 | htmlTemplaters: this.htmlTemplaters, 157 | docPageTplPath: path.resolve(__dirname, 'syntax-targets/docs-index.hbs'), 158 | projectName: this.config.projectName 159 | }); 160 | }, 161 | 162 | 163 | // convert a glob arg to array of file paths 164 | // read in each file and apply the parser function 165 | // save the results and return the number of parsed files 166 | _parseGlobs: function (fileGlobs, steps) { 167 | var files = this._globToFileList(fileGlobs); 168 | 169 | _.each(files, function (file) { 170 | var input = fs.readFileSync(file, 'utf8'); 171 | _.each(steps, function (step) { 172 | 173 | var output = step.parser.parse(input), 174 | dest = path.join( 175 | step.dest, 176 | this._fileName(file) + '.' + step.ext 177 | ); 178 | 179 | if (step.needsFileName) { 180 | output = JSON.parse(output); 181 | output['name'] = { 182 | name: this._fileName(file) 183 | }; 184 | output = JSON.stringify(output, null, 2); 185 | } 186 | 187 | if (step.jsonNav) { 188 | output = JSON.parse(output); 189 | output.nav = step.jsonNav; 190 | output = JSON.stringify(output, null, 2); 191 | } 192 | fs.writeFileSync(dest, output); 193 | // this feeds the output of one parser into the 194 | // input of the next parser 195 | input = output; 196 | }, this); 197 | }, this); 198 | 199 | return files.length; 200 | }, 201 | 202 | 203 | // Generate stubbed yaml file. 204 | stub: function(globs) { 205 | return this._parseGlobs(globs, [{ 206 | parser: jsToAst, 207 | dest: this.paths.ast, 208 | ext: 'ast' 209 | }, { 210 | parser: astToJsonPre, 211 | dest: this.paths.jsonPre, 212 | ext: 'json', 213 | needsFileName: true 214 | }, { 215 | parser: jsonPreToYamlStubbed, 216 | dest: this.paths.yamlStubbed, 217 | ext: 'yaml' 218 | }]); 219 | }, 220 | 221 | // Generate html documentation from documented yaml 222 | doc: function(files, dest) { 223 | var jsonNav = this._buildJsonNav(files); 224 | 225 | return this._parseGlobs(files, htmlTemplate, [{ 226 | parser: yamlDocumentedToJsonApi, 227 | dest: this.paths.jsonApi, 228 | ext: 'json', 229 | jsonNav: jsonNav 230 | }, { 231 | parser: jsonApiToDocs, 232 | dest: dest || this.paths.docs, 233 | ext: 'html' 234 | }]); 235 | }, 236 | 237 | // Lint the documentation 238 | lint: function(globs) { 239 | console.log('TODO: Implement the linter.'); 240 | } 241 | }; 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /src/parsers/ast-to-json-pre.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Dependencies 4 | //----------------------------------------- 5 | var path = require('path'), 6 | _ = require('lodash'), 7 | _s = require('underscore.string'), 8 | // Private Variables 9 | _recursionDepth = 0; 10 | 11 | 12 | module.exports = { 13 | 14 | init: function (options) { 15 | options = options || {}; 16 | this.matchers = options.matchers; 17 | }, 18 | 19 | // iterate the `matchers` object and call each 20 | // validation function with the current ast branch. Return 21 | // the syntax name of the first match. 22 | syntaxToDocument: function (branch) { 23 | var syntaxTargets = _.keys(this.matchers), 24 | results = false, 25 | self = this, 26 | syntaxJson; 27 | 28 | if (_.isNull(branch)) { return; } 29 | 30 | _.each(syntaxTargets, function (syntaxTarget) { 31 | syntaxJson = self.matchers[syntaxTarget](branch); 32 | 33 | if (syntaxJson) { 34 | results = { 35 | type: syntaxTarget, 36 | ast: syntaxJson 37 | }; 38 | } 39 | }); 40 | 41 | return results; 42 | }, 43 | 44 | 45 | parseBranch: function (branch, results) { 46 | var keys = _.keys(branch), 47 | maxDepth = 50, 48 | self = this, 49 | syntaxObject = this.syntaxToDocument(branch); 50 | 51 | // recursion e-break 52 | _recursionDepth++; 53 | 54 | if (_recursionDepth > maxDepth) { 55 | console.warn('ast-to-doc-json.parseBranch(): Exceeded max recursion depth.'); 56 | return; 57 | } 58 | 59 | // Does current childBranch need to be documented? 60 | if (syntaxObject) { 61 | // Check to see if this is a new syntax category and add 62 | // it to the results if it isn't. 63 | if (!results[syntaxObject.type]) { 64 | results[syntaxObject.type] = []; 65 | } 66 | 67 | results[syntaxObject.type].push(syntaxObject.ast); 68 | } 69 | 70 | _.each(keys, function (key) { 71 | var childBranch = branch[key]; 72 | 73 | // Current childBranch is an array so recurse 74 | // with members. 75 | if (_.isArray(childBranch)) { 76 | _.each(childBranch, function (sibling) { 77 | self.parseBranch(sibling, results); 78 | }); 79 | } 80 | // Current childBranch is an object so recurse 81 | // with the object. 82 | else if (_.isPlainObject(childBranch)) { 83 | self.parseBranch(childBranch, results); 84 | } 85 | }); 86 | 87 | _recursionDepth--; 88 | 89 | return results; 90 | }, 91 | 92 | 93 | // Walk the AST building a yaml string of whitelisted 94 | // syntax. 95 | parse: function (syntaxTree) { 96 | // we need a totaly blank object (with no 97 | // constructor, so we don't have name collision.) 98 | var results = Object.create( null ); 99 | 100 | // results['class'] = { 101 | // name: 'name' 102 | // }; 103 | 104 | this.parseBranch(JSON.parse(syntaxTree), results); 105 | 106 | return JSON.stringify(results, null, 2); 107 | } 108 | }; 109 | -------------------------------------------------------------------------------- /src/parsers/js-to-ast.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var esprima = require('esprima'); 4 | 5 | module.exports = { 6 | parse: function (javascript) { 7 | var json = esprima.parse(javascript, { 8 | loc: false, 9 | range: false, 10 | raw: false, 11 | tokens: false, 12 | comment: false, 13 | }); 14 | 15 | return JSON.stringify(json, null, 2); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/parsers/json-api-to-docs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var bluebird = require('bluebird'), 4 | fs = bluebird.promisifyAll(require('fs')), 5 | _ = require('lodash'), 6 | path = require('path'), 7 | Handlebars = require('handlebars'); 8 | // aliasCollision = require('alias-collision'); 9 | 10 | 11 | module.exports = { 12 | 13 | init: function(options) { 14 | options = options || {}; 15 | this.htmlTemplaters = options.htmlTemplaters; 16 | this.docPageTplPath = options.docPageTplPath; 17 | this.projectName = options.projectName; 18 | }, 19 | 20 | 21 | parse: function (jsonApi) { 22 | var docPageTpl = Handlebars.compile(fs.readFileSync(this.docPageTplPath).toString()), 23 | contentTemplater = this.htmlTemplaters['class'], 24 | model = {}, 25 | file = {}; 26 | 27 | jsonApi = JSON.parse(jsonApi); 28 | 29 | // TODO: elevate the namespacing to jsdoccer so we don't collide 30 | // with a function named 'nav'. 31 | model.projectName = this.projectName; 32 | model.nav = jsonApi.nav; 33 | model.file = file; 34 | model.file.name = jsonApi.name; 35 | model.file.constructor = jsonApi.constructor; 36 | model.file.functions = jsonApi.functions; 37 | model.file.properties = jsonApi.properties; 38 | model.file.events = jsonApi.events; 39 | model.content = contentTemplater(jsonApi); // currently we are not passing in a templater 40 | 41 | 42 | return docPageTpl(model); 43 | } 44 | 45 | }; 46 | -------------------------------------------------------------------------------- /src/parsers/json-pre-to-yaml-stubbed.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Dependencies 4 | var _ = require('lodash'), 5 | indentString = require('indent-string'); 6 | 7 | module.exports = { 8 | 9 | init: function(options) { 10 | options = options || {}; 11 | this.yamlTemplaters = options.yamlTemplaters || {}; 12 | }, 13 | 14 | parse: function (json) { 15 | var yaml = '', 16 | syntaxTypes; 17 | 18 | json = JSON.parse(json); 19 | syntaxTypes = _.keys(json); 20 | 21 | _.each(syntaxTypes, function (type) { 22 | var templater = this.yamlTemplaters[type], 23 | syntaxJsons = json[type]; 24 | 25 | // add type category 26 | 27 | if (Array.isArray(syntaxJsons)) { 28 | yaml += type + ':\n'; 29 | _.each(syntaxJsons, function (syntaxJson) { 30 | yaml += indentString(templater(syntaxJson), ' ', 2); 31 | yaml += '\n'; 32 | }); 33 | } else { 34 | yaml += type + ': ' + templater(syntaxJsons); 35 | yaml += '\n'; 36 | } 37 | 38 | }, this); 39 | 40 | return yaml; 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /src/parsers/yaml-documented-to-json-api.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dox = require('dox'), 4 | _ = require('lodash'), 5 | jsYaml = require('js-yaml'), 6 | marked = require('marked'), 7 | highlight = require('highlight.js'), 8 | markdown = new marked.Renderer(), 9 | fs = require('fs'), 10 | jsonWalker = require('../util/json-walker.js'), 11 | marker = marked, 12 | 13 | // TODO: move decoration functions into config 14 | parseDox = function (docString, name) { 15 | var doc, tags; 16 | 17 | try { 18 | doc = dox.parseComment(docString); 19 | } catch (err) { 20 | console.warn('jsDocFile failed to parse string ' + docString + ' dox at ' + name); 21 | } 22 | 23 | tags = doc.tags || []; 24 | doc.api = _.findWhere(tags, { 25 | type: 'api' 26 | }); 27 | doc.params = _.where(tags, { 28 | type: 'param' 29 | }); 30 | doc.paramStr = _.pluck(doc.params, 'name').join(', '); 31 | 32 | doc.params = _.map(doc.params, function (param) { 33 | return _.extend(param, { 34 | typeStr: param.types.join(', '), 35 | description: param.description.replace(/^- /, '') // because dox doesn't parse the - out 36 | }); 37 | }); 38 | 39 | 40 | return doc; 41 | }, 42 | decorationTargets = { 43 | 'example': marked, 44 | 'description': parseDox 45 | }; 46 | 47 | dox.setMarkedOptions({ 48 | renderer: markdown, 49 | gfm: true, 50 | tables: true, 51 | breaks: false, 52 | pedantic: false, 53 | sanitize: false, 54 | smartLists: true, 55 | smartypants: false, 56 | highlight: function (code, lang) { 57 | return highlight.highlight(lang, code).value; 58 | } 59 | }); 60 | 61 | module.exports = { 62 | 63 | parse: function(yaml) { 64 | var json = jsYaml.safeLoad(yaml); 65 | 66 | _.each(decorationTargets, function(fn, name) { 67 | jsonWalker(json, name, fn); 68 | }); 69 | 70 | return JSON.stringify(json, null, 2); 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /src/syntax-targets/class/linter.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChetHarrison/jsdoccer/38889056c1eedbfd907b26fd896b71f62acdf2e8/src/syntax-targets/class/linter.js -------------------------------------------------------------------------------- /src/syntax-targets/class/matcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W030 */ 3 | 4 | require('rx-array'); 5 | 6 | module.exports = function(ast) { 7 | return ast['class']; 8 | }; -------------------------------------------------------------------------------- /src/syntax-targets/class/templateHtml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'), 4 | path = require('path'), 5 | Handlebars = require('handlebars'), 6 | constructorTemplater = require('../constructor/templateHtml.js'), 7 | eventTemplater = require('../events/templateHtml.js'), 8 | propertyTemplater = require('../properties/templateHtml.js'), 9 | functionTemplater = require('../functions/templateHtml.js'), 10 | htmlTemplateLoader = require('../../util/html-template-loader.js'); 11 | 12 | module.exports = function(model) { 13 | var template = htmlTemplateLoader(path.join(__dirname, 'templates/html.hbs')); 14 | 15 | model.constructer = constructorTemplater(model); 16 | model.events = eventTemplater(model); 17 | model.properties = propertyTemplater(model); 18 | model.functions = functionTemplater(model); 19 | // TODO: file.description = model.description.description 20 | 21 | return template(model); 22 | }; -------------------------------------------------------------------------------- /src/syntax-targets/class/templateYaml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/yaml-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/yaml.tpl')); -------------------------------------------------------------------------------- /src/syntax-targets/class/templates/html.hbs: -------------------------------------------------------------------------------- 1 | {{# if name}} 2 |

{{name}}

3 | {{/if}} 4 | {{# if class}} 5 |
Class: {{class}}
6 | {{/if}} 7 | 8 | {{#each extends}} 9 |
Mixes In: {{this}}
10 | {{/each}} 11 | 12 | {{{description.description.full}}} 13 | 14 | {{#if examples}} 15 |

Examples

16 | {{#each examples}} 17 |

Example: {{name}}

18 |
19 | {{{example}}} 20 |
21 | {{/each}} 22 | {{/if}} 23 | 24 | {{{constructer}}} 25 | 26 | {{{functions}}} 27 | 28 | {{{properties}}} 29 | 30 | {{{events}}} -------------------------------------------------------------------------------- /src/syntax-targets/class/templates/yaml.tpl: -------------------------------------------------------------------------------- 1 | <%- name %> 2 | -------------------------------------------------------------------------------- /src/syntax-targets/constructor/linter.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChetHarrison/jsdoccer/38889056c1eedbfd907b26fd896b71f62acdf2e8/src/syntax-targets/constructor/linter.js -------------------------------------------------------------------------------- /src/syntax-targets/constructor/matcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W030 */ 3 | 4 | require('rx-array'); 5 | 6 | module.exports = function(ast) { 7 | // Two casses 8 | // 1) Named constructor,: search for methods named 9 | // constructor 10 | // 2) Anonymous constructor: find methods with the 11 | // assigned to capitalized objects or properites. 12 | var json = false; 13 | 14 | // Named Constructors 15 | if (ast.type === 'Property' && 16 | ast.value.type === 'FunctionExpression' && 17 | ast.key.type === 'Identifier' && 18 | ast.key.name === 'constructor') { 19 | 20 | json = [ast]. 21 | filter(function(ast) { 22 | return ast.type === 'Property' && 23 | ast.value.type === 'FunctionExpression' && 24 | ast.key.type === 'Identifier' && 25 | ast.key.name === 'constructor'; 26 | }). 27 | map(function(property) { 28 | return { 29 | tags: [property.key.name.indexOf('_') === 0 ? ['@api private'] : ['@api public'], 30 | property.value.params. 31 | filter(function (param) { 32 | return param.type === 'Identifier'; 33 | }). 34 | map(function (param) { 35 | return '@param {} ' + param.name + ' - ' + ''; 36 | }) 37 | ].mergeAll() // here's that mergeAll 38 | }; 39 | }); 40 | 41 | } else { 42 | 43 | json = [ast]. 44 | filter(function(exp) { 45 | return exp.type === 'AssignmentExpression' && 46 | exp.left.type === 'MemberExpression' && 47 | exp.left.object.type === 'Identifier' && 48 | exp.left.property.type === 'Identifier' && 49 | exp.right.type === 'FunctionExpression' && 50 | exp.left.property.name[0] === exp.left.property.name[0].toUpperCase(); 51 | }). 52 | map(function(exp) { return exp.right; }). 53 | map(function(exp) { 54 | return { 55 | tags: [ 56 | ['@api public'], 57 | exp.params. 58 | filter(function (param) { 59 | return param.type === 'Identifier'; 60 | }). 61 | map(function (param) { 62 | return '@param {} ' + param.name + ' - ' + ''; 63 | }) 64 | ].mergeAll() // here's that mergeAll 65 | }; 66 | }); 67 | } 68 | 69 | if (json.length > 0) { 70 | return json.pop(); 71 | } 72 | 73 | return false; 74 | }; -------------------------------------------------------------------------------- /src/syntax-targets/constructor/templateHtml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/html-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/html.hbs')); -------------------------------------------------------------------------------- /src/syntax-targets/constructor/templateYaml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/yaml-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/yaml.tpl')); -------------------------------------------------------------------------------- /src/syntax-targets/constructor/templates/html.hbs: -------------------------------------------------------------------------------- 1 | {{#if constructor}} 2 | {{#with constructor}} 3 |
4 | {{#with description}} 5 | 8 | 9 | {{{description.full}}} 10 | 11 | {{#if params}} 12 |
13 |

Params

14 | {{#each params}} 15 |
16 | {{name}} 17 | {{#if typeStr}}({{typeStr}}){{/if}} 18 | {{#if description}}   {{description}} {{/if}} 19 |
20 | {{/each}} 21 |
22 | {{/if}} 23 | {{/with}} 24 | 25 | {{#if examples}} 26 |

Examples

27 | {{#each examples}} 28 |
29 |

{{name}}

30 | {{{example}}} 31 |
32 | {{/each}} 33 | {{/if}} 34 |
35 | {{/with}} 36 | {{/if}} -------------------------------------------------------------------------------- /src/syntax-targets/constructor/templates/yaml.tpl: -------------------------------------------------------------------------------- 1 | 2 | description: |<% tags.forEach(function(tag) {%> 3 | <%= tag %><%}); %> 4 | 5 | examples: 6 | - 7 | name: 8 | example: | 9 | 10 | -------------------------------------------------------------------------------- /src/syntax-targets/docs-index.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 47 |
48 | 49 |
50 | {{{content}}} 51 |
52 |
53 | 54 | 55 | -------------------------------------------------------------------------------- /src/syntax-targets/events/linter.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChetHarrison/jsdoccer/38889056c1eedbfd907b26fd896b71f62acdf2e8/src/syntax-targets/events/linter.js -------------------------------------------------------------------------------- /src/syntax-targets/events/matcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W030 */ 3 | 4 | require('rx-array'); 5 | 6 | module.exports = function(ast) { 7 | 8 | var events, 9 | json = [ast]. 10 | filter(function(exp) { 11 | return exp.type === 'ExpressionStatement' && 12 | exp.expression.type && 13 | exp.expression.type === 'CallExpression' && 14 | exp.expression.callee && 15 | exp.expression.callee.object && 16 | exp.expression.callee.object.type && 17 | exp.expression.callee.object.type === 'ThisExpression' && 18 | exp.expression.callee.property && 19 | exp.expression.callee.property.type === 'Identifier' && 20 | exp.expression.callee.property.name === 'triggerMethod'; 21 | }). 22 | map(function(exp) { 23 | return { 24 | exp: exp, 25 | eventName: exp.expression.arguments. 26 | filter(function(arg) { 27 | return arg.type === 'Literal'; 28 | }). 29 | map(function(arg) { 30 | return arg.value; 31 | }).pop() 32 | }; 33 | }). 34 | filter(function(obj) { 35 | return obj.eventName; 36 | }). 37 | map(function(obj) { 38 | return { name: obj.eventName }; 39 | }); 40 | 41 | if (json.length > 0) { 42 | events = json.pop(); 43 | } else { 44 | events = false; 45 | } 46 | 47 | return events; 48 | }; -------------------------------------------------------------------------------- /src/syntax-targets/events/templateHtml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/html-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/html.hbs')); -------------------------------------------------------------------------------- /src/syntax-targets/events/templateYaml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/yaml-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/yaml.tpl')); -------------------------------------------------------------------------------- /src/syntax-targets/events/templates/html.hbs: -------------------------------------------------------------------------------- 1 | {{#if events}} 2 |

Events

3 | {{#each events}} 4 |
5 | {{#with description}} 6 |
7 |

● {{@key}}

8 |
9 | {{{description.full}}} 10 | {{/with}} 11 | 12 | {{#if examples}} 13 |

Examples

14 | {{#each examples}} 15 |
16 |

{{name}}

17 | {{{example}}} 18 |
19 | {{/each}} 20 | {{/if}} 21 |
22 | {{/each}} 23 | {{/if}} -------------------------------------------------------------------------------- /src/syntax-targets/events/templates/yaml.tpl: -------------------------------------------------------------------------------- 1 | 2 | name: <%= name %> 3 | 4 | description: | 5 | 6 | example: | 7 | -------------------------------------------------------------------------------- /src/syntax-targets/functions/linter.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChetHarrison/jsdoccer/38889056c1eedbfd907b26fd896b71f62acdf2e8/src/syntax-targets/functions/linter.js -------------------------------------------------------------------------------- /src/syntax-targets/functions/matcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W030 */ 3 | 4 | var _s = require('underscore.string'), 5 | 6 | _parseAstSubString = function(ast, subAstString) { 7 | var astString = JSON.stringify(ast, null, 2); 8 | 9 | return astString.indexOf(subAstString) > -1; 10 | }, 11 | 12 | _hasReturn = function(body) { 13 | var hasReturn = false; 14 | 15 | body.forEach(function(subAst) { 16 | if (subAst.type === 'ReturnStatement') { 17 | hasReturn = true; 18 | } 19 | }); 20 | 21 | return hasReturn; 22 | }, 23 | 24 | _formatParam = function(name) { 25 | return '@param {} ' + name + ' - ' + ''; 26 | }, 27 | 28 | _formatReturn = function() { 29 | return '@returns {} - '; 30 | }; 31 | 32 | 33 | require('rx-array'); 34 | 35 | module.exports = function(ast) { 36 | var json = [], 37 | 38 | mixinFunctions = [ast]. 39 | filter(function (ast) { 40 | return ( 41 | ast.type === 'Property' && 42 | ast.value.type === 'FunctionExpression' && 43 | ast.key.type === 'Identifier' && 44 | ast.key.name !== 'constructor' // filter named constructors 45 | ); 46 | }). 47 | map(function(property) { 48 | return { 49 | name: property.key.name, 50 | tags: [ 51 | property.key.name.indexOf('_') === 0 ? ['@api private'] : ['@api public'], 52 | property.value.params. 53 | filter(function (param) { 54 | return param.type === 'Identifier'; 55 | }). 56 | map(function (param) { 57 | return _formatParam(param.name); 58 | }), 59 | _hasReturn(property.value.body.body) ? [_formatReturn()] : [] 60 | ].mergeAll() 61 | }; 62 | }), 63 | 64 | functionExpressions = [ast]. 65 | filter(function (ast) { 66 | return ( 67 | ast.type === 'ExpressionStatement' && 68 | ast.expression.type === 'AssignmentExpression' && 69 | ast.expression.right.type === 'FunctionExpression' && 70 | ast.expression.left.object.type !== 'ThisExpression' 71 | ); 72 | }). 73 | map(function(ast) { 74 | var left = ast.expression.left, 75 | right = ast.expression.right, 76 | functionJson; 77 | 78 | functionJson = { 79 | name: left.property ? left.property.name : left.property.object, 80 | tags: [ 81 | right.params. 82 | map(function(params) { 83 | return _formatParam(params.name); 84 | }), 85 | right.body.body[0].type === 'ReturnStatement' ? 86 | [_formatReturn()] : [] 87 | ].mergeAll() 88 | }; 89 | 90 | return functionJson; 91 | }); 92 | 93 | if (mixinFunctions.length > 0) { 94 | return mixinFunctions.pop(); 95 | } 96 | 97 | if (functionExpressions.length > 0) { 98 | return functionExpressions.pop(); 99 | } 100 | 101 | return false; 102 | }; -------------------------------------------------------------------------------- /src/syntax-targets/functions/templateHtml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/html-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/html.hbs')); -------------------------------------------------------------------------------- /src/syntax-targets/functions/templateYaml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/yaml-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/yaml.tpl')); -------------------------------------------------------------------------------- /src/syntax-targets/functions/templates/html.hbs: -------------------------------------------------------------------------------- 1 | {{#if functions}} 2 |

Functions

3 | {{#each functions}} 4 |
5 | {{#with description}} 6 | 9 | {{{description.full}}} 10 | 11 | {{#if params}} 12 |
13 |

Params

14 | {{#each params}} 15 |
16 | {{name}} 17 | {{#if typeStr}}({{typeStr}}){{/if}} 18 | {{#if description}}   {{description}} {{/if}} 19 |
20 | {{/each}} 21 |
22 | {{/if}} 23 | {{/with}} 24 | 25 | {{#if examples}} 26 |

Examples

27 | {{#each examples}} 28 |
29 |

{{name}}

30 |
31 | {{{example}}} 32 |
33 |
34 | {{/each}} 35 | {{/if}} 36 |
37 | {{/each}} 38 | {{/if}} -------------------------------------------------------------------------------- /src/syntax-targets/functions/templates/yaml.tpl: -------------------------------------------------------------------------------- 1 | 2 | <%- name %>: 3 | description: |<% tags.forEach(function(tag) {%> 4 | <%= tag %><%}); %> 5 | 6 | examples: 7 | - 8 | name: 9 | example: | 10 | 11 | -------------------------------------------------------------------------------- /src/syntax-targets/name/linter.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChetHarrison/jsdoccer/38889056c1eedbfd907b26fd896b71f62acdf2e8/src/syntax-targets/name/linter.js -------------------------------------------------------------------------------- /src/syntax-targets/name/matcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W030 */ 3 | 4 | require('rx-array'); 5 | 6 | module.exports = function(ast) { 7 | return ast['fileName']; 8 | }; -------------------------------------------------------------------------------- /src/syntax-targets/name/templateHtml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'), 4 | path = require('path'), 5 | Handlebars = require('handlebars'), 6 | constructorTemplater = require('../constructor/templateHtml.js'), 7 | eventTemplater = require('../events/templateHtml.js'), 8 | propertyTemplater = require('../properties/templateHtml.js'), 9 | functionTemplater = require('../functions/templateHtml.js'), 10 | htmlTemplateLoader = require('../../util/html-template-loader.js'); 11 | 12 | module.exports = function(model) { 13 | var template = htmlTemplateLoader( 14 | path.join(__dirname, 'templates/html.hbs') 15 | ); 16 | 17 | model.constructor = constructorTemplater(model); 18 | model.events = eventTemplater(model); 19 | model.properties = propertyTemplater(model); 20 | model.functions = functionTemplater(model); 21 | 22 | return template(model); 23 | }; -------------------------------------------------------------------------------- /src/syntax-targets/name/templateYaml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/yaml-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/yaml.tpl')); -------------------------------------------------------------------------------- /src/syntax-targets/name/templates/html.hbs: -------------------------------------------------------------------------------- 1 | {{# if name}} 2 |

{{name}}

3 | {{/if}} 4 | 5 | {{#each extends}} 6 |
Mixes In: {{.}}
7 | {{/each}} 8 | 9 | {{{description}}} 10 | 11 | {{#if examples}} 12 |

Examples

13 | {{#each examples}} 14 |

Example: {{name}}

15 |
16 | {{{example}}} 17 |
18 | {{/each}} 19 | {{/if}} 20 | 21 | {{{constructor}}} 22 | 23 | {{{functions}}} 24 | 25 | {{{properties}}} 26 | 27 | {{{events}}} -------------------------------------------------------------------------------- /src/syntax-targets/name/templates/yaml.tpl: -------------------------------------------------------------------------------- 1 | <%- name %> 2 | -------------------------------------------------------------------------------- /src/syntax-targets/properties/linter.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChetHarrison/jsdoccer/38889056c1eedbfd907b26fd896b71f62acdf2e8/src/syntax-targets/properties/linter.js -------------------------------------------------------------------------------- /src/syntax-targets/properties/matcher.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /*jshint -W030 */ 3 | 4 | require('rx-array'); 5 | 6 | module.exports = function(ast) { 7 | var json = false; 8 | 9 | json = [ast]. 10 | filter(function (ast) { 11 | return ast.type === 'ExpressionStatement' && 12 | ast.expression.type === 'AssignmentExpression' && 13 | ast.expression.operator === '=' && 14 | ast.expression.left.type === 'MemberExpression' && 15 | ast.expression.left.object.type === 'ThisExpression'; 16 | }). 17 | map(function (ast) { 18 | return { 19 | name: ast.expression.left.property.name 20 | }; 21 | }); 22 | 23 | if (json.length > 0) { 24 | return json.pop(); 25 | } 26 | 27 | return false; 28 | }; -------------------------------------------------------------------------------- /src/syntax-targets/properties/templateHtml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/html-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/html.hbs')); -------------------------------------------------------------------------------- /src/syntax-targets/properties/templateYaml.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | loader = require('../../util/yaml-template-loader.js'); 5 | 6 | module.exports = loader(path.join(__dirname, '/templates/yaml.tpl')); -------------------------------------------------------------------------------- /src/syntax-targets/properties/templates/html.hbs: -------------------------------------------------------------------------------- 1 | {{#if properties}} 2 |

Properties

3 | {{#each properties}} 4 |
5 | {{#with description}} 6 |
7 |

● {{@key}}

8 |
9 | {{{description.full}}} 10 | {{/with}} 11 | 12 | {{#if examples}} 13 |

Examples

14 | {{#each examples}} 15 |
16 |

{{name}}

17 | {{{example}}} 18 |
19 | {{/each}} 20 | {{/if}} 21 |
22 | {{/each}} 23 | {{/if}} -------------------------------------------------------------------------------- /src/syntax-targets/properties/templates/yaml.tpl: -------------------------------------------------------------------------------- 1 | 2 | <%= name %>: | 3 | 4 | 5 | @type {} 6 | -------------------------------------------------------------------------------- /src/util/config-loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var shjs = require('shelljs'), 4 | stripJsonComments = require('strip-json-comments'); 5 | 6 | // jshint's config loader http://jshint.com/ 7 | module.exports = function (filePath) { 8 | if (!filePath) { 9 | return {}; 10 | } 11 | 12 | if (!shjs.test('-e', filePath)) { 13 | throw 'Can\'t find config file: ' + filePath; 14 | } 15 | 16 | try { 17 | var config = JSON.parse(stripJsonComments(shjs.cat(filePath))); 18 | return config; 19 | } catch (err) { 20 | throw 'Can\'t parse config file: ' + filePath ; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/util/file-globber.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // https://github.com/isaacs/node-glob 4 | var glob = require('glob'); 5 | 6 | // Returns and array of file paths. 7 | module.exports = function buildFileArray(fileGlobs) { 8 | var files, 9 | targets = []; 10 | 11 | fileGlobs.forEach(function(fileGlob) { 12 | files = glob.sync(fileGlob); 13 | 14 | files.forEach(function(expandedFile) { 15 | targets.push(expandedFile); 16 | }); 17 | }); 18 | 19 | return targets; 20 | }; 21 | -------------------------------------------------------------------------------- /src/util/html-template-loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'), 4 | path = require('path'), 5 | Handlebars = require('handlebars'); 6 | 7 | module.exports = function(templatePath) { 8 | return function(model) { 9 | var template = Handlebars.compile(fs.readFileSync(templatePath, 'utf8').toString()); 10 | 11 | return template(model); 12 | }; 13 | }; 14 | -------------------------------------------------------------------------------- /src/util/json-walker.js: -------------------------------------------------------------------------------- 1 | // jsonWalker 2 | // walk a json object and apply a decorator function to all 3 | // string values. 4 | // Example: 5 | // jsonWalker.walk(json, function(node){ doSomthingToNode; }); 6 | // your json's strings are now decorated 7 | 'use strict'; 8 | 9 | var _ = require('lodash'), 10 | walk = function(node, targetKey, valueDecorator) { 11 | if (_.isObject(node)) { 12 | var keys = _.keys(node); 13 | _.each(keys, function(key) { 14 | var value = node[key]; 15 | if (_.isString(value) && key === targetKey) { 16 | node[key] = valueDecorator(value); 17 | } 18 | else { 19 | walk(value, targetKey, valueDecorator); 20 | } 21 | }, this); 22 | } 23 | }; 24 | 25 | module.exports = walk; 26 | -------------------------------------------------------------------------------- /src/util/node-stack-tracer.js: -------------------------------------------------------------------------------- 1 | // http://massalabs.com/dev/2013/10/17/handling-errors-in-nodejs.html 2 | 'use strict'; 3 | 4 | var prettyjson = require('prettyjson'), 5 | formatJson = function (object) { 6 | // adds 4 spaces in front of each line 7 | var json = prettyjson.render(object); 8 | // json = json.split('\n').join('\n '); 9 | return ' ' + json; 10 | }; 11 | 12 | module.exports = function(error) { 13 | var metadata = formatJson(error), 14 | stack = error.stack.trim(), 15 | message = stack + '\n Metadata:\n' + metadata; 16 | console.error(message); 17 | }; 18 | -------------------------------------------------------------------------------- /src/util/registry.js: -------------------------------------------------------------------------------- 1 | // registry pattern 2 | // good stuff from http://lostechies.com/derickbailey/2014/01/28/killing-switch-statements-with-a-registry-an-example-and-screencast/ 3 | // with good stuff from Kyle Simpson 4 | // Use by delegation. Example: 5 | // var myHash = Object.create(registry); 6 | // myHash.init({ 7 | // values: { 8 | // 'foo': function() { ... } 9 | // } 10 | // }) before use 11 | 'use strict'; 12 | 13 | module.exports = { 14 | init: function(options) { 15 | options = options || {}; 16 | this._values = options.values || Object.create( null ); 17 | this._defaultValue = options.defaultValue || null; 18 | }, 19 | 20 | register: function(name, value) { 21 | this._values[name] = value; 22 | }, 23 | 24 | getValue: function(name) { 25 | var value = this._values[name]; 26 | if (value) { 27 | return value; 28 | } else { 29 | return this._defaultValue; 30 | } 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /src/util/yaml-template-loader.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'), 4 | _ = require('lodash'); 5 | 6 | module.exports = function(templatePath) { 7 | return function(model) { 8 | var template = fs.readFileSync(templatePath, 'utf8'); 9 | return _.template(template, model); 10 | }; 11 | }; 12 | -------------------------------------------------------------------------------- /styles/api.css: -------------------------------------------------------------------------------- 1 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ 2 | /* Tomorrow Comment */ 3 | .hljs-comment, 4 | .hljs-title { 5 | color: #8e908c; } 6 | 7 | /* Tomorrow Red */ 8 | .hljs-variable, 9 | .hljs-attribute, 10 | .hljs-tag, 11 | .hljs-regexp, 12 | .ruby .hljs-constant, 13 | .xml .hljs-tag .hljs-title, 14 | .xml .hljs-pi, 15 | .xml .hljs-doctype, 16 | .html .hljs-doctype, 17 | .css .hljs-id, 18 | .css .hljs-class, 19 | .css .hljs-pseudo { 20 | color: #c82829; } 21 | 22 | /* Tomorrow Orange */ 23 | .hljs-number, 24 | .hljs-preprocessor, 25 | .hljs-pragma, 26 | .hljs-built_in, 27 | .hljs-literal, 28 | .hljs-params, 29 | .hljs-constant { 30 | color: #f5871f; } 31 | 32 | /* Tomorrow Yellow */ 33 | .ruby .hljs-class .hljs-title, 34 | .css .hljs-rules .hljs-attribute { 35 | color: #eab700; } 36 | 37 | /* Tomorrow Green */ 38 | .hljs-string, 39 | .hljs-value, 40 | .hljs-inheritance, 41 | .hljs-header, 42 | .ruby .hljs-symbol, 43 | .xml .hljs-cdata { 44 | color: #718c00; } 45 | 46 | /* Tomorrow Aqua */ 47 | .css .hljs-hexcolor { 48 | color: #3e999f; } 49 | 50 | /* Tomorrow Blue */ 51 | .hljs-function, 52 | .python .hljs-decorator, 53 | .python .hljs-title, 54 | .ruby .hljs-function .hljs-title, 55 | .ruby .hljs-title .hljs-keyword, 56 | .perl .hljs-sub, 57 | .javascript .hljs-title, 58 | .coffeescript .hljs-title { 59 | color: #4271ae; } 60 | 61 | /* Tomorrow Purple */ 62 | .hljs-keyword, 63 | .javascript .hljs-function { 64 | color: #8959a8; } 65 | 66 | .hljs { 67 | display: block; 68 | overflow-x: auto; 69 | background: white; 70 | color: #4d4d4c; 71 | padding: 0.5em; 72 | -webkit-text-size-adjust: none; } 73 | 74 | .coffeescript .javascript, 75 | .javascript .xml, 76 | .tex .hljs-formula, 77 | .xml .javascript, 78 | .xml .vbscript, 79 | .xml .css, 80 | .xml .hljs-cdata { 81 | opacity: 0.5; } 82 | 83 | *, 84 | ::before, 85 | ::after { 86 | -webkit-box-sizing: border-box; 87 | box-sizing: border-box; } 88 | 89 | html { 90 | font-size: 100%; } 91 | 92 | body { 93 | margin: 0; 94 | font: normal 1.1em/1.5 Georgia, Times, "Times New Roman", serif; 95 | -webkit-font-smoothing: antialiased; 96 | color: #56585E; } 97 | 98 | h1, h2, h3, h4, h5, h6 { 99 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 100 | font-weight: 300; 101 | color: #cf2227; } 102 | 103 | a { 104 | color: #00a6fc; } 105 | 106 | code { 107 | padding: 0 0.2em; 108 | background: #f1f1f1; 109 | border-radius: 3px; 110 | font-family: Monaco, Consolas, "Lucida Console", monospace; 111 | font-size: 0.9em; } 112 | 113 | pre { 114 | padding: 10px; 115 | background: #f8f8f8; 116 | border-radius: 6px; 117 | overflow: auto; 118 | font-size: 16px; } 119 | 120 | pre code { 121 | background: none; 122 | color: inherit; 123 | line-height: inherit; } 124 | 125 | .docs { 126 | width: 1100px; } 127 | 128 | .docs__sidebar { 129 | float: left; 130 | width: 200px; 131 | padding: 10px; 132 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } 133 | 134 | .docs__sidebar select { 135 | width: 100%; 136 | font: inherit; } 137 | 138 | .docs__sidebar nav a { 139 | display: block; 140 | font-size: 16px; 141 | text-decoration: none; } 142 | 143 | .docs__sidebar nav ul { 144 | padding: 0; 145 | margin: 0; } 146 | 147 | .docs__sidebar nav li { 148 | list-style: none; } 149 | 150 | .docs_sidebar nav li:hover { 151 | background: #D1DFE6; } 152 | 153 | .docs__sidebar h3 { 154 | margin: 0; 155 | margin-top: 5px; } 156 | 157 | .docs__sidebar .class_links { 158 | border-top: 1px solid #D9E2E7; 159 | margin-top: 10px; 160 | padding-top: 5px; } 161 | 162 | .docs__content { 163 | position: relative; 164 | float: left; 165 | width: 800px; 166 | padding: 20px; 167 | background: white; } 168 | 169 | .docs__content h1 { 170 | font-size: 24px; 171 | margin: 0 0; } 172 | 173 | .docs__content h4, .docs__content h3 { 174 | margin-bottom: 0; } 175 | 176 | .docs__content p { 177 | font-size: 16px; } 178 | 179 | .function_block { 180 | border-top: 1px solid #ccc; 181 | padding-bottom: 10px; 182 | margin-bottom: 10px; } 183 | 184 | .function_block .function_signature a { 185 | text-decoration: none; } 186 | 187 | .property_block .property a { 188 | text-decoration: none; } 189 | 190 | .example_block h4 { 191 | margin-top: 0; } 192 | 193 | .example_block .example_content { 194 | display: none; } 195 | -------------------------------------------------------------------------------- /stylesheets/api.scss: -------------------------------------------------------------------------------- 1 | @import "api/highlight_tomorrow"; 2 | 3 | 4 | *, 5 | ::before, 6 | ::after { 7 | -webkit-box-sizing: border-box; 8 | box-sizing: border-box; 9 | } 10 | 11 | html { 12 | font-size: 100%; 13 | } 14 | 15 | body { 16 | margin: 0; 17 | font: normal 1.1em/1.5 Georgia, Times, "Times New Roman", serif; 18 | -webkit-font-smoothing: antialiased; 19 | color: #56585E; 20 | } 21 | 22 | h1, h2, h3, h4, h5, h6 { 23 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 24 | font-weight: 300; 25 | color: #cf2227; 26 | } 27 | 28 | a { 29 | color: #00a6fc; 30 | } 31 | 32 | code { 33 | padding: 0 0.2em; 34 | background: #f1f1f1; 35 | border-radius: 3px; 36 | font-family: Monaco, Consolas, "Lucida Console", monospace; 37 | font-size: 0.9em; 38 | } 39 | 40 | pre { 41 | padding: 10px; 42 | background: #f8f8f8; 43 | border-radius: 6px; 44 | overflow: auto; 45 | font-size: 16px; 46 | } 47 | 48 | pre code { 49 | background: none; 50 | color: inherit; 51 | line-height: inherit; 52 | } 53 | 54 | .docs { 55 | width: 1100px; 56 | } 57 | 58 | .docs__sidebar { 59 | float:left; 60 | width: 200px; 61 | padding: 10px; 62 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 63 | } 64 | 65 | .docs__sidebar select { 66 | width: 100%; 67 | font: inherit; 68 | } 69 | 70 | .docs__sidebar nav a { 71 | display: block; 72 | font-size: 16px; 73 | text-decoration: none; 74 | } 75 | 76 | .docs__sidebar nav ul { 77 | padding: 0; 78 | margin: 0; 79 | } 80 | 81 | .docs__sidebar nav li { 82 | list-style: none; 83 | } 84 | 85 | .docs_sidebar nav li:hover { 86 | background: #D1DFE6; 87 | } 88 | 89 | .docs__sidebar h3 { 90 | margin: 0; 91 | margin-top:5px; 92 | } 93 | 94 | .docs__sidebar .class_links { 95 | border-top: 1px solid #D9E2E7; 96 | margin-top:10px; 97 | padding-top:5px; 98 | } 99 | 100 | 101 | .docs__content { 102 | position: relative; 103 | float: left; 104 | width: 800px; 105 | padding: 20px; 106 | background: white; 107 | } 108 | 109 | .docs__content h1 { 110 | font-size: 24px; 111 | margin: 0 0; 112 | } 113 | 114 | .docs__content h4, .docs__content h3 { 115 | margin-bottom: 0; 116 | } 117 | 118 | .docs__content p { 119 | font-size: 16px; 120 | } 121 | 122 | .function_block { 123 | border-top: 1px solid #ccc; 124 | padding-bottom: 10px; 125 | margin-bottom: 10px; 126 | } 127 | 128 | .function_block .function_signature a{ 129 | text-decoration: none; 130 | } 131 | 132 | .property_block .property a{ 133 | text-decoration: none; 134 | } 135 | 136 | 137 | .example_block {} 138 | 139 | .example_block h4 { 140 | margin-top: 0; 141 | } 142 | 143 | .example_block .example_content { 144 | display: none; 145 | } 146 | -------------------------------------------------------------------------------- /stylesheets/api/_highlight_tomorrow.scss: -------------------------------------------------------------------------------- 1 | /* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ 2 | 3 | /* Tomorrow Comment */ 4 | .hljs-comment, 5 | .hljs-title { 6 | color: #8e908c; 7 | } 8 | 9 | /* Tomorrow Red */ 10 | .hljs-variable, 11 | .hljs-attribute, 12 | .hljs-tag, 13 | .hljs-regexp, 14 | .ruby .hljs-constant, 15 | .xml .hljs-tag .hljs-title, 16 | .xml .hljs-pi, 17 | .xml .hljs-doctype, 18 | .html .hljs-doctype, 19 | .css .hljs-id, 20 | .css .hljs-class, 21 | .css .hljs-pseudo { 22 | color: #c82829; 23 | } 24 | 25 | /* Tomorrow Orange */ 26 | .hljs-number, 27 | .hljs-preprocessor, 28 | .hljs-pragma, 29 | .hljs-built_in, 30 | .hljs-literal, 31 | .hljs-params, 32 | .hljs-constant { 33 | color: #f5871f; 34 | } 35 | 36 | /* Tomorrow Yellow */ 37 | .ruby .hljs-class .hljs-title, 38 | .css .hljs-rules .hljs-attribute { 39 | color: #eab700; 40 | } 41 | 42 | /* Tomorrow Green */ 43 | .hljs-string, 44 | .hljs-value, 45 | .hljs-inheritance, 46 | .hljs-header, 47 | .ruby .hljs-symbol, 48 | .xml .hljs-cdata { 49 | color: #718c00; 50 | } 51 | 52 | /* Tomorrow Aqua */ 53 | .css .hljs-hexcolor { 54 | color: #3e999f; 55 | } 56 | 57 | /* Tomorrow Blue */ 58 | .hljs-function, 59 | .python .hljs-decorator, 60 | .python .hljs-title, 61 | .ruby .hljs-function .hljs-title, 62 | .ruby .hljs-title .hljs-keyword, 63 | .perl .hljs-sub, 64 | .javascript .hljs-title, 65 | .coffeescript .hljs-title { 66 | color: #4271ae; 67 | } 68 | 69 | /* Tomorrow Purple */ 70 | .hljs-keyword, 71 | .javascript .hljs-function { 72 | color: #8959a8; 73 | } 74 | 75 | .hljs { 76 | display: block; 77 | overflow-x: auto; 78 | background: white; 79 | color: #4d4d4c; 80 | padding: 0.5em; 81 | -webkit-text-size-adjust: none; 82 | } 83 | 84 | .coffeescript .javascript, 85 | .javascript .xml, 86 | .tex .hljs-formula, 87 | .xml .javascript, 88 | .xml .vbscript, 89 | .xml .css, 90 | .xml .hljs-cdata { 91 | opacity: 0.5; 92 | } 93 | -------------------------------------------------------------------------------- /test/.jsdoccerrc-test: -------------------------------------------------------------------------------- 1 | { 2 | // Note: all comments are striped before this file is parsed. 3 | // if null the project name will be pulled from the root dir name 4 | "projectName": null, 5 | 6 | "js": { 7 | // glob paths to the js you want to document 8 | "src": ["./src/*.js"] 9 | }, 10 | 11 | "documentedYaml": { 12 | // Glob paths to your documented yaml. 13 | "src": ["./api/application.jsdoc"] 14 | }, 15 | 16 | // All generated intermediate files will be placed under this path. 17 | "dest": "./doccer/", 18 | 19 | // Syntax targets 20 | "targets": { 21 | "default": { 22 | "name": true, 23 | "class": true, 24 | "constructor": true, 25 | "events": true, 26 | "functions": true, 27 | "properties": true 28 | }, 29 | "custom": { 30 | // Add custom targets here. Example 31 | // "myTarget": { 32 | // "linter": "path/to/linter/function", 33 | // "matcher": "path/to/matcher/function", 34 | // "templateYaml": "path/to/templateYaml/function", 35 | // "templateHtml": "path/to/templateHtml/function" 36 | // } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | test/specs/src/**/*.js 2 | -------------------------------------------------------------------------------- /test/mock-files/docs/application.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 |
8 | 49 |
50 | 51 |
52 |

Application

53 |
Class: Marionette.Application
54 | 55 | 56 |

Applications are the entry point into most Marionette Applications. 57 | For all but the simplest of webapps you'll want to instantiate a new Application to act as the hub for the rest of your code.

58 |

Applications let you accomplish three things. 59 | Firstly, they provide a place to put start up code for your app through its Initializers. 60 | Secondly, they allow you to group your code into logical sections with the Module system. 61 | Lastly, they give you a way to connect Views to the document through its Regions.

62 |
var MyApp = new Backbone.Marionette.Application();
 63 | 
64 | 65 | 66 | 67 |
68 | 71 | 72 |

Creates a new Application.

73 |

The constructor function calls initialize if it exists, and sets the properties of the Application. 74 | Note that Applications are unique in that their options are automatically attached to the Application instead of a separate options object.

75 |

The options parameter can take any key/value pair and set it on the application instance. 76 | Two special properties that are used in the application are:

77 |
    78 |
  • regions - regions are set on the app
  • 79 |
  • channelName - channel name for the app
  • 80 |
81 | 82 | 83 |
84 |

Params

85 |
86 | options 87 | (...*) 88 |   Options to be available on the Application instance directly. 89 |
90 |
91 | 92 |

Examples

93 |
94 |

Add regions

95 |

You can also specify regions per Application instance.

96 |
new Marionette.Application({
 97 |   regions: {
 98 |     fooRegion: '#foo-region'
 99 |   }
100 | });
101 | 
102 | 103 |
104 |
105 | 106 | 107 |

Functions

108 |
109 | 112 |

If initialize is set in the Application class, it will be called when new regions are instantiated.

113 | 114 | 115 |
116 |

Params

117 |
118 | options 119 | (Object) 120 |   The constructor's options 121 |
122 |
123 | 124 |

Examples

125 |
126 |

Basic Use

127 |
128 |

The initialize function is a good place to put custom, post instantiation class logic.

129 |
var MyApp = Marionette.Application.extend({
130 |   initialize: function(options) {
131 |     console.log(options.container);
132 |   }
133 | });
134 | 
135 | var myApp = new MyApp({container: '#app'});
136 | 
137 | 138 |
139 |
140 |
141 |
142 | 143 |
144 |
145 | 146 |
147 |
148 | 151 |

Adds an initializer that runs once the Application has started, 152 | or immediately if the app has already been started.

153 |

Initializer callbacks will be executed when you start your application, 154 | and are bound to the application object as the context for 155 | the callback. In other words, this is the MyApp object inside 156 | of the initializer function.

157 |

The callback options argument is passed from the start method (see below).

158 |

Initializer callbacks are guaranteed to run, no matter when you 159 | add them to the app object. If you add them before the app is 160 | started, they will run when the start method is called. If you 161 | add them after the app is started, they will run immediately.

162 | 163 | 164 |
165 |

Params

166 |
167 | initializer 168 | 169 | 170 |
171 |
172 | 173 |

Examples

174 |
175 |

Adding initializers

176 |
177 |

Your application needs to do useful things, like displaying content in your 178 | regions, starting up your routers, and more. To accomplish these tasks and 179 | ensure that your Application is fully configured, you can add initializer 180 | callbacks to the application.

181 |
MyApp.addInitializer(function(options){
182 |   // do useful stuff here
183 |   var myView = new MyView({
184 |     model: options.someModel
185 |   });
186 |   MyApp.getRegion("main").show(myView);
187 | });
188 | 
189 | MyApp.addInitializer(function(options){
190 |   new MyAppRouter();
191 |   Backbone.history.start();
192 | });
193 | 
194 | 195 |
196 |
197 |
198 |
199 |
200 |

● start(options)

201 |
202 |

Start the Application, triggering the Initializers array of callbacks.

203 | 204 | 205 |
206 |

Params

207 |
208 | options 209 | (...*) 210 |   Options to pass to the `start` triggerMethods and the Initializers functions. 211 |
212 |
213 | 214 |

Examples

215 |
216 |

Starting an Application

217 |
218 |

Once you have your application configured, you can kick everything off by 219 | calling: MyApp.start(options).

220 |

This function takes a single optional parameter. This parameter will be passed 221 | to each of your initializer functions, as well as the initialize events. This 222 | allows you to provide extra configuration for various parts of your app throughout the 223 | initialization sequence.

224 |
var options = {
225 |   something: "some value",
226 |   another: "#some-selector"
227 | };
228 | 
229 | MyApp.start(options);
230 | 
231 | 232 |
233 |
234 |
235 |
236 | 239 |

You can create Regions through the addRegions method by passing in an object 240 | literal or a function that returns an object literal.

241 |

For more information on regions, see the region documentation 242 | Also, the API that Applications use to manage regions comes from the RegionManager Class, 243 | which is documented over here.

244 | 245 | 246 |
247 |

Params

248 |
249 | regions 250 | (Object, Function) 251 | 252 |
253 |
254 | 255 |

Examples

256 |
257 |

jQuery Selector

258 |
259 |

The first is to specify a jQuery selector as the value of the region 260 | definition. This will create an instance of a Marionette.Region directly, 261 | and assign it to the selector:

262 |
MyApp.addRegions({
263 |   someRegion: "#some-div",
264 |   anotherRegion: "#another-div"
265 | });
266 | 
267 | 268 |
269 |
270 |
271 |

Custom Region Class

272 |
273 |

The second is to specify a custom region class, where the region class has 274 | already specified a selector:

275 |
var MyCustomRegion = Marionette.Region.extend({
276 |   el: "#foo"
277 | });
278 | 
279 | MyApp.addRegions(function() {
280 |   return {
281 |     someRegion: MyCustomRegion
282 |   };
283 | });
284 | 
285 | 286 |
287 |
288 |
289 |

Custom Region Class And Selector

290 |
291 |

The third method is to specify a custom region class, and a jQuery selector 292 | for this region instance, using an object literal:

293 |
var MyCustomRegion = Marionette.Region.extend({});
294 | 
295 | MyApp.addRegions({
296 | 
297 |   someRegion: {
298 |     selector: "#foo",
299 |     regionClass: MyCustomRegion
300 |   },
301 | 
302 |   anotherRegion: {
303 |     selector: "#bar",
304 |     regionClass: MyCustomRegion
305 |   }
306 | 
307 | });
308 | 
309 | 310 |
311 |
312 |
313 |
314 | 315 |
316 |
317 | 320 |

Removes the specified Region from the Application. 321 | Removing a region will properly empty it before removing it from the application object.

322 | 323 | 324 |
325 |

Params

326 |
327 | regionName 328 | (String) 329 |   The name of the Region to be removed. 330 |
331 |
332 | 333 |

Examples

334 |
335 |

Remove a region

336 |
337 |

Regions can also be removed with the removeRegion method, passing in 338 | the name of the region to remove as a string value:

339 |
MyApp.removeRegion("someRegion");
340 | 
341 | 342 |
343 |
344 |
345 |
346 | 349 |

Returns a Region by name.

350 | 351 | 352 |
353 |

Params

354 |
355 | regionName 356 | (String) 357 |   The name of the Region to receive. 358 |
359 |
360 | 361 |

Examples

362 |
363 |

Get Region by name

364 |
365 |

A region can be retrieved by name, using the getRegion method:

366 |
var app = new Marionette.Application();
367 | app.addRegions({ r1: "#region1" });
368 | 
369 | // r1 === r1Again; true
370 | var r1 = app.getRegion("r1");
371 | var r1Again = app.r1;
372 | 
373 |

This is the preferred method of accessing Regions on the Application instance.

374 | 375 |
376 |
377 |
378 |
379 | 380 |
381 |
382 | 383 |
384 |
385 | 386 |
387 |
388 | 389 |
390 |
391 | 392 |
393 |
394 | 395 |
396 | 397 | 398 |

Properties

399 |
400 | 401 |
402 |
403 | 404 |
405 |
406 | 407 |
408 |
409 | 410 |
411 |
412 |
413 |

● regions

414 |
415 |

Region Options

416 | 417 | 418 |

Examples

419 |
420 |

Add regions as prototype property

421 |

You can also specify regions as a prototype property.

422 |
Marionette.Application.extend({
423 |   regions: {
424 |     fooRegion: '#foo-region'
425 |   }
426 | });
427 | 
428 | 429 |
430 |
431 |

Add regions as prototype function

432 |

You can also specify regions as a prototype function.

433 |

The options parameter is same as the constructor options parameter.

434 |
Marionette.Application.extend({
435 |   regions: function(options) {
436 |     return {
437 |       fooRegion: '#foo-region'
438 |     }
439 |   }
440 | });
441 | 
442 | 443 |
444 |
445 | 446 | 447 | 448 |
449 |
450 | 451 | 452 | -------------------------------------------------------------------------------- /test/mock-files/js/application.js: -------------------------------------------------------------------------------- 1 | // Application 2 | // ----------- 3 | 4 | // Contain and manage the composite application as a whole. 5 | // Stores and starts up `Region` objects, includes an 6 | // event aggregator as `app.vent` 7 | Marionette.Application = Marionette.Object.extend({ 8 | constructor: function(options) { 9 | this._initializeRegions(options); 10 | this._initCallbacks = new Marionette.Callbacks(); 11 | this.submodules = {}; 12 | _.extend(this, options); 13 | this._initChannel(); 14 | Marionette.Object.call(this, options); 15 | }, 16 | 17 | // Command execution, facilitated by Backbone.Wreqr.Commands 18 | execute: function() { 19 | this.commands.execute.apply(this.commands, arguments); 20 | }, 21 | 22 | // Request/response, facilitated by Backbone.Wreqr.RequestResponse 23 | request: function() { 24 | return this.reqres.request.apply(this.reqres, arguments); 25 | }, 26 | 27 | // Add an initializer that is either run at when the `start` 28 | // method is called, or run immediately if added after `start` 29 | // has already been called. 30 | addInitializer: function(initializer) { 31 | this._initCallbacks.add(initializer); 32 | }, 33 | 34 | // kick off all of the application's processes. 35 | // initializes all of the regions that have been added 36 | // to the app, and runs all of the initializer functions 37 | start: function(options) { 38 | this.triggerMethod('before:start', options); 39 | this._initCallbacks.run(options, this); 40 | this.triggerMethod('start', options); 41 | }, 42 | 43 | // Add regions to your app. 44 | // Accepts a hash of named strings or Region objects 45 | // addRegions({something: "#someRegion"}) 46 | // addRegions({something: Region.extend({el: "#someRegion"}) }); 47 | addRegions: function(regions) { 48 | return this._regionManager.addRegions(regions); 49 | }, 50 | 51 | // Empty all regions in the app, without removing them 52 | emptyRegions: function() { 53 | return this._regionManager.emptyRegions(); 54 | }, 55 | 56 | // Removes a region from your app, by name 57 | // Accepts the regions name 58 | // removeRegion('myRegion') 59 | removeRegion: function(region) { 60 | return this._regionManager.removeRegion(region); 61 | }, 62 | 63 | // Provides alternative access to regions 64 | // Accepts the region name 65 | // getRegion('main') 66 | getRegion: function(region) { 67 | return this._regionManager.get(region); 68 | }, 69 | 70 | // Get all the regions from the region manager 71 | getRegions: function(){ 72 | return this._regionManager.getRegions(); 73 | }, 74 | 75 | // Create a module, attached to the application 76 | module: function(moduleNames, moduleDefinition) { 77 | 78 | // Overwrite the module class if the user specifies one 79 | var ModuleClass = Marionette.Module.getClass(moduleDefinition); 80 | 81 | var args = _.toArray(arguments); 82 | args.unshift(this); 83 | 84 | // see the Marionette.Module object for more information 85 | return ModuleClass.create.apply(ModuleClass, args); 86 | }, 87 | 88 | // Enable easy overriding of the default `RegionManager` 89 | // for customized region interactions and business-specific 90 | // view logic for better control over single regions. 91 | getRegionManager: function() { 92 | return new Marionette.RegionManager(); 93 | }, 94 | 95 | // Internal method to initialize the regions that have been defined in a 96 | // `regions` attribute on the application instance 97 | _initializeRegions: function(options) { 98 | var regions = _.isFunction(this.regions) ? this.regions(options) : this.regions || {}; 99 | 100 | this._initRegionManager(); 101 | 102 | // Enable users to define `regions` in instance options. 103 | var optionRegions = Marionette.getOption(options, 'regions'); 104 | 105 | // Enable region options to be a function 106 | if (_.isFunction(optionRegions)) { 107 | optionRegions = optionRegions.call(this, options); 108 | } 109 | 110 | // Overwrite current regions with those passed in options 111 | _.extend(regions, optionRegions); 112 | 113 | this.addRegions(regions); 114 | 115 | return this; 116 | }, 117 | 118 | // Internal method to set up the region manager 119 | _initRegionManager: function() { 120 | this._regionManager = this.getRegionManager(); 121 | this._regionManager._parent = this; 122 | 123 | this.listenTo(this._regionManager, 'before:add:region', function() { 124 | Marionette._triggerMethod(this, 'before:add:region', arguments); 125 | }); 126 | 127 | this.listenTo(this._regionManager, 'add:region', function(name, region) { 128 | this[name] = region; 129 | Marionette._triggerMethod(this, 'add:region', arguments); 130 | }); 131 | 132 | this.listenTo(this._regionManager, 'before:remove:region', function() { 133 | Marionette._triggerMethod(this, 'before:remove:region', arguments); 134 | }); 135 | 136 | this.listenTo(this._regionManager, 'remove:region', function(name) { 137 | delete this[name]; 138 | Marionette._triggerMethod(this, 'remove:region', arguments); 139 | }); 140 | }, 141 | 142 | // Internal method to setup the Wreqr.radio channel 143 | _initChannel: function() { 144 | this.channelName = _.result(this, 'channelName') || 'global'; 145 | this.channel = _.result(this, 'channel') || Backbone.Wreqr.radio.channel(this.channelName); 146 | this.vent = _.result(this, 'vent') || this.channel.vent; 147 | this.commands = _.result(this, 'commands') || this.channel.commands; 148 | this.reqres = _.result(this, 'reqres') || this.channel.reqres; 149 | } 150 | }); -------------------------------------------------------------------------------- /test/mock-files/js/test.js: -------------------------------------------------------------------------------- 1 | var answer = 42; -------------------------------------------------------------------------------- /test/mock-files/json-api/application.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Application", 3 | "class": "Marionette.Application", 4 | "description": { 5 | "tags": [], 6 | "description": { 7 | "full": "

Applications are the entry point into most Marionette Applications. \nFor all but the simplest of webapps you'll want to instantiate a new Application to act as the hub for the rest of your code.

\n

Applications let you accomplish three things. \nFirstly, they provide a place to put start up code for your app through its Initializers. \nSecondly, they allow you to group your code into logical sections with the Module system. \nLastly, they give you a way to connect Views to the document through its Regions.

\n
var MyApp = new Backbone.Marionette.Application();\n
\n", 8 | "summary": "

Applications are the entry point into most Marionette Applications. \nFor all but the simplest of webapps you'll want to instantiate a new Application to act as the hub for the rest of your code.

\n", 9 | "body": "

Applications let you accomplish three things. \nFirstly, they provide a place to put start up code for your app through its Initializers. \nSecondly, they allow you to group your code into logical sections with the Module system. \nLastly, they give you a way to connect Views to the document through its Regions.

\n
var MyApp = new Backbone.Marionette.Application();\n
\n" 10 | }, 11 | "isPrivate": false, 12 | "params": [], 13 | "paramStr": "" 14 | }, 15 | "constructor": { 16 | "description": { 17 | "tags": [ 18 | { 19 | "type": "param", 20 | "types": [ 21 | "...*" 22 | ], 23 | "name": "options", 24 | "description": "Options to be available on the Application instance directly.", 25 | "optional": false, 26 | "typeStr": "...*" 27 | } 28 | ], 29 | "description": { 30 | "full": "

Creates a new Application.

\n

The constructor function calls initialize if it exists, and sets the properties of the Application. \nNote that Applications are unique in that their options are automatically attached to the Application instead of a separate options object.

\n

The options parameter can take any key/value pair and set it on the application instance.\nTwo special properties that are used in the application are:

\n
    \n
  • regions - regions are set on the app
  • \n
  • channelName - channel name for the app
  • \n
\n", 31 | "summary": "

Creates a new Application.

\n", 32 | "body": "

The constructor function calls initialize if it exists, and sets the properties of the Application. \nNote that Applications are unique in that their options are automatically attached to the Application instead of a separate options object.

\n

The options parameter can take any key/value pair and set it on the application instance.\nTwo special properties that are used in the application are:

\n
    \n
  • regions - regions are set on the app
  • \n
  • channelName - channel name for the app
  • \n
\n" 33 | }, 34 | "isPrivate": false, 35 | "params": [ 36 | { 37 | "type": "param", 38 | "types": [ 39 | "...*" 40 | ], 41 | "name": "options", 42 | "description": "Options to be available on the Application instance directly.", 43 | "optional": false, 44 | "typeStr": "...*" 45 | } 46 | ], 47 | "paramStr": "options" 48 | }, 49 | "examples": [ 50 | { 51 | "name": "Add regions", 52 | "example": "

You can also specify regions per Application instance.

\n
new Marionette.Application({\n  regions: {\n    fooRegion: '#foo-region'\n  }\n});\n
\n" 53 | } 54 | ] 55 | }, 56 | "properties": { 57 | "vent": "The eventAggregator from the global Channel to be used for Application-level events.\n\n@type {Backbone.Wreqr.EventAggregator}\n", 58 | "commands": "The commands instance from the global Channel to be used for Application-level commands.\n\n@type {Backbone.Wreqr.Commands}\n", 59 | "reqres": "The RequestResponse instance from the global Channel to be used for Application-level requests.\n\n@type {Backbone.Wreqr.RequestResponse}\n", 60 | "submodules": "The container for the Application's modules. \nModules are stored with their name as the key, and the module itself as the value.\n\n@type {Object}\n", 61 | "regions": { 62 | "description": { 63 | "tags": [], 64 | "description": { 65 | "full": "

Region Options

\n", 66 | "summary": "

Region Options

\n", 67 | "body": "" 68 | }, 69 | "isPrivate": false, 70 | "params": [], 71 | "paramStr": "" 72 | }, 73 | "examples": [ 74 | { 75 | "name": "Add regions as prototype property", 76 | "example": "

You can also specify regions as a prototype property.

\n
Marionette.Application.extend({\n  regions: {\n    fooRegion: '#foo-region'\n  }\n});\n
\n" 77 | }, 78 | { 79 | "name": "Add regions as prototype function", 80 | "example": "

You can also specify regions as a prototype function.

\n

The options parameter is same as the constructor options parameter.

\n
Marionette.Application.extend({\n  regions: function(options) {\n    return {\n      fooRegion: '#foo-region'\n    }\n  }\n});\n
\n" 81 | } 82 | ] 83 | } 84 | }, 85 | "functions": { 86 | "initialize": { 87 | "description": { 88 | "tags": [ 89 | { 90 | "type": "param", 91 | "types": [ 92 | "Object" 93 | ], 94 | "name": "options", 95 | "description": "The constructor's options", 96 | "optional": false, 97 | "typeStr": "Object" 98 | } 99 | ], 100 | "description": { 101 | "full": "

If initialize is set in the Application class, it will be called when new regions are instantiated.

\n", 102 | "summary": "

If initialize is set in the Application class, it will be called when new regions are instantiated.

\n", 103 | "body": "" 104 | }, 105 | "isPrivate": false, 106 | "params": [ 107 | { 108 | "type": "param", 109 | "types": [ 110 | "Object" 111 | ], 112 | "name": "options", 113 | "description": "The constructor's options", 114 | "optional": false, 115 | "typeStr": "Object" 116 | } 117 | ], 118 | "paramStr": "options" 119 | }, 120 | "examples": [ 121 | { 122 | "name": "Basic Use", 123 | "example": "

The initialize function is a good place to put custom, post instantiation class logic.

\n
var MyApp = Marionette.Application.extend({\n  initialize: function(options) {\n    console.log(options.container);\n  }\n});\n\nvar myApp = new MyApp({container: '#app'});\n
\n" 124 | } 125 | ] 126 | }, 127 | "execute": "A convenience method to access the execute method\non the instance of Backbone.Wreqr.Commands attached to\nevery instance of Marionette.Application.\n\nThis method is alternatively available as app.commands.execute,\nwhere app is the instance name of the Application.\n\n@param {String} commandName - The command to be executed.\n@param {...*} args - Additional arguments to pass to the command callback.\n@api public\n", 128 | "request": "A convenience method to access the request method on the instance of \nBackbone.Wreqr.RequestResponse attached to every instance of Marionette.Application.\n\nThis method is alternatively available as app.reqres.request,\nwhere app is the instance name of the Application.\n\n@param {String} requestName - The name of the request.\n@param {...*} args - Additional arguments to pass to the response callback.\n@api public\n", 129 | "addInitializer": { 130 | "description": { 131 | "tags": [ 132 | { 133 | "type": "api", 134 | "visibility": "public" 135 | }, 136 | { 137 | "type": "param", 138 | "types": [ 139 | "" 140 | ], 141 | "name": "initializer", 142 | "description": "", 143 | "optional": false, 144 | "typeStr": "" 145 | } 146 | ], 147 | "description": { 148 | "full": "

Adds an initializer that runs once the Application has started,\nor immediately if the app has already been started.

\n

Initializer callbacks will be executed when you start your application,\nand are bound to the application object as the context for\nthe callback. In other words, this is the MyApp object inside\nof the initializer function.

\n

The callback options argument is passed from the start method (see below).

\n

Initializer callbacks are guaranteed to run, no matter when you\nadd them to the app object. If you add them before the app is\nstarted, they will run when the start method is called. If you\nadd them after the app is started, they will run immediately.

\n", 149 | "summary": "

Adds an initializer that runs once the Application has started,\nor immediately if the app has already been started.

\n", 150 | "body": "

Initializer callbacks will be executed when you start your application,\nand are bound to the application object as the context for\nthe callback. In other words, this is the MyApp object inside\nof the initializer function.

\n

The callback options argument is passed from the start method (see below).

\n

Initializer callbacks are guaranteed to run, no matter when you\nadd them to the app object. If you add them before the app is\nstarted, they will run when the start method is called. If you\nadd them after the app is started, they will run immediately.

\n" 151 | }, 152 | "isPrivate": false, 153 | "api": { 154 | "type": "api", 155 | "visibility": "public" 156 | }, 157 | "params": [ 158 | { 159 | "type": "param", 160 | "types": [ 161 | "" 162 | ], 163 | "name": "initializer", 164 | "description": "", 165 | "optional": false, 166 | "typeStr": "" 167 | } 168 | ], 169 | "paramStr": "initializer" 170 | }, 171 | "examples": [ 172 | { 173 | "name": "Adding initializers", 174 | "example": "

Your application needs to do useful things, like displaying content in your\nregions, starting up your routers, and more. To accomplish these tasks and\nensure that your Application is fully configured, you can add initializer\ncallbacks to the application.

\n
MyApp.addInitializer(function(options){\n  // do useful stuff here\n  var myView = new MyView({\n    model: options.someModel\n  });\n  MyApp.getRegion(\"main\").show(myView);\n});\n\nMyApp.addInitializer(function(options){\n  new MyAppRouter();\n  Backbone.history.start();\n});\n
\n" 175 | } 176 | ] 177 | }, 178 | "start": { 179 | "description": { 180 | "tags": [ 181 | { 182 | "type": "param", 183 | "types": [ 184 | "...*" 185 | ], 186 | "name": "options", 187 | "description": "Options to pass to the `start` triggerMethods and the Initializers functions.", 188 | "optional": false, 189 | "typeStr": "...*" 190 | }, 191 | { 192 | "type": "api", 193 | "visibility": "public" 194 | } 195 | ], 196 | "description": { 197 | "full": "

Start the Application, triggering the Initializers array of callbacks.

\n", 198 | "summary": "

Start the Application, triggering the Initializers array of callbacks.

\n", 199 | "body": "" 200 | }, 201 | "isPrivate": false, 202 | "api": { 203 | "type": "api", 204 | "visibility": "public" 205 | }, 206 | "params": [ 207 | { 208 | "type": "param", 209 | "types": [ 210 | "...*" 211 | ], 212 | "name": "options", 213 | "description": "Options to pass to the `start` triggerMethods and the Initializers functions.", 214 | "optional": false, 215 | "typeStr": "...*" 216 | } 217 | ], 218 | "paramStr": "options" 219 | }, 220 | "examples": [ 221 | { 222 | "name": "Starting an Application", 223 | "example": "

Once you have your application configured, you can kick everything off by\ncalling: MyApp.start(options).

\n

This function takes a single optional parameter. This parameter will be passed\nto each of your initializer functions, as well as the initialize events. This\nallows you to provide extra configuration for various parts of your app throughout the\ninitialization sequence.

\n
var options = {\n  something: \"some value\",\n  another: \"#some-selector\"\n};\n\nMyApp.start(options);\n
\n" 224 | } 225 | ] 226 | }, 227 | "addRegions": { 228 | "description": { 229 | "tags": [ 230 | { 231 | "type": "api", 232 | "visibility": "public" 233 | }, 234 | { 235 | "type": "param", 236 | "types": [ 237 | "Object", 238 | "Function" 239 | ], 240 | "name": "regions", 241 | "description": "", 242 | "optional": false, 243 | "typeStr": "Object, Function" 244 | } 245 | ], 246 | "description": { 247 | "full": "

You can create Regions through the addRegions method by passing in an object\nliteral or a function that returns an object literal.

\n

For more information on regions, see the region documentation \nAlso, the API that Applications use to manage regions comes from the RegionManager Class, \nwhich is documented over here.

\n", 248 | "summary": "

You can create Regions through the addRegions method by passing in an object\nliteral or a function that returns an object literal.

\n", 249 | "body": "

For more information on regions, see the region documentation \nAlso, the API that Applications use to manage regions comes from the RegionManager Class, \nwhich is documented over here.

\n" 250 | }, 251 | "isPrivate": false, 252 | "api": { 253 | "type": "api", 254 | "visibility": "public" 255 | }, 256 | "params": [ 257 | { 258 | "type": "param", 259 | "types": [ 260 | "Object", 261 | "Function" 262 | ], 263 | "name": "regions", 264 | "description": "", 265 | "optional": false, 266 | "typeStr": "Object, Function" 267 | } 268 | ], 269 | "paramStr": "regions" 270 | }, 271 | "examples": [ 272 | { 273 | "name": "jQuery Selector", 274 | "example": "

The first is to specify a jQuery selector as the value of the region\ndefinition. This will create an instance of a Marionette.Region directly,\nand assign it to the selector:

\n
MyApp.addRegions({\n  someRegion: \"#some-div\",\n  anotherRegion: \"#another-div\"\n});\n
\n" 275 | }, 276 | { 277 | "name": "Custom Region Class", 278 | "example": "

The second is to specify a custom region class, where the region class has\nalready specified a selector:

\n
var MyCustomRegion = Marionette.Region.extend({\n  el: \"#foo\"\n});\n\nMyApp.addRegions(function() {\n  return {\n    someRegion: MyCustomRegion\n  };\n});\n
\n" 279 | }, 280 | { 281 | "name": "Custom Region Class And Selector", 282 | "example": "

The third method is to specify a custom region class, and a jQuery selector\nfor this region instance, using an object literal:

\n
var MyCustomRegion = Marionette.Region.extend({});\n\nMyApp.addRegions({\n\n  someRegion: {\n    selector: \"#foo\",\n    regionClass: MyCustomRegion\n  },\n\n  anotherRegion: {\n    selector: \"#bar\",\n    regionClass: MyCustomRegion\n  }\n\n});\n
\n" 283 | } 284 | ] 285 | }, 286 | "emptyRegions": "Empties all of the Application's Regions by destroying the View within each Region.\n\n@api public\n", 287 | "removeRegion": { 288 | "description": { 289 | "tags": [ 290 | { 291 | "type": "param", 292 | "types": [ 293 | "String" 294 | ], 295 | "name": "regionName", 296 | "description": "The name of the Region to be removed.", 297 | "optional": false, 298 | "typeStr": "String" 299 | }, 300 | { 301 | "type": "api", 302 | "visibility": "public" 303 | } 304 | ], 305 | "description": { 306 | "full": "

Removes the specified Region from the Application. \nRemoving a region will properly empty it before removing it from the application object.

\n", 307 | "summary": "

Removes the specified Region from the Application. \nRemoving a region will properly empty it before removing it from the application object.

\n", 308 | "body": "" 309 | }, 310 | "isPrivate": false, 311 | "api": { 312 | "type": "api", 313 | "visibility": "public" 314 | }, 315 | "params": [ 316 | { 317 | "type": "param", 318 | "types": [ 319 | "String" 320 | ], 321 | "name": "regionName", 322 | "description": "The name of the Region to be removed.", 323 | "optional": false, 324 | "typeStr": "String" 325 | } 326 | ], 327 | "paramStr": "regionName" 328 | }, 329 | "examples": [ 330 | { 331 | "name": "Remove a region", 332 | "example": "

Regions can also be removed with the removeRegion method, passing in\nthe name of the region to remove as a string value:

\n
MyApp.removeRegion(\"someRegion\");\n
\n" 333 | } 334 | ] 335 | }, 336 | "getRegion": { 337 | "description": { 338 | "tags": [ 339 | { 340 | "type": "param", 341 | "types": [ 342 | "String" 343 | ], 344 | "name": "regionName", 345 | "description": "The name of the Region to receive.", 346 | "optional": false, 347 | "typeStr": "String" 348 | }, 349 | { 350 | "type": "api", 351 | "visibility": "public" 352 | } 353 | ], 354 | "description": { 355 | "full": "

Returns a Region by name.

\n", 356 | "summary": "

Returns a Region by name.

\n", 357 | "body": "" 358 | }, 359 | "isPrivate": false, 360 | "api": { 361 | "type": "api", 362 | "visibility": "public" 363 | }, 364 | "params": [ 365 | { 366 | "type": "param", 367 | "types": [ 368 | "String" 369 | ], 370 | "name": "regionName", 371 | "description": "The name of the Region to receive.", 372 | "optional": false, 373 | "typeStr": "String" 374 | } 375 | ], 376 | "paramStr": "regionName" 377 | }, 378 | "examples": [ 379 | { 380 | "name": "Get Region by name", 381 | "example": "

A region can be retrieved by name, using the getRegion method:

\n
var app = new Marionette.Application();\napp.addRegions({ r1: \"#region1\" });\n\n// r1 === r1Again; true\nvar r1 = app.getRegion(\"r1\");\nvar r1Again = app.r1;\n
\n

This is the preferred method of accessing Regions on the Application instance.

\n" 382 | } 383 | ] 384 | }, 385 | "getRegions": "Returns an array of every Region from the RegionManager\n\n@api public\n", 386 | "module": "Create a module, attached to the application\n\n@api public\n@param {} moduleNames\n@param {} moduleDefinition\n", 387 | "getRegionManager": "Returns a new instance of a region manager.\n\nEnables easy overriding of the default `RegionManager` for customized region interactions \nand business-specific view logic for better control over single regions.\n\n@api public\n", 388 | "_initializeRegions": "Internal method to initialize the regions that have been defined in a\n`regions` attribute on the application instance\n\n@param {} options\n@api private\n", 389 | "_initRegionManager": "Instantiates the RegionManager for the Application object, and forwards\nthe events from the RegionManager to the Application itself.\n\n@api private\n", 390 | "_initChannel": "Internal method to setup the Wreqr.radio channel\n\n@api private\n" 391 | } 392 | } -------------------------------------------------------------------------------- /test/mock-files/json-pre/application.json: -------------------------------------------------------------------------------- 1 | { 2 | "constructor": [ 3 | { 4 | "tags": [ 5 | "@api public", 6 | "@param {} options - " 7 | ] 8 | } 9 | ], 10 | "properties": [ 11 | { 12 | "name": "_initCallbacks" 13 | }, 14 | { 15 | "name": "submodules" 16 | }, 17 | { 18 | "name": "_regionManager" 19 | }, 20 | { 21 | "name": "name" 22 | }, 23 | { 24 | "name": "channelName" 25 | }, 26 | { 27 | "name": "channel" 28 | }, 29 | { 30 | "name": "vent" 31 | }, 32 | { 33 | "name": "commands" 34 | }, 35 | { 36 | "name": "reqres" 37 | } 38 | ], 39 | "functions": [ 40 | { 41 | "name": "execute", 42 | "tags": [ 43 | "@api public" 44 | ] 45 | }, 46 | { 47 | "name": "request", 48 | "tags": [ 49 | "@api public", 50 | "@returns {} - " 51 | ] 52 | }, 53 | { 54 | "name": "addInitializer", 55 | "tags": [ 56 | "@api public", 57 | "@param {} initializer - " 58 | ] 59 | }, 60 | { 61 | "name": "start", 62 | "tags": [ 63 | "@api public", 64 | "@param {} options - " 65 | ] 66 | }, 67 | { 68 | "name": "addRegions", 69 | "tags": [ 70 | "@api public", 71 | "@param {} regions - ", 72 | "@returns {} - " 73 | ] 74 | }, 75 | { 76 | "name": "emptyRegions", 77 | "tags": [ 78 | "@api public", 79 | "@returns {} - " 80 | ] 81 | }, 82 | { 83 | "name": "removeRegion", 84 | "tags": [ 85 | "@api public", 86 | "@param {} region - ", 87 | "@returns {} - " 88 | ] 89 | }, 90 | { 91 | "name": "getRegion", 92 | "tags": [ 93 | "@api public", 94 | "@param {} region - ", 95 | "@returns {} - " 96 | ] 97 | }, 98 | { 99 | "name": "getRegions", 100 | "tags": [ 101 | "@api public", 102 | "@returns {} - " 103 | ] 104 | }, 105 | { 106 | "name": "module", 107 | "tags": [ 108 | "@api public", 109 | "@param {} moduleNames - ", 110 | "@param {} moduleDefinition - ", 111 | "@returns {} - " 112 | ] 113 | }, 114 | { 115 | "name": "getRegionManager", 116 | "tags": [ 117 | "@api public", 118 | "@returns {} - " 119 | ] 120 | }, 121 | { 122 | "name": "_initializeRegions", 123 | "tags": [ 124 | "@api private", 125 | "@param {} options - ", 126 | "@returns {} - " 127 | ] 128 | }, 129 | { 130 | "name": "_initRegionManager", 131 | "tags": [ 132 | "@api private" 133 | ] 134 | }, 135 | { 136 | "name": "_initChannel", 137 | "tags": [ 138 | "@api private" 139 | ] 140 | } 141 | ], 142 | "events": [ 143 | { 144 | "name": "before:start" 145 | }, 146 | { 147 | "name": "start" 148 | } 149 | ] 150 | } -------------------------------------------------------------------------------- /test/mock-files/yaml-documented/application.yaml: -------------------------------------------------------------------------------- 1 | name: Application 2 | 3 | class: Marionette.Application 4 | 5 | description: | 6 | Applications are the entry point into most Marionette Applications. 7 | For all but the simplest of webapps you'll want to instantiate a new Application to act as the hub for the rest of your code. 8 | 9 | Applications let you accomplish three things. 10 | Firstly, they provide a place to put start up code for your app through its Initializers. 11 | Secondly, they allow you to group your code into logical sections with the Module system. 12 | Lastly, they give you a way to connect Views to the document through its Regions. 13 | 14 | ```js 15 | var MyApp = new Backbone.Marionette.Application(); 16 | ``` 17 | 18 | constructor: 19 | description: | 20 | Creates a new Application. 21 | 22 | The constructor function calls initialize if it exists, and sets the properties of the Application. 23 | Note that Applications are unique in that their options are automatically attached to the Application instead of a separate options object. 24 | 25 | The `options` parameter can take any key/value pair and set it on the application instance. 26 | Two special properties that are used in the application are: 27 | + regions - regions are set on the app 28 | + channelName - channel name for the app 29 | 30 | @param {...*} options - Options to be available on the Application instance directly. 31 | 32 | examples: 33 | - 34 | name: Add regions 35 | example: | 36 | You can also specify regions per `Application` instance. 37 | 38 | ```js 39 | new Marionette.Application({ 40 | regions: { 41 | fooRegion: '#foo-region' 42 | } 43 | }); 44 | ``` 45 | 46 | properties: 47 | vent: | 48 | The eventAggregator from the global Channel to be used for Application-level events. 49 | 50 | @type {Backbone.Wreqr.EventAggregator} 51 | 52 | commands: | 53 | The commands instance from the global Channel to be used for Application-level commands. 54 | 55 | @type {Backbone.Wreqr.Commands} 56 | 57 | reqres: | 58 | The RequestResponse instance from the global Channel to be used for Application-level requests. 59 | 60 | @type {Backbone.Wreqr.RequestResponse} 61 | 62 | submodules: | 63 | The container for the Application's modules. 64 | Modules are stored with their name as the key, and the module itself as the value. 65 | 66 | @type {Object} 67 | 68 | regions: 69 | description: | 70 | Region Options 71 | 72 | examples: 73 | - 74 | name: Add regions as prototype property 75 | example: | 76 | You can also specify regions as a prototype property. 77 | 78 | ```js 79 | Marionette.Application.extend({ 80 | regions: { 81 | fooRegion: '#foo-region' 82 | } 83 | }); 84 | ``` 85 | 86 | - 87 | name: Add regions as prototype function 88 | example: | 89 | You can also specify regions as a prototype function. 90 | 91 | The `options` parameter is same as the constructor `options` parameter. 92 | 93 | ```js 94 | Marionette.Application.extend({ 95 | regions: function(options) { 96 | return { 97 | fooRegion: '#foo-region' 98 | } 99 | } 100 | }); 101 | ``` 102 | 103 | functions: 104 | initialize: 105 | description: | 106 | If `initialize` is set in the Application class, it will be called when new regions are instantiated. 107 | 108 | @param {Object} options - The constructor's options 109 | 110 | examples: 111 | - 112 | name: Basic Use 113 | example: | 114 | The `initialize` function is a good place to put custom, post instantiation class logic. 115 | 116 | ```js 117 | var MyApp = Marionette.Application.extend({ 118 | initialize: function(options) { 119 | console.log(options.container); 120 | } 121 | }); 122 | 123 | var myApp = new MyApp({container: '#app'}); 124 | ``` 125 | 126 | execute: | 127 | A convenience method to access the execute method 128 | on the instance of Backbone.Wreqr.Commands attached to 129 | every instance of Marionette.Application. 130 | 131 | This method is alternatively available as app.commands.execute, 132 | where app is the instance name of the Application. 133 | 134 | @param {String} commandName - The command to be executed. 135 | @param {...*} args - Additional arguments to pass to the command callback. 136 | @api public 137 | 138 | request: | 139 | A convenience method to access the request method on the instance of 140 | Backbone.Wreqr.RequestResponse attached to every instance of Marionette.Application. 141 | 142 | This method is alternatively available as app.reqres.request, 143 | where app is the instance name of the Application. 144 | 145 | @param {String} requestName - The name of the request. 146 | @param {...*} args - Additional arguments to pass to the response callback. 147 | @api public 148 | 149 | addInitializer: 150 | description: | 151 | Adds an initializer that runs once the Application has started, 152 | or immediately if the app has already been started. 153 | 154 | Initializer callbacks will be executed when you start your application, 155 | and are bound to the application object as the context for 156 | the callback. In other words, `this` is the `MyApp` object inside 157 | of the initializer function. 158 | 159 | The callback `options` argument is passed from the `start` method (see below). 160 | 161 | Initializer callbacks are guaranteed to run, no matter when you 162 | add them to the app object. If you add them before the app is 163 | started, they will run when the `start` method is called. If you 164 | add them after the app is started, they will run immediately. 165 | 166 | @api public 167 | @param {} initializer 168 | 169 | examples: 170 | - 171 | name: Adding initializers 172 | example: | 173 | Your application needs to do useful things, like displaying content in your 174 | regions, starting up your routers, and more. To accomplish these tasks and 175 | ensure that your `Application` is fully configured, you can add initializer 176 | callbacks to the application. 177 | 178 | ```js 179 | MyApp.addInitializer(function(options){ 180 | // do useful stuff here 181 | var myView = new MyView({ 182 | model: options.someModel 183 | }); 184 | MyApp.getRegion("main").show(myView); 185 | }); 186 | 187 | MyApp.addInitializer(function(options){ 188 | new MyAppRouter(); 189 | Backbone.history.start(); 190 | }); 191 | ``` 192 | 193 | start: 194 | description: | 195 | Start the Application, triggering the Initializers array of callbacks. 196 | 197 | @param {...*} options - Options to pass to the `start` triggerMethods and the Initializers functions. 198 | @api public 199 | 200 | examples: 201 | - 202 | name: Starting an Application 203 | example: | 204 | Once you have your application configured, you can kick everything off by 205 | calling: `MyApp.start(options)`. 206 | 207 | This function takes a single optional parameter. This parameter will be passed 208 | to each of your initializer functions, as well as the initialize events. This 209 | allows you to provide extra configuration for various parts of your app throughout the 210 | initialization sequence. 211 | 212 | ```js 213 | var options = { 214 | something: "some value", 215 | another: "#some-selector" 216 | }; 217 | 218 | MyApp.start(options); 219 | ``` 220 | 221 | addRegions: 222 | description: | 223 | You can create Regions through the `addRegions` method by passing in an object 224 | literal or a function that returns an object literal. 225 | 226 | For more information on regions, see [the region documentation](./marionette.region.md) 227 | Also, the API that Applications use to manage regions comes from the RegionManager Class, 228 | which is documented [over here](https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.regionmanager.md). 229 | 230 | @api public 231 | @param {Object|Function} regions 232 | 233 | examples: 234 | - 235 | name: jQuery Selector 236 | example: | 237 | The first is to specify a jQuery selector as the value of the region 238 | definition. This will create an instance of a Marionette.Region directly, 239 | and assign it to the selector: 240 | 241 | ```js 242 | MyApp.addRegions({ 243 | someRegion: "#some-div", 244 | anotherRegion: "#another-div" 245 | }); 246 | ``` 247 | - 248 | name: Custom Region Class 249 | example: | 250 | The second is to specify a custom region class, where the region class has 251 | already specified a selector: 252 | 253 | ```js 254 | var MyCustomRegion = Marionette.Region.extend({ 255 | el: "#foo" 256 | }); 257 | 258 | MyApp.addRegions(function() { 259 | return { 260 | someRegion: MyCustomRegion 261 | }; 262 | }); 263 | ``` 264 | 265 | - 266 | name: Custom Region Class And Selector 267 | example: | 268 | The third method is to specify a custom region class, and a jQuery selector 269 | for this region instance, using an object literal: 270 | 271 | ```js 272 | var MyCustomRegion = Marionette.Region.extend({}); 273 | 274 | MyApp.addRegions({ 275 | 276 | someRegion: { 277 | selector: "#foo", 278 | regionClass: MyCustomRegion 279 | }, 280 | 281 | anotherRegion: { 282 | selector: "#bar", 283 | regionClass: MyCustomRegion 284 | } 285 | 286 | }); 287 | ``` 288 | 289 | emptyRegions: | 290 | Empties all of the Application's Regions by destroying the View within each Region. 291 | 292 | @api public 293 | 294 | removeRegion: 295 | description: | 296 | Removes the specified Region from the Application. 297 | Removing a region will properly empty it before removing it from the application object. 298 | 299 | @param {String} regionName - The name of the Region to be removed. 300 | @api public 301 | 302 | examples: 303 | - 304 | name: Remove a region 305 | example: | 306 | Regions can also be removed with the `removeRegion` method, passing in 307 | the name of the region to remove as a string value: 308 | 309 | ```js 310 | MyApp.removeRegion("someRegion"); 311 | ``` 312 | 313 | getRegion: 314 | description: | 315 | Returns a Region by name. 316 | 317 | @param {String} regionName - The name of the Region to receive. 318 | @api public 319 | 320 | examples: 321 | - 322 | name: Get Region by name 323 | example: | 324 | A region can be retrieved by name, using the `getRegion` method: 325 | 326 | ```js 327 | var app = new Marionette.Application(); 328 | app.addRegions({ r1: "#region1" }); 329 | 330 | // r1 === r1Again; true 331 | var r1 = app.getRegion("r1"); 332 | var r1Again = app.r1; 333 | ``` 334 | 335 | This is the preferred method of accessing Regions on the Application instance. 336 | 337 | 338 | getRegions: | 339 | Returns an array of every Region from the RegionManager 340 | 341 | @api public 342 | 343 | module: | 344 | Create a module, attached to the application 345 | 346 | @api public 347 | @param {} moduleNames 348 | @param {} moduleDefinition 349 | 350 | getRegionManager: | 351 | Returns a new instance of a region manager. 352 | 353 | Enables easy overriding of the default `RegionManager` for customized region interactions 354 | and business-specific view logic for better control over single regions. 355 | 356 | @api public 357 | 358 | _initializeRegions: | 359 | Internal method to initialize the regions that have been defined in a 360 | `regions` attribute on the application instance 361 | 362 | @param {} options 363 | @api private 364 | 365 | _initRegionManager: | 366 | Instantiates the RegionManager for the Application object, and forwards 367 | the events from the RegionManager to the Application itself. 368 | 369 | @api private 370 | 371 | _initChannel: | 372 | Internal method to setup the Wreqr.radio channel 373 | 374 | @api private 375 | 376 | -------------------------------------------------------------------------------- /test/mock-files/yaml-stubbed/application.yaml: -------------------------------------------------------------------------------- 1 | constructor: 2 | 3 | description: | 4 | @api public 5 | @param {} options - 6 | 7 | examples: 8 | - 9 | name: 10 | example: | 11 | 12 | 13 | properties: 14 | 15 | _initCallbacks: | 16 | 17 | 18 | @type {} 19 | 20 | 21 | submodules: | 22 | 23 | 24 | @type {} 25 | 26 | 27 | _regionManager: | 28 | 29 | 30 | @type {} 31 | 32 | 33 | name: | 34 | 35 | 36 | @type {} 37 | 38 | 39 | channelName: | 40 | 41 | 42 | @type {} 43 | 44 | 45 | channel: | 46 | 47 | 48 | @type {} 49 | 50 | 51 | vent: | 52 | 53 | 54 | @type {} 55 | 56 | 57 | commands: | 58 | 59 | 60 | @type {} 61 | 62 | 63 | reqres: | 64 | 65 | 66 | @type {} 67 | 68 | functions: 69 | 70 | execute: 71 | description: | 72 | @api public 73 | 74 | examples: 75 | - 76 | name: 77 | example: | 78 | 79 | 80 | 81 | request: 82 | description: | 83 | @api public 84 | @returns {} - 85 | 86 | examples: 87 | - 88 | name: 89 | example: | 90 | 91 | 92 | 93 | addInitializer: 94 | description: | 95 | @api public 96 | @param {} initializer - 97 | 98 | examples: 99 | - 100 | name: 101 | example: | 102 | 103 | 104 | 105 | start: 106 | description: | 107 | @api public 108 | @param {} options - 109 | 110 | examples: 111 | - 112 | name: 113 | example: | 114 | 115 | 116 | 117 | addRegions: 118 | description: | 119 | @api public 120 | @param {} regions - 121 | @returns {} - 122 | 123 | examples: 124 | - 125 | name: 126 | example: | 127 | 128 | 129 | 130 | emptyRegions: 131 | description: | 132 | @api public 133 | @returns {} - 134 | 135 | examples: 136 | - 137 | name: 138 | example: | 139 | 140 | 141 | 142 | removeRegion: 143 | description: | 144 | @api public 145 | @param {} region - 146 | @returns {} - 147 | 148 | examples: 149 | - 150 | name: 151 | example: | 152 | 153 | 154 | 155 | getRegion: 156 | description: | 157 | @api public 158 | @param {} region - 159 | @returns {} - 160 | 161 | examples: 162 | - 163 | name: 164 | example: | 165 | 166 | 167 | 168 | getRegions: 169 | description: | 170 | @api public 171 | @returns {} - 172 | 173 | examples: 174 | - 175 | name: 176 | example: | 177 | 178 | 179 | 180 | module: 181 | description: | 182 | @api public 183 | @param {} moduleNames - 184 | @param {} moduleDefinition - 185 | @returns {} - 186 | 187 | examples: 188 | - 189 | name: 190 | example: | 191 | 192 | 193 | 194 | getRegionManager: 195 | description: | 196 | @api public 197 | @returns {} - 198 | 199 | examples: 200 | - 201 | name: 202 | example: | 203 | 204 | 205 | 206 | _initializeRegions: 207 | description: | 208 | @api private 209 | @param {} options - 210 | @returns {} - 211 | 212 | examples: 213 | - 214 | name: 215 | example: | 216 | 217 | 218 | 219 | _initRegionManager: 220 | description: | 221 | @api private 222 | 223 | examples: 224 | - 225 | name: 226 | example: | 227 | 228 | 229 | 230 | _initChannel: 231 | description: | 232 | @api private 233 | 234 | examples: 235 | - 236 | name: 237 | example: | 238 | 239 | 240 | events: 241 | 242 | name: before:start 243 | 244 | description: | 245 | 246 | example: | 247 | 248 | 249 | name: start 250 | 251 | description: | 252 | 253 | example: | 254 | 255 | -------------------------------------------------------------------------------- /test/specs/src/jsdoccer-spec.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChetHarrison/jsdoccer/38889056c1eedbfd907b26fd896b71f62acdf2e8/test/specs/src/jsdoccer-spec.js -------------------------------------------------------------------------------- /test/specs/src/parsers/ast-to-json-pre-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | expect = require('chai').expect, 5 | fs = require('fs'), 6 | root = '../../../../', 7 | match = root + 'src/syntax-targets/', 8 | astToDocJson = require(root + 'src/parsers/ast-to-json-pre.js'), 9 | expectedJSON = fs.readFileSync(path.resolve(__dirname, '../../../mock-files/json-pre/application.json'), {encoding: 'utf8'}), 10 | matchers = {}, 11 | astFile = fs.readFileSync(path.resolve(__dirname, '../../../mock-files/ast/application.json'), {encoding: 'utf8'}); 12 | 13 | matchers['class'] = require(match + 'class/matcher.js'), 14 | matchers['constructor'] = require(match + 'constructor/matcher.js'), 15 | matchers['events'] = require(match + 'events/matcher.js'), 16 | matchers['functions'] = require(match + 'functions/matcher.js'), 17 | matchers['properties'] = require(match + 'properties/matcher.js'); 18 | 19 | 20 | describe('ast-to-json-pre', function () { 21 | 22 | it('should return expected JSON', function () { 23 | astToDocJson.init({ matchers: matchers }) 24 | var generatedAst = astToDocJson.parse(astFile); 25 | expect(generatedAst).to.eql(expectedJSON); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/specs/src/parsers/js-to-ast-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | expect = require('chai').expect, 5 | fs = require('fs'), 6 | jsToAst = require('../../../../src/parsers/js-to-ast.js'); 7 | 8 | describe('parser js-to-ast', function () { 9 | var generatedAst; 10 | 11 | it('should return expected AST', function () { 12 | var desiredAST = JSON.stringify({ 13 | 'type': 'Program', 14 | 'body': [ 15 | { 16 | 'type': 'VariableDeclaration', 17 | 'declarations': [ 18 | { 19 | 'type': 'VariableDeclarator', 20 | 'id': { 21 | 'type': 'Identifier', 22 | 'name': 'answer' 23 | }, 24 | 'init': { 25 | 'type': 'Literal', 26 | 'value': 42, 27 | 'raw': '42' 28 | } 29 | } 30 | ], 31 | 'kind': 'var' 32 | } 33 | ] 34 | }, null, 2); 35 | 36 | generatedAst = jsToAst.parse('var answer = 42;'); 37 | 38 | expect(generatedAst).to.eql(desiredAST); 39 | }); 40 | }); 41 | 42 | -------------------------------------------------------------------------------- /test/specs/src/parsers/json-api-to-docs-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | expect = require('chai').expect, 5 | fs = require('fs'), 6 | root = '../../../../', 7 | htmlTemplaters = {}, 8 | match = root + 'src/syntax-targets/', 9 | jsonApiToDocs = require(root + 'src/parsers/json-api-to-docs.js'), 10 | expectedHtml = fs.readFileSync(path.resolve(__dirname, '../../../mock-files/docs/application.html'), {encoding: 'utf8'}), 11 | jsonFile = fs.readFileSync(path.resolve(__dirname, '../../../mock-files/json-api/application.json'), {encoding: 'utf8'}); 12 | 13 | htmlTemplaters['class'] = require(match + 'class/templateHtml.js'), 14 | htmlTemplaters['constructor'] = require(match + 'constructor/templateHtml.js'), 15 | htmlTemplaters['events'] = require(match + 'events/templateHtml.js'), 16 | htmlTemplaters['functions'] = require(match + 'functions/templateHtml.js'), 17 | htmlTemplaters['properties'] = require(match + 'properties/templateHtml.js'); 18 | 19 | describe('json-api-to-docs', function () { 20 | 21 | it('should return expected doc HTML', function () { 22 | var generatedHtml; 23 | 24 | jsonApiToDocs.init({ 25 | htmlTemplaters: htmlTemplaters, 26 | docPageTplPath: path.resolve(__dirname, root, 'src/syntax-targets/docs-index.hbs'), 27 | projectName: 'custom name' 28 | }); 29 | 30 | generatedHtml = jsonApiToDocs.parse(jsonFile); 31 | expect(generatedHtml).to.eql(expectedHtml); 32 | }); 33 | }); 34 | 35 | -------------------------------------------------------------------------------- /test/specs/src/parsers/json-pre-to-yaml-stubbed-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | expect = require('chai').expect, 5 | fs = require('fs'), 6 | root = '../../../../', 7 | match = root + 'src/syntax-targets/', 8 | jsonPreToYamlStubbed = require(root + 'src/parsers/json-pre-to-yaml-stubbed.js'), 9 | expectedYaml = fs.readFileSync(path.resolve(__dirname, '../../../mock-files/yaml-stubbed/application.yaml'), {encoding: 'utf8'}), 10 | yamlTemplaters = {}, 11 | jsonFile = fs.readFileSync(path.resolve(__dirname, '../../../mock-files/json-pre/application.json'), {encoding: 'utf8'}); 12 | 13 | yamlTemplaters['class'] = require(match + 'class/templateYaml.js'), 14 | yamlTemplaters['constructor'] = require(match + 'constructor/templateYaml.js'), 15 | yamlTemplaters['events'] = require(match + 'events/templateYaml.js'), 16 | yamlTemplaters['functions'] = require(match + 'functions/templateYaml.js'), 17 | yamlTemplaters['properties'] = require(match + 'properties/templateYaml.js'); 18 | 19 | describe('json-pre-to-yaml-stubbed', function () { 20 | 21 | it('should return expected stubbed YAML', function () { 22 | var generatedYaml; 23 | jsonPreToYamlStubbed.init({yamlTemplaters: yamlTemplaters}) 24 | generatedYaml = jsonPreToYamlStubbed.parse(jsonFile); 25 | expect(generatedYaml).to.eql(expectedYaml); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/specs/src/parsers/yaml-documented-to-json-api-spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'), 4 | expect = require('chai').expect, 5 | fs = require('fs'), 6 | root = '../../../../', 7 | yamlDocumentedToJsonApi = require(root + 'src/parsers/yaml-documented-to-json-api.js'), 8 | expectedJson = fs.readFileSync(path.resolve(__dirname, '../../../mock-files/json-api/application.json'), {encoding: 'utf8'}), 9 | yamlFile = fs.readFileSync(path.resolve(__dirname, '../../../mock-files/yaml-documented/application.yaml'), {encoding: 'utf8'}); 10 | 11 | describe('yaml-documented-to-json-api', function () { 12 | 13 | it('should return expected API JSON', function () { 14 | var generatedJson; 15 | 16 | generatedJson = yamlDocumentedToJsonApi.parse(yamlFile); 17 | expect(generatedJson).to.eql(expectedJson); 18 | }); 19 | }); 20 | --------------------------------------------------------------------------------