1
+ 'use strict' ;
2
+
3
+ var dom = require ( './src/dom' ) ;
4
+ var ngdoc = require ( './src/ngdoc' ) ;
5
+ var reader = require ( './src/reader' ) ;
6
+
7
+ var fs = require ( 'fs' ) ;
8
+ var vfs = require ( 'vinyl-fs' ) ;
9
+ var through2 = require ( 'through2' ) ;
10
+ var extend = require ( 'extend' ) ;
11
+ var _ = require ( 'lodash' ) ;
12
+ var gutil = require ( 'gulp-util' ) ;
13
+ var File = gutil . File ;
14
+ var PluginError = gutil . PluginError ;
15
+ var path = require ( 'path' ) ;
16
+ var StringDecoder = require ( 'string_decoder' ) . StringDecoder ;
17
+ var decoder = new StringDecoder ( 'utf8' ) ;
18
+ var merge = require ( 'merge-stream' ) ;
19
+
20
+ var setup = { sections : { } , pages : [ ] , apis : { } } ;
21
+ var fakeDest = '_FAKE_DEST_' ;
22
+ var templates = path . resolve ( __dirname , 'src/templates' ) ;
23
+ var bowerComponents = path . resolve ( __dirname , 'bower_components' ) ;
24
+
25
+ function copyTemplates ( ) {
26
+ return function ( ) {
27
+ return vfs . src ( [ '**/*' , '!**/*.tmpl' ] , { cwd : templates } ) ;
28
+ } ;
29
+ }
30
+
31
+ function streamFile ( src , dir , dest , name ) {
32
+ return function ( ) {
33
+ return vfs . src ( src ) . pipe ( through2 . obj ( function ( file , enc , callback ) {
34
+ name = name === undefined ? file . path . split ( '/' ) . pop ( ) : name ;
35
+ this . push ( new File ( {
36
+ base : dest ,
37
+ cwd : dest ,
38
+ path : path . join ( dest , dir , name ) ,
39
+ contents : file . contents
40
+ } ) ) ;
41
+ callback ( null ) ;
42
+ } ) ) ;
43
+ } ;
44
+ }
45
+
46
+ function sections ( sects ) {
47
+ return merge ( _ . map ( sects , function ( data , key ) {
48
+ if ( data instanceof String ) {
49
+ data = { glob : data } ;
50
+ }
51
+ if ( ! data . hasOwnProperty ( 'glob' ) ) {
52
+ throw new PluginError ( 'gulp-ngdocs' , 'Invalid sections, please refer to the documentation.' ) ;
53
+ }
54
+ if ( ! data . hasOwnProperty ( 'title' ) ) {
55
+ data . title = key ;
56
+ }
57
+ if ( ! data . hasOwnProperty ( 'api' ) ) {
58
+ data . api = true ;
59
+ }
60
+ var glob = data . glob ;
61
+ var opts = data . globOpts ;
62
+ setup . sections [ key ] = data . title ;
63
+ setup . apis [ key ] = data . api ;
64
+ return vfs . src ( glob , opts )
65
+ . pipe ( through2 . obj (
66
+ function ( file , enc , cb ) {
67
+ file . section = key ;
68
+ this . push ( file ) ;
69
+ cb ( null ) ;
70
+ }
71
+ ) ) ;
72
+ } ) ) ;
73
+ }
74
+
75
+ function process ( opts ) {
76
+
77
+ var options = extend ( {
78
+ startPage : '/api' ,
79
+ scripts : [ ] ,
80
+ styles : [ ] ,
81
+ title : 'API Documentation' ,
82
+ html5Mode : true ,
83
+ editExample : true ,
84
+ navTemplate : false ,
85
+ navContent : '' ,
86
+ navTemplateData : { }
87
+ } , opts ) ;
88
+ var defaultSection = 'api' ;
89
+ var defaultScripts = [
90
+ path . join ( bowerComponents , 'angular/angular.min.js' ) ,
91
+ path . join ( bowerComponents , 'angular/angular.min.js.map' ) ,
92
+ path . join ( bowerComponents , 'angular-animate/angular-animate.min.js' ) ,
93
+ path . join ( bowerComponents , 'marked/lib/marked.js' ) ,
94
+ path . join ( bowerComponents , 'google-code-prettify/src/prettify.js' )
95
+ ] ;
96
+
97
+ function writeSetup ( ) {
98
+ var options = setup . __options ,
99
+ content , data = {
100
+ scripts : options . scripts ,
101
+ styles : options . styles ,
102
+ sections : _ . keys ( setup . sections ) . join ( '|' ) ,
103
+ discussions : options . discussions ,
104
+ analytics : options . analytics ,
105
+ navContent : options . navContent ,
106
+ title : options . title ,
107
+ image : options . image ,
108
+ titleLink : options . titleLink ,
109
+ imageLink : options . imageLink ,
110
+ bestMatch : options . bestMatch ,
111
+ deferLoad : ! ! options . deferLoad
112
+ } ;
113
+
114
+ // create index.html
115
+ content = fs . readFileSync ( path . resolve ( templates , 'index.tmpl' ) , 'utf8' ) ;
116
+ content = _ . template ( content , data ) ;
117
+ docsStream . push ( new File ( {
118
+ base : fakeDest ,
119
+ cwd : fakeDest ,
120
+ path : path . join ( fakeDest , 'index.html' ) ,
121
+ contents : new Buffer ( content , 'utf8' )
122
+ } ) ) ;
123
+ // create setup file
124
+ setup . html5Mode = options . html5Mode ;
125
+ setup . editExample = options . editExample ;
126
+ setup . startPage = options . startPage ;
127
+ setup . discussions = options . discussions ;
128
+ setup . scripts = _ . map ( options . scripts , function ( url ) { return path . basename ( url ) ; } ) ;
129
+ docsStream . push ( new File ( {
130
+ base : fakeDest ,
131
+ cwd : fakeDest ,
132
+ path : setup . __file ,
133
+ contents : new Buffer ( 'NG_DOCS=' + JSON . stringify ( setup , null , 2 ) + ';' , 'utf8' )
134
+ } ) ) ;
135
+ }
136
+
137
+ function transformFunction ( file , enc , callback ) {
138
+ if ( file . isNull ( ) ) {
139
+ callback ( null ) ;
140
+ return ; // ignore
141
+ }
142
+ if ( file . isStream ( ) ) {
143
+ callback ( new gutil . PluginError ( 'gulp-ngdocs' , 'Streaming not supported' ) ) ;
144
+ return ;
145
+ }
146
+ if ( file . contents ) {
147
+ if ( ! merged ) {
148
+ merged = merge ( fstreams . map ( function ( f ) {
149
+ var s = f ( ) ;
150
+ s . on ( 'data' , function ( file ) {
151
+ docsStream . push ( file ) ;
152
+ } ) ;
153
+ return s ;
154
+ } ) ) ;
155
+
156
+ merged . on ( 'end' , function ( ) {
157
+ mergedEnded = true ;
158
+ if ( docsStreamEndCb ) {
159
+ docsStreamEndCb ( null ) ;
160
+ }
161
+ } ) ;
162
+ }
163
+ var content = decoder . write ( file . contents ) ;
164
+ if ( ! file . section ) {
165
+ file . section = defaultSection ;
166
+ }
167
+ reader . process ( content , file . path , file . section , options ) ;
168
+ }
169
+ callback ( null ) ;
170
+ }
171
+
172
+ function flushFunction ( cb ) {
173
+ if ( merged ) {
174
+ docsStreamEndCb = cb ;
175
+ ngdoc . merge ( reader . docs ) ;
176
+ reader . docs . forEach ( function ( doc ) {
177
+ // this hack is here because on OSX angular.module and angular.Module map to the same file.
178
+ var id = doc . id . replace ( 'angular.Module' , 'angular.IModule' ) . replace ( ':' , '.' ) ,
179
+ file = path . join ( fakeDest , 'partials' , doc . section , id + '.html' ) ,
180
+ dir = path . join ( fakeDest , 'partials' , doc . section ) ;
181
+ docsStream . push ( new File ( {
182
+ base : fakeDest ,
183
+ cwd : fakeDest ,
184
+ path : file ,
185
+ contents : new Buffer ( doc . html ( ) , 'utf8' )
186
+ } ) ) ;
187
+ } ) ;
188
+
189
+ ngdoc . checkBrokenLinks ( reader . docs , setup . apis , options ) ;
190
+
191
+ setup . pages = _ . union ( setup . pages , ngdoc . metadata ( reader . docs ) ) ;
192
+
193
+ writeSetup ( this ) ;
194
+
195
+ if ( mergedEnded ) {
196
+ docsStreamEndCb ( null ) ;
197
+ docsStreamEndCb = false ;
198
+ }
199
+ } else {
200
+ cb ( null ) ;
201
+ }
202
+ }
203
+
204
+ var fstreams = [ ] ;
205
+ var docsStream = through2 . obj ( transformFunction , flushFunction ) ;
206
+ var merged = false ;
207
+ var mergedEnded = false ;
208
+ var docsStreamEndCb = false ;
209
+ if ( options . navTemplate ) {
210
+ options . navContent = _ . template (
211
+ fs . readFileSync ( options . navTemplate , 'utf8' ) ,
212
+ options . navTemplateData ) ;
213
+ }
214
+
215
+ if ( options . image ) {
216
+ if ( ! / ^ ( ( h t t p s ? : ) ? \/ \/ | \. \. \/ ) / . test ( options . image ) ) {
217
+ fstreams . push ( streamFile ( options . image , 'img' , fakeDest ) ) ;
218
+ options . image = 'img/' + options . image ;
219
+ }
220
+ }
221
+
222
+ options . scripts = options . scripts . map ( function ( script ) {
223
+ fstreams . push ( streamFile ( script , 'js' , fakeDest ) ) ;
224
+ return path . join ( 'js' , script . split ( '/' ) . pop ( ) ) ;
225
+ } ) ;
226
+
227
+ defaultScripts . forEach ( function ( script , i ) {
228
+ fstreams . push ( streamFile ( script , 'js' , fakeDest ) ) ;
229
+ options . scripts . splice ( i , 0 , path . join ( 'js' , script . split ( '/' ) . pop ( ) ) ) ;
230
+ } ) ;
231
+
232
+ options . styles = _ . map ( options . styles , function ( file ) {
233
+ if ( / ^ ( ( h t t p s ? : ) ? \/ \/ | \. \. \/ ) / . test ( file ) ) {
234
+ return file ;
235
+ } else {
236
+ fstreams . push ( streamFile ( file , 'img' , fakeDest ) ) ;
237
+ return 'css/' + file . split ( '/' ) . pop ( ) ;
238
+ }
239
+ } ) ;
240
+
241
+ fstreams . push ( copyTemplates ( templates ) ) ;
242
+ setup . __file = path . join ( fakeDest , 'js/docs-setup.js' ) ;
243
+ setup . __options = options ;
244
+
245
+ reader . docs = [ ] ;
246
+ if ( Object . keys ( setup . sections ) . length === 0 ) {
247
+ setup . sections [ defaultSection ] = options . title ;
248
+ setup . apis [ defaultSection ] = true ;
249
+ }
250
+
251
+ return docsStream ;
252
+ }
253
+
254
+ module . exports = {
255
+ process : process ,
256
+ sections : sections
257
+ } ;
0 commit comments