1+ /**
2+ * @file Rule to prevent unsafe array iteration patterns like for...of loops
3+ * which rely on user-mutable global methods (Array.prototype[Symbol.iterator]).
4+ * Instead, traditional for loops should be used for safer iteration.
5+ */
6+ 'use strict' ;
7+
8+ //------------------------------------------------------------------------------
9+ // Rule Definition
10+ //------------------------------------------------------------------------------
11+
12+ const USE_FOR_LOOP = 'Use traditional for loop instead of for...of for array iteration to avoid relying on user-mutable Symbol.iterator.' ;
13+
14+ /**
15+ * Checks if a node represents an array-like expression
16+ * @param {Object } node - The AST node to check
17+ * @returns {boolean } - True if the node appears to be an array
18+ */
19+ function isArrayLike ( node ) {
20+ // Direct array literals
21+ if ( node . type === 'ArrayExpression' ) {
22+ return true ;
23+ }
24+
25+ // Variables/identifiers that might be arrays (we'll be conservative and flag all)
26+ if ( node . type === 'Identifier' ) {
27+ return true ;
28+ }
29+
30+ // Member expressions like obj.array, obj['array']
31+ if ( node . type === 'MemberExpression' ) {
32+ return true ;
33+ }
34+
35+ // Call expressions that might return arrays
36+ if ( node . type === 'CallExpression' ) {
37+ return true ;
38+ }
39+
40+ return false ;
41+ }
42+
43+ module . exports = {
44+ meta : {
45+ type : 'problem' ,
46+ docs : {
47+ description : 'disallow for...of loops on arrays to prevent unsafe iteration' ,
48+ category : 'Possible Errors' ,
49+ } ,
50+ fixable : null , // Not auto-fixable due to complexity of conversion
51+ schema : [ ] ,
52+ } ,
53+
54+ create ( context ) {
55+ return {
56+ ForOfStatement ( node ) {
57+ // Check if we're iterating over something that looks like an array
58+ if ( isArrayLike ( node . right ) ) {
59+ context . report ( {
60+ node,
61+ message : USE_FOR_LOOP ,
62+ } ) ;
63+ }
64+ } ,
65+ } ;
66+ } ,
67+ } ;
0 commit comments