Skip to content

Commit

Permalink
Merge pull request #67 from strongloop-internal/feature/promise
Browse files Browse the repository at this point in the history
Feature/promise
  • Loading branch information
Rand McKinney committed Jan 27, 2016
2 parents 54ebac8 + adb76df commit 2893448
Show file tree
Hide file tree
Showing 12 changed files with 311 additions and 53 deletions.
107 changes: 96 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,13 @@ Strong-docs uses [Github Flavored Markdown](http://github.github.com/github-flav
To create a section you only need to provide a markdown header eg. `#` or `###`. The following example creates several sections.

# My Section

This is a paragraph.

## Sub Section

This is a paragraph within a sub section.

The first section `# My Section` will have a depth of 1 and the second's depth will be 2. See (section depth)[#section-depth] for more info.

#### Links / Anchors
Expand Down Expand Up @@ -133,7 +133,7 @@ Strong-docs supports linking to images absolutely (using regular markdown):

![Alt text](http://foo.com/path/to/img.jpg)
![Alt text](http://foo.com/path/to/img.jpg "Optional title")

Or you can bundled your images with your site using the [assets setting](#assets).

{
Expand Down Expand Up @@ -173,8 +173,8 @@ exports.escape = function(html){
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
};
```
```

See the [JSDoc](http://usejsdoc.org/) site for more examples.

##### Ignoring Annotations
Expand All @@ -191,7 +191,7 @@ To ignore an annotation change the comment block from `/**` to `/*!`.
// ...
```

You can also use the `@private` attribute to prevent your annotation from being rendered in your doc site.
You can also use the `@private` attribute to prevent your annotation from being rendered in your doc site.

```js
/**
Expand Down Expand Up @@ -227,10 +227,10 @@ The following is a list of configuration properties for strong-docs. You may spe
- **content** - default: 'content' - specify your [documentation source files](#documentation-source-files)
- **codeSectionDepth** - default `4` - specify the depth of [JavaScript sections](#section-depth)
- **assets** - path to your assets directory

### Content

Documentation will be rendered in the order it is listed in the content array. Below is an example content array with markdown, JavaScript, and an injected section.
Documentation will be rendered in the order it is listed in the content array. Below is an example content array with markdown, JavaScript, and an injected section.

[
"docs/overview.md",
Expand Down Expand Up @@ -261,7 +261,7 @@ Link to these files from your docs like this:

![Alt text](assets/img.jpg)
[My File](assets/pkg.zip)

## JSDoc Annotations

### Supported annnotations
Expand Down Expand Up @@ -332,3 +332,88 @@ Link to these files from your docs like this:
* typedef
* variation
* version

### StrongLoop annnotations

#### promise

Syntax: `@promise [{Types}] [resolve object]`

`Types` and `resolve object` must be specified for a promise-only function.

```
/**
* Function to test a standalone promise.
*
* @param {Array} An array parameter.
* @promise {Array} Resolves an Array.
*
*/
function promiseStandalone(arg) {
}
```

`Types` and `resolve object` are optional if the function also accepts a callback.
The promise details are derived from the callback.

```
/**
* Function to test promise from a callback.
*
* @param {Array} An array parameter.
*
* @callback {Function} callback This is the callback.
* @param {Error} err Error object.
* @param {Object} instance Model instance.
*
* @promise
*
*/
function promiseCallback(arg, callback) {
}
```

Specifying `Types` and `resolve object` will overwrite the defaults derived from
the callback.

```
/**
* Function to test custom promise details.
*
* @param {Array} An array parameter.
*
* @callback {Function} callback This is the callback.
* @param {Error} err Error object.
* @param {Object} instance Model instance.
*
* @promise {String} Custom resolve object of type String.
*
*/
function promiseCustom(arg, callback) {
}
```

A warning message will be printed on the console and the documentation page,
if the promise cannot be meaningfully resolve with respect to the callback
implementation.

```
/**
* Function to test unresolvable promise from a callback.
*
* @param {Array} An array parameter.
*
* @callback {Function} callback This is the callback.
* @param {Error} err Error object.
* @param {Object} instanceA first Model instance.
* @param {Object} instanceB second Model instance.
* @promise
*
*/
function promiseUnresolvable(arg, callback) {
}
```
45 changes: 43 additions & 2 deletions lib/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function Annotation(comment, doc) {
if(shouldParse) {
var fn = tagParsers[tag.type] || notSupported;

fn.call(this, tag);
fn.call(this, tag, comment.ctx);
}

if(tag.description) {
Expand Down Expand Up @@ -68,7 +68,6 @@ function Annotation(comment, doc) {
var header;
var anchorId;
var memberOf = attrs.memberof;

if (args) {
args.forEach(function(arg) {
if (!arg.types) return;
Expand Down Expand Up @@ -380,6 +379,48 @@ var tagParsers = {
}
},
private: setProperty,
promise: function (tag, ctx) {
var resolveObject = { name: 'resolve' };
if (!tag.types) {
parseTagForType(tag);
if(tag.name) tag.description = tag.name + ' ' + tag.description;
tag.name = undefined;
}
tag.name = tag.name || 'promise';
mapStarToAny(tag);
this.promise = {};
this.promise.attrs = [];
// assign the input object types
if (this.args.length) {
this.promise.types = this.args[0].types;
}
// try to fill in the promise details from Callback properties
if ('callbackTag' in this) {
if (this.callbackTag.args.length === 1) {
console.log('Resolve object not found in %s', ctx.string)
resolveObject.types = ['undefined']
resolveObject.description = 'The resolve handler does not receive any arguments.'
}
else if (this.callbackTag.args.length === 2) {
resolveObject.types = this.callbackTag.args[1].types;
resolveObject.description = this.callbackTag.args[1].description;
}
else {
var warningMessage = 'Promise cannot be resolved in ' + ctx.string;
this.promise.warning = warningMessage;
console.log(warningMessage);
}
}
// custom description takes precedence over properties from Callback
if (tag.description.length > 0) {
resolveObject.types = tag.types;
resolveObject.description = tag.description;
}
this.promise.attrs.push(resolveObject);
if (!('description' in resolveObject)) {
console.log('Description for resolve object not found in %s', ctx.string)
}
},
property: function(tag) {
if(!tag.types) {
parseTagForType(tag);
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "strong-docs",
"description": "Sleek, intuitive, and powerful documentation site generator",
"version": "1.0.0",
"version": "1.1.0",
"repository": {
"type": "git",
"url": "git://github.com/strongloop/strong-docs.git"
Expand All @@ -16,7 +16,7 @@
"opener": "~1.3.0",
"express": "~3.4.0",
"js-yaml": "~2.1.0",
"dox": "iolo/dox",
"dox": "0.8.0",
"ejs": "~0.8.4",
"strong-task-emitter": "~0.0.5",
"markdown": "~0.5.0",
Expand Down
3 changes: 1 addition & 2 deletions public/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ a[name] {

/* Annotations */
.code-arguments-hdr {
text-transform: capitalize;
font-size: 120%;
margin-top: 20px;
margin-bottom: 10px;
Expand Down Expand Up @@ -137,4 +136,4 @@ section + section {

section {
margin-left: 30px;
}
}
48 changes: 42 additions & 6 deletions templates/annotation.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,17 @@
<%
} else if(arg.type === 'callback' && arg.args.length) {
%>
<div class="code-arguments-hdr"><%= arg.name || 'Callback' %></div>
<% if (!ann.promise) {%>
<div class="code-arguments-hdr">Callback</div>
<% } else { %>
<div class="code-arguments-hdr">Callback (optional)</div>
<p>
Optional callback. When the callback function is not provided,
a promise is returned instead (see below).
</p>
<% } %>
<table class="params code-callback-args">
<tr>
<th class="hdr-name">Name</th>
Expand All @@ -60,7 +70,7 @@
%>
<% } %>
<% if(Array.isArray(ann.properties) && ann.properties.length) { %>
<div class="code-arguments-hdr">Class Properties</div>
<table class="params code-arguments">
Expand Down Expand Up @@ -90,10 +100,10 @@
arg.properties.forEach(renderArg);
%>
</table>
<% }
<% }
})
}
%>
%>
<% if(ann.attrs.returns) { %>
<div class="code-arguments-hdr">Returns</div>
Expand All @@ -106,13 +116,39 @@
<% renderArg(ann.attrs.returns) %>
</table>
<% } %>
<% if(ann.attrs.example) {%>
<% if(ann.attrs.example) {%>
<div class="code-arguments-hdr">Example</div>
<div class="example">
<%- md(ann.attrs.example) %>
</div>
<% } %>
<% if(ann.promise) {%>
<div class="code-arguments-hdr">Promise</div>
<p>
This method supports both callback-based and promise-based invocation.
Call this method with no callback argument to get back a promise instead.
<% if(ann.promise.warning) {%>
<div>
<b>WARNING</b>: this promise implementation will not resolve according to
the callback function.
</div>
<% } %>
</p>
<table class="params code-callback-args">
<tr>
<th class="hdr-name">Handler</th>
<th class="hdr-type">Argument</th>
<th class="hdr-desc">Description</th>
</tr>
<%
ann.promise.attrs.forEach(renderArg);
%>
</table>
<% } %>
</section>
Expand Down
Loading

0 comments on commit 2893448

Please sign in to comment.