From 4f22d6866c052fb5b770ce4f377cecacacd9e6d8 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Thu, 23 Dec 2010 00:44:27 +0100 Subject: complete rewrite of documentation generation - romeved mustache.js - unified templates - improved testability of the code --- docs/spec/collectSpec.js | 288 ----------------------------------------------- docs/spec/ngdocSpec.js | 257 ++++++++++++++++++++++++++++++++++++++++++ docs/spec/specs.js | 39 +++++++ docs/spec/writerSpec.js | 18 +++ 4 files changed, 314 insertions(+), 288 deletions(-) delete mode 100644 docs/spec/collectSpec.js create mode 100644 docs/spec/ngdocSpec.js create mode 100644 docs/spec/specs.js create mode 100644 docs/spec/writerSpec.js (limited to 'docs/spec') diff --git a/docs/spec/collectSpec.js b/docs/spec/collectSpec.js deleted file mode 100644 index f0783bdf..00000000 --- a/docs/spec/collectSpec.js +++ /dev/null @@ -1,288 +0,0 @@ -console.log(__dirname); -require.paths.push(__dirname + "/../"); -require.paths.push(__dirname + "/../../"); -var fs = require('fs'); -var Script = process.binding('evals').Script; -var collect = load('docs/collect.js'); - -describe('collect', function(){ - describe('markdown', function(){ - it('should replace angular in markdown', function(){ - expect(collect.markdown('')). - toEqual('

<angular/>

'); - }); - - it('should not replace anything in
', function(){
-      expect(collect.markdown('bah x\n
\nangular.k\n
\n asdf x')). - toEqual( - '

bah x

' + - '
\nangular.k\n
' + - '

asdf x

'); - }); - - it('should replace text between two
 tags', function() {
-      expect(collect.markdown('
x
# One
b
')). - toEqual('
x

One

b
'); - }); - }); - - describe('processNgDoc', function() { - var processNgDoc = collect.processNgDoc, - documentation; - - beforeEach(function() { - documentation = { - pages: [], - byName: {} - }; - }); - - it('should store references to docs by name', function() { - var doc = {ngdoc: 'section', name: 'fake', raw: {text:''}}; - processNgDoc(documentation, doc); - expect(documentation.byName.fake).toBe(doc); - }); - - it('should connect doc to owner (specified by @methodOf)', function() { - var parentDoc = {ngdoc: 'section', name: 'parent', raw: {text:''}}; - var doc = {ngdoc: 'section', name: 'child', methodOf: 'parent', raw: {text:''}}; - processNgDoc(documentation, parentDoc); - processNgDoc(documentation, doc); - expect(documentation.byName.parent.method).toBeDefined(); - expect(documentation.byName.parent.method[0]).toBe(doc); - }); - - it('should not add doc to sections if @memberOf specified', function() { - var parentDoc = {ngdoc: 'parent', name: 'parent', raw: {text:''}}; - var doc = {ngdoc: 'child', name: 'child', methodOf: 'parent', raw: {text:''}}; - processNgDoc(documentation, parentDoc); - processNgDoc(documentation, doc); - expect(documentation.pages.child).not.toBeDefined(); - }); - - it('should throw exception if owner does not exist', function() { - expect(function() { - processNgDoc(documentation, {ngdoc: 'section', methodOf: 'not.exist', raw: {text:''}}); - }).toThrow('Owner "not.exist" is not defined.'); - }); - - it('should ignore non-ng docs', function() { - var doc = {name: 'anything'}; - expect(function() { - processNgDoc(documentation, doc); - }).not.toThrow(); - expect(documentation.pages).not.toContain(doc); - }); - }); - - describe('TAG', function(){ - var TAG = collect.TAG; - var doc; - beforeEach(function(){ - doc = {}; - }); - - describe('@param', function(){ - it('should parse with no default', function(){ - TAG.param(doc, 'param', - '{(number|string)} number Number \n to format.'); - expect(doc.param).toEqual([{ - type : '(number|string)', - name : 'number', - optional: false, - 'default' : undefined, - description : 'Number \n to format.' }]); - }); - it('should parse with default and optional', function(){ - TAG.param(doc, 'param', - '{(number|string)=} [fractionSize=2] desc'); - expect(doc.param).toEqual([{ - type : '(number|string)', - name : 'fractionSize', - optional: true, - 'default' : '2', - description : 'desc' }]); - }); - }); - - describe('@requires', function() { - it('should parse more @requires tag into array', function() { - TAG.requires(doc, 'requires', '$service'); - TAG.requires(doc, 'requires', '$another'); - - expect(doc.requires).toEqual([ - {name: '$service'}, - {name: '$another'} - ]); - }); - }); - - describe('@property', function() { - it('should parse @property tags into array', function() { - TAG.property(doc, 'property', '{type} name1 desc'); - TAG.property(doc, 'property', '{type} name2 desc'); - expect(doc.property.length).toEqual(2); - }); - - it('should parse @property with only name', function() { - TAG.property(doc, 'property', 'fake'); - expect(doc.property[0].name).toEqual('fake'); - }); - - it('should parse @property with optional type', function() { - TAG.property(doc, 'property', '{string} name'); - expect(doc.property[0].name).toEqual('name'); - expect(doc.property[0].type).toEqual('string'); - }); - - it('should parse @property with optional description', function() { - TAG.property(doc, 'property', 'name desc rip tion'); - expect(doc.property[0].name).toEqual('name'); - expect(doc.property[0].description).toEqual('desc rip tion'); - }); - - it('should parse @property with type and description both', function() { - TAG.property(doc, 'property', '{bool} name desc rip tion'); - expect(doc.property[0].name).toEqual('name'); - expect(doc.property[0].type).toEqual('bool'); - expect(doc.property[0].description).toEqual('desc rip tion'); - }); - - /** - * If property description is undefined, this variable is not set in the template, - * so the whole @description tag is used instead - */ - it('should set undefined description to "false"', function() { - TAG.property(doc, 'property', 'name'); - expect(doc.property[0].description).toBe(false); - }); - }); - - describe('@methodOf', function() { - it('should parse @methodOf tag', function() { - expect(function() { - TAG.methodOf(doc, 'methodOf', 'parentName'); - }).not.toThrow(); - expect(doc.methodOf).toEqual('parentName'); - }); - }); - - describe('@returns', function() { - it('should not parse @returns without type', function() { - expect(function() {TAG.returns(doc, 'returns', 'lala');}) - .toThrow(); - }); - - it('should parse @returns with type and description', function() { - TAG.returns(doc, 'returns', '{string} descrip tion'); - expect(doc.returns).toEqual({type: 'string', description: 'descrip tion'}); - }); - - it('should transform description of @returns with markdown', function() { - TAG.returns(doc, 'returns', '{string} descrip *tion*'); - expect(doc.returns).toEqual({type: 'string', description: 'descrip tion'}); - }); - - it('should support multiline content', function() { - TAG.returns(doc, 'returns', '{string} description\n new line\n another line'); - expect(doc.returns). - toEqual({type: 'string', description: 'description\n new line\n another line'}); - }); - }); - - describe('@description', function(){ - it('should support pre blocks', function(){ - TAG.description(doc, 'description', '
abc
'); - expect(doc.description). - toBe('
abc
'); - }); - - it('should support multiple pre blocks', function() { - TAG.description(doc, 'description', 'foo \n
abc
\n#bah\nfoo \n
cba
'); - expect(doc.description). - toBe('

foo

' + - '
abc
' + - '

bah

\n\n' + - '

foo

' + - '
cba
'); - - }); - - it('should support nested @link annotations with or without description', function() { - TAG.description(doc, 'description', - 'foo {@link angular.foo}\n\n da {@link angular.foo bar foo bar } \n\n' + - 'dad{@link angular.foo}\n\n' + - '{@link angular.directive.ng:foo ng:foo}'); - expect(doc.description). - toBe('

foo angular.foo

\n\n' + - '

da bar foo bar

\n\n' + - '

dadangular.foo

\n\n' + - '

ng:foo

'); - }); - - it('should increment all headings by one', function() { - TAG.description(doc, 'description', '# foo\nabc'); - expect(doc.description). - toBe('

foo

\n\n

abc

'); - }); - }); - - describe('@example', function(){ - it('should not remove {{}}', function(){ - TAG.example(doc, 'example', 'text {{ abc }}'); - expect(doc.example).toEqual('text {{ abc }}'); - }); - }); - - describe('@deprecated', function() { - it('should parse @deprecated', function() { - TAG.deprecated(doc, 'deprecated', 'Replaced with foo.'); - expect(doc.deprecated).toBe('Replaced with foo.'); - }) - }); - - describe('@workInProgress', function() { - it('should parse @workInProgress without a description and default to true', function() { - TAG.workInProgress(doc, 'workInProgress', ''); - expect(doc.workInProgress).toEqual({description: ''}); - }); - - it('should parse @workInProgress with a description', function() { - TAG.workInProgress(doc, 'workInProgress', 'my description'); - expect(doc.workInProgress).toEqual({description: '

my description

'}); - }); - }); - - }); - - describe('trim', function(){ - var trim = collect.trim; - it('should remove leading/trailing space', function(){ - expect(trim(' \nabc\n ')).toEqual('abc'); - }); - - it('should remove leading space on every line', function(){ - expect(trim('\n 1\n 2\n 3\n')).toEqual('1\n 2\n 3'); - }); - }); - - describe('keywords', function(){ - var keywords = collect.keywords; - it('should collect keywords', function(){ - expect(keywords('\nHello: World! @ignore.')).toEqual('hello world'); - expect(keywords('The `ng:class-odd` and ')).toEqual('and ng:class-odd the'); - }); - }); - -}); - -function load(path){ - var sandbox = { - require: require, - console: console, - __dirname: __dirname, - testmode: true - }; - Script.runInNewContext(fs.readFileSync(path), sandbox, path); - return sandbox; -} diff --git a/docs/spec/ngdocSpec.js b/docs/spec/ngdocSpec.js new file mode 100644 index 00000000..63be610b --- /dev/null +++ b/docs/spec/ngdocSpec.js @@ -0,0 +1,257 @@ +var ngdoc = require('ngdoc.js'); + +describe('ngdoc', function(){ + var Doc = ngdoc.Doc; + describe('Doc', function(){ + describe('metadata', function(){ + + it('should find keywords', function(){ + expect(new Doc('\nHello: World! @ignore.').keywords()).toEqual('hello world'); + expect(new Doc('The `ng:class-odd` and').keywords()).toEqual('and ng:class-odd the'); + }); + }); + + describe('parse', function(){ + it('should convert @names into properties', function(){ + var doc = new Doc('\n@name name\n@desc\ndesc\ndesc2\n@dep\n'); + doc.parse(); + expect(doc.name).toEqual('name'); + expect(doc.desc).toEqual('desc\ndesc2'); + expect(doc.dep).toEqual(''); + }); + + it('should parse parameters', function(){ + var doc = new Doc( + '@param {*} a short\n' + + '@param {Type} b med\n' + + '@param {Class=} [c=2] long\nline'); + doc.parse(); + expect(doc.param).toEqual([ + {name:'a', description:'short', type:'*', optional:false, 'default':undefined}, + {name:'b', description:'med', type:'Type', optional:false, 'default':undefined}, + {name:'c', description:'long\nline', type:'Class', optional:true, 'default':'2'} + ]); + }); + + it('should parse return', function(){ + var doc = new Doc('@returns {Type} text *bold*.'); + doc.parse(); + expect(doc.returns).toEqual({ + type: 'Type', + description: 'text bold.' + }); + }); + }); + + + }); + + describe('markdown', function(){ + var markdown = ngdoc.markdown; + + it('should replace angular in markdown', function(){ + expect(markdown('')). + toEqual('

<angular/>

'); + }); + + it('should not replace anything in
', function(){
+      expect(markdown('bah x\n
\nangular.k\n
\n asdf x')). + toEqual( + '

bah x

' + + '
\n' + 
+            'angular.k\n' + 
+            '
' + + '

asdf x

'); + }); + + it('should replace text between two
 tags', function() {
+      expect(markdown('
x
# One
b
')). + toMatch('

One

tion'}); + }); + + it('should support multiline content', function() { + var doc = new Doc("@returns {string} description\n new line\n another line"); + doc.parse(); + expect(doc.returns). + toEqual({type: 'string', description: 'description\n new line\n another line'}); + }); + }); + + describe('@description', function(){ + it('should support pre blocks', function(){ + var doc = new Doc("@description
abc
"); + doc.parse(); + expect(doc.description). + toBe('
abc
'); + }); + + it('should support multiple pre blocks', function() { + var doc = new Doc("@description foo \n
abc
\n#bah\nfoo \n
cba
"); + doc.parse(); + expect(doc.description). + toBe('

foo

' + + '
abc
' + + '

bah

\n\n' + + '

foo

' + + '
cba
'); + + }); + + it('should support nested @link annotations with or without description', function() { + var doc = new Doc("@description " + + 'foo {@link angular.foo}\n\n da {@link angular.foo bar foo bar } \n\n' + + 'dad{@link angular.foo}\n\n' + + '{@link angular.directive.ng:foo ng:foo}'); + doc.parse(); + expect(doc.description). + toBe('

foo angular.foo

\n\n' + + '

da bar foo bar

\n\n' + + '

dadangular.foo

\n\n' + + '

ng:foo

'); + }); + + it('should increment all headings by two', function() { + var doc = new Doc('@description # foo\nabc\n## bar \n xyz'); + doc.parse(); + expect(doc.description). + toBe('

foo

\n\n

abc

\n\n

bar

\n\n

xyz

'); + }); + }); + + describe('@example', function(){ + it('should not remove {{}}', function(){ + var doc = new Doc('@example text {{ abc }}'); + doc.parse(); + expect(doc.example).toEqual('text {{ abc }}'); + }); + }); + + describe('@deprecated', function() { + it('should parse @deprecated', function() { + var doc = new Doc('@deprecated Replaced with foo.'); + doc.parse(); + expect(doc.deprecated).toBe('Replaced with foo.'); + }); + }); + }); + +}); diff --git a/docs/spec/specs.js b/docs/spec/specs.js new file mode 100644 index 00000000..a6ba17a9 --- /dev/null +++ b/docs/spec/specs.js @@ -0,0 +1,39 @@ +if (global.jasmine) return; + +require.paths.push(__dirname + "/../../lib"); +require.paths.push(__dirname + '/../src'); +var jasmine = require('jasmine-1.0.1'); +var sys = require('util'); + +for(var key in jasmine) { + global[key] = jasmine[key]; +} + +//Patch Jasmine for proper stack traces +jasmine.Spec.prototype.fail = function (e) { + var expectationResult = new jasmine.ExpectationResult({ + passed: false, + message: e ? jasmine.util.formatException(e) : 'Exception' + }); + // PATCH + if (e) { + expectationResult.trace = e; + } + this.results_.addResult(expectationResult); +}; + + + +var isVerbose = false; +var showColors = true; +process.argv.forEach(function(arg){ + switch(arg) { + case '--color': showColors = true; break; + case '--noColor': showColors = false; break; + case '--verbose': isVerbose = true; break; + } +}); + +jasmine.executeSpecsInFolder(__dirname, function(runner, log){ + process.exit(runner.results().failedCount); +}, isVerbose, showColors); diff --git a/docs/spec/writerSpec.js b/docs/spec/writerSpec.js new file mode 100644 index 00000000..1a722ca6 --- /dev/null +++ b/docs/spec/writerSpec.js @@ -0,0 +1,18 @@ +var writer = require('writer.js'); +describe('writer', function(){ + describe('toString', function(){ + var toString = writer.toString; + + it('should merge string', function(){ + expect(toString('abc')).toEqual('abc'); + }); + + it('should merge obj', function(){ + expect(toString({a:1})).toEqual('{"a":1}'); + }); + + it('should merge array', function(){ + expect(toString(['abc',{}])).toEqual('abc{}'); + }); + }); +}); \ No newline at end of file -- cgit v1.2.3