comment-parser 0.3.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/.eslintrc +11 -0
- package/.travis.yml +2 -4
- package/CHANGELOG.md +10 -1
- package/README.md +35 -16
- package/index.js +31 -34
- package/package.json +11 -6
- package/parser.js +172 -257
- package/parsers.js +100 -0
- package/tests/custom-parsers.spec.js +90 -99
- package/tests/files.spec.js +45 -46
- package/tests/fixtures/sample.js +15 -15
- package/tests/parse.js +18 -0
- package/tests/parse.spec.js +731 -513
- package/.jshintrc +0 -11
package/parser.js
CHANGED
|
@@ -1,131 +1,43 @@
|
|
|
1
1
|
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
var
|
|
5
|
-
var
|
|
2
|
+
var PARSERS = require('./parsers')
|
|
3
|
+
|
|
4
|
+
var MARKER_START = '/**'
|
|
5
|
+
var MARKER_START_SKIP = '/***'
|
|
6
|
+
var MARKER_END = '*/'
|
|
6
7
|
|
|
7
8
|
/* ------- util functions ------- */
|
|
8
9
|
|
|
9
|
-
function merge(/* ...objects */) {
|
|
10
|
-
var k, obj
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
for (k in obj) { if (obj.hasOwnProperty(k)) {
|
|
14
|
-
res[k] = obj[k];
|
|
15
|
-
}}
|
|
16
|
-
}
|
|
17
|
-
return res;
|
|
18
|
-
}
|
|
10
|
+
function merge (/* ...objects */) {
|
|
11
|
+
var k, obj
|
|
12
|
+
var res = {}
|
|
13
|
+
var objs = Array.prototype.slice.call(arguments)
|
|
19
14
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
15
|
+
for (var i = 0, l = objs.length; i < l; i++) {
|
|
16
|
+
obj = objs[i]
|
|
17
|
+
for (k in obj) {
|
|
18
|
+
if (obj.hasOwnProperty(k)) {
|
|
19
|
+
res[k] = obj[k]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
27
22
|
}
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function skipws(str) {
|
|
32
|
-
var i = 0;
|
|
33
|
-
do {
|
|
34
|
-
if (str[i] !== ' ') { return i; }
|
|
35
|
-
} while (++i < str.length);
|
|
36
|
-
return i;
|
|
23
|
+
return res
|
|
37
24
|
}
|
|
38
25
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
var
|
|
42
|
-
|
|
43
|
-
PARSERS.parse_tag = function parse_tag(str) {
|
|
44
|
-
var result = str.match(/^\s*@(\S+)/);
|
|
45
|
-
|
|
46
|
-
if (!result) { throw new Error('Invalid `@tag`, missing @ symbol'); }
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
source : result[0],
|
|
50
|
-
data : {tag: result[1]}
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
PARSERS.parse_type = function parse_type(str, data) {
|
|
55
|
-
if (data.errors && data.errors.length) { return null; }
|
|
56
|
-
|
|
57
|
-
var pos = skipws(str);
|
|
58
|
-
var res = '';
|
|
59
|
-
var curlies = 0;
|
|
26
|
+
function find (list, filter) {
|
|
27
|
+
var k
|
|
28
|
+
var i = list.length
|
|
29
|
+
var matchs = true
|
|
60
30
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
pos ++;
|
|
67
|
-
if (curlies === 0) { break; }
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (curlies !== 0) { throw new Error('Invalid `{type}`, unpaired curlies'); }
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
source : str.slice(0, pos),
|
|
74
|
-
data : {type: res.slice(1, -1)}
|
|
75
|
-
};
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
PARSERS.parse_name = function parse_name(str, data) {
|
|
79
|
-
if (data.errors && data.errors.length) { return null; }
|
|
80
|
-
|
|
81
|
-
var pos = skipws(str);
|
|
82
|
-
var name = '';
|
|
83
|
-
var brackets = 0;
|
|
84
|
-
|
|
85
|
-
while (pos < str.length) {
|
|
86
|
-
brackets += (str[pos] === '[' ? 1 : (str[pos] === ']' ? -1 : 0));
|
|
87
|
-
name += str[pos];
|
|
88
|
-
pos ++;
|
|
89
|
-
if (brackets === 0 && /\s/.test(str[pos])) { break; }
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (brackets !== 0) { throw new Error('Invalid `name`, unpaired brackets'); }
|
|
93
|
-
|
|
94
|
-
var res = {name: name, optional: false};
|
|
95
|
-
|
|
96
|
-
if (name[0] === '[' && name[name.length - 1] === ']') {
|
|
97
|
-
res.optional = true;
|
|
98
|
-
name = name.slice(1, -1);
|
|
99
|
-
|
|
100
|
-
if (name.indexOf('=') !== -1) {
|
|
101
|
-
var parts = name.split('=');
|
|
102
|
-
name = parts[0];
|
|
103
|
-
res.default = parts[1].replace(/^(["'])(.+)(\1)$/, '$2');
|
|
31
|
+
while (i--) {
|
|
32
|
+
for (k in filter) {
|
|
33
|
+
if (filter.hasOwnProperty(k)) {
|
|
34
|
+
matchs = (filter[k] === list[i][k]) && matchs
|
|
35
|
+
}
|
|
104
36
|
}
|
|
37
|
+
if (matchs) { return list[i] }
|
|
105
38
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return {
|
|
110
|
-
source : str.slice(0, pos),
|
|
111
|
-
data : res
|
|
112
|
-
};
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
PARSERS.parse_description = function parse_description(str, data) {
|
|
116
|
-
if (data.errors && data.errors.length) { return null; }
|
|
117
|
-
|
|
118
|
-
var result = str.match(/^\s+([^$]+)?/);
|
|
119
|
-
|
|
120
|
-
if (result) {
|
|
121
|
-
return {
|
|
122
|
-
source : result[0],
|
|
123
|
-
data : {description: result[1] === undefined ? '' : result[1]}
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return null;
|
|
128
|
-
};
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
129
41
|
|
|
130
42
|
/* ------- parsing ------- */
|
|
131
43
|
|
|
@@ -135,219 +47,222 @@ PARSERS.parse_description = function parse_description(str, data) {
|
|
|
135
47
|
* @param {Array[function]} parsers Array of parsers to be applied to the source
|
|
136
48
|
* @returns {object} parsed tag node
|
|
137
49
|
*/
|
|
138
|
-
function parse_tag(str, parsers) {
|
|
139
|
-
if (typeof str !== 'string' || str[0] !== '@') { return null
|
|
50
|
+
function parse_tag (str, parsers) {
|
|
51
|
+
if (typeof str !== 'string' || str[0] !== '@') { return null }
|
|
140
52
|
|
|
141
|
-
var data = parsers.reduce(function(state, parser) {
|
|
142
|
-
var result
|
|
53
|
+
var data = parsers.reduce(function (state, parser) {
|
|
54
|
+
var result
|
|
143
55
|
|
|
144
56
|
try {
|
|
145
|
-
result = parser(state.source, merge({}, state.data))
|
|
146
|
-
// console.log('----------------');
|
|
147
|
-
// console.log(parser.name, ':', result);
|
|
57
|
+
result = parser(state.source, merge({}, state.data))
|
|
148
58
|
} catch (err) {
|
|
149
|
-
// console.warn('Parser "%s" failed: %s', parser.name, err.message);
|
|
150
59
|
state.data.errors = (state.data.errors || [])
|
|
151
|
-
.concat(parser.name + ': ' + err.message)
|
|
60
|
+
.concat(parser.name + ': ' + err.message)
|
|
152
61
|
}
|
|
153
62
|
|
|
154
63
|
if (result) {
|
|
155
|
-
state.source = state.source.slice(result.source.length)
|
|
156
|
-
state.data
|
|
64
|
+
state.source = state.source.slice(result.source.length)
|
|
65
|
+
state.data = merge(state.data, result.data)
|
|
157
66
|
}
|
|
158
67
|
|
|
159
|
-
return state
|
|
68
|
+
return state
|
|
160
69
|
}, {
|
|
161
|
-
source
|
|
162
|
-
data
|
|
163
|
-
}).data
|
|
70
|
+
source: str,
|
|
71
|
+
data: {}
|
|
72
|
+
}).data
|
|
164
73
|
|
|
165
|
-
data.optional
|
|
166
|
-
data.type
|
|
167
|
-
data.name
|
|
168
|
-
data.description = data.description === undefined ? '' : data.description
|
|
74
|
+
data.optional = !!data.optional
|
|
75
|
+
data.type = data.type === undefined ? '' : data.type
|
|
76
|
+
data.name = data.name === undefined ? '' : data.name
|
|
77
|
+
data.description = data.description === undefined ? '' : data.description
|
|
169
78
|
|
|
170
|
-
return data
|
|
79
|
+
return data
|
|
171
80
|
}
|
|
172
81
|
|
|
173
82
|
/**
|
|
174
83
|
* Parses comment block (array of String lines)
|
|
175
84
|
*/
|
|
176
|
-
function parse_block(source, opts) {
|
|
85
|
+
function parse_block (source, opts) {
|
|
86
|
+
var trim = opts.trim
|
|
87
|
+
? function trim (s) { return s.trim() }
|
|
88
|
+
: function trim (s) { return s }
|
|
177
89
|
|
|
178
90
|
var source_str = source
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
91
|
+
.map(function (line) { return trim(line.source) })
|
|
92
|
+
.join('\n')
|
|
93
|
+
|
|
94
|
+
source_str = trim(source_str)
|
|
182
95
|
|
|
183
|
-
var start = source[0].number
|
|
96
|
+
var start = source[0].number
|
|
184
97
|
|
|
185
98
|
// merge source lines into tags
|
|
186
99
|
// we assume tag starts with "@"
|
|
187
100
|
source = source
|
|
188
|
-
.reduce(function(tags, line) {
|
|
189
|
-
line.source = line.source
|
|
101
|
+
.reduce(function (tags, line) {
|
|
102
|
+
line.source = trim(line.source)
|
|
190
103
|
|
|
191
|
-
if (line.source.match(
|
|
192
|
-
tags.push({source: [line.source], line: line.number})
|
|
104
|
+
if (line.source.match(/^\s*@(\w+)/)) {
|
|
105
|
+
tags.push({source: [line.source], line: line.number})
|
|
193
106
|
} else {
|
|
194
|
-
var tag = tags[tags.length - 1]
|
|
195
|
-
tag.source.push(line.source)
|
|
107
|
+
var tag = tags[tags.length - 1]
|
|
108
|
+
tag.source.push(line.source)
|
|
196
109
|
}
|
|
197
110
|
|
|
198
|
-
return tags
|
|
111
|
+
return tags
|
|
199
112
|
}, [{source: []}])
|
|
200
|
-
.map(function(tag) {
|
|
201
|
-
tag.source = tag.source.join('\n')
|
|
202
|
-
return tag
|
|
203
|
-
})
|
|
113
|
+
.map(function (tag) {
|
|
114
|
+
tag.source = trim(tag.source.join('\n'))
|
|
115
|
+
return tag
|
|
116
|
+
})
|
|
204
117
|
|
|
205
118
|
// Block description
|
|
206
|
-
var description = source.shift()
|
|
119
|
+
var description = source.shift()
|
|
207
120
|
|
|
208
121
|
// skip if no descriptions and no tags
|
|
209
|
-
if (description.source === '' && source.length === 0) {
|
|
210
|
-
return null
|
|
122
|
+
if (description.source === '' && source.length === 0) {
|
|
123
|
+
return null
|
|
211
124
|
}
|
|
212
125
|
|
|
213
|
-
var tags = source.reduce(function(tags, tag) {
|
|
214
|
-
var tag_node = parse_tag(tag.source, opts.parsers
|
|
215
|
-
PARSERS.parse_tag,
|
|
216
|
-
PARSERS.parse_type,
|
|
217
|
-
PARSERS.parse_name,
|
|
218
|
-
PARSERS.parse_description
|
|
219
|
-
]);
|
|
126
|
+
var tags = source.reduce(function (tags, tag) {
|
|
127
|
+
var tag_node = parse_tag(tag.source, opts.parsers)
|
|
220
128
|
|
|
221
|
-
if (!tag_node) { return tags
|
|
129
|
+
if (!tag_node) { return tags }
|
|
222
130
|
|
|
223
|
-
tag_node.line
|
|
224
|
-
tag_node.source = tag.source
|
|
131
|
+
tag_node.line = tag.line
|
|
132
|
+
tag_node.source = tag.source
|
|
225
133
|
|
|
226
134
|
if (opts.dotted_names && tag_node.name.indexOf('.') !== -1) {
|
|
227
|
-
var parent_name
|
|
228
|
-
var parent_tag
|
|
229
|
-
var parent_tags = tags
|
|
230
|
-
var parts = tag_node.name.split('.')
|
|
135
|
+
var parent_name
|
|
136
|
+
var parent_tag
|
|
137
|
+
var parent_tags = tags
|
|
138
|
+
var parts = tag_node.name.split('.')
|
|
231
139
|
|
|
232
140
|
while (parts.length > 1) {
|
|
233
|
-
parent_name = parts.shift()
|
|
234
|
-
parent_tag
|
|
235
|
-
tag
|
|
236
|
-
name
|
|
237
|
-
})
|
|
141
|
+
parent_name = parts.shift()
|
|
142
|
+
parent_tag = find(parent_tags, {
|
|
143
|
+
tag: tag_node.tag,
|
|
144
|
+
name: parent_name
|
|
145
|
+
})
|
|
238
146
|
|
|
239
147
|
if (!parent_tag) {
|
|
240
148
|
parent_tag = {
|
|
241
|
-
tag
|
|
242
|
-
line
|
|
243
|
-
name
|
|
244
|
-
type
|
|
245
|
-
description
|
|
246
|
-
}
|
|
247
|
-
parent_tags.push(parent_tag)
|
|
149
|
+
tag: tag_node.tag,
|
|
150
|
+
line: Number(tag_node.line),
|
|
151
|
+
name: parent_name,
|
|
152
|
+
type: '',
|
|
153
|
+
description: ''
|
|
154
|
+
}
|
|
155
|
+
parent_tags.push(parent_tag)
|
|
248
156
|
}
|
|
249
157
|
|
|
250
|
-
parent_tag.tags = parent_tag.tags || []
|
|
251
|
-
parent_tags = parent_tag.tags
|
|
158
|
+
parent_tag.tags = parent_tag.tags || []
|
|
159
|
+
parent_tags = parent_tag.tags
|
|
252
160
|
}
|
|
253
161
|
|
|
254
|
-
tag_node.name = parts[0]
|
|
255
|
-
parent_tags.push(tag_node)
|
|
256
|
-
return tags
|
|
162
|
+
tag_node.name = parts[0]
|
|
163
|
+
parent_tags.push(tag_node)
|
|
164
|
+
return tags
|
|
257
165
|
}
|
|
258
166
|
|
|
259
|
-
return tags.concat(tag_node)
|
|
260
|
-
}, [])
|
|
261
|
-
|
|
262
|
-
// console.log('-----------');
|
|
263
|
-
// console.log(description, tags);
|
|
167
|
+
return tags.concat(tag_node)
|
|
168
|
+
}, [])
|
|
264
169
|
|
|
265
170
|
return {
|
|
266
|
-
tags
|
|
267
|
-
line
|
|
268
|
-
description
|
|
269
|
-
source
|
|
270
|
-
}
|
|
171
|
+
tags: tags,
|
|
172
|
+
line: start,
|
|
173
|
+
description: description.source,
|
|
174
|
+
source: source_str
|
|
175
|
+
}
|
|
271
176
|
}
|
|
272
177
|
|
|
273
178
|
/**
|
|
274
179
|
* Produces `extract` function with internal state initialized
|
|
275
180
|
*/
|
|
276
|
-
function mkextract(opts) {
|
|
277
|
-
|
|
278
|
-
var
|
|
279
|
-
var number = 0
|
|
181
|
+
function mkextract (opts) {
|
|
182
|
+
var chunk = null
|
|
183
|
+
var indent = 0
|
|
184
|
+
var number = 0
|
|
185
|
+
|
|
186
|
+
opts = merge({}, {
|
|
187
|
+
trim: true,
|
|
188
|
+
dotted_names: false,
|
|
189
|
+
parsers: [
|
|
190
|
+
PARSERS.parse_tag,
|
|
191
|
+
PARSERS.parse_type,
|
|
192
|
+
PARSERS.parse_name,
|
|
193
|
+
PARSERS.parse_description
|
|
194
|
+
]
|
|
195
|
+
}, opts || {})
|
|
280
196
|
|
|
281
197
|
/**
|
|
282
|
-
*
|
|
283
|
-
*
|
|
198
|
+
* Read lines until they make a block
|
|
199
|
+
* Return parsed block once fullfilled or null otherwise
|
|
284
200
|
*/
|
|
285
|
-
return function extract(line) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
number: number}], opts);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
number += 1;
|
|
298
|
-
|
|
299
|
-
// if start of comment
|
|
300
|
-
// then init the chunk
|
|
301
|
-
if (line.match(RE_COMMENT_START)) {
|
|
302
|
-
// console.log('line (1)', line);
|
|
303
|
-
// console.log(' clean:', line.replace(RE_COMMENT_START, ''));
|
|
304
|
-
chunk = [{source: line.replace(RE_COMMENT_START, ''), number: number - 1}];
|
|
305
|
-
return null;
|
|
201
|
+
return function extract (line) {
|
|
202
|
+
var result = null
|
|
203
|
+
var startPos = line.indexOf(MARKER_START)
|
|
204
|
+
var endPos = line.indexOf(MARKER_END)
|
|
205
|
+
|
|
206
|
+
// if open marker detected and it's not skip one
|
|
207
|
+
if (startPos !== -1 && line.indexOf(MARKER_START_SKIP) !== startPos) {
|
|
208
|
+
chunk = []
|
|
209
|
+
indent = startPos + MARKER_START.length
|
|
306
210
|
}
|
|
307
211
|
|
|
308
|
-
// if
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
212
|
+
// if we are on middle of comment block
|
|
213
|
+
if (chunk) {
|
|
214
|
+
var lineStart = indent
|
|
215
|
+
|
|
216
|
+
// figure out if we slice from opening marker pos
|
|
217
|
+
// or line start is shifted to the left
|
|
218
|
+
var nonSpaceChar = line.match(/\S/)
|
|
219
|
+
|
|
220
|
+
// skip for the first line starting with /** (fresh chunk)
|
|
221
|
+
// it always has the right indentation
|
|
222
|
+
if (chunk.length > 0 && nonSpaceChar) {
|
|
223
|
+
if (nonSpaceChar[0] === '*') {
|
|
224
|
+
lineStart = nonSpaceChar.index + 2
|
|
225
|
+
} else if (nonSpaceChar.index < indent) {
|
|
226
|
+
lineStart = nonSpaceChar.index
|
|
227
|
+
}
|
|
228
|
+
}
|
|
316
229
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
230
|
+
// slice the line until end or until closing marker start
|
|
231
|
+
chunk.push({
|
|
232
|
+
number: number,
|
|
233
|
+
source: line.slice(lineStart, endPos === -1 ? line.length : endPos)
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
// finalize block if end marker detected
|
|
237
|
+
if (endPos !== -1) {
|
|
238
|
+
result = parse_block(chunk, opts)
|
|
239
|
+
chunk = null
|
|
240
|
+
indent = 0
|
|
241
|
+
}
|
|
324
242
|
}
|
|
325
243
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
};
|
|
244
|
+
number += 1
|
|
245
|
+
return result
|
|
246
|
+
}
|
|
330
247
|
}
|
|
331
248
|
|
|
332
249
|
/* ------- Public API ------- */
|
|
333
250
|
|
|
334
|
-
module.exports = function parse(source, opts) {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
var
|
|
338
|
-
var
|
|
339
|
-
var extract = mkextract(opts);
|
|
340
|
-
var lines = source.split(/\n/);
|
|
251
|
+
module.exports = function parse (source, opts) {
|
|
252
|
+
var block
|
|
253
|
+
var blocks = []
|
|
254
|
+
var extract = mkextract(opts)
|
|
255
|
+
var lines = source.split(/\n/)
|
|
341
256
|
|
|
342
|
-
|
|
343
|
-
block = extract(lines.shift())
|
|
257
|
+
for (var i = 0, l = lines.length; i < l; i++) {
|
|
258
|
+
block = extract(lines.shift())
|
|
344
259
|
if (block) {
|
|
345
|
-
blocks.push(block)
|
|
260
|
+
blocks.push(block)
|
|
346
261
|
}
|
|
347
262
|
}
|
|
348
263
|
|
|
349
|
-
return blocks
|
|
350
|
-
}
|
|
264
|
+
return blocks
|
|
265
|
+
}
|
|
351
266
|
|
|
352
|
-
module.exports.PARSERS = PARSERS
|
|
353
|
-
module.exports.mkextract = mkextract
|
|
267
|
+
module.exports.PARSERS = PARSERS
|
|
268
|
+
module.exports.mkextract = mkextract
|
package/parsers.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
function skipws (str) {
|
|
2
|
+
var i = 0
|
|
3
|
+
do {
|
|
4
|
+
if (str[i] !== ' ') { return i }
|
|
5
|
+
} while (++i < str.length)
|
|
6
|
+
return i
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/* ------- default parsers ------- */
|
|
10
|
+
|
|
11
|
+
var PARSERS = {}
|
|
12
|
+
|
|
13
|
+
PARSERS.parse_tag = function parse_tag (str) {
|
|
14
|
+
var result = str.match(/^\s*@(\S+)/)
|
|
15
|
+
|
|
16
|
+
if (!result) { throw new Error('Invalid `@tag`, missing @ symbol') }
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
source: result[0],
|
|
20
|
+
data: {tag: result[1]}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
PARSERS.parse_type = function parse_type (str, data) {
|
|
25
|
+
if (data.errors && data.errors.length) { return null }
|
|
26
|
+
|
|
27
|
+
var pos = skipws(str)
|
|
28
|
+
var res = ''
|
|
29
|
+
var curlies = 0
|
|
30
|
+
|
|
31
|
+
if (str[pos] !== '{') { return null }
|
|
32
|
+
|
|
33
|
+
while (pos < str.length) {
|
|
34
|
+
curlies += (str[pos] === '{' ? 1 : (str[pos] === '}' ? -1 : 0))
|
|
35
|
+
res += str[pos]
|
|
36
|
+
pos++
|
|
37
|
+
if (curlies === 0) { break }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (curlies !== 0) { throw new Error('Invalid `{type}`, unpaired curlies') }
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
source: str.slice(0, pos),
|
|
44
|
+
data: {type: res.slice(1, -1)}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
PARSERS.parse_name = function parse_name (str, data) {
|
|
49
|
+
if (data.errors && data.errors.length) { return null }
|
|
50
|
+
|
|
51
|
+
var pos = skipws(str)
|
|
52
|
+
var name = ''
|
|
53
|
+
var brackets = 0
|
|
54
|
+
|
|
55
|
+
while (pos < str.length) {
|
|
56
|
+
brackets += (str[pos] === '[' ? 1 : (str[pos] === ']' ? -1 : 0))
|
|
57
|
+
name += str[pos]
|
|
58
|
+
pos++
|
|
59
|
+
if (brackets === 0 && /\s/.test(str[pos])) { break }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (brackets !== 0) { throw new Error('Invalid `name`, unpaired brackets') }
|
|
63
|
+
|
|
64
|
+
var res = {name: name, optional: false}
|
|
65
|
+
|
|
66
|
+
if (name[0] === '[' && name[name.length - 1] === ']') {
|
|
67
|
+
res.optional = true
|
|
68
|
+
name = name.slice(1, -1)
|
|
69
|
+
|
|
70
|
+
if (name.indexOf('=') !== -1) {
|
|
71
|
+
var parts = name.split('=')
|
|
72
|
+
name = parts[0]
|
|
73
|
+
res.default = parts[1].replace(/^(["'])(.+)(\1)$/, '$2')
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
res.name = name
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
source: str.slice(0, pos),
|
|
81
|
+
data: res
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
PARSERS.parse_description = function parse_description (str, data) {
|
|
86
|
+
if (data.errors && data.errors.length) { return null }
|
|
87
|
+
|
|
88
|
+
var result = str.match(/^\s+((.|\s)+)?/)
|
|
89
|
+
|
|
90
|
+
if (result) {
|
|
91
|
+
return {
|
|
92
|
+
source: result[0],
|
|
93
|
+
data: {description: result[1] === undefined ? '' : result[1]}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = PARSERS
|