UNPKG

@taml/parser

Version:

Parser for TAML (Terminal ANSI Markup Language) that generates AST nodes

251 lines 17.5 kB
/** * Validator for TAML tokens and syntax */ import { isValidTag } from "@taml/ast"; import { InvalidTagError, MismatchedTagError, UnclosedTagError, } from "./errors.js"; import { isCloseTagToken, isEofToken, isOpenTagToken, isTextToken, } from "./tokenizer.js"; /** * TAML Validator class */ export class TamlValidator { source; constructor(source) { this.source = source; } /** * Validate a sequence of tokens */ validateTokens(tokens) { const context = { tokens, position: 0, source: this.source, tagStack: [], errors: [], }; try { this.validateTokenSequence(context); // Check for unclosed tags at the end if (context.tagStack.length > 0) { const unclosedTag = context.tagStack[context.tagStack.length - 1]; if (unclosedTag) { const error = new UnclosedTagError(unclosedTag.tagName, unclosedTag.token.start, unclosedTag.token.line, unclosedTag.token.column, this.source); context.errors.push(error); } } return { valid: context.errors.length === 0, errors: context.errors, }; } catch (error) { if (error instanceof Error) { context.errors.push(error); } return { valid: false, errors: context.errors, }; } } /** * Validate the sequence of tokens */ validateTokenSequence(context) { while (context.position < context.tokens.length) { const token = context.tokens[context.position]; if (!token) { break; } if (isEofToken(token)) { break; } if (isOpenTagToken(token)) { this.validateOpenTag(context, token); } else if (isCloseTagToken(token)) { this.validateCloseTag(context, token); } else if (isTextToken(token)) { // Text tokens are always valid context.position++; } else { // Skip unexpected tokens context.position++; } } } /** * Validate an opening tag token */ validateOpenTag(context, token) { if (!isOpenTagToken(token)) { context.position++; return; } // Validate tag name against TAML specification if (!isValidTag(token.tagName)) { const error = new InvalidTagError(token.tagName, token.start, token.line, token.column, this.source); context.errors.push(error); context.position++; return; } // Push tag onto stack for tracking context.tagStack.push({ tagName: token.tagName, token, }); context.position++; } /** * Validate a closing tag token */ validateCloseTag(context, token) { if (!isCloseTagToken(token)) { context.position++; return; } // Validate tag name against TAML specification if (!isValidTag(token.tagName)) { const error = new InvalidTagError(token.tagName, token.start, token.line, token.column, this.source); context.errors.push(error); context.position++; return; } // Check if there's a matching opening tag if (context.tagStack.length === 0) { // No opening tag to match - this is an extra closing tag const error = new MismatchedTagError("(none)", token.tagName, token.start, token.line, token.column, this.source); context.errors.push(error); context.position++; return; } // Check if the closing tag matches the most recent opening tag const lastOpenTag = context.tagStack[context.tagStack.length - 1]; if (lastOpenTag && lastOpenTag.tagName !== token.tagName) { const error = new MismatchedTagError(lastOpenTag.tagName, token.tagName, token.start, token.line, token.column, this.source); context.errors.push(error); context.position++; return; } // Valid closing tag - pop from stack context.tagStack.pop(); context.position++; } /** * Get current validation state for debugging */ getDebugInfo(context) { return { position: context.position, currentToken: context.position < context.tokens.length ? (context.tokens[context.position] ?? null) : null, tagStack: context.tagStack.map((entry) => entry.tagName), errorCount: context.errors.length, }; } } /** * Convenience function to validate TAML tokens */ export function validateTamlTokens(tokens, source) { const validator = new TamlValidator(source); return validator.validateTokens(tokens); } /** * Validate tag name against TAML specification */ export function validateTagName(tagName) { return isValidTag(tagName); } /** * Check if nesting is valid (stack-based validation) */ export function validateNesting(tokens) { const tagStack = []; const unclosedTags = []; const mismatchedTags = []; for (const token of tokens) { if (isOpenTagToken(token)) { if (isValidTag(token.tagName)) { tagStack.push(token.tagName); } } else if (isCloseTagToken(token)) { if (isValidTag(token.tagName)) { if (tagStack.length === 0) { mismatchedTags.push({ expected: "(none)", actual: token.tagName }); } else { const lastTag = tagStack[tagStack.length - 1]; if (lastTag && lastTag === token.tagName) { tagStack.pop(); } else if (lastTag) { mismatchedTags.push({ expected: lastTag, actual: token.tagName }); } } } } } // Any remaining tags in stack are unclosed unclosedTags.push(...tagStack); return { valid: unclosedTags.length === 0 && mismatchedTags.length === 0, unclosedTags, mismatchedTags, }; } /** * Validate proper tag closure */ export function validateTagClosure(tokens) { const tagStack = []; const issues = []; for (const token of tokens) { if (isOpenTagToken(token)) { if (isValidTag(token.tagName)) { tagStack.push({ tagName: token.tagName, position: token.start }); } } else if (isCloseTagToken(token)) { if (isValidTag(token.tagName)) { if (tagStack.length === 0) { issues.push({ type: "extra", tagName: token.tagName, position: token.start, }); } else { const lastTag = tagStack[tagStack.length - 1]; if (lastTag && lastTag.tagName === token.tagName) { tagStack.pop(); } else { issues.push({ type: "mismatched", tagName: token.tagName, position: token.start, }); } } } } } // Any remaining tags in stack are unclosed for (const unclosedTag of tagStack) { issues.push({ type: "unclosed", tagName: unclosedTag.tagName, position: unclosedTag.position, }); } return { valid: issues.length === 0, issues, }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvdmFsaWRhdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsT0FBTyxFQUFnQixVQUFVLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckQsT0FBTyxFQUNMLGVBQWUsRUFDZixrQkFBa0IsRUFDbEIsZ0JBQWdCLEdBQ2pCLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFFTCxlQUFlLEVBQ2YsVUFBVSxFQUNWLGNBQWMsRUFDZCxXQUFXLEdBQ1osTUFBTSxnQkFBZ0IsQ0FBQztBQXFCeEI7O0dBRUc7QUFDSCxNQUFNLE9BQU8sYUFBYTtJQUNLO0lBQTdCLFlBQTZCLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO0lBQUcsQ0FBQztJQUUvQzs7T0FFRztJQUNILGNBQWMsQ0FBQyxNQUFtQjtRQUNoQyxNQUFNLE9BQU8sR0FBc0I7WUFDakMsTUFBTTtZQUNOLFFBQVEsRUFBRSxDQUFDO1lBQ1gsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNO1lBQ25CLFFBQVEsRUFBRSxFQUFFO1lBQ1osTUFBTSxFQUFFLEVBQUU7U0FDWCxDQUFDO1FBRUYsSUFBSSxDQUFDO1lBQ0gsSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRXBDLHFDQUFxQztZQUNyQyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNoQyxNQUFNLFdBQVcsR0FBRyxPQUFPLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO2dCQUNsRSxJQUFJLFdBQVcsRUFBRSxDQUFDO29CQUNoQixNQUFNLEtBQUssR0FBRyxJQUFJLGdCQUFnQixDQUNoQyxXQUFXLENBQUMsT0FBTyxFQUNuQixXQUFXLENBQUMsS0FBSyxDQUFDLEtBQUssRUFDdkIsV0FBVyxDQUFDLEtB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