From 15422cca1f72d0afd0a73d6ede0246cb416f2dbf Mon Sep 17 00:00:00 2001 From: Pier Paolo MAMMI Date: Tue, 18 Aug 2026 12:49:31 +0200 Subject: [PATCH] fix unclosed block detection add parser tests (codex) --- package-lock.json | 2 -- package.json | 1 + src/parser.ts | 3 ++- test/parser.test.js | 48 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 test/parser.test.js diff --git a/package-lock.json b/package-lock.json index 392e85f..4be48f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -303,7 +303,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -489,7 +488,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", diff --git a/package.json b/package.json index 7035506..decfd35 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "scripts": { "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", + "test": "npm run compile && node --test test/*.test.js", "watch": "tsc -watch -p ./", "lint": "eslint src --ext ts" }, diff --git a/src/parser.ts b/src/parser.ts index d211bd2..50ffb23 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -41,8 +41,9 @@ export class EftlParser { // Check for unclosed blocks for (const block of this.blockStack) { + const expectedClose = this.getMatchingClose(block.type); this.errors.push({ - message: `Unclosed block: ${block.token.value}`, + message: `Unclosed tag: ${block.token.value} (expected ${expectedClose})`, line: block.token.line, column: block.token.column, length: block.token.length diff --git a/test/parser.test.js b/test/parser.test.js new file mode 100644 index 0000000..4f0b476 --- /dev/null +++ b/test/parser.test.js @@ -0,0 +1,48 @@ +const assert = require('node:assert/strict'); +const test = require('node:test'); + +const { EftlParser } = require('../out/parser'); +const { EftlTokenizer } = require('../out/tokenizer'); + +function parse(source) { + const { tokens, errors: tokenizerErrors } = new EftlTokenizer(source).tokenize(); + assert.deepEqual(tokenizerErrors, []); + return new EftlParser(tokens).parse().errors; +} + +test('accepts a correctly closed VAR tag', () => { + assert.deepEqual(parse('[VAR][/VAR]'), []); +}); + +test('reports a VAR tag without its closing tag', () => { + assert.deepEqual(parse('[VAR]'), [{ + message: 'Unclosed tag: [VAR] (expected [/VAR])', + line: 1, + column: 1, + length: 5 + }]); +}); + +test('reports an unexpected closing tag', () => { + const errors = parse('[/VAR]'); + + assert.equal(errors.length, 1); + assert.match(errors[0].message, /Unexpected closing tag/); +}); + +test('reports every unclosed nested tag at its opening token', () => { + assert.deepEqual(parse('[EFTL]\n[VAR]'), [ + { + message: 'Unclosed tag: [EFTL] (expected [/EFTL])', + line: 1, + column: 1, + length: 6 + }, + { + message: 'Unclosed tag: [VAR] (expected [/VAR])', + line: 2, + column: 1, + length: 5 + } + ]); +}); \ No newline at end of file