const assert = require('node:assert/strict'); const fs = require('node:fs'); const test = require('node:test'); const oniguruma = require('vscode-oniguruma'); const textmate = require('vscode-textmate'); async function loadGrammar() { await oniguruma.loadWASM(fs.readFileSync(require.resolve('vscode-oniguruma/release/onig.wasm')).buffer); const registry = new textmate.Registry({ onigLib: Promise.resolve({ createOnigScanner: patterns => new oniguruma.OnigScanner(patterns), createOnigString: value => new oniguruma.OnigString(value) }), loadGrammar: async scopeName => scopeName === 'source.eftl' ? textmate.parseRawGrammar( fs.readFileSync('syntaxes/eftl.tmLanguage.json', 'utf8'), 'eftl.tmLanguage.json' ) : null }); return registry.loadGrammar('source.eftl'); } test('highlights nested VAR blocks, self-closing functions, and WHILE attributes', async () => { const grammar = await loadGrammar(); const source = [ '[EFTL]', '[VAR name="count" type="number"][SIZE_OF varname="items" /][/VAR]', '[WHILE threshold="99"][CONDITION][% count > 0 %][/CONDITION][DO]', '[VAR name="current" type="string"][VALUE_OF varname="items" index="count" /][/VAR]', '[/DO][/WHILE]', '[IF][CONDITION][% count == 0 %][/CONDITION][THEN]', '[VAR name="empty" type="boolean"][% empty = true; %][/VAR]', '[/THEN][/IF]', '[/EFTL]' ]; let ruleStack = textmate.INITIAL; const variableTokens = []; const selfClosingFunctionTokens = []; const thresholdTokens = []; const thresholdValueTokens = []; const whileTokens = []; for (const line of source) { const result = grammar.tokenizeLine(line, ruleStack); ruleStack = result.ruleStack; for (const token of result.tokens) { const text = line.slice(token.startIndex, token.endIndex); if (text === 'VAR' && line[token.startIndex - 1] !== '/') variableTokens.push(token); if (text === 'SIZE_OF' || text === 'VALUE_OF') selfClosingFunctionTokens.push(token); if (text === 'threshold') thresholdTokens.push(token); if (text === '"99"') thresholdValueTokens.push(token); if (text === 'WHILE') whileTokens.push(token); } } assert.equal(variableTokens.length, 3); for (const token of variableTokens) { assert.ok(token.scopes.includes('storage.type.variable.eftl')); } for (const token of selfClosingFunctionTokens) { assert.ok(token.scopes.includes('meta.function.eftl')); assert.ok(!token.scopes.includes('meta.function.block.eftl')); } assert.equal(thresholdTokens.length, 1); assert.ok(thresholdTokens[0].scopes.includes('entity.other.attribute-name.eftl')); assert.equal(thresholdValueTokens.length, 1); assert.ok(thresholdValueTokens[0].scopes.includes('string.quoted.double.eftl')); assert.equal(whileTokens.length, 1); assert.ok(whileTokens[0].scopes.includes('keyword.control.loop.eftl')); });