| 
									
										
										
										
											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>, | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |  *   types?: Object<string, Type>, | 
					
						
							|  |  |  |  *   overrides?: Object<string, Member>, | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |  * }} Langs | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {function({ | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |  *   clazz?: Class, | 
					
						
							|  |  |  |  *   member?: Member, | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |  *   param?: string, | 
					
						
							| 
									
										
										
										
											2022-11-02 13:35:51 -07:00
										 |  |  |  *   option?: string, | 
					
						
							|  |  |  |  *   href?: string, | 
					
						
							|  |  |  |  * }): string|undefined} Renderer | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {{ | 
					
						
							|  |  |  |  *   langs: Langs, | 
					
						
							|  |  |  |  *   since: string, | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |  *   deprecated: string | undefined, | 
					
						
							|  |  |  |  *   discouraged: string | undefined, | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |  *   experimental: boolean | 
					
						
							|  |  |  |  * }} Metainfo | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-02-10 07:13:14 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @typedef {{ | 
					
						
							|  |  |  |  *   csharpOptionOverloadsShortNotation?: boolean, | 
					
						
							|  |  |  |  * }} LanguageOptions | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  | /** @typedef {{ | 
					
						
							|  |  |  |  *    value: string, groupId: string, spec: MarkdownNode | 
					
						
							|  |  |  |  * }} CodeGroup */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @typedef {function(CodeGroup[]): MarkdownNode[]} CodeGroupTransformer */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  | class Documentation { | 
					
						
							|  |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {!Array<!Class>} classesArray | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    */ | 
					
						
							|  |  |  |   constructor(classesArray) { | 
					
						
							|  |  |  |     this.classesArray = classesArray; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Map<string, !Class>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |    * @param {LanguageOptions=} options | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |   filterForLanguage(lang, options = {}) { | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |       clazz.filterForLanguage(lang, options); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |       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) { | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     // @type {Map<string, Class>}
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     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
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |      * @param {Class|Member|undefined} classOrMember | 
					
						
							|  |  |  |      * @param {string} text | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |     this._patchLinksInText = (classOrMember, text) => patchLinksInText(classOrMember, text, classesMap, membersMap, linkRenderer); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (const clazz of this.classesArray) | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |       clazz.visit(item => item.spec && this.renderLinksInNodes(item.spec, item)); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * @param {MarkdownNode[]} nodes | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |    * @param {Class|Member=} classOrMember | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |   renderLinksInNodes(nodes, classOrMember) { | 
					
						
							|  |  |  |     md.visitAll(nodes, node => { | 
					
						
							|  |  |  |       if (!node.text) | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |       node.text = this.renderLinksInText(node.text, classOrMember); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} text | 
					
						
							|  |  |  |    * @param {Class|Member=} classOrMember | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   renderLinksInText(text, classOrMember) { | 
					
						
							|  |  |  |     return this._patchLinksInText?.(classOrMember, text); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-14 13:05:05 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} lang | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {CodeGroupTransformer} transformer | 
					
						
							| 
									
										
										
										
											2022-11-14 13:05:05 -08:00
										 |  |  |    */ | 
					
						
							|  |  |  |   setCodeGroupsTransformer(lang, transformer) { | 
					
						
							|  |  |  |     this._codeGroupsTransformer = { lang, transformer }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   generateSourceCodeComments() { | 
					
						
							| 
									
										
										
										
											2022-11-14 13:05:05 -08:00
										 |  |  |     for (const clazz of this.classesArray) { | 
					
						
							|  |  |  |       clazz.visit(item => { | 
					
						
							|  |  |  |         let spec = item.spec; | 
					
						
							|  |  |  |         if (spec && this._codeGroupsTransformer) | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |           spec = processCodeGroups(spec, this._codeGroupsTransformer.lang, this._codeGroupsTransformer.transformer); | 
					
						
							| 
									
										
										
										
											2022-11-14 13:05:05 -08:00
										 |  |  |         item.comment = generateSourceCodeComment(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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |  class Class { | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {!Array<!Member>} membersArray | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @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; | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |     this.deprecated = metainfo.deprecated; | 
					
						
							|  |  |  |     this.discouraged = metainfo.discouraged; | 
					
						
							| 
									
										
										
										
											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(); | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |     const match = /** @type {string[]} */(name.match(/(API|JS|CDP|[A-Z])(.*)/)); | 
					
						
							| 
									
										
										
										
											2020-12-28 23:42:51 -08:00
										 |  |  |     this.varName = match[1].toLowerCase() + match[2]; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Map<string, !Member>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.members = new Map(); | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Map<string, !Member>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.properties = new Map(); | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Array<!Member>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.propertiesArray = []; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Map<string, !Member>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.methods = new Map(); | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Array<!Member>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.methodsArray = []; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Map<string, !Member>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.events = new Map(); | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Array<!Member>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.eventsArray = []; | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   index() { | 
					
						
							|  |  |  |     this.members = new Map(); | 
					
						
							|  |  |  |     this.properties = new Map(); | 
					
						
							|  |  |  |     this.propertiesArray = []; | 
					
						
							|  |  |  |     this.methods = new Map(); | 
					
						
							|  |  |  |     this.methodsArray = []; | 
					
						
							|  |  |  |     this.events = new Map(); | 
					
						
							|  |  |  |     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-11-23 08:40:47 -08:00
										 |  |  |     const cls = new Class({ langs: this.langs, experimental: this.experimental, since: this.since, deprecated: this.deprecated, discouraged: this.discouraged }, 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 | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |    * @param {LanguageOptions=} options | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |   filterForLanguage(lang, options = {}) { | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |       member.filterForLanguage(lang, options); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |       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
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {function(Member|Class): void} visitor | 
					
						
							| 
									
										
										
										
											2020-12-28 17:38:00 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											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
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  | class Member { | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @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 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {?Type} type | 
					
						
							|  |  |  |    * @param {!Array<!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; | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |     this.deprecated = metainfo.deprecated; | 
					
						
							|  |  |  |     this.discouraged = metainfo.discouraged; | 
					
						
							| 
									
										
										
										
											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 =  ''; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Map<string, !Member>} */ | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |     this.args = new Map(); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     this.index(); | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {!Class | null} */ | 
					
						
							| 
									
										
										
										
											2020-12-28 23:42:51 -08:00
										 |  |  |     this.clazz = null; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {Member=} */ | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |     this.enclosingMethod = undefined; | 
					
						
							| 
									
										
										
										
											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('#')) { | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |       const match = /** @type {string[]} */(name.match(/(.*)#(.*)/)); | 
					
						
							| 
									
										
										
										
											2021-08-27 21:57:40 -07:00
										 |  |  |       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 | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |      * @type {Boolean | null} | 
					
						
							| 
									
										
										
										
											2021-06-16 23:19:24 -07:00
										 |  |  |      */ | 
					
						
							|  |  |  |     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') { | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |         // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-06-16 23:19:24 -07:00
										 |  |  |         arg.type.properties.sort((p1, p2) => p1.name.localeCompare(p2.name)); | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |         // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-06-16 23:19:24 -07:00
										 |  |  |         arg.type.properties.forEach(p => p.enclosingMethod = this); | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |    * @param {string} lang | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |    * @param {LanguageOptions=} options | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |   filterForLanguage(lang, options = {}) { | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |     if (!this.type) | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											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]; | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |     this.type.filterForLanguage(lang, options); | 
					
						
							| 
									
										
										
										
											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; | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |       overriddenArg.filterForLanguage(lang, options); | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |       // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-01-28 17:51:41 -08:00
										 |  |  |       if (overriddenArg.name === 'options' && !overriddenArg.type.properties.length) | 
					
						
							| 
									
										
										
										
											2021-01-10 18:18:35 -08:00
										 |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |       // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |       overriddenArg.type.filterForLanguage(lang, options); | 
					
						
							| 
									
										
										
										
											2021-01-28 17:51:41 -08:00
										 |  |  |       argsArray.push(overriddenArg); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |     } | 
					
						
							|  |  |  |     this.argsArray = argsArray; | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const optionsArg = this.argsArray.find(arg => arg.name === 'options'); | 
					
						
							|  |  |  |     if (lang === 'csharp' && optionsArg) { | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         patchCSharpOptionOverloads(optionsArg, options); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         throw new Error(`Error processing csharp options in ${this.clazz?.name}.${this.name}: ` + e.message); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |   filterOutExperimental() { | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |     if (!this.type) | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     this.type.filterOutExperimental(); | 
					
						
							|  |  |  |     const argsArray = []; | 
					
						
							|  |  |  |     for (const arg of this.argsArray) { | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |       if (arg.experimental || !arg.type) | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |         continue; | 
					
						
							|  |  |  |       arg.type.filterOutExperimental(); | 
					
						
							|  |  |  |       argsArray.push(arg); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     this.argsArray = argsArray; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 23:42:51 -08:00
										 |  |  |   clone() { | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |     const result = new Member(this.kind, { langs: this.langs, experimental: this.experimental, since: this.since, deprecated: this.deprecated, discouraged: this.discouraged }, 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 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {!Array<!Member>} argsArray | 
					
						
							|  |  |  |    * @param {?Type} returnType | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |    * @param {MarkdownNode[]=} spec | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @return {!Member} | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |   static createMethod(metainfo, name, argsArray, returnType, spec) { | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     return new 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 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {!Type} type | 
					
						
							| 
									
										
										
										
											2021-01-08 15:00:14 -08:00
										 |  |  |    * @param {!MarkdownNode[]=} spec | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    * @param {boolean=} required | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @return {!Member} | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |   static createProperty(metainfo, name, type, spec, required) { | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     return new 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 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {?Type=} type | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |    * @param {MarkdownNode[]=} spec | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @return {!Member} | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-07-05 16:24:50 -08:00
										 |  |  |   static createEvent(metainfo, name, type = null, spec) { | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     return new Member('event', metainfo, name, type, [], spec); | 
					
						
							| 
									
										
										
										
											2020-12-26 14:31:41 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-10 07:13:14 -08:00
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {function(Member|Class): void} visitor | 
					
						
							| 
									
										
										
										
											2020-12-28 17:38:00 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											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
										 |  |  |   } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  | class Type { | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} expression | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {!Array<!Member>=} properties | 
					
						
							|  |  |  |    * @return {Type} | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |    */ | 
					
						
							|  |  |  |   static parse(expression, properties = []) { | 
					
						
							|  |  |  |     expression = expression.replace(/\\\(/g, '(').replace(/\\\)/g, ')'); | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     const type = 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 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @return {Type} | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |    */ | 
					
						
							|  |  |  |   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)) { | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |       const type = new Type(parsedType.unionName || ''); | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       type.union = []; | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |       // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-02-05 16:32:13 -08:00
										 |  |  |       for (let t = parsedType; t; t = t.union) { | 
					
						
							|  |  |  |         const nestedUnion = !!t.unionName && t !== parsedType; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |         type.union.push(Type.fromParsedType(t, !nestedUnion)); | 
					
						
							| 
									
										
										
										
											2021-02-05 16:32:13 -08:00
										 |  |  |         if (nestedUnion) | 
					
						
							|  |  |  |           break; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       return type; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (parsedType.args) { | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |       const type = new Type('function'); | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       type.args = []; | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |       // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       for (let t = parsedType.args; t; t = t.next) | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |         type.args.push(Type.fromParsedType(t)); | 
					
						
							|  |  |  |       type.returnType = parsedType.retType ? Type.fromParsedType(parsedType.retType) : undefined; | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       return type; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (parsedType.template) { | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |       const type = new Type(parsedType.name); | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       type.templates = []; | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |       // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       for (let t = parsedType.template; t; t = t.next) | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |         type.templates.push(Type.fromParsedType(t)); | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |       return type; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     return new Type(parsedType.name); | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * @param {string} name | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {!Array<!Member>=} properties | 
					
						
							| 
									
										
										
										
											2019-11-18 18:18:28 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |   constructor(name, properties) { | 
					
						
							|  |  |  |     this.name = name.replace(/^\[/, '').replace(/\]$/, ''); | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {Member[] | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.properties = this.name === 'Object' ? properties : undefined; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {Type[] | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.union; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {Type[] | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.args; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {Type | undefined} */ | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |     this.returnType; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     /** @type {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() { | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     const type = new Type(this.name, this.properties ? this.properties.map(prop => prop.clone()) : undefined); | 
					
						
							| 
									
										
										
										
											2022-04-13 16:13:30 -07:00
										 |  |  |     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
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @returns {Member[]} | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |    */ | 
					
						
							|  |  |  |   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
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     * @returns {Member[] | undefined} | 
					
						
							| 
									
										
										
										
											2021-04-08 09:21:10 -03:00
										 |  |  |   */ | 
					
						
							|  |  |  |   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 | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |    * @param {LanguageOptions=} options | 
					
						
							| 
									
										
										
										
											2021-01-10 18:18:35 -08:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |   filterForLanguage(lang, options = {}) { | 
					
						
							| 
									
										
										
										
											2021-01-10 18:18:35 -08:00
										 |  |  |     if (!this.properties) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     const properties = []; | 
					
						
							|  |  |  |     for (const prop of this.properties) { | 
					
						
							|  |  |  |       if (prop.langs.only && !prop.langs.only.includes(lang)) | 
					
						
							|  |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |       prop.filterForLanguage(lang, options); | 
					
						
							| 
									
										
										
										
											2021-01-10 18:18:35 -08:00
										 |  |  |       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
										 |  |  |   /** | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |    * @param {Type[]} result | 
					
						
							| 
									
										
										
										
											2021-01-04 17:59:23 -08:00
										 |  |  |    */ | 
					
						
							|  |  |  |   _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
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |  * @param {ParsedType | null} type | 
					
						
							| 
									
										
										
										
											2021-02-05 15:28:48 -08:00
										 |  |  |  * @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
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |  * @param {Class|Member|undefined} classOrMember | 
					
						
							|  |  |  |  * @param {string} text | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |  * @param {Map<string, Class>} classesMap | 
					
						
							|  |  |  |  * @param {Map<string, Member>} membersMap | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |  * @param {Renderer} linkRenderer | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  | function patchLinksInText(classOrMember, text, classesMap, membersMap, linkRenderer) { | 
					
						
							|  |  |  |   text = text.replace(/\[`(\w+): ([^\]]+)`\](?:\(([^)]*?)\))?/g, (match, p1, p2, href) => { | 
					
						
							|  |  |  |     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, href }) || match; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     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; | 
					
						
							| 
									
										
										
										
											2021-01-29 16:02:17 -08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |       return linkRenderer({ param: alias, href }) || match; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (p1 === 'option') | 
					
						
							|  |  |  |       return linkRenderer({ option: p2, href }) || match; | 
					
						
							|  |  |  |     throw new Error(`Undefined link prefix, expected event|method|property|param|option, got: ` + match); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   text = text.replace(/\[([\w]+)\](?:\(([^)]*?)\))?/g, (match, p1, href) => { | 
					
						
							|  |  |  |     const clazz = classesMap.get(p1); | 
					
						
							|  |  |  |     if (clazz) | 
					
						
							|  |  |  |       return linkRenderer({ clazz, href }) || match; | 
					
						
							|  |  |  |     return match; | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2022-11-23 08:40:47 -08:00
										 |  |  |   return text; | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |  * @param {MarkdownNode[] | undefined} spec | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 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-09-27 08:27:23 -08:00
										 |  |  |     if (node.type === 'li' && node.liType === 'bullet') | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |       node.liType = 'default'; | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |     if (node.type === 'code' && node.codeLang) | 
					
						
							|  |  |  |       node.codeLang = parseCodeLang(node.codeLang).highlighter; | 
					
						
							| 
									
										
										
										
											2021-01-12 12:14:27 -08:00
										 |  |  |     if (node.type === 'note') { | 
					
						
							| 
									
										
										
										
											2022-09-27 08:27:23 -08:00
										 |  |  |       // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2021-01-12 12:14:27 -08:00
										 |  |  |       node.type = 'text'; | 
					
						
							| 
									
										
										
										
											2022-11-23 12:32:14 -08:00
										 |  |  |       node.text = '**NOTE** ' + node.text; | 
					
						
							| 
									
										
										
										
											2021-01-12 12:14:27 -08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2022-11-21 09:30:32 -08:00
										 |  |  |   // 5 is a typical member doc offset.
 | 
					
						
							|  |  |  |   return md.render(comments, { maxColumns: 120 - 5, omitLastCR: true, flattenText: true }); | 
					
						
							| 
									
										
										
										
											2021-01-07 15:00:04 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  |  * @param {Member} optionsArg | 
					
						
							| 
									
										
										
										
											2022-11-15 15:46:54 -08:00
										 |  |  |  * @param {LanguageOptions=} options | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function patchCSharpOptionOverloads(optionsArg, options = {}) { | 
					
						
							|  |  |  |   const props = optionsArg.type?.properties; | 
					
						
							|  |  |  |   if (!props) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   const propsToDelete = new Set(); | 
					
						
							|  |  |  |   const propsToAdd = []; | 
					
						
							|  |  |  |   for (const prop of props) { | 
					
						
							|  |  |  |     const union = prop.type?.union; | 
					
						
							|  |  |  |     if (!union) | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     const isEnum = union[0].name.startsWith('"'); | 
					
						
							|  |  |  |     const isNullable = union.length === 2 && union.some(type => type.name === 'null'); | 
					
						
							|  |  |  |     if (isEnum || isNullable) | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const shortNotation = []; | 
					
						
							|  |  |  |     propsToDelete.add(prop); | 
					
						
							|  |  |  |     for (const type of union) { | 
					
						
							|  |  |  |       const suffix = csharpOptionOverloadSuffix(prop.name, type.name); | 
					
						
							|  |  |  |       if (options.csharpOptionOverloadsShortNotation) { | 
					
						
							|  |  |  |         if (type.name === 'string') | 
					
						
							|  |  |  |           shortNotation.push(prop.alias); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           shortNotation.push(prop.alias + suffix); | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const newProp = prop.clone(); | 
					
						
							|  |  |  |       newProp.name = prop.name + suffix; | 
					
						
							|  |  |  |       newProp.alias = prop.alias + suffix; | 
					
						
							|  |  |  |       newProp.type = type; | 
					
						
							|  |  |  |       propsToAdd.push(newProp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (type.name === 'string') { | 
					
						
							|  |  |  |         const stringProp = prop.clone(); | 
					
						
							|  |  |  |         stringProp.type = type; | 
					
						
							|  |  |  |         propsToAdd.push(stringProp); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (options.csharpOptionOverloadsShortNotation) { | 
					
						
							|  |  |  |       const newProp = prop.clone(); | 
					
						
							|  |  |  |       newProp.alias = newProp.name = shortNotation.join('|'); | 
					
						
							|  |  |  |       propsToAdd.push(newProp); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   for (const prop of propsToDelete) | 
					
						
							|  |  |  |     props.splice(props.indexOf(prop), 1); | 
					
						
							|  |  |  |   props.push(...propsToAdd); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} option | 
					
						
							|  |  |  |  * @param {string} type | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function csharpOptionOverloadSuffix(option, type) { | 
					
						
							|  |  |  |   switch (type) { | 
					
						
							|  |  |  |     case 'string': return 'String'; | 
					
						
							|  |  |  |     case 'RegExp': return 'Regex'; | 
					
						
							|  |  |  |     case 'function': return 'Func'; | 
					
						
							|  |  |  |     case 'Buffer': return 'Byte'; | 
					
						
							|  |  |  |     case 'Serializable': return 'Object'; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   throw new Error(`CSharp option "${option}" has unsupported type overload "${type}"`); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-11-19 11:26:11 -08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {MarkdownNode[]} spec | 
					
						
							|  |  |  |  * @param {string} language | 
					
						
							|  |  |  |  * @param {CodeGroupTransformer} transformer | 
					
						
							|  |  |  |  * @returns {MarkdownNode[]} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function processCodeGroups(spec, language, transformer) { | 
					
						
							|  |  |  |   /** @type {MarkdownNode[]} */ | 
					
						
							|  |  |  |   const newSpec = []; | 
					
						
							|  |  |  |   for (let i = 0; i < spec.length; ++i) { | 
					
						
							|  |  |  |     /** @type {{value: string, groupId: string, spec: MarkdownNode}[]} */ | 
					
						
							|  |  |  |     const tabs = []; | 
					
						
							|  |  |  |     for (;i < spec.length; i++) { | 
					
						
							|  |  |  |       const codeLang = spec[i].codeLang; | 
					
						
							|  |  |  |       if (!codeLang) | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       let parsed; | 
					
						
							|  |  |  |       try { | 
					
						
							|  |  |  |         parsed = parseCodeLang(codeLang); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         throw new Error(e.message + '\n while processing:\n' + md.render([spec[i]])); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (!parsed.codeGroup) | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |       if (parsed.language && parsed.language !== language) | 
					
						
							|  |  |  |         continue; | 
					
						
							|  |  |  |       const [groupId, value] = parsed.codeGroup.split('-'); | 
					
						
							|  |  |  |       const clone = md.clone(spec[i]); | 
					
						
							|  |  |  |       clone.codeLang = parsed.highlighter; | 
					
						
							|  |  |  |       tabs.push({ groupId, value, spec: clone }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (tabs.length) { | 
					
						
							|  |  |  |       if (tabs.length === 1) | 
					
						
							|  |  |  |         throw new Error(`Lonely tab "${tabs[0].spec.codeLang}". Make sure there are at least two tabs in the group.\n` + md.render([tabs[0].spec])); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Validate group consistency.
 | 
					
						
							|  |  |  |       const groupId = tabs[0].groupId; | 
					
						
							|  |  |  |       const values = new Set(); | 
					
						
							|  |  |  |       for (const tab of tabs) { | 
					
						
							|  |  |  |         if (tab.groupId !== groupId) | 
					
						
							|  |  |  |           throw new Error('Mixed group ids: ' + md.render(spec)); | 
					
						
							|  |  |  |         if (values.has(tab.value)) | 
					
						
							|  |  |  |           throw new Error(`Duplicated tab "${tab.value}"\n` + md.render(tabs.map(tab => tab.spec))); | 
					
						
							|  |  |  |         values.add(tab.value); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Append transformed nodes.
 | 
					
						
							|  |  |  |       newSpec.push(...transformer(tabs)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (i < spec.length) | 
					
						
							|  |  |  |       newSpec.push(spec[i]); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return newSpec; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} codeLang | 
					
						
							|  |  |  |  * @return {{ highlighter: string, language: string|undefined, codeGroup: string|undefined}} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |  function parseCodeLang(codeLang) { | 
					
						
							|  |  |  |   if (codeLang === 'python async') | 
					
						
							|  |  |  |     return { highlighter: 'py', codeGroup: 'python-async', language: 'python' }; | 
					
						
							|  |  |  |   if (codeLang === 'python sync') | 
					
						
							|  |  |  |     return { highlighter: 'py', codeGroup: 'python-sync', language: 'python' }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const [highlighter] = codeLang.split(' '); | 
					
						
							|  |  |  |   if (!highlighter) | 
					
						
							|  |  |  |     throw new Error(`Cannot parse code block lang: "${codeLang}"`); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const languageMatch = codeLang.match(/ lang=([\w\d]+)/); | 
					
						
							|  |  |  |   let language = languageMatch ? languageMatch[1] : undefined; | 
					
						
							|  |  |  |   if (!language) { | 
					
						
							|  |  |  |     if (highlighter === 'ts') | 
					
						
							|  |  |  |       language = 'js'; | 
					
						
							|  |  |  |     else if (highlighter === 'py') | 
					
						
							|  |  |  |       language = 'python'; | 
					
						
							|  |  |  |     else if (['js', 'python', 'csharp', 'java'].includes(highlighter)) | 
					
						
							|  |  |  |       language = highlighter; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const tabMatch = codeLang.match(/ tab=([\w\d-]+)/); | 
					
						
							|  |  |  |   return { highlighter, language, codeGroup: tabMatch ? tabMatch[1] : '' }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = { Documentation, Class, Member, Type, processCodeGroups, parseCodeLang }; |