From 996c711885c8134d3c15ac67b398fdad1da3f4c3 Mon Sep 17 00:00:00 2001
From: Frank Weigel ' : options.beforeParagraph;
+ var afterParagraph = options.afterParagraph === undefined ? '
';
+ });
+ }
+
+ result = this._preProcessLinksInTextBlock(result);
+ return result;
+ },
+
+ /**
+ * Formats the namespace of annotations
+ * @param namespace - the namespace to be formatted
+ * @returns string - the formatted text
+ */
+ formatAnnotationNamespace: function (namespace) {
+ var result,
+ aNamespaceParts = namespace.split(".");
+
+ if (aNamespaceParts[0] === "Org" && aNamespaceParts[1] === "OData") {
+ result = '' + namespace + '';
+ } else {
+ result = namespace;
+ }
+
+ result = this._preProcessLinksInTextBlock(result);
+ return result;
+ },
+
+ /**
+ * Formats the description of annotations
+ * @param description - the description of the annotation
+ * @param since - the since version information of the annotation
+ * @returns string - the formatted description
+ */
+ formatAnnotationDescription: function (description, since) {
+ var result = description || "";
+
+ result += '
For more information, see ' + 'OData v4 Annotations';
+
+ if (since) {
+ result += '
Since: ' + since + '.';
+ }
+
+ result = this._preProcessLinksInTextBlock(result);
+ return result;
+ },
+
+ formatExceptionLink: function (linkText) {
+ linkText = linkText || '';
+ return linkText.indexOf('sap.ui.') !== -1;
+ },
+
+ formatMethodCode: function (sName, aParams, aReturnValue) {
+ var result = '' + sName + '(';
+
+ if (aParams && aParams.length > 0) {
+ /* We consider only root level parameters so we get rid of all that are not on the root level */
+ aParams = aParams.filter(oElem => {
+ return oElem.depth === undefined;
+ });
+ aParams.forEach(function (element, index, array) {
+ result += element.name;
+
+ if (element.optional) {
+ result += '?';
+ }
+
+ if (index < array.length - 1) {
+ result += ', ';
+ }
+ });
+ }
+
+ result += ') : ';
+
+ if (aReturnValue) {
+ result += aReturnValue.type;
+ } else {
+ result += 'void';
+ }
+
+ result += "
";
+
+ return result;
+ },
+
+ /**
+ * Formats method deprecation message and pre-process jsDoc link and code blocks
+ * @param {string} sSince since text
+ * @param {string} sDescription deprecation description text
+ * @returns {string} formatted deprecation message
+ */
+ formatMethodDeprecated: function (sSince, sDescription) {
+ return this.formatDeprecated(sSince, sDescription, "methods");
+ },
+
+ /**
+ * Formats event deprecation message and pre-process jsDoc link and code blocks
+ * @param {string} sSince since text
+ * @param {string} sDescription deprecation description text
+ * @returns {string} formatted deprecation message
+ */
+ formatEventDeprecated: function (sSince, sDescription) {
+ return this.formatDeprecated(sSince, sDescription, "events");
+ },
+
+ /**
+ * Formats the description of control properties
+ * @param description - the description of the property
+ * @param since - the since version information of the property
+ * @returns string - the formatted description
+ */
+ formatDescriptionSince: function (description, since) {
+ var result = description || "";
+
+ if (since) {
+ result += '
Since: ' + since + '.';
+ }
+
+ result = this._preProcessLinksInTextBlock(result);
+ return result;
+ },
+
+ /**
+ * Formats the default value of the property as a string.
+ * @param defaultValue - the default value of the property
+ * @returns string - The default value of the property formatted as a string.
+ */
+ formatDefaultValue: function (defaultValue) {
+ var sReturn;
+
+ switch (defaultValue) {
+ case null:
+ case undefined:
+ sReturn = '';
+ break;
+ case '':
+ sReturn = 'empty string';
+ break;
+ default:
+ sReturn = defaultValue;
+ }
+
+ return Array.isArray(sReturn) ? sReturn.join(', ') : sReturn;
+ },
+
+ /**
+ * Formats the constructor of the class
+ * @param name
+ * @param params
+ * @returns string - The code needed to create an object of that class
+ */
+ formatConstructor: function (name, params) {
+ var result = 'new ';
+
+ if (name) {
+ result += name + '(';
+ }
+
+ if (params) {
+ params.forEach(function (element, index, array) {
+ result += element.name;
+
+ if (element.optional) {
+ result += '?';
+ }
+
+ if (index < array.length - 1) {
+ result += ', ';
+ }
+ });
+ }
+
+ if (name) {
+ result += ')
';
+ }
+
+ return result;
+ },
+
+ formatExample: function (sCaption, sText) {
+ return this.formatDescription(
+ ["Example: ",
+ sCaption,
+ "",
+ sText,
+ "
"].join("")
+ );
+ },
+
+ /**
+ * Formats the name of a property or a method depending on if it's static or not
+ * @param sName {string} - Name
+ * @param sClassName {string} - Name of the class
+ * @param bStatic {boolean} - If it's static
+ * @returns {string} - Formatted name
+ */
+ formatEntityName: function (sName, sClassName, bStatic) {
+ return (bStatic === true) ? sClassName + "." + sName : sName;
+ },
+
+ JSDocUtil: function () {
+
+ var rEscapeRegExp = /[[\]{}()*+?.\\^$|]/g;
+
+ // Local mocked methods
+ var escapeRegExp = function escapeRegExp(sString) {
+ return sString.replace(rEscapeRegExp, "\\$&");
+ };
+
+ function defaultLinkFormatter(target, text) {
+ return "" + (text || target) + "
";
+ }
+
+ function format(src, options) {
+
+ options = options || {};
+ var beforeParagraph = options.beforeParagraph === undefined ? ' block -] [---- some header ----] [---- an inline [@link ...} tag ----] [---------- an empty line ---------] */
+ var r = /(
)|(<\/pre>)|(
Documentation links:";
+
+ iLen = aReferences.length;
+ for (i = 0; i < iLen; i++) {
+ // We treat references as links but as they may not be defined as such we enforce it if needed
+ if (/{@link.*}/.test(aReferences[i])) {
+ sDescription += "
";
+ }
+
+ // Calling formatDescription so it could handle further formatting
+ return this.formatDescription(sDescription);
+ },
+
+ /**
+ * Formats the description of the property
+ * @param description - the description of the property
+ * @param deprecatedText - the text explaining this property is deprecated
+ * @param deprecatedSince - the version when this property was deprecated
+ * @returns string - the formatted description
+ */
+ formatDescription: function (description, deprecatedText, deprecatedSince) {
+ if (!description && !deprecatedText && !deprecatedSince) {
+ return "";
+ }
+
+ var result = description || "";
+
+ if (deprecatedSince || deprecatedText) {
+ // Note: sapUiDocumentationDeprecated - transformed to sapUiDeprecated to keep json file size low
+ result += "
";
+
+ result += this.formatDeprecated(deprecatedSince, deprecatedText);
+
+ result += "";
+ }
+
+ result = this._preProcessLinksInTextBlock(result);
+ return result;
+ },
+
+ /**
+ * Formats the entity deprecation message and pre-process jsDoc link and code blocks
+ * @param {string} sSince since text
+ * @param {string} sDescription deprecation description text
+ * @param {string} sEntityType string representation of entity type
+ * @returns {string} formatted deprecation message
+ */
+ formatDeprecated: function (sSince, sDescription, sEntityType) {
+ var aResult;
+
+ // Build deprecation message
+ // Note: there may be no since or no description text available
+ aResult = ["Deprecated"];
+ if (sSince) {
+ aResult.push(" as of version " + sSince);
+ }
+ if (sDescription) {
+ // Evaluate code blocks - Handle ...
pattern
+ sDescription = sDescription.replace(/(\S+)<\/code>/gi, function (sMatch, sCodeEntity) {
+ return ['', sCodeEntity, ''].join("");
+ }
+ );
+
+ // Evaluate links in the deprecation description
+ aResult.push(". " + this._preProcessLinksInTextBlock(sDescription, true));
+ }
+
+ return aResult.join("");
+ },
+
+ _formatChildDescription: function (description) {
+ if (description) {
+ return this._extractFirstSentence(description);
+ }
+ },
+
+ /** Just the first sentence (up to a full stop). Should not break on dotted variable names. */
+ _extractFirstSentence: function(desc) {
+ if ( desc ) {
+ desc = String(desc).replace(/\s+/g, ' ').
+ replace(/^(<\/?p>|
|mSettings
that defines initial",
+ "property values, aggregated and associated objects as well as event handlers.",
+ "See {@link sap.ui.base.ManagedObject#constructor} for a general description of the syntax of the settings object."
+ );
+ }
+
+ // add the settings section only if there are any settings
+ if ( !isEmpty(oClassInfo.properties)
+ || !isEmpty(oClassInfo.aggregations)
+ || !isEmpty(oClassInfo.associations)
+ || !isEmpty(oClassInfo.events) ) {
+
+ lines.push(
+ "",
+ includeSettings ? "" : "@ui5-settings",
+ "The supported settings are:",
+ ""
+ );
+ if ( !isEmpty(oClassInfo.properties) ) {
+ lines.push("
");
+
+ // add the reference to the base class only if this is not ManagedObject and if the base class is known
+ if ( oClassInfo.name !== "sap.ui.base.ManagedObject" && oClassInfo.baseType ) {
+ lines.push(
+ "",
+ "In addition, all settings applicable to the base type {@link " + oClassInfo.baseType + "#constructor " + oClassInfo.baseType + "}",
+ "can be used as well."
+ );
+ }
+ lines.push("");
+
+ } else if ( oClassInfo.name !== "sap.ui.base.ManagedObject" && oClassInfo.baseType && oClassInfo.hasOwnProperty("abstract") ) {
+
+ // if a class has no settings, but metadata, point at least to the base class - if it makes sense
+ lines.push(
+ "",
+ newStyle && !includeSettings ? "@ui5-settings" : "",
+ "This class does not have its own settings, but all settings applicable to the base type",
+ "{@link " + oClassInfo.baseType + "#constructor " + oClassInfo.baseType + "} can be used."
+ );
+
+ }
+ }
+
+ debug(" enhancing constructor documentation with settings");
+ var enhancedComment =
+ rawClassComment.slice(0,p) +
+ "\n * " + removeDuplicateEmptyLines(lines).join("\n * ") +
+ (commentAlreadyProcessed ? "@ui5-updated-doclet\n * " : "") +
+ rawClassComment.slice(p);
+ enhancedComment = preprocessComment({ comment : enhancedComment, lineno : classComment.lineno });
+
+ if ( commentAlreadyProcessed ) {
+ jsdocCommentFound(enhancedComment);
+ } else {
+ setRawComment(classComment, enhancedComment);
+ }
+
+ }
+
+ newJSDoc([
+ "Returns a metadata object for class " + oClassInfo.name + ".",
+ "",
+ "@returns {sap.ui.base.Metadata} Metadata object describing this class",
+ "@public",
+ "@static",
+ "@name " + name("getMetadata", "", true),
+ "@function"
+ ]);
+
+ if ( !oClassInfo["final"] ) {
+ newJSDoc([
+ "Creates a new subclass of class " + oClassInfo.name + " with name ");
+ for (n in oClassInfo.properties) {
+ lines.push("
");
+ lines.push("");
+ for (n in oClassInfo.aggregations) {
+ if ( oClassInfo.aggregations[n].visibility !== "hidden" ) {
+ lines.push("
");
+ lines.push("");
+ for (n in oClassInfo.associations) {
+ lines.push("
");
+ lines.push("");
+ for (n in oClassInfo.events) {
+ lines.push("
");
+ lines.push("sClassName
",
+ "and enriches it with the information contained in oClassInfo
.",
+ "",
+ "oClassInfo
might contain the same kind of information as described in {@link " + (oClassInfo.baseType ? oClassInfo.baseType + ".extend" : "sap.ui.base.Object.extend Object.extend") + "}.",
+ "",
+ "@param {string} sClassName Name of the class being created",
+ "@param {object} [oClassInfo] Object literal with information about the class",
+ "@param {function} [FNMetaImpl] Constructor function for the metadata object; if not given, it defaults to sap.ui.core.ElementMetadata
",
+ "@returns {function} Created class / constructor function",
+ "@public",
+ "@static",
+ "@name " + name("extend", "", true),
+ "@function"
+ ]);
+ }
+
+ for (n in oClassInfo.properties ) {
+ info = oClassInfo.properties[n];
+ if ( info.visibility === 'hidden' ) {
+ continue;
+ }
+ // link = newStyle ? "{@link #setting:" + n + " " + n + "}" : "" + n + "
";
+ link = "{@link " + (newStyle ? "#setting:" + n : rname("get", n)) + " " + n + "}";
+ newJSDoc([
+ "Gets current value of property " + link + ".",
+ "",
+ !newStyle && info.doc ? info.doc : "",
+ "",
+ info.defaultValue !== null ? "Default value is " + (info.defaultValue === "" ? "empty string" : info.defaultValue) + "
." : "",
+ "@returns {" + info.type + "} Value of property " + n + "
",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("get",n),
+ "@function"
+ ]);
+ newJSDoc([
+ "Sets a new value for property " + link + ".",
+ "",
+ !newStyle && info.doc ? info.doc : "",
+ "",
+ "When called with a value of null
or undefined
, the default value of the property will be restored.",
+ "",
+ info.defaultValue !== null ? "Default value is " + (info.defaultValue === "" ? "empty string" : info.defaultValue) + "
." : "",
+ "@param {" + info.type + "} " + varname(n,info.type,true) + " New value for property " + n + "
",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("set",n),
+ "@function"
+ ]);
+ if ( info.bindable ) {
+ newJSDoc([
+ "Binds property " + link + " to model data.",
+ "",
+ "See {@link sap.ui.base.ManagedObject#bindProperty ManagedObject.bindProperty} for a ",
+ "detailed description of the possible properties of oBindingInfo
",
+ "@param {object} oBindingInfo The binding information",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("bind",n),
+ "@function"
+ ]);
+ newJSDoc([
+ "Unbinds property " + link + " from model data.",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("unbind",n),
+ "@function"
+ ]);
+ }
+ }
+
+ for (n in oClassInfo.aggregations ) {
+ info = oClassInfo.aggregations[n];
+ if ( info.visibility === 'hidden' ) {
+ continue;
+ }
+ // link = newStyle ? "{@link #setting:" + n + " " + n + "}" : "" + n + "
";
+ link = "{@link " + (newStyle ? "#setting:" + n : rname("get", n)) + " " + n + "}";
+ newJSDoc([
+ "Gets content of aggregation " + link + ".",
+ "",
+ !newStyle && info.doc ? info.doc : "",
+ "",
+ n === info.defaultAggregation ? "Note: this is the default aggregation for " + n + "." : "",
+ "@returns {" + makeTypeString(info) + "}",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("get",n),
+ "@function"
+ ]);
+ if ( info.cardinality == "0..n" ) {
+ n1 = info.singularName;
+ newJSDoc([
+ "Inserts a " + n1 + " into the aggregation " + link + ".",
+ "",
+ "@param {" + makeTypeString(info, true) + "}",
+ " " + varname(n1,info.altTypes ? "variant" : info.type) + " The " + n1 + " to insert; if empty, nothing is inserted",
+ "@param {int}",
+ " iIndex The 0
-based index the " + n1 + " should be inserted at; for",
+ " a negative value of iIndex
, the " + n1 + " is inserted at position 0; for a value",
+ " greater than the current size of the aggregation, the " + n1 + " is inserted at",
+ " the last position",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("insert",n1),
+ "@function"
+ ]);
+ newJSDoc([
+ "Adds some " + n1 + " to the aggregation " + link + ".",
+
+ "@param {" + makeTypeString(info, true) + "}",
+ " " + varname(n1,info.altTypes ? "variant" : info.type) + " The " + n1 + " to add; if empty, nothing is inserted",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("add",n1),
+ "@function"
+ ]);
+ newJSDoc([
+ "Removes a " + n1 + " from the aggregation " + link + ".",
+ "",
+ "@param {int | string | " + makeTypeString(info, true) + "} " + varname(n1,"variant") + " The " + n1 + " to remove or its index or id",
+ "@returns {" + makeTypeString(info, true) + "} The removed " + n1 + " or null
",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("remove", n1),
+ "@function"
+ ]);
+ newJSDoc([
+ "Removes all the controls from the aggregation " + link + ".",
+ "",
+ "Additionally, it unregisters them from the hosting UIArea.",
+ "@returns {" + makeTypeString(info) + "} An array of the removed elements (might be empty)",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("removeAll", n),
+ "@function"
+ ]);
+ newJSDoc([
+ "Checks for the provided " + info.type + "
in the aggregation " + link + ".",
+ "and returns its index if found or -1 otherwise.",
+ "@param {" + makeTypeString(info, true) + "}",
+ " " + varname(n1, info.altTypes ? "variant" : info.type) + " The " + n1 + " whose index is looked for",
+ "@returns {int} The index of the provided control in the aggregation if found, or -1 otherwise",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("indexOf", n1),
+ "@function"
+ ]);
+ } else {
+ newJSDoc([
+ "Sets the aggregated " + link + ".",
+ "@param {" + makeTypeString(info) + "} " + varname(n, info.altTypes ? "variant" : info.type) + " The " + n + " to set",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("set", n),
+ "@function"
+ ]);
+ }
+ newJSDoc([
+ "Destroys " + (info.cardinality === "0..n" ? "all " : "") + "the " + n + " in the aggregation " + link + ".",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("destroy", n),
+ "@function"
+ ]);
+ if ( info.bindable ) {
+ newJSDoc([
+ "Binds aggregation " + link + " to model data.",
+ "",
+ "See {@link sap.ui.base.ManagedObject#bindAggregation ManagedObject.bindAggregation} for a ",
+ "detailed description of the possible properties of oBindingInfo
.",
+ "@param {object} oBindingInfo The binding information",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("bind",n),
+ "@function"
+ ]);
+ newJSDoc([
+ "Unbinds aggregation " + link + " from model data.",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("unbind",n),
+ "@function"
+ ]);
+ }
+ }
+
+ for (n in oClassInfo.associations ) {
+ info = oClassInfo.associations[n];
+ if ( info.visibility === 'hidden' ) {
+ continue;
+ }
+ // link = newStyle ? "{@link #setting:" + n + " " + n + "}" : "" + n + "
";
+ link = "{@link " + (newStyle ? "#setting:" + n : rname("get", n)) + " " + n + "}";
+ newJSDoc([
+ info.cardinality === "0..n" ?
+ "Returns array of IDs of the elements which are the current targets of the association " + link + "." :
+ "ID of the element which is the current target of the association " + link + ", or null
.",
+ "",
+ newStyle && info.doc ? info.doc : "",
+ "",
+ "@returns {sap.ui.core.ID" + (info.cardinality === "0..n" ? "[]" : "") + "}",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("get",n),
+ "@function"
+ ]);
+ if ( info.cardinality === "0..n" ) {
+ n1 = info.singularName;
+ newJSDoc([
+ "Adds some " + n1 + " into the association " + link + ".",
+ "",
+ "@param {sap.ui.core.ID | " + info.type + "} " + varname(n1, "variant") + " The " + n + " to add; if empty, nothing is inserted",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("add",n1),
+ "@function"
+ ]);
+ newJSDoc([
+ "Removes an " + n1 + " from the association named " + link + ".",
+ "@param {int | sap.ui.core.ID | " + info.type + "} " + varname(n1,"variant") + " The " + n1 + " to be removed or its index or ID",
+ "@returns {sap.ui.core.ID} The removed " + n1 + " or null
",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("remove", n1),
+ "@function"
+ ]);
+ newJSDoc([
+ "Removes all the controls in the association named " + link + ".",
+ "@returns {sap.ui.core.ID[]} An array of the removed elements (might be empty)",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("removeAll", n),
+ "@function"
+ ]);
+ } else {
+ newJSDoc([
+ "Sets the associated " + link + ".",
+ "@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",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("set", n),
+ "@function"
+ ]);
+ }
+ }
+
+ for (n in oClassInfo.events ) {
+ info = oClassInfo.events[n];
+ //link = newStyle ? "{@link #event:" + n + " " + n + "}" : "" + n + "
";
+ link = "{@link #event:" + n + " " + n + "}";
+
+ lines = [
+ info.doc ? info.doc : "",
+ "",
+ "@name " + oClassInfo.name + "#" + n,
+ "@event",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@param {sap.ui.base.Event} oControlEvent",
+ "@param {sap.ui.base.EventProvider} oControlEvent.getSource",
+ "@param {object} oControlEvent.getParameters"
+ ];
+ for (pName in info.parameters ) {
+ lines.push(
+ "@param {" + (info.parameters[pName].type || "") + "} oControlEvent.getParameters." + pName + " " + (info.parameters[pName].doc || "")
+ );
+ }
+ lines.push("@public");
+ newJSDoc(lines);
+
+ newJSDoc([
+ "Attaches event handler fnFunction
to the " + link + " event of this " + oClassInfo.name + "
.",
+ "",
+ "When called, the context of the event handler (its this
) will be bound to oListener
if specified, ",
+ "otherwise it will be bound to this " + oClassInfo.name + "
itself.",
+ "",
+ !newStyle && info.doc ? info.doc : "",
+ "",
+ "@param {object}",
+ " [oData] An application-specific payload object that will be passed to the event handler along with the event object when firing the event",
+ "@param {function}",
+ " fnFunction The function to be called when the event occurs",
+ "@param {object}",
+ " [oListener] Context object to call the event handler with. Defaults to this " + oClassInfo.name + "
itself",
+ "",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ "@public",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@name " + name("attach", n),
+ "@function"
+ ]);
+ newJSDoc([
+ "Detaches event handler fnFunction
from the " + link + " event of this " + oClassInfo.name + "
.",
+ "",
+ "The passed function and listener object must match the ones used for event registration.",
+ "",
+ "@param {function}",
+ " fnFunction The function to be called, when the event occurs",
+ "@param {object}",
+ " oListener Context object on which the given function had to be called",
+ "@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@public",
+ "@name " + name("detach", n),
+ "@function"
+ ]);
+
+ // build documentation for fireEvent. It contains conditional parts which makes it a bit more complicated
+ lines = [
+ "Fires event " + link + " to attached listeners."
+ ];
+ if ( info.allowPreventDefault ) {
+ lines.push(
+ "",
+ "Listeners may prevent the default action of this event by using the preventDefault
-method on the event object.",
+ "");
+ }
+ lines.push(
+ "",
+ "@param {object} [mParameters] Parameters to pass along with the event"
+ );
+ if ( !isEmpty(info.parameters) ) {
+ for (pName in info.parameters) {
+ lines.push(
+ "@param {" + (info.parameters[pName].type || "any") + "} [mParameters." + pName + "] " + (info.parameters[pName].doc || "")
+ );
+ }
+ lines.push("");
+ }
+ if ( info.allowPreventDefault ) {
+ lines.push("@returns {boolean} Whether or not to prevent the default action");
+ } else {
+ lines.push("@returns {" + oClassInfo.name + "} Reference to this
in order to allow method chaining");
+ }
+ lines.push(
+ "@protected",
+ info.since ? "@since " + info.since : "",
+ info.deprecation ? "@deprecated " + info.deprecation : "",
+ info.experimental ? "@experimental " + info.experimental : "",
+ "@name " + name("fire", n),
+ "@function"
+ );
+ newJSDoc(lines);
+ }
+
+}
+
+function createDataTypeAutoDoc(oTypeInfo, classComment, node, parser, filename) {
+}
+
+/**
+ * Creates a human readable location info for a given doclet.
+ * @param doclet
+ * @returns {String}
+ */
+function location(doclet) {
+ var filename = (doclet.meta && doclet.meta.filename) || "unknown";
+ return " #" + ui5data(doclet).id + "@" + filename + (doclet.meta.lineno != null ? ":" + doclet.meta.lineno : "") + (doclet.synthetic ? "(synthetic)" : "");
+}
+
+// ---- Comment handling ---------------------------------------------------------------------------
+
+// --- comment related functions that depend on the JSdoc version (e.g. on the used parser)
+
+var isDocComment;
+var getLeadingCommentNode;
+
+// JSDoc added the node type Syntax.File
with the same change that activated Babylon
+// See https://github.com/jsdoc3/jsdoc/commit/ffec4a42291de6d68e6240f304b68d6abb82a869
+if ( Syntax.File === 'File' ) {
+
+ // JSDoc starting with version 3.5.0
+
+ isDocComment = function isDocCommentBabylon(comment) {
+ return comment && comment.type === 'CommentBlock' && comment.value && comment.value.charAt(0) === '*';
+ }
+
+ getLeadingCommentNode = function getLeadingCommentNodeBabylon(node, longname) {
+ var leadingComments = node.leadingComments;
+ if ( Array.isArray(leadingComments) ) {
+ // in babylon, all comments are already attached to the node
+ // and the last one is the closest one and should win
+ // non-block comments have to be filtered out
+ leadingComments = leadingComments.filter(isDocComment);
+ if ( leadingComments.length > 0 ) {
+ return leadingComments[leadingComments.length - 1];
+ }
+ }
+ }
+
+} else {
+
+ // JSDoc versions before 3.5.0
+
+ isDocComment = function isDoccommentEsprima(comment) {
+ return comment && comment.type === 'Block';
+ };
+
+ getLeadingCommentNode = function getLeadingCommentNodeEsprima(node, longname) {
+ var comment,
+ leadingComments = node.leadingComments;
+
+ // when espree is used, JSDOc attached the leading comment and the first one was picked
+ if (Array.isArray(leadingComments) && leadingComments.length && leadingComments[0].raw) {
+ comment = leadingComments[0];
+ }
+
+ // also check all comments attached to the Program node (if found) whether they refer to the same longname
+ // TODO check why any matches here override the direct leading comment from above
+ if ( longname && currentProgram && currentProgram.leadingComments && currentProgram.leadingComments.length ) {
+ leadingComments = currentProgram.leadingComments;
+ var rLongname = new RegExp("@(name|alias|class|namespace)\\s+" + longname.replace(/\./g, '\\.'));
+ for ( var i = 0; i < leadingComments.length; i++ ) {
+ var raw = getRawComment(leadingComments[i]);
+ if ( /^\/\*\*[\s\S]*\*\/$/.test(raw) && rLongname.test(raw) ) {
+ comment = leadingComments[i];
+ // console.log("\n\n**** alternative comment found for " + longname + " on program level\n\n", comment);
+ break;
+ }
+ }
+ }
+
+ return comment;
+ }
+}
+
+//--- comment related functions that are independent from the JSdoc version
+
+function getLeadingComment(node) {
+ var comment = getLeadingCommentNode(node);
+ return comment ? getRawComment(comment) : null;
+}
+
+function getLeadingDoclet(node, preprocess) {
+ var comment = getLeadingComment(node)
+ if ( comment && preprocess ) {
+ comment = preprocessComment({comment:comment, lineno: node.loc.start.line });
+ }
+ return comment ? new Doclet(comment, {}) : null;
+}
+
+/**
+ * Determines the raw comment string (source code form, including leading and trailing comment markers / *...* /) from a comment node.
+ * Works for Esprima and Babylon based JSDoc versions.
+ * @param commentNode
+ * @returns
+ */
+function getRawComment(commentNode) {
+ // in esprima, there's a 'raw' property, in babylon, the 'raw' string has to be reconstructed from the 'value' by adding the markers
+ return commentNode ? commentNode.raw || '/*' + commentNode.value + '*/' : '';
+}
+
+function setRawComment(commentNode, newRawComment) {
+ if ( commentNode.raw ) {
+ commentNode.raw = newRawComment;
+ }
+ commentNode.value = newRawComment.slice(2, -2);
+}
+
+/**
+ * Removes the mandatory comment markers and the optional but common asterisks at the beginning of each JSDoc comment line.
+ *
+ * The result is easier to parse/analyze.
+ *
+ * Implementation is a 1:1 copy from JSDoc's lib/jsdoc/doclet.js (closure function, not directly reusable)
+ *
+ * @param {string} docletSrc the source comment with or without block comment markers
+ * @returns {string} the unwrapped content of the JSDoc comment
+ *
+ */
+function unwrap(docletSrc) {
+ if (!docletSrc) { return ''; }
+
+ // note: keep trailing whitespace for @examples
+ // extra opening/closing stars are ignored
+ // left margin is considered a star and a space
+ // use the /m flag on regex to avoid having to guess what this platform's newline is
+ docletSrc =
+ docletSrc.replace(/^\/\*\*+/, '') // remove opening slash+stars
+ .replace(/\**\*\/$/, "\\Z") // replace closing star slash with end-marker
+ .replace(/^\s*(\* ?|\\Z)/gm, '') // remove left margin like: spaces+star or spaces+end-marker
+ .replace(/\s*\\Z$/g, ''); // remove end-marker
+
+ return docletSrc;
+}
+
+/**
+ * Inverse operation of unwrap.
+ *
+ * The prefix for lines is fixed to be " * ", lines are separated with '\n', independent from the platform.
+ */
+function wrap(lines) {
+ if ( typeof lines === "string" ) {
+ lines = lines.split(/\r\n?|\n/);
+ }
+ return "/**\n * " + lines.join('\n * ') + "\n */";
+}
+
+/**
+ * Preprocesses a JSDoc comment string to ensure some UI5 standards.
+ *
+ * @param {event} e Event for the new comment
+ * @returns {event}
+ */
+function preprocessComment(e) {
+
+ var src = e.comment;
+
+ // add a default visibility
+ if ( !/@private|@public|@protected|@sap-restricted|@ui5-restricted/.test(src) ) {
+ src = unwrap(src);
+ src = src + "\n@private";
+ src = wrap(src);
+ // console.log("added default visibility to '" + src + "'");
+ }
+
+ if ( /@class/.test(src) && /@static/.test(src) ) {
+ warning("combination of @class and @static is no longer supported with jsdoc3, converting it to @namespace and @classdesc: (line " + e.lineno + ")");
+ src = unwrap(src);
+ src = src.replace(/@class/, "@classdesc").replace(/@static/, "@namespace");
+ src = wrap(src);
+ //console.log(src);
+ }
+
+ return src;
+
+}
+
+// ---- other functionality ---------------------------------------------------------------------------
+
+// HACK: override cli.exit() to avoid that JSDoc3 exits the VM
+if ( pluginConfig.noExit ) {
+ info("disabling exit() call");
+ require( path.join(global.env.dirname, 'cli') ).exit = function(retval) {
+ info("cli.exit(): do nothing (ret val=" + retval + ")");
+ };
+}
+
+
+// ---- exports ----------------------------------------------------------------------------------------
+
+exports.defineTags = function(dictionary) {
+
+ /**
+ * a special value that is not 'falsy' but results in an empty string when output
+ * Used for the disclaimer and experimental tag
+ */
+ var EMPTY = {
+ toString: function() { return ""; }
+ };
+
+ /**
+ * A sapui5 specific tag to add a disclaimer to a symbol
+ */
+ dictionary.defineTag('disclaimer', {
+ // value is optional
+ onTagged: function(doclet, tag) {
+ doclet.disclaimer = tag.value || EMPTY;
+ }
+ });
+
+ /**
+ * A sapui5 specific tag to mark a symbol as experimental.
+ */
+ dictionary.defineTag('experimental', {
+ // value is optional
+ onTagged: function(doclet, tag) {
+ doclet.experimental = tag.value || EMPTY;
+ }
+ });
+
+ /**
+ * Re-introduce the deprecated 'final tag. JSDoc used it as a synonym for readonly, but we use it to mark classes as final
+ */
+ dictionary.defineTag('final', {
+ mustNotHaveValue: true,
+ onTagged: function(doclet, tag) {
+ doclet.final_ = true;
+ }
+ });
+
+ /**
+ * Introduce a new kind of symbol: 'interface'
+ * 'interface' is like 'class', but without a constructor.
+ * Support for 'interface' might not be complete (only standard UI5 use cases tested)
+ */
+ dictionary.defineTag('interface', {
+ //mustNotHaveValue: true,
+ onTagged: function(doclet, tag) {
+ // debug("setting kind of " + doclet.name + " to 'interface'");
+ doclet.kind = 'interface';
+ if ( tag.value ) {
+ doclet.classdesc = tag.value;
+ }
+ }
+ });
+
+ /**
+ * Classes can declare that they implement a set of interfaces
+ */
+ dictionary.defineTag('implements', {
+ mustHaveValue: true,
+ onTagged: function(doclet, tag) {
+ // console.log("setting implements of " + doclet.name + " to 'interface'");
+ if ( tag.value ) {
+ doclet.implements = doclet.implements || [];
+ tag.value.split(/\s*,\s*/g).forEach(function($) {
+ if ( doclet.implements.indexOf($) < 0 ) {
+ doclet.implements.push($);
+ }
+ });
+ }
+ }
+ });
+
+ /**
+ * Set the visibility of a doclet to 'restricted'.
+ */
+ dictionary.defineTag('ui5-restricted', {
+ onTagged: function(doclet, tag) {
+ doclet.access = 'restricted';
+ if ( tag.value ) {
+ ui5data(doclet).stakeholders = tag.value.trim().split(/(?:\s*,\s*|\s+)/);
+ }
+ }
+ });
+ dictionary.defineSynonym('ui5-restricted', 'sap-restricted');
+
+ /**
+ * Mark a doclet as synthetic.
+ *
+ * Used for doclets that the autodoc generation creates. This helps the template
+ * later to recognize such doclets and maybe filter them out.
+ */
+ dictionary.defineTag('synthetic', {
+ mustNotHaveValue: true,
+ onTagged: function(doclet, tag) {
+ doclet.synthetic = true;
+ }
+ });
+
+ /**
+ * Mark a doclet that intentionally updates a previous doclet
+ */
+ dictionary.defineTag('ui5-updated-doclet', {
+ mustNotHaveValue: true,
+ onTagged: function(doclet, tag) {
+ ui5data(doclet).updatedDoclet = true;
+ }
+ });
+
+ /**
+ * The @hideconstructor tag tells JSDoc that the generated documentation should not display the constructor for a class.
+ * Note: this tag will be natively available in JSDoc >= 3.5.0
+ */
+ dictionary.defineTag('hideconstructor', {
+ mustNotHaveValue: true,
+ onTagged: function(doclet, tag) {
+ doclet.hideconstructor = true;
+ }
+ });
+
+};
+
+exports.handlers = {
+
+ /**
+ * Before all files are parsed, determine the common path prefix of all filenames
+ */
+ parseBegin : function(e) {
+
+ pathPrefixes = env.opts._.reduce(function(result, fileOrDir) {
+ fileOrDir = path.resolve( path.normalize(fileOrDir) );
+ if ( fs.statSync(fileOrDir).isDirectory() ) {
+ if ( !fileOrDir.endsWith(path.sep) ) {
+ fileOrDir += path.sep;
+ }
+ result.push(fileOrDir);
+ }
+ return result;
+ }, []);
+ resourceNamePrefixes = pluginConfig.resourceNamePrefixes || [];
+ if ( !Array.isArray(resourceNamePrefixes) ) {
+ resourceNamePrefixes = [resourceNamePrefixes];
+ }
+ resourceNamePrefixes.forEach(ensureEndingSlash);
+ while ( resourceNamePrefixes.length < pathPrefixes.length ) {
+ resourceNamePrefixes.push('');
+ }
+
+ debug("path prefixes " + JSON.stringify(pathPrefixes));
+ debug("resource name prefixes " + JSON.stringify(resourceNamePrefixes));
+ },
+
+ /**
+ * Log each file before it is parsed
+ */
+ fileBegin: function (e) {
+ currentProgram = undefined;
+ currentModule = {
+ name: null,
+ resource: getResourceName(e.filename),
+ module: getModuleName(getResourceName(e.filename)),
+ localNames: Object.create(null)
+ };
+ debug(currentModule);
+ },
+
+ fileComplete: function (e) {
+ currentSource = undefined;
+ currentProgram = undefined;
+ currentModule = undefined;
+ },
+
+ jsdocCommentFound: function(e) {
+ // console.log("jsdocCommentFound: " + e.comment);
+ e.comment = preprocessComment(e);
+ },
+
+ symbolFound: function(e) {
+ // console.log("symbolFound: " + e.comment);
+ },
+
+ newDoclet: function(e) {
+
+ var _ui5data = ui5data(e.doclet);
+
+ // remove code: this is a try to reduce the required heap size
+ if ( e.doclet.meta ) {
+ if ( e.doclet.meta.code ) {
+ e.doclet.meta.code = {};
+ }
+ 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;
+ e.doclet.meta.__shortpath = getRelativePath(filepath);
+ _ui5data.resource = currentModule.resource;
+ _ui5data.module = currentModule.name || currentModule.module;
+ }
+
+
+ // JSDoc 3 has a bug when it encounters a property in an object literal with an empty string as name
+ // (e.g. { "" : something } will result in a doclet without longname
+ if ( !e.doclet.longname ) {
+ if ( e.doclet.memberof ) {
+ e.doclet.longname = e.doclet.memberof + "." + e.doclet.name; // TODO '.' depends on scope?
+ warning("found doclet without longname, derived longname: " + e.doclet.longname + " " + location(e.doclet));
+ } else {
+ error("found doclet without longname, could not derive longname " + location(e.doclet));
+ }
+ return;
+ }
+
+ // try to detect misused memberof
+ if ( e.doclet.memberof && e.doclet.longname.indexOf(e.doclet.memberof) !== 0 ) {
+ warning("potentially unsupported use of @name and @memberof " + location(e.doclet));
+ //console.log(e.doclet);
+ }
+
+ if ( e.doclet.returns
+ && e.doclet.returns.length > 0
+ && e.doclet.returns[0]
+ && e.doclet.returns[0].type
+ && e.doclet.returns[0].type.names
+ && e.doclet.returns[0].type.names[0] === 'this'
+ && e.doclet.memberof ) {
+ warning("fixing return type 'this' with " + e.doclet.memberof);
+ e.doclet.returns[0].type.names[0] = e.doclet.memberof;
+ }
+ },
+
+ beforeParse : function(e) {
+ msgHeader("parsing " + getRelativePath(e.filename));
+ currentSource = e.source;
+ },
+
+ parseComplete : function(e) {
+
+ var doclets = e.doclets;
+ var l = doclets.length,i,j,doclet;
+ //var noprivate = !env.opts.private;
+ var rAnonymous = /^new
) or as a normal function.
+ * It always returns an immutable Version instance.
+ *
+ * The parts of the version number (major, minor, patch, suffix) can be provided in several ways:
+ *
+ *
+ *
+ * To keep the code size small, this implementation mainly validates the single string variant.
+ * All other variants are only validated to some degree. It is the responsibility of the caller to
+ * provide proper parts.
+ *
+ * @param {int|string|any[]|jQuery.sap.Version} vMajor the major part of the version (int) or any of the single parameter variants explained above.
+ * @param {int} iMinor the minor part of the version number
+ * @param {int} iPatch the patch part of the version number
+ * @param {string} sSuffix the suffix part of the version number
+ * @return {jQuery.sap.Version} the version object as determined from the parameters
+ *
+ * @class Represents a version consisting of major, minor, patch version and suffix, e.g. '1.2.7-SNAPSHOT'.
+ *
+ * @author SAP SE
+ * @version ${version}
+ * @constructor
+ * @public
+ * @since 1.15.0
+ * @name jQuery.sap.Version
+ */
+ function Version(versionStr) {
+
+ var match = rVersion.exec(versionStr) || [];
+
+ function norm(v) {
+ v = parseInt(v,10);
+ return isNaN(v) ? 0 : v;
+ }
+
+ Object.defineProperty(this, "major", {
+ enumerable: true,
+ value: norm(match[0])
+ });
+ Object.defineProperty(this, "minor", {
+ enumerable: true,
+ value: norm(match[1])
+ });
+ Object.defineProperty(this, "patch", {
+ enumerable: true,
+ value: norm(match[2])
+ });
+ Object.defineProperty(this, "suffix", {
+ enumerable: true,
+ value: String(match[3] || "")
+ });
+
+ }
+
+ Version.prototype.toMajorMinor = function() {
+ return new Version(this.major + "." + this.minor);
+ };
+
+ Version.prototype.toString = function() {
+ return this.major + "." + this.minor + "." + this.patch + this.suffix;
+ };
+
+ Version.prototype.compareTo = function(other) {
+ return this.major - other.major ||
+ this.minor - other.minor ||
+ this.patch - other.patch ||
+ ((this.suffix < other.suffix) ? -1 : (this.suffix === other.suffix) ? 0 : 1);
+ };
+
+ return Version;
+
+}());
+
+// ---- Link class --------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+//TODO move to separate module
+
+var Link = (function() {
+
+ var Link = function() {
+ };
+
+ Link.prototype.toSymbol = function(longname) {
+ if ( longname != null ) {
+ longname = String(longname);
+ if ( /#constructor$/.test(longname) ) {
+ if ( !this.innerName ) {
+ this.innerName = 'constructor';
+ }
+ longname = longname.slice(0, -"#constructor".length);
+ }
+ this.longname = longname;
+ }
+ return this;
+ };
+
+ Link.prototype.withText = function(text) {
+ this.text = text;
+ return this;
+ };
+
+ Link.prototype.withTooltip = function(text) {
+ this.tooltip = text;
+ return this;
+ };
+
+ Link.prototype.toFile = function(file) {
+ if ( file != null ) this.file = file;
+ return this;
+ };
+
+ function _makeLink(href, target, tooltip, text) {
+ return '' + text + '';
+ }
+
+ Link.prototype.toString = function() {
+ var longname = this.longname,
+ linkString;
+
+ if (longname) {
+
+ if ( /^(?:(?:ftp|https?):\/\/|\.\.?\/)/.test(longname) ) {
+ // handle real hyperlinks (TODO should be handled with a different "to" method
+ linkString = _makeLink(longname, this.targetName, this.tooltip, this.text || longname);
+ } else if ( /^topic:/.test(longname) ) {
+ // handle documentation links
+ longname = conf.topicUrlPattern.replace("{{topic}}", longname.slice("topic:".length));
+ linkString = _makeLink(longname, this.targetName, this.tooltip, this.text || longname);
+ } else {
+ linkString = this._makeSymbolLink(longname);
+ }
+
+ } else if (this.file) {
+ linkString = _makeLink(Link.base + this.file, this.targetName, null, this.text || this.file);
+ }
+
+ return linkString;
+ };
+
+ var missingTypes = {};
+ Link.getMissingTypes = function() {
+ return Object.keys(missingTypes);
+ };
+
+ Link.prototype._makeSymbolLink = function(longname) {
+
+ // normalize .prototype. and #
+ longname = longname.replace(/\.prototype\./g, '#');
+
+ // if it is an internal reference, then don't validate against symbols, just create a link
+ if ( longname.charAt(0) == "#" ) {
+
+ return _makeLink(longname + (this.innerName ? "#" + this.innerName : ""), this.targetName, this.tooltip, this.text || longname.slice(1));
+
+ }
+
+ var linkTo = lookup(longname);
+ // if there is no symbol by that name just return the name unaltered
+ if ( !linkTo ) {
+
+ missingTypes[longname] = true;
+
+ return this.text || longname;
+
+ }
+
+ // it's a full symbol reference (potentially to another file)
+ var mainSymbol, anchor;
+ if ( (linkTo.kind === 'member' && !linkTo.isEnum) || linkTo.kind === 'constant' || linkTo.kind === 'function' || linkTo.kind === 'event' ) { // it's a method or property
+
+ mainSymbol = linkTo.memberof;
+ anchor = ( linkTo.kind === 'event' ? "event:" : "") + Link.symbolNameToLinkName(linkTo);
+
+ } else {
+
+ mainSymbol = linkTo.longname;
+ anchor = this.innerName;
+
+ }
+
+ return _makeLink(Link.baseSymbols + __uniqueFilenames[mainSymbol] + conf.ext + (anchor ? "#" + anchor : ""), this.targetName, this.tooltip, this.text || longname);
+ }
+
+ Link.symbolNameToLinkName = function(symbol) {
+ var linker = "";
+ if ( symbol.scope === 'static' ) {
+ linker = ".";
+ } else if (symbol.isInner) {
+ linker = "-"; // TODO-migrate?
+ }
+ return linker + symbol.name;
+ };
+
+ return Link;
+
+}());
+
+
+
+// ---- publish() - main entry point for JSDoc templates -------------------------------------------------------------------------------------------------------
+
+/** Called automatically by JsDoc Toolkit. */
+function publish(symbolSet) {
+
+ info("entering sapui5 template");
+
+ // create output dir
+ fs.mkPath(env.opts.destination);
+
+// if ( symbolSet().count() < 20000 ) {
+// info("writing raw symbols to " + path.join(env.opts.destination, "symbols-unpruned-ui5.json"));
+// fs.writeFileSync(path.join(env.opts.destination, "symbols-unpruned-ui5.json"), JSON.stringify(symbolSet().get(), filter, "\t"), 'utf8');
+// }
+
+ info("before prune: " + symbolSet().count() + " symbols.");
+ symbolSet = helper.prune(symbolSet);
+ info("after prune: " + symbolSet().count() + " symbols.");
+
+ __db = symbolSet;
+ __longnames = {};
+ __db().each(function($) {
+ __longnames[$.longname] = $;
+ });
+
+ if ( templateConf.apiJsonFolder ) {
+ info("loading external apis from folder '" + templateConf.apiJsonFolder + "'");
+ loadExternalSymbols(templateConf.apiJsonFolder);
+ }
+
+ var templatePath = path.join(env.opts.template, 'tmpl/');
+ info("using templates from '" + templatePath + "'");
+ view = new template.Template(templatePath);
+
+ function filter(key,value) {
+ if ( key === 'meta' ) {
+ //return;
+ }
+ if ( key === '__ui5' && value ) {
+ var v = {
+ resource: value.resource,
+ module: value.module,
+ stakeholders: value.stakeholders
+ };
+ if ( value.derived ) {
+ v.derived = value.derived.map(function($) { return $.longname });
+ }
+ if ( value.base ) {
+ v.base = value.base.longname;
+ }
+ if ( value.implementations ) {
+ v.base = value.implementations.map(function($) { return $.longname });
+ }
+ if ( value.parent ) {
+ v.parent = value.parent.longname;
+ }
+ if ( value.children ) {
+ v.children = value.children.map(function($) { return $.longname });
+ }
+ return v;
+ }
+ return value;
+ }
+
+ // now resolve relationships
+ var aRootNamespaces = createNamespaceTree();
+ var hierarchyRoots = createInheritanceTree();
+ collectMembers();
+ mergeEventDocumentation();
+
+ if ( symbolSet().count() < 20000 ) {
+ info("writing raw symbols to " + path.join(env.opts.destination, "symbols-pruned-ui5.json"));
+ fs.writeFileSync(path.join(env.opts.destination, "symbols-pruned-ui5.json"), JSON.stringify(symbolSet().get(), filter, "\t"), 'utf8');
+ }
+
+ // used to allow Link to check the details of things being linked to
+ Link.symbolSet = symbolSet;
+
+ // get an array version of the symbol set, useful for filtering
+ var symbols = symbolSet().get();
+
+ // -----
+
+ var PUBLISHING_VARIANTS = {
+
+ "apixml" : {
+ defaults : {
+ apiXmlFile: path.join(env.opts.destination, "jsapi.xml")
+ },
+ processor : function(conf) {
+ createAPIXML(symbols, conf.apiXmlFile, {
+ legacyContent: true
+ });
+ }
+ },
+
+ "apijson" : {
+ defaults : {
+ apiJsonFile: path.join(env.opts.destination, "api.json")
+ },
+ processor : function(conf) {
+ createAPIJSON(symbols, conf.apiJsonFile);
+ }
+ },
+
+ "fullapixml" : {
+ defaults : {
+ fullXmlFile: path.join(env.opts.destination, "fulljsapi.xml")
+ },
+ processor : function(conf) {
+ createAPIXML(symbols, conf.fullXmlFile, {
+ roots: aRootNamespaces,
+ omitDefaults : conf.omitDefaultsInFullXml,
+ resolveInheritance: true
+ });
+ }
+ },
+
+ "apijs" : {
+ defaults: {
+ jsapiFile: path.join(env.opts.destination, "api.js")
+ },
+ processor: function(conf) {
+ createAPIJS(symbols, conf.jsapiFile);
+ }
+ },
+
+ "full" : {
+ defaults : {
+ outdir: path.join(env.opts.destination, "full/"),
+ contentOnly: false,
+ hierarchyIndex: true
+ },
+ processor: function() {
+ publishClasses(symbolSet, aRootNamespaces, hierarchyRoots);
+ }
+ },
+
+ "public" : {
+ defaults: {
+ outdir: path.join(env.opts.destination, "public/"),
+ filter: function($) { return $.access === 'public' || $.access === 'protected' || $.access == null; },
+ contentOnly: false,
+ hierarchyIndex: true
+ },
+ processor: function(conf) {
+ publishClasses(symbolSet, aRootNamespaces, hierarchyRoots);
+ }
+ },
+
+ "demokit" : {
+ defaults: {
+ outdir: path.join(env.opts.destination, "demokit/"),
+ filter: function($) { return $.access === 'public' || $.access === 'protected' || $.access == null; },
+ contentOnly: true,
+ modulePages: true,
+ hierarchyIndex: false,
+ securityIndex: true,
+ sinceIndex: true,
+ deprecationIndex: true,
+ experimentalIndex: true,
+ suppressAuthor: true,
+ suppressVersion: true
+ },
+ processor: function(conf) {
+ publishClasses(symbolSet, aRootNamespaces, hierarchyRoots);
+ }
+ },
+
+ "demokit-internal" : {
+ defaults: {
+ outdir: path.join(env.opts.destination, "demokit-internal/"),
+ // filter: function($) { return $.access === 'public' || $.access === 'protected' || $.access === 'restricted' || $.access == null; },
+ contentOnly: true,
+ modulePages: true,
+ hierarchyIndex: false,
+ securityIndex: true,
+ sinceIndex: true,
+ deprecationIndex: true,
+ experimentalIndex: true,
+ suppressAuthor: true,
+ suppressVersion: true
+ },
+ processor: function(conf) {
+ publishClasses(symbolSet, aRootNamespaces, hierarchyRoots);
+ }
+ }
+
+ };
+
+ var now = new Date();
+
+ info("start publishing");
+ for (var i = 0; i < templateConf.variants.length; i++) {
+
+ var vVariant = templateConf.variants[i];
+ if ( typeof vVariant === "string" ) {
+ vVariant = { variant : vVariant };
+ }
+
+ info("");
+
+ if ( PUBLISHING_VARIANTS[vVariant.variant] ) {
+
+ // Merge different sources of configuration (listed in increasing priority order - last one wins)
+ // and expose the result in the global 'conf' variable
+ // - global defaults
+ // - defaults for current variant
+ // - user configuration for sapui5 template
+ // - user configuration for current variant
+ //
+ // Note: trailing slash expected for dirs
+ conf = merge({
+ ext: ".html",
+ filter: function($) { return true; },
+ templatesDir: "/templates/sapui5/",
+ symbolsDir: "symbols/",
+ modulesDir: "modules/",
+ topicUrlPattern: "../../guide/{{topic}}.html",
+ srcDir: "symbols/src/",
+ creationDate : now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDay() + " " + now.getHours() + ":" + now.getMinutes(),
+ outdir: env.opts.destination
+ }, PUBLISHING_VARIANTS[vVariant.variant].defaults, templateConf, vVariant);
+
+ info("publishing as variant '" + vVariant.variant + "'");
+ debug("final configuration:");
+ debug(conf);
+
+ PUBLISHING_VARIANTS[vVariant.variant].processor(conf);
+
+ info("done with variant " + vVariant.variant);
+
+ } else {
+
+ info("cannot publish unknown variant '" + vVariant.variant + "' (ignored)");
+
+ }
+ }
+
+ var builtinSymbols = templateConf.builtinSymbols;
+ if ( builtinSymbols ) {
+ Link.getMissingTypes().filter(function($) {
+ return builtinSymbols.indexOf($) < 0;
+ }).sort().forEach(function($) {
+ error(" unresolved reference: " + $);
+ });
+ }
+ info("publishing done.");
+
+}
+
+//---- namespace tree --------------------------------------------------------------------------------
+
+/**
+ * Completes the tree of namespaces. Namespaces for which content is available
+ * but which have not been documented are created as dummy without documentation.
+ */
+function createNamespaceTree() {
+
+ info("create namespace tree (" + __db().count() + " symbols)");
+
+ var aRootNamespaces = [];
+ var aTypes = __db(function() { return isaClass(this); }).get();
+
+ for (var i = 0; i < aTypes.length; i++) { // loop with a for-loop as it can handle concurrent modifications
+
+ var symbol = aTypes[i];
+ if ( symbol.memberof ) {
+
+ var parent = lookup(symbol.memberof);
+ if ( !parent ) {
+ warning("create missing namespace '" + symbol.memberof + "' (referenced by " + symbol.longname + ")");
+ parent = makeNamespace(symbol.memberof);
+ __longnames[symbol.memberof] = parent;
+ __db.insert(parent);
+ aTypes.push(parent); // concurrent modification: parent will be processed later in this loop
+ }
+ symbol.__ui5.parent = parent;
+ parent.__ui5.children = parent.__ui5.children || [];
+ parent.__ui5.children.push(symbol);
+
+ } else if ( symbol.longname !== ANONYMOUS_LONGNAME ) {
+
+ aRootNamespaces.push(symbol);
+
+ }
+ }
+
+ return aRootNamespaces;
+}
+
+function makeNamespace(memberof) {
+
+ info("adding synthetic namespace symbol " + memberof);
+
+ var comment = [
+ "@name " + memberof,
+ "@namespace",
+ "@synthetic",
+ "@public"
+ ];
+
+ var symbol = new doclet.Doclet("/**\n * " + comment.join("\n * ") + "\n */", {});
+ symbol.__ui5 = {};
+
+ return symbol;
+}
+
+//---- inheritance hierarchy ----------------------------------------------------------------------------
+
+/**
+ * Calculates the inheritance hierarchy for all class/interface/namespace symbols.
+ * Each node in the tree has the content
+ *
+ * Node : {
+ * longname : {string} // name of the node (usually equals symbol.longname)
+ * symbol : {Symbol} // backlink to the original symbol
+ * base : {Node} // parent node or undefined for root nodes
+ * derived : {Node[]} // subclasses/-types
+ * }
+ *
+ */
+function createInheritanceTree() {
+
+ function makeDoclet(longname, lines) {
+ lines.push("@name " + longname);
+ var newDoclet = new doclet.Doclet("/**\n * " + lines.join("\n * ") + "\n */", {});
+ newDoclet.__ui5 = {};
+ __longnames[longname] = newDoclet;
+ __db.insert(newDoclet);
+ return newDoclet;
+ }
+
+ info("create inheritance tree (" + __db().count() + " symbols)");
+
+ var oTypes = __db(function() { return isaClass(this); });
+ var aRootTypes = [];
+
+ var oObject = lookup("Object");
+ if ( !oObject ) {
+ oObject = makeDoclet("Object", [
+ "@class",
+ "@synthetic",
+ "@public"
+ ]);
+ aRootTypes.push(oObject);
+ }
+
+ function getOrCreateClass(sClass, sExtendingClass) {
+ var oClass = lookup(sClass);
+ if ( !oClass ) {
+ warning("create missing class " + sClass + " (extended by " + sExtendingClass + ")");
+ var sBaseClass = 'Object';
+ if ( externalSymbols[sClass] ) {
+ sBaseClass = externalSymbols[sClass].extends || sBaseClass;
+ }
+ var oBaseClass = getOrCreateClass(sBaseClass, sClass);
+ oClass = makeDoclet(sClass, [
+ "@extends " + sBaseClass,
+ "@class",
+ "@synthetic",
+ "@public"
+ ]);
+ oClass.__ui5.base = oBaseClass;
+ oBaseClass.__ui5.derived = oBaseClass.__ui5.derived || [];
+ oBaseClass.__ui5.derived.push(oClass);
+ }
+ return oClass;
+ }
+
+ // link them according to the inheritance infos
+ oTypes.each(function(oClass) {
+
+ if ( oClass.longname === 'Object') {
+ return;
+ }
+
+ var sBaseClass = "Object";
+ if ( oClass.augments && oClass.augments.length > 0 ) {
+ if ( oClass.augments.length > 1 ) {
+ warning("multiple inheritance detected in " + oClass.longname);
+ }
+ sBaseClass = oClass.augments[0];
+ } else {
+ aRootTypes.push(oClass);
+ }
+
+ var oBaseClass = getOrCreateClass(sBaseClass, oClass.longname);
+ oClass.__ui5.base = oBaseClass;
+ oBaseClass.__ui5.derived = oBaseClass.__ui5.derived || [];
+ oBaseClass.__ui5.derived.push(oClass);
+
+ if ( oClass.implements ) {
+ for (var j = 0; j < oClass.implements.length; j++) {
+ var oInterface = lookup(oClass.implements[j]);
+ if ( !oInterface ) {
+ warning("create missing interface " + oClass.implements[j]);
+ oInterface = makeDoclet(oClass.implements[j], [
+ "@extends Object",
+ "@interface",
+ "@synthetic",
+ "@public"
+ ]);
+ oInterface.__ui5.base = oObject;
+ oObject.__ui5.derived = oObject.__ui5.derived || [];
+ oObject.__ui5.derived.push(oInterface);
+ }
+ oInterface.__ui5.implementations = oInterface.__ui5.implementations || [];
+ oInterface.__ui5.implementations.push(oClass);
+ }
+ }
+ });
+
+ function setStereotype(oSymbol, sStereotype) {
+ if ( !oSymbol ) {
+ return;
+ }
+ oSymbol.__ui5.stereotype = sStereotype;
+ var derived = oSymbol.__ui5.derived;
+ if ( derived ) {
+ for (var i = 0; i < derived.length; i++ ) {
+ if ( !derived[i].__ui5.stereotype ) {
+ setStereotype(derived[i], sStereotype);
+ }
+ }
+ }
+ }
+
+ setStereotype(lookup("sap.ui.core.Component"), "component");
+ setStereotype(lookup("sap.ui.core.Control"), "control");
+ setStereotype(lookup("sap.ui.core.Element"), "element");
+ setStereotype(lookup("sap.ui.base.Object"), "object");
+
+ // check for cyclic inheritance (not supported)
+ // Note: the check needs to run bottom up, not top down as a typical cyclic dependency never will end at the root node
+ oTypes.each(function(oStartClass) {
+ var visited = {};
+ function visit(oClass) {
+ if ( visited[oClass.longname] ) {
+ throw new Error("cyclic inheritance detected: " + JSON.stringify(Object.keys(visited)));
+ }
+ if ( oClass.__ui5.base ) {
+ visited[oClass.longname] = true;
+ visit(oClass.__ui5.base);
+ delete visited[oClass.longname];
+ }
+ }
+ visit(oStartClass);
+ });
+
+ // collect root nodes (and ignore pure packages)
+ return aRootTypes;
+ /*
+ return __db(function() {
+ return R_KINDS.test(this.kind) && this.__ui5 && this.__ui5.base == null;
+ }).get();
+ */
+}
+
+function collectMembers() {
+ __db().each(function($) {
+ if ( $.memberof ) {
+ var parent = lookup($.memberof);
+ if ( parent && isaClass(parent) ) {
+ parent.__ui5.members = parent.__ui5.members || [];
+ parent.__ui5.members.push($);
+ }
+ }
+ });
+}
+
+function mergeEventDocumentation() {
+
+ console.log("merging JSDoc event documentation into UI5 metadata");
+
+ var oTypes = __db(function() { return isaClass(this); });
+
+ oTypes.each(function(symbol) {
+
+ var metadata = symbol.__ui5.metadata;
+ var members = symbol.__ui5.members;
+
+ if ( !metadata || !metadata.events || Object.keys(metadata.events).length <= 0 || !members ) {
+ return;
+ }
+
+ // console.log('mergeing events for ' + symbol.longname);
+ members.forEach(function($) {
+ if ( $.kind === 'event' && !$.inherited
+ && ($.access === 'public' || $.access === 'protected' || $.access == null)
+ && metadata.events[$.name]
+ && Array.isArray($.params)
+ && !$.synthetic ) {
+
+ var event = metadata.events[$.name];
+ var modified = false;
+ //console.log("<<<<<<<");
+ //console.log(event);
+ //console.log("=======");
+ //console.log($);
+
+ $.params.forEach(function(param) {
+ var m = /^\w+\.getParameters\.(.*)$/.exec(param.name);
+ if ( m ) {
+ var pname = m[1];
+ var ui5param = event.parameters[pname] || ( event.parameters[pname] = {});
+ if ( ui5param.type == null ) {
+ ui5param.type = listTypes(param.type);
+ modified = true;
+ }
+ if ( ui5param.doc == null ) {
+ ui5param.doc = param.description;
+ modified = true;
+ }
+ }
+ });
+
+ if ( modified ) {
+ console.log(" merged documentation for managed event " + symbol.longname + "#" + $.name);
+ }
+
+ //console.log("=======");
+ //console.log(JSON.stringify(event, null, '\t'));
+ //console.log(">>>>>>>");
+ }
+ });
+
+ });
+
+}
+
+// ---- publishing -----------------------------------------------------------------------
+
+function publishClasses(symbols, aRootNamespaces, hierarchyRoots) {
+
+ // create output dir
+ fs.mkPath(path.join(conf.outdir, conf.symbolsDir));
+
+ // get a list of all the classes in the symbolset
+ var classes = symbols(function() {
+ return isaClass(this) && conf.filter(this);
+ }).order("longname");
+
+ // create unique file names
+ __uniqueFilenames = {};
+ var filenames = {};
+ classes.get().sort(sortByAlias).forEach(function(symbol) {
+ var filename = escape(symbol.longname);
+ if ( filenames.hasOwnProperty(filename.toUpperCase()) && (filenames[filename.toUpperCase()].longname !== symbol.longname) ) {
+ // find an unused filename by appending "-n" where n is an integer > 0
+ for (var j = 1; filenames.hasOwnProperty(filename.toUpperCase() + "-" + j); j++);
+ warning("duplicate symbol names " + filenames[filename.toUpperCase()].longname + " and " + symbol.longname + ", renaming the latter to " + filename + "-" + j);
+ filename = filename + "-" + j;
+ }
+ filenames[filename.toUpperCase()] = symbol;
+ __uniqueFilenames[symbol.longname] = filename;
+ });
+ filenames = null;
+
+ // create a class index, displayed in the left-hand column of every class page
+ var classTemplate;
+ if ( !conf.contentOnly ) {
+ info("create embedded class index");
+ Link.base = "../";
+ Link.baseSymbols = "";
+ classTemplate = 'classWithIndex.html.tmpl';
+ publish.header = processTemplate("_header.tmpl", classes);
+ publish.footer = processTemplate("_footer.tmpl", classes);
+ publish.classesIndex = processTemplate("_navIndex.tmpl", classes); // kept in memory
+ } else {
+ var newStyle = !!pluginConf.newStyle;
+ classTemplate = newStyle ? "class-new.html.tmpl" : "class.html.tmpl";
+ publish.header = '';
+ publish.footer = '';
+ publish.classesIndex = '';
+
+ // instead create an index as XML
+ Link.base = "";
+ Link.baseSymbols = conf.symbolsDir;
+ processTemplateAndSave("index.xml.tmpl", aRootNamespaces, "index.xml");
+ }
+
+ // create each of the class pages
+ info("create class/namespace pages");
+ Link.base = "../";
+ Link.baseSymbols = "";
+ classes.each(function(symbol) {
+ var sOutName = path.join(conf.symbolsDir, __uniqueFilenames[symbol.longname]) + conf.ext;
+ processTemplateAndSave(classTemplate, symbol, sOutName);
+ });
+
+ if ( conf.modulePages ) {
+ info("create module pages");
+ Link.base = "../";
+ Link.baseSymbols = "../" + conf.symbolsDir;
+ fs.mkPath(path.join(conf.outdir, conf.modulesDir));
+ groupByModule(classes.get()).forEach(function(module) {
+ var sOutName = path.join(conf.modulesDir, module.name.replace(/\//g, '_')) + conf.ext;
+ processTemplateAndSave("module.html.tmpl", module, sOutName);
+ });
+ }
+
+ // regenerate the index with a different link base, used in the overview pages
+ info("create global class/namespace index");
+ Link.base = "";
+ Link.baseSymbols = conf.symbolsDir;
+ publish.header = processTemplate("_header.tmpl", classes);
+ publish.footer = processTemplate("_footer.tmpl", classes);
+ publish.classesIndex = processTemplate("_navIndex.tmpl", classes);
+
+ // create the all classes index
+ processTemplateAndSave("index.html.tmpl", classes, "index" + conf.ext);
+
+ // create the class hierarchy page
+ if ( conf.hierarchyIndex ) {
+ info("create class hierarchy index");
+ Link.base = "";
+ Link.baseSymbols = conf.symbolsDir;
+ processTemplateAndSave("hierarchy.html.tmpl", hierarchyRoots.filter(conf.filter), "hierarchy" + conf.ext);
+ }
+
+ if ( conf.sinceIndex ) {
+ info("create API by version index");
+ Link.base = "";
+ Link.baseSymbols = conf.symbolsDir;
+ var sinceSymbols = symbols(function() {
+ var r = !!this.since && !this.inherited && conf.filter(this);
+ if ( r && this.memberof ) {
+ var parent = lookup(this.memberof);
+ // filter out symbol when parent is filtered out
+ if ( !parent || !conf.filter(parent) ) {
+ debug("since index: filtering out " + this.longname + ", member of " + this.memberof);
+ r = false;
+ }
+ if ( parent && parent.since === this.since ) {
+ // r = false;
+ }
+ }
+ return r;
+ }).order("longname");
+ processTemplateAndSave("since.html.tmpl", sinceSymbols, "since" + conf.ext);
+ }
+
+ if ( conf.deprecationIndex ) {
+ info("create deprecated API index");
+ Link.base = "";
+ Link.baseSymbols = conf.symbolsDir;
+ var deprecatedSymbols = symbols(function() {
+ return !!this.deprecated && !this.inherited && conf.filter(this);
+ }).order("longname");
+ processTemplateAndSave("deprecation.html.tmpl", deprecatedSymbols, "deprecation" + conf.ext);
+ }
+
+ if ( conf.experimentalIndex ) {
+ info("create experimental API index");
+ Link.base = "";
+ Link.baseSymbols = conf.symbolsDir;
+ var experimentalSymbols = symbols(function() {
+ return !!this.experimental && !this.inherited && conf.filter(this);
+ }).order("longname");
+ processTemplateAndSave("experimental.html.tmpl", experimentalSymbols, "experimental" + conf.ext);
+ }
+
+ if ( conf.securityIndex ) {
+ info("create Security Relevant API index");
+
+ var securityRelevantSymbols = {};
+ A_SECURITY_TAGS.forEach(function(oTagDef) {
+ securityRelevantSymbols[oTagDef.name.toLowerCase()] = { tag : oTagDef, symbols: [] };
+ });
+ symbols().each(function($) {
+ var tags = $.tags;
+ if ( !$.inherited && conf.filter($) && tags ) {
+ for (var i = 0; i < tags.length; i++) {
+ if ( rSecurityTags.test(tags[i].title) ) {
+ securityRelevantSymbols[tags[i].title.toLowerCase()].symbols.push({ symbol: $, tag : tags[i]});
+ }
+ }
+ }
+ });
+
+ Link.base = "";
+ Link.baseSymbols = conf.symbolsDir;
+ processTemplateAndSave("security.html.tmpl", securityRelevantSymbols, "security" + conf.ext);
+ }
+
+ classes = null;
+
+ // copy needed mimes
+ info("copy mimes");
+ // copy the template's static files to outdir
+ var templatePath = env.opts.template;
+ var fromDir = path.join(templatePath, 'static');
+ var staticFiles = fs.ls(fromDir, 3);
+ staticFiles.forEach(function(fileName) {
+ var toDir = fs.toDir( fileName.replace(fromDir, conf.outdir) );
+ fs.mkPath(toDir);
+ fs.copyFileSync(fileName, toDir);
+ });
+
+ __uniqueFilenames = null;
+
+ info("publishing done.");
+}
+
+// ---- helper functions for the templates ----
+
+var rSinceVersion = /^([0-9]+(?:\.[0-9]+(?:\.[0-9]+)?)?([-.][0-9A-Z]+)?)(?:\s|$)/i;
+
+function extractVersion(value) {
+
+ if ( !value ) {
+ return;
+ }
+
+ if ( value === true ) {
+ value = '';
+ } else {
+ value = String(value);
+ }
+
+ var m = rSinceVersion.exec(value);
+ return m ? m[1] : undefined;
+
+}
+
+var rSince = /^(?:as\s+of|since)(?:\s+version)?\s*([0-9]+(?:\.[0-9]+(?:\.[0-9]+)?)?([-.][0-9A-Z]+)?)(?:\.$|\.\s+|[,:]\s*|\s-\s*|\s|$)/i;
+
+function extractSince(value) {
+
+ if ( !value ) {
+ return;
+ }
+
+ if ( value === true ) {
+ value = '';
+ } else {
+ value = String(value);
+ }
+
+ var m = rSince.exec(value);
+ if ( m ) {
+ return {
+ since : m[1],
+ pos : m[0].length,
+ value : value.slice(m[0].length).trim()
+ }
+ }
+
+ return {
+ pos : 0,
+ value: value.trim()
+ };
+
+}
+
+function sortByAlias(a, b) {
+ var partsA = a.longname.split(/[.#]/);
+ var partsB = b.longname.split(/[.#]/);
+ var i = 0;
+ while ( i < partsA.length && i < partsB.length ) {
+ if ( partsA[i].toLowerCase() < partsB[i].toLowerCase() )
+ return -1;
+ if ( partsA[i].toLowerCase() > partsB[i].toLowerCase() )
+ return 1;
+ i++;
+ }
+ if ( partsA.length < partsB.length )
+ return -1;
+ if ( partsA.length > partsB.length )
+ return 1;
+ // as a last resort, try to compare the aliases case sensitive in case we have aliases that only
+ // differ in case like with "sap.ui.model.type" and "sap.ui.model.Type"
+ if ( a.longname < b.longname ) {
+ return -1;
+ }
+ if ( a.longname > b.longname ) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+function isNonEmptyNamespace($) {
+ return $.isNamespace && (
+ ($.properties && $.properties.length > 0) ||
+ ($.methods && $.methods.length > 0) ||
+ ($.augments && $.augments.length > 0) ||
+ ($.children && $.children.length > 0));
+};*/
+
+/** Just the first sentence (up to a full stop). Should not break on dotted variable names. */
+function summarize(desc) {
+ if ( desc != null ) {
+ desc = String(desc).replace(/\s+/g, ' ').
+ replace(/"'/g, '"').
+ replace(/^(<\/?p>|
|\s)+/, '');
+
+ var match = /([\w\W]+?\.)[^a-z0-9_$]/i.exec(desc);
+ return match ? match[1] : desc;
+ }
+}
+
+/** Make a symbol sorter by some attribute. */
+function makeSortby(/* fields ...*/) {
+ var aFields = Array.prototype.slice.apply(arguments),
+ aNorms = [],
+ aFuncs = [];
+ for (var i = 0; i < arguments.length; i++) {
+ aNorms[i] = 1;
+ if ( typeof aFields[i] === 'function' ) {
+ aFuncs[i] = aFields[i];
+ continue;
+ }
+ aFuncs[i] = function($,n) { return $[n]; };
+ if ( aFields[i].indexOf("!") === 0 ) {
+ aNorms[i] = -1;
+ aFields[i] = aFields[i].slice(1);
+ }
+ if ( aFields[i] === 'deprecated' ) {
+ aFuncs[i] = function($,n) { return !!$[n]; };
+ } else if ( aFields[i] === 'static' ) {
+ aFields[i] = 'scope';
+ aFuncs[i] = function($,n) { return $[n] === 'static'; };
+ } else if ( aFields[i].indexOf("#") === 0 ) {
+ aFields[i] = aFields[i].slice(1);
+ aFuncs[i] = function($,n) { return $.comment.getTag(n).length > 0; };
+ }
+ }
+ return function(a, b) {
+ // info("compare " + a.longname + " : " + b.longname);
+ var r = 0,i,va,vb;
+ for (i = 0; r === 0 && i < aFields.length; i++) {
+ va = aFuncs[i](a,aFields[i]);
+ vb = aFuncs[i](b,aFields[i]);
+ if ( va && !vb ) {
+ r = -aNorms[i];
+ } else if ( !va && vb ) {
+ r = aNorms[i];
+ } else if ( va && vb ) {
+ va = String(va).toLowerCase();
+ vb = String(vb).toLowerCase();
+ if (va < vb) r = -aNorms[i];
+ if (va > vb) r = aNorms[i];
+ }
+ // debug(" " + aFields[i] + ": " + va + " ? " + vb + " = " + r);
+ }
+ return r;
+ }
+}
+
+/** Pull in the contents of an external file at the given path. */
+
+function processTemplateAndSave(sTemplateName, oData, sOutputName) {
+ var sResult = processTemplate(sTemplateName, oData);
+ if ( conf.normalizeWhitespace && /\.html$/.test(sOutputName) ) {
+ sResult = normalizeWhitespace(sResult);
+ }
+ var sOutpath = path.join(conf.outdir, sOutputName);
+ try {
+ fs.writeFileSync(sOutpath, sResult, 'utf8');
+ } catch (e) {
+ error("failed to write generated file '" + sOutpath + "':" + (e.message || String(e)));
+ }
+}
+
+function processTemplate(sTemplateName, data) {
+ debug("processing template '" + sTemplateName + "' for " + data.longname);
+
+ try {
+ var result = view.render(sTemplateName, {
+ asPlainSummary: asPlainSummary,
+ bySimpleName: bySimpleName,
+ childrenOfKind: childrenOfKind,
+ conf: conf,
+ data: data,
+ getConstructorDescription : getConstructorDescription,
+ getNSClass: getNSClass,
+ groupByVersion: groupByVersion,
+ extractSince: extractSince,
+ include: processTemplate,
+ Link: Link,
+ listTypes: listTypes,
+ linkTypes: linkTypes,
+ makeExample: makeExample,
+ makeLinkList: makeLinkList,
+ makeLinkToSymbolFile: makeLinkToSymbolFile,
+ makeSignature: makeSignature,
+ makeSortby: makeSortby,
+ publish : publish,
+ formatText: formatText,
+ simpleNameOf: simpleNameOf,
+ sortByAlias: sortByAlias,
+ summarize: summarize,
+ Version : Version
+ });
+ } catch (e) {
+ if ( e.source ) {
+ var filename = path.join(env.opts.destination, sTemplateName + ".js");
+ console.log("**** failed to process template, source written to " + filename);
+ fs.mkPath(path.dirname(filename));
+ fs.writeFileSync(filename, e.source, 'utf8');
+ }
+ console.log("error while processing " + sTemplateName);
+ throw e;
+ }
+ debug("processing template done.");
+ return result;
+}
+
+function groupByVersion(symbols, extractVersion) {
+
+ var map = {};
+
+ symbols.forEach(function(symbol) {
+
+ var version = extractVersion(symbol),
+ key = String(version);
+
+ if ( !map[key] ) {
+ map[key] = { version: version, symbols : [] };
+ }
+ map[key].symbols.push(symbol);
+
+ });
+
+ var groups = Object.keys(map).map(function(key) { return map[key]; });
+
+ return groups.sort(function(a,b) {
+ if ( !a.version && b.version ) {
+ return -1;
+ } else if ( a.version && !b.version ) {
+ return 1;
+ } else if ( a.version && b.version ) {
+ return -a.version.compareTo(b.version);
+ }
+ return 0;
+ });
+}
+
+function groupByModule(symbols) {
+
+ var map = {};
+
+ function add(key, symbol) {
+ if ( !map[key] ) {
+ map[key] = { name: key, symbols : [] };
+ }
+ if ( map[key].symbols.indexOf(symbol) < 0 ) {
+ map[key].symbols.push(symbol);
+ }
+ }
+
+ symbols.forEach(function(symbol) {
+
+ var key = symbol.__ui5.module;
+
+ if ( key ) {
+ add(key, symbol);
+ if ( symbol.__ui5.members ) {
+ symbol.__ui5.members.forEach(function($) {
+ if ( !$.inherited && $.__ui5.module && $.__ui5.module !== key && conf.filter($) ) {
+ add($.__ui5.module, $);
+ }
+ });
+ }
+ }
+
+ });
+
+ var groups = Object.keys(map).map(function(key) { return map[key]; });
+
+ return groups;
+}
+
+
+var REGEXP_TAG = /<(\/?(?:[A-Z][A-Z0-9_-]*:)?[A-Z][A-Z0-9_-]*)(?:\s[^>]*)?>/gi;
+
+/**
+ * Removes unnecessary whitespace from an HTML document:
+ * - if the text between two adjacent HTML tags consists of whitespace only, the whole text is removed
+ * - otherwise, any sequence of whitespace in the text is reduced to a single blank
+ * - inside a tag, whitespace is preserved
+ *
+ * Whitespace inside an element tag is not touched (although it could be normalized as well)
+ * @param {string} content raw HTML file
+ * @returns {string} HTML file with normalized whitespace
+ */
+function normalizeWhitespace(content) {
+ var compressed = '',
+ preformatted = 0,
+ p = 0, m, text;
+
+ REGEXP_TAG.lastIndex = 0;
+ while ( m = REGEXP_TAG.exec(content) ) {
+ if ( m.index > p ) {
+ text = content.slice(p, m.index);
+ if ( preformatted ) {
+ compressed += text;
+ // console.log(' "' + text + '" (preformatted)');
+ } else {
+ text = text.replace(/\s+/g,' ');
+ if ( text.trim() ) {
+ compressed += text;
+ }
+ // console.log(' "' + text + '" (trimmed)');
+ }
+ }
+
+ compressed += m[0];
+ // console.log(' "' + m[0] + '" (tag)');
+ p = m.index + m[0].length;
+
+ if ( /^pre$/i.test(m[1]) ) {
+ preformatted++;
+ } else if ( /^\/pre$/i.test(m[1]) && preformatted ) {
+ preformatted--;
+ }
+
+ }
+
+ if ( content.length > p ) {
+ text = content.slice(p, content.length);
+ if ( preformatted ) {
+ compressed += text;
+ // console.log(' "' + text + '" (preformatted)');
+ } else {
+ text = text.replace(/\s+/g,' ');
+ if ( text.trim() ) {
+ compressed += text;
+ }
+ // console.log(' "' + text + '" (trimmed)');
+ }
+ }
+
+ return compressed;
+}
+
+function makeLinkToSymbolFile(longname) {
+ return Link.baseSymbols + __uniqueFilenames[longname] + conf.ext;
+}
+
+function simpleNameOf(longname) {
+ longname = String(longname);
+ var p = longname.lastIndexOf('.');
+ return p < 0 ? longname : longname.slice(p + 1);
+}
+
+function bySimpleName(a,b) {
+ if ( a === b ) {
+ return 0;
+ }
+ var simpleA = simpleNameOf(a);
+ var simpleB = simpleNameOf(b);
+ if ( simpleA === simpleB ) {
+ return a < b ? -1 : 1;
+ } else {
+ return simpleA < simpleB ? -1 : 1;
+ }
+}
+
+/** Build output for displaying function parameters. */
+function makeSignature(params) {
+ var r = ['('], desc;
+ if ( params ) {
+ for (var i = 0, p; p = params[i]; i++) {
+ // ignore @param tags for 'virtual' params that are used to document members of config-like params
+ // (e.g. like "@param param1.key ...")
+ if (p.name && p.name.indexOf('.') == -1) {
+ if (i > 0)
+ r.push(', ');
+
+ r.push('');
+ r.push(p.name);
+ r.push('');
+ if ( p.optional )
+ r.push('?');
+ }
+ }
+ }
+ r.push(')');
+ return r.join('');
+}
+
+
+/*
+ * regexp to recognize important places in the text
+ *
+ * Capturing groups of the RegExp:
+ * group 1: begin of a pre block
+ * group 2: end of a pre block
+ * group 3: begin of a header/ul/ol/table, implicitly ends a paragraph
+ * group 4: end of a header/ul/ol/table, implicitly starts a new paragraph
+ * group 5: target portion of an inline @link tag
+ * group 6: (optional) text portion of an inline link tag
+ * group 7: an empty line which implicitly starts a new paragraph
+ *
+ * [-------
block -------] [----------------------- some flow content -----------------------] [---- an inline {@link ...} tag ----] [---------- an empty line ---------] */
+var rFormatText = /(
]*)?>)|(<\/pre>)|(<(?:h[\d+]|ul|ol|table)(?:\s[^>]*)?>)|(<\/(?:h[\d+]|ul|ol|table)>)|\{@link\s+([^}\s]+)(?:\s+([^\}]*))?\}|((?:\r\n|\r|\n)[ \t]*(?:\r\n|\r|\n))/gi;
+
+function formatText(text) {
+
+ if ( !text ) {
+ return '';
+ }
+
+ var inpre = false,
+ paragraphs = 0;
+
+ text = String(text).replace(rFormatText, function(match, pre, endpre, flow, endflow, linkTarget, linkText, emptyline) {
+ if ( pre ) {
+ inpre = true;
+ return pre.replace(/
/gi, "
").replace(/
/gi, "
");
+ } else if ( endpre ) {
+ inpre = false;
+ } else if ( flow ) {
+ if ( !inpre ) {
+ paragraphs++;
+ return '
'; + } + } else if ( emptyline ) { + if ( !inpre ) { + paragraphs++; + return '
'; + } + } else if ( linkTarget ) { + if ( !inpre ) { + // convert to a hyperlink + var link = new Link().toSymbol(linkTarget); + // if link tag contained a replacement text, use it + if ( linkText && linkText.trim()) { + link = link.withText(linkText.trim()); + } + return link.toString(); + } + } + return match; + }); + + if ( paragraphs > 0 ) { + text = '
' + text + '
'; + } + + // remove empty paragraphs + text = text.replace(/\s*<\/p>/g, '');
+
+ return text;
+}
+
+
+//console.log("#### samples");
+//console.log(formatText(summarize("This is a first\n\nparagraph with empty \n \n \nlines in it. This is the remainder.")));
+
+function childrenOfKind(data, kind) {
+ /* old version based on TaffyDB (slow)
+ var oChildren = symbolSet({kind: kind, memberof: data.longname === GLOBAL_LONGNAME ? {isUndefined: true} : data.longname}).filter(function() { return conf.filter(this); });
+ return {
+ own : oChildren.filter({inherited: {isUndefined:true}}).get().sort(makeSortby("!deprecated","static","name")),
+ borrowed : groupByContributors(data, oChildren.filter({inherited: true}).get().sort(makeSortby("name")))
+ } */
+ var oResult = {
+ own: [],
+ borrowed: []
+ };
+ //console.log("calculating kind " + kind + " from " + data.longname);
+ //console.log(data);
+ var fnFilter;
+ switch (kind) {
+ case 'property':
+ fnFilter = function($) {
+ return $.kind === 'constant' || ($.kind === 'member' && !$.isEnum);
+ }
+ break;
+ case 'event':
+ fnFilter = function($) {
+ return $.kind === 'event';
+ }
+ break;
+ case 'method':
+ fnFilter = function($) {
+ return $.kind === 'function';
+ }
+ break;
+ default:
+ // default: none
+ fnFilter = function($) { return false; };
+ break;
+ }
+
+ if ( data.__ui5.members ) {
+ data.__ui5.members.forEach(function($) {
+ if ( fnFilter($) && conf.filter($) ) {
+ oResult[$.inherited ? 'borrowed' : 'own'].push($);
+ }
+ });
+ }
+ oResult.own.sort(makeSortby("!deprecated","static","name"));
+ oResult.borrowed = groupByContributors(data, oResult.borrowed);
+
+ return oResult;
+}
+
+/**
+ * Determines the set of contributors of the given borrowed members.
+ * The contributors are sorted according to the inheritance hierarchy:
+ * first the base class of symbol, then the base class of the base class etc.
+ * Any contributors that can not be found in the hierarchy are appended
+ * to the set.
+ *
+ * @param symbol of which these are the members
+ * @param borrowedMembers set of borrowed members to determine the contributors for
+ * @return sorted array of contributors
+ */
+function groupByContributors(symbol, aBorrowedMembers) {
+
+ var MAX_ORDER = 1000, // a sufficiently large number
+ mContributors = {},
+ aSortedContributors = [],
+ i,order;
+
+ aBorrowedMembers.forEach(function($) {
+ $ = lookup($.inherits);
+ if ($ && mContributors[$.memberof] == null) {
+ mContributors[$.memberof] = { order : MAX_ORDER, items : [$] };
+ } else {
+ mContributors[$.memberof].items.push($);
+ }
+ });
+
+ // order contributors according to their distance in the inheritance hierarchy
+ order = 0;
+ (function handleAugments(oSymbol) {
+ var i,oTarget,aParentsToVisit;
+ if ( oSymbol.augments ) {
+ aParentsToVisit = [];
+ // first assign an order
+ for (i = 0; i < oSymbol.augments.length; i++) {
+ if ( mContributors[oSymbol.augments[i]] != null && mContributors[oSymbol.augments[i]].order === MAX_ORDER ) {
+ mContributors[oSymbol.augments[i]].order = ++order;
+ aParentsToVisit.push(oSymbol.augments[i]);
+ }
+ }
+ // only then dive into parents (breadth first search)
+ for (i = 0; i < aParentsToVisit.length; i++) {
+ oTarget = lookup(aParentsToVisit);
+ if ( oTarget ) {
+ handleAugments(oTarget);
+ }
+ }
+ }
+ }(symbol));
+
+ // convert to an array and sort by order
+ for (i in mContributors) {
+ aSortedContributors.push(mContributors[i]);
+ }
+ aSortedContributors.sort(function (a,b) { return a.order - b.order; });
+
+ return aSortedContributors;
+
+}
+
+function makeLinkList(aSymbols) {
+ return aSymbols
+ .sort(makeSortby("name"))
+ .map(function($) { return new Link().toSymbol($.longname).withText($.name); })
+ .join(", ");
+}
+
+// ---- type parsing ---------------------------------------------------------------------------------------------
+
+function TypeParser(defaultBuilder) {
+
+ /* TODO
+ * - function(this:) // type of this
+ * - function(new:) // constructor
+ */
+ var rLexer = /\s*(Array\.?<|Object\.?<|Set\.?<|Promise\.?<|function\(|\{|:|\(|\||\}|>|\)|,|\[\]|\*|\?|!|\.\.\.)|\s*(\w+(?:[.#~]\w+)*)|./g;
+
+ var input,
+ builder,
+ token,
+ tokenStr;
+
+ function next(expected) {
+ if ( expected !== undefined && token !== expected ) {
+ throw new SyntaxError("TypeParser: expected '" + expected + "', but found '" + tokenStr + "' (pos: " + rLexer.lastIndex + ", input='" + input + "')");
+ }
+ var match = rLexer.exec(input);
+ if ( match ) {
+ tokenStr = match[1] || match[2];
+ token = match[1] || (match[2] && 'symbol');
+ if ( !token ) {
+ throw new SyntaxError("TypeParser: unexpected '" + tokenStr + "' (pos: " + match.index + ", input='" + input + "')");
+ }
+ } else {
+ tokenStr = token = null;
+ }
+ }
+
+ function parseType() {
+ var nullable = false;
+ var mandatory = false;
+ if ( token === '?' ) {
+ next();
+ nullable = true;
+ } else if ( token === '!' ) {
+ next();
+ mandatory = true;
+ }
+
+ var type;
+
+ if ( token === 'Array.<' || token === 'Array<' ) {
+ next();
+ var componentType = parseType();
+ next('>');
+ type = builder.array(componentType);
+ } else if ( token === 'Object.<' || token === 'Object<' ) {
+ next();
+ var keyType;
+ var valueType = parseType();
+ if ( token === ',' ) {
+ next();
+ keyType = valueType;
+ valueType = parseType();
+ } else {
+ keyType = builder.synthetic(builder.simpleType('string'));
+ }
+ next('>');
+ type = builder.object(keyType, valueType);
+ } else if ( token === 'Set.<' || token === 'Set<' ) {
+ next();
+ var elementType = parseType();
+ next('>');
+ type = builder.set(elementType);
+ } else if ( token === 'Promise.<' || token === 'Promise<' ) {
+ next();
+ var elementType = parseType();
+ next('>');
+ type = builder.promise(elementType);
+ } else if ( token === 'function(' ) {
+ next();
+ var thisType, constructorType, paramTypes = [], returnType;
+ if ( tokenStr === 'this' ) {
+ next();
+ next(':');
+ thisType = parseType();
+ if ( token === ',' ) {
+ next();
+ }
+ } else if ( tokenStr === 'new' ) {
+ next();
+ next(':');
+ constructorType = parseType();
+ if ( token === ',' ) {
+ next();
+ }
+ }
+ while ( token === 'symbol' || token === '...' ) {
+ var repeatable = token === '...';
+ if ( repeatable) {
+ next();
+ }
+ var paramType = parseType();
+ if ( repeatable ) {
+ paramType = builder.repeatable(paramType);
+ }
+ paramTypes.push(paramType);
+ if ( token === ',' ) {
+ if ( repeatable ) {
+ throw new SyntaxError("TypeParser: only the last parameter of a function can be repeatable (pos: " + rLexer.lastIndex + ", input='" + input + "')");
+ }
+ next();
+ }
+ }
+ next(')');
+ if ( token === ':' ) {
+ next(':');
+ returnType = parseType();
+ }
+ type = builder.function(paramTypes, returnType, thisType, constructorType);
+ } else if ( token === '{' ) {
+ var structure = Object.create(null);
+ var propName,propType;
+ next();
+ do {
+ propName = tokenStr;
+ if ( !/^\w+$/.test(propName) ) {
+ throw new SyntaxError("TypeParser: structure field must have a simple name (pos: " + rLexer.lastIndex + ", input='" + input + "', field:'" + propName + "')");
+ }
+ next('symbol');
+ if ( token === ':' ) {
+ next();
+ propType = parseType();
+ } else {
+ propType = builder.synthetic(builder.simpleType('any'));
+ }
+ structure[propName] = propType;
+ if ( token === '}' ) {
+ break;
+ }
+ next(',');
+ } while (token);
+ next('}');
+ type = builder.structure(structure);
+ } else if ( token === '(' ) {
+ next();
+ type = parseTypes();
+ next(')');
+ } else if ( token === '*' ) {
+ next();
+ type = builder.simpleType('*');
+ } else {
+ type = builder.simpleType(tokenStr);
+ next('symbol');
+ while ( token === '[]' ) {
+ next();
+ type = builder.array(type);
+ }
+ }
+ if ( nullable ) {
+ type = builder.nullable(type);
+ }
+ if ( mandatory ) {
+ type = builder.mandatory(type);
+ }
+ return type;
+ }
+
+ function parseTypes() {
+ var types = [];
+ do {
+ types.push(parseType());
+ if ( token !== '|' ) {
+ break;
+ }
+ next();
+ } while (token);
+ return types.length === 1 ? types[0] : builder.union(types);
+ }
+
+ this.parse = function(typeStr, tempBuilder) {
+ builder = tempBuilder || defaultBuilder || TypeParser.ASTBuilder;
+ input = String(typeStr);
+ rLexer.lastIndex = 0;
+ next();
+ var type = parseTypes();
+ next(null);
+ return type;
+ }
+
+}
+
+TypeParser.ASTBuilder = {
+ simpleType: function(type) {
+ return {
+ type: 'simpleType',
+ name: type
+ };
+ },
+ array: function(componentType) {
+ return {
+ type: 'array',
+ component: componentType
+ };
+ },
+ object: function(keyType, valueType) {
+ return {
+ type: 'object',
+ key: keyType,
+ value: valueType
+ };
+ },
+ set: function(elementType) {
+ return {
+ type: 'set',
+ element: elementType
+ };
+ },
+ promise: function(fulfillmentType) {
+ return {
+ type: 'promise',
+ fulfill: fulfillmentType
+ };
+ },
+ function: function(paramTypes, returnType, thisType, constructorType) {
+ return {
+ type: 'function',
+ params: paramTypes,
+ return: returnType,
+ this: thisType,
+ constructor: constructorType
+ };
+ },
+ structure: function(structure) {
+ return {
+ type: 'structure',
+ fields: structure
+ };
+ },
+ union: function(types) {
+ return {
+ type: 'union',
+ types: types
+ };
+ },
+ synthetic: function(type) {
+ type.synthetic = true;
+ return type;
+ },
+ nullable: function(type) {
+ type.nullable = true;
+ return type;
+ },
+ mandatory: function(type) {
+ type.mandatory = true;
+ return type;
+ },
+ repeatable: function(type) {
+ type.repeatable = true;
+ return type;
+ }
+};
+
+TypeParser.LinkBuilder = function(style, encoded) {
+ this.linkStyle = style;
+ this.lt = encoded ? "<" : "<";
+ this.gt = encoded ? ">" : ">";
+};
+TypeParser.LinkBuilder.prototype = {
+ safe: function(type) {
+ return type.needsParenthesis ? "(" + type.str + ")" : type.str;
+ },
+ simpleType: function(type) {
+ if ( this.linkStyle === 'text' ) {
+ return {
+ str: type
+ };
+ }
+ var link = new Link().toSymbol(type);
+ if ( this.linkStyle === 'short' ) {
+ link.withText(simpleNameOf(type)).withTooltip(type);
+ }
+ return {
+ str: link.toString()
+ };
+ },
+ array: function(componentType) {
+ if ( componentType.needsParenthesis ) {
+ return {
+ str: "Array.<" + componentType.str + ">"
+ };
+ }
+ return {
+ str: componentType.str + "[]"
+ };
+ },
+ object: function(keyType, valueType) {
+ if ( keyType.synthetic ) {
+ return {
+ str: "Object." + this.lt + valueType.str + this.gt
+ };
+ }
+ return {
+ str: "Object." + this.lt + keyType.str + "," + valueType.str + this.gt
+ };
+ },
+ set: function(elementType) {
+ return {
+ str: 'Set.' + this.lt + elementType.str + this.gt
+ };
+ },
+ promise: function(fulfillmentType) {
+ return {
+ str: 'Promise.' + this.lt + fulfillmentType.str + this.gt
+ };
+ },
+ function: function(paramTypes, returnType) {
+ return {
+ str: "function(" + paramTypes.map(function(type) { return type.str; }).join(',') + ")" + ( returnType ? " : " + this.safe(returnType) : "")
+ };
+ },
+ structure: function(structure) {
+ var r = [];
+ for ( var fieldName in structure ) {
+ if ( structure[fieldName].synthetic ) {
+ r.push(fieldName);
+ } else {
+ r.push(fieldName + ":" + structure[fieldName].str);
+ }
+ }
+ return {
+ str: "{" + r.join(",") + "}"
+ };
+ },
+ union: function(types) {
+ return {
+ needsParenthesis: true,
+ str: types.map( this.safe.bind(this) ).join('|')
+ };
+ },
+ synthetic: function(type) {
+ type.synthetic = true;
+ return type;
+ },
+ nullable: function(type) {
+ type.str = "?" + type.str;
+ return type;
+ },
+ mandatory: function(type) {
+ type.str = "!" + type.str;
+ return type;
+ },
+ repeatable: function(type) {
+ type.str = "..." + type.str;
+ return type;
+ }
+};
+
+var typeParser = new TypeParser();
+var _SHORT_BUILDER = new TypeParser.LinkBuilder('short', true);
+var _LONG_BUILDER = new TypeParser.LinkBuilder('long', true);
+var _TEXT_BUILDER = new TypeParser.LinkBuilder('text', false);
+var _TEXT_BUILDER_ENCODED = new TypeParser.LinkBuilder('text', true);
+
+/*
+function testTypeParser(type) {
+ console.log("Type: '" + type + "' gives AST");
+ try {
+ console.log(typeParser.parse(type));
+ } catch (e) {
+ console.log("**** throws: " + e);
+ }
+}
+
+testTypeParser("Array. \s*(\r\n|\r|\n)?/gm, "\n");
+ // skip empty documentation
+ if ( !s ) return;
+
+ // for namespaces, enforce the @.memberof tag
+ if ( sMetaType === "namespace" && $.memberof && s.indexOf("@memberof") < 0 ) {
+ s = s + "\n@memberof " + $.memberof;
+ }
+
+ writeln("/**\n * " + s.replace(/\n/g, "\n * ") + "\n */");
+
+ /*
+ writeln("/**");
+ writeln(s.split(/\r\n|\r|\n/g).map(function($) { return " * " + $;}).join("\r\n"));
+ writeln(" * /");
+ */
+
+ }
+
+ function signature($) {
+ var p = $.params,
+ r = [],
+ i;
+ if ( p ) {
+ for (i = 0; i < p.length; i++) {
+ // ignore @param tags for 'virtual' params that are used to document members of config-like params
+ // (e.g. like "@param param1.key ...")
+ if (p[i].name && p[i].name.indexOf('.') < 0) {
+ r.push(p[i].name);
+ }
+ }
+ }
+ return r.join(',');
+ }
+
+ function qname(member,parent) {
+ var r = member.memberof;
+ if ( member.scope !== 'static' ) {
+ r += ".prototype";
+ }
+ return (r ? r + "." : "") + member.name;
+ }
+
+ var mValues = {
+ "boolean" : "false",
+ "int" : "0",
+ "float" : "0.0",
+ "number" : "0.0",
+ "string" : "\"\"",
+ "object" : "new Object()",
+ "function" : "function() {}"
+ };
+
+ function valueForType(type) {
+ if ( type && type.names && type.names[0] ) {
+ type = type.names[0];
+ if ( REGEXP_ARRAY_TYPE.test(type) || type.indexOf("[]") > 0 ) {
+ return "new Array()";
+ } else if ( mValues[type] ) {
+ return mValues[type];
+ } else if ( type.indexOf(".") > 0 ) {
+ return "new " + type + "()";
+ } else {
+ // return "/* unsupported type: " + member.type + " */ null";
+ return "null";
+ }
+ }
+ }
+
+ function value(member) {
+ return valueForType(member.type);
+ }
+
+ function retvalue(member) {
+ //console.log(member);
+ var r = valueForType(member.type || (member.returns && member.returns.length && member.returns[0] && member.returns[0].type && member.returns[0].type));
+ if ( r ) {
+ return "return " + r + ";";
+ }
+ return "";
+ }
+
+ var sortedSymbols = symbols.slice(0).filter(function($) { return isaClass($) && isAPI($) && !$.synthetic; }).sort(sortByAlias); // sort only a copy(!) of the symbols, otherwise the SymbolSet lookup is broken
+ sortedSymbols.forEach(function(symbol) {
+
+ var sMetaType = (symbol.kind === 'member' && symbol.isEnum) ? 'enum' : symbol.kind;
+ if ( sMetaType ) {
+
+ writeln("");
+ writeln("// ---- " + symbol.longname + " --------------------------------------------------------------------------");
+ writeln("");
+
+ var memberId, member;
+
+ var ownProperties = childrenOfKind(symbol, 'property').own.filter(isNoKeyword).sort(sortByAlias);
+ if ( sMetaType === "class" ) {
+ comment(symbol, sMetaType);
+ writeln(symbol.longname + " = function(" + signature(symbol) + ") {};");
+ for ( memberId in ownProperties ) {
+ member = ownProperties[memberId];
+ comment(member, sMetaType);
+ writeln(qname(member, symbol) + " = " + value(member));
+ writeln("");
+ }
+ } else if ( sMetaType === 'namespace' || sMetaType === 'enum' ) {
+ //console.log("found namespace " + symbol.longname);
+ //console.log(ownProperties);
+ if ( ownProperties.length ) {
+ writeln("// dummy function to make Eclipse aware of namespace");
+ writeln(symbol.longname + ".toString = function() { return \"\"; };");
+ }
+ }
+
+ var ownEvents = childrenOfKind(symbol, 'event').own.filter(isNoKeyword).sort(sortByAlias);
+ if ( ownEvents.length ) {
+ for ( memberId in ownEvents ) {
+ member = ownEvents[memberId];
+ comment(member, sMetaType);
+ writeln(qname(member, symbol) + " = function(" + signature(member) + ") { " + retvalue(member) + " };");
+ writeln("");
+ }
+ }
+
+ var ownMethods = childrenOfKind(symbol, 'method').own.filter(isNoKeyword).sort(sortByAlias);
+ if ( ownMethods.length ) {
+ for ( memberId in ownMethods ) {
+ member = ownMethods[memberId];
+ comment(member, sMetaType);
+ writeln(qname(member, symbol) + " = function(" + signature(member) + ") { " + retvalue(member) + " };");
+ writeln("");
+ }
+ }
+
+ }
+ });
+
+ writeln("// ---- static fields of namespaces ---------------------------------------------------------------------");
+
+ sortedSymbols.forEach(function(symbol) {
+
+ var sMetaType = (symbol.kind === 'member' && symbol.isEnum) ? 'enum' : symbol.kind;
+
+ if ( sMetaType === 'namespace' || sMetaType === 'enum' ) {
+
+ var ownProperties = childrenOfKind(symbol, 'property').own.filter(isNoKeyword).sort(sortByAlias);
+ if ( ownProperties.length ) {
+ writeln("");
+ writeln("// ---- " + symbol.longname + " --------------------------------------------------------------------------");
+ writeln("");
+
+ for (var memberId in ownProperties ) {
+ var member = ownProperties[memberId];
+ comment(member, sMetaType);
+ writeln(qname(member, symbol) + " = " + value(member) + ";");
+ writeln("");
+ }
+ }
+ }
+
+ });
+
+ fs.mkPath(path.dirname(filename));
+ fs.writeFileSync(filename, output.join(""), 'utf8');
+ info(" saved as " + filename);
+}
+
+// Description + Settings
+
+function getConstructorDescription(symbol) {
+ var description = symbol.description;
+ var tags = symbol.tags;
+ if ( tags ) {
+ for (var i = 0; i < tags.length; i++) {
+ if ( tags[i].title === "ui5-settings" && tags[i].text) {
+ description += "\n \n" + tags[i].text;
+ break;
+ }
+ }
+ }
+ return description;
+}
+
+
+// Example
+
+function makeExample(example) {
+ var result = {
+ caption: null,
+ example: example
+ },
+ match = /^\s* block -------] [---- an empty line and surrounding whitespace ----] [---- new line or whitespaces ----] */
+var rNormalizeText = /(
]*)?>)|(<\/pre>)|([ \t]*(?:\r\n|\r|\n)[ \t]*(?:\r\n|\r|\n)[ \t\r\n]*)|([ \t]*(?:\r\n|\r|\n)[ \t]*|[ \t]+)/gi;
+
+function normalizeWS(text) {
+ if ( text == null ) {
+ return text;
+ }
+
+ var inpre = false;
+ return String(text).replace(rNormalizeText, function(match, pre, endpre, emptyline, ws) {
+ if ( pre ) {
+ inpre = true;
+ return pre;
+ } else if ( endpre ) {
+ inpre = false;
+ return endpre;
+ } else if ( emptyline ) {
+ return inpre ? emptyline : '\n\n';
+ } else if ( ws ) {
+ return inpre ? ws : ' ';
+ }
+ return match;
+ });
+
+}
+
+//---- add on: API JSON -----------------------------------------------------------------
+
+function createAPIJSON(symbols, filename) {
+
+ var api = {
+ "$schema-ref": "http://schemas.sap.com/sapui5/designtime/api.json/1.0"
+ }
+
+ if ( templateConf.version ) {
+ api.version = templateConf.version.replace(/-SNAPSHOT$/,"");
+ }
+ if ( templateConf.uilib ) {
+ api.library = templateConf.uilib;
+ }
+
+ api.symbols = [];
+ // sort only a copy(!) of the symbols, otherwise the SymbolSet lookup is broken
+ symbols.slice(0).sort(sortByAlias).forEach(function(symbol) {
+ if ( isaClass(symbol) && !symbol.synthetic ) { // dump a symbol if it as a class symbol and if it is not a synthetic symbol
+ api.symbols.push(createAPIJSON4Symbol(symbol, false));
+ }
+ });
+
+ postProcessAPIJSON(api);
+
+ fs.mkPath(path.dirname(filename));
+ fs.writeFileSync(filename, JSON.stringify(api), 'utf8');
+ info(" apiJson saved as " + filename);
+}
+
+function createAPIJSON4Symbol(symbol, omitDefaults) {
+
+ var obj = [];
+ var curr = obj;
+ var attribForKind = 'kind';
+ var stack = [];
+
+ function isEmpty(obj) {
+ if ( !obj ) {
+ return true;
+ }
+ for (var n in obj) {
+ if ( obj.hasOwnProperty(n) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function tag(name, value, omitEmpty) {
+
+ if ( omitEmpty && !value ) {
+ return;
+ }
+ if ( arguments.length === 1 ) { // opening tag
+ stack.push(curr);
+ stack.push(attribForKind);
+ var obj = {};
+ if ( Array.isArray(curr) ) {
+ if ( attribForKind != null ) {
+ obj[attribForKind] = name;
+ }
+ curr.push(obj);
+ } else {
+ curr[name] = obj;
+ }
+ curr = obj;
+ attribForKind = null;
+ return;
+ }
+ if ( value == null ) {
+ curr[name] = true;
+ } else {
+ curr[name] = String(value);
+ }
+ }
+
+ function attrib(name, value, defaultValue, raw) {
+ var emptyTag = arguments.length === 1;
+ if ( omitDefaults && arguments.length >= 3 && value === defaultValue ) {
+ return;
+ }
+ curr[name] = emptyTag ? true : (raw ? value : String(value));
+ }
+
+ function closeTag(name, noIndent) {
+ attribForKind = stack.pop();
+ curr = stack.pop();
+ }
+
+ function collection(name, attribForKind) {
+ stack.push(curr);
+ stack.push(attribForKind);
+ // TODO only supported if this.curr was an object check or fully implement
+ curr = curr[name] = [];
+ attribForKind = attribForKind || null;
+ }
+
+ function endCollection(name) {
+ attribForKind = stack.pop();
+ curr = stack.pop();
+ }
+
+ function tagWithSince(name, value) {
+
+ if ( !value ) {
+ return;
+ }
+
+ var info = extractSince(value);
+
+ tag(name);
+ if ( info.since ) {
+ attrib("since", info.since);
+ }
+ if ( info.value ) {
+ curr["text"] = normalizeWS(info.value);
+ }
+ closeTag(name, true);
+
+ }
+
+ function examples(symbol) {
+ var j, example;
+
+ if ( symbol.examples && symbol.examples.length ) {
+ collection("examples");
+ for ( j = 0; j < symbol.examples.length; j++) {
+ example = makeExample(symbol.examples[j]);
+ tag("example");
+ if ( example.caption ) {
+ attrib("caption", example.caption);
+ }
+ attrib("text", example.example);
+ closeTag("example");
+ }
+ endCollection("examples");
+ }
+ }
+
+ function referencesList(symbol) {
+ if ( symbol.see && symbol.see.length ) {
+ curr["references"] = symbol.see.slice();
+ }
+ }
+
+ function visibility($) {
+ if ( $.access === 'protected' ) {
+ return "protected";
+ } else if ( $.access === 'restricted' ) {
+ return "restricted";
+ } else if ( $.access === 'private' ) {
+ return "private";
+ } else {
+ return "public";
+ }
+ }
+
+ function exceptions(symbol) {
+ var array = symbol.exceptions,
+ j, exception;
+
+ if ( Array.isArray(array) ) {
+ array = array.filter( function (ex) {
+ return (ex.type && listTypes(ex.type)) || (ex.description && ex.description.trim());
+ });
+ }
+ if ( array == null || array.length === 0 ) {
+ return;
+ }
+
+ collection("throws");
+ for (j = 0; j < array.length; j++) {
+ exception = array[j];
+ tag("exception");
+ if ( exception.type !== undefined ) {
+ attrib("type", listTypes(exception.type));
+ }
+ tag("description", normalizeWS(exception.description), true);
+ closeTag("exception");
+ }
+ endCollection("throws");
+ }
+
+ function methodList(tagname, methods) {
+ methods = methods && Object.keys(methods).map(function(key) { return methods[key]; });
+ if ( methods != null && methods.length > 0 ) {
+ curr[tagname] = methods;
+ }
+ }
+
+ function interfaceList(tagname, interfaces) {
+ if ( interfaces != null && interfaces.length > 0 ) {
+ curr[tagname] = interfaces.slice();
+ }
+ }
+
+ function hasSettings($, visited) {
+
+ visited = visited || {};
+
+ if ( $.augments && $.augments.length > 0 ) {
+ var baseSymbol = $.augments[0];
+ if ( visited.hasOwnProperty(baseSymbol) ) {
+ error("detected cyclic inheritance when looking at " + $.longname + ": " + JSON.stringify(visited));
+ return false;
+ }
+ visited[baseSymbol] = true;
+ baseSymbol = lookup(baseSymbol) ;
+ if ( hasSettings(baseSymbol, visited) ) {
+ return true;
+ }
+ }
+
+ var metadata = $.__ui5.metadata;
+ return metadata &&
+ (
+ !isEmpty(metadata.specialSettings)
+ || !isEmpty(metadata.properties)
+ || !isEmpty(metadata.aggregations)
+ || !isEmpty(metadata.associations)
+ || !isEmpty(metadata.annotations)
+ || !isEmpty(metadata.events)
+ );
+ }
+
+ function writeMetadata($) {
+
+ var metadata = $.__ui5.metadata;
+ if ( !metadata ) {
+ return;
+ }
+
+ var n;
+
+ if ( metadata.specialSettings && Object.keys(metadata.specialSettings).length > 0 ) {
+ collection("specialSettings");
+ for ( n in metadata.specialSettings ) {
+ var special = metadata.specialSettings[n];
+ tag("specialSetting");
+ attrib("name", special.name);
+ attrib("type", special.type);
+ attrib("visibility", special.visibility, 'public');
+ if ( special.since ) {
+ attrib("since", extractVersion(special.since));
+ }
+ tag("description", normalizeWS(special.doc), true);
+ tagWithSince("experimental", special.experimental);
+ tagWithSince("deprecated", special.deprecation);
+ methodList("method", special.methods);
+ closeTag("specialSetting");
+ }
+ endCollection("specialSettings");
+ }
+
+ if ( metadata.properties && Object.keys(metadata.properties).length > 0 ) {
+ collection("properties");
+ for ( n in metadata.properties ) {
+ var prop = metadata.properties[n];
+ tag("property");
+ attrib("name", prop.name);
+ attrib("type", prop.type, 'string');
+ attrib("defaultValue", prop.defaultValue, null, /* raw = */true);
+ attrib("group", prop.group, 'Misc');
+ attrib("visibility", prop.visibility, 'public');
+ if ( prop.since ) {
+ attrib("since", extractVersion(prop.since));
+ }
+ if ( prop.bindable ) {
+ attrib("bindable", prop.bindable, false, /* raw = */true);
+ }
+ tag("description", normalizeWS(prop.doc), true);
+ tagWithSince("experimental", prop.experimental);
+ tagWithSince("deprecated", prop.deprecation);
+ methodList("methods", prop.methods);
+ closeTag("property");
+ }
+ endCollection("properties");
+ }
+
+ if ( metadata.defaultProperty ) {
+ tag("defaultProperty", metadata.defaultProperty);
+ }
+
+ if ( metadata.dnd ) {
+ curr.dnd = metadata.dnd;
+ }
+
+ if ( metadata.aggregations && Object.keys(metadata.aggregations).length > 0 ) {
+ collection("aggregations");
+ for ( n in metadata.aggregations ) {
+ var aggr = metadata.aggregations[n];
+ tag("aggregation");
+ attrib("name", aggr.name);
+ attrib("singularName", aggr.singularName); // TODO omit default?
+ attrib("type", aggr.type, 'sap.ui.core.Control');
+ if ( aggr.altTypes ) {
+ curr.altTypes = aggr.altTypes.slice();
+ }
+ attrib("cardinality", aggr.cardinality, '0..n');
+ attrib("visibility", aggr.visibility, 'public');
+ if ( aggr.since ) {
+ attrib("since", extractVersion(aggr.since));
+ }
+ if ( aggr.bindable ) {
+ attrib("bindable", aggr.bindable, false, /* raw = */true);
+ }
+ if ( aggr.dnd ) {
+ curr.dnd = aggr.dnd;
+ }
+ tag("description", normalizeWS(aggr.doc), true);
+ tagWithSince("experimental", aggr.experimental);
+ tagWithSince("deprecated", aggr.deprecation);
+ methodList("methods", aggr.methods);
+ closeTag("aggregation");
+ }
+ endCollection("aggregations");
+ }
+
+ if ( metadata.defaultAggregation ) {
+ tag("defaultAggregation", metadata.defaultAggregation);
+ }
+
+ if ( metadata.associations && Object.keys(metadata.associations).length > 0 ) {
+ collection("associations");
+ for ( n in metadata.associations ) {
+ var assoc = metadata.associations[n];
+ tag("association");
+ attrib("name", assoc.name);
+ attrib("singularName", assoc.singularName); // TODO omit default?
+ attrib("type", assoc.type, 'sap.ui.core.Control');
+ attrib("cardinality", assoc.cardinality, '0..1');
+ attrib("visibility", assoc.visibility, 'public');
+ if ( assoc.since ) {
+ attrib("since", extractVersion(assoc.since));
+ }
+ tag("description", normalizeWS(assoc.doc), true);
+ tagWithSince("experimental", assoc.experimental);
+ tagWithSince("deprecated", assoc.deprecation);
+ methodList("methods", assoc.methods);
+ closeTag("association");
+ }
+ endCollection("associations");
+ }
+
+ if ( metadata.events && Object.keys(metadata.events).length > 0 ) {
+ collection("events");
+ for ( n in metadata.events ) {
+ var event = metadata.events[n];
+ tag("event");
+ attrib("name", event.name);
+ attrib("visibility", event.visibility, 'public');
+ if ( event.since ) {
+ attrib("since", extractVersion(event.since));
+ }
+ tag("description", normalizeWS(event.doc), true);
+ tagWithSince("experimental", event.experimental);
+ tagWithSince("deprecated", event.deprecation);
+ if ( event.parameters && Object.keys(event.parameters).length > 0 ) {
+ tag("parameters");
+ for ( var pn in event.parameters ) {
+ if ( event.parameters.hasOwnProperty(pn) ) {
+ var param = event.parameters[pn];
+ tag(pn);
+ attrib("name", pn);
+ attrib("type", param.type);
+ if ( param.since ) {
+ attrib("since", extractVersion(param.since));
+ }
+ tag("description", normalizeWS(param.doc), true);
+ tagWithSince("experimental", param.experimental);
+ tagWithSince("deprecated", param.deprecation);
+ closeTag(pn);
+ }
+ }
+ closeTag("parameters");
+ }
+ methodList("methods", event.methods, true);
+ closeTag("event");
+ }
+ endCollection("events");
+ }
+
+ if ( metadata.annotations && Object.keys(metadata.annotations).length > 0 ) {
+ collection("annotations");
+ for ( n in metadata.annotations ) {
+ var anno = metadata.annotations[n];
+ tag("annotation");
+ attrib("name", anno.name);
+ attrib("namespace", anno.namespace);
+ if ( anno.target && anno.target.length > 0 ) {
+ curr.target = anno.target.slice();
+ }
+ attrib("annotation", anno.annotation);
+ attrib("defaultValue", anno.defaultValue);
+ if ( anno.appliesTo && anno.appliesTo.length > 0 ) {
+ curr.appliesTo = anno.appliesTo.slice();
+ }
+ if ( anno.since ) {
+ attrib("since", extractVersion(anno.since));
+ }
+ tag("description", normalizeWS(anno.doc), true);
+ tagWithSince("deprecated", anno.deprecation);
+ closeTag("annotation");
+ }
+ endCollection("annotations");
+ }
+
+ if ( metadata.designtime ) { // don't write falsy values
+ tag("designtime", metadata.designtime);
+ }
+
+ }
+
+ function writeParameterProperties(paramName, params) {
+ var prefix = paramName + '.',
+ count = 0,
+ i;
+
+ for ( i = 0; i < params.length; i++ ) {
+
+ var name = params[i].name;
+ if ( name.lastIndexOf(prefix, 0) !== 0 ) { // startsWith
+ continue;
+ }
+ name = name.slice(prefix.length);
+ if ( name.indexOf('.') >= 0 ) {
+ continue;
+ }
+
+ if ( count === 0 ) {
+ tag("parameterProperties");
+ }
+
+ count++;
+
+ tag(name);
+ attrib("name", name);
+ attrib("type", listTypes(params[i].type));
+ attrib("optional", !!params[i].optional, false, /* raw = */true);
+ if ( params[i].defaultvalue !== undefined ) {
+ attrib("defaultValue", params[i].defaultvalue, undefined, /* raw = */true);
+ }
+ if ( params[i].since ) {
+ attrib("since", extractVersion(params[i].since));
+ }
+
+ writeParameterProperties(params[i].name, params);
+
+ tag("description", normalizeWS(params[i].description), true);
+ tagWithSince("experimental", params[i].experimental);
+ tagWithSince("deprecated", params[i].deprecated);
+
+ closeTag(name);
+ }
+
+ if ( count > 0 ) {
+ closeTag("parameterProperties");
+ }
+ }
+
+ /*
+ var rSplitSecTag = /^\s*\{([^\}]*)\}/;
+
+ function secTags($) {
+ if ( true ) {
+ return;
+ }
+ var aTags = $.tags;
+ if ( !aTags ) {
+ return;
+ }
+ for (var iTag = 0; iTag < A_SECURITY_TAGS.length; iTag++ ) {
+ var oTagDef = A_SECURITY_TAGS[iTag];
+ for (var j = 0; j < aTags.length; j++ ) {
+ if ( aTags[j].title.toLowerCase() === oTagDef.name.toLowerCase() ) {
+ tag(oTagDef.name);
+ var m = rSplitSecTag.exec(aTags[j].text);
+ if ( m && m[1].trim() ) {
+ var aParams = m[1].trim().split(/\s*\|\s* /); <-- remember to remove the space!
+ for (var iParam = 0; iParam < aParams.length; iParam++ ) {
+ tag(oTagDef.params[iParam], aParams[iParam]);
+ }
+ }
+ var sDesc = aTags[j].description;
+ tag("description", sDesc, true);
+ closeTag(oTagDef.name);
+ }
+ }
+ }
+ }
+ */
+
+ var kind = (symbol.kind === 'member' && symbol.isEnum) ? "enum" : symbol.kind; // handle pseudo-kind 'enum'
+
+ tag(kind);
+
+ attrib("name", symbol.longname);
+ attrib("basename", symbol.name);
+ if ( symbol.__ui5.resource ) {
+ attrib("resource", symbol.__ui5.resource);
+ }
+ if ( symbol.__ui5.module ) {
+ attrib("module", symbol.__ui5.module);
+ attrib("export", undefined, '', true);
+ }
+ if ( symbol.virtual ) {
+ attrib("abstract", true, false, /* raw = */true);
+ }
+ if ( symbol.final_ ) {
+ attrib("final", true, false, /* raw = */true);
+ }
+ if ( symbol.scope === 'static' ) {
+ attrib("static", true, false, /* raw = */true);
+ }
+ attrib("visibility", visibility(symbol), 'public');
+ if ( symbol.since ) {
+ attrib("since", extractVersion(symbol.since));
+ }
+ if ( symbol.augments && symbol.augments.length ) {
+ tag("extends", symbol.augments.sort().join(",")); // TODO what about multiple inheritance?
+ }
+ interfaceList("implements", symbol.implements);
+ tag("description", normalizeWS(symbol.classdesc || (symbol.kind === 'class' ? '' : symbol.description)), true);
+ tagWithSince("experimental", symbol.experimental);
+ tagWithSince("deprecated", symbol.deprecated);
+ if ( symbol.tags && symbol.tags.some(function(tag) { return tag.title === 'ui5-metamodel'; }) ) {
+ attrib('ui5-metamodel', true, false, /* raw = */true);
+ }
+
+ var i, j, member, param;
+
+ if ( kind === 'class' ) {
+
+ if ( symbol.__ui5.stereotype || hasSettings(symbol) ) {
+
+ tag("ui5-metadata");
+
+ if ( symbol.__ui5.stereotype ) {
+ attrib("stereotype", symbol.__ui5.stereotype);
+ }
+
+ writeMetadata(symbol);
+
+ closeTag("ui5-metadata");
+ }
+
+
+ // IF @hideconstructor tag is present we omit the whole constructor
+ if ( !symbol.hideconstructor ) {
+
+ tag("constructor");
+ attrib("visibility", visibility(symbol));
+ if (symbol.params && symbol.params.length > 0) {
+ collection("parameters");
+ for (j = 0; j < symbol.params.length; j++) {
+ param = symbol.params[j];
+ if (param.name.indexOf('.') >= 0) {
+ continue;
+ }
+ tag("parameter");
+ attrib("name", param.name);
+ attrib("type", listTypes(param.type));
+ attrib("optional", !!param.optional, false, /* raw = */true);
+ if (param.defaultvalue !== undefined) {
+ attrib("defaultValue", param.defaultvalue, undefined, /* raw = */true);
+ }
+ if (param.since) {
+ attrib("since", extractVersion(param.since));
+ }
+
+ writeParameterProperties(param.name, symbol.params);
+ tag("description", normalizeWS(param.description), true);
+ tagWithSince("experimental", param.experimental);
+ tagWithSince("deprecated", param.deprecated);
+ closeTag("parameter");
+ }
+ endCollection("parameters");
+ }
+ exceptions(symbol);
+ tag("description", normalizeWS(symbol.description), true);
+ // tagWithSince("experimental", symbol.experimental); // TODO repeat from class?
+ // tagWithSince("deprecated", symbol.deprecated); // TODO repeat from class?
+ examples(symbol); // TODO here or for class?
+ referencesList(symbol); // TODO here or for class?
+ // secTags(symbol); // TODO repeat from class?
+ closeTag("constructor");
+
+ }
+ } else if ( kind === 'namespace' ) {
+ if ( symbol.__ui5.stereotype || symbol.__ui5.metadata ) {
+ tag("ui5-metadata");
+
+ if ( symbol.__ui5.stereotype ) {
+ attrib("stereotype", symbol.__ui5.stereotype);
+ }
+
+ if ( symbol.__ui5.metadata && symbol.__ui5.metadata.basetype ) {
+ attrib("basetype", symbol.__ui5.metadata.basetype);
+ }
+
+ if ( symbol.__ui5.metadata && symbol.__ui5.metadata.pattern ) {
+ attrib("pattern", symbol.__ui5.metadata.pattern);
+ }
+
+ if ( symbol.__ui5.metadata && symbol.__ui5.metadata.range ) {
+ attrib("range", symbol.__ui5.metadata.range, null, /* raw = */ true);
+ }
+
+ closeTag("ui5-metadata");
+ }
+ }
+
+ var ownProperties = childrenOfKind(symbol, "property").own.sort(sortByAlias);
+ if ( ownProperties.length > 0 ) {
+ collection("properties");
+ for ( i = 0; i < ownProperties.length; i++ ) {
+ member = ownProperties[i];
+ tag("property");
+ attrib("name", member.name);
+ if ( member.__ui5.module && member.__ui5.module !== symbol.__ui5.module ) {
+ attrib("module", member.__ui5.module);
+ attrib("export", undefined, '', true);
+ }
+ attrib("visibility", visibility(member), 'public');
+ if ( member.scope === 'static' ) {
+ attrib("static", true, false, /* raw = */true);
+ }
+ if ( member.since ) {
+ attrib("since", extractVersion(member.since));
+ }
+ attrib("type", listTypes(member.type));
+ tag("description", normalizeWS(member.description), true);
+ tagWithSince("experimental", member.experimental);
+ tagWithSince("deprecated", member.deprecated);
+ examples(member);
+ referencesList(member);
+ if ( member.__ui5.resource && member.__ui5.resource !== symbol.__ui5.resource ) {
+ attrib("resource", member.__ui5.resource);
+ }
+ closeTag("property");
+ }
+ endCollection("properties");
+ }
+
+ var ownEvents = childrenOfKind(symbol, 'event').own.sort(sortByAlias);
+ if ( ownEvents.length > 0 ) {
+ collection("events");
+ for (i = 0; i < ownEvents.length; i++ ) {
+ member = ownEvents[i];
+ tag("event");
+ attrib("name", member.name);
+ if ( member.__ui5.module && member.__ui5.module !== symbol.__ui5.module ) {
+ attrib("module", member.__ui5.module);
+ attrib("export", undefined, '', true);
+ }
+ attrib("visibility", visibility(member), 'public');
+ if ( member.scope === 'static' ) {
+ attrib("static", true, false, /* raw = */true);
+ }
+ if ( member.since ) {
+ attrib("since", extractVersion(member.since));
+ }
+
+ if ( member.params && member.params.length > 0 ) {
+ collection("parameters");
+ for (j = 0; j < member.params.length; j++) {
+ param = member.params[j];
+ if ( param.name.indexOf('.') >= 0 ) {
+ continue;
+ }
+
+ tag("parameter");
+ attrib("name", param.name);
+ attrib("type", listTypes(param.type));
+ if ( param.since ) {
+ attrib("since", extractVersion(param.since));
+ }
+ writeParameterProperties(param.name, member.params);
+ tag("description", normalizeWS(param.description), true);
+ tagWithSince("experimental", param.experimental);
+ tagWithSince("deprecated", param.deprecated);
+ closeTag("parameter");
+ }
+ endCollection("parameters");
+ }
+ tag("description", normalizeWS(member.description), true);
+ tagWithSince("deprecated", member.deprecated);
+ tagWithSince("experimental", member.experimental);
+ examples(member);
+ referencesList(member);
+ //secTags(member);
+ if ( member.__ui5.resource && member.__ui5.resource !== symbol.__ui5.resource ) {
+ attrib("resource", member.__ui5.resource);
+ }
+ closeTag("event");
+ }
+ endCollection("events");
+ }
+
+ var ownMethods = childrenOfKind(symbol, 'method').own.sort(sortByAlias);
+ if ( ownMethods.length > 0 ) {
+ collection("methods");
+ for ( i = 0; i < ownMethods.length; i++ ) {
+ member = ownMethods[i];
+ tag("method");
+ attrib("name", member.name);
+ if ( member.__ui5.module && member.__ui5.module !== symbol.__ui5.module ) {
+ attrib("module", member.__ui5.module);
+ attrib("export", undefined, '', true);
+ }
+ attrib("visibility", visibility(member), 'public');
+ if ( member.scope === 'static' ) {
+ attrib("static", true, false, /* raw = */true);
+ }
+ if ( member.tags && member.tags.some(function(tag) { return tag.title === 'ui5-metamodel'; }) ) {
+ attrib('ui5-metamodel', true, false, /* raw = */true);
+ }
+
+ var returns = member.returns && member.returns.length && member.returns[0];
+ var type = member.type || (returns && returns.type);
+ type = listTypes(type);
+ //if ( type && type !== 'void' ) {
+ // attrib("type", type, 'void');
+ //}
+ if ( type && type !== 'void' || returns && returns.description ) {
+ tag("returnValue");
+ if ( type && type !== 'void' ) {
+ attrib("type", type);
+ }
+ if ( returns && returns.description ) {
+ attrib("description", normalizeWS(returns.description));
+ }
+ closeTag("returnValue");
+ }
+ if ( member.since ) {
+ attrib("since", extractVersion(member.since));
+ }
+
+ if ( member.params && member.params.length > 0 ) {
+ collection("parameters");
+ for ( j = 0; j < member.params.length; j++) {
+ param = member.params[j];
+ if ( param.name.indexOf('.') >= 0 ) {
+ continue;
+ }
+ tag("parameter");
+ attrib("name", param.name);
+ attrib("type", listTypes(param.type));
+ attrib("optional", !!param.optional, false, /* raw = */true);
+ if ( param.defaultvalue !== undefined ) {
+ attrib("defaultValue", param.defaultvalue, undefined, /* raw = */true);
+ }
+ if ( param.since ) {
+ attrib("since", extractVersion(param.since));
+ }
+ writeParameterProperties(param.name, member.params);
+ tag("description", normalizeWS(param.description), true);
+ tagWithSince("experimental", param.experimental);
+ tagWithSince("deprecated", param.deprecated);
+ closeTag("parameter");
+ }
+ endCollection("parameters");
+ }
+ exceptions(member);
+ tag("description", normalizeWS(member.description), true);
+ tagWithSince("experimental", member.experimental);
+ tagWithSince("deprecated", member.deprecated);
+ examples(member);
+ referencesList(member);
+ //secTags(member);
+ if ( member.__ui5.resource && member.__ui5.resource !== symbol.__ui5.resource ) {
+ attrib("resource", member.__ui5.resource);
+ }
+ closeTag("method");
+ }
+ endCollection("methods");
+ }
+
+// if ( roots && symbol.__ui5.children && symbol.__ui5.children.length ) {
+// collection("children", "kind");
+// symbol.__ui5.children.forEach(writeSymbol);
+// endCollection("children");
+// }
+
+ closeTag(kind);
+
+ return obj[0];
+}
+
+function postProcessAPIJSON(api) {
+ var modules = {};
+ var symbols = api.symbols;
+ var i,j,n,symbol,defaultExport;
+
+ // collect modules and the symbols that refer to them
+ for ( i = 0; i < symbols.length; i++) {
+ symbol = symbols[i];
+ if ( symbol.module ) {
+ modules[symbol.module] = modules[symbol.module] || [];
+ modules[symbol.module].push({
+ name: symbol.name,
+ symbol: symbol
+ });
+ }
+ if ( symbol.properties ) {
+ for ( j = 0; j < symbol.properties.length; j++ ) {
+ if ( symbol.properties[j].static && symbol.properties[j].module ) {
+ modules[symbol.properties[j].module] = modules[symbol.properties[j].module] || [];
+ modules[symbol.properties[j].module].push({
+ name: symbol.name + "." + symbol.properties[j].name,
+ symbol: symbol.properties[j]
+ });
+ }
+ }
+ }
+ if ( symbol.methods ) {
+ for ( j = 0; j < symbol.methods.length; j++ ) {
+ if ( symbol.methods[j].static && symbol.methods[j].module ) {
+ modules[symbol.methods[j].module] = modules[symbol.methods[j].module] || [];
+ modules[symbol.methods[j].module].push({
+ name: symbol.name + "." + symbol.methods[j].name,
+ symbol: symbol.methods[j]
+ });
+ }
+ }
+ }
+ }
+
+ function guessExport(defaultExport, symbol) {
+ if ( symbol.name === defaultExport ) {
+ // default export equals the symbol name
+ symbol.symbol.export = "";
+ //console.log(" (default):" + defaultExport);
+ } else if ( symbol.name.lastIndexOf(defaultExport + ".", 0) === 0 ) {
+ // default export is a prefix of the symbol name
+ symbol.symbol.export = symbol.name.slice(defaultExport.length + 1);
+ //console.log(" " + symbol.name.slice(defaultExport.length + 1) + ":" + symbol.name);
+ } else {
+ // default export is not a prefix of the symbol name -> no way to access it in AMD
+ symbol.symbol.export = undefined;
+ console.log(" **** could not identify module export for API " + symbol.name);
+ }
+ }
+
+ for ( n in modules ) {
+
+ symbols = modules[n].sort(function(a,b) {
+ if ( a.name === b.name ) {
+ return 0;
+ }
+ return a.name < b.name ? -1 : 1;
+ });
+
+ // console.log(' resolved exports of ' + n + ": " + symbols.map(function(symbol) { return symbol.name; } ));
+ if ( /^jquery\.sap\./.test(n) ) {
+ // the jquery.sap.* modules all export 'jQuery'.
+ // any API from those modules is reachable via 'jQuery.*'
+ defaultExport = 'jQuery';
+ symbols.forEach(
+ guessExport.bind(this, defaultExport)
+ );
+ } else if ( /\/library$/.test(n) ) {
+ // library.js modules export the library namespace
+ defaultExport = n.replace(/\/library$/, "").replace(/\//g, ".");
+ if ( symbols.some(function(symbol) { return symbol.name === defaultExport; }) ) {
+ // if there is a symbol for the namespace, then all other symbols from the module should be sub-exports of that symbol
+ symbols.forEach(
+ guessExport.bind(this, defaultExport)
+ );
+ } else {
+ // otherwise, we don't know how to map it to an export
+ symbols.forEach(function(symbol) {
+ symbol.symbol.export = symbol.name;
+ console.log(" **** unresolved " + symbol.name + " in library.js (no export that matches module name)");
+ });
+ }
+ } else {
+ // for all other modules, the assumed default export is identical to the name of the module (converted to a 'dot' name)
+ defaultExport = n.replace(/\//g, ".");
+ if ( symbols.some(function(symbol) { return symbol.name === defaultExport; }) ) {
+ symbols.forEach(
+ guessExport.bind(this, defaultExport)
+ );
+ //} else if ( symbols.length === 1 && (symbols[0].symbol.kind === 'class' || symbols[0].symbol.kind === 'namespace') ) {
+ // if there is only one symbol and if that symbol is of type class or namespace, assume it is the default export
+ // TODO is that assumption safe? Was only done because of IBarPageEnabler (which maybe better should be fixed in the JSDoc)
+ //symbols[0].symbol.export = '';
+ } else {
+ symbols.forEach(function(symbol) {
+ symbol.symbol.export = undefined;
+ console.log(" **** unresolved " + symbol.name + " (no export that matches module name)");
+ });
+ }
+ }
+ }
+}
+
+//---- add on: API XML -----------------------------------------------------------------
+
+function createAPIXML(symbols, filename, options) {
+
+ options = options || {};
+ var roots = options.roots || null;
+ var legacyContent = !!options.legacyContent;
+ var omitDefaults = !!options.omitDefaults;
+ var addRedundancy = !!options.resolveInheritance;
+
+ var indent = 0;
+ var output = [];
+ var sIndent = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+ var tags = [];
+ var ENUM = legacyContent ? "namespace" : "enum" ;
+ var BASETYPE = legacyContent ? "baseType" : "extends";
+ var PROPERTY = legacyContent ? "parameter" : "property";
+ var unclosedStartTag = false;
+
+ function getAPIJSON(name) {
+
+ var symbol = lookup(name);
+ if ( symbol && !symbol.synthetic ) {
+ return createAPIJSON4Symbol(symbol, false);
+ }
+ if ( addRedundancy && externalSymbols[name] ) {
+ debug(" using " + name + " from external dependency");
+ return externalSymbols[name];
+ }
+ return symbol;
+ }
+
+ function encode(s) {
+ return s ? s.replace(/&/g, "&").replace(/ 0 )
+ output.push(sIndent.slice(0,indent));
+ if ( arguments.length ) {
+ for (var i = 0; i < arguments.length; i++)
+ output.push(arguments[i]);
+ }
+ output.push("\n");
+ }
+
+ function rootTag(name) {
+ tags = [];
+ unclosedStartTag = false;
+ tag(name);
+ }
+
+ function closeRootTag(name) {
+ closeTag(name);
+ }
+
+ function namespace(alias, namespace) {
+ attrib(alias, namespace);
+ }
+
+ function tag(name, value, omitEmpty) {
+
+ if ( omitEmpty && !value ) {
+ return;
+ }
+ if ( unclosedStartTag ) {
+ unclosedStartTag = false;
+ write('>\n');
+ }
+ if ( arguments.length === 1 ) { // opening tag
+ if ( indent > 0 ) {
+ output.push(sIndent.slice(0,indent));
+ }
+ write("<", name);
+ unclosedStartTag = true;
+ if ( legacyContent ) {
+ unclosedStartTag = false;
+ write(">\n");
+ }
+ tags.push(name);
+ indent++;
+ return;
+ }
+ if ( value == null ) {
+ writeln("<", name, "/>");
+ } else {
+ writeln("<", name, ">", encode(String(value)), "", name, ">");
+ }
+ }
+
+ function attrib(name, value, defaultValue) {
+ var emptyTag = arguments.length === 1;
+ if ( omitDefaults && arguments.length === 3 && value === defaultValue ) {
+ return;
+ }
+
+ if ( !legacyContent ) {
+ write(" " + name + "=\"");
+ write(emptyTag ? "true" : encode(String(value)).replace(/"/g, """));
+ write("\"");
+ } else {
+ if ( emptyTag ) {
+ writeln("<", name, "/>");
+ } else {
+ writeln("<", name, ">", encode(String(value)), "", name, ">");
+ }
+ }
+ }
+
+ function closeTag(name, noIndent) {
+
+ indent--;
+ var top = tags.pop();
+ if ( top != name ) {
+ // ERROR?
+ }
+
+ if ( unclosedStartTag ) {
+ unclosedStartTag = false;
+ write("/>\n");
+ } else if ( noIndent ) {
+ write("", name, ">\n");
+ } else {
+ writeln("", name, ">");
+ }
+ }
+
+ function textContent(text) {
+ if ( unclosedStartTag ) {
+ unclosedStartTag = false;
+ write('>');
+ }
+ write(encode(text));
+ }
+
+ function tagWithSince(tagName, prop) {
+ if ( prop ) {
+ tag(tagName);
+ if ( prop.since ) {
+ attrib("since", prop.since);
+ }
+ if ( prop.text && prop.text.trim() ) {
+ textContent(prop.text);
+ }
+ closeTag(tagName, true);
+ }
+ }
+
+ function getAsString() {
+ return output.join("");
+ }
+
+ function writeMetadata(symbolAPI, inherited) {
+
+ var ui5Metadata = symbolAPI["ui5-metadata"];
+ if ( !ui5Metadata ) {
+ return;
+ }
+
+ if ( addRedundancy && symbolAPI["extends"] ) {
+ var baseSymbolAPI = getAPIJSON(symbolAPI["extends"]);
+ if ( baseSymbolAPI ) {
+ writeMetadata(baseSymbolAPI, true);
+ }
+ }
+
+ if ( ui5Metadata.specialSettings ) {
+ ui5Metadata.specialSettings.forEach(function(special) {
+ tag("specialSetting");
+ attrib("name", special.name);
+ attrib("type", special.type);
+ attrib("visibility", special.visibility, 'public');
+ if ( special.since ) {
+ attrib("since", special.since);
+ }
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", special.description, true);
+ tagWithSince("experimental", special.experimental);
+ tagWithSince("deprecated", special.deprecated);
+ tag("methods", special.methods);
+ closeTag("specialSetting");
+ });
+ }
+
+ if ( ui5Metadata.properties ) {
+ ui5Metadata.properties.forEach(function(prop) {
+ tag("property");
+ attrib("name", prop.name);
+ attrib("type", prop.type, 'string');
+ if ( prop.defaultValue !== null ) {
+ attrib("defaultValue", prop.defaultValue, null);
+ }
+ attrib("visibility", prop.visibility, 'public');
+ if ( prop.since ) {
+ attrib("since", prop.since);
+ }
+ if ( prop.bindable ) {
+ attrib("bindable", prop.bindable);
+ }
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", prop.description, true);
+ tagWithSince("experimental", prop.experimental);
+ tagWithSince("deprecated", prop.deprecated);
+ tag("methods", prop.methods);
+ closeTag("property");
+ });
+ }
+
+ if ( ui5Metadata.defaultProperty ) {
+ tag("defaultProperty", ui5Metadata.defaultProperty);
+ }
+
+ if ( ui5Metadata.aggregations ) {
+ ui5Metadata.aggregations.forEach(function(aggr) {
+ tag("aggregation");
+ attrib("name", aggr.name);
+ attrib("singularName", aggr.singularName); // TODO omit default?
+ attrib("type", aggr.type, 'sap.ui.core.Control');
+ if ( aggr.altTypes ) {
+ attrib("altTypes", aggr.altTypes.join(","));
+ }
+ attrib("cardinality", aggr.cardinality, '0..n');
+ attrib("visibility", aggr.visibility, 'public');
+ if ( aggr.since ) {
+ attrib("since", aggr.since);
+ }
+ if ( aggr.bindable ) {
+ attrib("bindable", aggr.bindable);
+ }
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", aggr.description, true);
+ tagWithSince("experimental", aggr.experimental);
+ tagWithSince("deprecated", aggr.deprecated);
+ tag("methods", aggr.methods);
+ closeTag("aggregation");
+ });
+ }
+
+ if ( ui5Metadata.defaultAggregation ) {
+ tag("defaultAggregation", ui5Metadata.defaultAggregation);
+ }
+
+ if ( ui5Metadata.associations ) {
+ ui5Metadata.associations.forEach(function(assoc) {
+ tag("association");
+ attrib("name", assoc.name);
+ attrib("singularName", assoc.singularName); // TODO omit default?
+ attrib("type", assoc.type, 'sap.ui.core.Control');
+ attrib("cardinality", assoc.cardinality, '0..1');
+ attrib("visibility", assoc.visibility, 'public');
+ if ( assoc.since ) {
+ attrib("since", assoc.since);
+ }
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", assoc.description, true);
+ tagWithSince("experimental", assoc.experimental);
+ tagWithSince("deprecated", assoc.deprecated);
+ tag("methods", assoc.methods);
+ closeTag("association");
+ });
+ }
+
+ if ( ui5Metadata.events ) {
+ ui5Metadata.events.forEach(function(event) {
+ tag("event");
+ attrib("name", event.name);
+ attrib("visibility", event.visibility, 'public');
+ if ( event.since ) {
+ attrib("since", event.since);
+ }
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", event.description, true);
+ tagWithSince("experimental", event.experimental);
+ tagWithSince("deprecated", event.deprecated);
+ if ( event.parameters ) {
+ tag("parameters");
+ for ( var pn in event.parameters ) {
+ if ( event.parameters.hasOwnProperty(pn) ) {
+ var param = event.parameters[pn];
+
+ tag("parameter");
+ attrib("name", param.name);
+ attrib("type", param.type);
+ if ( param.since ) {
+ attrib("since", param.since);
+ }
+ tag("description", param.description, true);
+ tagWithSince("experimental", param.experimental);
+ tagWithSince("deprecated", param.deprecated);
+ closeTag("parameter");
+ }
+ }
+ closeTag("parameters");
+ }
+ tag("methods", event.methods, true);
+ closeTag("event");
+ });
+ }
+
+ if ( ui5Metadata.annotations ) {
+ ui5Metadata.annotations.forEach(function(anno) {
+ tag("annotation");
+ attrib("name", anno.name);
+ attrib("namespace", anno.namespace); // TODO omit default?
+ attrib("target", anno.target);
+ attrib("annotation", anno.annotation);
+ attrib("appliesTo", anno.appliesTo);
+ if ( anno.since ) {
+ attrib("since", anno.since);
+ }
+ tag("description", anno.description, true);
+ tagWithSince("deprecated", anno.deprecated);
+ closeTag("annotation");
+ });
+ }
+
+ }
+
+ function writeParameterPropertiesForMSettings(symbolAPI, inherited) {
+
+ var ui5Metadata = symbolAPI["ui5-metadata"];
+ if ( !ui5Metadata ) {
+ return;
+ }
+
+ if ( symbolAPI["extends"] ) {
+ var baseSymbolAPI = getAPIJSON(symbolAPI["extends"]);
+ writeParameterPropertiesForMSettings(baseSymbolAPI, true);
+ }
+
+ if ( ui5Metadata.specialSettings ) {
+ ui5Metadata.specialSettings.forEach(function(special) {
+ if ( special.visibility !== 'hidden' ) {
+ tag("property");
+ attrib("name", special.name);
+ attrib("type", special.type);
+ attrib("optional");
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", special.description, true);
+ closeTag("property");
+ }
+ });
+ }
+
+ if ( ui5Metadata.properties ) {
+ ui5Metadata.properties.forEach(function(prop) {
+ tag("property");
+ attrib("name", prop.name);
+ attrib("type", prop.type);
+ attrib("group", prop.group, 'Misc');
+ if ( prop.defaultValue !== null ) {
+ attrib("defaultValue", typeof prop.defaultValue === 'string' ? "\"" + prop.defaultValue + "\"" : prop.defaultValue);
+ }
+ attrib("optional");
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", prop.description, true);
+ closeTag("property");
+ });
+ }
+
+ if ( ui5Metadata.aggregations ) {
+ ui5Metadata.aggregations.forEach(function(aggr) {
+ if ( aggr.visibility !== "hidden" ) {
+ tag("property");
+ attrib("name", aggr.name);
+ attrib("type", aggr.type + (aggr.cardinality === '0..1' ? "" : "[]"));
+ if ( aggr.altTypes ) {
+ attrib("altTypes", aggr.altTypes.join(","));
+ }
+ attrib("optional");
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", aggr.description, true);
+ closeTag("property");
+ }
+ });
+ }
+
+ if ( ui5Metadata.associations ) {
+ ui5Metadata.associations.forEach(function(assoc) {
+ if ( assoc.visibility !== "hidden" ) {
+ tag("property");
+ attrib("name", assoc.name);
+ attrib("type", "(" + assoc.type + "|" + "string)" + (assoc.cardinality === '0..1' ? "" : "[]"));
+ attrib("optional");
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", assoc.description, true);
+ closeTag("property");
+ }
+ });
+ }
+
+ if ( ui5Metadata.events ) {
+ ui5Metadata.events.forEach(function(event) {
+ tag("property");
+ attrib("name", event.name);
+ attrib("type", "function|array");
+ attrib("optional");
+ if ( inherited ) {
+ attrib("origin", symbolAPI.name);
+ }
+ tag("description", event.description, true);
+ closeTag("property");
+ });
+ }
+
+ }
+
+ function writeParameterProperties(param, paramName) {
+ var props = param.parameterProperties,
+ prefix = paramName + '.',
+ count = 0;
+
+ if ( props ) {
+ for (var n in props ) {
+ if ( props.hasOwnProperty(n) ) {
+
+ param = props[n];
+
+ if ( !legacyContent && count === 0 ) {
+ tag("parameterProperties");
+ }
+
+ count++;
+
+ tag(PROPERTY);
+ attrib("name", legacyContent ? prefix + n : n);
+ attrib("type", param.type);
+ if ( param.since ) {
+ attrib("since", param.since);
+ }
+ if ( param.optional ) {
+ attrib("optional", param.optional);
+ }
+
+ if ( !legacyContent ) {
+ writeParameterProperties(param, prefix + n);
+ }
+
+ tag("description", param.description, true);
+ tagWithSince("experimental", param.experimental);
+ tagWithSince("deprecated", param.deprecated);
+
+ closeTag(PROPERTY);
+
+ if ( legacyContent ) {
+ writeParameterProperties(param, prefix + n);
+ }
+ }
+ }
+ }
+
+ if ( !legacyContent && count > 0 ) {
+ closeTag("parameterProperties");
+ }
+ }
+
+ /*
+ var rSplitSecTag = /^\s*\{([^\}]*)\}/;
+
+ function secTags($) {
+ if ( !legacyContent ) {
+ return;
+ }
+ var aTags = $.tags;
+ if ( !aTags ) {
+ return;
+ }
+ for (var iTag = 0; iTag < A_SECURITY_TAGS.length; iTag++ ) {
+ var oTagDef = A_SECURITY_TAGS[iTag];
+ for (var j = 0; j < aTags.length; j++ ) {
+ if ( aTags[j].title.toLowerCase() === oTagDef.name.toLowerCase() ) {
+ tag(oTagDef.name);
+ var m = rSplitSecTag.exec(aTags[j].text);
+ if ( m && m[1].trim() ) {
+ var aParams = m[1].trim().split(/\s*\|\s* /); <-- remove the blank!
+ for (var iParam = 0; iParam < aParams.length; iParam++ ) {
+ tag(oTagDef.params[iParam], aParams[iParam]);
+ }
+ }
+ var sDesc = aTags[j].description;
+ tag("description", sDesc, true);
+ closeTag(oTagDef.name);
+ }
+ }
+ }
+ }
+ */
+
+ function writeSymbol(symbol) {
+
+ var kind;
+
+ if ( isaClass(symbol) && (roots || !symbol.synthetic) ) { // dump a symbol if it as a class symbol and if either hierarchies are dumped or if it is not a synthetic symbol
+
+ // for the hierarchy we use only the local information
+ var symbolAPI = createAPIJSON4Symbol(symbol);
+
+ kind = symbolAPI.kind === 'enum' ? ENUM : symbolAPI.kind;
+
+ tag(kind);
+
+ attrib("name", symbolAPI.name);
+ attrib("basename", symbolAPI.basename);
+// if ( symbolAPI["resource"] ) {
+// attrib("resource");
+// }
+ if ( symbolAPI["module"] ) {
+ attrib("module", symbolAPI["module"]);
+ }
+ if ( symbolAPI["abstract"] ) {
+ attrib("abstract");
+ }
+ if ( symbolAPI["final"] ) {
+ attrib("final");
+ }
+ if ( symbolAPI["static"] ) {
+ attrib("static");
+ }
+ attrib("visibility", symbolAPI.visibility, 'public');
+ if ( symbolAPI.since ) {
+ attrib("since", symbolAPI.since);
+ }
+ if ( symbolAPI["extends"] ) {
+ tag(BASETYPE, symbolAPI["extends"]); // TODO what about multiple inheritance?
+ }
+ tag("description", symbolAPI.description, true);
+ tagWithSince("experimental", symbolAPI.experimental);
+ tagWithSince("deprecated", symbolAPI.deprecated);
+
+ if ( kind === 'class' ) {
+
+ var hasSettings = symbolAPI["ui5-metadata"];
+
+ if ( !legacyContent && symbolAPI["ui5-metadata"] ) {
+
+ tag("ui5-metadata");
+
+ if ( symbolAPI["ui5-metadata"].stereotype ) {
+ attrib("stereotype", symbolAPI["ui5-metadata"].stereotype);
+ }
+
+ writeMetadata(symbolAPI);
+
+ closeTag("ui5-metadata");
+
+ }
+
+ tag("constructor");
+ if ( legacyContent ) {
+ attrib("name", symbolAPI.basename);
+ }
+ attrib("visibility", symbolAPI.visibility, 'public');
+ if ( symbolAPI.constructor.parameters ) {
+ symbolAPI.constructor.parameters.forEach(function(param, j) {
+
+ tag("parameter");
+ attrib("name", param.name);
+ attrib("type", param.type);
+ attrib("optional", param.optional, false);
+ if ( param.defaultValue !== undefined ) {
+ attrib("defaultValue", param.defaultValue);
+ }
+ if ( param.since ) {
+ attrib("since", param.since);
+ }
+
+ if ( !legacyContent ) {
+ if ( hasSettings && j == 1 && /setting/i.test(param.name) && /object/i.test(param.type) ) {
+ if ( addRedundancy ) {
+ tag("parameterProperties");
+ writeParameterPropertiesForMSettings(symbolAPI);
+ closeTag("parameterProperties");
+ }
+ } else {
+ writeParameterProperties(param, param.name);
+ }
+ }
+ tag("description", param.description, true);
+ tagWithSince("experimental", param.experimental);
+ tagWithSince("deprecated", param.deprecated);
+ closeTag("parameter");
+ if ( legacyContent ) {
+ writeParameterProperties(param, param.name);
+ }
+ });
+ }
+
+ tag("description", getConstructorDescription(symbol), true);
+ // tagWithSince("experimental", symbol.experimental); // TODO repeat from class?
+ // tagWithSince("deprecated", symbol.deprecated); // TODO repeat from class?
+ // secTags(symbol); // TODO repeat from class?
+ closeTag("constructor");
+ }
+
+ /* TODO MIGRATE or remove, if not needed
+ var ownSubspaces = ( symbol.__ui5.children || [] ).filter(function($) { return $.kind === 'namespace' }).sort(sortByAlias);
+ for (var i=0; i
undefined
once data has been written
+ */
+module.exports = async function({workspace, options}) {
+ let allResources;
+ if (workspace.byGlobSource) { // API only available on duplex collections
+ allResources = await workspace.byGlobSource(options.pattern);
+ } else {
+ allResources = await workspace.byGlob(options.pattern);
+ }
+ return runJSDoc({
+ resources: allResources,
+ options
+ }).then((createdResources) => {
+ console.log(createdResources);
+ return Promise.all(createdResources.map((resource) => {
+ return workspace.write(resource);
+ }));
+ });
+};
diff --git a/lib/tasks/taskRepository.js b/lib/tasks/taskRepository.js
index 2b1285c5b..3afffd6e0 100644
--- a/lib/tasks/taskRepository.js
+++ b/lib/tasks/taskRepository.js
@@ -2,6 +2,7 @@ const tasks = {
replaceCopyright: require("./replaceCopyright"),
replaceVersion: require("./replaceVersion"),
createDebugFiles: require("./createDebugFiles"),
+ createJSDoc: require("./createJSDoc"),
uglify: require("./uglify"),
buildThemes: require("./buildThemes"),
transformBootstrapHtml: require("./transformBootstrapHtml"),
diff --git a/lib/types/library/LibraryBuilder.js b/lib/types/library/LibraryBuilder.js
index 98fb709b4..f38f6117a 100644
--- a/lib/types/library/LibraryBuilder.js
+++ b/lib/types/library/LibraryBuilder.js
@@ -8,6 +8,7 @@ const tasks = { // can't require index.js due to circular dependency
generateStandaloneAppBundle: require("../../tasks/bundlers/generateStandaloneAppBundle"),
buildThemes: require("../../tasks/buildThemes"),
createDebugFiles: require("../../tasks/createDebugFiles"),
+ createJSDoc: require("../../tasks/createJSDoc"),
generateLibraryManifest: require("../../tasks/generateLibraryManifest"),
generateVersionInfo: require("../../tasks/generateVersionInfo"),
replaceCopyright: require("../../tasks/replaceCopyright"),
@@ -39,6 +40,20 @@ class LibraryBuilder extends AbstractBuilder {
});
});
+ this.addTask("createJSDoc", () => {
+ const createJSDoc = tasks.createJSDoc;
+ return createJSDoc({
+ workspace: resourceCollections.workspace,
+ options: {
+ libraryName: project.metadata.name,
+ version: project.version,
+ pattern: "/resources/**/*.js"
+ }
+ }).then(() => {
+ console.log("createJSDOC done");
+ });
+ });
+
const componentPreload = project.builder && project.builder.componentPreload;
if (componentPreload) {
const generateComponentPreload = tasks.generateComponentPreload;
@@ -75,6 +90,9 @@ class LibraryBuilder extends AbstractBuilder {
options: {
projectName: project.metadata.name
}
+ }).catch((err) => {
+ console.log("generateLibraryPreload failed:", err);
+ throw err;
});
});
diff --git a/package-lock.json b/package-lock.json
index 182864a19..1f05464e5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1605,15 +1605,6 @@
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
- "catharsis": {
- "version": "0.8.9",
- "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz",
- "integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=",
- "dev": true,
- "requires": {
- "underscore-contrib": "~0.3.0"
- }
- },
"chai": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
@@ -2083,7 +2074,6 @@
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
- "dev": true,
"requires": {
"lru-cache": "^4.0.1",
"shebang-command": "^1.2.0",
@@ -2914,6 +2904,17 @@
"chardet": "^0.7.0",
"iconv-lite": "^0.4.24",
"tmp": "^0.0.33"
+ },
+ "dependencies": {
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ }
}
},
"extglob": {
@@ -4517,8 +4518,7 @@
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
- "dev": true
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"isobject": {
"version": "3.0.1",
@@ -4581,58 +4581,12 @@
}
}
},
- "js2xmlparser": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz",
- "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=",
- "dev": true,
- "requires": {
- "xmlcreate": "^1.0.1"
- }
- },
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
"optional": true
},
- "jsdoc": {
- "version": "3.5.5",
- "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.5.tgz",
- "integrity": "sha512-6PxB65TAU4WO0Wzyr/4/YhlGovXl0EVYfpKbpSroSj0qBxT4/xod/l40Opkm38dRHRdQgdeY836M0uVnJQG7kg==",
- "dev": true,
- "requires": {
- "babylon": "7.0.0-beta.19",
- "bluebird": "~3.5.0",
- "catharsis": "~0.8.9",
- "escape-string-regexp": "~1.0.5",
- "js2xmlparser": "~3.0.0",
- "klaw": "~2.0.0",
- "marked": "~0.3.6",
- "mkdirp": "~0.5.1",
- "requizzle": "~0.2.1",
- "strip-json-comments": "~2.0.1",
- "taffydb": "2.6.2",
- "underscore": "~1.8.3"
- },
- "dependencies": {
- "babylon": {
- "version": "7.0.0-beta.19",
- "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz",
- "integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A==",
- "dev": true
- },
- "mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "dev": true,
- "requires": {
- "minimist": "0.0.8"
- }
- }
- }
- },
"jsdoctypeparser": {
"version": "2.0.0-alpha-8",
"resolved": "https://registry.npmjs.org/jsdoctypeparser/-/jsdoctypeparser-2.0.0-alpha-8.tgz",
@@ -4700,15 +4654,6 @@
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
},
- "klaw": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz",
- "integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.9"
- }
- },
"last-line-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/last-line-stream/-/last-line-stream-1.0.0.tgz",
@@ -4955,7 +4900,6 @@
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
"integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
- "dev": true,
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
@@ -4988,12 +4932,6 @@
"object-visit": "^1.0.0"
}
},
- "marked": {
- "version": "0.3.19",
- "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz",
- "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==",
- "dev": true
- },
"matcher": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz",
@@ -6690,8 +6628,7 @@
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
- "dev": true
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"p-finally": {
"version": "1.0.0",
@@ -6994,8 +6931,7 @@
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
- "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
- "dev": true
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"punycode": {
"version": "1.4.1",
@@ -7320,23 +7256,6 @@
"integrity": "sha1-WhtS63Dr7UPrmC6XTIWrWVceVvo=",
"dev": true
},
- "requizzle": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz",
- "integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=",
- "dev": true,
- "requires": {
- "underscore": "~1.6.0"
- },
- "dependencies": {
- "underscore": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
- "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
- "dev": true
- }
- }
- },
"resolve-cwd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
@@ -7494,7 +7413,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
- "dev": true,
"requires": {
"shebang-regex": "^1.0.0"
}
@@ -7502,8 +7420,7 @@
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
- "dev": true
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
},
"sift": {
"version": "5.1.0",
@@ -8004,12 +7921,6 @@
}
}
},
- "taffydb": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
- "integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg=",
- "dev": true
- },
"tap-nyan": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/tap-nyan/-/tap-nyan-1.1.0.tgz",
@@ -8147,12 +8058,11 @@
"dev": true
},
"tmp": {
- "version": "0.0.33",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
- "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
- "dev": true,
+ "version": "0.0.31",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
+ "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=",
"requires": {
- "os-tmpdir": "~1.0.2"
+ "os-tmpdir": "~1.0.1"
}
},
"to-fast-properties": {
@@ -8292,29 +8202,6 @@
"integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=",
"dev": true
},
- "underscore": {
- "version": "1.8.3",
- "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
- "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
- "dev": true
- },
- "underscore-contrib": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz",
- "integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=",
- "dev": true,
- "requires": {
- "underscore": "1.6.0"
- },
- "dependencies": {
- "underscore": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
- "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=",
- "dev": true
- }
- }
- },
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
@@ -8514,7 +8401,6 @@
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
"requires": {
"isexe": "^2.0.0"
}
@@ -8668,12 +8554,6 @@
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
},
- "xmlcreate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz",
- "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=",
- "dev": true
- },
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
@@ -8683,8 +8563,7 @@
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
- "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
- "dev": true
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
},
"yargs-parser": {
"version": "10.1.0",
diff --git a/package.json b/package.json
index b631b5a89..4af010f9c 100644
--- a/package.json
+++ b/package.json
@@ -95,6 +95,7 @@
"@ui5/fs": "^1.0.1",
"@ui5/logger": "^1.0.0",
"cheerio": "^0.22.0",
+ "cross-spawn": "^5.1.0",
"escodegen": "^1.11.0",
"escope": "^3.6.0",
"esprima": "^4.0.1",
@@ -106,6 +107,7 @@
"pretty-hrtime": "^1.0.3",
"replacestream": "^4.0.3",
"semver": "^5.6.0",
+ "tmp": "0.0.31",
"uglify-es": "^3.2.2",
"xml2js": "^0.4.17",
"yazl": "^2.5.1"
@@ -121,7 +123,6 @@
"eslint-config-google": "^0.11.0",
"eslint-plugin-jsdoc": "^4.0.1",
"extract-zip": "^1.6.7",
- "jsdoc": "^3.5.5",
"mock-require": "^3.0.3",
"nyc": "^13.2.0",
"opn-cli": "^4.0.0",