dtao / autodoc Goto Github PK
View Code? Open in Web Editor NEWDoc generation on steroids
Home Page: https://npmjs.org/package/autodoc
License: MIT License
Doc generation on steroids
Home Page: https://npmjs.org/package/autodoc
License: MIT License
Hey nice approach and library!
Have installed it globally via:
sudo npm install autodoc -g
then wanted to test the documentation functionality but got this :(
what could be the reason?
Event tried and installed jasmin-node also as global to see if it helps...
sudo npm install jasmin-node -g
but it did not.
I am running node v0.10.24 on Ubuntu 12.04LTS if it is relevant.
The file I'm trying to document is very basic one, something like:
/** Aplication object and ...blabla */
(function(){
/** Some API */
return {
}
}());
Help will be appreciated!
Thanks
If your javascript looks like this:
/*
Does a thing
*/
MyLibrary.prototype.thing = function() {
return console.log("Thing done!");
};
(Note the single asterisk after the slash, instead of two.) Then you end up with documentation that looks like this:
With the uncomfortable /*
in there.
This is perhaps only an issue because ###
block comments in CoffeeScript become /*
-style JavaScript block comments.
To see everything available:
https://github.com/ariya/esprima/blob/master/esprima.js#L114-L153
Deal with assumptions discussed in comment #1032. Sorry, you didn't get away with it. ;-) Haha. I'm just doing what you asked me to.
I love autodoc, I love the inline testing and doc generating, and I love how it encourages me to write simple tiny testable functions :-)
One question I have is: is there a way to allow external variables in a test?
Eg one of my functions uses _.filter
, and I can't figure out how to make autodoc's testing find/have _
.
Am I missing something or is this just not a feature yet?
Not an issue, just thought I'd say awesome project :) Heard you on JSJabber and thought I'd check it out, because I began work on exactly the same thing (I'm a DRY fanatic and the runnable examples above the code was really getting to me lol) 5 months ago inside my form validation library, though I've been struggling to find the time to finish it. I'm also using the docs to generate a manifest of files, then use that manifest to build a front-end library compiler, where users can build a custom version of the library to suit their needs (using compile.js - also a WIP). Demo here, click "Build Custom", kinda like the Modernizr download page. So, this might be way out of scope for you though I thought I'd give you the idea. Hopefully I'll find some time to finish my library and I'll be able to swap my stuff out for this :)
Or maybe it's the identifier that's screwed up? I'll get to the bottom of this!
For example I want to be able to do something like:
/*
* fn(input) // => (an array of 10 numbers)
*/
...and have Breakneck automatically pass '(an array of 10 numbers)' to some handler I've defined, which can customize the assertion logic I want to use.
In other words something like Cucumber (but obviously lightweight).
Something really needs to be done about the fact that GitHub thinks this project is 68% CSS.
And yeah, that file really doesn't belong here anyway.
What I mean is, let examples be written like:
foo();
bar();
baz(); // => 1
bar();
baz();
foo(); // => 2
In other words support multiple setup steps per example and run everything in order.
It would be really awesome if by clicking in the /*...*/
in the signature opened up into the contents of that function.
C:\Users\Jonas\Code\emitter.js>autodoc --test --verbose emitter.js
module.js:340
throw err;
^
Error: Cannot find module 'C:UsersJonasCodeemitter.jsemitter.js'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at eval (eval at runTests (C:\Users\Jonas\AppData\Roaming\npm\node_modules\autodoc\bin\autodoc:136:8), <anonymous>:1:18)
at runTests (C:\Users\Jonas\AppData\Roaming\npm\node_modules\autodoc\bin\autodoc:136:3)
at Object.<anonymous> (C:\Users\Jonas\AppData\Roaming\npm\node_modules\autodoc\bin\autodoc:192:20)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
NOT on the browser. (Currently I'm using CodeMirror because it provides line-level styling. It's about the most heavyweight solution you could possibly come up with. So I need to find a syntax highlighting solution that allows me to style code snippets by line, so I can show the little checkmark or red X to indicate if an example passes.)
I think there's like google-code-prettify library or something like that that might do the trick.
This might be a pipe dream, but it would be pretty cool. Wonder if it'd be possible to generalize somehow so any language that compiles to javascript could be supported...
This may entail the use of some custom handlers, but otherwise I think it just makes sense.
First of all, thanks a lot for this project! I love the idea of having testable examples right on top of your functions.
I tried to get it to work with promises and I was surprised how easy it is to integrate new features like that (although it took me a while to get started, I guess the documentation could be a little clearer about how to write and use custom handlers). Anyway, thats what I came up with in order to test functions that return promises:
(Btw, just in case somebody struggles getting started with custom handlers as well, here is my package.json scripts configuration):
"scripts": {
"test": "autodoc --test --handlers autodoc-helpers/autodoc-helpers.js --partials ./autodoc-helpers --verbose ./my-file-name.js",
"docs": "autodoc --handlers ./autodoc-helpers/autodoc-helpers.js --partials ./autodoc-helpers ./my-file-name.js"
}
autodoc-helpers/autodoc-helpers.js:
this.exampleHandlers = [
{
pattern: /^resolves in (.*)$/,
template: 'autodoc-promise-resolve',
data: function(match) {
return { expectedResult : match[1] };
}
},
{
pattern: /^rejects with (.*)$/,
template: 'autodoc-promise-reject',
data: function(match) {
return { expectedError : match[1] };
}
}
];
autodoc-helpers/autodoc-promise-resolve.js:
var test = {
error : undefined,
result : undefined,
onSuccessCallCount : 0,
onErrorCallCount : 0
};
var onSuccess = function (result) {
test.result = result;
test.onSuccessCallCount++;
};
var onError = function (error) {
test.error = error;
test.onErrorCallCount++;
};
runs(function() {
{{{actual}}}.then(onSuccess).catch(onError);
});
waitsFor(function() {
return test.onSuccessCallCount > 0 || test.onErrorCallCount > 0;
});
runs(function() {
expect(test.onErrorCallCount).toEqual(0);
expect(test.onSuccessCallCount).toEqual(1);
expect(test.result).toEqual({{{expectedResult}}});
});
autodoc-helpers/autodoc-promise-reject.js:
var test = {
error : undefined,
result : undefined,
onSuccessCallCount : 0,
onErrorCallCount : 0
};
var onSuccess = function (result) {
test.result = result;
test.onSuccessCallCount++;
};
var onError = function (error) {
test.error = error;
test.onErrorCallCount++;
};
runs(function() {
{{{actual}}}.then(onSuccess).catch(onError);
});
waitsFor(function() {
return test.onSuccessCallCount > 0 || test.onErrorCallCount > 0;
});
runs(function() {
expect(test.onSuccessCallCount).toEqual(0);
expect(test.onErrorCallCount).toEqual(1);
expect(test.error).toEqual({{{expectedError}}});
});
Now, I can write tests like this:
/**
@example
promiseFn() // resolves in {foo : 'bar'}
*/
function promiseFn () {
return Promise.resolve({foo : 'bar'});
}
module.exports = promiseFn;
I had to export the function that I wanted to test, otherwise I would get "promiseFn is not defined". So my first question is: Does that mean that you can only test functions that you make public by either exporting them directly or wrapped inside an exported object?
For the case that everything works fine, this works great! But if the expected result varies from the actual output, I get a weird error message (saying "Passed" in red letters). But at least it tells me that the test failed.
/**
@example
promiseFn() // resolves in {foo : 'baz'}
*/
function promiseFn () {
return Promise.resolve({foo : 'bar'});
}
module.exports = promiseFn;
console output:
F
1) Passed.
14: /**
15: @example
16: promiseFn() // rejects with {foo : 'baz'}
17: */
18: function promiseFn () {
19: return Promise.reject({foo : 'bar'});
20: }
Ran 1 specs in 24ms.
0 passed, 1 failed
So my second and main question is: How do I get autodoc to display an error message that makes sense?
And one last thing:
While testing the error cases of my functions, I noticed that it is quite easy to do as long I know exactly what the error looks like:
/**
@example
promiseFn() // rejects with {errorMessage : 'Static text', code : 42}
*/
function promiseFn () {
return Promise.reject({errorMessage : 'Static text', code : 42});
}
module.exports = promiseFn;
But as soon as the error is dynamic, I had to do some weird unpacking which seems a little unintuitive to me.
/**
@example
var extractErrorCode = function (error) {
return Promise.reject(error.code);
};
promiseFn().catch(extractErrorCode) // rejects with 42
*/
function promiseFn () {
return Promise.reject({errorMessage : 'Dynamic text', code : 42});
}
module.exports = promiseFn;
Does anyone have an idea how to solve this more elegantly?
One last question: Is this project still active and do you still think it is a good idea to write tests and documentation in this way?
Looking forward to your response,
Jesse
I have a few custom types and I would like those included on the documentation. For example:
/**
* The wish object
* @typedef {Object} wish
* @property {string} id - Unique identifier for the wish.
* @property {context} context - The context of the wish. Can be given as a
* string or array. In which case it is assigned to the wish's context.any property.
* @property {{timesMade: {total: number, magicWords: {string}}}} data - Any
* data you wish to associate with the wish.
* Genie adds a 'timesMade' property with total and magicWords
* properties to keep track of how often a wish is made with a
* given magicWord.
* @property {[]} magicWords - Used to match this wish on genie.getMatchingWishes
* @property {Function} action - The action to be performed when genie.makeWish is
* called with this wish.
*/
I'd like there to be a section for types or something and links too! That'd be great.
See https://gist.github.com/kentcdodds/8260581 to understand the problem. /cc @kentcdodds
BTW, breakneck is an awesome idea. Love what I'm seeing so far. 😸
Seems like it would be useful to run the specs server-side with a breakneck command... something like breakneck --spec <filename>
. (Presuming, of course, that the library doesn't require the DOM or any other set of predefined globals.) That way, it could become part of the test suite.
Just to warn you, I'm very new to GitHub, pretty new to Node. Anyway, I installed autodoc a couple days ago (using npm on Windows 7, if it matters), and when I tried running this:
autodoc\example>autodoc -t redundant.js
I got this:
autodoc\node_modules\codemirror-highlight\node_modules\codemirror\addon\runmode\runmode.node.js:104
var lines = splitLines(string), state = (options && options.state) || export
^
ReferenceError: options is not defined
Full trace here: https://gist.github.com/r-o-b/4b3ddbcb1b8e25d668bb#file-gistfile1-txt
Any ideas? I got the same error with my .js file, but I figured the example file was a better place to start...
Thanks.
I'm think something like this:
var x = [];
foo(); // => 1
bar(x); // x => [1]
baz(); // instanceof CustomObject
blah(); // throws
Hopefully that makes sense. Shouldn't be too hard given the custom handler support that's already there.
Maybe make this an option.
The tests are written in CoffeeScript, but the library itself is written in JavaScript. Why the inconsistency?
This one's admittedly a bit more "out there"; but I think it'd be sweet. Say you have some internal function that isn't exposed. Typically you have no choice in this case if you want to test the function. You have to expose it somehow.
What if autodoc just pulled the raw code out and dumped it in a spec runner template to run the examples?
Obviously there would be some complications here. But I think a decent approach might be: in the template, lift all private functions to the global scope. I think this would make the majority of cases work.
Anyway, it's worth a try!
As it is, I have to type it exactly as it is from the first character to the last. Here's a piece from genie's matching algorithm that you may be able to use:
var _matchRankMap = {
equals: 5,
startsWith: 4,
wordStartsWith: 3,
contains: 2,
acronym: 1,
matches: 0,
noMatch: -1
};
/**
* Gives a _matchRankMap score based on
* how well the two strings match.
* @param {string} magicWord
* @param {string} givenMagicWord
* @returns {number}
* @private
*/
function _stringsMatch(magicWord, givenMagicWord) {
/* jshint maxcomplexity:8 */
magicWord = ('' + magicWord).toLowerCase();
// too long
if (givenMagicWord.length > magicWord.length) {
return _matchRankMap.noMatch;
}
// equals
if (magicWord === givenMagicWord) {
return _matchRankMap.equals;
}
// starts with
if (magicWord.indexOf(givenMagicWord) === 0) {
return _matchRankMap.startsWith;
}
// word starts with
if (magicWord.indexOf(' ' + givenMagicWord) !== -1) {
return _matchRankMap.wordStartsWith;
}
// contains
if (magicWord.indexOf(givenMagicWord) !== -1) {
return _matchRankMap.contains;
} else if (givenMagicWord.length === 1) {
// If the only character in the given magic word
// isn't even contained in the magic word, then
// it's definitely not a match.
return _matchRankMap.noMatch;
}
// acronym
if (_getAcronym(magicWord).indexOf(givenMagicWord) !== -1) {
return _matchRankMap.acronym;
}
return _stringsByCharOrder(magicWord, givenMagicWord);
}
/**
* Generates an acronym for a string.
*
* @param {string} string
* @returns {string}
* @private
* @examples
* _getAcronym('i love candy') // => 'ilc'
* _getAcronym('water-fall in the spring-time') // => 'wfitst'
*/
function _getAcronym(string) {
var acronym = '';
var wordsInString = string.split(' ');
_each(wordsInString, function(wordInString) {
var splitByHyphenWords = wordInString.split('-');
_each(splitByHyphenWords, function(splitByHyphenWord) {
acronym += splitByHyphenWord.substr(0, 1);
});
});
return acronym;
}
/**
* Returns a _matchRankMap.matches or noMatch score based on whether
* the characters in the givenMagicWord are found in order in the
* magicWord
* @param {string} magicWord
* @param {string} givenMagicWord
* @returns {number}
* @private
*/
function _stringsByCharOrder(magicWord, givenMagicWord) {
var charNumber = 0;
function _findMatchingCharacter(matchChar, string) {
var found = false;
for (var j = charNumber; j < string.length; j++) {
var stringChar = string[j];
if (stringChar === matchChar) {
found = true;
charNumber = j + 1;
break;
}
}
return found;
}
for (var i = 0; i < givenMagicWord.length; i++) {
var matchChar = givenMagicWord[i];
var found = _findMatchingCharacter(matchChar, magicWord);
if (!found) {
return _matchRankMap.noMatch;
}
}
return _matchRankMap.matches;
}
Perhaps there's a better way to do this, but my library (kentcdodds/genie) is running Travis Builds using grunt. Right now it's running Mocha tests, but I want to switch to autodoc and still have my builds run the tests. It'd also be useful during development so I can have a grunt watch
going as I'm coding away 👍
Themes—shouldn't be hard at all. Can just start w/ Bootswatch.
Layout—as a start, maybe just do... two-column, three-column, nav on left/right.
Specifying object properties like this (below) does not result in the correct documentation. The object properties should go in a nested table in the row for the object - 'opts', in this case. With autodoc, each object property gets it's own line in the main table. Also, using 'opts.host' as an example, the string ".host - Hostname or IP address" ends up in the Description column.
/**
* @param {Object} opts - The connection options object
* @param {string} opts.host - Hostname or IP address
* @param {integer} opts.port - Port number
* @param {string=} opts.username - Username
* @param {string=} opts.password - Password
*/
autodoc --version
0.6.2
When I give my package.json this
"autodoc": "https://github.com/dtao/autodoc.git"
It gives me this error on npm install
Error: ENOENT, open '/var/folders/63/w7j_jfrs5g1bz3dxnv0d9j100000gn/T/npm-17041-JNqw-VKQ/1389014143301-0.059972834307700396/package/package.json'
Not certain what needs to be done to fix this, but I would prefer to be on the bleeding edge of this library :) It seems like there's a file missing maybe...
This is a pretty common trope in JS code:
someAsyncFunction('parameter1', function parameter2(err, result) {
if(err) {
console.err(err.toString());
return;
}
console.log(result);
});
or as in underscore or lazy.js:
lazy([1,2,3]).map(function(index, value) {
return index + value;
}).toArray();
Right now, when documenting these API's, we have to resort to something like:
/**
* Does some async thing!
* @argument {string} foo This is very unimportant.
* @argument {function} callback When we've finished our calculation, we call this function and provide it two arguments -- the first is an error, which will be `null` if everything works out okay, and the second is an instance of `HolyGrail` which will make all your dreams come true.
*/
someAsyncFunction: function(foo, callback) {
// ...
}
This seems less than ideal. JSDoc provides the @callback
tag, which might be the optimal solution here. What do you think?
Works fine:
/*
@example
true // => true
false // => true
*/
Highlights the "true // => true" line:
/*
@example
true // => true
false // => true
*/
Looking back on things... I don't know why I decided to deviate from JsDoc and require the @examples
tag instead of the standard @example
one.
People might have built stuff on top of other test runners or prefer the output of other runners, e.g. mocha.
I also think Autodoc ought to have its own runner, so that neither jasmine nor mocha nor birds of the air nor creatures of the earth are necessary.
Given the following example:
/*
@example
var foo = {
bar : 'baz'
};
*/
There is no indentation at all in the output, which would make the examples much easier to read :)
Pathetic!
Besides Mustache, that is. Like... JST? HAML?
Say I have this, in CoffeeScript:
###
@name MyLibrary
@fileOverview
This is an awesome library that does things
###
class MyLibrary
###
Does a thing
####
thing: ->
console.log "Thing done!"
This is the documentation it generates:
Moving the @fileOverview
comment into the class declaration makes the bogus null.call
function go away, but that seems like a silly thing to have to do.
Right now, in order to use the project you have to have objects called doctrine
, esprima
, and marked
in the global namespace, or you are required to manually pass in a codeParser
, commendParser
, and markdownParser
to the Breakneck.parse
function. I get what you're doing here -- it allows for dependency injection. On the other hand, requiring up all these dependencies just to use the project seems wrong.
Maybe it'd make sense to have the "main" file in package.json
point to something that requires up these files and then passes them into Breakneck? Gonna build a quick POC of this kind of thing...
Not sure what the package does, but it's certainly not this one: https://npmjs.org/package/breakneck
It occurred to me that one very definite "tell" would be a line like:
module.exports = Foo;
Given a line like this, I'd say it's highly likely the library name is Foo.
I'm assuming it's MIT (https://github.com/dtao/autodoc/blob/master/package.json#L17) but it would be nice if you could add something in the readme file or even add a separate file that contains the entire license (as it is in lazy.js).
This shouldn't be that hard, really.
If it's an object with a bunch of properties, it's a "namespace".
If it's a function, then it's class. Its direct properties are "static" members and its prototype's properties are "instance" members.
And if it doesn't belong to a namespace and it's got no members, then it's just a function.
Right now wherever Autodoc fails, it's because of some random thing that is typically easy for me to identify but would be totally cryptic to anyone else. If this library is going to be super useful to the dev community at large, then pro-active validation and meaningful error messages will be very important.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.