Skip to content

Commit 46771e1

Browse files
committed
✨ improve 'getFunctionNameWithKind'
1 parent 05b8390 commit 46771e1

File tree

3 files changed

+145
-92
lines changed

3 files changed

+145
-92
lines changed

docs/api/ast-utils.md

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -214,16 +214,19 @@ Get the name and kind of a given function node.
214214
- `({ foo: function() {} })` ........................ `method 'foo'`
215215
- `({ ['foo']: function() {} })` .................... `method 'foo'`
216216
- `({ [foo]: function() {} })` ...................... `method`
217+
- `({ [foo]: function() {} })` ...................... `method [foo]` if sourceCode is present.
217218
- `({ foo() {} })` .................................. `method 'foo'`
218219
- `({ foo: function* foo() {} })` ................... `generator method 'foo'`
219220
- `({ foo: function*() {} })` ....................... `generator method 'foo'`
220221
- `({ ['foo']: function*() {} })` ................... `generator method 'foo'`
221222
- `({ [foo]: function*() {} })` ..................... `generator method`
223+
- `({ [foo]: function*() {} })` ..................... `generator method [foo]` if sourceCode is present.
222224
- `({ *foo() {} })` ................................. `generator method 'foo'`
223225
- `({ foo: async function foo() {} })` .............. `async method 'foo'`
224226
- `({ foo: async function() {} })` .................. `async method 'foo'`
225227
- `({ ['foo']: async function() {} })` .............. `async method 'foo'`
226228
- `({ [foo]: async function() {} })` ................ `async method`
229+
- `({ [foo]: async function() {} })` ................ `async method [foo]` if sourceCode is present.
227230
- `({ async foo() {} })` ............................ `async method 'foo'`
228231
- `({ get foo() {} })` .............................. `getter 'foo'`
229232
- `({ set foo(a) {} })` ............................. `setter 'foo'`
@@ -235,31 +238,36 @@ Get the name and kind of a given function node.
235238
- `class A { *['foo']() {} }` ....................... `generator method 'foo'`
236239
- `class A { async ['foo']() {} }` .................. `async method 'foo'`
237240
- `class A { [foo]() {} }` .......................... `method`
241+
- `class A { [foo]() {} }` .......................... `method [foo]` if sourceCode is present.
238242
- `class A { *[foo]() {} }` ......................... `generator method`
243+
- `class A { *[foo]() {} }` ......................... `generator method [foo]` if sourceCode is present.
239244
- `class A { async [foo]() {} }` .................... `async method`
245+
- `class A { async [foo]() {} }` .................... `async method [foo]` if sourceCode is present.
240246
- `class A { get foo() {} }` ........................ `getter 'foo'`
241247
- `class A { set foo(a) {} }` ....................... `setter 'foo'`
242248
- `class A { static foo() {} }` ..................... `static method 'foo'`
243249
- `class A { static *foo() {} }` .................... `static generator method 'foo'`
244250
- `class A { static async foo() {} }` ............... `static async method 'foo'`
245251
- `class A { static get foo() {} }` ................. `static getter 'foo'`
246252
- `class A { static set foo(a) {} }` ................ `static setter 'foo'`
247-
- `class A { #foo() {} }` ........................... `private method '#foo'`
248-
- `class A { *#foo() {} }` .......................... `private generator method '#foo'`
249-
- `class A { async #foo() {} }` ..................... `private async method '#foo'`
250-
- `class A { get #foo() {} }` ....................... `private getter '#foo'`
251-
- `class A { set #foo(a) {} }` ...................... `private setter '#foo'`
252-
- `class A { static #foo() {} }` .................... `private static method '#foo'`
253-
- `class A { static *#foo() {} }` ................... `private static generator method '#foo'`
254-
- `class A { static async #foo() {} }` .............. `private static async method '#foo'`
255-
- `class A { static get #foo() {} }` ................ `private static getter '#foo'`
256-
- `class A { static set #foo(a) {} }` ............... `private static setter '#foo'`
257-
- `class A { #foo = function() {} }` ................ `private method '#foo'"`
258-
- `class A { #foo = function*() {} }` ............... `private generator method '#foo'"`
259-
- `class A { #foo = async function() {} }` .......... `private async method '#foo'"`
260-
- `class A { static #foo = function() {} }` ......... `private static method '#foo'"`
261-
- `class A { static #foo = function*() {} }` ........ `private static generator method '#foo'"`
262-
- `class A { static #foo = async function() {} }` ... `private static async method '#foo'"`
253+
- `class A { #foo() {} }` ........................... `private method #foo`
254+
- `class A { '#foo'() {} }` ......................... `method '#foo'`
255+
- `class A { *#foo() {} }` .......................... `private generator method #foo`
256+
- `class A { async #foo() {} }` ..................... `private async method #foo`
257+
- `class A { get #foo() {} }` ....................... `private getter #foo`
258+
- `class A { set #foo(a) {} }` ...................... `private setter #foo`
259+
- `class A { static #foo() {} }` .................... `static private method #foo`
260+
- `class A { static *#foo() {} }` ................... `static private generator method #foo`
261+
- `class A { static async #foo() {} }` .............. `static private async method #foo`
262+
- `class A { static get #foo() {} }` ................ `static private getter #foo`
263+
- `class A { static set #foo(a) {} }` ............... `static private setter #foo`
264+
- `class A { '#foo' = function() {} }` .............. `method '#foo'"`
265+
- `class A { #foo = function() {} }` ................ `private method #foo"`
266+
- `class A { #foo = function*() {} }` ............... `private generator method #foo"`
267+
- `class A { #foo = async function() {} }` .......... `private async method #foo"`
268+
- `class A { static #foo = function() {} }` ......... `static private method #foo"`
269+
- `class A { static #foo = function*() {} }` ........ `static private generator method #foo"`
270+
- `class A { static #foo = async function() {} }` ... `static private async method #foo"`
263271
```
264272

265273
</details>
@@ -269,6 +277,7 @@ Get the name and kind of a given function node.
269277
Name | Type | Description
270278
:-----|:-----|:------------
271279
node | Node | The function node to get the name and kind. This should be any of `FunctionDeclaration`, `FunctionExpression`, and `ArrowFunctionExpression` node.
280+
sourceCode | SourceCode | Optional. The source code object to get the text of computed property keys.
272281

273282
### Return value
274283

@@ -282,12 +291,14 @@ const { getFunctionNameWithKind } = require("eslint-utils")
282291
module.exports = {
283292
meta: {},
284293
create(context) {
294+
const sourceCode = context.getSourceCode()
295+
285296
return {
286297
FunctionDeclaration(node) {
287298
context.report({
288299
node,
289300
message: "disallow this {{name}}!",
290-
data: { name: getFunctionNameWithKind(node) }
301+
data: { name: getFunctionNameWithKind(node, sourceCode) }
291302
})
292303
},
293304
}

src/get-function-name-with-kind.js

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,27 @@ import { getPropertyName } from "./get-property-name"
33
/**
44
* Get the name and kind of the given function node.
55
* @param {ASTNode} node - The function node to get.
6+
* @param {SourceCode} [sourceCode] The source code object to get the code of computed property keys.
67
* @returns {string} The name and kind of the function node.
78
*/
8-
export function getFunctionNameWithKind(node) {
9+
// eslint-disable-next-line complexity
10+
export function getFunctionNameWithKind(node, sourceCode) {
911
const parent = node.parent
1012
const tokens = []
11-
const isFieldDefinition =
12-
parent.type === "MethodDefinition" ||
13-
parent.type === "PropertyDefinition"
14-
let privateName = null
15-
if (isFieldDefinition) {
16-
if (parent.key.type === "PrivateIdentifier") {
17-
privateName = `#${parent.key.name}`
18-
tokens.push("private")
19-
}
13+
const isObjectMethod = parent.type === "Property" && parent.value === node
14+
const isClassMethod =
15+
parent.type === "MethodDefinition" && parent.value === node
16+
const isClassFieldMethod =
17+
parent.type === "PropertyDefinition" && parent.value === node
18+
19+
// Modifiers.
20+
if (isClassMethod || isClassFieldMethod) {
2021
if (parent.static) {
2122
tokens.push("static")
2223
}
24+
if (parent.key.type === "PrivateIdentifier") {
25+
tokens.push("private")
26+
}
2327
}
2428
if (node.async) {
2529
tokens.push("async")
@@ -28,9 +32,8 @@ export function getFunctionNameWithKind(node) {
2832
tokens.push("generator")
2933
}
3034

31-
if (node.type === "ArrowFunctionExpression") {
32-
tokens.push("arrow", "function")
33-
} else if (parent.type === "Property" || isFieldDefinition) {
35+
// Kinds.
36+
if (isObjectMethod || isClassMethod) {
3437
if (parent.kind === "constructor") {
3538
return "constructor"
3639
}
@@ -41,38 +44,45 @@ export function getFunctionNameWithKind(node) {
4144
} else {
4245
tokens.push("method")
4346
}
47+
} else if (isClassFieldMethod) {
48+
tokens.push("method")
4449
} else {
50+
if (node.type === "ArrowFunctionExpression") {
51+
tokens.push("arrow")
52+
}
4553
tokens.push("function")
4654
}
4755

48-
if (node.id) {
49-
tokens.push(`'${node.id.name}'`)
50-
} else {
51-
const name = privateName || getPropertyName(parent)
52-
53-
if (name) {
54-
tokens.push(`'${name}'`)
56+
// Names.
57+
if (isObjectMethod || isClassMethod || isClassFieldMethod) {
58+
if (parent.key.type === "PrivateIdentifier") {
59+
tokens.push(`#${parent.key.name}`)
60+
} else {
61+
const name = getPropertyName(parent)
62+
if (name) {
63+
tokens.push(`'${name}'`)
64+
} else if (sourceCode) {
65+
const keyText = sourceCode.getText(parent.key)
66+
if (!keyText.includes("\n")) {
67+
tokens.push(`[${keyText}]`)
68+
}
69+
}
5570
}
56-
}
57-
58-
if (
59-
node.type === "ArrowFunctionExpression" ||
60-
(node.type === "FunctionExpression" && node.id === null)
71+
} else if (node.id) {
72+
tokens.push(`'${node.id.name}'`)
73+
} else if (
74+
parent.type === "VariableDeclarator" &&
75+
parent.id &&
76+
parent.id.type === "Identifier"
6177
) {
62-
if (
63-
parent.type === "VariableDeclarator" &&
64-
parent.id &&
65-
parent.id.type === "Identifier"
66-
) {
67-
tokens.push(`'${parent.id.name}'`)
68-
}
69-
if (
70-
parent.type === "AssignmentExpression" &&
71-
parent.left &&
72-
parent.left.type === "Identifier"
73-
) {
74-
tokens.push(`'${parent.left.name}'`)
75-
}
78+
tokens.push(`'${parent.id.name}'`)
79+
} else if (
80+
(parent.type === "AssignmentExpression" ||
81+
parent.type === "AssignmentPattern") &&
82+
parent.left &&
83+
parent.left.type === "Identifier"
84+
) {
85+
tokens.push(`'${parent.left.name}'`)
7686
}
7787

7888
return tokens.join(" ")

test/get-function-name-with-kind.js

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,17 @@ describe("The 'getFunctionNameWithKind' function", () => {
3434
"({ foo: function foo() {} })": "method 'foo'",
3535
"({ foo: function() {} })": "method 'foo'",
3636
"({ ['foo']: function() {} })": "method 'foo'",
37-
"({ [foo]: function() {} })": "method",
37+
"({ [foo]: function() {} })": "method [foo]",
3838
"({ foo() {} })": "method 'foo'",
3939
"({ foo: function* foo() {} })": "generator method 'foo'",
4040
"({ foo: function*() {} })": "generator method 'foo'",
4141
"({ ['foo']: function*() {} })": "generator method 'foo'",
42-
"({ [foo]: function*() {} })": "generator method",
42+
"({ [foo]: function*() {} })": "generator method [foo]",
4343
"({ *foo() {} })": "generator method 'foo'",
4444
"({ foo: async function foo() {} })": "async method 'foo'",
4545
"({ foo: async function() {} })": "async method 'foo'",
4646
"({ ['foo']: async function() {} })": "async method 'foo'",
47-
"({ [foo]: async function() {} })": "async method",
47+
"({ [foo]: async function() {} })": "async method [foo]",
4848
"({ async foo() {} })": "async method 'foo'",
4949
"({ get foo() {} })": "getter 'foo'",
5050
"({ set foo(a) {} })": "setter 'foo'",
@@ -55,9 +55,9 @@ describe("The 'getFunctionNameWithKind' function", () => {
5555
"class A { ['foo']() {} }": "method 'foo'",
5656
"class A { *['foo']() {} }": "generator method 'foo'",
5757
"class A { async ['foo']() {} }": "async method 'foo'",
58-
"class A { [foo]() {} }": "method",
59-
"class A { *[foo]() {} }": "generator method",
60-
"class A { async [foo]() {} }": "async method",
58+
"class A { [foo]() {} }": "method [foo]",
59+
"class A { *[foo]() {} }": "generator method [foo]",
60+
"class A { async [foo]() {} }": "async method [foo]",
6161
"class A { get foo() {} }": "getter 'foo'",
6262
"class A { set foo(a) {} }": "setter 'foo'",
6363
"class A { static foo() {} }": "static method 'foo'",
@@ -69,64 +69,67 @@ describe("The 'getFunctionNameWithKind' function", () => {
6969

7070
semver.gte(eslint.CLIEngine.version, "7.0.0")
7171
? {
72-
"class A { #foo() {} }": "private method '#foo'",
73-
"class A { *#foo() {} }": "private generator method '#foo'",
74-
"class A { async #foo() {} }": "private async method '#foo'",
75-
"class A { get #foo() {} }": "private getter '#foo'",
76-
"class A { set #foo(a) {} }": "private setter '#foo'",
77-
"class A { static #foo() {} }":
78-
"private static method '#foo'",
72+
"class A { #foo() {} }": "private method #foo",
73+
"class A { '#foo'() {} }": "method '#foo'",
74+
"class A { *#foo() {} }": "private generator method #foo",
75+
"class A { async #foo() {} }": "private async method #foo",
76+
"class A { get #foo() {} }": "private getter #foo",
77+
"class A { set #foo(a) {} }": "private setter #foo",
78+
"class A { static #foo() {} }": "static private method #foo",
7979
"class A { static *#foo() {} }":
80-
"private static generator method '#foo'",
80+
"static private generator method #foo",
8181
"class A { static async #foo() {} }":
82-
"private static async method '#foo'",
82+
"static private async method #foo",
8383
"class A { static get #foo() {} }":
84-
"private static getter '#foo'",
84+
"static private getter #foo",
8585
"class A { static set #foo(a) {} }":
86-
"private static setter '#foo'",
86+
"static private setter #foo",
8787
"class A { foo = function() {} }": "method 'foo'",
88-
"class A { foo = () => {} }": "arrow function 'foo'",
88+
"class A { foo = () => {} }": "method 'foo'",
8989
"class A { foo = function*() {} }": "generator method 'foo'",
9090
"class A { foo = async function() {} }": "async method 'foo'",
9191
"class A { ['foo'] = function() {} }": "method 'foo'",
92-
"class A { ['foo'] = () => {} }": "arrow function 'foo'",
92+
"class A { ['foo'] = () => {} }": "method 'foo'",
9393
"class A { ['foo'] = function*() {} }":
9494
"generator method 'foo'",
9595
"class A { ['foo'] = async function() {} }":
9696
"async method 'foo'",
97-
"class A { [foo] = function() {} }": "method",
98-
"class A { [foo] = () => {} }": "arrow function",
99-
"class A { [foo] = function*() {} }": "generator method",
100-
"class A { [foo] = async function() {} }": "async method",
97+
"class A { [foo] = function() {} }": "method [foo]",
98+
"class A { [foo] = () => {} }": "method [foo]",
99+
"class A { [foo] = function*() {} }":
100+
"generator method [foo]",
101+
"class A { [foo] = async function() {} }":
102+
"async method [foo]",
101103
"class A { static foo = function() {} }":
102104
"static method 'foo'",
103-
"class A { static foo = () => {} }":
104-
"static arrow function 'foo'",
105+
"class A { static foo = () => {} }": "static method 'foo'",
105106
"class A { static foo = function*() {} }":
106107
"static generator method 'foo'",
107108
"class A { static foo = async function() {} }":
108109
"static async method 'foo'",
109-
"class A { #foo = function() {} }": "private method '#foo'",
110-
"class A { #foo = () => {} }":
111-
"private arrow function '#foo'",
110+
"class A { #foo = function() {} }": "private method #foo",
111+
"class A { #foo = () => {} }": "private method #foo",
112112
"class A { #foo = function*() {} }":
113-
"private generator method '#foo'",
113+
"private generator method #foo",
114114
"class A { #foo = async function() {} }":
115-
"private async method '#foo'",
115+
"private async method #foo",
116116
"class A { static #foo = function() {} }":
117-
"private static method '#foo'",
117+
"static private method #foo",
118118
"class A { static #foo = () => {} }":
119-
"private static arrow function '#foo'",
119+
"static private method #foo",
120120
"class A { static #foo = function*() {} }":
121-
"private static generator method '#foo'",
121+
"static private generator method #foo",
122122
"class A { static #foo = async function() {} }":
123-
"private static async method '#foo'",
123+
"static private async method #foo",
124124
}
125125
: {}
126126
)
127127

128128
for (const key of Object.keys(expectedResults)) {
129-
it(`should return "${expectedResults[key]}" for "${key}".`, () => {
129+
const expectedResult1 = expectedResults[key].replace(/\s+\[.+?\]/gu, "")
130+
const expectedResult2 = expectedResults[key]
131+
132+
it(`should return "${expectedResult1}" for "${key}".`, () => {
130133
const linter = new eslint.Linter()
131134

132135
let actualResult = null
@@ -149,7 +152,36 @@ describe("The 'getFunctionNameWithKind' function", () => {
149152
0,
150153
messages[0] && messages[0].message
151154
)
152-
assert.strictEqual(actualResult, expectedResults[key])
155+
assert.strictEqual(actualResult, expectedResult1)
156+
})
157+
158+
it(`should return "${expectedResult2}" for "${key}" if sourceCode is present.`, () => {
159+
const linter = new eslint.Linter()
160+
161+
let actualResult = null
162+
linter.defineRule("test", context => ({
163+
":function"(node) {
164+
actualResult = getFunctionNameWithKind(
165+
node,
166+
context.getSourceCode()
167+
)
168+
},
169+
}))
170+
const messages = linter.verify(key, {
171+
rules: { test: "error" },
172+
parserOptions: {
173+
ecmaVersion: semver.gte(eslint.CLIEngine.version, "7.0.0")
174+
? 2022
175+
: 2018,
176+
},
177+
})
178+
179+
assert.strictEqual(
180+
messages.length,
181+
0,
182+
messages[0] && messages[0].message
183+
)
184+
assert.strictEqual(actualResult, expectedResult2)
153185
})
154186
}
155187
})

0 commit comments

Comments
 (0)