| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Copyright 2017 Google Inc. All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  | // @ts-check
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 11:11:40 -08:00
										 |  |  | const md = require('../markdown'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 17:38:00 -08:00
										 |  |  | /** @typedef {import('../markdown').MarkdownNode} MarkdownNode */ | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {{ | 
					
						
							|  |  |  |   *   name: string, | 
					
						
							|  |  |  |   *   args: ParsedType | null, | 
					
						
							|  |  |  |   *   retType: ParsedType | null, | 
					
						
							|  |  |  |   *   template: ParsedType | null, | 
					
						
							|  |  |  |   *   union: ParsedType | null, | 
					
						
							| 
									
										
										
										
											2021-02-05 15:28:48 -08:00
										 |  |  |   *   unionName?: string, | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   *   next: ParsedType | null, | 
					
						
							|  |  |  |   * }} ParsedType | 
					
						
							|  |  |  |   */ | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {{ | 
					
						
							|  |  |  |  *   only?: string[], | 
					
						
							| 
									
										
										
										
											2021-01-15 16:01:41 -08:00
										 |  |  |  *   aliases?: Object<string, string>, | 
					
						
							| 
									
										
										
										
											2021-01-28 17:51:41 -08:00
										 |  |  |  *   types?: Object<string, Documentation.Type>, | 
					
						
							|  |  |  |  *   overrides?: Object<string, Documentation.Member>, | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |  * }} Langs | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {function({ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |  *   clazz?: Documentation.Class, | 
					
						
							|  |  |  |  *   member?: Documentation.Member, | 
					
						
							|  |  |  |  *   param?: string, | 
					
						
							|  |  |  |  *   option?: string | 
					
						
							|  |  |  |  * }): string} Renderer | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {{ | 
					
						
							|  |  |  |  *   langs: Langs, | 
					
						
							|  |  |  |  *   since: string, | 
					
						
							|  |  |  |  *   experimental: boolean | 
					
						
							|  |  |  |  * }} Metainfo | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-02-10 07:13:14 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | class Documentation { | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * @param {!Array<!Documentation.Class>} classesArray | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   constructor(classesArray) { | 
					
						
							|  |  |  |     this.classesArray = classesArray; | 
					
						
							|  |  |  |     /** @type {!Map<string, !Documentation.Class>} */ | 
					
						
							|  |  |  |     this.classes = new Map(); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     this.index(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-22 11:01:18 -07:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {!Documentation} documentation | 
					
						
							|  |  |  |    * @return {!Documentation} | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   mergeWith(documentation) { | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     return new Documentation([...this.classesArray, ...documentation.classesArray].map(cls => cls.clone())); | 
					
						
							| 
									
										
										
										
											2021-07-22 11:01:18 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {string[]} errors | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   copyDocsFromSuperclasses(errors) { | 
					
						
							|  |  |  |     for (const [name, clazz] of this.classes.entries()) { | 
					
						
							|  |  |  |       clazz.validateOrder(errors, clazz); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-28 10:41:46 +02:00
										 |  |  |       if (!clazz.extends || ['EventEmitter', 'Error', 'Exception', 'RuntimeException'].includes(clazz.extends)) | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |         continue; | 
					
						
							|  |  |  |       const superClass = this.classes.get(clazz.extends); | 
					
						
							|  |  |  |       if (!superClass) { | 
					
						
							|  |  |  |         errors.push(`Undefined superclass: ${superClass} in ${name}`); | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       for (const memberName of clazz.members.keys()) { | 
					
						
							|  |  |  |         if (superClass.members.has(memberName)) | 
					
						
							|  |  |  |           errors.push(`Member documentation overrides base: ${name}.${memberName} over ${clazz.extends}.${memberName}`); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       clazz.membersArray = [...clazz.membersArray, ...superClass.membersArray.map(c => c.clone())]; | 
					
						
							|  |  |  |       clazz.index(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} lang | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   filterForLanguage(lang) { | 
					
						
							|  |  |  |     const classesArray = []; | 
					
						
							|  |  |  |     for (const clazz of this.classesArray) { | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |       if (clazz.langs.only && !clazz.langs.only.includes(lang)) | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |         continue; | 
					
						
							|  |  |  |       clazz.filterForLanguage(lang); | 
					
						
							|  |  |  |       classesArray.push(clazz); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.classesArray = classesArray; | 
					
						
							|  |  |  |     this.index(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |   filterOutExperimental() { | 
					
						
							|  |  |  |     const classesArray = []; | 
					
						
							|  |  |  |     for (const clazz of this.classesArray) { | 
					
						
							|  |  |  |       if (clazz.experimental) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       clazz.filterOutExperimental(); | 
					
						
							|  |  |  |       classesArray.push(clazz); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.classesArray = classesArray; | 
					
						
							|  |  |  |     this.index(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   index() { | 
					
						
							|  |  |  |     for (const cls of this.classesArray) { | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |       this.classes.set(cls.name, cls); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |       cls.index(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * @param {Renderer} linkRenderer | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   setLinkRenderer(linkRenderer) { | 
					
						
							|  |  |  |     // @type {Map<string, Documentation.Class>}
 | 
					
						
							|  |  |  |     const classesMap = new Map(); | 
					
						
							|  |  |  |     const membersMap = new Map(); | 
					
						
							|  |  |  |     for (const clazz of this.classesArray) { | 
					
						
							|  |  |  |       classesMap.set(clazz.name, clazz); | 
					
						
							|  |  |  |       for (const member of clazz.membersArray) | 
					
						
							|  |  |  |         membersMap.set(`${member.kind}: ${clazz.name}.${member.name}`, member); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param {Documentation.Class|Documentation.Member|null} classOrMember | 
					
						
							|  |  |  |      * @param {MarkdownNode[]} nodes | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     this._patchLinks = (classOrMember, nodes) => patchLinks(classOrMember, nodes, classesMap, membersMap, linkRenderer); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (const clazz of this.classesArray) | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |       clazz.visit(item => this._patchLinks(item, item.spec)); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * @param {MarkdownNode[]} nodes | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   renderLinksInText(nodes) { | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |     this._patchLinks(null, nodes); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   generateSourceCodeComments() { | 
					
						
							|  |  |  |     for (const clazz of this.classesArray) | 
					
						
							|  |  |  |       clazz.visit(item => item.comment = generateSourceCodeComment(item.spec)); | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |   clone() { | 
					
						
							|  |  |  |     return new Documentation(this.classesArray.map(cls => cls.clone())); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Documentation.Class = class { | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |    * @param {Metainfo} metainfo | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @param {string} name | 
					
						
							|  |  |  |    * @param {!Array<!Documentation.Member>} membersArray | 
					
						
							|  |  |  |    * @param {?string=} extendsName | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |    * @param {MarkdownNode[]=} spec | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |   constructor(metainfo, name, membersArray, extendsName = null, spec = undefined) { | 
					
						
							|  |  |  |     this.langs = metainfo.langs; | 
					
						
							|  |  |  |     this.experimental = metainfo.experimental; | 
					
						
							|  |  |  |     this.since = metainfo.since; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.name = name; | 
					
						
							|  |  |  |     this.membersArray = membersArray; | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |     this.spec = spec; | 
					
						
							| 
									
										
										
										
											2019-12-20 13:07:14 -08:00
										 |  |  |     this.extends = extendsName; | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     this.comment = ''; | 
					
						
							| 
									
										
										
										
											2019-12-20 13:07:14 -08:00
										 |  |  |     this.index(); | 
					
						
							| 
									
										
										
										
											2021-10-19 09:37:17 -07:00
										 |  |  |     const match = name.match(/(API|JS|CDP|[A-Z])(.*)/); | 
					
						
							| 
									
										
										
										
											2020-12-28 23:42:51 -08:00
										 |  |  |     this.varName = match[1].toLowerCase() + match[2]; | 
					
						
							| 
									
										
										
										
											2019-12-20 13:07:14 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   index() { | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     /** @type {!Map<string, !Documentation.Member>} */ | 
					
						
							|  |  |  |     this.members = new Map(); | 
					
						
							|  |  |  |     /** @type {!Map<string, !Documentation.Member>} */ | 
					
						
							|  |  |  |     this.properties = new Map(); | 
					
						
							|  |  |  |     /** @type {!Array<!Documentation.Member>} */ | 
					
						
							|  |  |  |     this.propertiesArray = []; | 
					
						
							|  |  |  |     /** @type {!Map<string, !Documentation.Member>} */ | 
					
						
							|  |  |  |     this.methods = new Map(); | 
					
						
							|  |  |  |     /** @type {!Array<!Documentation.Member>} */ | 
					
						
							|  |  |  |     this.methodsArray = []; | 
					
						
							|  |  |  |     /** @type {!Map<string, !Documentation.Member>} */ | 
					
						
							|  |  |  |     this.events = new Map(); | 
					
						
							|  |  |  |     /** @type {!Array<!Documentation.Member>} */ | 
					
						
							|  |  |  |     this.eventsArray = []; | 
					
						
							| 
									
										
										
										
											2019-12-20 13:07:14 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (const member of this.membersArray) { | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |       this.members.set(member.name, member); | 
					
						
							|  |  |  |       if (member.kind === 'method') { | 
					
						
							|  |  |  |         this.methods.set(member.name, member); | 
					
						
							|  |  |  |         this.methodsArray.push(member); | 
					
						
							|  |  |  |       } else if (member.kind === 'property') { | 
					
						
							|  |  |  |         this.properties.set(member.name, member); | 
					
						
							|  |  |  |         this.propertiesArray.push(member); | 
					
						
							|  |  |  |       } else if (member.kind === 'event') { | 
					
						
							|  |  |  |         this.events.set(member.name, member); | 
					
						
							|  |  |  |         this.eventsArray.push(member); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-12-28 23:42:51 -08:00
										 |  |  |       member.clazz = this; | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |       member.index(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |   clone() { | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |     const cls = new Documentation.Class({ langs: this.langs, experimental: this.experimental, since: this.since }, this.name, this.membersArray.map(m => m.clone()), this.extends, this.spec); | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     cls.comment = this.comment; | 
					
						
							|  |  |  |     return cls; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} lang | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   filterForLanguage(lang) { | 
					
						
							|  |  |  |     const membersArray = []; | 
					
						
							|  |  |  |     for (const member of this.membersArray) { | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |       if (member.langs.only && !member.langs.only.includes(lang)) | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |         continue; | 
					
						
							|  |  |  |       member.filterForLanguage(lang); | 
					
						
							|  |  |  |       membersArray.push(member); | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     this.membersArray = membersArray; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-12-20 16:57:21 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |   filterOutExperimental()  { | 
					
						
							|  |  |  |     const membersArray = []; | 
					
						
							|  |  |  |     for (const member of this.membersArray) { | 
					
						
							|  |  |  |       if (member.experimental) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       member.filterOutExperimental(); | 
					
						
							|  |  |  |       membersArray.push(member); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.membersArray = membersArray; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-24 18:24:02 -08:00
										 |  |  |   validateOrder(errors, cls) { | 
					
						
							| 
									
										
										
										
											2019-12-20 16:57:21 -08:00
										 |  |  |     const members = this.membersArray; | 
					
						
							|  |  |  |     // Events should go first.
 | 
					
						
							|  |  |  |     let eventIndex = 0; | 
					
						
							|  |  |  |     for (; eventIndex < members.length && members[eventIndex].kind === 'event'; ++eventIndex); | 
					
						
							|  |  |  |     for (; eventIndex < members.length && members[eventIndex].kind !== 'event'; ++eventIndex); | 
					
						
							|  |  |  |     if (eventIndex < members.length) | 
					
						
							|  |  |  |       errors.push(`Events should go first. Event '${members[eventIndex].name}' in class ${cls.name} breaks order`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Constructor should be right after events and before all other members.
 | 
					
						
							|  |  |  |     const constructorIndex = members.findIndex(member => member.kind === 'method' && member.name === 'constructor'); | 
					
						
							|  |  |  |     if (constructorIndex > 0 && members[constructorIndex - 1].kind !== 'event') | 
					
						
							|  |  |  |       errors.push(`Constructor of ${cls.name} should go before other methods`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Events should be sorted alphabetically.
 | 
					
						
							|  |  |  |     for (let i = 0; i < members.length - 1; ++i) { | 
					
						
							|  |  |  |       const member1 = this.membersArray[i]; | 
					
						
							|  |  |  |       const member2 = this.membersArray[i + 1]; | 
					
						
							|  |  |  |       if (member1.kind !== 'event' || member2.kind !== 'event') | 
					
						
							|  |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2021-02-04 19:19:38 +01:00
										 |  |  |       if (member1.name.localeCompare(member2.name, 'en', { sensitivity: 'base' }) > 0) | 
					
						
							| 
									
										
										
										
											2019-12-20 16:57:21 -08:00
										 |  |  |         errors.push(`Event '${member1.name}' in class ${this.name} breaks alphabetic ordering of events`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // All other members should be sorted alphabetically.
 | 
					
						
							|  |  |  |     for (let i = 0; i < members.length - 1; ++i) { | 
					
						
							|  |  |  |       const member1 = this.membersArray[i]; | 
					
						
							|  |  |  |       const member2 = this.membersArray[i + 1]; | 
					
						
							|  |  |  |       if (member1.kind === 'event' || member2.kind === 'event') | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       if (member1.kind === 'method' && member1.name === 'constructor') | 
					
						
							|  |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2021-02-04 19:19:38 +01:00
										 |  |  |       if (member1.name.replace(/^\$+/, '$').localeCompare(member2.name.replace(/^\$+/, '$'), 'en', { sensitivity: 'base' }) > 0) { | 
					
						
							| 
									
										
										
										
											2019-12-20 16:57:21 -08:00
										 |  |  |         let memberName1 = `${this.name}.${member1.name}`; | 
					
						
							|  |  |  |         if (member1.kind === 'method') | 
					
						
							|  |  |  |           memberName1 += '()'; | 
					
						
							|  |  |  |         let memberName2 = `${this.name}.${member2.name}`; | 
					
						
							|  |  |  |         if (member2.kind === 'method') | 
					
						
							|  |  |  |           memberName2 += '()'; | 
					
						
							|  |  |  |         errors.push(`Bad alphabetic ordering of ${this.name} members: ${memberName1} should go after ${memberName2}`); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-10 07:13:14 -08:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2020-12-28 17:38:00 -08:00
										 |  |  |    * @param {function(Documentation.Member|Documentation.Class): void} visitor | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |   visit(visitor) { | 
					
						
							|  |  |  |     visitor(this); | 
					
						
							|  |  |  |     for (const p of this.propertiesArray) | 
					
						
							|  |  |  |       p.visit(visitor); | 
					
						
							|  |  |  |     for (const m of this.methodsArray) | 
					
						
							|  |  |  |       m.visit(visitor); | 
					
						
							|  |  |  |     for (const e of this.eventsArray) | 
					
						
							|  |  |  |       e.visit(visitor); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Documentation.Member = class { | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} kind | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |    * @param {Metainfo} metainfo | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @param {string} name | 
					
						
							|  |  |  |    * @param {?Documentation.Type} type | 
					
						
							|  |  |  |    * @param {!Array<!Documentation.Member>} argsArray | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |    * @param {MarkdownNode[]=} spec | 
					
						
							| 
									
										
										
										
											2020-03-20 01:30:35 -07:00
										 |  |  |    * @param {boolean=} required | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |   constructor(kind, metainfo, name, type, argsArray, spec = undefined, required = true) { | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.kind = kind; | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |     this.langs = metainfo.langs; | 
					
						
							|  |  |  |     this.experimental = metainfo.experimental; | 
					
						
							|  |  |  |     this.since = metainfo.since; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.name = name; | 
					
						
							|  |  |  |     this.type = type; | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |     this.spec = spec; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.argsArray = argsArray; | 
					
						
							|  |  |  |     this.required = required; | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |     this.comment =  ''; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     /** @type {!Map<string, !Documentation.Member>} */ | 
					
						
							|  |  |  |     this.args = new Map(); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     this.index(); | 
					
						
							| 
									
										
										
										
											2020-12-28 23:42:51 -08:00
										 |  |  |     /** @type {!Documentation.Class} */ | 
					
						
							|  |  |  |     this.clazz = null; | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |     /** @type {Documentation.Member=} */ | 
					
						
							|  |  |  |     this.enclosingMethod = undefined; | 
					
						
							| 
									
										
										
										
											2021-01-07 11:11:40 -08:00
										 |  |  |     this.deprecated = false; | 
					
						
							|  |  |  |     if (spec) { | 
					
						
							|  |  |  |       md.visitAll(spec, node => { | 
					
						
							|  |  |  |         if (node.text && node.text.includes('**DEPRECATED**')) | 
					
						
							|  |  |  |           this.deprecated = true; | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2021-01-07 23:37:53 -08:00
										 |  |  |     }; | 
					
						
							|  |  |  |     this.async = false; | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |     this.alias = name; | 
					
						
							| 
									
										
										
										
											2021-08-27 21:57:40 -07:00
										 |  |  |     this.overloadIndex = 0; | 
					
						
							|  |  |  |     if (name.includes('#')) { | 
					
						
							|  |  |  |       const match = name.match(/(.*)#(.*)/); | 
					
						
							|  |  |  |       this.alias = match[1]; | 
					
						
							|  |  |  |       this.overloadIndex = (+match[2]) - 1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-07-22 11:01:18 -07:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-06-16 23:19:24 -07:00
										 |  |  |      * Param is true and option false | 
					
						
							|  |  |  |      * @type {Boolean} | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     this.paramOrOption = null; | 
					
						
							| 
									
										
										
										
											2020-12-28 23:42:51 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   index() { | 
					
						
							|  |  |  |     this.args = new Map(); | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |     if (this.kind === 'method') | 
					
						
							|  |  |  |       this.enclosingMethod = this; | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     for (const arg of this.argsArray) { | 
					
						
							|  |  |  |       this.args.set(arg.name, arg); | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |       arg.enclosingMethod = this; | 
					
						
							|  |  |  |       if (arg.name === 'options') { | 
					
						
							| 
									
										
										
										
											2021-06-16 23:19:24 -07:00
										 |  |  |         arg.type.properties.sort((p1, p2) => p1.name.localeCompare(p2.name)); | 
					
						
							|  |  |  |         arg.type.properties.forEach(p => p.enclosingMethod = this); | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |    * @param {string} lang | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   filterForLanguage(lang) { | 
					
						
							| 
									
										
										
										
											2021-01-15 16:01:41 -08:00
										 |  |  |     if (this.langs.aliases && this.langs.aliases[lang]) | 
					
						
							|  |  |  |       this.alias = this.langs.aliases[lang]; | 
					
						
							|  |  |  |     if (this.langs.types && this.langs.types[lang]) | 
					
						
							|  |  |  |       this.type = this.langs.types[lang]; | 
					
						
							|  |  |  |     this.type.filterForLanguage(lang); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     const argsArray = []; | 
					
						
							|  |  |  |     for (const arg of this.argsArray) { | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |       if (arg.langs.only && !arg.langs.only.includes(lang)) | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2021-01-28 17:51:41 -08:00
										 |  |  |       const overriddenArg = (arg.langs.overrides && arg.langs.overrides[lang]) || arg; | 
					
						
							|  |  |  |       overriddenArg.filterForLanguage(lang); | 
					
						
							|  |  |  |       if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length) | 
					
						
							| 
									
										
										
										
											2021-01-10 18:18:35 -08:00
										 |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |       overriddenArg.type.filterForLanguage(lang); | 
					
						
							| 
									
										
										
										
											2021-01-28 17:51:41 -08:00
										 |  |  |       argsArray.push(overriddenArg); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |     this.argsArray = argsArray; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |   filterOutExperimental() { | 
					
						
							|  |  |  |     this.type.filterOutExperimental(); | 
					
						
							|  |  |  |     const argsArray = []; | 
					
						
							|  |  |  |     for (const arg of this.argsArray) { | 
					
						
							|  |  |  |       if (arg.experimental) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       arg.type.filterOutExperimental(); | 
					
						
							|  |  |  |       argsArray.push(arg); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.argsArray = argsArray; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 23:42:51 -08:00
										 |  |  |   clone() { | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |     const result = new Documentation.Member(this.kind, { langs: this.langs, experimental: this.experimental, since: this.since }, this.name, this.type.clone(), this.argsArray.map(arg => arg.clone()), this.spec, this.required); | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     result.alias = this.alias; | 
					
						
							| 
									
										
										
										
											2021-01-07 23:37:53 -08:00
										 |  |  |     result.async = this.async; | 
					
						
							| 
									
										
										
										
											2021-06-16 23:19:24 -07:00
										 |  |  |     result.paramOrOption = this.paramOrOption; | 
					
						
							| 
									
										
										
										
											2021-01-07 23:37:53 -08:00
										 |  |  |     return result; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |    * @param {Metainfo} metainfo | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @param {string} name | 
					
						
							|  |  |  |    * @param {!Array<!Documentation.Member>} argsArray | 
					
						
							|  |  |  |    * @param {?Documentation.Type} returnType | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |    * @param {MarkdownNode[]=} spec | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @return {!Documentation.Member} | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |   static createMethod(metainfo, name, argsArray, returnType, spec) { | 
					
						
							|  |  |  |     return new Documentation.Member('method', metainfo, name, returnType, argsArray, spec); | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |    * @param {Metainfo} metainfo | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |    * @param {!string} name | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @param {!Documentation.Type} type | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |    * @param {!MarkdownNode[]=} spec | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @param {boolean=} required | 
					
						
							|  |  |  |    * @return {!Documentation.Member} | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |   static createProperty(metainfo, name, type, spec, required) { | 
					
						
							|  |  |  |     return new Documentation.Member('property', metainfo, name, type, [], spec, required); | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |    * @param {Metainfo} metainfo | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @param {string} name | 
					
						
							|  |  |  |    * @param {?Documentation.Type=} type | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |    * @param {MarkdownNode[]=} spec | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @return {!Documentation.Member} | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |   static createEvent(metainfo, name, type = null, spec) { | 
					
						
							|  |  |  |     return new Documentation.Member('event', metainfo, name, type, [], spec); | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-10 07:13:14 -08:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2020-12-28 17:38:00 -08:00
										 |  |  |    * @param {function(Documentation.Member|Documentation.Class): void} visitor | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |   visit(visitor) { | 
					
						
							|  |  |  |     visitor(this); | 
					
						
							|  |  |  |     if (this.type) | 
					
						
							|  |  |  |       this.type.visit(visitor); | 
					
						
							|  |  |  |     for (const arg of this.argsArray) | 
					
						
							|  |  |  |       arg.visit(visitor); | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Documentation.Type = class { | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} expression | 
					
						
							|  |  |  |    * @param {!Array<!Documentation.Member>=} properties | 
					
						
							|  |  |  |    * @return {Documentation.Type} | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   static parse(expression, properties = []) { | 
					
						
							|  |  |  |     expression = expression.replace(/\\\(/g, '(').replace(/\\\)/g, ')'); | 
					
						
							|  |  |  |     const type = Documentation.Type.fromParsedType(parseTypeExpression(expression)); | 
					
						
							| 
									
										
										
										
											2021-01-05 09:42:49 -08:00
										 |  |  |     type.expression = expression; | 
					
						
							|  |  |  |     if (type.name === 'number') | 
					
						
							|  |  |  |       throw new Error('Number types should be either int or float, not number in: ' + expression); | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     if (!properties.length) | 
					
						
							|  |  |  |       return type; | 
					
						
							|  |  |  |     const types = []; | 
					
						
							|  |  |  |     type._collectAllTypes(types); | 
					
						
							|  |  |  |     let success = false; | 
					
						
							|  |  |  |     for (const t of types) { | 
					
						
							|  |  |  |       if (t.name === 'Object') { | 
					
						
							|  |  |  |         t.properties = properties; | 
					
						
							|  |  |  |         success = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!success) | 
					
						
							|  |  |  |       throw new Error('Nested properties given, but there are no objects in type expression: ' + expression); | 
					
						
							|  |  |  |     return type; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * @param {ParsedType} parsedType | 
					
						
							|  |  |  |    * @return {Documentation.Type} | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   static fromParsedType(parsedType, inUnion = false) { | 
					
						
							| 
									
										
										
										
											2022-03-08 16:02:31 -08:00
										 |  |  |     if (!inUnion && !parsedType.unionName && isStringUnion(parsedType) ) { | 
					
						
							|  |  |  |       throw new Error('Enum must have a name:\n' + JSON.stringify(parsedType, null, 2)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!inUnion && (parsedType.union || parsedType.unionName)) { | 
					
						
							| 
									
										
										
										
											2021-02-05 16:32:13 -08:00
										 |  |  |       const type = new Documentation.Type(parsedType.unionName || ''); | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       type.union = []; | 
					
						
							| 
									
										
										
										
											2021-02-05 16:32:13 -08:00
										 |  |  |       for (let t = parsedType; t; t = t.union) { | 
					
						
							|  |  |  |         const nestedUnion = !!t.unionName && t !== parsedType; | 
					
						
							|  |  |  |         type.union.push(Documentation.Type.fromParsedType(t, !nestedUnion)); | 
					
						
							|  |  |  |         if (nestedUnion) | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       return type; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (parsedType.args) { | 
					
						
							|  |  |  |       const type = new Documentation.Type('function'); | 
					
						
							|  |  |  |       type.args = []; | 
					
						
							|  |  |  |       for (let t = parsedType.args; t; t = t.next) | 
					
						
							|  |  |  |         type.args.push(Documentation.Type.fromParsedType(t)); | 
					
						
							|  |  |  |       type.returnType = parsedType.retType ? Documentation.Type.fromParsedType(parsedType.retType) : null; | 
					
						
							|  |  |  |       return type; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (parsedType.template) { | 
					
						
							|  |  |  |       const type = new Documentation.Type(parsedType.name); | 
					
						
							|  |  |  |       type.templates = []; | 
					
						
							|  |  |  |       for (let t = parsedType.template; t; t = t.next) | 
					
						
							|  |  |  |         type.templates.push(Documentation.Type.fromParsedType(t)); | 
					
						
							|  |  |  |       return type; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return new Documentation.Type(parsedType.name); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} name | 
					
						
							|  |  |  |    * @param {!Array<!Documentation.Member>=} properties | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   constructor(name, properties) { | 
					
						
							|  |  |  |     this.name = name.replace(/^\[/, '').replace(/\]$/, ''); | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     /** @type {Documentation.Member[] | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.properties = this.name === 'Object' ? properties : undefined; | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     /** @type {Documentation.Type[] | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.union; | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     /** @type {Documentation.Type[] | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.args; | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     /** @type {Documentation.Type | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.returnType; | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     /** @type {Documentation.Type[] | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.templates; | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     /** @type {string | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-05 09:42:49 -08:00
										 |  |  |     this.expression; | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   visit(visitor) { | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     const types = []; | 
					
						
							|  |  |  |     this._collectAllTypes(types); | 
					
						
							|  |  |  |     for (const type of types) { | 
					
						
							|  |  |  |       for (const p of type.properties || []) | 
					
						
							|  |  |  |         p.visit(visitor); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |   clone() { | 
					
						
							|  |  |  |     const type = new Documentation.Type(this.name, this.properties ? this.properties.map(prop => prop.clone()) : undefined); | 
					
						
							|  |  |  |     if (this.union) | 
					
						
							|  |  |  |       type.union = this.union.map(type => type.clone()); | 
					
						
							|  |  |  |     if (this.args) | 
					
						
							|  |  |  |       type.args = this.args.map(type => type.clone()); | 
					
						
							|  |  |  |     if (this.returnType) | 
					
						
							|  |  |  |       type.returnType = this.returnType.clone(); | 
					
						
							|  |  |  |     if (this.templates) | 
					
						
							|  |  |  |       type.templates = this.templates.map(type => type.clone()); | 
					
						
							|  |  |  |     type.expression = this.expression; | 
					
						
							|  |  |  |     return type; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @returns {Documentation.Member[]} | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   deepProperties() { | 
					
						
							|  |  |  |     const types = []; | 
					
						
							|  |  |  |     this._collectAllTypes(types); | 
					
						
							|  |  |  |     for (const type of types) { | 
					
						
							|  |  |  |       if (type.properties && type.properties.length) | 
					
						
							|  |  |  |         return type.properties; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return []; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-08 09:21:10 -03:00
										 |  |  |   /** | 
					
						
							|  |  |  |     * @returns {Documentation.Member[]} | 
					
						
							|  |  |  |   */ | 
					
						
							|  |  |  |   sortedProperties() { | 
					
						
							|  |  |  |     if (!this.properties) | 
					
						
							|  |  |  |       return this.properties; | 
					
						
							|  |  |  |     const sortedProperties = [...this.properties]; | 
					
						
							|  |  |  |     sortedProperties.sort((p1, p2) => p1.name.localeCompare(p2.name)); | 
					
						
							|  |  |  |     return sortedProperties; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-10 18:18:35 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} lang | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   filterForLanguage(lang) { | 
					
						
							|  |  |  |     if (!this.properties) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     const properties = []; | 
					
						
							|  |  |  |     for (const prop of this.properties) { | 
					
						
							|  |  |  |       if (prop.langs.only && !prop.langs.only.includes(lang)) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       prop.filterForLanguage(lang); | 
					
						
							|  |  |  |       properties.push(prop); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.properties = properties; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |   filterOutExperimental() { | 
					
						
							|  |  |  |     if (!this.properties) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     const properties = []; | 
					
						
							|  |  |  |     for (const prop of this.properties) { | 
					
						
							|  |  |  |       if (prop.experimental) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       prop.filterOutExperimental(); | 
					
						
							|  |  |  |       properties.push(prop); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.properties = properties; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {Documentation.Type[]} result | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   _collectAllTypes(result) { | 
					
						
							|  |  |  |     result.push(this); | 
					
						
							|  |  |  |     for (const t of this.union || []) | 
					
						
							|  |  |  |       t._collectAllTypes(result); | 
					
						
							|  |  |  |     for (const t of this.args || []) | 
					
						
							|  |  |  |       t._collectAllTypes(result); | 
					
						
							|  |  |  |     for (const t of this.templates || []) | 
					
						
							|  |  |  |       t._collectAllTypes(result); | 
					
						
							|  |  |  |     if (this.returnType) | 
					
						
							|  |  |  |       this.returnType._collectAllTypes(result); | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-05 15:28:48 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {ParsedType} type | 
					
						
							|  |  |  |  * @returns {boolean} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function isStringUnion(type) { | 
					
						
							|  |  |  |   while (type) { | 
					
						
							|  |  |  |     if (!type.name.startsWith('"') || !type.name.endsWith('"')) | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |     type = type.union; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {string} type | 
					
						
							|  |  |  |  * @returns {ParsedType} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function parseTypeExpression(type) { | 
					
						
							|  |  |  |   type = type.trim(); | 
					
						
							|  |  |  |   let name = type; | 
					
						
							|  |  |  |   let next = null; | 
					
						
							|  |  |  |   let template = null; | 
					
						
							|  |  |  |   let args = null; | 
					
						
							|  |  |  |   let retType = null; | 
					
						
							|  |  |  |   let firstTypeLength = type.length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   for (let i = 0; i < type.length; i++) { | 
					
						
							|  |  |  |     if (type[i] === '<') { | 
					
						
							|  |  |  |       name = type.substring(0, i); | 
					
						
							|  |  |  |       const matching = matchingBracket(type.substring(i), '<', '>'); | 
					
						
							|  |  |  |       template = parseTypeExpression(type.substring(i + 1, i + matching - 1)); | 
					
						
							|  |  |  |       firstTypeLength = i + matching; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (type[i] === '(') { | 
					
						
							|  |  |  |       name = type.substring(0, i); | 
					
						
							|  |  |  |       const matching = matchingBracket(type.substring(i), '(', ')'); | 
					
						
							|  |  |  |       args = parseTypeExpression(type.substring(i + 1, i + matching - 1)); | 
					
						
							|  |  |  |       i = i + matching; | 
					
						
							|  |  |  |       if (type[i] === ':') { | 
					
						
							|  |  |  |         retType = parseTypeExpression(type.substring(i + 1)); | 
					
						
							|  |  |  |         next = retType.next; | 
					
						
							|  |  |  |         retType.next = null; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (type[i] === '|' || type[i] === ',') { | 
					
						
							|  |  |  |       name = type.substring(0, i); | 
					
						
							|  |  |  |       firstTypeLength = i; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   let union = null; | 
					
						
							|  |  |  |   if (type[firstTypeLength] === '|') | 
					
						
							|  |  |  |     union = parseTypeExpression(type.substring(firstTypeLength + 1)); | 
					
						
							|  |  |  |   else if (type[firstTypeLength] === ',') | 
					
						
							|  |  |  |     next = parseTypeExpression(type.substring(firstTypeLength + 1)); | 
					
						
							| 
									
										
										
										
											2021-02-05 15:28:48 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (template && !template.unionName && isStringUnion(template)) { | 
					
						
							|  |  |  |     template.unionName = name; | 
					
						
							|  |  |  |     return template; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   return { | 
					
						
							|  |  |  |     name, | 
					
						
							|  |  |  |     args, | 
					
						
							|  |  |  |     retType, | 
					
						
							|  |  |  |     template, | 
					
						
							|  |  |  |     union, | 
					
						
							|  |  |  |     next | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} str | 
					
						
							|  |  |  |  * @param {any} open | 
					
						
							|  |  |  |  * @param {any} close | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function matchingBracket(str, open, close) { | 
					
						
							|  |  |  |   let count = 1; | 
					
						
							|  |  |  |   let i = 1; | 
					
						
							|  |  |  |   for (; i < str.length && count; i++) { | 
					
						
							|  |  |  |     if (str[i] === open) | 
					
						
							|  |  |  |       count++; | 
					
						
							|  |  |  |     else if (str[i] === close) | 
					
						
							|  |  |  |       count--; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return i; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |  * @param {Documentation.Class|Documentation.Member|null} classOrMember | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |  * @param {MarkdownNode[]} spec | 
					
						
							|  |  |  |  * @param {Map<string, Documentation.Class>} classesMap | 
					
						
							|  |  |  |  * @param {Map<string, Documentation.Member>} membersMap | 
					
						
							|  |  |  |  * @param {Renderer} linkRenderer | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  | function patchLinks(classOrMember, spec, classesMap, membersMap, linkRenderer) { | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   if (!spec) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   md.visitAll(spec, node => { | 
					
						
							|  |  |  |     if (!node.text) | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2021-02-10 07:13:14 -08:00
										 |  |  |     node.text = node.text.replace(/\[`(\w+): ([^\]]+)`\]/g, (match, p1, p2) => { | 
					
						
							|  |  |  |       if (['event', 'method', 'property'].includes(p1)) { | 
					
						
							|  |  |  |         const memberName = p1 + ': ' + p2; | 
					
						
							|  |  |  |         const member = membersMap.get(memberName); | 
					
						
							|  |  |  |         if (!member) | 
					
						
							|  |  |  |           throw new Error('Undefined member references: ' + match); | 
					
						
							|  |  |  |         return linkRenderer({ member }) || match; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |       if (p1 === 'param') { | 
					
						
							|  |  |  |         let alias = p2; | 
					
						
							|  |  |  |         if (classOrMember) { | 
					
						
							|  |  |  |           // param/option reference can only be in method or same method parameter comments.
 | 
					
						
							|  |  |  |           // @ts-ignore
 | 
					
						
							|  |  |  |           const method = classOrMember.enclosingMethod; | 
					
						
							|  |  |  |           const param = method.argsArray.find(a => a.name === p2); | 
					
						
							|  |  |  |           if (!param) | 
					
						
							|  |  |  |             throw new Error(`Referenced parameter ${match} not found in the parent method ${method.name} `); | 
					
						
							|  |  |  |           alias = param.alias; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return linkRenderer({ param: alias }) || match; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |       if (p1 === 'option') | 
					
						
							|  |  |  |         return linkRenderer({ option: p2 }) || match; | 
					
						
							| 
									
										
										
										
											2021-02-10 07:13:14 -08:00
										 |  |  |       throw new Error(`Undefined link prefix, expected event|method|property|param|option, got: ` + match); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2021-01-28 01:21:27 +01:00
										 |  |  |     node.text = node.text.replace(/\[([\w]+)\]/g, (match, p1) => { | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |       const clazz = classesMap.get(p1); | 
					
						
							|  |  |  |       if (clazz) | 
					
						
							|  |  |  |         return linkRenderer({ clazz }) || match; | 
					
						
							|  |  |  |       return match; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {MarkdownNode[]} spec | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function generateSourceCodeComment(spec) { | 
					
						
							|  |  |  |   const comments = (spec || []).filter(n => !n.type.startsWith('h') && (n.type !== 'li' ||  n.liType !== 'default')).map(c => md.clone(c)); | 
					
						
							|  |  |  |   md.visitAll(comments, node => { | 
					
						
							| 
									
										
										
										
											2022-06-10 16:34:31 -08:00
										 |  |  |     if (node.codeLang && node.codeLang.includes('tab=js-js')) | 
					
						
							|  |  |  |       node.type = 'null'; | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     if (node.liType === 'bullet') | 
					
						
							|  |  |  |       node.liType = 'default'; | 
					
						
							| 
									
										
										
										
											2021-01-12 12:14:27 -08:00
										 |  |  |     if (node.type === 'note') { | 
					
						
							|  |  |  |       node.type = 'text'; | 
					
						
							|  |  |  |       node.text = '> NOTE: ' + node.text; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   }); | 
					
						
							|  |  |  |   return md.render(comments, 120); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | module.exports = Documentation; |