@@ -29,6 +29,8 @@ function alwaysFalse() {
29
29
/** @type {import('../types').Rule.RuleModule } */
30
30
module . exports = {
31
31
meta : {
32
+ dialects : [ "javascript" , "typescript" ] ,
33
+ language : "javascript" ,
32
34
type : "suggestion" ,
33
35
34
36
docs : {
@@ -83,6 +85,61 @@ module.exports = {
83
85
} ,
84
86
] = context . options ;
85
87
88
+ /**
89
+ * Has AST suggesting a directive.
90
+ * @param {ASTNode } node any node
91
+ * @returns {boolean } whether the given node structurally represents a directive
92
+ */
93
+ function looksLikeDirective ( node ) {
94
+ return (
95
+ node . type === "ExpressionStatement" &&
96
+ node . expression . type === "Literal" &&
97
+ typeof node . expression . value === "string"
98
+ ) ;
99
+ }
100
+
101
+ /**
102
+ * Gets the leading sequence of members in a list that pass the predicate.
103
+ * @param {Function } predicate ([a] -> Boolean) the function used to make the determination
104
+ * @param {a[] } list the input list
105
+ * @returns {a[] } the leading sequence of members in the given list that pass the given predicate
106
+ */
107
+ function takeWhile ( predicate , list ) {
108
+ for ( let i = 0 ; i < list . length ; ++ i ) {
109
+ if ( ! predicate ( list [ i ] ) ) {
110
+ return list . slice ( 0 , i ) ;
111
+ }
112
+ }
113
+ return list . slice ( ) ;
114
+ }
115
+
116
+ /**
117
+ * Gets leading directives nodes in a Node body.
118
+ * @param {ASTNode } node a Program or BlockStatement node
119
+ * @returns {ASTNode[] } the leading sequence of directive nodes in the given node's body
120
+ */
121
+ function directives ( node ) {
122
+ return takeWhile ( looksLikeDirective , node . body ) ;
123
+ }
124
+
125
+ /**
126
+ * Detect if a Node is a directive.
127
+ * @param {ASTNode } node any node
128
+ * @returns {boolean } whether the given node is considered a directive in its current position
129
+ */
130
+ function isDirective ( node ) {
131
+ /**
132
+ * https://tc39.es/ecma262/#directive-prologue
133
+ *
134
+ * Only `FunctionBody`, `ScriptBody` and `ModuleBody` can have directive prologue.
135
+ * Class static blocks do not have directive prologue.
136
+ */
137
+ return (
138
+ astUtils . isTopLevelExpressionStatement ( node ) &&
139
+ directives ( node . parent ) . includes ( node )
140
+ ) ;
141
+ }
142
+
86
143
/**
87
144
* The member functions return `true` if the type has no side-effects.
88
145
* Unknown nodes are handled as `false`, then this rule ignores those.
@@ -154,7 +211,7 @@ module.exports = {
154
211
ExpressionStatement ( node ) {
155
212
if (
156
213
Checker . isDisallowed ( node . expression ) &&
157
- ! astUtils . isDirective ( node )
214
+ ! isDirective ( node )
158
215
) {
159
216
context . report ( { node, messageId : "unusedExpression" } ) ;
160
217
}
0 commit comments