@ui5/webcomponents-tools 0.0.0-e7dd012d7 → 0.0.0-ebd9a4db3

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