import { streamAst as e } from "../utils/ast-utils.js";
import { tokenToRange as t } from "../utils/cst-utils.js";
import { findNodeForKeyword as n, findNodeForProperty as r } from "../utils/grammar-utils.js";
import { cancellation_exports as i } from "../utils/cancellation.js";
import { interruptAndCheck as a, isOperationCancelled as o } from "../utils/promise-utils.js";
import { diagnosticData as s } from "./validation-registry.js";
//#region ../../node_modules/langium/lib/validation/document-validator.js
var c = Object.freeze({
	validateNode: !0,
	validateChildren: !0
}), l = class {
	constructor(e) {
		this.validationRegistry = e.validation.ValidationRegistry, this.metadata = e.LanguageMetaData, this.profiler = e.shared.profilers.LangiumProfiler, this.languageId = e.LanguageMetaData.languageId;
	}
	async validateDocument(e, t = {}, n = i.CancellationToken.None) {
		let r = e.parseResult, s = [];
		if (await a(n), (!t.categories || t.categories.includes("built-in")) && (this.processLexingErrors(r, s, t), t.stopAfterLexingErrors && s.some((e) => e.data?.code === p.LexingError) || (this.processParsingErrors(r, s, t), t.stopAfterParsingErrors && s.some((e) => e.data?.code === p.ParsingError)) || (this.processLinkingErrors(e, s, t), t.stopAfterLinkingErrors && s.some((e) => e.data?.code === p.LinkingError)))) return s;
		try {
			s.push(...await this.validateAst(r.value, t, n));
		} catch (e) {
			if (o(e)) throw e;
			console.error("An error occurred during validation:", e);
		}
		return await a(n), s;
	}
	processLexingErrors(e, t, n) {
		let r = [...e.lexerErrors, ...e.lexerReport?.diagnostics ?? []];
		for (let e of r) {
			let n = e.severity ?? "error", r = {
				severity: d(n),
				range: {
					start: {
						line: e.line - 1,
						character: e.column - 1
					},
					end: {
						line: e.line - 1,
						character: e.column + e.length - 1
					}
				},
				message: e.message,
				data: f(n),
				source: this.getSource()
			};
			t.push(r);
		}
	}
	processParsingErrors(e, n, r) {
		for (let r of e.parserErrors) {
			let e;
			if (isNaN(r.token.startOffset)) {
				if ("previousToken" in r) {
					let t = r.previousToken;
					if (isNaN(t.startOffset)) {
						let t = {
							line: 0,
							character: 0
						};
						e = {
							start: t,
							end: t
						};
					} else {
						let n = {
							line: t.endLine - 1,
							character: t.endColumn
						};
						e = {
							start: n,
							end: n
						};
					}
				}
			} else e = t(r.token);
			if (e) {
				let t = {
					severity: d("error"),
					range: e,
					message: r.message,
					data: s(p.ParsingError),
					source: this.getSource()
				};
				n.push(t);
			}
		}
	}
	processLinkingErrors(e, t, n) {
		for (let n of e.references) {
			let e = n.error;
			if (e) {
				let r = {
					node: e.info.container,
					range: n.$refNode?.range,
					property: e.info.property,
					index: e.info.index,
					data: {
						code: p.LinkingError,
						containerType: e.info.container.$type,
						property: e.info.property,
						refText: e.info.reference.$refText
					}
				};
				t.push(this.toDiagnostic("error", e.message, r));
			}
		}
	}
	async validateAst(e, t, n = i.CancellationToken.None) {
		let r = [], a = (e, t, n) => {
			r.push(this.toDiagnostic(e, t, n));
		};
		return await this.validateAstBefore(e, t, a, n), await this.validateAstNodes(e, t, a, n), await this.validateAstAfter(e, t, a, n), r;
	}
	async validateAstBefore(e, t, n, r = i.CancellationToken.None) {
		let o = this.validationRegistry.checksBefore;
		for (let i of o) await a(r), await i(e, n, t.categories ?? [], r);
	}
	async validateAstNodes(t, n, r, o = i.CancellationToken.None) {
		if (this.profiler?.isActive("validating")) {
			let i = this.profiler.createTask("validating", this.languageId);
			i.start();
			try {
				let a = e(t).iterator();
				for (let e of a) {
					i.startSubTask(e.$type);
					let t = this.validateSingleNodeOptions(e, n);
					if (t.validateNode) try {
						let t = this.validationRegistry.getChecks(e.$type, n.categories);
						for (let n of t) await n(e, r, o);
					} finally {
						i.stopSubTask(e.$type);
					}
					t.validateChildren || a.prune();
				}
			} finally {
				i.stop();
			}
		} else {
			let i = e(t).iterator();
			for (let e of i) {
				await a(o);
				let t = this.validateSingleNodeOptions(e, n);
				if (t.validateNode) {
					let t = this.validationRegistry.getChecks(e.$type, n.categories);
					for (let n of t) await n(e, r, o);
				}
				t.validateChildren || i.prune();
			}
		}
	}
	validateSingleNodeOptions(e, t) {
		return c;
	}
	async validateAstAfter(e, t, n, r = i.CancellationToken.None) {
		let o = this.validationRegistry.checksAfter;
		for (let i of o) await a(r), await i(e, n, t.categories ?? [], r);
	}
	toDiagnostic(e, t, n) {
		return {
			message: t,
			range: u(n),
			severity: d(e),
			code: n.code,
			codeDescription: n.codeDescription,
			tags: n.tags,
			relatedInformation: n.relatedInformation,
			data: n.data,
			source: this.getSource()
		};
	}
	getSource() {
		return this.metadata.languageId;
	}
};
function u(e) {
	if (e.range) return e.range;
	let t;
	return typeof e.property == "string" ? t = r(e.node.$cstNode, e.property, e.index) : typeof e.keyword == "string" && (t = n(e.node.$cstNode, e.keyword, e.index)), t ??= e.node.$cstNode, t ? t.range : {
		start: {
			line: 0,
			character: 0
		},
		end: {
			line: 0,
			character: 0
		}
	};
}
function d(e) {
	switch (e) {
		case "error": return 1;
		case "warning": return 2;
		case "info": return 3;
		case "hint": return 4;
		default: throw Error("Invalid diagnostic severity: " + e);
	}
}
function f(e) {
	switch (e) {
		case "error": return s(p.LexingError);
		case "warning": return s(p.LexingWarning);
		case "info": return s(p.LexingInfo);
		case "hint": return s(p.LexingHint);
		default: throw Error("Invalid diagnostic severity: " + e);
	}
}
var p;
(function(e) {
	e.LexingError = "lexing-error", e.LexingWarning = "lexing-warning", e.LexingInfo = "lexing-info", e.LexingHint = "lexing-hint", e.ParsingError = "parsing-error", e.LinkingError = "linking-error";
})(p ||= {});
//#endregion
export { l as DefaultDocumentValidator };
