mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 23:40:23 +00:00
complete rewrite of documentation generation
- romeved mustache.js - unified templates - improved testability of the code
This commit is contained in:
parent
aab3df7aea
commit
4f22d6866c
33 changed files with 1271 additions and 1071 deletions
|
|
@ -1,58 +0,0 @@
|
||||||
<h1>{{name}}</h1>
|
|
||||||
|
|
||||||
{{#workInProgress}}
|
|
||||||
<fieldset class="workInProgress">
|
|
||||||
<legend>Work In Progress</legend>
|
|
||||||
This page is currently being revised. It might be incomplete or contain inaccuracies.
|
|
||||||
{{{workInProgress.description}}}
|
|
||||||
</fieldset>
|
|
||||||
{{/workInProgress}}
|
|
||||||
|
|
||||||
{{#deprecated}}
|
|
||||||
<fieldset class="deprecated">
|
|
||||||
<legend>Deprecated API</legend>
|
|
||||||
{{deprecated}}
|
|
||||||
</fieldset>
|
|
||||||
{{/deprecated}}
|
|
||||||
|
|
||||||
<h2>Description</h2>
|
|
||||||
{{{description}}}
|
|
||||||
|
|
||||||
<h2>Usage</h2>
|
|
||||||
<h3>In HTML Template Binding</h3>
|
|
||||||
<tt>
|
|
||||||
<pre>
|
|
||||||
<{{element}} {{shortName}}="{{paramFirst.name}}">
|
|
||||||
...
|
|
||||||
</{{element}}>
|
|
||||||
</pre>
|
|
||||||
</tt>
|
|
||||||
|
|
||||||
<h3>Parameters</h3>
|
|
||||||
<ul>
|
|
||||||
{{#param}}
|
|
||||||
<li><tt>{{name}}</tt> –
|
|
||||||
<tt>{{{#type}}{{type}}{{/type}}{{^type}}*{{/type}}{{#optional}}={{/optional}}}</tt>
|
|
||||||
<tt>{{#default}}[{{default}}]{{/default}}</tt>
|
|
||||||
– {{{description}}}</li>
|
|
||||||
{{/param}}
|
|
||||||
</ul>
|
|
||||||
{{{paramDescription}}}
|
|
||||||
|
|
||||||
{{#css}}
|
|
||||||
<h3>CSS</h3>
|
|
||||||
{{{css}}}
|
|
||||||
{{/css}}
|
|
||||||
|
|
||||||
{{#example}}
|
|
||||||
<h2>Example</h2>
|
|
||||||
{{{exampleDescription}}}
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
{{/example}}
|
|
||||||
{{{example}}}
|
|
||||||
{{#example}}
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
{{/example}}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
NG_PAGES={{{JSON}}};
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
<h1>{{name}}</h1>
|
|
||||||
|
|
||||||
{{#workInProgress}}
|
|
||||||
<fieldset class="workInProgress">
|
|
||||||
<legend>Work In Progress</legend>
|
|
||||||
This page is currently being revised. It might be incomplete or contain inaccuracies.
|
|
||||||
{{{workInProgress.description}}}
|
|
||||||
</fieldset>
|
|
||||||
{{/workInProgress}}
|
|
||||||
|
|
||||||
{{#deprecated}}
|
|
||||||
<fieldset class="deprecated">
|
|
||||||
<legend>Deprecated API</legend>
|
|
||||||
{{deprecated}}
|
|
||||||
</fieldset>
|
|
||||||
{{/deprecated}}
|
|
||||||
|
|
||||||
<h2>Description</h2>
|
|
||||||
{{{description}}}
|
|
||||||
|
|
||||||
<h2>Usage</h2>
|
|
||||||
<h3>In HTML Template Binding</h3>
|
|
||||||
<tt>
|
|
||||||
<span>{{</span>
|
|
||||||
{{paramFirst.name}}_expression
|
|
||||||
| {{shortName}}{{#paramRest}}{{^default}}:{{name}}{{/default}}{{#default}}<i>[:{{name}}={{default}}]</i>{{/default}}{{/paramRest}}
|
|
||||||
<span> }}</span>
|
|
||||||
</tt>
|
|
||||||
<h3>In JavaScript</h3>
|
|
||||||
<tt ng:non-bindable>
|
|
||||||
angular.filter.{{shortName}}({{paramFirst.name}}{{#paramRest}}, {{name}}{{/paramRest}} );
|
|
||||||
</tt>
|
|
||||||
|
|
||||||
<h3>Parameters</h3>
|
|
||||||
<ul>
|
|
||||||
{{#param}}
|
|
||||||
<li><tt>{{name}}</tt> –
|
|
||||||
<tt>{{{#type}}{{type}}{{/type}}{{^type}}*{{/type}}{{#optional}}={{/optional}}}</tt>
|
|
||||||
<tt>{{#default}}[{{default}}]{{/default}}</tt>
|
|
||||||
– {{{description}}}</li>
|
|
||||||
{{/param}}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{#returns}}
|
|
||||||
<h3>Returns</h3>
|
|
||||||
<tt>{{{{type}}}}</tt> {{{description}}}
|
|
||||||
{{/returns}}
|
|
||||||
|
|
||||||
{{#css}}
|
|
||||||
<h3>CSS</h3>
|
|
||||||
{{{css}}}
|
|
||||||
{{/css}}
|
|
||||||
|
|
||||||
{{#example}}
|
|
||||||
<h2>Example</h2>
|
|
||||||
{{{exampleDescription}}}
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
{{/example}}
|
|
||||||
{{{example}}}
|
|
||||||
{{#example}}
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
{{/example}}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
<h1>{{name}}</h1>
|
|
||||||
|
|
||||||
{{#workInProgress}}
|
|
||||||
<fieldset class="workInProgress">
|
|
||||||
<legend>Work In Progress</legend>
|
|
||||||
This page is currently being revised. It might be incomplete or contain inaccuracies.
|
|
||||||
{{{workInProgress.description}}}
|
|
||||||
</fieldset>
|
|
||||||
{{/workInProgress}}
|
|
||||||
|
|
||||||
{{#deprecated}}
|
|
||||||
<fieldset class="deprecated">
|
|
||||||
<legend>Deprecated API</legend>
|
|
||||||
{{deprecated}}
|
|
||||||
</fieldset>
|
|
||||||
{{/deprecated}}
|
|
||||||
|
|
||||||
<h2>Description</h2>
|
|
||||||
{{{description}}}
|
|
||||||
|
|
||||||
<h2>Usage</h2>
|
|
||||||
<h3>In HTML Template Binding</h3>
|
|
||||||
<tt>
|
|
||||||
<input type="text" ng:format="{{shortName}}">
|
|
||||||
</tt>
|
|
||||||
<h3>In JavaScript</h3>
|
|
||||||
<tt ng:non-bindable>
|
|
||||||
var userInputString = angular.formatter.{{shortName}}.format(modelValue);<br/>
|
|
||||||
var modelValue = angular.formatter.{{shortName}}.parse(userInputString);
|
|
||||||
</tt>
|
|
||||||
|
|
||||||
{{#returns}}
|
|
||||||
<h3>Returns</h3>
|
|
||||||
<tt>{{{{type}}}}</tt> {{{description}}}
|
|
||||||
{{/returns}}
|
|
||||||
|
|
||||||
{{#css}}
|
|
||||||
<h3>CSS</h3>
|
|
||||||
{{{css}}}
|
|
||||||
{{/css}}
|
|
||||||
|
|
||||||
{{#example}}
|
|
||||||
<h2>Example</h2>
|
|
||||||
{{{exampleDescription}}}
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
{{/example}}
|
|
||||||
{{{example}}}
|
|
||||||
{{#example}}
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
{{/example}}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
<h1>{{name}}</h1>
|
|
||||||
|
|
||||||
{{#workInProgress}}
|
|
||||||
<fieldset class="workInProgress">
|
|
||||||
<legend>Work In Progress</legend>
|
|
||||||
This page is currently being revised. It might be incomplete or contain inaccuracies.
|
|
||||||
{{{workInProgress.description}}}
|
|
||||||
</fieldset>
|
|
||||||
{{/workInProgress}}
|
|
||||||
|
|
||||||
{{#deprecated}}
|
|
||||||
<fieldset class="deprecated">
|
|
||||||
<legend>Deprecated API</legend>
|
|
||||||
{{deprecated}}
|
|
||||||
</fieldset>
|
|
||||||
{{/deprecated}}
|
|
||||||
|
|
||||||
<h2>Description</h2>
|
|
||||||
{{{description}}}
|
|
||||||
|
|
||||||
<h2>Usage</h2>
|
|
||||||
<tt ng:non-bindable>
|
|
||||||
{{name}}({{paramFirst.name}}{{#paramRest}}, {{name}}{{/paramRest}} );
|
|
||||||
</tt>
|
|
||||||
|
|
||||||
<h3>Parameters</h3>
|
|
||||||
<ul>
|
|
||||||
{{#param}}
|
|
||||||
<li><tt>{{name}}</tt> –
|
|
||||||
<tt>{{{#type}}{{type}}{{/type}}{{^type}}*{{/type}}{{#optional}}={{/optional}}}</tt>
|
|
||||||
<tt>{{#default}}[{{default}}]{{/default}}</tt>
|
|
||||||
– {{{description}}}</li>
|
|
||||||
{{/param}}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{#returns}}
|
|
||||||
<h3>Returns</h3>
|
|
||||||
<tt>{{{{type}}}}</tt> {{{description}}}
|
|
||||||
{{/returns}}
|
|
||||||
|
|
||||||
{{#example}}
|
|
||||||
<h2>Example</h2>
|
|
||||||
{{{exampleDescription}}}
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
{{/example}}
|
|
||||||
{{{example}}}
|
|
||||||
{{#example}}
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
{{/example}}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<h1>{{name}}</h1>
|
|
||||||
|
|
||||||
{{#workInProgress}}
|
|
||||||
<fieldset class="workInProgress">
|
|
||||||
<legend>Work In Progress</legend>
|
|
||||||
This page is currently being revised. It might be incomplete or contain inaccuracies.
|
|
||||||
{{{workInProgress.description}}}
|
|
||||||
</fieldset>
|
|
||||||
{{/workInProgress}}
|
|
||||||
|
|
||||||
{{#deprecated}}
|
|
||||||
<fieldset class="deprecated">
|
|
||||||
<legend>Deprecated API</legend>
|
|
||||||
{{deprecated}}
|
|
||||||
</fieldset>
|
|
||||||
{{/deprecated}}
|
|
||||||
|
|
||||||
{{{description}}}
|
|
||||||
|
|
||||||
{{#example}}
|
|
||||||
<h2>Example</h2>
|
|
||||||
{{{exampleDescription}}}
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
{{/example}}
|
|
||||||
{{{example}}}
|
|
||||||
{{#example}}
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
{{/example}}
|
|
||||||
|
|
@ -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('<angular/>')).
|
|
||||||
toEqual('<p><tt><angular/></tt></p>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should not replace anything in <pre>', function(){
|
|
||||||
expect(collect.markdown('bah x\n<pre>\nangular.k\n</pre>\n asdf x')).
|
|
||||||
toEqual(
|
|
||||||
'<p>bah x</p>' +
|
|
||||||
'<pre>\nangular.k\n</pre>' +
|
|
||||||
'<p>asdf x</p>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should replace text between two <pre></pre> tags', function() {
|
|
||||||
expect(collect.markdown('<pre>x</pre># One<pre>b</pre>')).
|
|
||||||
toEqual('<pre>x</pre><h1>One</h1><pre>b</pre>');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
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 <em>tion</em>'});
|
|
||||||
});
|
|
||||||
|
|
||||||
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', '<pre>abc</pre>');
|
|
||||||
expect(doc.description).
|
|
||||||
toBe('<div ng:non-bindable><pre class="brush: js; html-script: true;">abc</pre></div>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should support multiple pre blocks', function() {
|
|
||||||
TAG.description(doc, 'description', 'foo \n<pre>abc</pre>\n#bah\nfoo \n<pre>cba</pre>');
|
|
||||||
expect(doc.description).
|
|
||||||
toBe('<p>foo </p>' +
|
|
||||||
'<div ng:non-bindable><pre class="brush: js; html-script: true;">abc</pre></div>' +
|
|
||||||
'<h2>bah</h2>\n\n' +
|
|
||||||
'<p>foo </p>' +
|
|
||||||
'<div ng:non-bindable><pre class="brush: js; html-script: true;">cba</pre></div>');
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
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('<p>foo <a href="#!angular.foo"><code>angular.foo</code></a></p>\n\n' +
|
|
||||||
'<p>da <a href="#!angular.foo"><code>bar foo bar</code></a> </p>\n\n' +
|
|
||||||
'<p>dad<a href="#!angular.foo"><code>angular.foo</code></a></p>\n\n' +
|
|
||||||
'<p><a href="#!angular.directive.ng:foo"><code>ng:foo</code></a></p>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should increment all headings by one', function() {
|
|
||||||
TAG.description(doc, 'description', '# foo\nabc');
|
|
||||||
expect(doc.description).
|
|
||||||
toBe('<h2>foo</h2>\n\n<p>abc</p>');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
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: '<p>my description</p>'});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
257
docs/spec/ngdocSpec.js
Normal file
257
docs/spec/ngdocSpec.js
Normal file
|
|
@ -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 <em>bold</em>.'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('markdown', function(){
|
||||||
|
var markdown = ngdoc.markdown;
|
||||||
|
|
||||||
|
it('should replace angular in markdown', function(){
|
||||||
|
expect(markdown('<angular/>')).
|
||||||
|
toEqual('<p><tt><angular/></tt></p>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not replace anything in <pre>', function(){
|
||||||
|
expect(markdown('bah x\n<pre>\nangular.k\n</pre>\n asdf x')).
|
||||||
|
toEqual(
|
||||||
|
'<p>bah x</p>' +
|
||||||
|
'<div ng:non-bindable><pre class="brush: js; html-script: true;">\n' +
|
||||||
|
'angular.k\n' +
|
||||||
|
'</pre></div>' +
|
||||||
|
'<p>asdf x</p>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace text between two <pre></pre> tags', function() {
|
||||||
|
expect(markdown('<pre>x</pre># One<pre>b</pre>')).
|
||||||
|
toMatch('</div><h3>One</h3><div');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('trim', function(){
|
||||||
|
var trim = ngdoc.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('merge', function(){
|
||||||
|
it('should merge child with parent', function(){
|
||||||
|
var parent = new Doc({name:'angular.service.abc'});
|
||||||
|
var methodA = new Doc({name:'methodA', methodOf:'angular.service.abc'});
|
||||||
|
var methodB = new Doc({name:'methodB', methodOf:'angular.service.abc'});
|
||||||
|
var propA = new Doc({name:'propA', propertyOf:'angular.service.abc'});
|
||||||
|
var propB = new Doc({name:'propB', propertyOf:'angular.service.abc'});
|
||||||
|
;var docs = [methodB, methodA, propB, propA, parent]; // keep wrong order;
|
||||||
|
ngdoc.merge(docs);
|
||||||
|
expect(docs.length).toEqual(1);
|
||||||
|
expect(docs[0].name).toEqual('angular.service.abc');
|
||||||
|
expect(docs[0].methods).toEqual([methodA, methodB]);
|
||||||
|
expect(docs[0].properties).toEqual([propA, propB]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
describe('TAG', function(){
|
||||||
|
describe('@param', function(){
|
||||||
|
it('should parse with no default', function(){
|
||||||
|
var doc = new Doc('@param {(number|string)} number Number \n to format.');
|
||||||
|
doc.parse();
|
||||||
|
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(){
|
||||||
|
var doc = new Doc('@param {(number|string)=} [fractionSize=2] desc');
|
||||||
|
doc.parse();
|
||||||
|
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() {
|
||||||
|
var doc = new Doc('@requires $service\n@requires $another');
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.requires).toEqual(['$service', '$another']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('@property', function() {
|
||||||
|
it('should parse @property tags into array', function() {
|
||||||
|
var doc = new Doc("@property {type} name1 desc\n@property {type} name2 desc");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.properties.length).toEqual(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse @property with only name', function() {
|
||||||
|
var doc = new Doc("@property fake");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.properties[0].name).toEqual('fake');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse @property with optional type', function() {
|
||||||
|
var doc = new Doc("@property {string} name");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.properties[0].name).toEqual('name');
|
||||||
|
expect(doc.properties[0].type).toEqual('string');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse @property with optional description', function() {
|
||||||
|
var doc = new Doc("@property name desc rip tion");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.properties[0].name).toEqual('name');
|
||||||
|
expect(doc.properties[0].description).toEqual('desc rip tion');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse @property with type and description both', function() {
|
||||||
|
var doc = new Doc("@property {bool} name desc rip tion");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.properties[0].name).toEqual('name');
|
||||||
|
expect(doc.properties[0].type).toEqual('bool');
|
||||||
|
expect(doc.properties[0].description).toEqual('desc rip tion');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('@returns', function() {
|
||||||
|
it('should not parse @returns without type', function() {
|
||||||
|
var doc = new Doc("@returns lala");
|
||||||
|
expect(doc.parse).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should parse @returns with type and description', function() {
|
||||||
|
var doc = new Doc("@returns {string} descrip tion");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.returns).toEqual({type: 'string', description: 'descrip tion'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should transform description of @returns with markdown', function() {
|
||||||
|
var doc = new Doc("@returns {string} descrip *tion*");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.returns).toEqual({type: 'string', description: 'descrip <em>tion</em>'});
|
||||||
|
});
|
||||||
|
|
||||||
|
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 <pre>abc</pre>");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.description).
|
||||||
|
toBe('<div ng:non-bindable><pre class="brush: js; html-script: true;">abc</pre></div>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support multiple pre blocks', function() {
|
||||||
|
var doc = new Doc("@description foo \n<pre>abc</pre>\n#bah\nfoo \n<pre>cba</pre>");
|
||||||
|
doc.parse();
|
||||||
|
expect(doc.description).
|
||||||
|
toBe('<p>foo </p>' +
|
||||||
|
'<div ng:non-bindable><pre class="brush: js; html-script: true;">abc</pre></div>' +
|
||||||
|
'<h3>bah</h3>\n\n' +
|
||||||
|
'<p>foo </p>' +
|
||||||
|
'<div ng:non-bindable><pre class="brush: js; html-script: true;">cba</pre></div>');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
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('<p>foo <a href="#!angular.foo"><code>angular.foo</code></a></p>\n\n' +
|
||||||
|
'<p>da <a href="#!angular.foo"><code>bar foo bar</code></a> </p>\n\n' +
|
||||||
|
'<p>dad<a href="#!angular.foo"><code>angular.foo</code></a></p>\n\n' +
|
||||||
|
'<p><a href="#!angular.directive.ng:foo"><code>ng:foo</code></a></p>');
|
||||||
|
});
|
||||||
|
|
||||||
|
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('<h3>foo</h3>\n\n<p>abc</p>\n\n<h4>bar</h4>\n\n<p>xyz</p>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
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.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
39
docs/spec/specs.js
Normal file
39
docs/spec/specs.js
Normal file
|
|
@ -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);
|
||||||
18
docs/spec/writerSpec.js
Normal file
18
docs/spec/writerSpec.js
Normal file
|
|
@ -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{}');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
require.paths.push("./lib");
|
|
||||||
var jasmine = require('jasmine-1.0.1');
|
|
||||||
var sys = require('util');
|
|
||||||
|
|
||||||
for(var key in jasmine) {
|
|
||||||
global[key] = jasmine[key];
|
|
||||||
}
|
|
||||||
|
|
||||||
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 + '/spec', function(runner, log){
|
|
||||||
process.exit(runner.results().failedCount);
|
|
||||||
}, isVerbose, showColors);
|
|
||||||
|
|
@ -2,7 +2,10 @@ function noop(){}
|
||||||
|
|
||||||
function chain(delegateFn, explicitDone){
|
function chain(delegateFn, explicitDone){
|
||||||
var onDoneFn = noop;
|
var onDoneFn = noop;
|
||||||
var onErrorFn = noop;
|
var onErrorFn = function(e){
|
||||||
|
console.error(e.stack || e);
|
||||||
|
process.exit(-1);
|
||||||
|
};
|
||||||
var waitForCount = 1;
|
var waitForCount = 1;
|
||||||
delegateFn = delegateFn || noop;
|
delegateFn = delegateFn || noop;
|
||||||
var stackError = new Error('capture stack');
|
var stackError = new Error('capture stack');
|
||||||
123
docs/src/dom.js
Normal file
123
docs/src/dom.js
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
/**
|
||||||
|
* DOM generation class
|
||||||
|
*/
|
||||||
|
|
||||||
|
exports.DOM = DOM;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function DOM(){
|
||||||
|
this.out = [];
|
||||||
|
this.headingDepth = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var INLINE_TAGS = {
|
||||||
|
i: true,
|
||||||
|
b: true
|
||||||
|
};
|
||||||
|
|
||||||
|
DOM.prototype = {
|
||||||
|
toString: function() {
|
||||||
|
return this.out.join('');
|
||||||
|
},
|
||||||
|
|
||||||
|
text: function(content) {
|
||||||
|
if (typeof content == "string") {
|
||||||
|
this.out.push(content.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'));
|
||||||
|
} else if (typeof content == 'function') {
|
||||||
|
content.call(this, this);
|
||||||
|
} else if (content instanceof Array) {
|
||||||
|
this.ul(content);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
html: function(html) {
|
||||||
|
if (html) {
|
||||||
|
this.out.push(html);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
tag: function(name, attr, text) {
|
||||||
|
if (!text) {
|
||||||
|
text = attr;
|
||||||
|
attr = {};
|
||||||
|
if (name == 'code')
|
||||||
|
attr['ng:non-bindable'] = '';
|
||||||
|
}
|
||||||
|
this.out.push('<' + name);
|
||||||
|
for(var key in attr) {
|
||||||
|
this.out.push(" " + key + '="' + attr[key] + '"');
|
||||||
|
}
|
||||||
|
this.out.push('>');
|
||||||
|
this.text(text);
|
||||||
|
this.out.push('</' + name + '>');
|
||||||
|
if (!INLINE_TAGS[name])
|
||||||
|
this.out.push('\n');
|
||||||
|
},
|
||||||
|
|
||||||
|
code: function(text) {
|
||||||
|
this.tag('div', {'ng:non-bindable':''}, function(){
|
||||||
|
this.tag('pre', {'class':"brush: js; html-script: true;"}, text);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
example: function(source, scenario) {
|
||||||
|
if (source || scenario) {
|
||||||
|
this.h('Example', function(){
|
||||||
|
if (scenario === false) {
|
||||||
|
this.code(source);
|
||||||
|
} else {
|
||||||
|
this.tag('doc:example', function(){
|
||||||
|
if (source) this.tag('doc:source', source);
|
||||||
|
if (scenario) this.tag('doc:scenario', scenario);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
h: function(heading, content, fn){
|
||||||
|
if (content==undefined || content && content.legth == 0) return;
|
||||||
|
this.tag('h' + this.headingDepth, heading);
|
||||||
|
this.headingDepth++;
|
||||||
|
if (content instanceof Array) {
|
||||||
|
this.ul(content, {'class': heading.toLowerCase()}, fn);
|
||||||
|
} else if (fn) {
|
||||||
|
fn.call(this, content);
|
||||||
|
} else {
|
||||||
|
this.text(content);
|
||||||
|
}
|
||||||
|
this.headingDepth--;
|
||||||
|
},
|
||||||
|
|
||||||
|
h1: function(attr, text) {
|
||||||
|
this.tag('h1', attr, text);
|
||||||
|
},
|
||||||
|
|
||||||
|
h2: function(attr, text) {
|
||||||
|
this.tag('h2', attr, text);
|
||||||
|
},
|
||||||
|
|
||||||
|
h3: function(attr, text) {
|
||||||
|
this.tag('h3', attr, text);
|
||||||
|
},
|
||||||
|
|
||||||
|
p: function(attr, text) {
|
||||||
|
this.tag('p', attr, text);
|
||||||
|
},
|
||||||
|
|
||||||
|
ul: function(list, attr, fn) {
|
||||||
|
if (typeof attr == 'function') {
|
||||||
|
fn = attr;
|
||||||
|
attr = {};
|
||||||
|
}
|
||||||
|
this.tag('ul', attr, function(dom){
|
||||||
|
list.forEach(function(item){
|
||||||
|
dom.out.push('<li>');
|
||||||
|
dom.text(fn ? fn(item) : item);
|
||||||
|
dom.out.push('</li>\n');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
42
docs/src/gen-docs.js
Normal file
42
docs/src/gen-docs.js
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
require.paths.push(__dirname);
|
||||||
|
require.paths.push('lib');
|
||||||
|
var reader = require('reader.js'),
|
||||||
|
ngdoc = require('ngdoc.js'),
|
||||||
|
writer = require('writer.js'),
|
||||||
|
callback = require('callback.js');
|
||||||
|
|
||||||
|
var docs = [];
|
||||||
|
var start;
|
||||||
|
var work = callback.chain(function(){
|
||||||
|
start = now();
|
||||||
|
console.log('Generating Angular Reference Documentation...');
|
||||||
|
reader.collect(work.waitMany(function(text, file, line){
|
||||||
|
var doc = new ngdoc.Doc(text, file, line);
|
||||||
|
docs.push(doc);
|
||||||
|
doc.parse();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
var writes = callback.chain(function(){
|
||||||
|
ngdoc.merge(docs);
|
||||||
|
docs.forEach(function(doc){
|
||||||
|
writer.output(doc.name + '.html', doc.html(), writes.waitFor());
|
||||||
|
});
|
||||||
|
var metadata = ngdoc.metadata(docs);
|
||||||
|
writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata), ';'], writes.waitFor());
|
||||||
|
writer.copy('index.html', writes.waitFor());
|
||||||
|
writer.copy('docs.js', writes.waitFor());
|
||||||
|
writer.copy('docs.css', writes.waitFor());
|
||||||
|
writer.copy('doc_widgets.js', writes.waitFor());
|
||||||
|
writer.copy('doc_widgets.css', writes.waitFor());
|
||||||
|
writer.copy('docs-scenario.html', writes.waitFor());
|
||||||
|
writer.output('docs-scenario.js', ngdoc.scenarios(docs), writes.waitFor());
|
||||||
|
});
|
||||||
|
writes.onDone(function(){
|
||||||
|
console.log('DONE. Generated ' + docs.length + ' pages in ' +
|
||||||
|
(now()-start) + 'ms.' );
|
||||||
|
});
|
||||||
|
work.onDone(writes);
|
||||||
|
writer.makeDir('build/docs', work);
|
||||||
|
|
||||||
|
///////////////////////////////////
|
||||||
|
function now(){ return new Date().getTime(); }
|
||||||
0
docs/src/ignore.words
Normal file
0
docs/src/ignore.words
Normal file
614
docs/src/ngdoc.js
Normal file
614
docs/src/ngdoc.js
Normal file
|
|
@ -0,0 +1,614 @@
|
||||||
|
/**
|
||||||
|
* All parsing/transformation code goes here. All code here should be sync to ease testing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Showdown = require('showdown').Showdown;
|
||||||
|
var DOM = require('dom.js').DOM;
|
||||||
|
var NEW_LINE = /\n\r?/;
|
||||||
|
|
||||||
|
exports.markdown = markdown;
|
||||||
|
exports.markdownNoP = markdownNoP;
|
||||||
|
exports.trim = trim;
|
||||||
|
exports.metadata = metadata;
|
||||||
|
exports.scenarios = scenarios;
|
||||||
|
exports.merge = merge;
|
||||||
|
exports.Doc = Doc;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
function Doc(text, file, line) {
|
||||||
|
if (typeof text == 'object') {
|
||||||
|
for ( var key in text) {
|
||||||
|
this[key] = text[key];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.text = text;
|
||||||
|
this.file = file;
|
||||||
|
this.line = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Doc.METADATA_IGNORE = (function(){
|
||||||
|
var words = require('fs').readFileSync(__dirname + '/ignore.words', 'utf8');
|
||||||
|
return words.toString().split(/[,\s\n\r]+/gm);
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Doc.prototype = {
|
||||||
|
keywords: function keywords(){
|
||||||
|
var keywords = {};
|
||||||
|
Doc.METADATA_IGNORE.forEach(function(ignore){ keywords[ignore] = true; });
|
||||||
|
var words = [];
|
||||||
|
var tokens = this.text.toLowerCase().split(/[,\.\`\'\"\s]+/mg);
|
||||||
|
tokens.forEach(function(key){
|
||||||
|
var match = key.match(/^(([a-z]|ng\:)[\w\_\-]{2,})/);
|
||||||
|
if (match){
|
||||||
|
key = match[1];
|
||||||
|
if (!keywords[key]) {
|
||||||
|
keywords[key] = true;
|
||||||
|
words.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
words.sort();
|
||||||
|
return words.join(' ');
|
||||||
|
},
|
||||||
|
|
||||||
|
parse: function(){
|
||||||
|
var atName;
|
||||||
|
var atText;
|
||||||
|
var match;
|
||||||
|
var self = this;
|
||||||
|
self.text.split(NEW_LINE).forEach(function(line){
|
||||||
|
if (match = line.match(/^\s*@(\w+)(\s+(.*))?/)) {
|
||||||
|
// we found @name ...
|
||||||
|
// if we have existing name
|
||||||
|
flush();
|
||||||
|
atName = match[1];
|
||||||
|
atText = [];
|
||||||
|
if(match[3]) atText.push(match[3]);
|
||||||
|
} else {
|
||||||
|
if (atName) {
|
||||||
|
atText.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
flush();
|
||||||
|
this.shortName = (this.name || '').split(/[\.#]/).pop();
|
||||||
|
this.description = markdown(this.description);
|
||||||
|
|
||||||
|
function flush(){
|
||||||
|
if (atName) {
|
||||||
|
var text = trim(atText.join('\n'));
|
||||||
|
if (atName == 'param') {
|
||||||
|
var match = text.match(/^{([^}=]+)(=)?}\s+(([^\s=]+)|\[(\S+)=([^\]]+)\])\s+(.*)/);
|
||||||
|
// 1 12 2 34 4 5 5 6 6 3 7 7
|
||||||
|
if (!match) {
|
||||||
|
throw new Error("Not a valid 'param' format: " + text);
|
||||||
|
}
|
||||||
|
var param = {
|
||||||
|
name: match[5] || match[4],
|
||||||
|
description:markdownNoP(text.replace(match[0], match[7])),
|
||||||
|
type: match[1],
|
||||||
|
optional: !!match[2],
|
||||||
|
'default':match[6]
|
||||||
|
};
|
||||||
|
self.param = self.param || [];
|
||||||
|
self.param.push(param);
|
||||||
|
} else if (atName == 'returns') {
|
||||||
|
var match = text.match(/^{([^}=]+)}\s+(.*)/);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error("Not a valid 'returns' format: " + text);
|
||||||
|
}
|
||||||
|
self.returns = {
|
||||||
|
type: match[1],
|
||||||
|
description: markdownNoP(text.replace(match[0], match[2]))
|
||||||
|
};
|
||||||
|
} else if(atName == 'requires') {
|
||||||
|
self.requires = self.requires || [];
|
||||||
|
self.requires.push(text);
|
||||||
|
} else if(atName == 'property') {
|
||||||
|
var match = text.match(/^({(\S+)}\s*)?(\S+)(\s+(.*))?/);
|
||||||
|
if (!match) {
|
||||||
|
throw new Error("Not a valid 'property' format: " + text);
|
||||||
|
}
|
||||||
|
var property = {
|
||||||
|
type: match[2],
|
||||||
|
name: match[3],
|
||||||
|
description: match[5] || ''
|
||||||
|
};
|
||||||
|
self.properties = self.properties || [];
|
||||||
|
self.properties.push(property);
|
||||||
|
} else {
|
||||||
|
self[atName] = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
html: function(){
|
||||||
|
var dom = new DOM(),
|
||||||
|
self = this;
|
||||||
|
|
||||||
|
dom.h(this.name, function(){
|
||||||
|
notice('workInProgress', 'Work in Progress',
|
||||||
|
'This page is currently being revised. It might be incomplete or contain inaccuracies.');
|
||||||
|
notice('depricated', 'Depricated API');
|
||||||
|
dom.h('Description', self.description, html);
|
||||||
|
dom.h('Dependencies', self.requires);
|
||||||
|
|
||||||
|
usage();
|
||||||
|
|
||||||
|
dom.h('Methods', self.methods, function(method){
|
||||||
|
var signature = (method.param || []).map(property('name'));
|
||||||
|
dom.h(method.shortName + '(' + signature.join(', ') + ')', method, function(){
|
||||||
|
dom.html(method.description);
|
||||||
|
method.html_usage_parameters(dom);
|
||||||
|
dom.example(method.example, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
dom.h('Properties', self.properties, function(property){
|
||||||
|
dom.h(property.name, function(){
|
||||||
|
dom.text(property.description);
|
||||||
|
dom.example(property.example, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dom.example(self.example, self.scenario);
|
||||||
|
});
|
||||||
|
|
||||||
|
return dom.toString();
|
||||||
|
|
||||||
|
//////////////////////////
|
||||||
|
|
||||||
|
function html(text){
|
||||||
|
this.html(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
function usage(){
|
||||||
|
(self['html_usage_' + self.ngdoc] || function(){
|
||||||
|
throw new Error("Don't know how to format @ngdoc: " + self.ngdoc);
|
||||||
|
}).call(self, dom);
|
||||||
|
}
|
||||||
|
|
||||||
|
function section(name, property, fn) {
|
||||||
|
var value = self[property];
|
||||||
|
if (value) {
|
||||||
|
dom.h2(name);
|
||||||
|
if (typeof value == 'string') {
|
||||||
|
value = markdown(value) + '\n';
|
||||||
|
fn ? fn(value) : dom.html(value);
|
||||||
|
} else if (value instanceof Array) {
|
||||||
|
dom.ul(value, fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function notice(name, legend, msg){
|
||||||
|
if (self[name] == undefined) return;
|
||||||
|
dom.tag('fieldset', {'class':name}, function(dom){
|
||||||
|
dom.tag('legend', legend);
|
||||||
|
dom.text(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_parameters: function(dom) {
|
||||||
|
dom.h('Parameters', this.param, function(param){
|
||||||
|
dom.tag('code', function(){
|
||||||
|
dom.text(param.name);
|
||||||
|
if (param.optional) {
|
||||||
|
dom.tag('i', function(){
|
||||||
|
dom.text('(optional');
|
||||||
|
if(param['default']) {
|
||||||
|
dom.text('=' + param['default']);
|
||||||
|
}
|
||||||
|
dom.text(')');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dom.text(' – {');
|
||||||
|
dom.text(param.type);
|
||||||
|
dom.text('} – ');
|
||||||
|
});
|
||||||
|
dom.html(param.description);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_returns: function(dom) {
|
||||||
|
var self = this;
|
||||||
|
if (self.returns) {
|
||||||
|
dom.h('Returns', function(){
|
||||||
|
dom.tag('code', self.returns.type);
|
||||||
|
dom.text('– ');
|
||||||
|
dom.html(self.returns.description);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_function: function(dom){
|
||||||
|
var self = this;
|
||||||
|
dom.h('Usage', function(){
|
||||||
|
dom.code(function(){
|
||||||
|
dom.text(self.name);
|
||||||
|
dom.text('(');
|
||||||
|
var first = true;
|
||||||
|
(self.param || []).forEach(function(param){
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
dom.text(', ');
|
||||||
|
}
|
||||||
|
dom.text(param.name);
|
||||||
|
});
|
||||||
|
dom.text(');');
|
||||||
|
});
|
||||||
|
|
||||||
|
self.html_usage_parameters(dom);
|
||||||
|
self.html_usage_returns(dom);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_directive: function(dom){
|
||||||
|
var self = this;
|
||||||
|
dom.h('Usage', function(){
|
||||||
|
dom.tag('pre', {'class':"brush: js; html-script: true;"}, function(){
|
||||||
|
dom.text('<' + self.element + ' ');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
if (self.param) {
|
||||||
|
dom.text('="' + self.param[0].name + '"');
|
||||||
|
}
|
||||||
|
dom.text('>\n ...\n');
|
||||||
|
dom.text('</' + self.element + '>');
|
||||||
|
});
|
||||||
|
self.html_usage_parameters(dom);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_filter: function(dom){
|
||||||
|
var self = this;
|
||||||
|
dom.h('Usage', function(){
|
||||||
|
dom.h('In HTML Template Binding', function(){
|
||||||
|
dom.tag('code', function(){
|
||||||
|
dom.text('{{ ');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
dom.text('_expression | ');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
var first = true;
|
||||||
|
(self.param||[]).forEach(function(param){
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
if (param.optional) {
|
||||||
|
dom.tag('i', function(){
|
||||||
|
dom.text('[:' + param.name + ']');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dom.text(':' + param.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dom.text(' }}');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dom.h3('In JavaScript', function(){
|
||||||
|
dom.tag('code', function(){
|
||||||
|
dom.text('angular.filter.');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
dom.text('(');
|
||||||
|
var first = true;
|
||||||
|
(self.param||[]).forEach(function(param){
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
dom.text(param.name);
|
||||||
|
} else {
|
||||||
|
if (param.optional) {
|
||||||
|
dom.tag('i', function(){
|
||||||
|
dom.text('[, ' + param.name + ']');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dom.text(', ' + param.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dom.text(')');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.html_usage_parameters(dom);
|
||||||
|
self.html_usage_returns(dom);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_formatter: function(dom){
|
||||||
|
var self = this;
|
||||||
|
dom.h('Usage', function(){
|
||||||
|
dom.h('In HTML Template Binding', function(){
|
||||||
|
dom.code(function(){
|
||||||
|
dom.text('<input type="text" ng:format="');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
dom.text('">');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dom.h3('In JavaScript', function(){
|
||||||
|
dom.code(function(){
|
||||||
|
dom.text('var userInputString = angular.formatter.');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
dom.text('.format(modelValue);');
|
||||||
|
});
|
||||||
|
dom.html('<br/>');
|
||||||
|
dom.code(function(){
|
||||||
|
dom.text('var modelValue = angular.formatter.');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
dom.text('.parse(userInputString);');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.html_usage_returns(dom);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_validator: function(dom){
|
||||||
|
var self = this;
|
||||||
|
dom.h('Usage', function(){
|
||||||
|
dom.h('In HTML Template Binding', function(){
|
||||||
|
dom.code(function(){
|
||||||
|
dom.text('<input type="text" ng:validate="');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
var first = true;
|
||||||
|
(self.param||[]).forEach(function(param){
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
if (param.optional) {
|
||||||
|
dom.text('[:' + param.name + ']');
|
||||||
|
} else {
|
||||||
|
dom.text(':' + param.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dom.text('"/>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
dom.h('In JavaScript', function(){
|
||||||
|
dom.code(function(){
|
||||||
|
dom.text('angular.validator.');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
dom.text('(');
|
||||||
|
var first = true;
|
||||||
|
(self.param||[]).forEach(function(param){
|
||||||
|
if (first) {
|
||||||
|
first = false;
|
||||||
|
dom.text(param.name);
|
||||||
|
} else {
|
||||||
|
if (param.optional) {
|
||||||
|
dom.text('[, ' + param.name + ']');
|
||||||
|
} else {
|
||||||
|
dom.text(', ' + param.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dom.text(')');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.html_usage_parameters(dom);
|
||||||
|
self.html_usage_returns(dom);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_widget: function(dom){
|
||||||
|
var self = this;
|
||||||
|
dom.h('Usage', function(){
|
||||||
|
dom.h('In HTML Template Binding', function(){
|
||||||
|
dom.code(function(){
|
||||||
|
if (self.shortName.match(/^@/)) {
|
||||||
|
dom.text('<');
|
||||||
|
dom.text(self.element);
|
||||||
|
dom.text(' ');
|
||||||
|
dom.text(self.shortName.substring(1));
|
||||||
|
if (self.param) {
|
||||||
|
dom.text('="');
|
||||||
|
dom.text(self.param[0].name);
|
||||||
|
dom.text('"');
|
||||||
|
}
|
||||||
|
dom.text('>\n ...\n</');
|
||||||
|
dom.text(self.element);
|
||||||
|
dom.text('>');
|
||||||
|
} else {
|
||||||
|
dom.text('<');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
(self.param||[]).forEach(function(param){
|
||||||
|
if (param.optional) {
|
||||||
|
dom.text(' [' + param.name + '="..."]');
|
||||||
|
} else {
|
||||||
|
dom.text(' ' + param.name + '="..."');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dom.text('></');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
dom.text('>');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.html_usage_parameters(dom);
|
||||||
|
self.html_usage_returns(dom);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_overview: function(dom){
|
||||||
|
},
|
||||||
|
|
||||||
|
html_usage_service: function(dom){
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
function markdown (text) {
|
||||||
|
if (!text) return text;
|
||||||
|
var parts = text.split(/(<pre>[\s\S]*?<\/pre>)/),
|
||||||
|
match;
|
||||||
|
|
||||||
|
parts.forEach(function(text, i){
|
||||||
|
if (text.match(/^<pre>/)) {
|
||||||
|
text = text.
|
||||||
|
replace(/^<pre>/, '<div ng:non-bindable><pre class="brush: js; html-script: true;">').
|
||||||
|
replace(/<\/pre>/, '</pre></div>');
|
||||||
|
} else {
|
||||||
|
text = text.replace(/<angular\/>/gm, '<tt><angular/></tt>');
|
||||||
|
text = new Showdown.converter().makeHtml(text.replace(/^#/gm, '###'));
|
||||||
|
|
||||||
|
while (match = text.match(R_LINK)) {
|
||||||
|
text = text.replace(match[0], '<a href="#!' + match[1] + '"><code>' +
|
||||||
|
(match[4] || match[1]) +
|
||||||
|
'</code></a>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parts[i] = text;
|
||||||
|
});
|
||||||
|
return parts.join('');
|
||||||
|
};
|
||||||
|
var R_LINK = /{@link ([^\s}]+)((\s|\n)+(.+?))?\s*}/m;
|
||||||
|
// 1 123 3 4 42
|
||||||
|
function markdownNoP(text) {
|
||||||
|
var lines = markdown(text).split(NEW_LINE);
|
||||||
|
var last = lines.length - 1;
|
||||||
|
lines[0] = lines[0].replace(/^<p>/, '');
|
||||||
|
lines[last] = lines[last].replace(/<\/p>$/, '');
|
||||||
|
return lines.join('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
function scenarios(docs){
|
||||||
|
var specs = [];
|
||||||
|
docs.forEach(function(doc){
|
||||||
|
if (doc.scenario) {
|
||||||
|
specs.push('describe("');
|
||||||
|
specs.push(doc.name);
|
||||||
|
specs.push('", function(){\n');
|
||||||
|
specs.push(' beforeEach(function(){\n');
|
||||||
|
specs.push(' browser().navigateTo("index.html#!' + doc.name + '");');
|
||||||
|
specs.push(' });\n\n');
|
||||||
|
specs.push(doc.scenario);
|
||||||
|
specs.push('\n});\n\n');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return specs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
function metadata(docs){
|
||||||
|
var words = [];
|
||||||
|
docs.forEach(function(doc){
|
||||||
|
words.push({
|
||||||
|
name:doc.name,
|
||||||
|
type: doc.ngdoc,
|
||||||
|
keywords:doc.keywords()
|
||||||
|
});
|
||||||
|
});
|
||||||
|
words.sort(keywordSort);
|
||||||
|
return words;
|
||||||
|
}
|
||||||
|
|
||||||
|
function keywordSort(a,b){
|
||||||
|
// supper ugly comparator that orders all utility methods and objects before all the other stuff
|
||||||
|
// like widgets, directives, services, etc.
|
||||||
|
// Mother of all beautiful code please forgive me for the sin that this code certainly is.
|
||||||
|
|
||||||
|
if (a.name === b.name) return 0;
|
||||||
|
if (a.name === 'angular') return -1;
|
||||||
|
if (b.name === 'angular') return 1;
|
||||||
|
|
||||||
|
function namespacedName(page) {
|
||||||
|
return (page.name.match(/\./g).length === 1 && page.type !== 'overview' ? '0' : '1') + page.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
var namespacedA = namespacedName(a),
|
||||||
|
namespacedB = namespacedName(b);
|
||||||
|
|
||||||
|
return namespacedA < namespacedB ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
function trim(text) {
|
||||||
|
var MAX = 9999;
|
||||||
|
var empty = RegExp.prototype.test.bind(/^\s*$/);
|
||||||
|
var lines = text.split('\n');
|
||||||
|
var minIndent = MAX;
|
||||||
|
lines.forEach(function(line){
|
||||||
|
minIndent = Math.min(minIndent, indent(line));
|
||||||
|
});
|
||||||
|
for ( var i = 0; i < lines.length; i++) {
|
||||||
|
lines[i] = lines[i].substring(minIndent);
|
||||||
|
}
|
||||||
|
// remove leading lines
|
||||||
|
while (empty(lines[0])) {
|
||||||
|
lines.shift();
|
||||||
|
}
|
||||||
|
// remove trailing
|
||||||
|
while (empty(lines[lines.length - 1])) {
|
||||||
|
lines.pop();
|
||||||
|
}
|
||||||
|
return lines.join('\n');
|
||||||
|
|
||||||
|
function indent(line) {
|
||||||
|
for(var i = 0; i < line.length; i++) {
|
||||||
|
if (line.charAt(i) != ' ') {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
function merge(docs){
|
||||||
|
var byName = {};
|
||||||
|
docs.forEach(function(doc){
|
||||||
|
byName[doc.name] = doc;
|
||||||
|
});
|
||||||
|
for(var i=0; i<docs.length;) {
|
||||||
|
if (findParent(docs[i], 'method') ||
|
||||||
|
findParent(docs[i], 'property')) {
|
||||||
|
docs.splice(i, 1);
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findParent(doc, name){
|
||||||
|
var parentName = doc[name+'Of'];
|
||||||
|
if (!parentName) return false;
|
||||||
|
|
||||||
|
var parent = byName[parentName];
|
||||||
|
if (!parent)
|
||||||
|
throw new Error("No parent named '" + parentName + "' for '" +
|
||||||
|
doc.name + "' in @" + name + "Of.");
|
||||||
|
|
||||||
|
var listName = (name + 's').replace(/ys$/, 'ies');
|
||||||
|
var list = parent[listName] = (parent[listName] || []);
|
||||||
|
list.push(doc);
|
||||||
|
list.sort(orderByName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function orderByName(a, b){
|
||||||
|
return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function property(name) {
|
||||||
|
return function(value){
|
||||||
|
return value[name];
|
||||||
|
};
|
||||||
|
}
|
||||||
91
docs/src/reader.js
Normal file
91
docs/src/reader.js
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* All reading related code here. This is so that we can separate the async code from sync code
|
||||||
|
* for testability
|
||||||
|
*/
|
||||||
|
require.paths.push(__dirname);
|
||||||
|
var fs = require('fs'),
|
||||||
|
callback = require('callback');
|
||||||
|
|
||||||
|
var NEW_LINE = /\n\r?/;
|
||||||
|
|
||||||
|
function collect(callback){
|
||||||
|
findJsFiles('src', callback.waitMany(function(file) {
|
||||||
|
//console.log('reading', file, '...');
|
||||||
|
findNgDocInJsFile(file, callback.waitMany(function(doc, line) {
|
||||||
|
callback(doc, file, line);
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
findNgDocInDir('docs/', callback.waitMany(callback));
|
||||||
|
callback.done();
|
||||||
|
}
|
||||||
|
|
||||||
|
function findJsFiles(dir, callback){
|
||||||
|
fs.readdir(dir, callback.waitFor(function(err, files){
|
||||||
|
if (err) return this.error(err);
|
||||||
|
files.forEach(function(file){
|
||||||
|
var path = dir + '/' + file;
|
||||||
|
fs.lstat(path, callback.waitFor(function(err, stat){
|
||||||
|
if (err) return this.error(err);
|
||||||
|
if (stat.isDirectory())
|
||||||
|
findJsFiles(path, callback.waitMany(callback));
|
||||||
|
else if (/\.js$/.test(path))
|
||||||
|
callback(path);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
callback.done();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function findNgDocInDir(directory, docNotify) {
|
||||||
|
fs.readdir(directory, docNotify.waitFor(function(err, files){
|
||||||
|
if (err) return this.error(err);
|
||||||
|
files.forEach(function(file){
|
||||||
|
//console.log('reading', directory + file, '...');
|
||||||
|
if (!file.match(/\.ngdoc$/)) return;
|
||||||
|
fs.readFile(directory + file, docNotify.waitFor(function(err, content){
|
||||||
|
if (err) return this.error(err);
|
||||||
|
docNotify(content.toString(), directory + file, 1);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
docNotify.done();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function findNgDocInJsFile(file, callback) {
|
||||||
|
fs.readFile(file, callback.waitFor(function(err, content){
|
||||||
|
var lines = content.toString().split(NEW_LINE);
|
||||||
|
var text;
|
||||||
|
var startingLine ;
|
||||||
|
var match;
|
||||||
|
var inDoc = false;
|
||||||
|
lines.forEach(function(line, lineNumber){
|
||||||
|
lineNumber++;
|
||||||
|
// is the comment starting?
|
||||||
|
if (!inDoc && (match = line.match(/^\s*\/\*\*\s*(.*)$/))) {
|
||||||
|
line = match[1];
|
||||||
|
inDoc = true;
|
||||||
|
text = [];
|
||||||
|
startingLine = lineNumber;
|
||||||
|
}
|
||||||
|
// are we done?
|
||||||
|
if (inDoc && line.match(/\*\//)) {
|
||||||
|
text = text.join('\n');
|
||||||
|
text = text.replace(/^\n/, '');
|
||||||
|
if (text.match(/@ngdoc/)){
|
||||||
|
callback(text, startingLine);
|
||||||
|
}
|
||||||
|
doc = null;
|
||||||
|
inDoc = false;
|
||||||
|
}
|
||||||
|
// is the comment add text
|
||||||
|
if (inDoc){
|
||||||
|
text.push(line.replace(/^\s*\*\s?/, ''));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
callback.done();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
exports.collect = collect;
|
||||||
|
|
@ -100,6 +100,12 @@ a {
|
||||||
margin-top: 1.5em;
|
margin-top: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#main ul.methods h3,
|
||||||
|
#main ul.properties h3 {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
font-family: "Courier New", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
.main-title {
|
.main-title {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
<script src="../angular.min.js" ng:autobind></script>
|
<script src="../angular.min.js" ng:autobind></script>
|
||||||
<script src="docs.js"></script>
|
<script src="docs.js"></script>
|
||||||
<script src="doc_widgets.js"></script>
|
<script src="doc_widgets.js"></script>
|
||||||
<script src="docs-data.js"></script>
|
<script src="docs-keywords.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body style="display:none;" ng:show="true">
|
<body style="display:none;" ng:show="true">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
61
docs/src/writer.js
Normal file
61
docs/src/writer.js
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
/**
|
||||||
|
* All writing related code here. This is so that we can separate the async code from sync code
|
||||||
|
* for testability
|
||||||
|
*/
|
||||||
|
require.paths.push(__dirname);
|
||||||
|
var fs = require('fs');
|
||||||
|
var OUTPUT_DIR = "build/docs/";
|
||||||
|
|
||||||
|
function output(docs, content, callback){
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.output = function(file, content, callback){
|
||||||
|
//console.log('writing', OUTPUT_DIR + file, '...');
|
||||||
|
fs.writeFile(
|
||||||
|
OUTPUT_DIR + file,
|
||||||
|
exports.toString(content),
|
||||||
|
callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.toString = function toString(obj){
|
||||||
|
switch (typeof obj) {
|
||||||
|
case 'string':
|
||||||
|
return obj;
|
||||||
|
case 'object':
|
||||||
|
if (obj instanceof Array) {
|
||||||
|
obj.forEach(function (value, key){
|
||||||
|
obj[key] = toString(value);
|
||||||
|
});
|
||||||
|
return obj.join('');
|
||||||
|
} else {
|
||||||
|
return JSON.stringify(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.makeDir = function (path, callback) {
|
||||||
|
var parts = path.split(/\//);
|
||||||
|
path = '.';
|
||||||
|
(function next(){
|
||||||
|
if (parts.length) {
|
||||||
|
path += '/' + parts.shift();
|
||||||
|
fs.mkdir(path, 0777, next);
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.copy = function(filename, callback){
|
||||||
|
//console.log('writing', OUTPUT_DIR + filename, '...');
|
||||||
|
fs.readFile('docs/src/templates/' + filename, function(err, content){
|
||||||
|
if (err) return callback.error(err);
|
||||||
|
fs.writeFile(
|
||||||
|
OUTPUT_DIR + filename,
|
||||||
|
content,
|
||||||
|
callback);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<h1>{{name}}</h1>
|
|
||||||
|
|
||||||
{{#workInProgress}}
|
|
||||||
<fieldset class="workInProgress">
|
|
||||||
<legend>Work In Progress</legend>
|
|
||||||
This page is currently being revised. It might be incomplete or contain inaccuracies.
|
|
||||||
{{{workInProgress.description}}}
|
|
||||||
</fieldset>
|
|
||||||
{{/workInProgress}}
|
|
||||||
|
|
||||||
{{#deprecated}}
|
|
||||||
<fieldset class="deprecated">
|
|
||||||
<legend>Deprecated API</legend>
|
|
||||||
{{deprecated}}
|
|
||||||
</fieldset>
|
|
||||||
{{/deprecated}}
|
|
||||||
|
|
||||||
<h2>Description</h2>
|
|
||||||
{{{description}}}
|
|
||||||
|
|
||||||
<h2>Usage</h2>
|
|
||||||
<h3>In HTML Template Binding</h3>
|
|
||||||
<tt>
|
|
||||||
<input type="text" ng:validate="{{shortName}}{{#paramRest}}{{^default}}:{{name}}{{/default}}{{#default}}<i>[:{{name}}]</i>{{/default}}{{/paramRest}}"/>
|
|
||||||
</tt>
|
|
||||||
|
|
||||||
<h3>In JavaScript</h3>
|
|
||||||
<tt ng:non-bindable>
|
|
||||||
angular.validator.{{shortName}}({{paramFirst.name}}{{#paramRest}}{{^default}}, {{name}}{{/default}}{{#default}}<i>[, {{name}}]</i>{{/default}}{{/paramRest}} );
|
|
||||||
</tt>
|
|
||||||
|
|
||||||
<h3>Parameters</h3>
|
|
||||||
<ul>
|
|
||||||
{{#param}}
|
|
||||||
<li><tt>{{name}}</tt> –
|
|
||||||
<tt>{{{#type}}{{type}}{{/type}}{{^type}}*{{/type}}{{#optional}}={{/optional}}}</tt>
|
|
||||||
<tt>{{#default}}[{{default}}]{{/default}}</tt>
|
|
||||||
– {{{description}}}</li>
|
|
||||||
{{/param}}
|
|
||||||
</ul>
|
|
||||||
{{{paramDescription}}}
|
|
||||||
|
|
||||||
{{#css}}
|
|
||||||
<h3>CSS</h3>
|
|
||||||
{{{css}}}
|
|
||||||
{{/css}}
|
|
||||||
|
|
||||||
{{#example}}
|
|
||||||
<h2>Example</h2>
|
|
||||||
{{{exampleDescription}}}
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
{{/example}}
|
|
||||||
{{{example}}}
|
|
||||||
{{#example}}
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
{{/example}}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
<h1>{{name}}</h1>
|
|
||||||
|
|
||||||
{{#workInProgress}}
|
|
||||||
<fieldset class="workInProgress">
|
|
||||||
<legend>Work In Progress</legend>
|
|
||||||
This page is currently being revised. It might be incomplete or contain inaccuracies.
|
|
||||||
{{{workInProgress.description}}}
|
|
||||||
</fieldset>
|
|
||||||
{{/workInProgress}}
|
|
||||||
|
|
||||||
{{#deprecated}}
|
|
||||||
<fieldset class="deprecated">
|
|
||||||
<legend>Deprecated API</legend>
|
|
||||||
{{deprecated}}
|
|
||||||
</fieldset>
|
|
||||||
{{/deprecated}}
|
|
||||||
|
|
||||||
<h2>Description</h2>
|
|
||||||
{{{description}}}
|
|
||||||
|
|
||||||
<h2>Usage</h2>
|
|
||||||
<h3>In HTML Template Binding</h3>
|
|
||||||
<tt>
|
|
||||||
{{^element}}
|
|
||||||
<pre>
|
|
||||||
<{{shortName}}{{#param}} {{#default}}<i>[</i>{{/default}}{{name}}="..."{{#default}}<i>]</i>{{/default}}{{/param}}>{{#usageContent}}
|
|
||||||
|
|
||||||
{{usageContent}}
|
|
||||||
{{/usageContent}}</{{shortName}}>
|
|
||||||
</pre>
|
|
||||||
{{/element}}
|
|
||||||
{{#element}}
|
|
||||||
<pre>
|
|
||||||
<{{element}} {{shortName}}{{#paramFirst}}="{{paramFirst.name}}{{/paramFirst}}">
|
|
||||||
...
|
|
||||||
</{{element}}>
|
|
||||||
</pre>
|
|
||||||
{{/element}}
|
|
||||||
</tt>
|
|
||||||
|
|
||||||
<h3>Parameters</h3>
|
|
||||||
<ul>
|
|
||||||
{{#param}}
|
|
||||||
<li><tt>{{name}}</tt> –
|
|
||||||
<tt>{{{#type}}{{type}}{{/type}}{{^type}}*{{/type}}{{#optional}}={{/optional}}}</tt>
|
|
||||||
<tt>{{#default}}[{{default}}]{{/default}}</tt>
|
|
||||||
– {{{description}}}</li>
|
|
||||||
{{/param}}
|
|
||||||
</ul>
|
|
||||||
{{{paramDescription}}}
|
|
||||||
|
|
||||||
{{#css}}
|
|
||||||
<h3>CSS</h3>
|
|
||||||
{{{css}}}
|
|
||||||
{{/css}}
|
|
||||||
|
|
||||||
{{#example}}
|
|
||||||
<h2>Example</h2>
|
|
||||||
{{{exampleDescription}}}
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
{{/example}}
|
|
||||||
{{{example}}}
|
|
||||||
{{#example}}
|
|
||||||
</doc:source>
|
|
||||||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
{{/example}}
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
|
. ~/.bashrc
|
||||||
node docs/specs.js --noColor && node docs/collect.js
|
node docs/spec/specs.js --noColor && node docs/src/gen-docs.js
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
Copyright (c) 2009 Chris Wanstrath (Ruby)
|
|
||||||
Copyright (c) 2010 Jan Lehnardt (JavaScript)
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
@ -1,344 +0,0 @@
|
||||||
/*
|
|
||||||
* CommonJS-compatible mustache.js module
|
|
||||||
*
|
|
||||||
* See http://github.com/janl/mustache.js for more info.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
mustache.js Ñ Logic-less templates in JavaScript
|
|
||||||
|
|
||||||
See http://mustache.github.com/ for more info.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var Mustache = function() {
|
|
||||||
var Renderer = function() {};
|
|
||||||
|
|
||||||
Renderer.prototype = {
|
|
||||||
otag: "{{",
|
|
||||||
ctag: "}}",
|
|
||||||
pragmas: {},
|
|
||||||
buffer: [],
|
|
||||||
pragmas_implemented: {
|
|
||||||
"IMPLICIT-ITERATOR": true
|
|
||||||
},
|
|
||||||
context: {},
|
|
||||||
|
|
||||||
render: function(template, context, partials, in_recursion) {
|
|
||||||
// reset buffer & set context
|
|
||||||
if(!in_recursion) {
|
|
||||||
this.context = context;
|
|
||||||
this.buffer = []; // TODO: make this non-lazy
|
|
||||||
}
|
|
||||||
|
|
||||||
// fail fast
|
|
||||||
if(!this.includes("", template)) {
|
|
||||||
if(in_recursion) {
|
|
||||||
return template;
|
|
||||||
} else {
|
|
||||||
this.send(template);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template = this.render_pragmas(template);
|
|
||||||
var html = this.render_section(template, context, partials);
|
|
||||||
if(in_recursion) {
|
|
||||||
return this.render_tags(html, context, partials, in_recursion);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.render_tags(html, context, partials, in_recursion);
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Sends parsed lines
|
|
||||||
*/
|
|
||||||
send: function(line) {
|
|
||||||
if(line != "") {
|
|
||||||
this.buffer.push(line);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Looks for %PRAGMAS
|
|
||||||
*/
|
|
||||||
render_pragmas: function(template) {
|
|
||||||
// no pragmas
|
|
||||||
if(!this.includes("%", template)) {
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
var that = this;
|
|
||||||
var regex = new RegExp(this.otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" +
|
|
||||||
this.ctag);
|
|
||||||
return template.replace(regex, function(match, pragma, options) {
|
|
||||||
if(!that.pragmas_implemented[pragma]) {
|
|
||||||
throw({message:
|
|
||||||
"This implementation of mustache doesn't understand the '" +
|
|
||||||
pragma + "' pragma"});
|
|
||||||
}
|
|
||||||
that.pragmas[pragma] = {};
|
|
||||||
if(options) {
|
|
||||||
var opts = options.split("=");
|
|
||||||
that.pragmas[pragma][opts[0]] = opts[1];
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
// ignore unknown pragmas silently
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Tries to find a partial in the curent scope and render it
|
|
||||||
*/
|
|
||||||
render_partial: function(name, context, partials) {
|
|
||||||
name = this.trim(name);
|
|
||||||
if(!partials || partials[name] === undefined) {
|
|
||||||
throw({message: "unknown_partial '" + name + "'"});
|
|
||||||
}
|
|
||||||
if(typeof(context[name]) != "object") {
|
|
||||||
return this.render(partials[name], context, partials, true);
|
|
||||||
}
|
|
||||||
return this.render(partials[name], context[name], partials, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Renders inverted (^) and normal (#) sections
|
|
||||||
*/
|
|
||||||
render_section: function(template, context, partials) {
|
|
||||||
if(!this.includes("#", template) && !this.includes("^", template)) {
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
|
|
||||||
var that = this;
|
|
||||||
// CSW - Added "+?" so it finds the tighest bound, not the widest
|
|
||||||
var regex = new RegExp(this.otag + "(\\^|\\#)\\s*(.+)\\s*" + this.ctag +
|
|
||||||
"\n*([\\s\\S]+?)" + this.otag + "\\/\\s*\\2\\s*" + this.ctag +
|
|
||||||
"\\s*", "mg");
|
|
||||||
|
|
||||||
// for each {{#foo}}{{/foo}} section do...
|
|
||||||
return template.replace(regex, function(match, type, name, content) {
|
|
||||||
var value = that.find(name, context);
|
|
||||||
if(type == "^") { // inverted section
|
|
||||||
if(!value || that.is_array(value) && value.length === 0) {
|
|
||||||
// false or empty list, render it
|
|
||||||
return that.render(content, context, partials, true);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
} else if(type == "#") { // normal section
|
|
||||||
if(that.is_array(value)) { // Enumerable, Let's loop!
|
|
||||||
return that.map(value, function(row) {
|
|
||||||
return that.render(content, that.create_context(row),
|
|
||||||
partials, true);
|
|
||||||
}).join("");
|
|
||||||
} else if(that.is_object(value)) { // Object, Use it as subcontext!
|
|
||||||
return that.render(content, that.create_context(value),
|
|
||||||
partials, true);
|
|
||||||
} else if(typeof value === "function") {
|
|
||||||
// higher order section
|
|
||||||
return value.call(context, content, function(text) {
|
|
||||||
return that.render(text, context, partials, true);
|
|
||||||
});
|
|
||||||
} else if(value) { // boolean section
|
|
||||||
return that.render(content, context, partials, true);
|
|
||||||
} else {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Replace {{foo}} and friends with values from our view
|
|
||||||
*/
|
|
||||||
render_tags: function(template, context, partials, in_recursion) {
|
|
||||||
// tit for tat
|
|
||||||
var that = this;
|
|
||||||
|
|
||||||
var new_regex = function() {
|
|
||||||
return new RegExp(that.otag + "(=|!|>|\\{|%)?([^\\/#\\^]+?)\\1?" +
|
|
||||||
that.ctag + "+", "g");
|
|
||||||
};
|
|
||||||
|
|
||||||
var regex = new_regex();
|
|
||||||
var tag_replace_callback = function(match, operator, name) {
|
|
||||||
switch(operator) {
|
|
||||||
case "!": // ignore comments
|
|
||||||
return "";
|
|
||||||
case "=": // set new delimiters, rebuild the replace regexp
|
|
||||||
that.set_delimiters(name);
|
|
||||||
regex = new_regex();
|
|
||||||
return "";
|
|
||||||
case ">": // render partial
|
|
||||||
return that.render_partial(name, context, partials);
|
|
||||||
case "{": // the triple mustache is unescaped
|
|
||||||
return that.find(name, context);
|
|
||||||
default: // escape the value
|
|
||||||
return that.escape(that.find(name, context));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var lines = template.split("\n");
|
|
||||||
for(var i = 0; i < lines.length; i++) {
|
|
||||||
lines[i] = lines[i].replace(regex, tag_replace_callback, this);
|
|
||||||
if(!in_recursion) {
|
|
||||||
this.send(lines[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(in_recursion) {
|
|
||||||
return lines.join("\n");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
set_delimiters: function(delimiters) {
|
|
||||||
var dels = delimiters.split(" ");
|
|
||||||
this.otag = this.escape_regex(dels[0]);
|
|
||||||
this.ctag = this.escape_regex(dels[1]);
|
|
||||||
},
|
|
||||||
|
|
||||||
escape_regex: function(text) {
|
|
||||||
// thank you Simon Willison
|
|
||||||
if(!arguments.callee.sRE) {
|
|
||||||
var specials = [
|
|
||||||
'/', '.', '*', '+', '?', '|',
|
|
||||||
'(', ')', '[', ']', '{', '}', '\\'
|
|
||||||
];
|
|
||||||
arguments.callee.sRE = new RegExp(
|
|
||||||
'(\\' + specials.join('|\\') + ')', 'g'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return text.replace(arguments.callee.sRE, '\\$1');
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
find `name` in current `context`. That is find me a value
|
|
||||||
from the view object
|
|
||||||
*/
|
|
||||||
find: function(name, context) {
|
|
||||||
name = this.trim(name);
|
|
||||||
|
|
||||||
// Checks whether a value is thruthy or false or 0
|
|
||||||
function is_kinda_truthy(bool) {
|
|
||||||
return bool === false || bool === 0 || bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = context;
|
|
||||||
var path = name.split(/\./);
|
|
||||||
for(var i = 0; i < path.length; i++) {
|
|
||||||
name = path[i];
|
|
||||||
if(value && is_kinda_truthy(value[name])) {
|
|
||||||
value = value[name];
|
|
||||||
} else if(i == 0 && is_kinda_truthy(this.context[name])) {
|
|
||||||
value = this.context[name];
|
|
||||||
} else {
|
|
||||||
value = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(typeof value === "function") {
|
|
||||||
return value.apply(context);
|
|
||||||
}
|
|
||||||
if(value !== undefined) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
// silently ignore unkown variables
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
|
|
||||||
// Utility methods
|
|
||||||
|
|
||||||
/* includes tag */
|
|
||||||
includes: function(needle, haystack) {
|
|
||||||
return haystack.indexOf(this.otag + needle) != -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Does away with nasty characters
|
|
||||||
*/
|
|
||||||
escape: function(s) {
|
|
||||||
s = String(s === null ? "" : s);
|
|
||||||
return s.replace(/&(?!\w+;)|["'<>\\]/g, function(s) {
|
|
||||||
switch(s) {
|
|
||||||
case "&": return "&";
|
|
||||||
case "\\": return "\\\\";
|
|
||||||
case '"': return '"';
|
|
||||||
case "'": return ''';
|
|
||||||
case "<": return "<";
|
|
||||||
case ">": return ">";
|
|
||||||
default: return s;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// by @langalex, support for arrays of strings
|
|
||||||
create_context: function(_context) {
|
|
||||||
if(this.is_object(_context)) {
|
|
||||||
return _context;
|
|
||||||
} else {
|
|
||||||
var iterator = ".";
|
|
||||||
if(this.pragmas["IMPLICIT-ITERATOR"]) {
|
|
||||||
iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator;
|
|
||||||
}
|
|
||||||
var ctx = {};
|
|
||||||
ctx[iterator] = _context;
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
is_object: function(a) {
|
|
||||||
return a && typeof a == "object";
|
|
||||||
},
|
|
||||||
|
|
||||||
is_array: function(a) {
|
|
||||||
return Object.prototype.toString.call(a) === '[object Array]';
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Gets rid of leading and trailing whitespace
|
|
||||||
*/
|
|
||||||
trim: function(s) {
|
|
||||||
return s.replace(/^\s*|\s*$/g, "");
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
Why, why, why? Because IE. Cry, cry cry.
|
|
||||||
*/
|
|
||||||
map: function(array, fn) {
|
|
||||||
if (typeof array.map == "function") {
|
|
||||||
return array.map(fn);
|
|
||||||
} else {
|
|
||||||
var r = [];
|
|
||||||
var l = array.length;
|
|
||||||
for(var i = 0; i < l; i++) {
|
|
||||||
r.push(fn(array[i]));
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return({
|
|
||||||
name: "mustache.js",
|
|
||||||
version: "0.3.1-dev",
|
|
||||||
|
|
||||||
/*
|
|
||||||
Turns a template and view into HTML
|
|
||||||
*/
|
|
||||||
to_html: function(template, view, partials, send_fun) {
|
|
||||||
var renderer = new Renderer();
|
|
||||||
if(send_fun) {
|
|
||||||
renderer.send = send_fun;
|
|
||||||
}
|
|
||||||
renderer.render(template, view, partials);
|
|
||||||
if(!send_fun) {
|
|
||||||
return renderer.buffer.join("\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}();
|
|
||||||
|
|
||||||
|
|
||||||
exports.name = Mustache.name;
|
|
||||||
exports.version = Mustache.version;
|
|
||||||
|
|
||||||
exports.to_html = function() {
|
|
||||||
return Mustache.to_html.apply(this, arguments);
|
|
||||||
};
|
|
||||||
|
|
@ -711,7 +711,7 @@ function concat(array1, array2, index) {
|
||||||
*/
|
*/
|
||||||
function bind(self, fn) {
|
function bind(self, fn) {
|
||||||
var curryArgs = arguments.length > 2 ? slice.call(arguments, 2, arguments.length) : [];
|
var curryArgs = arguments.length > 2 ? slice.call(arguments, 2, arguments.length) : [];
|
||||||
if (typeof fn == $function) {
|
if (typeof fn == $function && !(fn instanceof RegExp)) {
|
||||||
return curryArgs.length ? function() {
|
return curryArgs.length ? function() {
|
||||||
return arguments.length ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0, arguments.length))) : fn.apply(self, curryArgs);
|
return arguments.length ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0, arguments.length))) : fn.apply(self, curryArgs);
|
||||||
}: function() {
|
}: function() {
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,19 @@ extend(angularValidator, {
|
||||||
* Use regexp validator to restrict the input to any Regular Expression.
|
* Use regexp validator to restrict the input to any Regular Expression.
|
||||||
*
|
*
|
||||||
* @param {string} value value to validate
|
* @param {string} value value to validate
|
||||||
* @param {regexp} expression regular expression.
|
* @param {string|regexp} expression regular expression.
|
||||||
|
* @param {string=} msg error message to display.
|
||||||
* @css ng-validation-error
|
* @css ng-validation-error
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* <script> var ssn = /^\d\d\d-\d\d-\d\d\d\d$/; </script>
|
* <script> function Cntl(){
|
||||||
|
* this.ssnRegExp = /^\d\d\d-\d\d-\d\d\d\d$/;
|
||||||
|
* }
|
||||||
|
* </script>
|
||||||
* Enter valid SSN:
|
* Enter valid SSN:
|
||||||
* <input name="ssn" value="123-45-6789" ng:validate="regexp:$window.ssn" >
|
* <div ng:controller="Cntl">
|
||||||
|
* <input name="ssn" value="123-45-6789" ng:validate="regexp:ssnRegExp" >
|
||||||
|
* </div>
|
||||||
*
|
*
|
||||||
* @scenario
|
* @scenario
|
||||||
* it('should invalidate non ssn', function(){
|
* it('should invalidate non ssn', function(){
|
||||||
|
|
|
||||||
|
|
@ -554,7 +554,8 @@ angularWidget('option', function(){
|
||||||
* (e.g. ng:include won't work for file:// access).
|
* (e.g. ng:include won't work for file:// access).
|
||||||
*
|
*
|
||||||
* @param {string} src expression evaluating to URL.
|
* @param {string} src expression evaluating to URL.
|
||||||
* @param {Scope=} [scope=new_child_scope] expression evaluating to angular.scope
|
* @param {Scope=} [scope=new_child_scope] optional expression which evaluates to an
|
||||||
|
* instance of angular.scope to set the HTML fragment to.
|
||||||
* @param {string=} onload Expression to evaluate when a new partial is loaded.
|
* @param {string=} onload Expression to evaluate when a new partial is loaded.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue