@mui/internal-babel-plugin-display-name 1.0.4-canary.2 → 1.0.4-canary.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +18 -13
- package/src/index.d.ts +13 -0
- package/src/index.js +86 -68
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,33 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mui/internal-babel-plugin-display-name",
|
|
3
|
-
"version": "1.0.4-canary.
|
|
3
|
+
"version": "1.0.4-canary.20",
|
|
4
|
+
"author": "MUI Team",
|
|
4
5
|
"description": "Babel plugin for automatic React display name generation with tree-shaking and prefix support, forked from @zendesk/babel-plugin-react-displayname.",
|
|
6
|
+
"license": "Apache-2.0",
|
|
5
7
|
"repository": {
|
|
6
8
|
"type": "git",
|
|
7
9
|
"url": "git+https://github.com/mui/mui-public.git",
|
|
8
10
|
"directory": "packages/babel-plugin-display-name"
|
|
9
11
|
},
|
|
10
12
|
"main": "src/index.js",
|
|
11
|
-
"
|
|
13
|
+
"types": "src/index.d.ts",
|
|
12
14
|
"files": [
|
|
13
|
-
"src/index.js"
|
|
15
|
+
"src/index.js",
|
|
16
|
+
"src/index.d.ts",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
"README.md"
|
|
14
19
|
],
|
|
15
20
|
"dependencies": {
|
|
16
|
-
"@babel/helper-module-imports": "^7.
|
|
17
|
-
"@babel/helper-plugin-utils": "^7.
|
|
21
|
+
"@babel/helper-module-imports": "^7.28.6",
|
|
22
|
+
"@babel/helper-plugin-utils": "^7.28.6"
|
|
18
23
|
},
|
|
19
24
|
"devDependencies": {
|
|
20
|
-
"@babel/core": "
|
|
21
|
-
"@babel/preset-env": "
|
|
22
|
-
"@babel/preset-react": "
|
|
23
|
-
"@types/babel__core": "
|
|
24
|
-
"@types/babel__helper-plugin-utils": "
|
|
25
|
+
"@babel/core": "7.29.0",
|
|
26
|
+
"@babel/preset-env": "7.29.5",
|
|
27
|
+
"@babel/preset-react": "7.28.5",
|
|
28
|
+
"@types/babel__core": "7.20.5",
|
|
29
|
+
"@types/babel__helper-plugin-utils": "7.10.3"
|
|
25
30
|
},
|
|
26
31
|
"peerDependencies": {
|
|
27
32
|
"@babel/core": "7",
|
|
28
33
|
"@babel/preset-react": "7"
|
|
29
34
|
},
|
|
30
|
-
"license": "Apache-2.0",
|
|
31
35
|
"keywords": [
|
|
32
36
|
"displayName",
|
|
33
37
|
"babel",
|
|
@@ -35,8 +39,9 @@
|
|
|
35
39
|
"babel-plugin"
|
|
36
40
|
],
|
|
37
41
|
"homepage": "https://github.com/mui/mui-public",
|
|
38
|
-
"gitSha": "
|
|
42
|
+
"gitSha": "350e6291912c0c23528bda9573d07ce786aeb386",
|
|
39
43
|
"scripts": {
|
|
40
|
-
"test": "jest"
|
|
44
|
+
"test": "jest",
|
|
45
|
+
"typescript": "tsgo -noEmit"
|
|
41
46
|
}
|
|
42
47
|
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PluginObj } from '@babel/core';
|
|
2
|
+
|
|
3
|
+
interface AllowedCallees {
|
|
4
|
+
[moduleName: string]: string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface PluginOptions {
|
|
8
|
+
allowedCallees?: AllowedCallees;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
declare const plugin: (options?: PluginOptions) => PluginObj;
|
|
12
|
+
|
|
13
|
+
export default plugin;
|
package/src/index.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
const { declare } = require('@babel/helper-plugin-utils');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @typedef {import('@babel/core')} babel
|
|
7
|
-
* @typedef {
|
|
6
|
+
* @typedef {typeof import('@babel/core')} babel
|
|
7
|
+
* @typedef {typeof import('@babel/core').types} BabelTypes
|
|
8
|
+
* @typedef {{ id: import('@babel/core').types.Expression, computed?: boolean }} ComponentIdentifier
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
// remember to set `cacheDirectory` to `false` when modifying this plugin
|
|
@@ -17,6 +18,10 @@ const DEFAULT_ALLOWED_CALLEES = {
|
|
|
17
18
|
const calleeModuleMapping = new Map(); // Mapping of callee name to module name
|
|
18
19
|
const seenDisplayNames = new Set();
|
|
19
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Applies allowed callees mapping to the internal calleeModuleMapping.
|
|
23
|
+
* @param {Record<string, string[]>} mapping - The mapping of module names to method names.
|
|
24
|
+
*/
|
|
20
25
|
function applyAllowedCallees(mapping) {
|
|
21
26
|
Object.entries(mapping).forEach(([moduleName, methodNames]) => {
|
|
22
27
|
methodNames.forEach((methodName) => {
|
|
@@ -27,57 +32,59 @@ function applyAllowedCallees(mapping) {
|
|
|
27
32
|
});
|
|
28
33
|
}
|
|
29
34
|
|
|
30
|
-
module.exports =
|
|
31
|
-
api.
|
|
32
|
-
|
|
33
|
-
calleeModuleMapping.clear();
|
|
35
|
+
module.exports = /** @type {any} */ (
|
|
36
|
+
declare((api, /** @type {import('./index.d.ts').PluginOptions} */ options) => {
|
|
37
|
+
api.assertVersion(7);
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
calleeModuleMapping.clear();
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
applyAllowedCallees(options.allowedCallees);
|
|
39
|
-
}
|
|
41
|
+
applyAllowedCallees(DEFAULT_ALLOWED_CALLEES);
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
if (options.allowedCallees) {
|
|
44
|
+
applyAllowedCallees(options.allowedCallees);
|
|
45
|
+
}
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
const t = api.types;
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
name: '@probablyup/babel-plugin-react-displayname',
|
|
51
|
+
visitor: {
|
|
52
|
+
Program() {
|
|
53
|
+
// We allow duplicate names across files,
|
|
54
|
+
// so we clear when we're transforming on a new file
|
|
55
|
+
seenDisplayNames.clear();
|
|
56
|
+
},
|
|
57
|
+
'FunctionExpression|ArrowFunctionExpression|ObjectMethod': (
|
|
58
|
+
/** @type {import('@babel/core').NodePath<import('@babel/core').types.FunctionExpression|import('@babel/core').types.ArrowFunctionExpression|import('@babel/core').types.ObjectMethod>} */ path,
|
|
59
|
+
) => {
|
|
60
|
+
// if the parent is a call expression, make sure it's an allowed one
|
|
61
|
+
if (
|
|
62
|
+
path.parentPath && path.parentPath.isCallExpression()
|
|
63
|
+
? isAllowedCallExpression(t, path.parentPath)
|
|
64
|
+
: true
|
|
65
|
+
) {
|
|
66
|
+
if (doesReturnJSX(t, path.node.body)) {
|
|
67
|
+
addDisplayNamesToFunctionComponent(t, path);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
CallExpression(path) {
|
|
72
|
+
if (isAllowedCallExpression(t, path)) {
|
|
61
73
|
addDisplayNamesToFunctionComponent(t, path);
|
|
62
74
|
}
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
CallExpression(path) {
|
|
66
|
-
if (isAllowedCallExpression(t, path)) {
|
|
67
|
-
addDisplayNamesToFunctionComponent(t, path);
|
|
68
|
-
}
|
|
75
|
+
},
|
|
69
76
|
},
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
77
|
+
};
|
|
78
|
+
})
|
|
79
|
+
);
|
|
73
80
|
|
|
74
81
|
/**
|
|
75
82
|
* Checks if this function returns JSX nodes.
|
|
76
83
|
* It does not do type-checking, which means calling
|
|
77
84
|
* other functions that return JSX will still return `false`.
|
|
78
85
|
*
|
|
79
|
-
* @param {
|
|
80
|
-
* @param {babel.types.Statement | babel.types.Expression} node function node
|
|
86
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
87
|
+
* @param {import('@babel/core').types.Statement | import('@babel/core').types.Expression} node function node
|
|
81
88
|
*/
|
|
82
89
|
function doesReturnJSX(t, node) {
|
|
83
90
|
if (!node) {
|
|
@@ -90,7 +97,7 @@ function doesReturnJSX(t, node) {
|
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
return body.some((statement) => {
|
|
93
|
-
/** @type {babel.Node | null | undefined} */
|
|
100
|
+
/** @type {import('@babel/core').types.Node | null | undefined} */
|
|
94
101
|
let currentNode;
|
|
95
102
|
|
|
96
103
|
if (t.isReturnStatement(statement)) {
|
|
@@ -132,8 +139,8 @@ function doesReturnJSX(t, node) {
|
|
|
132
139
|
* Checks if this node is JSXElement or JSXFragment,
|
|
133
140
|
* which are the root nodes of react components.
|
|
134
141
|
*
|
|
135
|
-
* @param {
|
|
136
|
-
* @param {babel.Node | null | undefined} node babel node
|
|
142
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
143
|
+
* @param {import('@babel/core').types.Node | null | undefined} node babel node
|
|
137
144
|
*/
|
|
138
145
|
function isJSX(t, node) {
|
|
139
146
|
return t.isJSXElement(node) || t.isJSXFragment(node);
|
|
@@ -142,12 +149,12 @@ function isJSX(t, node) {
|
|
|
142
149
|
/**
|
|
143
150
|
* Checks if this path is an allowed CallExpression.
|
|
144
151
|
*
|
|
145
|
-
* @param {
|
|
146
|
-
* @param {babel.NodePath<babel.types.CallExpression>} path path of callee
|
|
152
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
153
|
+
* @param {import('@babel/core').NodePath<import('@babel/core').types.CallExpression>} path path of callee
|
|
147
154
|
*/
|
|
148
155
|
function isAllowedCallExpression(t, path) {
|
|
149
156
|
const calleePath = path.get('callee');
|
|
150
|
-
const callee = /** @type {babel.types.Expression} */ (path.node.callee);
|
|
157
|
+
const callee = /** @type {import('@babel/core').types.Expression} */ (path.node.callee);
|
|
151
158
|
/** @type {string | undefined} */
|
|
152
159
|
const calleeName = /** @type {any} */ (callee).name || /** @type {any} */ (callee).property?.name;
|
|
153
160
|
const moduleNames = calleeName && calleeModuleMapping.get(calleeName);
|
|
@@ -183,8 +190,8 @@ function isAllowedCallExpression(t, path) {
|
|
|
183
190
|
* - not within other JSX elements
|
|
184
191
|
* - not called by a react hook or _createClass helper
|
|
185
192
|
*
|
|
186
|
-
* @param {
|
|
187
|
-
* @param {babel.NodePath<babel.types.FunctionExpression|babel.types.ArrowFunctionExpression|babel.types.ObjectMethod|babel.types.CallExpression>} path path of function
|
|
193
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
194
|
+
* @param {import('@babel/core').NodePath<import('@babel/core').types.FunctionExpression|import('@babel/core').types.ArrowFunctionExpression|import('@babel/core').types.ObjectMethod|import('@babel/core').types.CallExpression>} path path of function
|
|
188
195
|
*/
|
|
189
196
|
function addDisplayNamesToFunctionComponent(t, path) {
|
|
190
197
|
/** @type {ComponentIdentifier[]} */
|
|
@@ -193,7 +200,7 @@ function addDisplayNamesToFunctionComponent(t, path) {
|
|
|
193
200
|
componentIdentifiers.push({ id: /** @type {any} */ (path.node).key });
|
|
194
201
|
}
|
|
195
202
|
|
|
196
|
-
/** @type {babel.NodePath | undefined} */
|
|
203
|
+
/** @type {import('@babel/core').NodePath | undefined} */
|
|
197
204
|
let assignmentPath;
|
|
198
205
|
let hasCallee = false;
|
|
199
206
|
let hasObjectProperty = false;
|
|
@@ -232,7 +239,7 @@ function addDisplayNamesToFunctionComponent(t, path) {
|
|
|
232
239
|
if (parentPath.isAssignmentExpression()) {
|
|
233
240
|
assignmentPath = parentPath.parentPath;
|
|
234
241
|
componentIdentifiers.unshift({
|
|
235
|
-
id: /** @type {babel.types.Expression} */ (parentPath.node.left),
|
|
242
|
+
id: /** @type {import('@babel/core').types.Expression} */ (parentPath.node.left),
|
|
236
243
|
});
|
|
237
244
|
return true;
|
|
238
245
|
}
|
|
@@ -254,7 +261,7 @@ function addDisplayNamesToFunctionComponent(t, path) {
|
|
|
254
261
|
}
|
|
255
262
|
assignmentPath = parentPath.parentPath;
|
|
256
263
|
componentIdentifiers.unshift({
|
|
257
|
-
id: /** @type {babel.types.Expression} */ (parentPath.node.id),
|
|
264
|
+
id: /** @type {import('@babel/core').types.Expression} */ (parentPath.node.id),
|
|
258
265
|
});
|
|
259
266
|
return true;
|
|
260
267
|
}
|
|
@@ -269,7 +276,7 @@ function addDisplayNamesToFunctionComponent(t, path) {
|
|
|
269
276
|
hasObjectProperty = true;
|
|
270
277
|
const node = parentPath.node;
|
|
271
278
|
componentIdentifiers.unshift({
|
|
272
|
-
id: /** @type {babel.types.Expression} */ (node.key),
|
|
279
|
+
id: /** @type {import('@babel/core').types.Expression} */ (node.key),
|
|
273
280
|
computed: node.computed,
|
|
274
281
|
});
|
|
275
282
|
}
|
|
@@ -313,7 +320,7 @@ function addDisplayNamesToFunctionComponent(t, path) {
|
|
|
313
320
|
/**
|
|
314
321
|
* Generate a displayName string based on the ids collected.
|
|
315
322
|
*
|
|
316
|
-
* @param {
|
|
323
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
317
324
|
* @param {ComponentIdentifier[]} componentIdentifiers list of { id, computed } objects
|
|
318
325
|
*/
|
|
319
326
|
function generateDisplayName(t, componentIdentifiers) {
|
|
@@ -333,8 +340,9 @@ function generateDisplayName(t, componentIdentifiers) {
|
|
|
333
340
|
/**
|
|
334
341
|
* Generate a displayName string based on the node.
|
|
335
342
|
*
|
|
336
|
-
* @param {
|
|
337
|
-
* @param {babel.Node} node identifier or member expression node
|
|
343
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
344
|
+
* @param {import('@babel/core').types.Node} node identifier or member expression node
|
|
345
|
+
* @returns {string}
|
|
338
346
|
*/
|
|
339
347
|
function generateNodeDisplayName(t, node) {
|
|
340
348
|
if (t.isIdentifier(node)) {
|
|
@@ -357,47 +365,51 @@ function generateNodeDisplayName(t, node) {
|
|
|
357
365
|
/**
|
|
358
366
|
* Checks if this path has been previously assigned to a particular value.
|
|
359
367
|
*
|
|
360
|
-
* @param {
|
|
361
|
-
* @param {babel.NodePath} assignmentPath path where assignement will take place
|
|
368
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
369
|
+
* @param {import('@babel/core').NodePath} assignmentPath path where assignement will take place
|
|
362
370
|
* @param {string} pattern assignment path in string form e.g. `x.y.z`
|
|
363
371
|
* @param {string} value assignment value to compare with
|
|
364
372
|
* @returns {boolean}
|
|
365
373
|
*/
|
|
366
374
|
function hasBeenAssignedPrev(t, assignmentPath, pattern, value) {
|
|
367
375
|
return assignmentPath.getAllPrevSiblings().some((sibling) => {
|
|
368
|
-
const expression = /** @type {babel.NodePath} */ (sibling.get('expression'));
|
|
376
|
+
const expression = /** @type {import('@babel/core').NodePath} */ (sibling.get('expression'));
|
|
369
377
|
if (!t.isAssignmentExpression(expression.node, { operator: '=' })) {
|
|
370
378
|
return false;
|
|
371
379
|
}
|
|
372
380
|
if (!t.isStringLiteral(expression.node.right, { value })) {
|
|
373
381
|
return false;
|
|
374
382
|
}
|
|
375
|
-
return /** @type {babel.NodePath} */ (expression.get('left')).matchesPattern(
|
|
383
|
+
return /** @type {import('@babel/core').NodePath} */ (expression.get('left')).matchesPattern(
|
|
384
|
+
pattern,
|
|
385
|
+
);
|
|
376
386
|
});
|
|
377
387
|
}
|
|
378
388
|
|
|
379
389
|
/**
|
|
380
390
|
* Checks if this path will be assigned later in the scope.
|
|
381
391
|
*
|
|
382
|
-
* @param {
|
|
383
|
-
* @param {babel.NodePath} assignmentPath path where assignement will take place
|
|
392
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
393
|
+
* @param {import('@babel/core').NodePath} assignmentPath path where assignement will take place
|
|
384
394
|
* @param {string} pattern assignment path in string form e.g. `x.y.z`
|
|
385
395
|
* @returns {boolean}
|
|
386
396
|
*/
|
|
387
397
|
function hasBeenAssignedNext(t, assignmentPath, pattern) {
|
|
388
398
|
return assignmentPath.getAllNextSiblings().some((sibling) => {
|
|
389
|
-
const expression = /** @type {babel.NodePath} */ (sibling.get('expression'));
|
|
399
|
+
const expression = /** @type {import('@babel/core').NodePath} */ (sibling.get('expression'));
|
|
390
400
|
if (!t.isAssignmentExpression(expression.node, { operator: '=' })) {
|
|
391
401
|
return false;
|
|
392
402
|
}
|
|
393
|
-
return /** @type {babel.NodePath} */ (expression.get('left')).matchesPattern(
|
|
403
|
+
return /** @type {import('@babel/core').NodePath} */ (expression.get('left')).matchesPattern(
|
|
404
|
+
pattern,
|
|
405
|
+
);
|
|
394
406
|
});
|
|
395
407
|
}
|
|
396
408
|
|
|
397
409
|
/**
|
|
398
410
|
* Generate a displayName ExpressionStatement node based on the ids.
|
|
399
411
|
*
|
|
400
|
-
* @param {
|
|
412
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
401
413
|
* @param {ComponentIdentifier[]} componentIdentifiers list of { id, computed } objects
|
|
402
414
|
* @param {string} displayName name of the function component
|
|
403
415
|
*/
|
|
@@ -428,9 +440,9 @@ function createDisplayNameStatement(t, componentIdentifiers, displayName) {
|
|
|
428
440
|
/**
|
|
429
441
|
* Helper that creates a MemberExpression node from the ids.
|
|
430
442
|
*
|
|
431
|
-
* @param {
|
|
443
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
432
444
|
* @param {ComponentIdentifier[]} componentIdentifiers list of { id, computed } objects
|
|
433
|
-
* @returns {babel.types.Expression}
|
|
445
|
+
* @returns {import('@babel/core').types.Expression}
|
|
434
446
|
*/
|
|
435
447
|
function createMemberExpression(t, componentIdentifiers) {
|
|
436
448
|
let node = componentIdentifiers[0].id;
|
|
@@ -447,11 +459,16 @@ function createMemberExpression(t, componentIdentifiers) {
|
|
|
447
459
|
* Changes the arrow function to a function expression and gives it a name.
|
|
448
460
|
* `name` will be changed to ensure that it is unique within the scope. e.g. `helper` -> `_helper`
|
|
449
461
|
*
|
|
450
|
-
* @param {
|
|
462
|
+
* @param {BabelTypes} t content of @babel/types package
|
|
463
|
+
* @param {import('@babel/core').NodePath<import('@babel/core').types.ArrowFunctionExpression | import('@babel/core').types.CallExpression | import('@babel/core').types.FunctionExpression | import('@babel/core').types.ObjectMethod>} path path to the function node
|
|
451
464
|
* @param {string} name name of function to follow after
|
|
452
465
|
*/
|
|
453
466
|
function setInternalFunctionName(t, path, name) {
|
|
454
|
-
if (
|
|
467
|
+
if (
|
|
468
|
+
!name ||
|
|
469
|
+
('id' in path.node && path.node.id != null) ||
|
|
470
|
+
('key' in path.node && path.node.key != null)
|
|
471
|
+
) {
|
|
455
472
|
return;
|
|
456
473
|
}
|
|
457
474
|
|
|
@@ -459,5 +476,6 @@ function setInternalFunctionName(t, path, name) {
|
|
|
459
476
|
if (path.isArrowFunctionExpression()) {
|
|
460
477
|
path.arrowFunctionToExpression();
|
|
461
478
|
}
|
|
479
|
+
// @ts-expect-error Not really an error
|
|
462
480
|
path.node.id = id;
|
|
463
481
|
}
|