@@ -8,6 +8,7 @@ var root = {};
8
8
var stack = [ root ] ;
9
9
var depth = 0 ;
10
10
var current = root ;
11
+ var state = null ;
11
12
12
13
function doJSON ( input , cb ) {
13
14
var lexed = marked . lexer ( input ) ;
@@ -16,15 +17,16 @@ function doJSON(input, cb) {
16
17
var text = tok . text ;
17
18
18
19
// <!-- type = module -->
19
- // This is for cases where the markdown itself is lacking.
20
+ // This is for cases where the markdown semantic structure is lacking.
20
21
var meta ;
21
22
if ( type === 'paragraph' &&
22
23
( meta = text . match ( / ^ < ! - - ( [ ^ = ] + ) = ( [ ^ \- ] ) + - - > \n * $ / ) ) ) {
23
24
current [ meta [ 1 ] . trim ( ) ] = meta [ 2 ] . trim ( ) ;
24
25
return
25
26
}
26
27
27
- if ( type === 'heading' ) {
28
+ if ( type === 'heading' &&
29
+ ! text . trim ( ) . toLowerCase ( ) . match ( / ^ e x a m p l e / ) ) {
28
30
if ( Math . abs ( tok . depth - depth ) > 1 ) {
29
31
return cb ( new Error ( 'Inappropriate heading level\n' +
30
32
JSON . stringify ( tok ) ) ) ;
@@ -47,10 +49,55 @@ function doJSON(input, cb) {
47
49
current = newSection ( tok ) ;
48
50
depth = tok . depth ;
49
51
stack . push ( current ) ;
52
+ state = 'AFTERHEADING' ;
53
+ return ;
54
+ } // heading
55
+
56
+ // Immediately after a heading, we can expect the following
57
+ //
58
+ // { type: 'code', text: 'Stability: ...' },
59
+ //
60
+ // a list: starting with list_start, ending with list_end,
61
+ // maybe containing other nested lists in each item.
62
+ //
63
+ // If one of these isnt' found, then anything that comes between
64
+ // here and the next heading should be parsed as the desc.
65
+ var stability
66
+ if ( state === 'AFTERHEADING' ) {
67
+ if ( type === 'code' &&
68
+ ( stability = text . match ( / ^ S t a b i l i t y : ( [ 0 - 5 ] ) (?: \s * - \s * ) ? ( .* ) $ / ) ) ) {
69
+ current . stability = parseInt ( stability [ 1 ] , 10 ) ;
70
+ current . stabilityText = stability [ 2 ] . trim ( ) ;
71
+ return ;
72
+ } else if ( type === 'list_start' && ! tok . ordered ) {
73
+ state = 'AFTERHEADING_LIST' ;
74
+ current . list = current . list || [ ] ;
75
+ current . list . push ( tok ) ;
76
+ current . list . level = 1 ;
77
+ } else {
78
+ current . desc = current . desc || [ ] ;
79
+ current . desc . push ( tok ) ;
80
+ state = 'DESC' ;
81
+ }
50
82
return ;
51
83
}
52
84
53
- // { type: 'code', text: 'Stability: 1 - Experimental' },
85
+ if ( state === 'AFTERHEADING_LIST' ) {
86
+ current . list . push ( tok ) ;
87
+ if ( type === 'list_start' ) {
88
+ current . list . level ++ ;
89
+ } else if ( type === 'list_end' ) {
90
+ current . list . level -- ;
91
+ }
92
+ if ( current . list . level === 0 ) {
93
+ state = 'AFTERHEADING' ;
94
+ processList ( current ) ;
95
+ }
96
+ return ;
97
+ }
98
+
99
+ current . desc = current . desc || [ ] ;
100
+ current . desc . push ( tok ) ;
54
101
55
102
} ) ;
56
103
@@ -63,6 +110,192 @@ function doJSON(input, cb) {
63
110
}
64
111
65
112
113
+ // go from something like this:
114
+ // [ { type: 'list_item_start' },
115
+ // { type: 'text',
116
+ // text: '`settings` Object, Optional' },
117
+ // { type: 'list_start', ordered: false },
118
+ // { type: 'list_item_start' },
119
+ // { type: 'text',
120
+ // text: 'exec: String, file path to worker file. Default: `__filename`' },
121
+ // { type: 'list_item_end' },
122
+ // { type: 'list_item_start' },
123
+ // { type: 'text',
124
+ // text: 'args: Array, string arguments passed to worker.' },
125
+ // { type: 'text',
126
+ // text: 'Default: `process.argv.slice(2)`' },
127
+ // { type: 'list_item_end' },
128
+ // { type: 'list_item_start' },
129
+ // { type: 'text',
130
+ // text: 'silent: Boolean, whether or not to send output to parent\'s stdio.' },
131
+ // { type: 'text', text: 'Default: `false`' },
132
+ // { type: 'space' },
133
+ // { type: 'list_item_end' },
134
+ // { type: 'list_end' },
135
+ // { type: 'list_item_end' },
136
+ // { type: 'list_end' } ]
137
+ // to something like:
138
+ // [ { name: 'settings',
139
+ // type: 'object',
140
+ // optional: true,
141
+ // settings:
142
+ // [ { name: 'exec',
143
+ // type: 'string',
144
+ // desc: 'file path to worker file',
145
+ // default: '__filename' },
146
+ // { name: 'args',
147
+ // type: 'array',
148
+ // default: 'process.argv.slice(2)',
149
+ // desc: 'string arguments passed to worker.' },
150
+ // { name: 'silent',
151
+ // type: 'boolean',
152
+ // desc: 'whether or not to send output to parent\'s stdio.',
153
+ // default: 'false' } ] } ]
154
+
155
+ function processList ( section ) {
156
+ var list = section . list ;
157
+ var values = [ ] ;
158
+ var current ;
159
+ var stack = [ ] ;
160
+
161
+ // for now, *just* build the heirarchical list
162
+ list . forEach ( function ( tok ) {
163
+ var type = tok . type ;
164
+ if ( type === 'space' ) return ;
165
+ if ( type === 'list_item_start' ) {
166
+ if ( ! current ) {
167
+ var n = { } ;
168
+ values . push ( n ) ;
169
+ current = n ;
170
+ } else {
171
+ current . options = current . options || [ ] ;
172
+ stack . push ( current ) ;
173
+ var n = { } ;
174
+ current . options . push ( n ) ;
175
+ current = n ;
176
+ }
177
+ return ;
178
+ } else if ( type === 'list_item_end' ) {
179
+ if ( ! current ) {
180
+ throw new Error ( 'invalid list - end without current item\n' +
181
+ JSON . stringify ( tok ) + '\n' +
182
+ JSON . stringify ( list ) ) ;
183
+ }
184
+ current = stack . pop ( ) ;
185
+ } else if ( type === 'text' ) {
186
+ if ( ! current ) {
187
+ throw new Error ( 'invalid list - text without current item\n' +
188
+ JSON . stringify ( tok ) + '\n' +
189
+ JSON . stringify ( list ) ) ;
190
+ }
191
+ current . textRaw = current . textRaw || '' ;
192
+ current . textRaw += tok . text + ' ' ;
193
+ }
194
+ } ) ;
195
+
196
+ // shove the name in there for properties, since they are always
197
+ // just going to be the value etc.
198
+ if ( section . type === 'property' ) {
199
+ values [ 0 ] . textRaw = '`' + section . name + '` ' + values [ 0 ] . textRaw ;
200
+ }
201
+
202
+ // now pull the actual values out of the text bits.
203
+ values . forEach ( parseListItem ) ;
204
+
205
+ // Now figure out what this list actually means.
206
+ // depending on the section type, the list could be different things.
207
+
208
+ switch ( section . type ) {
209
+ case 'method' :
210
+ // each item is an argument, unless the name is 'return',
211
+ // in which case it's the return value.
212
+ section . params = values . filter ( function ( v ) {
213
+ if ( v . name === 'return' ) {
214
+ section . return = v ;
215
+ return false ;
216
+ }
217
+ return true ;
218
+ } ) ;
219
+ break ;
220
+
221
+ case 'property' :
222
+ // there should be only one item, which is the value.
223
+ // copy the data up to the section.
224
+ var value = values [ 0 ] ;
225
+ delete value . name ;
226
+ section . typeof = value . type ;
227
+ delete value . type ;
228
+ Object . keys ( value ) . forEach ( function ( k ) {
229
+ section [ k ] = value [ k ] ;
230
+ } ) ;
231
+ break ;
232
+
233
+ case 'event' :
234
+ // event: each item is an argument.
235
+ section . params = values ;
236
+ break ;
237
+ }
238
+
239
+ // section.listParsed = values;
240
+ delete section . list ;
241
+
242
+ }
243
+
244
+
245
+ function parseListItem ( item ) {
246
+ if ( item . options ) item . options . forEach ( parseListItem ) ;
247
+ if ( ! item . textRaw ) return ;
248
+
249
+ // the goal here is to find the name, type, default, and optional.
250
+ // anything left over is 'desc'
251
+ var text = item . textRaw . trim ( ) ;
252
+ text = text . replace ( / ^ ( A r g u m e n t | P a r a m ) s ? \s * : ? \s * / i, '' ) ;
253
+
254
+ text = text . replace ( / ^ , / , '' ) . trim ( ) ;
255
+ var retExpr = / ^ R e t u r n s ? \s * : ? \s * / i;
256
+ var ret = text . match ( retExpr ) ;
257
+ if ( ret ) {
258
+ item . name = 'return' ;
259
+ text = text . replace ( retExpr , '' ) ;
260
+ } else {
261
+ var nameExpr = / ^ [ ' ` " ] ? ( [ ^ ' ` " : ] + ) [ ' ` " ] ? \s * : ? \s * / ;
262
+ var name = text . match ( nameExpr ) ;
263
+ if ( name ) {
264
+ item . name = name [ 1 ] ;
265
+ text = text . replace ( nameExpr , '' ) ;
266
+ }
267
+ }
268
+
269
+ text = text . replace ( / ^ , / , '' ) . trim ( ) ;
270
+ var defaultExpr = / d e f a u l t \s * [: = ] ? \s * [ ' " ` ] ? ( [ ^ , ' " ` ] * ) [ ' " ` ] ? / i;
271
+ var def = text . match ( defaultExpr ) ;
272
+ if ( def ) {
273
+ item . default = def [ 1 ] ;
274
+ text = text . replace ( defaultExpr , '' ) ;
275
+ }
276
+
277
+ text = text . replace ( / ^ , / , '' ) . trim ( ) ;
278
+ var typeExpr =
279
+ / ^ ( (?: [ a - z A - Z ] * ) ? o b j e c t | s t r i n g | b o o l (?: e a n ) ? | r e g e x p ? | n u l l | f u n c t i o n ) / i;
280
+ var type = text . match ( typeExpr ) ;
281
+ if ( type ) {
282
+ item . type = type [ 1 ] ;
283
+ text = text . replace ( typeExpr , '' ) ;
284
+ }
285
+
286
+ text = text . replace ( / ^ , / , '' ) . trim ( ) ;
287
+ var optExpr = / ^ O p t i o n a l \. | (?: , ) ? O p t i o n a l $ / ;
288
+ var optional = text . match ( optExpr ) ;
289
+ if ( optional ) {
290
+ item . optional = true ;
291
+ text = text . replace ( optExpr , '' ) ;
292
+ }
293
+
294
+ text = text . trim ( ) ;
295
+ if ( text ) item . desc = text ;
296
+ }
297
+
298
+
66
299
function finishSection ( section , parent ) {
67
300
if ( ! section || ! parent ) {
68
301
throw new Error ( 'Invalid finishSection call\n' +
@@ -72,9 +305,28 @@ function finishSection(section, parent) {
72
305
73
306
if ( ! section . type ) {
74
307
section . type = 'module' ;
308
+ section . displayName = section . name ;
75
309
section . name = section . name . toLowerCase ( ) ;
76
310
}
77
311
312
+ if ( section . desc ) {
313
+ section . desc = marked . parser ( section . desc ) ;
314
+ }
315
+
316
+ if ( section . list ) {
317
+ processList ( section ) ;
318
+ }
319
+
320
+ // properties are a bit special.
321
+ // their "type" is the type of object, not "property"
322
+ if ( section . properties ) {
323
+ section . properties . forEach ( function ( p ) {
324
+ if ( p . typeof ) p . type = p . typeof ;
325
+ else delete p . type ;
326
+ delete p . typeof ;
327
+ } ) ;
328
+ }
329
+
78
330
var plur ;
79
331
if ( section . type . slice ( - 1 ) === 's' ) {
80
332
plur = section . type + 'es' ;
@@ -99,7 +351,7 @@ var methExpr = /^(?:method:?\s*)?[^\.]+\.([^ \.\(\)]+)\([^\)]*\)\s*?$/i;
99
351
function newSection ( tok ) {
100
352
var section = { } ;
101
353
// infer the type from the text.
102
- var text = tok . text ;
354
+ var text = section . textRaw = tok . text ;
103
355
if ( text . match ( eventExpr ) ) {
104
356
section . type = 'event' ;
105
357
section . name = text . replace ( eventExpr , '$1' ) ;
0 commit comments