//#region src/errors.ts
function tokenToString(token) {
	if (token.text !== void 0 && token.text !== "") return `'${token.type}' with value '${token.text}'`;
	else return `'${token.type}'`;
}
var NoParsletFoundError = class NoParsletFoundError extends Error {
	token;
	constructor(token) {
		super(`No parslet found for token: ${tokenToString(token)}`);
		this.token = token;
		Object.setPrototypeOf(this, NoParsletFoundError.prototype);
	}
	getToken() {
		return this.token;
	}
};
var EarlyEndOfParseError = class EarlyEndOfParseError extends Error {
	token;
	constructor(token) {
		super(`The parsing ended early. The next token was: ${tokenToString(token)}`);
		this.token = token;
		Object.setPrototypeOf(this, EarlyEndOfParseError.prototype);
	}
	getToken() {
		return this.token;
	}
};
var UnexpectedTypeError = class UnexpectedTypeError extends Error {
	constructor(result, message) {
		let error = `Unexpected type: '${result.type}'.`;
		if (message !== void 0) error += ` Message: ${message}`;
		super(error);
		Object.setPrototypeOf(this, UnexpectedTypeError.prototype);
	}
};
//#endregion
//#region src/lexer/Token.ts
const baseNameTokens = [
	"module",
	"keyof",
	"event",
	"external",
	"readonly",
	"is",
	"typeof",
	"in",
	"null",
	"undefined",
	"function",
	"asserts",
	"infer",
	"extends",
	"import"
];
const reservedWordsAsRootTSTypes = [
	"false",
	"null",
	"true",
	"void"
];
[...reservedWordsAsRootTSTypes];
const reservedWords$1 = {
	always: [
		"break",
		"case",
		"catch",
		"class",
		"const",
		"continue",
		"debugger",
		"default",
		"delete",
		"do",
		"else",
		"export",
		"extends",
		"false",
		"finally",
		"for",
		"function",
		"if",
		"import",
		"in",
		"instanceof",
		"new",
		"null",
		"return",
		"super",
		"switch",
		"this",
		"throw",
		"true",
		"try",
		"typeof",
		"var",
		"void",
		"while",
		"with"
	],
	strictMode: [
		"let",
		"static",
		"yield"
	],
	moduleOrAsyncFunctionBodies: ["await"]
};
const futureReservedWords = {
	always: ["enum"],
	strictMode: [
		"implements",
		"interface",
		"package",
		"private",
		"protected",
		"public"
	]
};
const strictModeNonIdentifiers = ["arguments", "eval"];
//#endregion
//#region src/assertTypes.ts
function assertResultIsNotReservedWord(parser, result) {
	let text;
	if (result.type === "JsdocTypeName") text = result.value;
	else if (result.type === "JsdocTypeParenthesis") {
		let res = result;
		while (res.type === "JsdocTypeParenthesis") res = res.element;
		if (res.type === "JsdocTypeName") text = res.value;
		else return result;
	} else return result;
	if (reservedWords$1.always.includes(text) && !reservedWordsAsRootTSTypes.includes(text) && (text !== "this" || parser.classContext !== true)) throw new Error(`Unexpected reserved keyword "${text}"`);
	if (futureReservedWords.always.includes(text)) throw new Error(`Unexpected future reserved keyword "${text}"`);
	if (parser.module !== void 0 && parser.module || parser.strictMode !== void 0 && parser.strictMode) {
		if (reservedWords$1.strictMode.includes(text)) throw new Error(`Unexpected reserved keyword "${text}" for strict mode`);
		if (futureReservedWords.strictMode.includes(text)) throw new Error(`Unexpected future reserved keyword "${text}" for strict mode`);
		if (strictModeNonIdentifiers.includes(text)) throw new Error(`The item "${text}" is not an identifier in strict mode`);
	}
	if (parser.module !== void 0 && parser.module || parser.asyncFunctionBody !== void 0 && parser.asyncFunctionBody) {
		if (reservedWords$1.moduleOrAsyncFunctionBodies.includes(text)) throw new Error(`Unexpected reserved keyword "${text}" for modules or async function bodies`);
	}
	return result;
}
/**
* Throws an error if the provided result is not a {@link RootResult}
*/
function assertRootResult(result) {
	if (result === void 0) throw new Error("Unexpected undefined");
	if (result.type === "JsdocTypeKeyValue" || result.type === "JsdocTypeParameterList" || result.type === "JsdocTypeProperty" || result.type === "JsdocTypeReadonlyProperty" || result.type === "JsdocTypeObjectField" || result.type === "JsdocTypeJsdocObjectField" || result.type === "JsdocTypeIndexSignature" || result.type === "JsdocTypeMappedType" || result.type === "JsdocTypeTypeParameter" || result.type === "JsdocTypeCallSignature" || result.type === "JsdocTypeConstructorSignature" || result.type === "JsdocTypeMethodSignature" || result.type === "JsdocTypeIndexedAccessIndex" || result.type === "JsdocTypeComputedProperty" || result.type === "JsdocTypeComputedMethod") throw new UnexpectedTypeError(result);
	return result;
}
function assertPlainKeyValueOrRootResult(result) {
	if (result.type === "JsdocTypeKeyValue") return assertPlainKeyValueResult(result);
	return assertRootResult(result);
}
function assertPlainKeyValueOrNameResult(result) {
	if (result.type === "JsdocTypeName") return result;
	return assertPlainKeyValueResult(result);
}
function assertPlainKeyValueResult(result) {
	if (result.type !== "JsdocTypeKeyValue") throw new UnexpectedTypeError(result);
	return result;
}
function assertNumberOrVariadicNameResult(result) {
	if (result.type === "JsdocTypeVariadic") {
		if (result.element?.type === "JsdocTypeName") return result;
		throw new UnexpectedTypeError(result);
	}
	if (result.type !== "JsdocTypeNumber" && result.type !== "JsdocTypeName") throw new UnexpectedTypeError(result);
	return result;
}
function assertArrayOrTupleResult(result) {
	if (result.type === "JsdocTypeTuple") return result;
	if (result.type === "JsdocTypeGeneric" && result.meta.brackets === "square") return result;
	throw new UnexpectedTypeError(result);
}
function isSquaredProperty(result) {
	return result.type === "JsdocTypeIndexSignature" || result.type === "JsdocTypeMappedType";
}
//#endregion
//#region src/Parser.ts
var Parser = class {
	grammar;
	_lexer;
	baseParser;
	externalParsers;
	module;
	strictMode;
	asyncFunctionBody;
	classContext;
	rangeStart;
	range;
	locStart;
	loc;
	constructor(grammar, lexer, baseParser, { module, strictMode, asyncFunctionBody, classContext, range = false, rangeStart = 0, loc = false, locStart = {
		line: 1,
		column: 0
	}, externalParsers } = {}) {
		this.grammar = grammar;
		this._lexer = lexer;
		this.baseParser = baseParser;
		this.externalParsers = externalParsers;
		this.module = module;
		this.strictMode = strictMode;
		this.asyncFunctionBody = asyncFunctionBody;
		this.classContext = classContext;
		this.rangeStart = rangeStart;
		this.range = range;
		this.locStart = locStart;
		this.loc = loc;
	}
	get lexer() {
		return this._lexer;
	}
	/**
	* Parses a given string and throws an error if the parse ended before the end of the string.
	*/
	parse() {
		const result = this.parseType(0);
		if (this.lexer.current.type !== "EOF") throw new EarlyEndOfParseError(this.lexer.current);
		return result;
	}
	/**
	* Parses with the current lexer and asserts that the result is a {@link RootResult}.
	*/
	parseType(precedence) {
		return assertRootResult(this.parseIntermediateType(precedence));
	}
	/**
	* The main parsing function. First it tries to parse the current state in the prefix step, and then it continues
	* to parse the state in the infix step.
	*/
	parseIntermediateType(precedence) {
		const result = this.tryParslets(null, precedence);
		if (result === null) throw new NoParsletFoundError(this.lexer.current);
		return this.parseInfixIntermediateType(result, precedence);
	}
	/**
	* In the infix parsing step the parser continues to parse the current state with all parslets until none returns
	* a result.
	*/
	parseInfixIntermediateType(left, precedence) {
		let result = this.tryParslets(left, precedence);
		while (result !== null) {
			left = result;
			result = this.tryParslets(left, precedence);
		}
		return left;
	}
	/**
	* Tries to parse the current state with all parslets in the grammar and returns the first non null result.
	*/
	tryParslets(left, precedence) {
		for (const parslet of this.grammar) {
			const rangeStart = this.rangeStart;
			const locStartLine = this.locStart.line;
			const locStartColumn = this.locStart.column;
			const result = parslet(this, precedence, left);
			if (result !== null) {
				if (this.range) result.range = [rangeStart, this.rangeStart];
				if (this.loc) result.loc = {
					end: {
						line: this.locStart.line,
						column: this.locStart.column
					},
					start: {
						line: locStartLine,
						column: locStartColumn
					}
				};
				return result;
			}
		}
		return null;
	}
	/**
	* If the given type equals the current type of the {@link Lexer} advance the lexer. Return true if the lexer was
	* advanced.
	*/
	consume(types) {
		if (!Array.isArray(types)) types = [types];
		if (types.includes(this.lexer.current.type)) {
			if (this.range)
 /* c8 ignore next -- Default is for TS */
			this.rangeStart += this.lexer.current?.reduced ?? 0;
			if (this.loc) {
				/* c8 ignore next 4 -- Defaults are for TS */
				this.locStart.line += this.lexer.current?.line ?? 0;
				this.locStart.column = (this.lexer.current?.line ?? 0) > 0 ? this.lexer.current?.column ?? 0 : this.locStart.column + (this.lexer.current?.column ?? 0);
			}
			this._lexer = this.lexer.advance();
			return true;
		} else return false;
	}
	acceptLexerState(parser) {
		this._lexer = parser.lexer;
	}
};
//#endregion
//#region src/parslets/isQuestionMarkUnknownType.ts
function isQuestionMarkUnknownType(next) {
	return next === "}" || next === "EOF" || next === "|" || next === "," || next === ")" || next === ">";
}
//#endregion
//#region src/parslets/NullableParslets.ts
const nullableParslet = (parser, precedence, left) => {
	const type = parser.lexer.current.type;
	const next = parser.lexer.next.type;
	const inferSuffix = left?.type === "JsdocTypeInfer";
	if (!(left === null && type === "?" && !isQuestionMarkUnknownType(next) || left !== null && !inferSuffix && type === "?" && 12 > precedence)) return null;
	parser.consume("?");
	if (left === null) return {
		type: "JsdocTypeNullable",
		element: parser.parseType(12),
		meta: { position: "prefix" }
	};
	else return {
		type: "JsdocTypeNullable",
		element: assertRootResult(left),
		meta: { position: "suffix" }
	};
};
//#endregion
//#region src/parslets/Parslet.ts
function composeParslet(options) {
	const parslet = (parser, curPrecedence, left) => {
		const type = parser.lexer.current.type;
		const next = parser.lexer.next.type;
		if (left === null) {
			if ("parsePrefix" in options) {
				if (options.accept(type, next)) return options.parsePrefix(parser);
			}
		} else if ("parseInfix" in options) {
			if (options.precedence > curPrecedence && options.accept(type, next)) return options.parseInfix(parser, left);
		}
		return null;
	};
	Object.defineProperty(parslet, "name", { value: options.name });
	return parslet;
}
//#endregion
//#region src/parslets/OptionalParslet.ts
const optionalParslet = composeParslet({
	name: "optionalParslet",
	accept: (type) => type === "=",
	precedence: 11,
	parsePrefix: (parser) => {
		parser.consume("=");
		return {
			type: "JsdocTypeOptional",
			element: parser.parseType(11),
			meta: { position: "prefix" }
		};
	},
	parseInfix: (parser, left) => {
		parser.consume("=");
		return {
			type: "JsdocTypeOptional",
			element: assertRootResult(left),
			meta: { position: "suffix" }
		};
	}
});
//#endregion
//#region src/parslets/NumberParslet.ts
const numberParslet = composeParslet({
	name: "numberParslet",
	accept: (type) => type === "Number",
	parsePrefix: (parser) => {
		const text = parser.lexer.current.text;
		parser.consume("Number");
		if (text.endsWith("n")) {
			const bigintText = text.slice(0, -1);
			return {
				type: "JsdocTypeBigInt",
				value: BigInt(bigintText).toString()
			};
		}
		return {
			type: "JsdocTypeNumber",
			value: parseFloat(text)
		};
	}
});
//#endregion
//#region src/parslets/ParenthesisParslet.ts
const parenthesisParslet = composeParslet({
	name: "parenthesisParslet",
	accept: (type) => type === "(",
	parsePrefix: (parser) => {
		parser.consume("(");
		if (parser.consume(")")) return {
			type: "JsdocTypeParameterList",
			elements: []
		};
		const result = parser.parseIntermediateType(0);
		if (!parser.consume(")")) throw new Error("Unterminated parenthesis");
		if (result.type === "JsdocTypeParameterList") return result;
		else if (result.type === "JsdocTypeKeyValue") return {
			type: "JsdocTypeParameterList",
			elements: [result]
		};
		return {
			type: "JsdocTypeParenthesis",
			element: assertRootResult(result)
		};
	}
});
//#endregion
//#region src/parslets/SpecialTypesParslet.ts
const specialTypesParslet = composeParslet({
	name: "specialTypesParslet",
	accept: (type, next) => type === "?" && isQuestionMarkUnknownType(next) || type === "null" || type === "undefined" || type === "*",
	parsePrefix: (parser) => {
		if (parser.consume("null")) return { type: "JsdocTypeNull" };
		if (parser.consume("undefined")) return { type: "JsdocTypeUndefined" };
		if (parser.consume("*")) return { type: "JsdocTypeAny" };
		if (parser.consume("?")) return { type: "JsdocTypeUnknown" };
		throw new Error(`Unacceptable token: ${parser.lexer.current.text}`);
	}
});
//#endregion
//#region src/parslets/NotNullableParslet.ts
const notNullableParslet = composeParslet({
	name: "notNullableParslet",
	accept: (type) => type === "!",
	precedence: 12,
	parsePrefix: (parser) => {
		parser.consume("!");
		return {
			type: "JsdocTypeNotNullable",
			element: parser.parseType(12),
			meta: { position: "prefix" }
		};
	},
	parseInfix: (parser, left) => {
		parser.consume("!");
		return {
			type: "JsdocTypeNotNullable",
			element: assertRootResult(left),
			meta: { position: "suffix" }
		};
	}
});
//#endregion
//#region src/parslets/ParameterListParslet.ts
function createParameterListParslet({ allowTrailingComma }) {
	return composeParslet({
		name: "parameterListParslet",
		accept: (type) => type === ",",
		precedence: 1,
		parseInfix: (parser, left) => {
			const elements = [assertPlainKeyValueOrRootResult(left)];
			parser.consume(",");
			do
				try {
					const next = parser.parseIntermediateType(1);
					elements.push(assertPlainKeyValueOrRootResult(next));
				} catch (e) {
					if (allowTrailingComma && e instanceof NoParsletFoundError) break;
					else throw e;
				}
			while (parser.consume(","));
			if (elements.length > 0 && elements.slice(0, -1).some((e) => e.type === "JsdocTypeVariadic")) throw new Error("Only the last parameter may be a rest parameter");
			return {
				type: "JsdocTypeParameterList",
				elements
			};
		}
	});
}
//#endregion
//#region src/parslets/GenericParslet.ts
const genericParslet = composeParslet({
	name: "genericParslet",
	accept: (type, next) => type === "<" || type === "." && next === "<",
	precedence: 17,
	parseInfix: (parser, left) => {
		const dot = parser.consume(".");
		parser.consume("<");
		const elements = [];
		do
			if (parser.consume("infer")) {
				const name = parser.parseIntermediateType(12);
				if (name.type !== "JsdocTypeName") throw new UnexpectedTypeError(name, "A typescript infer always has to have a name.");
				elements.push({
					type: "JsdocTypeInfer",
					element: name
				});
			} else elements.push(parser.parseType(1));
		while (parser.consume(","));
		if (!parser.consume(">")) throw new Error("Unterminated generic parameter list");
		return {
			type: "JsdocTypeGeneric",
			left: assertRootResult(left),
			elements,
			meta: {
				brackets: "angle",
				dot
			}
		};
	}
});
//#endregion
//#region src/parslets/UnionParslets.ts
const unionParslet = composeParslet({
	name: "unionParslet",
	accept: (type) => type === "|",
	precedence: 5,
	parseInfix: (parser, left) => {
		parser.consume("|");
		const elements = [];
		do
			elements.push(parser.parseType(5));
		while (parser.consume("|"));
		return {
			type: "JsdocTypeUnion",
			elements: [assertResultIsNotReservedWord(parser, assertRootResult(left)), ...elements.map((element) => assertResultIsNotReservedWord(parser, element))]
		};
	}
});
//#endregion
//#region src/grammars/baseGrammar.ts
const baseGrammar = [
	nullableParslet,
	optionalParslet,
	numberParslet,
	parenthesisParslet,
	specialTypesParslet,
	notNullableParslet,
	createParameterListParslet({ allowTrailingComma: true }),
	genericParslet,
	unionParslet,
	optionalParslet
];
//#endregion
//#region src/parslets/NamePathParslet.ts
function createNamePathParslet({ allowSquareBracketsOnAnyType, allowJsdocNamePaths, pathGrammar }) {
	return function namePathParslet(parser, precedence, left) {
		if (left === null || precedence >= 18) return null;
		const type = parser.lexer.current.type;
		const next = parser.lexer.next.type;
		if (!(type === "." && next !== "<" || type === "[" && (allowSquareBracketsOnAnyType || left.type === "JsdocTypeName") || allowJsdocNamePaths && (type === "~" || type === "#"))) return null;
		let pathType;
		let brackets = false;
		if (parser.consume(".")) pathType = "property";
		else if (parser.consume("[")) {
			pathType = "property-brackets";
			brackets = true;
		} else if (parser.consume("~")) pathType = "inner";
		else {
			parser.consume("#");
			pathType = "instance";
		}
		const pathParser = brackets && allowSquareBracketsOnAnyType ? parser : pathGrammar !== null ? new Parser(pathGrammar, parser.lexer, parser) : parser;
		const parsed = pathParser.parseType(brackets && allowSquareBracketsOnAnyType ? 0 : 18);
		parser.acceptLexerState(pathParser);
		let right;
		switch (parsed.type) {
			case "JsdocTypeName":
				right = {
					type: "JsdocTypeProperty",
					value: parsed.value,
					meta: { quote: void 0 }
				};
				break;
			case "JsdocTypeNumber":
				right = {
					type: "JsdocTypeProperty",
					value: parsed.value.toString(10),
					meta: { quote: void 0 }
				};
				break;
			case "JsdocTypeBigInt": throw new UnexpectedTypeError(parsed, "Expecting 'JsdocTypeName', 'JsdocTypeNumber', 'JsdocStringValue' or 'JsdocTypeSpecialNamePath'");
			case "JsdocTypeStringValue":
				right = {
					type: "JsdocTypeProperty",
					value: parsed.value,
					meta: { quote: parsed.meta.quote }
				};
				break;
			case "JsdocTypeSpecialNamePath":
				if (parsed.specialType === "event") right = parsed;
				else throw new UnexpectedTypeError(parsed, "Type 'JsdocTypeSpecialNamePath' is only allowed with specialType 'event'");
				break;
			default:
				if (!brackets || !allowSquareBracketsOnAnyType) throw new UnexpectedTypeError(parsed, "Expecting 'JsdocTypeName', 'JsdocTypeNumber', 'JsdocStringValue' or 'JsdocTypeSpecialNamePath'");
				right = {
					type: "JsdocTypeIndexedAccessIndex",
					right: parsed
				};
		}
		if (brackets && !parser.consume("]")) {
			const token = parser.lexer.current;
			throw new Error(`Unterminated square brackets. Next token is '${token.type}' with text '${token.text}'`);
		}
		return {
			type: "JsdocTypeNamePath",
			left: assertRootResult(left),
			right,
			pathType
		};
	};
}
//#endregion
//#region src/parslets/NameParslet.ts
function createNameParslet({ allowedAdditionalTokens }) {
	return composeParslet({
		name: "nameParslet",
		accept: (type) => type === "Identifier" || type === "this" || type === "new" || allowedAdditionalTokens.includes(type),
		parsePrefix: (parser) => {
			const { type, text } = parser.lexer.current;
			parser.consume(type);
			return {
				type: "JsdocTypeName",
				value: text
			};
		}
	});
}
//#endregion
//#region src/parslets/StringValueParslet.ts
const stringValueParslet = composeParslet({
	name: "stringValueParslet",
	accept: (type) => type === "StringValue",
	parsePrefix: (parser) => {
		const text = parser.lexer.current.text;
		parser.consume("StringValue");
		return {
			type: "JsdocTypeStringValue",
			value: text.slice(1, -1),
			meta: { quote: text.startsWith("'") ? "single" : "double" }
		};
	}
});
//#endregion
//#region src/parslets/SpecialNamePathParslet.ts
function createSpecialNamePathParslet({ pathGrammar, allowedTypes }) {
	return composeParslet({
		name: "specialNamePathParslet",
		accept: (type) => allowedTypes.includes(type),
		parsePrefix: (parser) => {
			const type = parser.lexer.current.type;
			parser.consume(type);
			if (!parser.consume(":")) return {
				type: "JsdocTypeName",
				value: type
			};
			let result;
			let token = parser.lexer.current;
			if (parser.consume("StringValue")) result = {
				type: "JsdocTypeSpecialNamePath",
				value: token.text.slice(1, -1),
				specialType: type,
				meta: { quote: token.text.startsWith("'") ? "single" : "double" }
			};
			else {
				let value = "";
				const allowed = [
					"Identifier",
					"@",
					"/"
				];
				while (allowed.some((type) => parser.consume(type))) {
					value += token.text;
					token = parser.lexer.current;
				}
				result = {
					type: "JsdocTypeSpecialNamePath",
					value,
					specialType: type,
					meta: { quote: void 0 }
				};
			}
			const moduleParser = new Parser(pathGrammar, parser.lexer, parser);
			const moduleResult = moduleParser.parseInfixIntermediateType(result, 0);
			parser.acceptLexerState(moduleParser);
			return assertRootResult(moduleResult);
		}
	});
}
//#endregion
//#region src/grammars/pathGrammar.ts
const basePathGrammar = [
	createNameParslet({ allowedAdditionalTokens: ["external", "module"] }),
	stringValueParslet,
	numberParslet,
	createNamePathParslet({
		allowSquareBracketsOnAnyType: false,
		allowJsdocNamePaths: true,
		pathGrammar: null
	})
];
const pathGrammar = [
	...basePathGrammar,
	createSpecialNamePathParslet({
		allowedTypes: ["event"],
		pathGrammar: basePathGrammar
	}),
	createNameParslet({ allowedAdditionalTokens: baseNameTokens })
];
//#endregion
//#region src/parslets/FunctionParslet.ts
function getParameters(value) {
	let parameters;
	if (value.type === "JsdocTypeParameterList") parameters = value.elements;
	else if (value.type === "JsdocTypeParenthesis") parameters = [value.element];
	else throw new UnexpectedTypeError(value);
	return parameters.map((p) => assertPlainKeyValueOrRootResult(p));
}
function getUnnamedParameters(value) {
	const parameters = getParameters(value);
	if (parameters.some((p) => p.type === "JsdocTypeKeyValue")) throw new Error("No parameter should be named");
	return parameters;
}
function createFunctionParslet({ allowNamedParameters, allowNoReturnType, allowWithoutParenthesis, allowNewAsFunctionKeyword }) {
	return composeParslet({
		name: "functionParslet",
		accept: (type, next) => type === "function" || allowNewAsFunctionKeyword && type === "new" && next === "(",
		parsePrefix: (parser) => {
			const newKeyword = parser.consume("new");
			parser.consume("function");
			const hasParenthesis = parser.lexer.current.type === "(";
			if (!hasParenthesis) {
				if (!allowWithoutParenthesis) throw new Error("function is missing parameter list");
				return {
					type: "JsdocTypeName",
					value: "function"
				};
			}
			let result = {
				type: "JsdocTypeFunction",
				parameters: [],
				arrow: false,
				constructor: newKeyword,
				parenthesis: hasParenthesis
			};
			const value = parser.parseIntermediateType(14);
			if (allowNamedParameters === void 0) result.parameters = getUnnamedParameters(value);
			else if (newKeyword && value.type === "JsdocTypeFunction" && value.arrow) {
				result = value;
				result.constructor = true;
				return result;
			} else {
				result.parameters = getParameters(value);
				for (const p of result.parameters) if (p.type === "JsdocTypeKeyValue" && !allowNamedParameters.includes(p.key)) throw new Error(`only allowed named parameters are ${allowNamedParameters.join(", ")} but got ${p.type}`);
			}
			if (parser.consume(":")) result.returnType = parser.parseType(7);
			else if (!allowNoReturnType) throw new Error("function is missing return type");
			return result;
		}
	});
}
//#endregion
//#region src/parslets/VariadicParslet.ts
function createVariadicParslet({ allowPostfix, allowEnclosingBrackets }) {
	return composeParslet({
		name: "variadicParslet",
		accept: (type) => type === "...",
		precedence: 7,
		parsePrefix: (parser) => {
			parser.consume("...");
			const brackets = allowEnclosingBrackets && parser.consume("[");
			try {
				const element = parser.parseType(7);
				if (brackets && !parser.consume("]")) throw new Error("Unterminated variadic type. Missing ']'");
				return {
					type: "JsdocTypeVariadic",
					element: assertRootResult(element),
					meta: {
						position: "prefix",
						squareBrackets: brackets
					}
				};
			} catch (e) {
				if (e instanceof NoParsletFoundError) {
					if (brackets) throw new Error("Empty square brackets for variadic are not allowed.", { cause: e });
					return {
						type: "JsdocTypeVariadic",
						meta: {
							position: void 0,
							squareBrackets: false
						}
					};
				} else throw e;
			}
		},
		parseInfix: allowPostfix ? (parser, left) => {
			parser.consume("...");
			return {
				type: "JsdocTypeVariadic",
				element: assertRootResult(left),
				meta: {
					position: "suffix",
					squareBrackets: false
				}
			};
		} : void 0
	});
}
//#endregion
//#region src/parslets/SymbolParslet.ts
const symbolParslet = composeParslet({
	name: "symbolParslet",
	accept: (type) => type === "(",
	precedence: 10,
	parseInfix: (parser, left) => {
		if (left.type !== "JsdocTypeName") throw new Error("Symbol expects a name on the left side. (Reacting on '(')");
		parser.consume("(");
		const result = {
			type: "JsdocTypeSymbol",
			value: left.value
		};
		if (!parser.consume(")")) {
			result.element = assertNumberOrVariadicNameResult(parser.parseIntermediateType(10));
			if (!parser.consume(")")) throw new Error("Symbol does not end after value");
		}
		return result;
	}
});
//#endregion
//#region src/parslets/ArrayBracketsParslet.ts
const arrayBracketsParslet = composeParslet({
	name: "arrayBracketsParslet",
	precedence: 16,
	accept: (type, next) => type === "[" && next === "]",
	parseInfix: (parser, left) => {
		parser.consume("[");
		parser.consume("]");
		return {
			type: "JsdocTypeGeneric",
			left: {
				type: "JsdocTypeName",
				value: "Array"
			},
			elements: [assertRootResult(left)],
			meta: {
				brackets: "square",
				dot: false
			}
		};
	}
});
//#endregion
//#region src/parslets/ObjectParslet.ts
function createObjectParslet({ signatureGrammar, objectFieldGrammar, allowKeyTypes }) {
	return composeParslet({
		name: "objectParslet",
		accept: (type) => type === "{",
		parsePrefix: (parser) => {
			parser.consume("{");
			const result = {
				type: "JsdocTypeObject",
				meta: { separator: "comma" },
				elements: []
			};
			if (!parser.consume("}")) {
				let separator;
				const fieldParser = new Parser(objectFieldGrammar, parser.lexer, parser, parser.externalParsers?.computedPropertyParser !== void 0 ? { externalParsers: { computedPropertyParser: parser.externalParsers.computedPropertyParser } } : void 0);
				while (true) {
					fieldParser.acceptLexerState(parser);
					let field = fieldParser.parseIntermediateType(2);
					parser.acceptLexerState(fieldParser);
					if (field === void 0 && allowKeyTypes) field = parser.parseIntermediateType(2);
					let optional = false;
					if (field.type === "JsdocTypeNullable") {
						optional = true;
						field = field.element;
					}
					if (field.type === "JsdocTypeNumber" || field.type === "JsdocTypeName" || field.type === "JsdocTypeStringValue") {
						let quote;
						if (field.type === "JsdocTypeStringValue") quote = field.meta.quote;
						result.elements.push({
							type: "JsdocTypeObjectField",
							key: field.value.toString(),
							right: void 0,
							optional,
							readonly: false,
							meta: { quote }
						});
					} else if (signatureGrammar !== void 0 && (field.type === "JsdocTypeCallSignature" || field.type === "JsdocTypeConstructorSignature" || field.type === "JsdocTypeMethodSignature")) {
						const signatureParser = new Parser([...signatureGrammar, ...parser.grammar.flatMap((grammar) => {
							if (grammar.name === "keyValueParslet") return [];
							return [grammar];
						})], parser.lexer, parser);
						signatureParser.acceptLexerState(parser);
						const params = signatureParser.parseIntermediateType(2);
						parser.acceptLexerState(signatureParser);
						field.parameters = getParameters(params);
						const returnType = parser.parseType(2);
						field.returnType = returnType;
						result.elements.push(field);
					} else if (field.type === "JsdocTypeObjectField" || field.type === "JsdocTypeJsdocObjectField") result.elements.push(field);
					else if (field.type === "JsdocTypeReadonlyProperty" && field.element.type === "JsdocTypeObjectField") {
						if (typeof field.element.key === "object" && field.element.key.type === "JsdocTypeComputedMethod") throw new Error("Computed method may not be readonly");
						field.element.readonly = true;
						result.elements.push(field.element);
					} else throw new UnexpectedTypeError(field);
					if (parser.lexer.current.startOfLine) {
						separator ??= "linebreak";
						parser.consume(",") || parser.consume(";");
					} else if (parser.consume(",")) {
						if (parser.lexer.current.startOfLine) separator = "comma-and-linebreak";
						else separator = "comma";
					} else if (parser.consume(";")) {
						if (parser.lexer.current.startOfLine) separator = "semicolon-and-linebreak";
						else separator = "semicolon";
					} else break;
					if (parser.lexer.current.type === "}") break;
				}
				result.meta.separator = separator ?? "comma";
				if ((separator ?? "").endsWith("linebreak")) result.meta.propertyIndent = "  ";
				if (!parser.consume("}")) throw new Error("Unterminated record type. Missing '}'");
			}
			return result;
		}
	});
}
//#endregion
//#region src/parslets/ObjectFieldParslet.ts
function createObjectFieldParslet({ allowSquaredProperties, allowKeyTypes, allowReadonly, allowOptional }) {
	return composeParslet({
		name: "objectFieldParslet",
		precedence: 3,
		accept: (type) => type === ":",
		parseInfix: (parser, left) => {
			let optional = false;
			let readonlyProperty = false;
			if (allowOptional && left.type === "JsdocTypeNullable") {
				optional = true;
				left = left.element;
			}
			if (allowReadonly && left.type === "JsdocTypeReadonlyProperty") {
				readonlyProperty = true;
				left = left.element;
			}
			if (left.type === "JsdocTypeBigInt") throw new UnexpectedTypeError(left);
			/* c8 ignore next 2 -- Always has base parser? */
			const parentParser = parser.baseParser ?? parser;
			parentParser.acceptLexerState(parser);
			if (left.type === "JsdocTypeNumber" || left.type === "JsdocTypeName" || left.type === "JsdocTypeStringValue" || isSquaredProperty(left)) {
				/* c8 ignore next 3 -- Guard */
				if (isSquaredProperty(left) && !allowSquaredProperties) throw new UnexpectedTypeError(left);
				parentParser.consume(":");
				let quote;
				if (left.type === "JsdocTypeStringValue") quote = left.meta.quote;
				const right = parentParser.parseType(3);
				parser.acceptLexerState(parentParser);
				return {
					type: "JsdocTypeObjectField",
					/* c8 ignore next -- Guard; not needed anymore? */
					key: isSquaredProperty(left) ? left : left.value.toString(),
					right,
					optional,
					readonly: readonlyProperty,
					meta: { quote }
				};
			} else {
				if (!allowKeyTypes) throw new UnexpectedTypeError(left);
				parentParser.consume(":");
				const right = parentParser.parseType(3);
				parser.acceptLexerState(parentParser);
				return {
					type: "JsdocTypeJsdocObjectField",
					left: assertRootResult(left),
					right
				};
			}
		}
	});
}
//#endregion
//#region src/parslets/KeyValueParslet.ts
function createKeyValueParslet({ allowOptional, allowVariadic, acceptParameterList }) {
	return composeParslet({
		name: "keyValueParslet",
		precedence: 3,
		accept: (type) => type === ":",
		parseInfix: (parser, left) => {
			let optional = false;
			let variadic = false;
			if (allowOptional && left.type === "JsdocTypeNullable") {
				optional = true;
				left = left.element;
			}
			if (allowVariadic && left.type === "JsdocTypeVariadic" && left.element !== void 0) {
				variadic = true;
				left = left.element;
			}
			if (left.type !== "JsdocTypeName") {
				if (acceptParameterList !== void 0 && left.type === "JsdocTypeParameterList") {
					parser.consume(":");
					return left;
				}
				throw new UnexpectedTypeError(left);
			}
			parser.consume(":");
			const right = parser.parseType(3);
			return {
				type: "JsdocTypeKeyValue",
				key: left.value,
				right,
				optional,
				variadic
			};
		}
	});
}
//#endregion
//#region src/grammars/jsdocGrammar.ts
const jsdocBaseGrammar = [
	...baseGrammar,
	createFunctionParslet({
		allowWithoutParenthesis: true,
		allowNamedParameters: ["this", "new"],
		allowNoReturnType: true,
		allowNewAsFunctionKeyword: false
	}),
	stringValueParslet,
	createSpecialNamePathParslet({
		allowedTypes: [
			"module",
			"external",
			"event"
		],
		pathGrammar
	}),
	createVariadicParslet({
		allowEnclosingBrackets: true,
		allowPostfix: true
	}),
	createNameParslet({ allowedAdditionalTokens: ["keyof"] }),
	symbolParslet,
	arrayBracketsParslet,
	createNamePathParslet({
		allowSquareBracketsOnAnyType: false,
		allowJsdocNamePaths: true,
		pathGrammar
	})
];
const jsdocGrammar = [
	...jsdocBaseGrammar,
	createObjectParslet({
		objectFieldGrammar: [
			createNameParslet({ allowedAdditionalTokens: [
				"typeof",
				"module",
				"in"
			] }),
			createObjectFieldParslet({
				allowSquaredProperties: false,
				allowKeyTypes: true,
				allowOptional: false,
				allowReadonly: false
			}),
			...jsdocBaseGrammar
		],
		allowKeyTypes: true
	}),
	createKeyValueParslet({
		allowOptional: true,
		allowVariadic: true
	})
];
const jsdocNameGrammar = [
	genericParslet,
	arrayBracketsParslet,
	createNameParslet({ allowedAdditionalTokens: baseNameTokens })
];
const jsdocNamePathGrammar = [
	genericParslet,
	arrayBracketsParslet,
	createNameParslet({ allowedAdditionalTokens: baseNameTokens }),
	createNamePathParslet({
		allowSquareBracketsOnAnyType: false,
		allowJsdocNamePaths: true,
		pathGrammar
	})
];
const jsdocNamePathSpecialGrammar = [createSpecialNamePathParslet({
	allowedTypes: [
		"module",
		"external",
		"event"
	],
	pathGrammar
}), ...jsdocNamePathGrammar];
//#endregion
//#region src/parslets/TypeOfParslet.ts
const typeOfParslet = composeParslet({
	name: "typeOfParslet",
	accept: (type) => type === "typeof",
	parsePrefix: (parser) => {
		parser.consume("typeof");
		return {
			type: "JsdocTypeTypeof",
			element: parser.parseType(13)
		};
	}
});
//#endregion
//#region src/grammars/closureGrammar.ts
const objectFieldGrammar$1 = [
	createNameParslet({ allowedAdditionalTokens: [
		"typeof",
		"module",
		"keyof",
		"event",
		"external",
		"in"
	] }),
	nullableParslet,
	optionalParslet,
	stringValueParslet,
	numberParslet,
	createObjectFieldParslet({
		allowSquaredProperties: false,
		allowKeyTypes: false,
		allowOptional: false,
		allowReadonly: false
	})
];
const closureGrammar = [
	...baseGrammar,
	createObjectParslet({
		allowKeyTypes: false,
		objectFieldGrammar: objectFieldGrammar$1
	}),
	createNameParslet({ allowedAdditionalTokens: [
		"event",
		"external",
		"in"
	] }),
	typeOfParslet,
	createFunctionParslet({
		allowWithoutParenthesis: false,
		allowNamedParameters: ["this", "new"],
		allowNoReturnType: true,
		allowNewAsFunctionKeyword: false
	}),
	createVariadicParslet({
		allowEnclosingBrackets: false,
		allowPostfix: false
	}),
	createNameParslet({ allowedAdditionalTokens: ["keyof"] }),
	createSpecialNamePathParslet({
		allowedTypes: ["module"],
		pathGrammar
	}),
	createNamePathParslet({
		allowSquareBracketsOnAnyType: false,
		allowJsdocNamePaths: true,
		pathGrammar
	}),
	createKeyValueParslet({
		allowOptional: false,
		allowVariadic: false
	}),
	symbolParslet
];
const closureNameGrammar = [
	genericParslet,
	arrayBracketsParslet,
	createNameParslet({ allowedAdditionalTokens: baseNameTokens })
];
const closureNamePathGrammar = [
	genericParslet,
	arrayBracketsParslet,
	createNameParslet({ allowedAdditionalTokens: baseNameTokens }),
	createNamePathParslet({
		allowSquareBracketsOnAnyType: false,
		allowJsdocNamePaths: true,
		pathGrammar
	})
];
const closureNamePathSpecialGrammar = [createSpecialNamePathParslet({
	allowedTypes: ["module"],
	pathGrammar
}), ...closureNamePathGrammar];
//#endregion
//#region src/parslets/assertsParslet.ts
const assertsParslet = composeParslet({
	name: "assertsParslet",
	accept: (type) => type === "asserts",
	parsePrefix: (parser) => {
		parser.consume("asserts");
		const left = parser.parseIntermediateType(10);
		if (left.type !== "JsdocTypeName") throw new UnexpectedTypeError(left, "A typescript asserts always has to have a name.");
		if (!parser.consume("is")) return {
			type: "JsdocTypeAssertsPlain",
			element: left
		};
		return {
			type: "JsdocTypeAsserts",
			left,
			right: assertRootResult(parser.parseIntermediateType(8))
		};
	}
});
//#endregion
//#region src/parslets/FunctionPropertyParslet.ts
const functionPropertyParslet = composeParslet({
	name: "functionPropertyParslet",
	accept: (type, next) => type === "new" && (next === "(" || next === "<") || type === "Identifier" && (next === "(" || next === "<") || type === "StringValue" && (next === "(" || next === "<") || type === "(" || type === "<",
	parsePrefix: (parser) => {
		let result;
		const returnType = {
			type: "JsdocTypeName",
			value: "void"
		};
		if (parser.consume("new")) result = {
			type: "JsdocTypeConstructorSignature",
			parameters: [],
			returnType
		};
		else {
			const text = parser.lexer.current.text;
			if (parser.consume("Identifier")) result = {
				type: "JsdocTypeMethodSignature",
				name: text,
				meta: { quote: void 0 },
				parameters: [],
				returnType
			};
			else {
				const text = parser.lexer.current.text;
				if (parser.consume("StringValue")) result = {
					type: "JsdocTypeMethodSignature",
					name: text.slice(1, -1),
					meta: { quote: text.startsWith("\"") ? "double" : "single" },
					parameters: [],
					returnType
				};
				else result = {
					type: "JsdocTypeCallSignature",
					parameters: [],
					returnType
				};
			}
		}
		const typeParameters = [];
		if (parser.consume("<")) {
			do {
				let defaultValue = void 0;
				let name = parser.parseIntermediateType(10);
				if (name.type === "JsdocTypeOptional") {
					name = name.element;
					defaultValue = parser.parseType(10);
				}
				if (name.type !== "JsdocTypeName") throw new UnexpectedTypeError(name);
				let constraint = void 0;
				if (parser.consume("extends")) {
					constraint = parser.parseType(10);
					if (constraint.type === "JsdocTypeOptional") {
						constraint = constraint.element;
						defaultValue = parser.parseType(10);
					}
				}
				const typeParameter = {
					type: "JsdocTypeTypeParameter",
					name
				};
				if (constraint !== void 0) typeParameter.constraint = constraint;
				if (defaultValue !== void 0) typeParameter.defaultValue = defaultValue;
				typeParameters.push(typeParameter);
				if (parser.consume(">")) break;
			} while (parser.consume(","));
			result.typeParameters = typeParameters;
		}
		/* c8 ignore next 3 -- Unreachable */
		if (!(parser.lexer.current.type === "(")) throw new Error("function property is missing parameter list");
		return result;
	}
});
//#endregion
//#region src/parslets/TupleParslet.ts
function createTupleParslet({ allowQuestionMark }) {
	return composeParslet({
		name: "tupleParslet",
		accept: (type) => type === "[",
		parsePrefix: (parser) => {
			parser.consume("[");
			const result = {
				type: "JsdocTypeTuple",
				elements: []
			};
			if (parser.consume("]")) return result;
			const typeList = parser.parseIntermediateType(0);
			if (typeList.type === "JsdocTypeParameterList") {
				if (typeList.elements[0].type === "JsdocTypeKeyValue") result.elements = typeList.elements.map(assertPlainKeyValueResult);
				else result.elements = typeList.elements.map(assertRootResult);
			} else if (typeList.type === "JsdocTypeKeyValue") result.elements = [assertPlainKeyValueResult(typeList)];
			else result.elements = [assertRootResult(typeList)];
			if (!parser.consume("]")) throw new Error("Unterminated '['");
			if (!allowQuestionMark && result.elements.some((e) => e.type === "JsdocTypeUnknown")) throw new Error("Question mark in tuple not allowed");
			return result;
		}
	});
}
//#endregion
//#region src/parslets/KeyOfParslet.ts
const keyOfParslet = composeParslet({
	name: "keyOfParslet",
	accept: (type) => type === "keyof",
	parsePrefix: (parser) => {
		parser.consume("keyof");
		return {
			type: "JsdocTypeKeyof",
			element: assertRootResult(parser.parseType(13))
		};
	}
});
//#endregion
//#region src/parslets/InferParslet.ts
const inferParslet = composeParslet({
	name: "inferParslet",
	accept: (type) => type === "infer",
	parsePrefix: (parser) => {
		parser.consume("infer");
		const element = parser.parseIntermediateType(12);
		/* c8 ignore next 3 -- c8 does not mark the exercised throw as covered */
		if (element.type !== "JsdocTypeName") throw new UnexpectedTypeError(element, "A typescript infer always has to have a name.");
		return {
			type: "JsdocTypeInfer",
			element
		};
	}
});
//#endregion
//#region src/parslets/ImportParslet.ts
const importParslet = composeParslet({
	name: "importParslet",
	accept: (type) => type === "import",
	parsePrefix: (parser) => {
		parser.consume("import");
		if (!parser.consume("(")) throw new Error("Missing parenthesis after import keyword");
		const path = parser.parseType(7);
		if (path.type !== "JsdocTypeStringValue") throw new Error("Only string values are allowed as paths for imports");
		if (!parser.consume(")")) throw new Error("Missing closing parenthesis after import keyword");
		return {
			type: "JsdocTypeImport",
			element: path
		};
	}
});
//#endregion
//#region src/parslets/ReadonlyPropertyParslet.ts
const readonlyPropertyParslet = composeParslet({
	name: "readonlyPropertyParslet",
	accept: (type, next) => type === "readonly" && next !== ":" && next !== "?",
	parsePrefix: (parser) => {
		parser.consume("readonly");
		return {
			type: "JsdocTypeReadonlyProperty",
			element: parser.parseIntermediateType(3)
		};
	}
});
//#endregion
//#region src/parslets/ArrowFunctionParslet.ts
const arrowFunctionParslet = composeParslet({
	name: "arrowFunctionParslet",
	precedence: 15,
	accept: (type) => type === "=>",
	parseInfix: (parser, left) => {
		parser.consume("=>");
		return {
			type: "JsdocTypeFunction",
			parameters: getParameters(left).map(assertPlainKeyValueOrNameResult),
			arrow: true,
			constructor: false,
			parenthesis: true,
			returnType: parser.parseType(2)
		};
	}
});
//#endregion
//#region src/parslets/GenericArrowFunctionParslet.ts
const genericArrowFunctionParslet = composeParslet({
	name: "genericArrowFunctionParslet",
	accept: (type) => type === "<",
	parsePrefix: (parser) => {
		const typeParameters = [];
		parser.consume("<");
		do {
			let defaultValue = void 0;
			let name = parser.parseIntermediateType(10);
			if (name.type === "JsdocTypeOptional") {
				name = name.element;
				defaultValue = parser.parseType(10);
			}
			if (name.type !== "JsdocTypeName") throw new UnexpectedTypeError(name);
			let constraint = void 0;
			if (parser.consume("extends")) {
				constraint = parser.parseType(10);
				if (constraint.type === "JsdocTypeOptional") {
					constraint = constraint.element;
					defaultValue = parser.parseType(10);
				}
			}
			const typeParameter = {
				type: "JsdocTypeTypeParameter",
				name
			};
			if (constraint !== void 0) typeParameter.constraint = constraint;
			if (defaultValue !== void 0) typeParameter.defaultValue = defaultValue;
			typeParameters.push(typeParameter);
			if (parser.consume(">")) break;
		} while (parser.consume(","));
		const functionBase = parser.parseIntermediateType(10);
		functionBase.typeParameters = typeParameters;
		return functionBase;
	}
});
//#endregion
//#region src/parslets/IntersectionParslet.ts
const intersectionParslet = composeParslet({
	name: "intersectionParslet",
	accept: (type) => type === "&",
	precedence: 6,
	parseInfix: (parser, left) => {
		parser.consume("&");
		const elements = [];
		do
			elements.push(parser.parseType(6));
		while (parser.consume("&"));
		return {
			type: "JsdocTypeIntersection",
			elements: [assertResultIsNotReservedWord(parser, assertRootResult(left)), ...elements.map((element) => assertResultIsNotReservedWord(parser, element))]
		};
	}
});
//#endregion
//#region src/parslets/predicateParslet.ts
const predicateParslet = composeParslet({
	name: "predicateParslet",
	precedence: 8,
	accept: (type) => type === "is",
	parseInfix: (parser, left) => {
		if (left.type !== "JsdocTypeName") throw new UnexpectedTypeError(left, "A typescript predicate always has to have a name on the left side.");
		parser.consume("is");
		return {
			type: "JsdocTypePredicate",
			left,
			right: assertRootResult(parser.parseIntermediateType(8))
		};
	}
});
//#endregion
//#region src/lexer/Lexer.ts
const breakingWhitespaceRegex = /^\s*\n\s*/v;
var Lexer = class Lexer {
	text = "";
	lexerRules;
	current;
	next;
	previous;
	static create(lexerRules, text) {
		const current = this.read(lexerRules, text);
		text = current.text;
		const next = this.read(lexerRules, text);
		text = next.text;
		return new Lexer(lexerRules, text, void 0, current.token, next.token);
	}
	constructor(lexerRules, text, previous, current, next) {
		this.lexerRules = lexerRules;
		this.text = text;
		this.previous = previous;
		this.current = current;
		this.next = next;
	}
	static read(lexerRules, text, startOfLine = false) {
		startOfLine ||= breakingWhitespaceRegex.test(text);
		const start = text.length;
		const initialWhitespace = /^\s+/v.exec(text)?.[0] ?? "";
		text = text.trimStart();
		const trimmed = start - text.length;
		for (const rule of lexerRules) {
			const partial = rule(text);
			if (partial !== null) {
				const initialLines = initialWhitespace.split("\n");
				const currentLines = partial.text.split("\n");
				const token = {
					...partial,
					startOfLine,
					reduced: trimmed + partial.text.length,
					line: initialLines.length + currentLines.length - 2,
					column: currentLines.length === 1 ? (initialLines.at(-1)?.length ?? 0) + (currentLines.at(-1)?.length ?? 0) : currentLines.at(-1)?.length ?? 0
				};
				text = text.slice(token.text.length);
				return {
					text,
					token
				};
			}
		}
		throw new Error(`Unexpected Token ${text}`);
	}
	remaining() {
		return this.next.text + this.text;
	}
	advance() {
		const next = Lexer.read(this.lexerRules, this.text);
		return new Lexer(this.lexerRules, next.text, this.current, this.next, next.token);
	}
};
//#endregion
//#region src/parslets/ObjectSquaredPropertyParslet.ts
const objectSquaredPropertyParslet = composeParslet({
	name: "objectSquarePropertyParslet",
	accept: (type) => type === "[",
	parsePrefix: (parser) => {
		if (parser.baseParser === void 0) throw new Error("Only allowed inside object grammar");
		parser.consume("[");
		let innerBracketType;
		if (parser.externalParsers?.computedPropertyParser === void 0) try {
			innerBracketType = parser.parseIntermediateType(2);
		} catch (err) {
			throw new Error("Error parsing value inside square bracketed property.", { cause: err });
		}
		let result;
		if (innerBracketType?.type === "JsdocTypeObjectField" && typeof innerBracketType.key === "string" && !innerBracketType.optional && !innerBracketType.readonly && innerBracketType.right !== void 0) {
			const key = innerBracketType.key;
			if (!parser.consume("]")) throw new Error("Unterminated square brackets");
			if (!parser.consume(":")) throw new Error("Incomplete index signature");
			const parentParser = parser.baseParser;
			parentParser.acceptLexerState(parser);
			innerBracketType.key = {
				type: "JsdocTypeIndexSignature",
				key,
				right: innerBracketType.right
			};
			innerBracketType.optional = false;
			innerBracketType.meta.quote = void 0;
			result = innerBracketType;
			const right = parentParser.parseType(4);
			result.right = right;
			parser.acceptLexerState(parentParser);
		} else if (innerBracketType?.type === "JsdocTypeName" && parser.consume("in")) {
			const parentParser = parser.baseParser;
			parentParser.acceptLexerState(parser);
			const mappedTypeRight = parentParser.parseType(4);
			if (!parentParser.consume("]")) throw new Error("Unterminated square brackets");
			const optional = parentParser.consume("?");
			if (!parentParser.consume(":")) throw new Error("Incomplete mapped type clause: missing colon");
			const right = parentParser.parseType(4);
			result = {
				type: "JsdocTypeObjectField",
				optional,
				readonly: false,
				meta: { quote: void 0 },
				key: {
					type: "JsdocTypeMappedType",
					key: innerBracketType.value,
					right: mappedTypeRight
				},
				right
			};
			parser.acceptLexerState(parentParser);
		} else {
			if (parser.externalParsers?.computedPropertyParser !== void 0) {
				let remaining = parser.lexer.current.text + parser.lexer.remaining();
				let checkingText = remaining;
				while (checkingText !== "") {
					try {
						innerBracketType = parser.externalParsers.computedPropertyParser(checkingText);
						break;
					} catch (err) {}
					checkingText = checkingText.slice(0, -1);
				}
				remaining = remaining.slice(checkingText.length);
				const remainingTextParser = new Parser(parser.grammar, Lexer.create(parser.lexer.lexerRules, remaining), parser.baseParser, { externalParsers: { computedPropertyParser: parser.externalParsers.computedPropertyParser } });
				parser.acceptLexerState(remainingTextParser);
			}
			if (!parser.consume("]")) throw new Error("Unterminated square brackets");
			let optional = parser.consume("?");
			const typeParameters = [];
			if (parser.consume("<")) do {
				let defaultValue = void 0;
				let name = parser.parseIntermediateType(10);
				if (name.type === "JsdocTypeOptional") {
					name = name.element;
					defaultValue = parser.parseType(10);
				}
				if (name.type !== "JsdocTypeName") throw new UnexpectedTypeError(name);
				let constraint = void 0;
				if (parser.consume("extends")) {
					constraint = parser.parseType(10);
					if (constraint.type === "JsdocTypeOptional") {
						constraint = constraint.element;
						defaultValue = parser.parseType(10);
					}
				}
				const typeParameter = {
					type: "JsdocTypeTypeParameter",
					name
				};
				if (constraint !== void 0) typeParameter.constraint = constraint;
				if (defaultValue !== void 0) typeParameter.defaultValue = defaultValue;
				typeParameters.push(typeParameter);
				if (parser.consume(">")) break;
			} while (parser.consume(","));
			let type;
			let key;
			const checkMiddle = () => {
				if (!optional) optional = parser.consume("?");
			};
			let right;
			if (parser.lexer.current.type === "(") {
				const signatureParser = new Parser([createKeyValueParslet({
					allowVariadic: true,
					allowOptional: true,
					acceptParameterList: true
				}), ...parser.baseParser.grammar.flatMap((grammar) => {
					if (grammar.name === "keyValueParslet") return [];
					return [grammar];
				})], parser.lexer, parser);
				signatureParser.acceptLexerState(parser);
				const params = signatureParser.parseIntermediateType(2);
				parser.acceptLexerState(signatureParser);
				const parameters = getParameters(params);
				type = "JsdocTypeComputedMethod";
				checkMiddle();
				parser.consume(":");
				const nextValue = parser.parseType(4);
				key = {
					type,
					optional,
					value: innerBracketType,
					parameters,
					returnType: nextValue
				};
				if (typeParameters.length > 0) key.typeParameters = typeParameters;
			} else {
				type = "JsdocTypeComputedProperty";
				checkMiddle();
				if (!parser.consume(":")) throw new Error("Incomplete computed property: missing colon");
				right = parser.parseType(4);
				key = {
					type,
					value: innerBracketType
				};
			}
			result = {
				type: "JsdocTypeObjectField",
				optional: type === "JsdocTypeComputedMethod" ? false : optional,
				readonly: false,
				meta: { quote: void 0 },
				key,
				right
			};
		}
		return result;
	}
});
//#endregion
//#region src/parslets/ReadonlyArrayParslet.ts
const readonlyArrayParslet = composeParslet({
	name: "readonlyArrayParslet",
	accept: (type) => type === "readonly",
	parsePrefix: (parser) => {
		parser.consume("readonly");
		return {
			type: "JsdocTypeReadonlyArray",
			element: assertArrayOrTupleResult(parser.parseIntermediateType(0))
		};
	}
});
//#endregion
//#region src/parslets/ConditionalParslet.ts
const conditionalParslet = composeParslet({
	name: "conditionalParslet",
	precedence: 8,
	accept: (type) => type === "extends",
	parseInfix: (parser, left) => {
		parser.consume("extends");
		const extendsType = assertRootResult(parser.parseType(13));
		parser.consume("?");
		const trueType = parser.parseType(3);
		parser.consume(":");
		return {
			type: "JsdocTypeConditional",
			checksType: assertRootResult(left),
			extendsType,
			trueType,
			falseType: parser.parseType(8)
		};
	}
});
//#endregion
//#region src/lexer/LexerRules.ts
function makePunctuationRule(type) {
	return (text) => {
		if (text.startsWith(type)) return {
			type,
			text: type
		};
		else return null;
	};
}
function getQuoted(text) {
	let position = 0;
	let char = void 0;
	const mark = text[0];
	let escaped = false;
	if (mark !== "'" && mark !== "\"") return null;
	while (position < text.length) {
		position++;
		char = text[position];
		if (!escaped && char === mark) {
			position++;
			break;
		}
		escaped = !escaped && char === "\\";
	}
	if (char !== mark) throw new Error("Unterminated String");
	return text.slice(0, position);
}
/**
* Gets a full template literal (enclosed in backticks)
*/
function getTemplateLiteral(text) {
	let position = 0;
	let char = void 0;
	const mark = text[0];
	let escaped = false;
	if (mark !== "`") return null;
	while (position < text.length) {
		position++;
		char = text[position];
		if (!escaped && char === mark) {
			position++;
			break;
		}
		escaped = !escaped && char === "\\";
	}
	if (char !== mark) throw new Error("Unterminated template literal");
	return text.slice(0, position);
}
/**
* Gets the next literal (non-interpolation) portion of a text
*/
function getTemplateLiteralLiteral(text) {
	let position = 0;
	const start = text[0];
	let escaped = false;
	if (start === "`" || start === "$" && text[1] === "{") return null;
	while (position < text.length) {
		position++;
		const char = text[position];
		if (!escaped && (char === "`" || char === "$" && text[position + 1] === "{")) break;
		escaped = !escaped && char === "\\";
	}
	return text.slice(0, position);
}
const identifierStartRegex = /[$_\p{ID_Start}]|\\u\p{Hex_Digit}{4}|\\u\{0*(?:\p{Hex_Digit}{1,5}|10\p{Hex_Digit}{4})\}/v;
const identifierContinueRegex = /[$\p{ID_Continue}\u200C\u200D]|\\u\p{Hex_Digit}{4}|\\u\{0*(?:\p{Hex_Digit}{1,5}|10\p{Hex_Digit}{4})\}/v;
const identifierContinueRegexLoose = /[$\-\p{ID_Continue}\u200C\u200D]|\\u\p{Hex_Digit}{4}|\\u\{0*(?:\p{Hex_Digit}{1,5}|10\p{Hex_Digit}{4})\}/v;
function makeGetIdentifier(identifierContinueRegex) {
	return function(text) {
		let char = text[0];
		if (!identifierStartRegex.test(char)) return null;
		let position = 1;
		do {
			char = text[position];
			if (!identifierContinueRegex.test(char)) break;
			position++;
		} while (position < text.length);
		return text.slice(0, position);
	};
}
const bigintRegex = /^(?:-?\d+n)/v;
const numberRegex = /^(?:-?(?:(?:\d*\.\d+|\d+)(?:[Ee][+\-]?\d+)?))/v;
const looseNumberRegex = /^(?:NaN|-?(?:(?:\d*\.\d+|\d+)(?:[Ee][+\-]?\d+)?|Infinity))/v;
function getGetNumber(numberRegex) {
	return function getNumber(text) {
		return numberRegex.exec(text)?.[0] ?? null;
	};
}
const looseIdentifierRule = (text) => {
	const value = makeGetIdentifier(identifierContinueRegexLoose)(text);
	if (value === null) return null;
	return {
		type: "Identifier",
		text: value
	};
};
const identifierRule = (text) => {
	const value = makeGetIdentifier(identifierContinueRegex)(text);
	if (value === null) return null;
	return {
		type: "Identifier",
		text: value
	};
};
function makeKeyWordRule(type) {
	return (text) => {
		if (!text.startsWith(type)) return null;
		const prepends = text[type.length];
		if (prepends !== void 0 && identifierContinueRegex.test(prepends)) return null;
		return {
			type,
			text: type
		};
	};
}
const stringValueRule = (text) => {
	const value = getQuoted(text);
	if (value === null) return null;
	return {
		type: "StringValue",
		text: value
	};
};
const templateLiteralRule = (text) => {
	const value = getTemplateLiteral(text);
	if (value === null) return null;
	return {
		type: "TemplateLiteral",
		text: value
	};
};
const eofRule = (text) => {
	if (text.length > 0) return null;
	return {
		type: "EOF",
		text: ""
	};
};
const numberRule = (text) => {
	const bigintValue = bigintRegex.exec(text)?.[0];
	if (bigintValue !== void 0) return {
		type: "Number",
		text: bigintValue
	};
	const value = getGetNumber(numberRegex)(text);
	if (value === null) return null;
	return {
		type: "Number",
		text: value
	};
};
const looseNumberRule = (text) => {
	const bigintValue = bigintRegex.exec(text)?.[0];
	if (bigintValue !== void 0) return {
		type: "Number",
		text: bigintValue
	};
	const value = getGetNumber(looseNumberRegex)(text);
	if (value === null) return null;
	return {
		type: "Number",
		text: value
	};
};
/**
* Will be processed highest precedence first
*/
const rules = [
	eofRule,
	makePunctuationRule("=>"),
	makePunctuationRule("("),
	makePunctuationRule(")"),
	makePunctuationRule("{"),
	makePunctuationRule("}"),
	makePunctuationRule("["),
	makePunctuationRule("]"),
	makePunctuationRule("|"),
	makePunctuationRule("&"),
	makePunctuationRule("<"),
	makePunctuationRule(">"),
	makePunctuationRule(","),
	makePunctuationRule(";"),
	makePunctuationRule("*"),
	makePunctuationRule("?"),
	makePunctuationRule("!"),
	makePunctuationRule("="),
	makePunctuationRule(":"),
	makePunctuationRule("..."),
	makePunctuationRule("."),
	makePunctuationRule("#"),
	makePunctuationRule("~"),
	makePunctuationRule("/"),
	makePunctuationRule("@"),
	makeKeyWordRule("undefined"),
	makeKeyWordRule("null"),
	makeKeyWordRule("function"),
	makeKeyWordRule("this"),
	makeKeyWordRule("new"),
	makeKeyWordRule("module"),
	makeKeyWordRule("event"),
	makeKeyWordRule("extends"),
	makeKeyWordRule("external"),
	makeKeyWordRule("infer"),
	makeKeyWordRule("typeof"),
	makeKeyWordRule("keyof"),
	makeKeyWordRule("readonly"),
	makeKeyWordRule("import"),
	makeKeyWordRule("is"),
	makeKeyWordRule("in"),
	makeKeyWordRule("asserts"),
	numberRule,
	identifierRule,
	stringValueRule,
	templateLiteralRule
];
const looseRules = rules.toSpliced(-4, 2, looseNumberRule, looseIdentifierRule);
//#endregion
//#region src/parslets/TemplateLiteralParslet.ts
const templateLiteralParslet = composeParslet({
	name: "templateLiteralParslet",
	accept: (type) => type === "TemplateLiteral",
	parsePrefix: (parser) => {
		const text = parser.lexer.current.text;
		parser.consume("TemplateLiteral");
		const literals = [];
		const interpolations = [];
		let currentText = text.slice(1, -1);
		const advanceLiteral = () => {
			const literal = getTemplateLiteralLiteral(currentText) ?? "";
			literals.push(literal.replace(/\\`/gv, "`"));
			currentText = currentText.slice(literal.length);
		};
		advanceLiteral();
		while (true) {
			if (currentText.startsWith("${")) {
				currentText = currentText.slice(2);
				let templateParser;
				let interpolationType;
				let snipped = currentText;
				let remnant = "";
				while (true) try {
					templateParser = new Parser(parser.grammar, Lexer.create(parser.lexer.lexerRules, snipped));
					interpolationType = templateParser.parseType(0);
					break;
				} catch (err) {
					remnant = snipped.slice(-1) + remnant;
					snipped = snipped.slice(0, -1);
				}
				interpolations.push(interpolationType);
				if (templateParser.lexer.current.text !== "}") throw new Error("unterminated interpolation");
				currentText = templateParser.lexer.remaining() + remnant;
			} else break;
			advanceLiteral();
		}
		return {
			type: "JsdocTypeTemplateLiteral",
			literals,
			interpolations
		};
	}
});
//#endregion
//#region src/parslets/UniqueSymbolParslet.ts
const uniqueSymbolParslet = (parser, _precedence, left) => {
	if (left !== null) return null;
	if (parser.lexer.current.type !== "Identifier" || parser.lexer.current.text !== "unique" || parser.lexer.next.type !== "Identifier" || parser.lexer.next.text !== "symbol") return null;
	parser.consume("Identifier");
	parser.consume("Identifier");
	return { type: "JsdocTypeUniqueSymbol" };
};
//#endregion
//#region src/grammars/typescriptGrammar.ts
const objectFieldGrammar = [
	functionPropertyParslet,
	readonlyPropertyParslet,
	createNameParslet({ allowedAdditionalTokens: baseNameTokens }),
	nullableParslet,
	optionalParslet,
	stringValueParslet,
	numberParslet,
	createObjectFieldParslet({
		allowSquaredProperties: true,
		allowKeyTypes: false,
		allowOptional: true,
		allowReadonly: true
	}),
	objectSquaredPropertyParslet
];
const typescriptGrammar = [
	...baseGrammar,
	createObjectParslet({
		allowKeyTypes: false,
		objectFieldGrammar,
		signatureGrammar: [createKeyValueParslet({
			allowVariadic: true,
			allowOptional: true,
			acceptParameterList: true
		})]
	}),
	readonlyArrayParslet,
	typeOfParslet,
	keyOfParslet,
	inferParslet,
	importParslet,
	stringValueParslet,
	createFunctionParslet({
		allowWithoutParenthesis: true,
		allowNoReturnType: true,
		allowNamedParameters: [
			"this",
			"new",
			"args"
		],
		allowNewAsFunctionKeyword: true
	}),
	createTupleParslet({ allowQuestionMark: false }),
	createVariadicParslet({
		allowEnclosingBrackets: false,
		allowPostfix: false
	}),
	assertsParslet,
	conditionalParslet,
	uniqueSymbolParslet,
	createNameParslet({ allowedAdditionalTokens: [
		"event",
		"external",
		"in"
	] }),
	createSpecialNamePathParslet({
		allowedTypes: ["module"],
		pathGrammar
	}),
	arrayBracketsParslet,
	arrowFunctionParslet,
	genericArrowFunctionParslet,
	createNamePathParslet({
		allowSquareBracketsOnAnyType: true,
		allowJsdocNamePaths: false,
		pathGrammar
	}),
	intersectionParslet,
	predicateParslet,
	templateLiteralParslet,
	createKeyValueParslet({
		allowVariadic: true,
		allowOptional: true
	})
];
const typescriptNameGrammar = [
	genericParslet,
	arrayBracketsParslet,
	createNameParslet({ allowedAdditionalTokens: baseNameTokens })
];
const typescriptNamePathGrammar = [
	genericParslet,
	arrayBracketsParslet,
	createNameParslet({ allowedAdditionalTokens: baseNameTokens }),
	createNamePathParslet({
		allowSquareBracketsOnAnyType: true,
		allowJsdocNamePaths: true,
		pathGrammar
	})
];
const typescriptNamePathSpecialGrammar = [createSpecialNamePathParslet({
	allowedTypes: ["module"],
	pathGrammar
}), ...typescriptNamePathGrammar];
//#endregion
//#region src/parse.ts
/**
* This function parses the given expression in the given mode and produces a {@link RootResult}.
* @param expression
* @param mode
*/
function parse(expression, mode, { range = false, rangeStart, loc = false, locStart = {
	column: 0,
	line: 1
}, module = true, strictMode = true, asyncFunctionBody = true, classContext = false, computedPropertyParser } = {}) {
	let parser;
	switch (mode) {
		case "closure":
			parser = new Parser(closureGrammar, Lexer.create(looseRules, expression), void 0, {
				module,
				strictMode,
				asyncFunctionBody,
				classContext,
				range,
				rangeStart,
				loc,
				locStart
			});
			break;
		case "jsdoc":
			parser = new Parser(jsdocGrammar, Lexer.create(looseRules, expression), void 0, {
				module,
				strictMode,
				asyncFunctionBody,
				classContext,
				range,
				rangeStart,
				loc,
				locStart
			});
			break;
		case "typescript": parser = new Parser(typescriptGrammar, Lexer.create(rules, expression), void 0, {
			module,
			strictMode,
			asyncFunctionBody,
			classContext,
			range,
			rangeStart,
			loc,
			locStart,
			externalParsers: { computedPropertyParser }
		});
	}
	const result = parser.parse();
	return assertResultIsNotReservedWord(parser, result);
}
/**
* This function tries to parse the given expression in multiple modes and returns the first successful
* {@link RootResult}. By default it tries `'typescript'`, `'closure'` and `'jsdoc'` in this order. If
* no mode was successful it throws the error that was produced by the last parsing attempt.
* @param expression
* @param modes
*/
function tryParse(expression, modes = [
	"typescript",
	"closure",
	"jsdoc"
], { module = true, strictMode = true, asyncFunctionBody = true, classContext = false, computedPropertyParser, range, rangeStart, loc = false, locStart = {
	column: 0,
	line: 1
} } = {}) {
	let error;
	for (const mode of modes) try {
		return parse(expression, mode, {
			module,
			strictMode,
			asyncFunctionBody,
			classContext,
			computedPropertyParser,
			range,
			rangeStart,
			loc,
			locStart
		});
	} catch (e) {
		error = e;
	}
	throw error;
}
/**
* This function parses the given expression in the given mode and produces a name path.
* @param expression
* @param mode
*/
function parseNamePath(expression, mode, { includeSpecial = false } = {}) {
	switch (mode) {
		case "closure": return new Parser(includeSpecial ? closureNamePathSpecialGrammar : closureNamePathGrammar, Lexer.create(looseRules, expression)).parse();
		case "jsdoc": return new Parser(includeSpecial ? jsdocNamePathSpecialGrammar : jsdocNamePathGrammar, Lexer.create(looseRules, expression)).parse();
		case "typescript": return new Parser(includeSpecial ? typescriptNamePathSpecialGrammar : typescriptNamePathGrammar, Lexer.create(rules, expression)).parse();
	}
}
/**
* This function parses the given expression in the given mode and produces a name.
* @param expression
* @param mode
*/
function parseName(expression, mode) {
	switch (mode) {
		case "closure": return new Parser(closureNameGrammar, Lexer.create(looseRules, expression)).parse();
		case "jsdoc": return new Parser(jsdocNameGrammar, Lexer.create(looseRules, expression)).parse();
		case "typescript": return new Parser(typescriptNameGrammar, Lexer.create(rules, expression)).parse();
	}
}
//#endregion
//#region src/transforms/transform.ts
function transform(rules, parseResult) {
	const rule = rules[parseResult.type];
	if (rule === void 0) throw new Error(`In this set of transform rules exists no rule for type ${parseResult.type}.`);
	return rule(parseResult, (aParseResult) => transform(rules, aParseResult));
}
function notAvailableTransform(parseResult) {
	throw new Error("This transform is not available. Are you trying the correct parsing mode?");
}
function extractSpecialParams(source) {
	const result = { params: [] };
	for (const param of source.parameters) if (param.type === "JsdocTypeKeyValue") {
		if (param.key === "this") result.this = param.right;
		else if (param.key === "new") result.new = param.right;
		else result.params.push(param);
	} else result.params.push(param);
	return result;
}
//#endregion
//#region src/transforms/stringify.ts
function applyPosition(position, target, value) {
	return position === "prefix" ? value + target : target + value;
}
function quote(value, quote) {
	switch (quote) {
		case "double": return `"${value}"`;
		case "single": return `'${value}'`;
		case void 0: return value;
	}
}
function stringifyRules({ computedPropertyStringifier } = {}) {
	return {
		JsdocTypeParenthesis: (result, transform) => `(${result.element !== void 0 ? transform(result.element) : ""})`,
		JsdocTypeKeyof: (result, transform) => `keyof ${transform(result.element)}`,
		JsdocTypeFunction: (result, transform) => {
			if (!result.arrow) {
				let stringified = result.constructor ? "new" : "function";
				if (!result.parenthesis) return stringified;
				stringified += `(${result.parameters.map(transform).join(`,${result.meta?.parameterSpacing ?? " "}`)})`;
				if (result.returnType !== void 0) stringified += `${result.meta?.preReturnMarkerSpacing ?? ""}:${result.meta?.postReturnMarkerSpacing ?? " "}${transform(result.returnType)}`;
				return stringified;
			} else {
				if (result.returnType === void 0) throw new Error("Arrow function needs a return type.");
				let stringified = `${result.typeParameters !== void 0 ? `<${result.typeParameters.map(transform).join(`,${result.meta?.typeParameterSpacing ?? " "}`)}>${result.meta?.postGenericSpacing ?? ""}` : ""}(${result.parameters.map(transform).join(`,${result.meta?.parameterSpacing ?? " "}`)})${result.meta?.preReturnMarkerSpacing ?? " "}=>${result.meta?.postReturnMarkerSpacing ?? " "}${transform(result.returnType)}`;
				if (result.constructor) stringified = `new ${stringified}`;
				return stringified;
			}
		},
		JsdocTypeName: (result) => result.value,
		JsdocTypeInfer: (result, transform) => `infer ${transform(result.element)}`,
		JsdocTypeUniqueSymbol: () => "unique symbol",
		JsdocTypeTuple: (result, transform) => `[${result.elements.map(transform).join(`,${result.meta?.elementSpacing ?? " "}`)}]`,
		JsdocTypeVariadic: (result, transform) => result.meta.position === void 0 ? "..." : applyPosition(result.meta.position, transform(result.element), "..."),
		JsdocTypeNamePath: (result, transform) => {
			const left = transform(result.left);
			const right = transform(result.right);
			switch (result.pathType) {
				case "inner": return `${left}~${right}`;
				case "instance": return `${left}#${right}`;
				case "property": return `${left}.${right}`;
				case "property-brackets": return `${left}[${right}]`;
			}
		},
		JsdocTypeStringValue: (result) => quote(result.value, result.meta.quote),
		JsdocTypeAny: () => "*",
		JsdocTypeGeneric: (result, transform) => {
			if (result.meta.brackets === "square") {
				const element = result.elements[0];
				const transformed = transform(element);
				if (element.type === "JsdocTypeUnion" || element.type === "JsdocTypeIntersection") return `(${transformed})[]`;
				else return `${transformed}[]`;
			} else return `${transform(result.left)}${result.meta.dot ? "." : ""}<${result.elements.map(transform).join(`,${result.meta.elementSpacing ?? " "}`)}>`;
		},
		JsdocTypeImport: (result, transform) => `import(${transform(result.element)})`,
		JsdocTypeObjectField: (result, transform) => {
			let text = "";
			if (result.readonly) text += "readonly ";
			let optionalBeforeParentheses = false;
			if (typeof result.key === "string") text += quote(result.key, result.meta.quote);
			else {
				if (result.key.type === "JsdocTypeComputedMethod") optionalBeforeParentheses = true;
				text += transform(result.key);
			}
			text += result.meta.postKeySpacing ?? "";
			if (!optionalBeforeParentheses && result.optional) {
				text += "?";
				text += result.meta.postOptionalSpacing ?? "";
			}
			if (result.right === void 0) return text;
			else return `${text}:${result.meta.postColonSpacing ?? " "}${transform(result.right)}`;
		},
		JsdocTypeJsdocObjectField: (result, transform) => `${transform(result.left)}: ${transform(result.right)}`,
		JsdocTypeKeyValue: (result, transform) => {
			let text = result.key;
			if (result.optional) text += `${result.meta?.postKeySpacing ?? ""}?${result.meta?.postOptionalSpacing ?? ""}`;
			else if (result.variadic) text = `...${result.meta?.postVariadicSpacing ?? ""}${text}`;
			else if (result.right !== void 0) text += result.meta?.postKeySpacing ?? "";
			if (result.right === void 0) return text;
			else return `${text}:${result.meta?.postColonSpacing ?? " "}${transform(result.right)}`;
		},
		JsdocTypeSpecialNamePath: (result) => `${result.specialType}:${quote(result.value, result.meta.quote)}`,
		JsdocTypeNotNullable: (result, transform) => applyPosition(result.meta.position, transform(result.element), "!"),
		JsdocTypeNull: () => "null",
		JsdocTypeNullable: (result, transform) => applyPosition(result.meta.position, transform(result.element), "?"),
		JsdocTypeNumber: (result) => result.value.toString(),
		JsdocTypeBigInt: (result) => `${result.value}n`,
		JsdocTypeObject: (result, transform) => {
			/* c8 ignore next -- Guard */
			const lbType = (result.meta.separator ?? "").endsWith("linebreak");
			const lbEnding = result.meta.separator === "comma-and-linebreak" ? ",\n" : result.meta.separator === "semicolon-and-linebreak" ? ";\n" : result.meta.separator === "linebreak" ? "\n" : "";
			const separatorForSingleObjectField = result.meta.separatorForSingleObjectField ?? false;
			const trailingPunctuation = result.meta.trailingPunctuation ?? false;
			const bracketSpacing = result.meta.bracketSpacing ?? "";
			return `{${
			/* c8 ignore next -- Guard */
			(lbType && (separatorForSingleObjectField || result.elements.length > 1) ? `\n${result.meta.propertyIndent ?? ""}` : bracketSpacing) + result.elements.map(transform).join(result.meta.separator === "comma" ? ", " : lbType ? lbEnding + (result.meta.propertyIndent ?? "") : "; ") + (separatorForSingleObjectField && result.elements.length === 1 ? result.meta.separator === "comma" ? "," : lbType ? lbEnding : ";" : trailingPunctuation && result.meta.separator !== void 0 ? result.meta.separator.startsWith("comma") ? "," : result.meta.separator.startsWith("semicolon") ? ";" : "" : "") + (lbType && result.elements.length > 1 ? "\n" : bracketSpacing)}}`;
		},
		JsdocTypeOptional: (result, transform) => applyPosition(result.meta.position, transform(result.element), "="),
		JsdocTypeSymbol: (result, transform) => `${result.value}(${result.element !== void 0 ? transform(result.element) : ""})`,
		JsdocTypeTypeof: (result, transform) => `typeof ${transform(result.element)}`,
		JsdocTypeUndefined: () => "undefined",
		JsdocTypeUnion: (result, transform) => result.elements.map(transform).join(result.meta?.spacing === void 0 ? " | " : `${result.meta.spacing}|${result.meta.spacing}`),
		JsdocTypeUnknown: () => "?",
		JsdocTypeIntersection: (result, transform) => result.elements.map(transform).join(" & "),
		JsdocTypeProperty: (result) => quote(result.value, result.meta.quote),
		JsdocTypePredicate: (result, transform) => `${transform(result.left)} is ${transform(result.right)}`,
		JsdocTypeIndexSignature: (result, transform) => `[${result.key}: ${transform(result.right)}]`,
		JsdocTypeMappedType: (result, transform) => `[${result.key} in ${transform(result.right)}]`,
		JsdocTypeAsserts: (result, transform) => `asserts ${transform(result.left)} is ${transform(result.right)}`,
		JsdocTypeReadonlyArray: (result, transform) => `readonly ${transform(result.element)}`,
		JsdocTypeAssertsPlain: (result, transform) => `asserts ${transform(result.element)}`,
		JsdocTypeConditional: (result, transform) => `${transform(result.checksType)} extends ${transform(result.extendsType)} ? ${transform(result.trueType)} : ${transform(result.falseType)}`,
		JsdocTypeTypeParameter: (result, transform) => `${transform(result.name)}${result.constraint !== void 0 ? ` extends ${transform(result.constraint)}` : ""}${result.defaultValue !== void 0 ? `${result.meta?.defaultValueSpacing ?? " "}=${result.meta?.defaultValueSpacing ?? " "}${transform(result.defaultValue)}` : ""}`,
		JsdocTypeCallSignature: (result, transform) => `${result.typeParameters !== void 0 ? `<${result.typeParameters.map(transform).join(`,${result.meta?.typeParameterSpacing ?? " "}`)}>${result.meta?.postGenericSpacing ?? ""}` : ""}(${result.parameters.map(transform).join(`,${result.meta?.parameterSpacing ?? " "}`)})${result.meta?.preReturnMarkerSpacing ?? ""}:${result.meta?.postReturnMarkerSpacing ?? " "}${transform(result.returnType)}`,
		JsdocTypeConstructorSignature: (result, transform) => `new${result.meta?.postNewSpacing ?? " "}${result.typeParameters !== void 0 ? `<${result.typeParameters.map(transform).join(`,${result.meta?.typeParameterSpacing ?? " "}`)}>${result.meta?.postGenericSpacing ?? ""}` : ""}(${result.parameters.map(transform).join(`,${result.meta?.parameterSpacing ?? " "}`)})${result.meta?.preReturnMarkerSpacing ?? ""}:${result.meta?.postReturnMarkerSpacing ?? " "}${transform(result.returnType)}`,
		JsdocTypeMethodSignature: (result, transform) => {
			const quote = result.meta.quote === "double" ? "\"" : result.meta.quote === "single" ? "'" : "";
			return `${quote}${result.name}${quote}${result.meta.postMethodNameSpacing ?? ""}${result.typeParameters !== void 0 ? `<${result.typeParameters.map(transform).join(`,${result.meta.typeParameterSpacing ?? " "}`)}>${result.meta.postGenericSpacing ?? ""}` : ""}(${result.parameters.map(transform).join(`,${result.meta.parameterSpacing ?? " "}`)})${result.meta.preReturnMarkerSpacing ?? ""}:${result.meta.postReturnMarkerSpacing ?? " "}${transform(result.returnType)}`;
		},
		JsdocTypeIndexedAccessIndex: (result, transform) => transform(result.right),
		JsdocTypeTemplateLiteral: (result, transform) => `\`${result.literals.slice(0, -1).map((literal, idx) => `${literal.replace(/`/gv, "\\`")}\${${transform(result.interpolations[idx])}}`).join("") + result.literals.slice(-1)[0].replace(/`/gv, "\\`")}\``,
		JsdocTypeComputedProperty: (result, transform) => {
			if (result.value.type.startsWith("JsdocType")) return `[${transform(result.value)}]`;
			else {
				if (computedPropertyStringifier === void 0) throw new Error("Must have a computed property stringifier");
				return `[${computedPropertyStringifier(result.value).replace(/;$/v, "")}]`;
			}
		},
		JsdocTypeComputedMethod: (result, transform) => {
			if (result.value.type.startsWith("JsdocType")) return `[${transform(result.value)}]${result.optional ? "?" : ""}${result.typeParameters !== void 0 ? `<${result.typeParameters.map(transform).join(`,${result.meta?.typeParameterSpacing ?? " "}`)}>${result.meta?.postGenericSpacing ?? ""}` : ""}(${result.parameters.map(transform).join(`,${result.meta?.parameterSpacing ?? " "}`)})${result.meta?.preReturnMarkerSpacing ?? ""}:${result.meta?.postReturnMarkerSpacing ?? " "}${transform(result.returnType)}`;
			else {
				if (computedPropertyStringifier === void 0) throw new Error("Must have a computed property stringifier");
				return `[${computedPropertyStringifier(result.value).replace(/;$/v, "")}](${result.parameters.map(transform).join(`,${result.meta?.parameterSpacing ?? " "}`)})${result.meta?.preReturnMarkerSpacing ?? ""}:${result.meta?.postReturnMarkerSpacing ?? " "}${transform(result.returnType)}`;
			}
		}
	};
}
const storedStringifyRules = stringifyRules();
function stringify(result, stringificationRules = storedStringifyRules) {
	if (typeof stringificationRules === "function") stringificationRules = stringifyRules({ computedPropertyStringifier: stringificationRules });
	return transform(stringificationRules, result);
}
//#endregion
//#region src/transforms/catharsisTransform.ts
const reservedWords = [
	"null",
	"true",
	"false",
	"break",
	"case",
	"catch",
	"class",
	"const",
	"continue",
	"debugger",
	"default",
	"delete",
	"do",
	"else",
	"export",
	"extends",
	"finally",
	"for",
	"function",
	"if",
	"import",
	"in",
	"instanceof",
	"new",
	"return",
	"super",
	"switch",
	"this",
	"throw",
	"try",
	"typeof",
	"var",
	"void",
	"while",
	"with",
	"yield"
];
function makeName(value) {
	const result = {
		type: "NameExpression",
		name: value
	};
	if (reservedWords.includes(value)) result.reservedWord = true;
	return result;
}
const catharsisTransformRules = {
	JsdocTypeOptional: (result, transform) => {
		const transformed = transform(result.element);
		transformed.optional = true;
		return transformed;
	},
	JsdocTypeNullable: (result, transform) => {
		const transformed = transform(result.element);
		transformed.nullable = true;
		return transformed;
	},
	JsdocTypeNotNullable: (result, transform) => {
		const transformed = transform(result.element);
		transformed.nullable = false;
		return transformed;
	},
	JsdocTypeVariadic: (result, transform) => {
		if (result.element === void 0) throw new Error("dots without value are not allowed in catharsis mode");
		const transformed = transform(result.element);
		transformed.repeatable = true;
		return transformed;
	},
	JsdocTypeAny: () => ({ type: "AllLiteral" }),
	JsdocTypeNull: () => ({ type: "NullLiteral" }),
	JsdocTypeStringValue: (result) => makeName(quote(result.value, result.meta.quote)),
	JsdocTypeUndefined: () => ({ type: "UndefinedLiteral" }),
	JsdocTypeUnknown: () => ({ type: "UnknownLiteral" }),
	JsdocTypeFunction: (result, transform) => {
		const params = extractSpecialParams(result);
		const transformed = {
			type: "FunctionType",
			params: params.params.map(transform)
		};
		if (params.this !== void 0) transformed.this = transform(params.this);
		if (params.new !== void 0) transformed.new = transform(params.new);
		if (result.returnType !== void 0) transformed.result = transform(result.returnType);
		return transformed;
	},
	JsdocTypeGeneric: (result, transform) => ({
		type: "TypeApplication",
		applications: result.elements.map((o) => transform(o)),
		expression: transform(result.left)
	}),
	JsdocTypeSpecialNamePath: (result) => makeName(`${result.specialType}:${quote(result.value, result.meta.quote)}`),
	JsdocTypeName: (result) => {
		if (result.value !== "function") return makeName(result.value);
		else return {
			type: "FunctionType",
			params: []
		};
	},
	JsdocTypeNumber: (result) => makeName(result.value.toString()),
	JsdocTypeBigInt: (result) => makeName(`${result.value}n`),
	JsdocTypeObject: (result, transform) => {
		const transformed = {
			type: "RecordType",
			fields: []
		};
		for (const field of result.elements) if (field.type !== "JsdocTypeObjectField" && field.type !== "JsdocTypeJsdocObjectField") transformed.fields.push({
			type: "FieldType",
			key: transform(field),
			value: void 0
		});
		else transformed.fields.push(transform(field));
		return transformed;
	},
	JsdocTypeObjectField: (result, transform) => {
		if (typeof result.key !== "string") throw new Error("Index signatures and mapped types are not supported");
		return {
			type: "FieldType",
			key: makeName(quote(result.key, result.meta.quote)),
			value: result.right === void 0 ? void 0 : transform(result.right)
		};
	},
	JsdocTypeJsdocObjectField: (result, transform) => ({
		type: "FieldType",
		key: transform(result.left),
		value: transform(result.right)
	}),
	JsdocTypeUnion: (result, transform) => ({
		type: "TypeUnion",
		elements: result.elements.map((e) => transform(e))
	}),
	JsdocTypeKeyValue: (result, transform) => ({
		type: "FieldType",
		key: makeName(result.key),
		value: result.right === void 0 ? void 0 : transform(result.right)
	}),
	JsdocTypeNamePath: (result, transform) => {
		const leftResult = transform(result.left);
		let rightValue;
		if (result.right.type === "JsdocTypeIndexedAccessIndex") throw new TypeError("JsdocTypeIndexedAccessIndex is not supported in catharsis");
		if (result.right.type === "JsdocTypeSpecialNamePath") rightValue = transform(result.right).name;
		else rightValue = quote(result.right.value, result.right.meta.quote);
		const joiner = result.pathType === "inner" ? "~" : result.pathType === "instance" ? "#" : ".";
		return makeName(`${leftResult.name}${joiner}${rightValue}`);
	},
	JsdocTypeSymbol: (result) => {
		let value = "";
		let element = result.element;
		let trailingDots = false;
		if (element?.type === "JsdocTypeVariadic") {
			if (element.meta.position === "prefix") value = "...";
			else trailingDots = true;
			element = element.element;
		}
		if (element?.type === "JsdocTypeName") value += element.value;
		else if (element?.type === "JsdocTypeNumber") value += element.value.toString();
		if (trailingDots) value += "...";
		return makeName(`${result.value}(${value})`);
	},
	JsdocTypeParenthesis: (result, transform) => transform(assertRootResult(result.element)),
	JsdocTypeMappedType: notAvailableTransform,
	JsdocTypeIndexSignature: notAvailableTransform,
	JsdocTypeInfer: notAvailableTransform,
	JsdocTypeUniqueSymbol: notAvailableTransform,
	JsdocTypeImport: notAvailableTransform,
	JsdocTypeKeyof: notAvailableTransform,
	JsdocTypeTuple: notAvailableTransform,
	JsdocTypeTypeof: notAvailableTransform,
	JsdocTypeIntersection: notAvailableTransform,
	JsdocTypeProperty: notAvailableTransform,
	JsdocTypePredicate: notAvailableTransform,
	JsdocTypeAsserts: notAvailableTransform,
	JsdocTypeReadonlyArray: notAvailableTransform,
	JsdocTypeAssertsPlain: notAvailableTransform,
	JsdocTypeConditional: notAvailableTransform,
	JsdocTypeTypeParameter: notAvailableTransform,
	JsdocTypeCallSignature: notAvailableTransform,
	JsdocTypeConstructorSignature: notAvailableTransform,
	JsdocTypeMethodSignature: notAvailableTransform,
	JsdocTypeIndexedAccessIndex: notAvailableTransform,
	JsdocTypeTemplateLiteral: notAvailableTransform,
	JsdocTypeComputedProperty: notAvailableTransform,
	JsdocTypeComputedMethod: notAvailableTransform
};
function catharsisTransform(result) {
	return transform(catharsisTransformRules, result);
}
//#endregion
//#region src/transforms/jtpTransform.ts
function getQuoteStyle(quote) {
	switch (quote) {
		case void 0: return "none";
		case "single": return "single";
		case "double": return "double";
	}
}
function getMemberType(type) {
	switch (type) {
		case "inner": return "INNER_MEMBER";
		case "instance": return "INSTANCE_MEMBER";
		case "property": return "MEMBER";
		case "property-brackets": return "MEMBER";
	}
}
function nestResults(type, results) {
	if (results.length === 2) return {
		type,
		left: results[0],
		right: results[1]
	};
	else return {
		type,
		left: results[0],
		right: nestResults(type, results.slice(1))
	};
}
const jtpRules = {
	JsdocTypeOptional: (result, transform) => ({
		type: "OPTIONAL",
		value: transform(result.element),
		meta: { syntax: result.meta.position === "prefix" ? "PREFIX_EQUAL_SIGN" : "SUFFIX_EQUALS_SIGN" }
	}),
	JsdocTypeNullable: (result, transform) => ({
		type: "NULLABLE",
		value: transform(result.element),
		meta: { syntax: result.meta.position === "prefix" ? "PREFIX_QUESTION_MARK" : "SUFFIX_QUESTION_MARK" }
	}),
	JsdocTypeNotNullable: (result, transform) => ({
		type: "NOT_NULLABLE",
		value: transform(result.element),
		meta: { syntax: result.meta.position === "prefix" ? "PREFIX_BANG" : "SUFFIX_BANG" }
	}),
	JsdocTypeVariadic: (result, transform) => {
		const transformed = {
			type: "VARIADIC",
			meta: { syntax: result.meta.position === "prefix" ? "PREFIX_DOTS" : result.meta.position === "suffix" ? "SUFFIX_DOTS" : "ONLY_DOTS" }
		};
		if (result.element !== void 0) transformed.value = transform(result.element);
		return transformed;
	},
	JsdocTypeName: (result) => ({
		type: "NAME",
		name: result.value
	}),
	JsdocTypeTypeof: (result, transform) => ({
		type: "TYPE_QUERY",
		name: transform(result.element)
	}),
	JsdocTypeTuple: (result, transform) => ({
		type: "TUPLE",
		entries: result.elements.map(transform)
	}),
	JsdocTypeKeyof: (result, transform) => ({
		type: "KEY_QUERY",
		value: transform(result.element)
	}),
	JsdocTypeImport: (result) => ({
		type: "IMPORT",
		path: {
			type: "STRING_VALUE",
			quoteStyle: getQuoteStyle(result.element.meta.quote),
			string: result.element.value
		}
	}),
	JsdocTypeUndefined: () => ({
		type: "NAME",
		name: "undefined"
	}),
	JsdocTypeAny: () => ({ type: "ANY" }),
	JsdocTypeFunction: (result, transform) => {
		const specialParams = extractSpecialParams(result);
		const transformed = {
			type: result.arrow ? "ARROW" : "FUNCTION",
			params: specialParams.params.map((param) => {
				if (param.type === "JsdocTypeKeyValue") {
					if (param.right === void 0) throw new Error("Function parameter without ':' is not expected to be 'KEY_VALUE'");
					return {
						type: "NAMED_PARAMETER",
						name: param.key,
						typeName: transform(param.right)
					};
				} else return transform(param);
			}),
			new: null,
			returns: null
		};
		if (specialParams.this !== void 0) transformed.this = transform(specialParams.this);
		else if (!result.arrow) transformed.this = null;
		if (specialParams.new !== void 0) transformed.new = transform(specialParams.new);
		if (result.returnType !== void 0) transformed.returns = transform(result.returnType);
		return transformed;
	},
	JsdocTypeGeneric: (result, transform) => {
		const transformed = {
			type: "GENERIC",
			subject: transform(result.left),
			objects: result.elements.map(transform),
			meta: { syntax: result.meta.brackets === "square" ? "SQUARE_BRACKET" : result.meta.dot ? "ANGLE_BRACKET_WITH_DOT" : "ANGLE_BRACKET" }
		};
		if (result.meta.brackets === "square" && result.elements[0].type === "JsdocTypeFunction" && !result.elements[0].parenthesis) transformed.objects[0] = {
			type: "NAME",
			name: "function"
		};
		return transformed;
	},
	JsdocTypeObjectField: (result, transform) => {
		if (typeof result.key !== "string") throw new Error("Index signatures and mapped types are not supported");
		if (result.right === void 0) return {
			type: "RECORD_ENTRY",
			key: result.key,
			quoteStyle: getQuoteStyle(result.meta.quote),
			value: null,
			readonly: false
		};
		let right = transform(result.right);
		if (result.optional) right = {
			type: "OPTIONAL",
			value: right,
			meta: { syntax: "SUFFIX_KEY_QUESTION_MARK" }
		};
		return {
			type: "RECORD_ENTRY",
			key: result.key,
			quoteStyle: getQuoteStyle(result.meta.quote),
			value: right,
			readonly: false
		};
	},
	JsdocTypeJsdocObjectField: () => {
		throw new Error("Keys may not be typed in jsdoctypeparser.");
	},
	JsdocTypeKeyValue: (result, transform) => {
		if (result.right === void 0) return {
			type: "RECORD_ENTRY",
			key: result.key,
			quoteStyle: "none",
			value: null,
			readonly: false
		};
		let right = transform(result.right);
		if (result.optional) right = {
			type: "OPTIONAL",
			value: right,
			meta: { syntax: "SUFFIX_KEY_QUESTION_MARK" }
		};
		return {
			type: "RECORD_ENTRY",
			key: result.key,
			quoteStyle: "none",
			value: right,
			readonly: false
		};
	},
	JsdocTypeObject: (result, transform) => {
		const entries = [];
		for (const field of result.elements) if (field.type === "JsdocTypeObjectField" || field.type === "JsdocTypeJsdocObjectField") entries.push(transform(field));
		return {
			type: "RECORD",
			entries
		};
	},
	JsdocTypeSpecialNamePath: (result) => {
		if (result.specialType !== "module") throw new Error(`jsdoctypeparser does not support type ${result.specialType} at this point.`);
		return {
			type: "MODULE",
			value: {
				type: "FILE_PATH",
				quoteStyle: getQuoteStyle(result.meta.quote),
				path: result.value
			}
		};
	},
	JsdocTypeNamePath: (result, transform) => {
		let hasEventPrefix = false;
		let name;
		let quoteStyle;
		if (result.right.type === "JsdocTypeIndexedAccessIndex") throw new TypeError("JsdocTypeIndexedAccessIndex not allowed in jtp");
		if (result.right.type === "JsdocTypeSpecialNamePath" && result.right.specialType === "event") {
			hasEventPrefix = true;
			name = result.right.value;
			quoteStyle = getQuoteStyle(result.right.meta.quote);
		} else {
			name = result.right.value;
			quoteStyle = getQuoteStyle(result.right.meta.quote);
		}
		const transformed = {
			type: getMemberType(result.pathType),
			owner: transform(result.left),
			name,
			quoteStyle,
			hasEventPrefix
		};
		if (transformed.owner.type === "MODULE") {
			const tModule = transformed.owner;
			transformed.owner = transformed.owner.value;
			tModule.value = transformed;
			return tModule;
		} else return transformed;
	},
	JsdocTypeUnion: (result, transform) => nestResults("UNION", result.elements.map(transform)),
	JsdocTypeParenthesis: (result, transform) => ({
		type: "PARENTHESIS",
		value: transform(assertRootResult(result.element))
	}),
	JsdocTypeNull: () => ({
		type: "NAME",
		name: "null"
	}),
	JsdocTypeUnknown: () => ({ type: "UNKNOWN" }),
	JsdocTypeStringValue: (result) => ({
		type: "STRING_VALUE",
		quoteStyle: getQuoteStyle(result.meta.quote),
		string: result.value
	}),
	JsdocTypeIntersection: (result, transform) => nestResults("INTERSECTION", result.elements.map(transform)),
	JsdocTypeNumber: (result) => ({
		type: "NUMBER_VALUE",
		number: result.value.toString()
	}),
	JsdocTypeBigInt: (result) => ({
		type: "NUMBER_VALUE",
		number: `${result.value}n`
	}),
	JsdocTypeSymbol: notAvailableTransform,
	JsdocTypeProperty: notAvailableTransform,
	JsdocTypePredicate: notAvailableTransform,
	JsdocTypeMappedType: notAvailableTransform,
	JsdocTypeIndexSignature: notAvailableTransform,
	JsdocTypeInfer: notAvailableTransform,
	JsdocTypeUniqueSymbol: notAvailableTransform,
	JsdocTypeAsserts: notAvailableTransform,
	JsdocTypeReadonlyArray: notAvailableTransform,
	JsdocTypeAssertsPlain: notAvailableTransform,
	JsdocTypeConditional: notAvailableTransform,
	JsdocTypeTypeParameter: notAvailableTransform,
	JsdocTypeCallSignature: notAvailableTransform,
	JsdocTypeConstructorSignature: notAvailableTransform,
	JsdocTypeMethodSignature: notAvailableTransform,
	JsdocTypeIndexedAccessIndex: notAvailableTransform,
	JsdocTypeTemplateLiteral: notAvailableTransform,
	JsdocTypeComputedProperty: notAvailableTransform,
	JsdocTypeComputedMethod: notAvailableTransform
};
function jtpTransform(result) {
	return transform(jtpRules, result);
}
//#endregion
//#region src/transforms/identityTransformRules.ts
function identityTransformRules() {
	return {
		JsdocTypeIntersection: (result, transform) => ({
			type: "JsdocTypeIntersection",
			elements: result.elements.map(transform)
		}),
		JsdocTypeGeneric: (result, transform) => ({
			type: "JsdocTypeGeneric",
			left: transform(result.left),
			elements: result.elements.map(transform),
			meta: {
				dot: result.meta.dot,
				brackets: result.meta.brackets
			}
		}),
		JsdocTypeNullable: (result) => result,
		JsdocTypeUnion: (result, transform) => ({
			type: "JsdocTypeUnion",
			elements: result.elements.map(transform)
		}),
		JsdocTypeUnknown: (result) => result,
		JsdocTypeUndefined: (result) => result,
		JsdocTypeTypeof: (result, transform) => ({
			type: "JsdocTypeTypeof",
			element: transform(result.element)
		}),
		JsdocTypeSymbol: (result, transform) => {
			const transformed = {
				type: "JsdocTypeSymbol",
				value: result.value
			};
			if (result.element !== void 0) transformed.element = transform(result.element);
			return transformed;
		},
		JsdocTypeOptional: (result, transform) => ({
			type: "JsdocTypeOptional",
			element: transform(result.element),
			meta: { position: result.meta.position }
		}),
		JsdocTypeObject: (result, transform) => ({
			type: "JsdocTypeObject",
			meta: { separator: "comma" },
			elements: result.elements.map(transform)
		}),
		JsdocTypeNumber: (result) => result,
		JsdocTypeBigInt: (result) => result,
		JsdocTypeNull: (result) => result,
		JsdocTypeNotNullable: (result, transform) => ({
			type: "JsdocTypeNotNullable",
			element: transform(result.element),
			meta: { position: result.meta.position }
		}),
		JsdocTypeSpecialNamePath: (result) => result,
		JsdocTypeObjectField: (result, transform) => ({
			type: "JsdocTypeObjectField",
			key: result.key,
			right: result.right === void 0 ? void 0 : transform(result.right),
			optional: result.optional,
			readonly: result.readonly,
			meta: result.meta
		}),
		JsdocTypeJsdocObjectField: (result, transform) => ({
			type: "JsdocTypeJsdocObjectField",
			left: transform(result.left),
			right: transform(result.right)
		}),
		JsdocTypeKeyValue: (result, transform) => ({
			type: "JsdocTypeKeyValue",
			key: result.key,
			right: result.right === void 0 ? void 0 : transform(result.right),
			optional: result.optional,
			variadic: result.variadic
		}),
		JsdocTypeImport: (result, transform) => ({
			type: "JsdocTypeImport",
			element: transform(result.element)
		}),
		JsdocTypeAny: (result) => result,
		JsdocTypeStringValue: (result) => result,
		JsdocTypeNamePath: (result) => result,
		JsdocTypeVariadic: (result, transform) => {
			const transformed = {
				type: "JsdocTypeVariadic",
				meta: {
					position: result.meta.position,
					squareBrackets: result.meta.squareBrackets
				}
			};
			if (result.element !== void 0) transformed.element = transform(result.element);
			return transformed;
		},
		JsdocTypeTuple: (result, transform) => ({
			type: "JsdocTypeTuple",
			elements: result.elements.map(transform)
		}),
		JsdocTypeName: (result) => result,
		JsdocTypeInfer: (result, transform) => ({
			type: "JsdocTypeInfer",
			element: transform(result.element)
		}),
		JsdocTypeUniqueSymbol: (result) => result,
		JsdocTypeFunction: (result, transform) => {
			const transformed = {
				type: "JsdocTypeFunction",
				arrow: result.arrow,
				parameters: result.parameters.map(transform),
				constructor: result.constructor,
				parenthesis: result.parenthesis
			};
			if (result.returnType !== void 0) transformed.returnType = transform(result.returnType);
			return transformed;
		},
		JsdocTypeKeyof: (result, transform) => ({
			type: "JsdocTypeKeyof",
			element: transform(result.element)
		}),
		JsdocTypeParenthesis: (result, transform) => ({
			type: "JsdocTypeParenthesis",
			element: transform(result.element)
		}),
		JsdocTypeProperty: (result) => result,
		JsdocTypePredicate: (result, transform) => ({
			type: "JsdocTypePredicate",
			left: transform(result.left),
			right: transform(result.right)
		}),
		JsdocTypeIndexSignature: (result, transform) => ({
			type: "JsdocTypeIndexSignature",
			key: result.key,
			right: transform(result.right)
		}),
		JsdocTypeMappedType: (result, transform) => ({
			type: "JsdocTypeMappedType",
			key: result.key,
			right: transform(result.right)
		}),
		JsdocTypeAsserts: (result, transform) => ({
			type: "JsdocTypeAsserts",
			left: transform(result.left),
			right: transform(result.right)
		}),
		JsdocTypeReadonlyArray: (result, transform) => ({
			type: "JsdocTypeReadonlyArray",
			element: transform(result.element)
		}),
		JsdocTypeAssertsPlain: (result, transform) => ({
			type: "JsdocTypeAssertsPlain",
			element: transform(result.element)
		}),
		JsdocTypeConditional: (result, transform) => ({
			type: "JsdocTypeConditional",
			checksType: transform(result.checksType),
			extendsType: transform(result.extendsType),
			trueType: transform(result.trueType),
			falseType: transform(result.falseType)
		}),
		JsdocTypeTypeParameter: (result, transform) => ({
			type: "JsdocTypeTypeParameter",
			name: transform(result.name),
			constraint: result.constraint !== void 0 ? transform(result.constraint) : void 0,
			defaultValue: result.defaultValue !== void 0 ? transform(result.defaultValue) : void 0
		}),
		JsdocTypeCallSignature: (result, transform) => ({
			type: "JsdocTypeCallSignature",
			parameters: result.parameters.map(transform),
			returnType: transform(result.returnType)
		}),
		JsdocTypeConstructorSignature: (result, transform) => ({
			type: "JsdocTypeConstructorSignature",
			parameters: result.parameters.map(transform),
			returnType: transform(result.returnType)
		}),
		JsdocTypeMethodSignature: (result, transform) => ({
			type: "JsdocTypeMethodSignature",
			name: result.name,
			parameters: result.parameters.map(transform),
			returnType: transform(result.returnType),
			meta: result.meta
		}),
		JsdocTypeIndexedAccessIndex: (result, transform) => ({
			type: "JsdocTypeIndexedAccessIndex",
			right: transform(result.right)
		}),
		JsdocTypeTemplateLiteral: (result, transform) => ({
			type: "JsdocTypeTemplateLiteral",
			literals: result.literals,
			interpolations: result.interpolations.map(transform)
		}),
		JsdocTypeComputedProperty: (result, transform) => {
			if (result.value.type.startsWith("JsdocType")) return {
				type: "JsdocTypeComputedProperty",
				value: transform(result.value)
			};
			else return {
				type: "JsdocTypeComputedProperty",
				value: structuredClone(result.value)
			};
		},
		JsdocTypeComputedMethod: (result, transform) => {
			if (result.value.type.startsWith("JsdocType")) return {
				type: "JsdocTypeComputedMethod",
				value: transform(result.value),
				optional: result.optional,
				parameters: result.parameters.map(transform),
				returnType: transform(result.returnType)
			};
			else return {
				type: "JsdocTypeComputedMethod",
				value: structuredClone(result.value),
				optional: result.optional,
				parameters: result.parameters.map(transform),
				returnType: transform(result.returnType)
			};
		}
	};
}
//#endregion
//#region src/visitorKeys.ts
const visitorKeys = {
	JsdocTypeAny: [],
	JsdocTypeBigInt: [],
	JsdocTypeFunction: [
		"typeParameters",
		"parameters",
		"returnType"
	],
	JsdocTypeGeneric: ["left", "elements"],
	JsdocTypeImport: ["element"],
	JsdocTypeIndexSignature: ["right"],
	JsdocTypeIntersection: ["elements"],
	JsdocTypeKeyof: ["element"],
	JsdocTypeKeyValue: ["right"],
	JsdocTypeMappedType: ["right"],
	JsdocTypeName: [],
	JsdocTypeInfer: ["element"],
	JsdocTypeUniqueSymbol: [],
	JsdocTypeNamePath: ["left", "right"],
	JsdocTypeNotNullable: ["element"],
	JsdocTypeNull: [],
	JsdocTypeNullable: ["element"],
	JsdocTypeNumber: [],
	JsdocTypeObject: ["elements"],
	JsdocTypeObjectField: ["key", "right"],
	JsdocTypeJsdocObjectField: ["left", "right"],
	JsdocTypeOptional: ["element"],
	JsdocTypeParenthesis: ["element"],
	JsdocTypeSpecialNamePath: [],
	JsdocTypeStringValue: [],
	JsdocTypeSymbol: ["element"],
	JsdocTypeTuple: ["elements"],
	JsdocTypeTypeof: ["element"],
	JsdocTypeUndefined: [],
	JsdocTypeUnion: ["elements"],
	JsdocTypeUnknown: [],
	JsdocTypeVariadic: ["element"],
	JsdocTypeProperty: [],
	JsdocTypePredicate: ["left", "right"],
	JsdocTypeAsserts: ["left", "right"],
	JsdocTypeReadonlyArray: ["element"],
	JsdocTypeAssertsPlain: ["element"],
	JsdocTypeConditional: [
		"checksType",
		"extendsType",
		"trueType",
		"falseType"
	],
	JsdocTypeTypeParameter: [
		"name",
		"constraint",
		"defaultValue"
	],
	JsdocTypeCallSignature: [
		"typeParameters",
		"parameters",
		"returnType"
	],
	JsdocTypeConstructorSignature: [
		"typeParameters",
		"parameters",
		"returnType"
	],
	JsdocTypeMethodSignature: [
		"typeParameters",
		"parameters",
		"returnType"
	],
	JsdocTypeIndexedAccessIndex: ["right"],
	JsdocTypeTemplateLiteral: ["interpolations"],
	JsdocTypeComputedProperty: ["value"],
	JsdocTypeComputedMethod: [
		"value",
		"typeParameters",
		"parameters",
		"returnType"
	]
};
//#endregion
//#region src/traverse.ts
function _traverse(node, parentNode, property, index, onEnter, onLeave) {
	onEnter?.(node, parentNode, property, index);
	const keysToVisit = visitorKeys[node.type];
	for (const key of keysToVisit) {
		const value = node[key];
		if (value !== void 0) {
			if (Array.isArray(value)) for (const [index, element] of value.entries()) _traverse(element, node, key, index, onEnter, onLeave);
			else if (value !== null && typeof value === "object" && "type" in value) _traverse(value, node, key, void 0, onEnter, onLeave);
		}
	}
	onLeave?.(node, parentNode, property, index);
}
/**
* A function to traverse an AST. It traverses it depth first.
* @param node the node to start traversing at.
* @param onEnter node visitor function that will be called on entering the node. This corresponds to preorder traversing.
* @param onLeave node visitor function that will be called on leaving the node. This corresponds to postorder traversing.
*/
function traverse(node, onEnter, onLeave) {
	_traverse(node, void 0, void 0, void 0, onEnter, onLeave);
}
//#endregion
export { catharsisTransform, identityTransformRules, jtpTransform, parse, parseName, parseNamePath, stringify, stringifyRules, transform, traverse, tryParse, visitorKeys };
