@ui5/webcomponents-tools 1.24.0-rc.4 → 2.0.0-rc.0

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.
@@ -1,2468 +0,0 @@
1
- /*
2
- * JSDoc3 plugin for UI5 documentation generation.
3
- *
4
- * (c) Copyright 2009-2018 SAP SE or an SAP affiliate company.
5
- * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
6
- */
7
-
8
- /* global require, exports, env */
9
- /* eslint strict: [2, "global"]*/
10
-
11
- 'use strict';
12
-
13
- /**
14
- * UI5 plugin for JSDoc3 (3.3.0-alpha5)
15
- *
16
- * The plugin adds the following SAPUI5 specific tag definitions to JSDoc3
17
- *
18
- * disclaimer
19
- *
20
- * experimental
21
- *
22
- * final
23
- *
24
- * interface
25
- *
26
- * implements
27
- *
28
- * slot
29
- *
30
- * appenddocs
31
- *
32
- * tagname
33
- *
34
- * native
35
- *
36
- * noattribute
37
- *
38
- * formEvents
39
- *
40
- * formProperty
41
- *
42
- * allowPreventDefault
43
- *
44
- * It furthermore listens to the following JSDoc3 events to implement additional functionality
45
- *
46
- * parseBegin
47
- * to create short names for all file that are to be parsed
48
- *
49
- * fileBegin
50
- * to write some line to the log (kind of a progress indicator)
51
- *
52
- * jsdocCommentFound
53
- * to pre-process comments, empty lines are used as paragraph markers
54
- * a default visibility is added, legacy tag combinations used in JSdoc2 are converted to JSDoc3 conventions
55
- *
56
- * newDoclet
57
- *
58
- * parseComplete
59
- * remove undocumented/ignored/private doclets or duplicate doclets
60
- *
61
- *
62
- * Last but not least, it implements an astNodeVisitor to detect UI5 specific "extend" calls and to create
63
- * documentation for the properties, aggregations etc. that are created with the "extend" call.
64
- *
65
- * @module plugins/sapui5-jsdoc
66
- */
67
-
68
- /* imports */
69
- var Syntax = require('jsdoc/src/syntax').Syntax;
70
- var Doclet = require('jsdoc/doclet').Doclet;
71
- var fs = require('jsdoc/fs');
72
- var path = require('jsdoc/path');
73
- var pluginConfig = (env.conf && env.conf.templates && env.conf.templates.ui5) || {};
74
-
75
- /* ---- global vars---- */
76
-
77
- /**
78
- * Potential path prefixes.
79
- *
80
- * Will be determined in the handler for the parseBegin event
81
- */
82
- var pathPrefixes = [];
83
-
84
- /**
85
- * Prefixes of the UI5 unified resource name for the source files is NOT part of the file name.
86
- * (e.g. when a common root namespaces has been omitted from the folder structure).
87
- *
88
- * The prefix will be prepended to all resource names.
89
- */
90
- var resourceNamePrefixes = [];
91
-
92
- /**
93
- * A UI5 specific unique Id for all doclets.
94
- */
95
- var docletUid = 0;
96
-
97
- var currentProgram;
98
-
99
- /**
100
- * Information about the current module.
101
- *
102
- * The info object is created in the 'fileBegin' event handler and the 'resource' and 'module' properties
103
- * are derived from the filename provided by the event. The derived information is only correct, when the
104
- * resource name prefix is known for the directory from which a source is loaded (prefixes can be configured
105
- * via sapui5.resourceNamePrefixes, for UI5 libraries it is empty by default).
106
- *
107
- * During AST visiting, the 'name' property and the 'localeNames' map will be filled.
108
- * 'name' will be the name of the class defined by the module (assuming that there is only one).
109
- * 'localNames' will contain information objects for each parameter of an AMD Factory function and for
110
- * all shortcut variables that are defined top-level in the module factory function (e.g. something like
111
- * var ButtonDesign = coreLibrary.ButtonDesign; ).
112
- * An info object for a local name either can have a 'value' property (simple, constant value) or it can
113
- * have a 'module' and optionally a 'path' value. In that case, the local name represents an AMD
114
- * module import or a shortcut derived from such an import.
115
- *
116
- * See {@link getREsolvedObjectName} how the knowledge about locale names is used.
117
- *
118
- * @type {{name:string,resource:string,module:string,localName:Object<string,object>}}
119
- */
120
- var currentModule;
121
-
122
- var currentSource;
123
-
124
- /**
125
- * Cached UI5 metadata for encountered UI5 classes.
126
- *
127
- * The metadata is collected from the 'metadata' property of 'extend' calls. It is stored
128
- * in this map keyed by the name of the class (as defined in the first parameter of the extend call).
129
- * Only after all files have been parsed, the collected information can be associated with the
130
- * corresponding JSDoc doclet (e.g. with the class documentation).
131
- */
132
- var classInfos = Object.create(null);
133
-
134
- /**
135
- *
136
- */
137
- var typeInfos = Object.create(null);
138
-
139
- /**
140
- * Cached designtime info for encountered sources.
141
- *
142
- * The designtime information is collected only for files named '*.designtime.js'.
143
- * It is stored in this map keyed by the corresponding module name (e.g. 'sap/m/designtime/Button.designtime').
144
- * Only after all files have been parsed, the collected information can be associated with runtime metadata
145
- * that refers to that designtime module name.
146
- */
147
- var designtimeInfos = Object.create(null);
148
-
149
- /* ---- private functions ---- */
150
-
151
- function ui5data(doclet) {
152
- return doclet.__ui5 || (doclet.__ui5 = { id: ++docletUid });
153
- }
154
-
155
- var pendingMessageHeader;
156
-
157
- function msgHeader(str) {
158
- pendingMessageHeader = str;
159
- }
160
-
161
- function debug() {
162
- if ( env.opts.debug ) {
163
- console.log.apply(console, arguments);
164
- }
165
- }
166
-
167
- function info() {
168
- if ( env.opts.verbose || env.opts.debug ) {
169
- if ( pendingMessageHeader ) {
170
- console.log("");
171
- pendingMessageHeader = null;
172
- }
173
- console.log.apply(console, arguments);
174
- }
175
- }
176
-
177
- function warning(msg) {
178
- if ( pendingMessageHeader ) {
179
- if ( !env.opts.verbose && !env.opts.debug ) {
180
- console.log(pendingMessageHeader);
181
- } else {
182
- console.log("");
183
- }
184
- pendingMessageHeader = null;
185
- }
186
- var args = Array.prototype.slice.apply(arguments);
187
- // args[0] = "**** warning: " + args[0]; // TODO: fix warnings. For the moment disable them
188
- console.log.apply(console, args);
189
- }
190
-
191
- function error(msg) {
192
- if ( pendingMessageHeader && !env.opts.verbose && !env.opts.debug ) {
193
- if ( !env.opts.verbose && !env.opts.debug ) {
194
- console.log(pendingMessageHeader);
195
- } else {
196
- console.log("");
197
- }
198
- pendingMessageHeader = null;
199
- }
200
- var args = Array.prototype.slice.apply(arguments);
201
- args[0] = "**** error: " + args[0];
202
- // console.log.apply(console, args); // TODO: fix warnings. For the moment disable them
203
- }
204
-
205
- //---- path handling ---------------------------------------------------------
206
-
207
- function ensureEndingSlash(path) {
208
- path = path || '';
209
- return path && path.slice(-1) !== '/' ? path + '/' : path;
210
- }
211
-
212
- function getRelativePath(filename) {
213
- var relative = path.resolve(filename);
214
- for ( var i = 0; i < pathPrefixes.length; i++ ) {
215
- if ( relative.indexOf(pathPrefixes[i]) === 0 ) {
216
- relative = relative.slice(pathPrefixes[i].length);
217
- break;
218
- }
219
- }
220
- return relative.replace(/\\/g, '/');
221
- }
222
-
223
- function getResourceName(filename) {
224
- var resource = path.resolve(filename);
225
- for ( var i = 0; i < pathPrefixes.length; i++ ) {
226
- if ( resource.indexOf(pathPrefixes[i]) === 0 ) {
227
- resource = resourceNamePrefixes[i] + resource.slice(pathPrefixes[i].length);
228
- break;
229
- }
230
- }
231
- return resource.replace(/\\/g, '/');
232
- }
233
-
234
- function getModuleName(resource) {
235
- return resource.replace(/\.js$/,'');
236
- }
237
-
238
- /*
239
- * resolves relative AMD module identifiers relative to a given base name
240
- */
241
- function resolveModuleName(base, name) {
242
- var stack = base.split('/');
243
- stack.pop();
244
- name.split('/').forEach(function(segment, i) {
245
- if ( segment == '..' ) {
246
- stack.pop();
247
- } else if ( segment === '.' ) {
248
- // ignore
249
- } else {
250
- if ( i === 0 ) {
251
- stack = [];
252
- }
253
- stack.push(segment);
254
- }
255
- });
256
- return stack.join('/');
257
- }
258
-
259
- // ---- AMD handling
260
-
261
- function analyzeModuleDefinition(node) {
262
- var args = node.arguments;
263
- var arg = 0;
264
- if ( arg < args.length
265
- && args[arg].type === Syntax.Literal && typeof args[arg].value === 'string' ) {
266
- warning("module explicitly defined a module name '" + args[arg].value + "'");
267
- currentModule.name = args[arg].value;
268
- arg++;
269
- }
270
- if ( arg < args.length && args[arg].type === Syntax.ArrayExpression ) {
271
- currentModule.dependencies = convertValue(args[arg], "string[]");
272
- arg++;
273
- }
274
- if ( arg < args.length && args[arg].type === Syntax.FunctionExpression ) {
275
- currentModule.factory = args[arg];
276
- arg++;
277
- }
278
- if ( currentModule.dependencies && currentModule.factory ) {
279
- for ( var i = 0; i < currentModule.dependencies.length && i < currentModule.factory.params.length; i++ ) {
280
- var name = currentModule.factory.params[i].name;
281
- var module = resolveModuleName(currentModule.module, currentModule.dependencies[i]);
282
- debug(" import " + name + " from '" + module + "'");
283
- currentModule.localNames[name] = {
284
- module: module
285
- // no (or empty) path
286
- };
287
- }
288
- }
289
- if ( currentModule.factory ) {
290
- collectShortcuts(currentModule.factory.body);
291
- }
292
- }
293
-
294
- /**
295
- * Searches the given body for variable declarations that can be evaluated statically,
296
- * either because they refer to known AMD modukle imports (e.g. shortcut varialbes)
297
- * or because they have a (design time) constant value.
298
- *
299
- * @param {ASTNode} body
300
- */
301
- function collectShortcuts(body) {
302
-
303
- function checkAssignment(name, valueNode) {
304
- if ( valueNode.type === Syntax.Literal ) {
305
- currentModule.localNames[name] = {
306
- value: valueNode.value
307
- };
308
- debug("compile time constant found ", name, valueNode.value);
309
- } else if ( valueNode.type === Syntax.MemberExpression ) {
310
- var _import = getLeftmostName(valueNode);
311
- var local = _import && currentModule.localNames[_import];
312
- if ( typeof local === 'object' && local.module ) {
313
- currentModule.localNames[name] = {
314
- module: local.module,
315
- path: getObjectName(valueNode).split('.').slice(1).join('.') // TODO chaining if local has path
316
- };
317
- debug(" found local shortcut: ", name, currentModule.localNames[name]);
318
- }
319
- } else if ( isRequireSyncCall(valueNode) || isProbingRequireCall(valueNode) ) {
320
- if ( valueNode.arguments[0]
321
- && valueNode.arguments[0].type === Syntax.Literal
322
- && typeof valueNode.arguments[0].value === 'string' ) {
323
- currentModule.localNames[name] = {
324
- module: valueNode.arguments[0].value
325
- // no (or empty) path
326
- };
327
- debug(" found local import: %s = %s('%s')", name, valueNode.callee.property.name, valueNode.arguments[0].value);
328
- }
329
- } else if ( isExtendCall(valueNode) ) {
330
- currentModule.localNames[name] = {
331
- class: valueNode.arguments[0].value
332
- // no (or empty) path
333
- };
334
- debug(" found local class definition: %s = .extend('%s', ...)", name, valueNode.arguments[0].value);
335
- }
336
- }
337
-
338
- if ( body.type === Syntax.BlockStatement ) {
339
- body.body.forEach(function ( stmt ) {
340
- // console.log(stmt);
341
- if ( stmt.type === Syntax.VariableDeclaration ) {
342
- stmt.declarations.forEach(function(decl) {
343
- if ( decl.init ) {
344
- checkAssignment(decl.id.name, decl.init);
345
- }
346
- })
347
- } else if ( stmt.type === Syntax.ExpressionStatement
348
- && stmt.expression.type === Syntax.AssignmentExpression
349
- && stmt.expression.left.type === Syntax.Identifier ) {
350
- checkAssignment(stmt.expression.left.name, stmt.expression.right);
351
- }
352
- });
353
- }
354
- }
355
-
356
- // ---- text handling ---------------------------------------------------------
357
-
358
- var rPlural = /(children|ies|ves|oes|ses|ches|shes|xes|s)$/i;
359
- var mSingular = {'children' : -3, 'ies' : 'y', 'ves' : 'f', 'oes' : -2, 'ses' : -2, 'ches' : -2, 'shes' : -2, 'xes' : -2, 's' : -1 };
360
-
361
- function guessSingularName(sPluralName) {
362
- return sPluralName.replace(rPlural, function($,sPlural) {
363
- var vRepl = mSingular[sPlural.toLowerCase()];
364
- return typeof vRepl === "string" ? vRepl : sPlural.slice(0,vRepl);
365
- });
366
- }
367
-
368
- /**
369
- * Creates a map of property values from an AST 'object literal' node.
370
- *
371
- * The values in the map are again AST 'property' nodes (representing key/value pairs).
372
- * It would be more convenient to just return the values, but the property node is needed
373
- * to find the corresponding (preceding) documentation comment.
374
- *
375
- * @param node
376
- * @param defaultKey
377
- * @returns {Map<string,Property>}
378
- */
379
- function createPropertyMap(node, defaultKey) {
380
-
381
- var result;
382
-
383
- if ( node != null ) {
384
-
385
- // if, instead of an object literal only a literal is given and there is a defaultKey, then wrap the literal in a map
386
- if ( node.type === Syntax.Literal && defaultKey != null ) {
387
- result = {};
388
- result[defaultKey] = { type: Syntax.Property, value: node };
389
- return result;
390
- }
391
-
392
- if ( node.type != Syntax.ObjectExpression ) {
393
- // something went wrong, it's not an object literal
394
- error("not an object literal:" + node.type + ":" + node.value);
395
- // console.log(node.toSource());
396
- return undefined;
397
- }
398
-
399
- // invariant: node.type == Syntax.ObjectExpression
400
- result = {};
401
- for (var i = 0; i < node.properties.length; i++) {
402
- var prop = node.properties[i];
403
- var name;
404
- //console.log("objectproperty " + prop.type);
405
- if ( prop.key.type === Syntax.Identifier ) {
406
- name = prop.key.name;
407
- } else if ( prop.key.type === Syntax.Literal ) {
408
- name = String(prop.key.value);
409
- } else {
410
- name = prop.key.toSource();
411
- }
412
- //console.log("objectproperty " + prop.type + ":" + name);
413
- result[name] = prop;
414
- }
415
- }
416
- return result;
417
- }
418
-
419
- function isExtendCall(node) {
420
-
421
- return (
422
- node
423
- && node.type === Syntax.CallExpression
424
- && node.callee.type === Syntax.MemberExpression
425
- && node.callee.property.type === Syntax.Identifier
426
- && node.callee.property.name === 'extend'
427
- && node.arguments.length >= 2
428
- && node.arguments[0].type === Syntax.Literal
429
- && typeof node.arguments[0].value === "string"
430
- && node.arguments[1].type === Syntax.ObjectExpression
431
- );
432
-
433
- }
434
-
435
- function isSapUiDefineCall(node) {
436
-
437
- return (
438
- node
439
- && node.type === Syntax.CallExpression
440
- && node.callee.type === Syntax.MemberExpression
441
- && node.callee.object.type === Syntax.MemberExpression
442
- && node.callee.object.object.type === Syntax.Identifier
443
- && node.callee.object.object.name === 'sap'
444
- && node.callee.object.property.type === Syntax.Identifier
445
- && node.callee.object.property.name === 'ui'
446
- && node.callee.property.type === Syntax.Identifier
447
- && node.callee.property.name === 'define'
448
- );
449
-
450
- }
451
-
452
- function isCreateDataTypeCall(node) {
453
- return (
454
- node
455
- && node.type === Syntax.CallExpression
456
- && node.callee.type === Syntax.MemberExpression
457
- && /^(sap\.ui\.base\.)?DataType$/.test(getObjectName(node.callee.object))
458
- && node.callee.property.type === Syntax.Identifier
459
- && node.callee.property.name === 'createType'
460
- );
461
- }
462
-
463
- function isRequireSyncCall(node) {
464
- return (
465
- node
466
- && node.type === Syntax.CallExpression
467
- && node.callee.type === Syntax.MemberExpression
468
- && node.callee.object.type === Syntax.MemberExpression
469
- && node.callee.object.object.type === Syntax.Identifier
470
- && node.callee.object.object.name === 'sap'
471
- && node.callee.object.property.type === Syntax.Identifier
472
- && node.callee.object.property.name === 'ui'
473
- && node.callee.property.type === Syntax.Identifier
474
- && node.callee.property.name === 'requireSync'
475
- );
476
- }
477
-
478
- function isProbingRequireCall(node) {
479
- return (
480
- node
481
- && node.type === Syntax.CallExpression
482
- && node.callee.type === Syntax.MemberExpression
483
- && node.callee.object.type === Syntax.MemberExpression
484
- && node.callee.object.object.type === Syntax.Identifier
485
- && node.callee.object.object.name === 'sap'
486
- && node.callee.object.property.type === Syntax.Identifier
487
- && node.callee.object.property.name === 'ui'
488
- && node.callee.property.type === Syntax.Identifier
489
- && node.callee.property.name === 'require'
490
- && node.arguments.length === 1
491
- && node.arguments[0].type === Syntax.Literal
492
- && typeof node.arguments[0].value === 'string' // TODO generalize to statically analyzable constants
493
- );
494
- }
495
-
496
- function getObjectName(node) {
497
- if ( node.type === Syntax.MemberExpression && !node.computed && node.property.type === Syntax.Identifier ) {
498
- var prefix = getObjectName(node.object);
499
- return prefix ? prefix + "." + node.property.name : null;
500
- } else if ( node.type === Syntax.Identifier ) {
501
- return /* scope[node.name] ? scope[node.name] : */ node.name;
502
- } else {
503
- return null;
504
- }
505
- }
506
-
507
- /*
508
- * Checks whether the node is a qualified name (a.b.c) and if so,
509
- * returns the leftmost identifier a
510
- */
511
- function getLeftmostName(node) {
512
- while ( node.type === Syntax.MemberExpression ) {
513
- node = node.object;
514
- }
515
- if ( node.type === Syntax.Identifier ) {
516
- return node.name;
517
- }
518
- // return undefined;
519
- }
520
-
521
- function getResolvedObjectName(node) {
522
- var name = getObjectName(node);
523
- var _import = getLeftmostName(node);
524
- var local = _import && currentModule.localNames[_import];
525
- if ( local && (local.class || local.module) ) {
526
- var resolvedName;
527
- if ( local.class ) {
528
- resolvedName = local.class;
529
- } else {
530
- resolvedName = local.module.replace(/\//g, ".").replace(/\.library$/, "");
531
- if ( local.path ) {
532
- resolvedName = resolvedName + "." + local.path;
533
- }
534
- }
535
- if ( name.indexOf('.') > 0 ) {
536
- resolvedName = resolvedName + name.slice(name.indexOf('.'));
537
- }
538
- debug("resolved " + name + " to " + resolvedName);
539
- return resolvedName;
540
- }
541
- return name;
542
- }
543
-
544
- function convertValue(node, type, propertyName) {
545
-
546
- var value;
547
-
548
- if ( node.type === Syntax.Literal ) {
549
-
550
- // 'string' or number or true or false
551
- return node.value;
552
-
553
- } else if ( node.type === Syntax.UnaryExpression
554
- && node.prefix
555
- && node.argument.type === Syntax.Literal
556
- && typeof node.argument.value === 'number'
557
- && ( node.operator === '-' || node.operator === '+' )) {
558
-
559
- // -n or +n
560
- value = node.argument.value;
561
- return node.operator === '-' ? -value : value;
562
-
563
- } else if ( node.type === Syntax.MemberExpression && type ) {
564
-
565
- // enum value (a.b.c)
566
- value = getResolvedObjectName(node);
567
- if ( value.indexOf(type + ".") === 0 ) {
568
- // starts with fully qualified enum name -> cut off name
569
- return value.slice(type.length + 1);
570
- // } else if ( value.indexOf(type.split(".").slice(-1)[0] + ".") === 0 ) {
571
- // // unqualified name might be a local name (just a guess - would need static code analysis for proper solution)
572
- // return value.slice(type.split(".").slice(-1)[0].length + 1);
573
- } else {
574
- warning("did not understand default value '%s'%s, falling back to source", value, propertyName ? " of property '" + propertyName + "'" : "");
575
- return value;
576
- }
577
-
578
- } else if ( node.type === Syntax.Identifier ) {
579
- if ( node.name === 'undefined') {
580
- // undefined
581
- return undefined;
582
- }
583
- var local = currentModule.localNames[node.name];
584
- if ( typeof local === 'object' && 'value' in local ) {
585
- // TODO check type
586
- return local.value;
587
- }
588
- } else if ( node.type === Syntax.ArrayExpression ) {
589
-
590
- if ( node.elements.length === 0 ) {
591
- // empty array literal
592
- return "[]"; // TODO return this string or an empty array
593
- }
594
-
595
- if ( type && type.slice(-2) === "[]" ) {
596
- var componentType = type.slice(0,-2);
597
- return node.elements.map( function(elem) {
598
- return convertValue(elem, componentType, propertyName);
599
- });
600
- }
601
-
602
- } else if ( node.type === Syntax.ObjectExpression ) {
603
-
604
- if ( node.properties.length === 0 && (type === 'object' || type === 'any') ) {
605
- return {};
606
- }
607
-
608
- }
609
-
610
- value = '???';
611
- if ( currentSource && node.range ) {
612
- value = currentSource.slice( node.range[0], node.range[1] );
613
- }
614
- error("unexpected type of default value (type='%s', source='%s')%s, falling back to '%s'", node.type, node.toString(), propertyName ? " of property '" + propertyName + "'" : "", value);
615
- return value;
616
- }
617
-
618
- function convertStringArray(node) {
619
- if ( node.type !== Syntax.ArrayExpression ) {
620
- throw new Error("not an array");
621
- }
622
- var result = [];
623
- for ( var i = 0; i < node.elements.length; i++ ) {
624
- if ( node.elements[i].type !== Syntax.Literal || typeof node.elements[i].value !== 'string' ) {
625
- throw new Error("not a string literal");
626
- }
627
- result.push(node.elements[i].value);
628
- }
629
- // console.log(result);
630
- return result;
631
- }
632
-
633
- function convertDragDropValue(node, cardinality) {
634
- var mDragDropValue;
635
- var mDefaults = { draggable : false, droppable: false };
636
-
637
- if ( node.type === Syntax.ObjectExpression ) {
638
- mDragDropValue = (node.properties || []).reduce(function(oObject, oProperty) {
639
- var sKey = convertValue(oProperty.key);
640
- if (mDefaults.hasOwnProperty(sKey)) {
641
- oObject[sKey] = convertValue(oProperty.value);
642
- }
643
- return oObject;
644
- }, {});
645
- } else if ( node.type === Syntax.Literal ) {
646
- mDragDropValue = {
647
- draggable : node.value,
648
- droppable : node.value
649
- };
650
- } else {
651
- throw new Error("not a valid dnd node");
652
- }
653
-
654
- return Object.assign(mDefaults, mDragDropValue);
655
- }
656
-
657
- function collectClassInfo(extendCall, classDoclet) {
658
-
659
- var baseType;
660
- if ( classDoclet && classDoclet.augments && classDoclet.augments.length === 1 ) {
661
- baseType = classDoclet.augments[0];
662
- }
663
- if ( extendCall.callee.type === Syntax.MemberExpression ) {
664
- var baseCandidate = getResolvedObjectName(extendCall.callee.object);
665
- if ( baseCandidate && baseType == null ) {
666
- baseType = baseCandidate;
667
- } else if ( baseCandidate !== baseType ) {
668
- error("documented base type '" + baseType + "' doesn't match technical base type '" + baseCandidate + "'");
669
- }
670
- }
671
-
672
- var oClassInfo = {
673
- name : extendCall.arguments[0].value,
674
- baseType : baseType,
675
- interfaces : [],
676
- doc : classDoclet && classDoclet.description,
677
- deprecation : classDoclet && classDoclet.deprecated,
678
- since : classDoclet && classDoclet.since,
679
- experimental : classDoclet && classDoclet.experimental,
680
- specialSettings : {},
681
- properties : {},
682
- aggregations : {},
683
- associations : {},
684
- events : {},
685
- methods : {},
686
- annotations : {},
687
- designtime: false
688
- };
689
-
690
- function upper(n) {
691
- return n.slice(0,1).toUpperCase() + n.slice(1);
692
- }
693
-
694
- function each(node, defaultKey, callback) {
695
- var map,n,settings,doclet;
696
-
697
- map = node && createPropertyMap(node.value);
698
- if ( map ) {
699
- for (n in map ) {
700
- if ( map.hasOwnProperty(n) ) {
701
- doclet = getLeadingDoclet(map[n]);
702
- settings = createPropertyMap(map[n].value, defaultKey);
703
- if ( settings == null ) {
704
- error("no valid metadata for " + n + " (AST type '" + map[n].value.type + "')");
705
- continue;
706
- }
707
-
708
- callback(n, settings, doclet, map[n]);
709
- }
710
- }
711
- }
712
- }
713
-
714
- var classInfoNode = extendCall.arguments[1];
715
- var classInfoMap = createPropertyMap(classInfoNode);
716
- if ( classInfoMap && classInfoMap.metadata && classInfoMap.metadata.value.type !== Syntax.ObjectExpression ) {
717
- warning("class metadata exists but can't be analyzed. It is not of type 'ObjectExpression', but a '" + classInfoMap.metadata.value.type + "'.");
718
- return null;
719
- }
720
-
721
- var metadata = classInfoMap && classInfoMap.metadata && createPropertyMap(classInfoMap.metadata.value);
722
- if ( metadata ) {
723
-
724
- debug(" analyzing metadata for '" + oClassInfo.name + "'");
725
-
726
- oClassInfo["abstract"] = !!(metadata["abstract"] && metadata["abstract"].value.value);
727
- oClassInfo["final"] = !!(metadata["final"] && metadata["final"].value.value);
728
- oClassInfo.dnd = metadata.dnd && convertDragDropValue(metadata.dnd.value);
729
-
730
- if ( metadata.interfaces ) {
731
- oClassInfo.interfaces = convertStringArray(metadata.interfaces.value);
732
- }
733
-
734
- each(metadata.specialSettings, "type", function(n, settings, doclet) {
735
- oClassInfo.specialSettings[n] = {
736
- name : n,
737
- doc : doclet && doclet.description,
738
- since : doclet && doclet.since,
739
- deprecation : doclet && doclet.deprecated,
740
- experimental : doclet && doclet.experimental,
741
- visibility : (settings.visibility && settings.visibility.value.value) || "public",
742
- type : settings.type ? settings.type.value.value : "any"
743
- };
744
- });
745
-
746
- oClassInfo.defaultProperty = (metadata.defaultProperty && metadata.defaultProperty.value.value) || undefined;
747
-
748
- each(metadata.properties, "type", function(n, settings, doclet) {
749
- var type;
750
- var N = upper(n);
751
- var methods;
752
- oClassInfo.properties[n] = {
753
- name : n,
754
- doc : doclet && doclet.description,
755
- since : doclet && doclet.since,
756
- deprecation : doclet && doclet.deprecated,
757
- experimental : doclet && doclet.experimental,
758
- readonly : doclet && doclet.readonly,
759
- visibility : (settings.visibility && settings.visibility.value.value) || "public",
760
- type : (type = settings.type ? settings.type.value.value : "string"),
761
- defaultValue : settings.defaultValue ? convertValue(settings.defaultValue.value, type, n) : null,
762
- group : settings.group ? settings.group.value.value : 'Misc',
763
- bindable : settings.bindable ? !!convertValue(settings.bindable.value) : false,
764
- methods: (methods = {
765
- "get": "get" + N,
766
- "set": "set" + N
767
- })
768
- };
769
- if ( oClassInfo.properties[n].bindable ) {
770
- methods["bind"] = "bind" + N;
771
- methods["unbind"] = "unbind" + N;
772
- }
773
- // if ( !settings.defaultValue ) {
774
- // console.log("property without defaultValue: " + oClassInfo.name + "." + n);
775
- //}
776
- if ( oClassInfo.properties[n].visibility !== 'public' ) {
777
- error("Property '" + n + "' uses visibility '" + oClassInfo.properties[n].visibility + "' which is not supported by the runtime");
778
- }
779
- });
780
-
781
- oClassInfo.defaultAggregation = (metadata.defaultAggregation && metadata.defaultAggregation.value.value) || undefined;
782
-
783
- each(metadata.aggregations, "type", function(n, settings, doclet) {
784
- var N = upper(n);
785
- var methods;
786
- var aggr = oClassInfo.aggregations[n] = {
787
- name: n,
788
- doc : doclet && doclet.description,
789
- deprecation : doclet && doclet.deprecated,
790
- since : doclet && doclet.since,
791
- experimental : doclet && doclet.experimental,
792
- visibility : (settings.visibility && settings.visibility.value.value) || "public",
793
- type : settings.type ? settings.type.value.value : "sap.ui.core.Control",
794
- altTypes: settings.altTypes ? convertStringArray(settings.altTypes.value) : undefined,
795
- singularName : settings.singularName ? settings.singularName.value.value : guessSingularName(n),
796
- cardinality : (settings.multiple && !settings.multiple.value.value) ? "0..1" : "0..n",
797
- bindable : settings.bindable ? !!convertValue(settings.bindable.value) : false,
798
- methods: (methods = {
799
- "get": "get" + N,
800
- "destroy": "destroy" + N
801
- })
802
- };
803
-
804
- aggr.dnd = settings.dnd && convertDragDropValue(settings.dnd.value, aggr.cardinality);
805
-
806
- if ( aggr.cardinality === "0..1" ) {
807
- methods["set"] = "set" + N;
808
- } else {
809
- var N1 = upper(aggr.singularName);
810
- methods["insert"] = "insert" + N1;
811
- methods["add"] = "add" + N1;
812
- methods["remove"] = "remove" + N1;
813
- methods["indexOf"] = "indexOf" + N1;
814
- methods["removeAll"] = "removeAll" + N;
815
- }
816
- if ( aggr.bindable ) {
817
- methods["bind"] = "bind" + N;
818
- methods["unbind"] = "unbind" + N;
819
- }
820
- });
821
-
822
- each(metadata.associations, "type", function(n, settings, doclet) {
823
- var N = upper(n);
824
- var methods;
825
- oClassInfo.associations[n] = {
826
- name: n,
827
- doc : doclet && doclet.description,
828
- deprecation : doclet && doclet.deprecated,
829
- since : doclet && doclet.since,
830
- experimental : doclet && doclet.experimental,
831
- visibility : (settings.visibility && settings.visibility.value.value) || "public",
832
- type : settings.type ? settings.type.value.value : "sap.ui.core.Control",
833
- singularName : settings.singularName ? settings.singularName.value.value : guessSingularName(n),
834
- cardinality : (settings.multiple && settings.multiple.value.value) ? "0..n" : "0..1",
835
- methods: (methods = {
836
- "get": "get" + N
837
- })
838
- };
839
- if ( oClassInfo.associations[n].cardinality === "0..1" ) {
840
- methods["set"] = "set" + N;
841
- } else {
842
- var N1 = upper(oClassInfo.associations[n].singularName);
843
- methods["add"] = "add" + N1;
844
- methods["remove"] = "remove" + N1;
845
- methods["removeAll"] = "removeAll" + N;
846
- }
847
- if ( oClassInfo.associations[n].visibility !== 'public' ) {
848
- error("Association '" + n + "' uses visibility '" + oClassInfo.associations[n].visibility + "' which is not supported by the runtime");
849
- }
850
- });
851
-
852
- each(metadata.events, null, function(n, settings, doclet) {
853
- var N = upper(n);
854
- var info = oClassInfo.events[n] = {
855
- name: n,
856
- doc : doclet && doclet.description,
857
- deprecation : doclet && doclet.deprecated,
858
- since : doclet && doclet.since,
859
- experimental : doclet && doclet.experimental,
860
- visibility : /* (settings.visibility && settings.visibility.value.value) || */ "public",
861
- allowPreventDefault : !!(settings.allowPreventDefault && settings.allowPreventDefault.value.value),
862
- parameters : {},
863
- methods: {
864
- "attach": "attach" + N,
865
- "detach": "detach" + N,
866
- "fire": "fire" + N
867
- }
868
- };
869
- each(settings.parameters, "type", function(pName, pSettings, pDoclet) {
870
- info.parameters[pName] = {
871
- name : pName,
872
- doc : pDoclet && pDoclet.description,
873
- deprecation : pDoclet && pDoclet.deprecated,
874
- since : pDoclet && pDoclet.since,
875
- experimental : pDoclet && pDoclet.experimental,
876
- type : pSettings && pSettings.type ? pSettings.type.value.value : ""
877
- };
878
- });
879
- });
880
-
881
- var designtime = (metadata.designtime && convertValue(metadata.designtime.value)) || (metadata.designTime && convertValue(metadata.designTime.value));
882
- if ( typeof designtime === 'string' || typeof designtime === 'boolean' ) {
883
- oClassInfo.designtime = designtime;
884
- }
885
- // console.log(oClassInfo.name + ":" + JSON.stringify(oClassInfo, null, " "));
886
- }
887
-
888
- // remember class info by name
889
- classInfos[oClassInfo.name] = oClassInfo;
890
-
891
- return oClassInfo;
892
- }
893
-
894
- function collectDesigntimeInfo(dtNode) {
895
-
896
- function each(node, defaultKey, callback) {
897
- var map,n,settings,doclet;
898
-
899
- map = node && createPropertyMap(node.value);
900
- if ( map ) {
901
- for (n in map ) {
902
- if ( map.hasOwnProperty(n) ) {
903
- doclet = getLeadingDoclet(map[n], true);
904
- settings = createPropertyMap(map[n].value, defaultKey);
905
- if ( settings == null ) {
906
- error("no valid metadata for " + n + " (AST type '" + map[n].value.type + "')");
907
- continue;
908
- }
909
-
910
- callback(n, settings, doclet, map[n]);
911
- }
912
- }
913
- }
914
- }
915
-
916
- var oDesigntimeInfo;
917
-
918
- var map = createPropertyMap(dtNode.argument);
919
-
920
- if (map.annotations) {
921
-
922
- oDesigntimeInfo = {
923
- annotations: {}
924
- };
925
-
926
- each(map.annotations, null, function(n, settings, doclet) {
927
- var appliesTo = [],
928
- targets = [],
929
- i, oAnno, iPos;
930
-
931
- if (settings.appliesTo) {
932
- for (i = 0; i < settings.appliesTo.value.elements.length; i++) {
933
- appliesTo.push(settings.appliesTo.value.elements[i].value);
934
- }
935
- }
936
-
937
- if (settings.target) {
938
- for (i = 0; i < settings.target.value.elements.length; i++) {
939
- targets.push(settings.target.value.elements[i].value);
940
- }
941
- }
942
-
943
- oDesigntimeInfo.annotations[n] = {
944
- name: n,
945
- doc : doclet && doclet.description,
946
- deprecation : doclet && doclet.deprecated,
947
- since : doclet && doclet.since || settings.since && settings.since.value.value,
948
- namespace: settings.namespace && settings.namespace.value.value,
949
- annotation: settings.annotation && settings.annotation.value.value,
950
- appliesTo: appliesTo,
951
- target: targets,
952
- interpretation: settings.interpretation && settings.interpretation.value.value,
953
- defaultValue: settings.defaultValue && settings.defaultValue.value.value
954
- };
955
-
956
- oAnno = oDesigntimeInfo.annotations[n].annotation;
957
- iPos = oAnno && oAnno.lastIndexOf(".");
958
-
959
- if ( !oDesigntimeInfo.annotations[n].namespace && iPos > 0 ) {
960
- oDesigntimeInfo.annotations[n].namespace = oAnno.slice(0, iPos);
961
- oDesigntimeInfo.annotations[n].annotation = oAnno.slice(iPos + 1);
962
- }
963
- })
964
- }
965
-
966
- return oDesigntimeInfo;
967
- }
968
-
969
- function determineValueRangeBorder(range, expression, varname, inverse) {
970
- if ( expression.type === Syntax.BinaryExpression ) {
971
- var value;
972
- if ( expression.left.type === Syntax.Identifier && expression.left.name === varname && expression.right.type === Syntax.Literal ) {
973
- value = expression.right.value;
974
- } else if ( expression.left.type === Syntax.Literal && expression.right.type === Syntax.Identifier && expression.right.name === varname ) {
975
- inverse = !inverse;
976
- value = expression.left.value;
977
- } else {
978
- return false;
979
- }
980
- switch (expression.operator) {
981
- case '<':
982
- range[inverse ? 'minExclusive' : 'maxExclusive'] = value;
983
- break;
984
- case '<=':
985
- range[inverse ? 'minInclusive' : 'maxInclusive'] = value;
986
- break;
987
- case '>=':
988
- range[inverse ? 'maxInclusive' : 'minInclusive'] = value;
989
- break;
990
- case '>':
991
- range[inverse ? 'maxExclusive' : 'minExclusive'] = value;
992
- break;
993
- default:
994
- return false;
995
- }
996
- return true;
997
- }
998
- return false;
999
- }
1000
-
1001
- function determineValueRange(expression, varname, inverse) {
1002
- var range = {};
1003
- if ( expression.type === Syntax.LogicalExpression
1004
- && expression.operator === '&&'
1005
- && expression.left.type === Syntax.BinaryExpression
1006
- && expression.right.type === Syntax.BinaryExpression
1007
- && determineValueRangeBorder(range, expression.left, varname, inverse)
1008
- && determineValueRangeBorder(range, expression.right, varname, inverse) ) {
1009
- return range;
1010
- } else if ( expression.type === Syntax.BinaryExpression
1011
- && determineValueRangeBorder(range, expression, varname, inverse) ) {
1012
- return range;
1013
- }
1014
- return undefined;
1015
- }
1016
-
1017
- function collectDataTypeInfo(extendCall, classDoclet) {
1018
- var args = extendCall.arguments,
1019
- i = 0,
1020
- name, def, base, pattern, range;
1021
-
1022
- if ( i < args.length && args[i].type === Syntax.Literal && typeof args[i].value === 'string' ) {
1023
- name = args[i++].value;
1024
- }
1025
- if ( i < args.length && args[i].type === Syntax.ObjectExpression ) {
1026
- def = createPropertyMap(args[i++]);
1027
- }
1028
- if ( i < args.length ) {
1029
- if ( args[i].type === Syntax.Literal && typeof args[i].value === 'string' ) {
1030
- base = args[i++].value;
1031
- } else if ( args[i].type === Syntax.CallExpression
1032
- && args[i].callee.type === Syntax.MemberExpression
1033
- && /^(sap\.ui\.base\.)?DataType$/.test(getObjectName(args[i].callee.object))
1034
- && args[i].callee.property.type === Syntax.Identifier
1035
- && args[i].callee.property.name === 'getType'
1036
- && args[i].arguments.length === 1
1037
- && args[i].arguments[0].type === Syntax.Literal
1038
- && typeof args[i].arguments[0].value === 'string' ) {
1039
- base = args[i++].arguments[0].value;
1040
- } else {
1041
- error("could not identify base type of data type '" + name + "'");
1042
- }
1043
- } else {
1044
- base = "any";
1045
- }
1046
-
1047
- if ( def
1048
- && def.isValid
1049
- && def.isValid.value.type === Syntax.FunctionExpression
1050
- && def.isValid.value.params.length === 1
1051
- && def.isValid.value.params[0].type === Syntax.Identifier
1052
- && def.isValid.value.body.body.length === 1 ) {
1053
- var varname = def.isValid.value.params[0].name;
1054
- var stmt = def.isValid.value.body.body[0];
1055
- if ( stmt.type === Syntax.ReturnStatement && stmt.argument ) {
1056
- if ( stmt.argument.type === Syntax.CallExpression
1057
- && stmt.argument.callee.type === Syntax.MemberExpression
1058
- && stmt.argument.callee.object.type === Syntax.Literal
1059
- && stmt.argument.callee.object.regex
1060
- && stmt.argument.callee.property.type === Syntax.Identifier
1061
- && stmt.argument.callee.property.name === 'test' ) {
1062
- pattern = stmt.argument.callee.object.regex.pattern;
1063
- // console.log(pattern);
1064
- } else {
1065
- range = determineValueRange(stmt.argument, varname, false);
1066
- }
1067
- } else if ( stmt.type === Syntax.IfStatement
1068
- && stmt.consequent.type === Syntax.BlockStatement
1069
- && stmt.consequent.body.length === 1
1070
- && stmt.consequent.body[0].type === Syntax.ReturnStatement
1071
- && stmt.consequent.body[0].argument
1072
- && stmt.consequent.body[0].argument.type === Syntax.Literal
1073
- && typeof stmt.consequent.body[0].argument.value === 'boolean'
1074
- && stmt.alternate.type === Syntax.BlockStatement
1075
- && stmt.alternate.body.length === 1
1076
- && stmt.alternate.body[0].type === Syntax.ReturnStatement
1077
- && stmt.alternate.body[0].argument
1078
- && stmt.alternate.body[0].argument.type === Syntax.Literal
1079
- && typeof stmt.alternate.body[0].argument.value === 'boolean'
1080
- && stmt.consequent.body[0].argument.value !== typeof stmt.alternate.body[0].argument.value ) {
1081
- var inverse = stmt.alternate.body[0].argument.value;
1082
- range = determineValueRange(stmt.test, varname, inverse);
1083
- } else {
1084
- console.log(stmt);
1085
- }
1086
- }
1087
-
1088
- // remember type info by name
1089
- if ( name && def && base ) {
1090
- typeInfos[name] = {
1091
- name: name,
1092
- def: def,
1093
- pattern: pattern,
1094
- range: range,
1095
- base: base
1096
- };
1097
- // console.log("found data type:", typeInfos[name]);
1098
- }
1099
- }
1100
-
1101
- var rEmptyLine = /^\s*$/;
1102
-
1103
- function createAutoDoc(oClassInfo, classComment, node, parser, filename, commentAlreadyProcessed) {
1104
-
1105
- var newStyle = !!pluginConfig.newStyle,
1106
- includeSettings = !!pluginConfig.includeSettingsInConstructor,
1107
- rawClassComment = getRawComment(classComment),
1108
- p,n,n1,pName,info,lines,link;
1109
-
1110
- function isEmpty(obj) {
1111
- if ( !obj ) {
1112
- return true;
1113
- }
1114
- for (var n in obj) {
1115
- if ( obj.hasOwnProperty(n) ) {
1116
- return false;
1117
- }
1118
- }
1119
- return true;
1120
- }
1121
-
1122
- function jsdocCommentFound(comment) {
1123
- parser.emit('jsdocCommentFound', {
1124
- event:'jsdocCommentFound',
1125
- comment : comment,
1126
- lineno : node.loc.start.line,
1127
- filename : filename,
1128
- range : [ node.range[0], node.range[0] ]
1129
- }, parser);
1130
- }
1131
-
1132
- function removeDuplicateEmptyLines(lines) {
1133
- var lastWasEmpty = false,
1134
- i,j,l,line;
1135
-
1136
- for (i = 0, j = 0, l = lines.length; i < l; i++) {
1137
- line = lines[i];
1138
- if ( line == null || rEmptyLine.test(line) ) {
1139
- if ( !lastWasEmpty ) {
1140
- lines[j++] = line;
1141
- }
1142
- lastWasEmpty = true;
1143
- } else {
1144
- lines[j++] = line;
1145
- lastWasEmpty = false;
1146
- }
1147
- }
1148
- return j < i ? lines.slice(0,j) : lines;
1149
- }
1150
-
1151
- function newJSDoc(lines) {
1152
- //console.log("add completely new jsdoc comment to prog " + node.type + ":" + node.nodeId + ":" + Object.keys(node));
1153
-
1154
- lines = removeDuplicateEmptyLines(lines);
1155
- lines.push("@synthetic");
1156
-
1157
- var comment = " * " + lines.join("\r\n * ");
1158
- jsdocCommentFound("/**\r\n" + comment + "\r\n */")
1159
-
1160
- var m = /@name\s+([^\r\n\t ]+)/.exec(comment);
1161
- debug(" creating synthetic comment '" + (m && m[1]) + "'");
1162
- }
1163
-
1164
- function rname(prefix,n,_static) {
1165
- return (_static ? "." : "#") + prefix + n.slice(0,1).toUpperCase() + n.slice(1);
1166
- }
1167
-
1168
- function name(prefix,n,_static) {
1169
- return oClassInfo.name + rname(prefix,n,_static);
1170
- }
1171
-
1172
- /*
1173
- * creates a JSDoc type string from the given metadata info object.
1174
- * It takes into account the type, the altTypes and the cardinality
1175
- * (the latter only if componentTypeOnly is not set).
1176
- */
1177
- function makeTypeString(aggr, componentTypeOnly) {
1178
- var s = aggr.type;
1179
- if ( aggr.altTypes ) {
1180
- s = s + "|" + aggr.altTypes.join("|");
1181
- }
1182
- if ( !componentTypeOnly && aggr.cardinality === "0..n" ) {
1183
- // if multiple types are allowed, use Array.<> for proper grouping
1184
- if ( aggr.altTypes ) {
1185
- s = "Array.<" + s + ">";
1186
- } else {
1187
- s = s + "[]";
1188
- }
1189
- }
1190
- return s;
1191
- }
1192
-
1193
- // function shortname(s) {
1194
- // return s.slice(s.lastIndexOf('.') + 1);
1195
- // }
1196
-
1197
- var HUNGARIAN_PREFIXES = {
1198
- 'int' : 'i',
1199
- 'boolean' : 'b',
1200
- 'float' : 'f',
1201
- 'string' : 's',
1202
- 'function' : 'fn',
1203
- 'object' : 'o',
1204
- 'regexp' : 'r',
1205
- 'jQuery' : '$',
1206
- 'any' : 'o',
1207
- 'variant' : 'v',
1208
- 'map' : 'm'
1209
- };
1210
-
1211
- function varname(n, type, property) {
1212
- var prefix = HUNGARIAN_PREFIXES[type] || (property ? "s" : "o");
1213
- return prefix + n.slice(0,1).toUpperCase() + n.slice(1);
1214
- }
1215
-
1216
- // add a list of the possible settings if and only if
1217
- // - documentation for the constructor exists
1218
- // - no (generated) documentation for settings exists already
1219
- // - a suitable place for inserting the settings can be found
1220
- var m = /(?:^|\r\n|\n|\r)[ \t]*\**[ \t]*@[a-zA-Z]/.exec(rawClassComment);
1221
- p = m ? m.index : -1;
1222
- var hasSettingsDocs = rawClassComment.indexOf("The supported settings are:") >= 0;
1223
-
1224
- // heuristic to recognize a ManagedObject
1225
- var isManagedObject = (
1226
- /@extends\s+sap\.ui\.(?:base\.ManagedObject|core\.(?:Element|Control|Component))(?:\s|$)/.test(rawClassComment)
1227
- || oClassInfo.library
1228
- || !isEmpty(oClassInfo.specialSettings)
1229
- || !isEmpty(oClassInfo.properties)
1230
- || !isEmpty(oClassInfo.aggregations)
1231
- || !isEmpty(oClassInfo.associations)
1232
- || !isEmpty(oClassInfo.events)
1233
- );
1234
-
1235
- if ( p >= 0 && !hasSettingsDocs ) {
1236
- lines = [
1237
- ""
1238
- ];
1239
-
1240
- if ( isManagedObject ) { // only a ManagedObject has settings
1241
-
1242
- if ( oClassInfo.name !== "sap.ui.base.ManagedObject" ) {
1243
- // add the hint for the general description only when the current class is not ManagedObject itself
1244
- lines.push(
1245
- "",
1246
- "Accepts an object literal <code>mSettings</code> that defines initial",
1247
- "property values, aggregated and associated objects as well as event handlers.",
1248
- "See {@link sap.ui.base.ManagedObject#constructor} for a general description of the syntax of the settings object."
1249
- );
1250
- }
1251
-
1252
- // add the settings section only if there are any settings
1253
- if ( !isEmpty(oClassInfo.properties)
1254
- || !isEmpty(oClassInfo.aggregations)
1255
- || !isEmpty(oClassInfo.associations)
1256
- || !isEmpty(oClassInfo.events) ) {
1257
-
1258
- lines.push(
1259
- "",
1260
- includeSettings ? "" : "@ui5-settings",
1261
- "The supported settings are:",
1262
- "<ul>"
1263
- );
1264
- if ( !isEmpty(oClassInfo.properties) ) {
1265
- lines.push("<li>Properties");
1266
- lines.push("<ul>");
1267
- for (n in oClassInfo.properties) {
1268
- lines.push("<li>{@link " + rname("get", n) + " " + n + "} : " + oClassInfo.properties[n].type + (oClassInfo.properties[n].defaultValue !== null ? " (default: " + oClassInfo.properties[n].defaultValue + ")" : "") + (oClassInfo.defaultProperty == n ? " (default)" : "") + "</li>");
1269
- }
1270
- lines.push("</ul>");
1271
- lines.push("</li>");
1272
- }
1273
- if ( !isEmpty(oClassInfo.aggregations) ) {
1274
- lines.push("<li>Aggregations");
1275
- lines.push("<ul>");
1276
- for (n in oClassInfo.aggregations) {
1277
- if ( oClassInfo.aggregations[n].visibility !== "hidden" ) {
1278
- lines.push("<li>{@link " + rname("get", n) + " " + n + "} : " + makeTypeString(oClassInfo.aggregations[n]) + (oClassInfo.defaultAggregation == n ? " (default)" : "") + "</li>");
1279
- }
1280
- }
1281
- lines.push("</ul>");
1282
- lines.push("</li>");
1283
- }
1284
- if ( !isEmpty(oClassInfo.associations) ) {
1285
- lines.push("<li>Associations");
1286
- lines.push("<ul>");
1287
- for (n in oClassInfo.associations) {
1288
- lines.push("<li>{@link " + rname("get", n) + " " + n + "} : (sap.ui.core.ID | " + oClassInfo.associations[n].type + ")" + (oClassInfo.associations[n].cardinality === "0..n" ? "[]" : "") + "</li>");
1289
- }
1290
- lines.push("</ul>");
1291
- lines.push("</li>");
1292
- }
1293
- if ( !isEmpty(oClassInfo.events) ) {
1294
- lines.push("<li>Events");
1295
- lines.push("<ul>");
1296
- for (n in oClassInfo.events) {
1297
- lines.push("<li>{@link " + "#event:" + n + " " + n + "} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li>");
1298
- }
1299
- lines.push("</ul>");
1300
- lines.push("</li>");
1301
- }
1302
- lines.push("</ul>");
1303
-
1304
- // add the reference to the base class only if this is not ManagedObject and if the base class is known
1305
- if ( oClassInfo.name !== "sap.ui.base.ManagedObject" && oClassInfo.baseType ) {
1306
- lines.push(
1307
- "",
1308
- "In addition, all settings applicable to the base type {@link " + oClassInfo.baseType + "#constructor " + oClassInfo.baseType + "}",
1309
- "can be used as well."
1310
- );
1311
- }
1312
- lines.push("");
1313
-
1314
- } else if ( oClassInfo.name !== "sap.ui.base.ManagedObject" && oClassInfo.baseType && oClassInfo.hasOwnProperty("abstract") ) {
1315
-
1316
- // if a class has no settings, but metadata, point at least to the base class - if it makes sense
1317
- lines.push(
1318
- "",
1319
- newStyle && !includeSettings ? "@ui5-settings" : "",
1320
- "This class does not have its own settings, but all settings applicable to the base type",
1321
- "{@link " + oClassInfo.baseType + "#constructor " + oClassInfo.baseType + "} can be used."
1322
- );
1323
-
1324
- }
1325
- }
1326
-
1327
- debug(" enhancing constructor documentation with settings");
1328
- var enhancedComment =
1329
- rawClassComment.slice(0,p) +
1330
- "\n * " + removeDuplicateEmptyLines(lines).join("\n * ") +
1331
- (commentAlreadyProcessed ? "@ui5-updated-doclet\n * " : "") +
1332
- rawClassComment.slice(p);
1333
- enhancedComment = preprocessComment({ comment : enhancedComment, lineno : classComment.lineno });
1334
-
1335
- if ( commentAlreadyProcessed ) {
1336
- jsdocCommentFound(enhancedComment);
1337
- } else {
1338
- setRawComment(classComment, enhancedComment);
1339
- }
1340
-
1341
- }
1342
-
1343
- newJSDoc([
1344
- "Returns a metadata object for class " + oClassInfo.name + ".",
1345
- "",
1346
- "@returns {sap.ui.base.Metadata} Metadata object describing this class",
1347
- "@public",
1348
- "@static",
1349
- "@name " + name("getMetadata", "", true),
1350
- "@function"
1351
- ]);
1352
-
1353
- if ( !oClassInfo["final"] ) {
1354
- newJSDoc([
1355
- "Creates a new subclass of class " + oClassInfo.name + " with name <code>sClassName</code>",
1356
- "and enriches it with the information contained in <code>oClassInfo</code>.",
1357
- "",
1358
- "<code>oClassInfo</code> might contain the same kind of information as described in {@link " + (oClassInfo.baseType ? oClassInfo.baseType + ".extend" : "sap.ui.base.Object.extend Object.extend") + "}.",
1359
- "",
1360
- "@param {string} sClassName Name of the class being created",
1361
- "@param {object} [oClassInfo] Object literal with information about the class",
1362
- "@param {function} [FNMetaImpl] Constructor function for the metadata object; if not given, it defaults to <code>sap.ui.core.ElementMetadata</code>",
1363
- "@returns {function} Created class / constructor function",
1364
- "@public",
1365
- "@static",
1366
- "@name " + name("extend", "", true),
1367
- "@function"
1368
- ]);
1369
- }
1370
-
1371
- for (n in oClassInfo.properties ) {
1372
- info = oClassInfo.properties[n];
1373
- if ( info.visibility === 'hidden' ) {
1374
- continue;
1375
- }
1376
- // link = newStyle ? "{@link #setting:" + n + " " + n + "}" : "<code>" + n + "</code>";
1377
- link = "{@link " + (newStyle ? "#setting:" + n : rname("get", n)) + " " + n + "}";
1378
- newJSDoc([
1379
- "Gets current value of property " + link + ".",
1380
- "",
1381
- !newStyle && info.doc ? info.doc : "",
1382
- "",
1383
- info.defaultValue !== null ? "Default value is <code>" + (info.defaultValue === "" ? "empty string" : info.defaultValue) + "</code>." : "",
1384
- "@returns {" + info.type + "} Value of property <code>" + n + "</code>",
1385
- info.since ? "@since " + info.since : "",
1386
- info.deprecation ? "@deprecated " + info.deprecation : "",
1387
- info.experimental ? "@experimental " + info.experimental : "",
1388
- "@public",
1389
- "@name " + name("get",n),
1390
- "@function"
1391
- ]);
1392
- newJSDoc([
1393
- "Sets a new value for property " + link + ".",
1394
- "",
1395
- !newStyle && info.doc ? info.doc : "",
1396
- "",
1397
- "When called with a value of <code>null</code> or <code>undefined</code>, the default value of the property will be restored.",
1398
- "",
1399
- info.defaultValue !== null ? "Default value is <code>" + (info.defaultValue === "" ? "empty string" : info.defaultValue) + "</code>." : "",
1400
- "@param {" + info.type + "} " + varname(n,info.type,true) + " New value for property <code>" + n + "</code>",
1401
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1402
- info.since ? "@since " + info.since : "",
1403
- info.deprecation ? "@deprecated " + info.deprecation : "",
1404
- info.experimental ? "@experimental " + info.experimental : "",
1405
- "@public",
1406
- "@name " + name("set",n),
1407
- "@function"
1408
- ]);
1409
- if ( info.bindable ) {
1410
- newJSDoc([
1411
- "Binds property " + link + " to model data.",
1412
- "",
1413
- "See {@link sap.ui.base.ManagedObject#bindProperty ManagedObject.bindProperty} for a ",
1414
- "detailed description of the possible properties of <code>oBindingInfo</code>",
1415
- "@param {object} oBindingInfo The binding information",
1416
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1417
- info.since ? "@since " + info.since : "",
1418
- info.deprecation ? "@deprecated " + info.deprecation : "",
1419
- info.experimental ? "@experimental " + info.experimental : "",
1420
- "@public",
1421
- "@name " + name("bind",n),
1422
- "@function"
1423
- ]);
1424
- newJSDoc([
1425
- "Unbinds property " + link + " from model data.",
1426
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1427
- info.since ? "@since " + info.since : "",
1428
- info.deprecation ? "@deprecated " + info.deprecation : "",
1429
- info.experimental ? "@experimental " + info.experimental : "",
1430
- "@public",
1431
- "@name " + name("unbind",n),
1432
- "@function"
1433
- ]);
1434
- }
1435
- }
1436
-
1437
- for (n in oClassInfo.aggregations ) {
1438
- info = oClassInfo.aggregations[n];
1439
- if ( info.visibility === 'hidden' ) {
1440
- continue;
1441
- }
1442
- // link = newStyle ? "{@link #setting:" + n + " " + n + "}" : "<code>" + n + "</code>";
1443
- link = "{@link " + (newStyle ? "#setting:" + n : rname("get", n)) + " " + n + "}";
1444
- newJSDoc([
1445
- "Gets content of aggregation " + link + ".",
1446
- "",
1447
- !newStyle && info.doc ? info.doc : "",
1448
- "",
1449
- n === info.defaultAggregation ? "<strong>Note</strong>: this is the default aggregation for " + n + "." : "",
1450
- "@returns {" + makeTypeString(info) + "}",
1451
- info.since ? "@since " + info.since : "",
1452
- info.deprecation ? "@deprecated " + info.deprecation : "",
1453
- info.experimental ? "@experimental " + info.experimental : "",
1454
- "@public",
1455
- "@name " + name("get",n),
1456
- "@function"
1457
- ]);
1458
- if ( info.cardinality == "0..n" ) {
1459
- n1 = info.singularName;
1460
- newJSDoc([
1461
- "Inserts a " + n1 + " into the aggregation " + link + ".",
1462
- "",
1463
- "@param {" + makeTypeString(info, true) + "}",
1464
- " " + varname(n1,info.altTypes ? "variant" : info.type) + " The " + n1 + " to insert; if empty, nothing is inserted",
1465
- "@param {int}",
1466
- " iIndex The <code>0</code>-based index the " + n1 + " should be inserted at; for",
1467
- " a negative value of <code>iIndex</code>, the " + n1 + " is inserted at position 0; for a value",
1468
- " greater than the current size of the aggregation, the " + n1 + " is inserted at",
1469
- " the last position",
1470
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1471
- info.since ? "@since " + info.since : "",
1472
- info.deprecation ? "@deprecated " + info.deprecation : "",
1473
- info.experimental ? "@experimental " + info.experimental : "",
1474
- "@public",
1475
- "@name " + name("insert",n1),
1476
- "@function"
1477
- ]);
1478
- newJSDoc([
1479
- "Adds some " + n1 + " to the aggregation " + link + ".",
1480
-
1481
- "@param {" + makeTypeString(info, true) + "}",
1482
- " " + varname(n1,info.altTypes ? "variant" : info.type) + " The " + n1 + " to add; if empty, nothing is inserted",
1483
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1484
- info.since ? "@since " + info.since : "",
1485
- info.deprecation ? "@deprecated " + info.deprecation : "",
1486
- info.experimental ? "@experimental " + info.experimental : "",
1487
- "@public",
1488
- "@name " + name("add",n1),
1489
- "@function"
1490
- ]);
1491
- newJSDoc([
1492
- "Removes a " + n1 + " from the aggregation " + link + ".",
1493
- "",
1494
- "@param {int | string | " + makeTypeString(info, true) + "} " + varname(n1,"variant") + " The " + n1 + " to remove or its index or id",
1495
- "@returns {" + makeTypeString(info, true) + "} The removed " + n1 + " or <code>null</code>",
1496
- info.since ? "@since " + info.since : "",
1497
- info.deprecation ? "@deprecated " + info.deprecation : "",
1498
- info.experimental ? "@experimental " + info.experimental : "",
1499
- "@public",
1500
- "@name " + name("remove", n1),
1501
- "@function"
1502
- ]);
1503
- newJSDoc([
1504
- "Removes all the controls from the aggregation " + link + ".",
1505
- "",
1506
- "Additionally, it unregisters them from the hosting UIArea.",
1507
- "@returns {" + makeTypeString(info) + "} An array of the removed elements (might be empty)",
1508
- info.since ? "@since " + info.since : "",
1509
- info.deprecation ? "@deprecated " + info.deprecation : "",
1510
- info.experimental ? "@experimental " + info.experimental : "",
1511
- "@public",
1512
- "@name " + name("removeAll", n),
1513
- "@function"
1514
- ]);
1515
- newJSDoc([
1516
- "Checks for the provided <code>" + info.type + "</code> in the aggregation " + link + ".",
1517
- "and returns its index if found or -1 otherwise.",
1518
- "@param {" + makeTypeString(info, true) + "}",
1519
- " " + varname(n1, info.altTypes ? "variant" : info.type) + " The " + n1 + " whose index is looked for",
1520
- "@returns {int} The index of the provided control in the aggregation if found, or -1 otherwise",
1521
- info.since ? "@since " + info.since : "",
1522
- info.deprecation ? "@deprecated " + info.deprecation : "",
1523
- info.experimental ? "@experimental " + info.experimental : "",
1524
- "@public",
1525
- "@name " + name("indexOf", n1),
1526
- "@function"
1527
- ]);
1528
- } else {
1529
- newJSDoc([
1530
- "Sets the aggregated " + link + ".",
1531
- "@param {" + makeTypeString(info) + "} " + varname(n, info.altTypes ? "variant" : info.type) + " The " + n + " to set",
1532
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1533
- info.since ? "@since " + info.since : "",
1534
- info.deprecation ? "@deprecated " + info.deprecation : "",
1535
- info.experimental ? "@experimental " + info.experimental : "",
1536
- "@public",
1537
- "@name " + name("set", n),
1538
- "@function"
1539
- ]);
1540
- }
1541
- newJSDoc([
1542
- "Destroys " + (info.cardinality === "0..n" ? "all " : "") + "the " + n + " in the aggregation " + link + ".",
1543
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1544
- info.since ? "@since " + info.since : "",
1545
- info.deprecation ? "@deprecated " + info.deprecation : "",
1546
- info.experimental ? "@experimental " + info.experimental : "",
1547
- "@public",
1548
- "@name " + name("destroy", n),
1549
- "@function"
1550
- ]);
1551
- if ( info.bindable ) {
1552
- newJSDoc([
1553
- "Binds aggregation " + link + " to model data.",
1554
- "",
1555
- "See {@link sap.ui.base.ManagedObject#bindAggregation ManagedObject.bindAggregation} for a ",
1556
- "detailed description of the possible properties of <code>oBindingInfo</code>.",
1557
- "@param {object} oBindingInfo The binding information",
1558
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1559
- info.since ? "@since " + info.since : "",
1560
- info.deprecation ? "@deprecated " + info.deprecation : "",
1561
- info.experimental ? "@experimental " + info.experimental : "",
1562
- "@public",
1563
- "@name " + name("bind",n),
1564
- "@function"
1565
- ]);
1566
- newJSDoc([
1567
- "Unbinds aggregation " + link + " from model data.",
1568
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1569
- info.since ? "@since " + info.since : "",
1570
- info.deprecation ? "@deprecated " + info.deprecation : "",
1571
- info.experimental ? "@experimental " + info.experimental : "",
1572
- "@public",
1573
- "@name " + name("unbind",n),
1574
- "@function"
1575
- ]);
1576
- }
1577
- }
1578
-
1579
- for (n in oClassInfo.associations ) {
1580
- info = oClassInfo.associations[n];
1581
- if ( info.visibility === 'hidden' ) {
1582
- continue;
1583
- }
1584
- // link = newStyle ? "{@link #setting:" + n + " " + n + "}" : "<code>" + n + "</code>";
1585
- link = "{@link " + (newStyle ? "#setting:" + n : rname("get", n)) + " " + n + "}";
1586
- newJSDoc([
1587
- info.cardinality === "0..n" ?
1588
- "Returns array of IDs of the elements which are the current targets of the association " + link + "." :
1589
- "ID of the element which is the current target of the association " + link + ", or <code>null</code>.",
1590
- "",
1591
- newStyle && info.doc ? info.doc : "",
1592
- "",
1593
- "@returns {sap.ui.core.ID" + (info.cardinality === "0..n" ? "[]" : "") + "}",
1594
- info.since ? "@since " + info.since : "",
1595
- info.deprecation ? "@deprecated " + info.deprecation : "",
1596
- info.experimental ? "@experimental " + info.experimental : "",
1597
- "@public",
1598
- "@name " + name("get",n),
1599
- "@function"
1600
- ]);
1601
- if ( info.cardinality === "0..n" ) {
1602
- n1 = info.singularName;
1603
- newJSDoc([
1604
- "Adds some " + n1 + " into the association " + link + ".",
1605
- "",
1606
- "@param {sap.ui.core.ID | " + info.type + "} " + varname(n1, "variant") + " The " + n + " to add; if empty, nothing is inserted",
1607
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1608
- info.since ? "@since " + info.since : "",
1609
- info.deprecation ? "@deprecated " + info.deprecation : "",
1610
- info.experimental ? "@experimental " + info.experimental : "",
1611
- "@public",
1612
- "@name " + name("add",n1),
1613
- "@function"
1614
- ]);
1615
- newJSDoc([
1616
- "Removes an " + n1 + " from the association named " + link + ".",
1617
- "@param {int | sap.ui.core.ID | " + info.type + "} " + varname(n1,"variant") + " The " + n1 + " to be removed or its index or ID",
1618
- "@returns {sap.ui.core.ID} The removed " + n1 + " or <code>null</code>",
1619
- info.since ? "@since " + info.since : "",
1620
- info.deprecation ? "@deprecated " + info.deprecation : "",
1621
- info.experimental ? "@experimental " + info.experimental : "",
1622
- "@public",
1623
- "@name " + name("remove", n1),
1624
- "@function"
1625
- ]);
1626
- newJSDoc([
1627
- "Removes all the controls in the association named " + link + ".",
1628
- "@returns {sap.ui.core.ID[]} An array of the removed elements (might be empty)",
1629
- info.since ? "@since " + info.since : "",
1630
- info.deprecation ? "@deprecated " + info.deprecation : "",
1631
- info.experimental ? "@experimental " + info.experimental : "",
1632
- "@public",
1633
- "@name " + name("removeAll", n),
1634
- "@function"
1635
- ]);
1636
- } else {
1637
- newJSDoc([
1638
- "Sets the associated " + link + ".",
1639
- "@param {sap.ui.core.ID | " + info.type + "} " + varname(n, info.type) + " ID of an element which becomes the new target of this " + n + " association; alternatively, an element instance may be given",
1640
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1641
- info.since ? "@since " + info.since : "",
1642
- info.deprecation ? "@deprecated " + info.deprecation : "",
1643
- info.experimental ? "@experimental " + info.experimental : "",
1644
- "@public",
1645
- "@name " + name("set", n),
1646
- "@function"
1647
- ]);
1648
- }
1649
- }
1650
-
1651
- for (n in oClassInfo.events ) {
1652
- info = oClassInfo.events[n];
1653
- //link = newStyle ? "{@link #event:" + n + " " + n + "}" : "<code>" + n + "</code>";
1654
- link = "{@link #event:" + n + " " + n + "}";
1655
-
1656
- lines = [
1657
- info.doc ? info.doc : "",
1658
- "",
1659
- "@name " + oClassInfo.name + "#" + n,
1660
- "@event",
1661
- info.since ? "@since " + info.since : "",
1662
- info.deprecation ? "@deprecated " + info.deprecation : "",
1663
- info.experimental ? "@experimental " + info.experimental : "",
1664
- "@param {sap.ui.base.Event} oControlEvent",
1665
- "@param {sap.ui.base.EventProvider} oControlEvent.getSource",
1666
- "@param {object} oControlEvent.getParameters"
1667
- ];
1668
- for (pName in info.parameters ) {
1669
- lines.push(
1670
- "@param {" + (info.parameters[pName].type || "") + "} oControlEvent.getParameters." + pName + " " + (info.parameters[pName].doc || "")
1671
- );
1672
- }
1673
- lines.push("@public");
1674
- newJSDoc(lines);
1675
-
1676
- newJSDoc([
1677
- "Attaches event handler <code>fnFunction</code> to the " + link + " event of this <code>" + oClassInfo.name + "</code>.",
1678
- "",
1679
- "When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener</code> if specified, ",
1680
- "otherwise it will be bound to this <code>" + oClassInfo.name + "</code> itself.",
1681
- "",
1682
- !newStyle && info.doc ? info.doc : "",
1683
- "",
1684
- "@param {object}",
1685
- " [oData] An application-specific payload object that will be passed to the event handler along with the event object when firing the event",
1686
- "@param {function}",
1687
- " fnFunction The function to be called when the event occurs",
1688
- "@param {object}",
1689
- " [oListener] Context object to call the event handler with. Defaults to this <code>" + oClassInfo.name + "</code> itself",
1690
- "",
1691
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1692
- "@public",
1693
- info.since ? "@since " + info.since : "",
1694
- info.deprecation ? "@deprecated " + info.deprecation : "",
1695
- info.experimental ? "@experimental " + info.experimental : "",
1696
- "@name " + name("attach", n),
1697
- "@function"
1698
- ]);
1699
- newJSDoc([
1700
- "Detaches event handler <code>fnFunction</code> from the " + link + " event of this <code>" + oClassInfo.name + "</code>.",
1701
- "",
1702
- "The passed function and listener object must match the ones used for event registration.",
1703
- "",
1704
- "@param {function}",
1705
- " fnFunction The function to be called, when the event occurs",
1706
- "@param {object}",
1707
- " oListener Context object on which the given function had to be called",
1708
- "@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining",
1709
- info.since ? "@since " + info.since : "",
1710
- info.deprecation ? "@deprecated " + info.deprecation : "",
1711
- info.experimental ? "@experimental " + info.experimental : "",
1712
- "@public",
1713
- "@name " + name("detach", n),
1714
- "@function"
1715
- ]);
1716
-
1717
- // build documentation for fireEvent. It contains conditional parts which makes it a bit more complicated
1718
- lines = [
1719
- "Fires event " + link + " to attached listeners."
1720
- ];
1721
- if ( info.allowPreventDefault ) {
1722
- lines.push(
1723
- "",
1724
- "Listeners may prevent the default action of this event by using the <code>preventDefault</code>-method on the event object.",
1725
- "");
1726
- }
1727
- lines.push(
1728
- "",
1729
- "@param {object} [mParameters] Parameters to pass along with the event"
1730
- );
1731
- if ( !isEmpty(info.parameters) ) {
1732
- for (pName in info.parameters) {
1733
- lines.push(
1734
- "@param {" + (info.parameters[pName].type || "any") + "} [mParameters." + pName + "] " + (info.parameters[pName].doc || "")
1735
- );
1736
- }
1737
- lines.push("");
1738
- }
1739
- if ( info.allowPreventDefault ) {
1740
- lines.push("@returns {boolean} Whether or not to prevent the default action");
1741
- } else {
1742
- lines.push("@returns {" + oClassInfo.name + "} Reference to <code>this</code> in order to allow method chaining");
1743
- }
1744
- lines.push(
1745
- "@protected",
1746
- info.since ? "@since " + info.since : "",
1747
- info.deprecation ? "@deprecated " + info.deprecation : "",
1748
- info.experimental ? "@experimental " + info.experimental : "",
1749
- "@name " + name("fire", n),
1750
- "@function"
1751
- );
1752
- newJSDoc(lines);
1753
- }
1754
-
1755
- }
1756
-
1757
- function createDataTypeAutoDoc(oTypeInfo, classComment, node, parser, filename) {
1758
- }
1759
-
1760
- /**
1761
- * Creates a human readable location info for a given doclet.
1762
- * @param doclet
1763
- * @returns {String}
1764
- */
1765
- function location(doclet) {
1766
- var filename = (doclet.meta && doclet.meta.filename) || "unknown";
1767
- return " #" + ui5data(doclet).id + "@" + filename + (doclet.meta.lineno != null ? ":" + doclet.meta.lineno : "") + (doclet.synthetic ? "(synthetic)" : "");
1768
- }
1769
-
1770
- // ---- Comment handling ---------------------------------------------------------------------------
1771
-
1772
- // --- comment related functions that depend on the JSdoc version (e.g. on the used parser)
1773
-
1774
- var isDocComment;
1775
- var getLeadingCommentNode;
1776
-
1777
- // JSDoc added the node type <code>Syntax.File</code> with the same change that activated Babylon
1778
- // See https://github.com/jsdoc3/jsdoc/commit/ffec4a42291de6d68e6240f304b68d6abb82a869
1779
- if ( Syntax.File === 'File' ) {
1780
-
1781
- // JSDoc starting with version 3.5.0
1782
-
1783
- isDocComment = function isDocCommentBabylon(comment) {
1784
- return comment && comment.type === 'CommentBlock' && comment.value && comment.value.charAt(0) === '*';
1785
- }
1786
-
1787
- getLeadingCommentNode = function getLeadingCommentNodeBabylon(node, longname) {
1788
- var leadingComments = node.leadingComments;
1789
- if ( Array.isArray(leadingComments) ) {
1790
- // in babylon, all comments are already attached to the node
1791
- // and the last one is the closest one and should win
1792
- // non-block comments have to be filtered out
1793
- leadingComments = leadingComments.filter(isDocComment);
1794
- if ( leadingComments.length > 0 ) {
1795
- return leadingComments[leadingComments.length - 1];
1796
- }
1797
- }
1798
- }
1799
-
1800
- } else {
1801
-
1802
- // JSDoc versions before 3.5.0
1803
-
1804
- isDocComment = function isDoccommentEsprima(comment) {
1805
- return comment && comment.type === 'Block';
1806
- };
1807
-
1808
- getLeadingCommentNode = function getLeadingCommentNodeEsprima(node, longname) {
1809
- var comment,
1810
- leadingComments = node.leadingComments;
1811
-
1812
- // when espree is used, JSDOc attached the leading comment and the first one was picked
1813
- if (Array.isArray(leadingComments) && leadingComments.length && leadingComments[0].raw) {
1814
- comment = leadingComments[0];
1815
- }
1816
-
1817
- // also check all comments attached to the Program node (if found) whether they refer to the same longname
1818
- // TODO check why any matches here override the direct leading comment from above
1819
- if ( longname && currentProgram && currentProgram.leadingComments && currentProgram.leadingComments.length ) {
1820
- leadingComments = currentProgram.leadingComments;
1821
- var rLongname = new RegExp("@(name|alias|class|namespace)\\s+" + longname.replace(/\./g, '\\.'));
1822
- for ( var i = 0; i < leadingComments.length; i++ ) {
1823
- var raw = getRawComment(leadingComments[i]);
1824
- if ( /^\/\*\*[\s\S]*\*\/$/.test(raw) && rLongname.test(raw) ) {
1825
- comment = leadingComments[i];
1826
- // console.log("\n\n**** alternative comment found for " + longname + " on program level\n\n", comment);
1827
- break;
1828
- }
1829
- }
1830
- }
1831
-
1832
- return comment;
1833
- }
1834
- }
1835
-
1836
- //--- comment related functions that are independent from the JSdoc version
1837
-
1838
- function getLeadingComment(node) {
1839
- var comment = getLeadingCommentNode(node);
1840
- return comment ? getRawComment(comment) : null;
1841
- }
1842
-
1843
- function getLeadingDoclet(node, preprocess) {
1844
- var comment = getLeadingComment(node)
1845
- if ( comment && preprocess ) {
1846
- comment = preprocessComment({comment:comment, lineno: node.loc.start.line });
1847
- }
1848
- return comment ? new Doclet(comment, {}) : null;
1849
- }
1850
-
1851
- /**
1852
- * Determines the raw comment string (source code form, including leading and trailing comment markers / *...* /) from a comment node.
1853
- * Works for Esprima and Babylon based JSDoc versions.
1854
- * @param commentNode
1855
- * @returns
1856
- */
1857
- function getRawComment(commentNode) {
1858
- // in esprima, there's a 'raw' property, in babylon, the 'raw' string has to be reconstructed from the 'value' by adding the markers
1859
- return commentNode ? commentNode.raw || '/*' + commentNode.value + '*/' : '';
1860
- }
1861
-
1862
- function setRawComment(commentNode, newRawComment) {
1863
- if ( commentNode.raw ) {
1864
- commentNode.raw = newRawComment;
1865
- }
1866
- commentNode.value = newRawComment.slice(2, -2);
1867
- }
1868
-
1869
- /**
1870
- * Removes the mandatory comment markers and the optional but common asterisks at the beginning of each JSDoc comment line.
1871
- *
1872
- * The result is easier to parse/analyze.
1873
- *
1874
- * Implementation is a 1:1 copy from JSDoc's lib/jsdoc/doclet.js (closure function, not directly reusable)
1875
- *
1876
- * @param {string} docletSrc the source comment with or without block comment markers
1877
- * @returns {string} the unwrapped content of the JSDoc comment
1878
- *
1879
- */
1880
- function unwrap(docletSrc) {
1881
- if (!docletSrc) { return ''; }
1882
-
1883
- // note: keep trailing whitespace for @examples
1884
- // extra opening/closing stars are ignored
1885
- // left margin is considered a star and a space
1886
- // use the /m flag on regex to avoid having to guess what this platform's newline is
1887
- docletSrc =
1888
- docletSrc.replace(/^\/\*\*+/, '') // remove opening slash+stars
1889
- .replace(/\**\*\/$/, "\\Z") // replace closing star slash with end-marker
1890
- .replace(/^\s*(\* ?|\\Z)/gm, '') // remove left margin like: spaces+star or spaces+end-marker
1891
- .replace(/\s*\\Z$/g, ''); // remove end-marker
1892
-
1893
- return docletSrc;
1894
- }
1895
-
1896
- /**
1897
- * Inverse operation of unwrap.
1898
- *
1899
- * The prefix for lines is fixed to be " * ", lines are separated with '\n', independent from the platform.
1900
- */
1901
- function wrap(lines) {
1902
- if ( typeof lines === "string" ) {
1903
- lines = lines.split(/\r\n?|\n/);
1904
- }
1905
- return "/**\n * " + lines.join('\n * ') + "\n */";
1906
- }
1907
-
1908
- /**
1909
- * Preprocesses a JSDoc comment string to ensure some UI5 standards.
1910
- *
1911
- * @param {event} e Event for the new comment
1912
- * @returns {event}
1913
- */
1914
- function preprocessComment(e) {
1915
-
1916
- var src = e.comment;
1917
-
1918
- // add a default visibility
1919
- if ( !/@private|@public|@protected|@sap-restricted|@ui5-restricted/.test(src) ) {
1920
- src = unwrap(src);
1921
- src = src + "\n@private";
1922
- src = wrap(src);
1923
- // console.log("added default visibility to '" + src + "'");
1924
- }
1925
-
1926
- if ( /@class/.test(src) && /@static/.test(src) ) {
1927
- warning("combination of @class and @static is no longer supported with jsdoc3, converting it to @namespace and @classdesc: (line " + e.lineno + ")");
1928
- src = unwrap(src);
1929
- src = src.replace(/@class/, "@classdesc").replace(/@static/, "@namespace");
1930
- src = wrap(src);
1931
- //console.log(src);
1932
- }
1933
-
1934
- return src;
1935
-
1936
- }
1937
-
1938
- // ---- other functionality ---------------------------------------------------------------------------
1939
-
1940
- // HACK: override cli.exit() to avoid that JSDoc3 exits the VM
1941
- if ( pluginConfig.noExit ) {
1942
- info("disabling exit() call");
1943
- require( path.join(global.env.dirname, 'cli') ).exit = function(retval) {
1944
- info("cli.exit(): do nothing (ret val=" + retval + ")");
1945
- };
1946
- }
1947
-
1948
-
1949
- // ---- exports ----------------------------------------------------------------------------------------
1950
-
1951
- exports.defineTags = function(dictionary) {
1952
-
1953
- /**
1954
- * a special value that is not 'falsy' but results in an empty string when output
1955
- * Used for the disclaimer and experimental tag
1956
- */
1957
- var EMPTY = {
1958
- toString: function() { return ""; }
1959
- };
1960
-
1961
- /**
1962
- * A sapui5 specific tag to add a disclaimer to a symbol
1963
- */
1964
- dictionary.defineTag('disclaimer', {
1965
- // value is optional
1966
- onTagged: function(doclet, tag) {
1967
- doclet.disclaimer = tag.value || EMPTY;
1968
- }
1969
- });
1970
-
1971
- /**
1972
- * A sapui5 specific tag to mark a symbol as experimental.
1973
- */
1974
- dictionary.defineTag('experimental', {
1975
- // value is optional
1976
- onTagged: function(doclet, tag) {
1977
- doclet.experimental = tag.value || EMPTY;
1978
- }
1979
- });
1980
-
1981
- /**
1982
- * Re-introduce the deprecated 'final tag. JSDoc used it as a synonym for readonly, but we use it to mark classes as final
1983
- */
1984
- dictionary.defineTag('final', {
1985
- mustNotHaveValue: true,
1986
- onTagged: function(doclet, tag) {
1987
- doclet.final_ = true;
1988
- }
1989
- });
1990
-
1991
- /**
1992
- * Introduce a new kind of symbol: 'interface'
1993
- * 'interface' is like 'class', but without a constructor.
1994
- * Support for 'interface' might not be complete (only standard UI5 use cases tested)
1995
- */
1996
- dictionary.defineTag('interface', {
1997
- //mustNotHaveValue: true,
1998
- onTagged: function(doclet, tag) {
1999
- // debug("setting kind of " + doclet.name + " to 'interface'");
2000
- doclet.kind = 'interface';
2001
- if ( tag.value ) {
2002
- doclet.classdesc = tag.value;
2003
- }
2004
- }
2005
- });
2006
-
2007
- /**
2008
- * Classes can declare that they implement a set of interfaces
2009
- */
2010
- dictionary.defineTag('implements', {
2011
- mustHaveValue: true,
2012
- onTagged: function(doclet, tag) {
2013
- // console.log("setting implements of " + doclet.name + " to 'interface'");
2014
- if ( tag.value ) {
2015
- doclet.implements = doclet.implements || [];
2016
- tag.value.split(/\s*,\s*/g).forEach(function($) {
2017
- if ( doclet.implements.indexOf($) < 0 ) {
2018
- doclet.implements.push($);
2019
- }
2020
- });
2021
- }
2022
- }
2023
- });
2024
-
2025
- /**
2026
- * Set the visibility of a doclet to 'restricted'.
2027
- */
2028
- dictionary.defineTag('ui5-restricted', {
2029
- onTagged: function(doclet, tag) {
2030
- doclet.access = 'restricted';
2031
- if ( tag.value ) {
2032
- ui5data(doclet).stakeholders = tag.value.trim().split(/(?:\s*,\s*|\s+)/);
2033
- }
2034
- }
2035
- });
2036
- dictionary.defineSynonym('ui5-restricted', 'sap-restricted');
2037
-
2038
- /**
2039
- * Mark a doclet as synthetic.
2040
- *
2041
- * Used for doclets that the autodoc generation creates. This helps the template
2042
- * later to recognize such doclets and maybe filter them out.
2043
- */
2044
- dictionary.defineTag('synthetic', {
2045
- mustNotHaveValue: true,
2046
- onTagged: function(doclet, tag) {
2047
- doclet.synthetic = true;
2048
- }
2049
- });
2050
-
2051
- /**
2052
- * Mark a doclet that intentionally updates a previous doclet
2053
- */
2054
- dictionary.defineTag('ui5-updated-doclet', {
2055
- mustNotHaveValue: true,
2056
- onTagged: function(doclet, tag) {
2057
- ui5data(doclet).updatedDoclet = true;
2058
- }
2059
- });
2060
-
2061
- /**
2062
- * The @hideconstructor tag tells JSDoc that the generated documentation should not display the constructor for a class.
2063
- * Note: this tag will be natively available in JSDoc >= 3.5.0
2064
- */
2065
- dictionary.defineTag('hideconstructor', {
2066
- mustNotHaveValue: true,
2067
- onTagged: function(doclet, tag) {
2068
- doclet.hideconstructor = true;
2069
- }
2070
- });
2071
-
2072
- dictionary.defineTag('slot', {
2073
- onTagged: function(doclet, tag) {
2074
- doclet.slot = true;
2075
- if (tag.value) {
2076
- doclet.propertyName = tag.value;
2077
- }
2078
- }
2079
- });
2080
-
2081
- dictionary.defineTag('appenddocs', {
2082
- mustHaveValue: false,
2083
- onTagged: function(doclet, tag) {
2084
- doclet.appenddocs = tag.value;
2085
- }
2086
- });
2087
-
2088
- dictionary.defineTag('tagname', {
2089
- mustHaveValue: true,
2090
- onTagged: function(doclet, tag) {
2091
- doclet.tagname = tag.value;
2092
- }
2093
- });
2094
-
2095
- dictionary.defineTag('allowPreventDefault', {
2096
- mustHaveValue: false,
2097
- onTagged: function(doclet, tag) {
2098
- doclet.allowPreventDefault = true;
2099
- }
2100
- });
2101
-
2102
- dictionary.defineTag('native', {
2103
- mustHaveValue: false,
2104
- onTagged: function(doclet, tag) {
2105
- doclet.native = true;
2106
- }
2107
- });
2108
-
2109
- dictionary.defineTag('noattribute', {
2110
- mustHaveValue: false,
2111
- onTagged: function(doclet, tag) {
2112
- doclet.noattribute = true;
2113
- }
2114
- });
2115
-
2116
- dictionary.defineTag('formEvents', {
2117
- mustHaveValue: false,
2118
- onTagged: function(doclet, tag) {
2119
- if (tag.value) {
2120
- doclet.formEvents = doclet.formEvents || [];
2121
- tag.value.split(" ").forEach(function($) {
2122
- if ( doclet.formEvents.indexOf($) < 0 ) {
2123
- doclet.formEvents.push($);
2124
- }
2125
- });
2126
- }
2127
- }
2128
- });
2129
-
2130
- dictionary.defineTag('formProperty', {
2131
- mustHaveValue: false,
2132
- onTagged: function(doclet, tag) {
2133
- doclet.formProperty = true;
2134
- }
2135
- });
2136
-
2137
- dictionary.defineTag('formAssociated', {
2138
- mustHaveValue: false,
2139
- onTagged: function(doclet, tag) {
2140
- doclet.formAssociated = doclet.formAssociated || true;
2141
- }
2142
- });
2143
- };
2144
-
2145
- exports.handlers = {
2146
-
2147
- /**
2148
- * Before all files are parsed, determine the common path prefix of all filenames
2149
- */
2150
- parseBegin : function(e) {
2151
-
2152
- pathPrefixes = env.opts._.reduce(function(result, fileOrDir) {
2153
- fileOrDir = path.resolve( path.normalize(fileOrDir) );
2154
- if ( fs.statSync(fileOrDir).isDirectory() ) {
2155
- // ensure a trailing path separator
2156
- if ( fileOrDir.indexOf(path.sep, fileOrDir.length - path.sep.length) < 0 ) {
2157
- fileOrDir += path.sep;
2158
- }
2159
- result.push(fileOrDir);
2160
- }
2161
- return result;
2162
- }, []);
2163
- resourceNamePrefixes = pluginConfig.resourceNamePrefixes || [];
2164
- if ( !Array.isArray(resourceNamePrefixes) ) {
2165
- resourceNamePrefixes = [resourceNamePrefixes];
2166
- }
2167
- resourceNamePrefixes.forEach(ensureEndingSlash);
2168
- while ( resourceNamePrefixes.length < pathPrefixes.length ) {
2169
- resourceNamePrefixes.push('');
2170
- }
2171
-
2172
- debug("path prefixes " + JSON.stringify(pathPrefixes));
2173
- debug("resource name prefixes " + JSON.stringify(resourceNamePrefixes));
2174
- },
2175
-
2176
- /**
2177
- * Log each file before it is parsed
2178
- */
2179
- fileBegin: function (e) {
2180
- currentProgram = undefined;
2181
- currentModule = {
2182
- name: null,
2183
- resource: getResourceName(e.filename),
2184
- module: getModuleName(getResourceName(e.filename)),
2185
- localNames: Object.create(null)
2186
- };
2187
- },
2188
-
2189
- fileComplete: function (e) {
2190
- // debug("module info after parsing: ", currentModule);
2191
- currentSource = undefined;
2192
- currentProgram = undefined;
2193
- currentModule = undefined;
2194
- },
2195
-
2196
- jsdocCommentFound: function(e) {
2197
- // console.log("jsdocCommentFound: " + e.comment);
2198
- e.comment = preprocessComment(e);
2199
- },
2200
-
2201
- symbolFound: function(e) {
2202
- // console.log("symbolFound: " + e.comment);
2203
- },
2204
-
2205
- newDoclet: function(e) {
2206
-
2207
- var _ui5data = ui5data(e.doclet);
2208
-
2209
- // remove code: this is a try to reduce the required heap size
2210
- if ( e.doclet.meta ) {
2211
- if ( e.doclet.meta.code ) {
2212
- e.doclet.meta.code = {};
2213
- }
2214
- var filepath = (e.doclet.meta.path && e.doclet.meta.path !== 'null' ) ? path.join(e.doclet.meta.path, e.doclet.meta.filename) : e.doclet.meta.filename;
2215
- e.doclet.meta.__shortpath = getRelativePath(filepath);
2216
- _ui5data.resource = currentModule.resource;
2217
- _ui5data.module = currentModule.name || currentModule.module;
2218
- }
2219
-
2220
-
2221
- // JSDoc 3 has a bug when it encounters a property in an object literal with an empty string as name
2222
- // (e.g. { "" : something } will result in a doclet without longname
2223
- if ( !e.doclet.longname ) {
2224
- if ( e.doclet.memberof ) {
2225
- e.doclet.longname = e.doclet.memberof + "." + e.doclet.name; // TODO '.' depends on scope?
2226
- warning("found doclet without longname, derived longname: " + e.doclet.longname + " " + location(e.doclet));
2227
- } else {
2228
- error("found doclet without longname, could not derive longname " + location(e.doclet));
2229
- }
2230
- return;
2231
- }
2232
-
2233
- // try to detect misused memberof
2234
- if ( e.doclet.memberof && e.doclet.longname.indexOf(e.doclet.memberof) !== 0 ) {
2235
- warning("potentially unsupported use of @name and @memberof " + location(e.doclet));
2236
- //console.log(e.doclet);
2237
- }
2238
-
2239
- if ( e.doclet.returns
2240
- && e.doclet.returns.length > 0
2241
- && e.doclet.returns[0]
2242
- && e.doclet.returns[0].type
2243
- && e.doclet.returns[0].type.names
2244
- && e.doclet.returns[0].type.names[0] === 'this'
2245
- && e.doclet.memberof ) {
2246
- warning("fixing return type 'this' with " + e.doclet.memberof);
2247
- e.doclet.returns[0].type.names[0] = e.doclet.memberof;
2248
- }
2249
- },
2250
-
2251
- beforeParse : function(e) {
2252
- msgHeader("parsing " + getRelativePath(e.filename));
2253
- currentSource = e.source;
2254
- },
2255
-
2256
- parseComplete : function(e) {
2257
-
2258
- var doclets = e.doclets;
2259
- var l = doclets.length,i,j,doclet;
2260
- //var noprivate = !env.opts.private;
2261
- var rAnonymous = /^<anonymous>(~|$)/;
2262
-
2263
- // remove undocumented symbols, ignored symbols, anonymous functions and their members, scope members
2264
- for (i = 0, j = 0; i < l; i++) {
2265
-
2266
- doclet = doclets[i];
2267
- if ( !doclet.undocumented &&
2268
- !doclet.ignore &&
2269
- !(doclet.memberof && rAnonymous.test(doclet.memberof)) &&
2270
- doclet.longname.indexOf("~") < 0 ) {
2271
- doclets[j++] = doclet;
2272
- }
2273
- }
2274
- if ( j < l ) {
2275
- doclets.splice(j, l - j);
2276
- info("removed " + (l - j) + " undocumented, ignored or anonymous symbols");
2277
- l = j;
2278
- }
2279
-
2280
- // sort doclets by name, synthetic, lineno, uid
2281
- // 'ignore' is a combination of criteria, see function above
2282
- debug("sorting doclets by name");
2283
- doclets.sort(function(a,b) {
2284
- if ( a.longname === b.longname ) {
2285
- if ( a.synthetic === b.synthetic ) {
2286
- if ( a.meta && b.meta && a.meta.filename == b.meta.filename ) {
2287
- if ( a.meta.lineno !== b.meta.lineno ) {
2288
- return a.meta.lineno < b.meta.lineno ? -1 : 1;
2289
- }
2290
- }
2291
- return a.__ui5.id - b.__ui5.id;
2292
- }
2293
- return a.synthetic && !b.synthetic ? -1 : 1;
2294
- }
2295
- return a.longname < b.longname ? -1 : 1;
2296
- });
2297
- debug("sorting doclets by name done.");
2298
-
2299
- for (i = 0, j = 0; i < l; i++) {
2300
-
2301
- doclet = doclets[i];
2302
-
2303
- // add metadata to symbol
2304
- if ( classInfos[doclet.longname] ) {
2305
- doclet.__ui5.metadata = classInfos[doclet.longname];
2306
-
2307
- // add designtime infos, if configured
2308
- var designtimeModule = doclet.__ui5.metadata.designtime;
2309
- if ( designtimeModule && typeof designtimeModule !== 'string' ) {
2310
- designtimeModule = doclet.__ui5.module + ".designtime";
2311
- }
2312
- if ( designtimeModule && designtimeInfos[designtimeModule] ) {
2313
- info("associating designtime data with class metadata: ", designtimeModule);
2314
- // TODO do a more generic merge or maybe add whole information as "designtime" information
2315
- doclet.__ui5.metadata.annotations = designtimeInfos[designtimeModule].annotations;
2316
- }
2317
-
2318
- // derive extends from UI5 APIs
2319
- if ( doclet.__ui5.metadata.baseType
2320
- && !(doclet.augments && doclet.augments.length > 0) ) {
2321
- doclet.augments = doclet.augments || [];
2322
- info(" @extends " + doclet.__ui5.metadata.baseType + " derived from UI5 APIs (" + doclet.longname + ")");
2323
- doclet.augments.push(doclet.__ui5.metadata.baseType);
2324
- }
2325
-
2326
- // derive interface implementations from UI5 metadata
2327
- if ( doclet.__ui5.metadata.interfaces && doclet.__ui5.metadata.interfaces.length ) {
2328
- doclet.__ui5.metadata.interfaces.forEach(function(intf) {
2329
- doclet.implements = doclet.implements || [];
2330
- if ( doclet.implements.indexOf(intf) < 0 ) {
2331
- info(" @implements " + intf + " derived from UI5 metadata (" + doclet.longname + ")");
2332
- doclet.implements.push(intf);
2333
- }
2334
- })
2335
- }
2336
- }
2337
-
2338
- if ( typeInfos[doclet.longname] ) {
2339
- doclet.__ui5.stereotype = 'datatype';
2340
- doclet.__ui5.metadata = {
2341
- basetype: typeInfos[doclet.longname].base,
2342
- pattern: typeInfos[doclet.longname].pattern,
2343
- range: typeInfos[doclet.longname].range
2344
- };
2345
- }
2346
-
2347
- // check for duplicates: last one wins
2348
- if ( j > 0 && doclets[j - 1].longname === doclet.longname ) {
2349
- if ( !doclets[j - 1].synthetic && !doclet.__ui5.updatedDoclet ) {
2350
- // replacing synthetic comments or updating comments are trivial case. Just log non-trivial duplicates
2351
- debug("ignoring duplicate doclet for " + doclet.longname + ":" + location(doclet) + " overrides " + location(doclets[j - 1]));
2352
- }
2353
- doclets[j - 1] = doclet;
2354
- } else {
2355
- doclets[j++] = doclet;
2356
- }
2357
- }
2358
-
2359
- if ( j < l ) {
2360
- doclets.splice(j, l - j);
2361
- info("removed " + (l - j) + " duplicate symbols - " + doclets.length + " remaining");
2362
- }
2363
-
2364
- if ( pluginConfig.saveSymbols ) {
2365
-
2366
- fs.mkPath(env.opts.destination);
2367
-
2368
- fs.writeFileSync(path.join(env.opts.destination, "symbols-parseComplete.json"), JSON.stringify(e.doclets, null, "\t"), 'utf8');
2369
-
2370
- }
2371
-
2372
- }
2373
- };
2374
-
2375
- exports.astNodeVisitor = {
2376
-
2377
- visitNode: function(node, e, parser, currentSourceName) {
2378
-
2379
-
2380
- var comment;
2381
-
2382
- if ( node.type === Syntax.Program ) {
2383
- currentProgram = node;
2384
- }
2385
-
2386
- function processExtendCall(extendCall, comment, commentAlreadyProcessed) {
2387
- var doclet = comment && new Doclet(getRawComment(comment), {});
2388
- var classInfo = collectClassInfo(extendCall, doclet);
2389
- if ( classInfo ) {
2390
- createAutoDoc(classInfo, comment, extendCall, parser, currentSourceName, commentAlreadyProcessed);
2391
- }
2392
- }
2393
-
2394
- function processDataType(createCall, comment) {
2395
- var doclet = comment && new Doclet(getRawComment(comment), {});
2396
- var typeInfo = collectDataTypeInfo(createCall, doclet);
2397
- if ( typeInfo ) {
2398
- createDataTypeAutoDoc(typeInfo, comment, createCall, parser, currentSourceName);
2399
- }
2400
- }
2401
-
2402
- if ( node.type === Syntax.ExpressionStatement ) {
2403
- if ( isSapUiDefineCall(node.expression) ) {
2404
- analyzeModuleDefinition(node.expression);
2405
- /*
2406
- } else if ( isJQuerySapDeclareCall(node.expression)
2407
- && node.expression.arguments.length > 0
2408
- && node.expression.arguments[0].type === Syntax.Literal
2409
- && typeof node.expression.arguments[0].value === "string" ) {
2410
- warning("module has explicit module name " + node.expression.arguments[0].value);
2411
- */
2412
- }
2413
-
2414
- }
2415
-
2416
- if (node.type === Syntax.ReturnStatement && node.argument && node.argument.type === Syntax.ObjectExpression && /\.designtime\.js$/.test(currentSourceName) ) {
2417
-
2418
- // assume this node to return designtime metadata. Collect it and remember it by its module name
2419
- var oDesigntimeInfo = collectDesigntimeInfo(node);
2420
- if ( oDesigntimeInfo ) {
2421
- designtimeInfos[currentModule.module] = oDesigntimeInfo;
2422
- info("collected designtime info " + currentModule.module);
2423
- }
2424
-
2425
- } else if ( node.type === Syntax.ExpressionStatement && isExtendCall(node.expression) ) {
2426
-
2427
- // Something.extend(...) -- return value (new class) is not used in an assignment
2428
-
2429
- // className = node.expression.arguments[0].value;
2430
- comment = getLeadingCommentNode(node) || getLeadingCommentNode(node.expression);
2431
- // console.log("ast node with comment " + comment);
2432
- processExtendCall(node.expression, comment);
2433
-
2434
- } else if ( node.type === Syntax.VariableDeclaration ) {
2435
- node.declarations.forEach(function(decl, idx) {
2436
- if ( isExtendCall(decl.init) ) {
2437
- // var NewClass = Something.extend(...)
2438
-
2439
- // className = node.declarations[0].init.arguments[0].value;
2440
- comment = (idx === 0 ? getLeadingCommentNode(node) : undefined) || getLeadingCommentNode(decl);
2441
- // console.log("ast node with comment " + comment);
2442
- processExtendCall(decl.init, comment);
2443
- }
2444
- })
2445
-
2446
- } else if ( node.type === Syntax.ReturnStatement && isExtendCall(node.argument) ) {
2447
-
2448
- // return Something.extend(...)
2449
-
2450
- var className = node.argument.arguments[0].value;
2451
- comment = getLeadingCommentNode(node, className) || getLeadingCommentNode(node.argument, className);
2452
- // console.log("ast node with comment " + comment);
2453
- processExtendCall(node.argument, comment, true);
2454
- } else if ( node.type === Syntax.ExpressionStatement && node.expression.type === Syntax.AssignmentExpression ) {
2455
-
2456
- if ( isCreateDataTypeCall(node.expression.right) ) {
2457
-
2458
- // thisLib.TypeName = DataType.createType( ... )
2459
- comment = getLeadingCommentNode(node) || getLeadingCommentNode(node.expression);
2460
- processDataType(node.expression.right);
2461
- // TODO remember knowledge about type and its name (left hand side of assignment)
2462
-
2463
- }
2464
-
2465
- }
2466
- }
2467
-
2468
- };