-
Notifications
You must be signed in to change notification settings - Fork 26
Expand file tree
/
Copy pathbabel-plugin-add-use-client.js
More file actions
121 lines (104 loc) · 3.62 KB
/
babel-plugin-add-use-client.js
File metadata and controls
121 lines (104 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* Babel plugin to add 'use client' directive at the top of files
* Only applies to design, ui, and charts packages
* Works for both ESM and CommonJS builds
*
* Reference: https://github.com/ant-design/ant-design
*/
module.exports = function ({ types: t }) {
const targetPackages = ['design', 'ui', 'charts'];
/**
* Normalize path separators
*/
function normalizePath(path) {
return path ? path.replace(/\\/g, '/') : '';
}
/**
* Check if path contains a target package
* Simplified logic: check if path includes any target package name
*/
function isTargetPackage(filename, cwd) {
const normalizedFilename = normalizePath(filename || '');
const normalizedCwd = normalizePath(cwd || process.cwd());
const currentWorkingDir = normalizePath(process.cwd());
// Simple check: if any path contains a target package name
const checkPath = path => {
if (!path) return false;
return targetPackages.some(pkg => {
return path.includes(`/${pkg}/`) || path.includes(`\\${pkg}\\`);
});
};
return (
checkPath(normalizedFilename) || checkPath(normalizedCwd) || checkPath(currentWorkingDir)
);
}
/**
* Check if file should have 'use client' added
* Only add to:
* 1. .jsx or .tsx files
* 2. src/index.ts or src/xxx/index.ts files (including component index files)
*/
function shouldAddUseClient(filename) {
if (!filename) return false;
const normalized = normalizePath(filename);
// Match .jsx or .tsx files
// Match src/index.ts or src/xxx/index.ts
return /\.(j|t)sx$/.test(normalized) || /src(\/[\w-]+)?\/index\.ts$/.test(normalized);
}
return {
visitor: {
Program(path, state) {
// Get file path from state - try all possible sources
const filename =
state.file?.opts?.filename ||
state.file?.opts?.sourceFileName ||
state.file?.opts?.sourceFilePath ||
state.file?.opts?.sourceRoot ||
state.filename ||
'';
const cwd = state.file?.opts?.cwd || process.cwd();
// Check if this is a target package
const isTarget = isTargetPackage(filename, cwd);
if (!isTarget) {
return;
}
// Check if file should have 'use client' added
const shouldAdd = shouldAddUseClient(filename);
if (!shouldAdd) {
return;
}
// Check if 'use client' already exists
const body = path.node.body;
let hasUseClient = false;
let useStrictIndex = -1;
// Find if 'use client' already exists and locate 'use strict' if present
for (let i = 0; i < body.length; i++) {
const statement = body[i];
if (t.isExpressionStatement(statement) && t.isStringLiteral(statement.expression)) {
const value = statement.expression.value;
if (value === 'use client') {
hasUseClient = true;
break;
}
if (value === 'use strict' && useStrictIndex === -1) {
useStrictIndex = i;
}
}
}
if (hasUseClient) {
return; // Already has 'use client'
}
// Add 'use client' directive
// Insert after 'use strict' if it exists, otherwise at the beginning
const useClientDirective = t.expressionStatement(t.stringLiteral('use client'));
if (useStrictIndex !== -1) {
// Insert after 'use strict'
body.splice(useStrictIndex + 1, 0, useClientDirective);
} else {
// Insert at the very beginning
body.unshift(useClientDirective);
}
},
},
};
};