From 52d1ddc2c2b6b474a8602abf18ac56ae9fc7c905 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Fri, 23 Feb 2024 01:30:32 -0500 Subject: [PATCH] Implement rest params in abstract closures (#573) --- src/lint/rules/variable-use-def.ts | 15 ++++- test/lint-variable-use-def.js | 96 ++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/src/lint/rules/variable-use-def.ts b/src/lint/rules/variable-use-def.ts index 8058248b..3a9e9361 100644 --- a/src/lint/rules/variable-use-def.ts +++ b/src/lint/rules/variable-use-def.ts @@ -265,9 +265,21 @@ function walkAlgorithm( continue; } // TODO this kind of parsing should really be factored out + let varName = true; for (let i = 0; i < paramList.items.length; ++i) { const item = paramList.items[i]; - if (i % 2 === 0) { + if (varName) { + if (item.name === 'text' && item.contents === '...') { + if (i < paramList.items.length - 2) { + report({ + ruleId: 'bad-ac', + message: `expected rest param to come last`, + ...offsetToLineAndColumn(algorithmSource, item.location.start.offset), + }); + continue stepLoop; + } + continue; + } if (item.name !== 'underscore') { report({ ruleId: 'bad-ac', @@ -287,6 +299,7 @@ function walkAlgorithm( continue stepLoop; } } + varName = !varName; } } diff --git a/test/lint-variable-use-def.js b/test/lint-variable-use-def.js index 7679990a..81f77c3b 100644 --- a/test/lint-variable-use-def.js +++ b/test/lint-variable-use-def.js @@ -401,6 +401,102 @@ describe('variables are declared and used appropriately', () => { ); }); + it('abstract closure rest parameters must be last', async () => { + await assertLint( + positioned` + +

Object.fromEntries ( _obj_ )

+ + 1. Let _closure_ be a new Abstract Closure with parameters (${M}..._x_, _y_) that captures nothing and performs the following steps when called: + 1. Do something with _x_. + 1. Return *undefined*. + 1. Return _closure_. + +
+ `, + { + ruleId: 'bad-ac', + nodeType: 'emu-alg', + message: 'expected rest param to come last', + }, + ); + + await assertLint( + positioned` + +

Object.fromEntries ( _obj_ )

+ + 1. Let _closure_ be a new Abstract Closure with parameters (${M}..._x_,) that captures nothing and performs the following steps when called: + 1. Do something with _x_. + 1. Return *undefined*. + 1. Return _closure_. + +
+ `, + { + ruleId: 'bad-ac', + nodeType: 'emu-alg', + message: 'expected rest param to come last', + }, + ); + }); + + it('abstract closure rest parameters must be variables', async () => { + await assertLint( + positioned` + +

Object.fromEntries ( _obj_ )

+ + 1. Let _closure_ be a new Abstract Closure with parameters (${M}...x) that captures nothing and performs the following steps when called: + 1. Do something with _x_. + 1. Return *undefined*. + 1. Return _closure_. + +
+ `, + { + ruleId: 'bad-ac', + nodeType: 'emu-alg', + message: 'expected to find a parameter name here', + }, + ); + + await assertLint( + positioned` + +

Object.fromEntries ( _obj_ )

+ + 1. Let _closure_ be a new Abstract Closure with parameters (${M}..._x_,) that captures nothing and performs the following steps when called: + 1. Do something with _x_. + 1. Return *undefined*. + 1. Return _closure_. + +
+ `, + { + ruleId: 'bad-ac', + nodeType: 'emu-alg', + message: 'expected rest param to come last', + }, + ); + }); + + it('abstract closure rest parameters are visible', async () => { + await assertLintFree( + ` + +

Object.fromEntries ( _obj_ )

+ + 1. Let _closure_ be a new Abstract Closure with parameters (..._x_) that captures nothing and performs the following steps when called: + 1. Do something with _x_. + 1. Return *undefined*. + 1. Return _closure_. + +
+ `, + ); + }); + it('multiple declarations are visible', async () => { await assertLintFree( `