unplugin-zed-gpui 0.0.2 → 0.0.3
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/dist/index.cjs +293 -3
- package/dist/{index.d.cts → index.d.ts} +1 -2
- package/dist/index.mjs +267 -1
- package/package.json +10 -44
- package/dist/esbuild.cjs +0 -6
- package/dist/esbuild.cjs.map +0 -1
- package/dist/esbuild.d.cts +0 -6
- package/dist/esbuild.d.cts.map +0 -1
- package/dist/esbuild.d.mts +0 -7
- package/dist/esbuild.d.mts.map +0 -1
- package/dist/esbuild.mjs +0 -7
- package/dist/esbuild.mjs.map +0 -1
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts +0 -26
- package/dist/index.d.mts.map +0 -1
- package/dist/noble.cjs +0 -7
- package/dist/noble.d.cts +0 -2
- package/dist/noble.d.mts +0 -2
- package/dist/noble.mjs +0 -2
- package/dist/rollup.cjs +0 -6
- package/dist/rollup.cjs.map +0 -1
- package/dist/rollup.d.cts +0 -1350
- package/dist/rollup.d.cts.map +0 -1
- package/dist/rollup.d.mts +0 -1351
- package/dist/rollup.d.mts.map +0 -1
- package/dist/rollup.mjs +0 -7
- package/dist/rollup.mjs.map +0 -1
- package/dist/rspack.cjs +0 -6
- package/dist/rspack.cjs.map +0 -1
- package/dist/rspack.d.cts +0 -6
- package/dist/rspack.d.cts.map +0 -1
- package/dist/rspack.d.mts +0 -7
- package/dist/rspack.d.mts.map +0 -1
- package/dist/rspack.mjs +0 -7
- package/dist/rspack.mjs.map +0 -1
- package/dist/src-CQKToE8V.cjs +0 -30417
- package/dist/src-CQKToE8V.cjs.map +0 -1
- package/dist/src-Cdq30MRu.mjs +0 -30412
- package/dist/src-Cdq30MRu.mjs.map +0 -1
- package/dist/vite.cjs +0 -6
- package/dist/vite.cjs.map +0 -1
- package/dist/vite.d.cts +0 -6
- package/dist/vite.d.cts.map +0 -1
- package/dist/vite.d.mts +0 -7
- package/dist/vite.d.mts.map +0 -1
- package/dist/vite.mjs +0 -7
- package/dist/vite.mjs.map +0 -1
- package/dist/webpack.cjs +0 -6
- package/dist/webpack.cjs.map +0 -1
- package/dist/webpack.d.cts +0 -6
- package/dist/webpack.d.cts.map +0 -1
- package/dist/webpack.d.mts +0 -7
- package/dist/webpack.d.mts.map +0 -1
- package/dist/webpack.mjs +0 -7
- package/dist/webpack.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,296 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
//#region \0rolldown/runtime.js
|
|
6
|
+
var __create = Object.create;
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
14
|
+
key = keys[i];
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
16
|
+
get: ((k) => from[k]).bind(null, key),
|
|
17
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
26
|
+
//#endregion
|
|
27
|
+
let unplugin = require("unplugin");
|
|
28
|
+
let _babel_parser = require("@babel/parser");
|
|
29
|
+
let _babel_types = require("@babel/types");
|
|
30
|
+
_babel_types = __toESM(_babel_types, 1);
|
|
31
|
+
let _babel_generator = require("@babel/generator");
|
|
32
|
+
_babel_generator = __toESM(_babel_generator, 1);
|
|
33
|
+
//#region src/index.ts
|
|
34
|
+
const defaultOptions = {
|
|
35
|
+
zedGpuiPackageName: "zed-gpui",
|
|
36
|
+
elementPath: "zed-gpui/element",
|
|
37
|
+
debug: false
|
|
38
|
+
};
|
|
39
|
+
const keepHTMLElementMethods = /* @__PURE__ */ new Set([
|
|
40
|
+
"on",
|
|
41
|
+
"off",
|
|
42
|
+
"on_",
|
|
43
|
+
"off_"
|
|
44
|
+
]);
|
|
45
|
+
const factoryElementTypes = {
|
|
46
|
+
div: "HTMLDivElement",
|
|
47
|
+
span: "HTMLSpanElement",
|
|
48
|
+
section: "HTMLElement",
|
|
49
|
+
p: "HTMLParagraphElement",
|
|
50
|
+
input: "HTMLInputElement",
|
|
51
|
+
textarea: "HTMLTextAreaElement",
|
|
52
|
+
btn: "HTMLButtonElement",
|
|
53
|
+
select: "HTMLSelectElement"
|
|
54
|
+
};
|
|
55
|
+
const tagElementTypes = {
|
|
56
|
+
a: "HTMLAnchorElement",
|
|
57
|
+
button: "HTMLButtonElement",
|
|
58
|
+
details: "HTMLDetailsElement",
|
|
59
|
+
dialog: "HTMLDialogElement",
|
|
60
|
+
form: "HTMLFormElement",
|
|
61
|
+
img: "HTMLImageElement",
|
|
62
|
+
input: "HTMLInputElement",
|
|
63
|
+
label: "HTMLLabelElement",
|
|
64
|
+
meter: "HTMLMeterElement",
|
|
65
|
+
option: "HTMLOptionElement",
|
|
66
|
+
progress: "HTMLProgressElement",
|
|
67
|
+
select: "HTMLSelectElement",
|
|
68
|
+
textarea: "HTMLTextAreaElement",
|
|
69
|
+
video: "HTMLMediaElement",
|
|
70
|
+
audio: "HTMLMediaElement"
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Unplugin for zed-gpui tree-shaking optimization
|
|
74
|
+
* Removes unused zed-gpui methods from the bundle
|
|
75
|
+
*/
|
|
76
|
+
const zedGpuiPlugin = (0, unplugin.createUnplugin)((options = {}) => {
|
|
77
|
+
const opts = {
|
|
78
|
+
...defaultOptions,
|
|
79
|
+
...options
|
|
80
|
+
};
|
|
81
|
+
const usedMethods = {
|
|
82
|
+
unknown: /* @__PURE__ */ new Set(),
|
|
83
|
+
byPrototype: /* @__PURE__ */ new Map()
|
|
84
|
+
};
|
|
85
|
+
return {
|
|
86
|
+
name: "unplugin-zed-gpui",
|
|
87
|
+
transform(code, id) {
|
|
88
|
+
if (hasElementPrototypeAssign(code)) {
|
|
89
|
+
if (opts.debug) {
|
|
90
|
+
console.log(`[zed-gpui] Processing element file: ${id}`);
|
|
91
|
+
console.log(`[zed-gpui] Used methods:`, formatUsedMethods(usedMethods));
|
|
92
|
+
}
|
|
93
|
+
return transformElementFile(code, usedMethods, opts);
|
|
94
|
+
}
|
|
95
|
+
if (shouldProcessFile(id)) analyzeUsage(code, usedMethods, opts);
|
|
96
|
+
return null;
|
|
97
|
+
},
|
|
98
|
+
buildEnd() {
|
|
99
|
+
usedMethods.unknown.clear();
|
|
100
|
+
usedMethods.byPrototype.clear();
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
/**
|
|
105
|
+
* Check if a file should be analyzed for zed-gpui usage
|
|
106
|
+
*/
|
|
107
|
+
function shouldProcessFile(id) {
|
|
108
|
+
if (id.includes("node_modules") || id.includes("dist")) return false;
|
|
109
|
+
return /\.(ts|js|tsx|jsx)$/.test(id);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Analyze code to find zed-gpui method usage
|
|
113
|
+
*/
|
|
114
|
+
function analyzeUsage(code, usedMethods, options) {
|
|
115
|
+
try {
|
|
116
|
+
const ast = (0, _babel_parser.parse)(code, {
|
|
117
|
+
sourceType: "module",
|
|
118
|
+
plugins: ["typescript", "jsx"]
|
|
119
|
+
});
|
|
120
|
+
let hasZedGpuiImport = false;
|
|
121
|
+
const program = ast.program;
|
|
122
|
+
for (const node of program.body) if (_babel_types.isImportDeclaration(node)) {
|
|
123
|
+
const source = node.source.value;
|
|
124
|
+
if (source === options.zedGpuiPackageName || source.startsWith(options.zedGpuiPackageName + "/")) {
|
|
125
|
+
hasZedGpuiImport = true;
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
if (!hasZedGpuiImport && !hasZedGpuiUsage(code)) return;
|
|
130
|
+
scanNodeForMethodCalls(program, usedMethods, /* @__PURE__ */ new Map());
|
|
131
|
+
if (options.debug && (usedMethods.unknown.size > 0 || usedMethods.byPrototype.size > 0)) console.log(`[zed-gpui] Found methods in file:`, formatUsedMethods(usedMethods));
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (options.debug) console.warn(`[zed-gpui] Failed to parse:`, error);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Quick check if code might contain zed-gpui usage
|
|
138
|
+
*/
|
|
139
|
+
function hasZedGpuiUsage(code) {
|
|
140
|
+
return /\.\s*([a-z_][a-zA-Z0-9_]*)\s*\(/.test(code);
|
|
141
|
+
}
|
|
142
|
+
function hasElementPrototypeAssign(code) {
|
|
143
|
+
return code.includes("Object.assign") && /HTML[A-Za-z]*Element\.prototype/.test(code);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Recursively scan AST nodes for method calls
|
|
147
|
+
*/
|
|
148
|
+
function scanNodeForMethodCalls(node, usedMethods, bindings) {
|
|
149
|
+
if (_babel_types.isProgram(node) || _babel_types.isBlockStatement(node)) {
|
|
150
|
+
const scopedBindings = new Map(bindings);
|
|
151
|
+
for (const child of node.body) scanNodeForMethodCalls(child, usedMethods, scopedBindings);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (_babel_types.isFunctionDeclaration(node) || _babel_types.isFunctionExpression(node) || _babel_types.isArrowFunctionExpression(node)) {
|
|
155
|
+
const scopedBindings = new Map(bindings);
|
|
156
|
+
for (const param of node.params) bindElementType(param, scopedBindings);
|
|
157
|
+
scanNodeForMethodCalls(node.body, usedMethods, scopedBindings);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (_babel_types.isVariableDeclaration(node)) {
|
|
161
|
+
for (const declaration of node.declarations) {
|
|
162
|
+
if (declaration.init) scanNodeForMethodCalls(declaration.init, usedMethods, bindings);
|
|
163
|
+
if (_babel_types.isIdentifier(declaration.id)) {
|
|
164
|
+
const elementType = getElementTypeFromTypeAnnotation(declaration.id) ?? (declaration.init ? inferElementType(declaration.init, bindings) : void 0);
|
|
165
|
+
if (elementType) bindings.set(declaration.id.name, elementType);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (_babel_types.isAssignmentExpression(node)) {
|
|
171
|
+
scanNodeForMethodCalls(node.right, usedMethods, bindings);
|
|
172
|
+
if (_babel_types.isIdentifier(node.left)) {
|
|
173
|
+
const elementType = inferElementType(node.right, bindings);
|
|
174
|
+
if (elementType) bindings.set(node.left.name, elementType);
|
|
175
|
+
} else scanNodeForMethodCalls(node.left, usedMethods, bindings);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (_babel_types.isCallExpression(node) && _babel_types.isMemberExpression(node.callee) && !_babel_types.isSuper(node.callee.object)) {
|
|
179
|
+
const property = node.callee.property;
|
|
180
|
+
if (_babel_types.isIdentifier(property) && /^[a-z][a-zA-Z0-9_]*$/.test(property.name)) addUsedMethod(usedMethods, inferElementType(node.callee.object, bindings), property.name);
|
|
181
|
+
}
|
|
182
|
+
for (const key in node) {
|
|
183
|
+
if (!Object.prototype.hasOwnProperty.call(node, key)) continue;
|
|
184
|
+
const child = node[key];
|
|
185
|
+
if (Array.isArray(child)) child.forEach((item) => item?.type && scanNodeForMethodCalls(item, usedMethods, bindings));
|
|
186
|
+
else if (child?.type) scanNodeForMethodCalls(child, usedMethods, bindings);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function bindElementType(node, bindings) {
|
|
190
|
+
if (_babel_types.isIdentifier(node)) {
|
|
191
|
+
const elementType = getElementTypeFromTypeAnnotation(node);
|
|
192
|
+
if (elementType) bindings.set(node.name, elementType);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function addUsedMethod(usedMethods, elementType, methodName) {
|
|
196
|
+
if (!elementType) {
|
|
197
|
+
usedMethods.unknown.add(methodName);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (!usedMethods.byPrototype.has(elementType)) usedMethods.byPrototype.set(elementType, /* @__PURE__ */ new Set());
|
|
201
|
+
usedMethods.byPrototype.get(elementType).add(methodName);
|
|
202
|
+
}
|
|
203
|
+
function inferElementType(node, bindings) {
|
|
204
|
+
if (_babel_types.isIdentifier(node)) return bindings.get(node.name);
|
|
205
|
+
if (_babel_types.isTSAsExpression(node) || _babel_types.isTSTypeAssertion(node)) return getElementTypeFromTsType(node.typeAnnotation) ?? inferElementType(node.expression, bindings);
|
|
206
|
+
if (_babel_types.isCallExpression(node)) {
|
|
207
|
+
if (_babel_types.isIdentifier(node.callee)) {
|
|
208
|
+
if (node.callee.name === "h" && _babel_types.isStringLiteral(node.arguments[0])) return tagElementTypes[node.arguments[0].value] ?? "HTMLElement";
|
|
209
|
+
return factoryElementTypes[node.callee.name];
|
|
210
|
+
}
|
|
211
|
+
if (_babel_types.isMemberExpression(node.callee)) {
|
|
212
|
+
if (_babel_types.isMemberExpression(node.callee) && _babel_types.isIdentifier(node.callee.property, { name: "createElement" }) && _babel_types.isIdentifier(node.callee.object, { name: "document" }) && _babel_types.isStringLiteral(node.arguments[0])) return tagElementTypes[node.arguments[0].value] ?? "HTMLElement";
|
|
213
|
+
return inferElementType(node.callee.object, bindings);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
function getElementTypeFromTypeAnnotation(node) {
|
|
218
|
+
return node.typeAnnotation && _babel_types.isTSTypeAnnotation(node.typeAnnotation) ? getElementTypeFromTsType(node.typeAnnotation.typeAnnotation) : void 0;
|
|
219
|
+
}
|
|
220
|
+
function getElementTypeFromTsType(node) {
|
|
221
|
+
return _babel_types.isTSTypeReference(node) && _babel_types.isIdentifier(node.typeName) && isElementType(node.typeName.name) ? node.typeName.name : void 0;
|
|
222
|
+
}
|
|
223
|
+
function isElementType(name) {
|
|
224
|
+
return name === "HTMLElement" || /^HTML[A-Za-z]*Element$/.test(name);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Transform element.ts to remove unused methods
|
|
228
|
+
*/
|
|
229
|
+
function transformElementFile(code, usedMethods, options) {
|
|
230
|
+
try {
|
|
231
|
+
const ast = (0, _babel_parser.parse)(code, {
|
|
232
|
+
sourceType: "module",
|
|
233
|
+
plugins: ["typescript"]
|
|
234
|
+
});
|
|
235
|
+
let modified = false;
|
|
236
|
+
const prototypeMethods = /* @__PURE__ */ new Map();
|
|
237
|
+
for (const node of ast.program.body) {
|
|
238
|
+
if (!_babel_types.isExpressionStatement(node) || !_babel_types.isCallExpression(node.expression)) continue;
|
|
239
|
+
const targetPrototype = getAssignedPrototype(node.expression.arguments[0]);
|
|
240
|
+
const sourceArg = unwrapExpression(node.expression.arguments[1]);
|
|
241
|
+
if (!targetPrototype || !_babel_types.isObjectExpression(sourceArg)) continue;
|
|
242
|
+
prototypeMethods.set(targetPrototype, new Set(sourceArg.properties.map((prop) => _babel_types.isObjectProperty(prop) || _babel_types.isObjectMethod(prop) ? getPropertyName(prop.key) : void 0).filter((methodName) => !!methodName)));
|
|
243
|
+
}
|
|
244
|
+
for (const node of ast.program.body) {
|
|
245
|
+
if (!_babel_types.isExpressionStatement(node) || !_babel_types.isCallExpression(node.expression)) continue;
|
|
246
|
+
const callExpr = node.expression;
|
|
247
|
+
if (!_babel_types.isMemberExpression(callExpr.callee) || !_babel_types.isIdentifier(callExpr.callee.object, { name: "Object" }) || !_babel_types.isIdentifier(callExpr.callee.property, { name: "assign" }) || callExpr.arguments.length < 2) continue;
|
|
248
|
+
const targetPrototype = getAssignedPrototype(callExpr.arguments[0]);
|
|
249
|
+
const sourceArg = unwrapExpression(callExpr.arguments[1]);
|
|
250
|
+
if (!targetPrototype || !_babel_types.isObjectExpression(sourceArg)) continue;
|
|
251
|
+
const originalProperties = sourceArg.properties.length;
|
|
252
|
+
sourceArg.properties = sourceArg.properties.filter((prop) => {
|
|
253
|
+
if (!_babel_types.isObjectProperty(prop) && !_babel_types.isObjectMethod(prop)) return true;
|
|
254
|
+
const methodName = getPropertyName(prop.key);
|
|
255
|
+
if (!methodName || isMethodUsed(targetPrototype, methodName, usedMethods, prototypeMethods)) return true;
|
|
256
|
+
if (options.debug) console.log(`[zed-gpui] Removing unused method: ${targetPrototype}.${methodName}`);
|
|
257
|
+
return false;
|
|
258
|
+
});
|
|
259
|
+
if (sourceArg.properties.length !== originalProperties) {
|
|
260
|
+
modified = true;
|
|
261
|
+
if (options.debug) console.log(`[zed-gpui] Removed ${originalProperties - sourceArg.properties.length} unused methods from ${targetPrototype}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (modified) return { code: (0, _babel_generator.default)(ast, {}, code).code };
|
|
265
|
+
return null;
|
|
266
|
+
} catch (error) {
|
|
267
|
+
console.error("[zed-gpui] Failed to transform element file:", error);
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
function getAssignedPrototype(node) {
|
|
272
|
+
return _babel_types.isMemberExpression(node) && _babel_types.isIdentifier(node.object) && _babel_types.isIdentifier(node.property, { name: "prototype" }) && isElementType(node.object.name) ? node.object.name : void 0;
|
|
273
|
+
}
|
|
274
|
+
function unwrapExpression(node) {
|
|
275
|
+
while (_babel_types.isTSAsExpression(node) || _babel_types.isTSTypeAssertion(node) || _babel_types.isTSNonNullExpression(node)) node = node.expression;
|
|
276
|
+
return node;
|
|
277
|
+
}
|
|
278
|
+
function getPropertyName(node) {
|
|
279
|
+
if (_babel_types.isIdentifier(node)) return node.name;
|
|
280
|
+
if (_babel_types.isStringLiteral(node)) return node.value;
|
|
281
|
+
}
|
|
282
|
+
function isMethodUsed(prototypeName, methodName, usedMethods, prototypeMethods) {
|
|
283
|
+
if (usedMethods.unknown.has(methodName) || usedMethods.byPrototype.get(prototypeName)?.has(methodName)) return true;
|
|
284
|
+
if (prototypeName !== "HTMLElement") return false;
|
|
285
|
+
if (keepHTMLElementMethods.has(methodName)) return true;
|
|
286
|
+
for (const [usedPrototype, methods] of usedMethods.byPrototype) if (usedPrototype !== "HTMLElement" && methods.has(methodName) && !prototypeMethods.get(usedPrototype)?.has(methodName)) return true;
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
function formatUsedMethods(usedMethods) {
|
|
290
|
+
return {
|
|
291
|
+
unknown: Array.from(usedMethods.unknown).sort(),
|
|
292
|
+
byPrototype: Object.fromEntries(Array.from(usedMethods.byPrototype.entries()).map(([prototype, methods]) => [prototype, Array.from(methods).sort()]))
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
//#endregion
|
|
296
|
+
exports.default = zedGpuiPlugin;
|
|
297
|
+
exports.zedGpuiPlugin = zedGpuiPlugin;
|
|
@@ -22,5 +22,4 @@ interface PluginOptions {
|
|
|
22
22
|
*/
|
|
23
23
|
declare const zedGpuiPlugin: import("unplugin").UnpluginInstance<PluginOptions, boolean>;
|
|
24
24
|
//#endregion
|
|
25
|
-
export { PluginOptions, zedGpuiPlugin as default, zedGpuiPlugin };
|
|
26
|
-
//# sourceMappingURL=index.d.cts.map
|
|
25
|
+
export { PluginOptions, zedGpuiPlugin as default, zedGpuiPlugin };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,268 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createUnplugin } from "unplugin";
|
|
2
|
+
import { parse } from "@babel/parser";
|
|
3
|
+
import * as t from "@babel/types";
|
|
4
|
+
import generate from "@babel/generator";
|
|
5
|
+
//#region src/index.ts
|
|
6
|
+
const defaultOptions = {
|
|
7
|
+
zedGpuiPackageName: "zed-gpui",
|
|
8
|
+
elementPath: "zed-gpui/element",
|
|
9
|
+
debug: false
|
|
10
|
+
};
|
|
11
|
+
const keepHTMLElementMethods = /* @__PURE__ */ new Set([
|
|
12
|
+
"on",
|
|
13
|
+
"off",
|
|
14
|
+
"on_",
|
|
15
|
+
"off_"
|
|
16
|
+
]);
|
|
17
|
+
const factoryElementTypes = {
|
|
18
|
+
div: "HTMLDivElement",
|
|
19
|
+
span: "HTMLSpanElement",
|
|
20
|
+
section: "HTMLElement",
|
|
21
|
+
p: "HTMLParagraphElement",
|
|
22
|
+
input: "HTMLInputElement",
|
|
23
|
+
textarea: "HTMLTextAreaElement",
|
|
24
|
+
btn: "HTMLButtonElement",
|
|
25
|
+
select: "HTMLSelectElement"
|
|
26
|
+
};
|
|
27
|
+
const tagElementTypes = {
|
|
28
|
+
a: "HTMLAnchorElement",
|
|
29
|
+
button: "HTMLButtonElement",
|
|
30
|
+
details: "HTMLDetailsElement",
|
|
31
|
+
dialog: "HTMLDialogElement",
|
|
32
|
+
form: "HTMLFormElement",
|
|
33
|
+
img: "HTMLImageElement",
|
|
34
|
+
input: "HTMLInputElement",
|
|
35
|
+
label: "HTMLLabelElement",
|
|
36
|
+
meter: "HTMLMeterElement",
|
|
37
|
+
option: "HTMLOptionElement",
|
|
38
|
+
progress: "HTMLProgressElement",
|
|
39
|
+
select: "HTMLSelectElement",
|
|
40
|
+
textarea: "HTMLTextAreaElement",
|
|
41
|
+
video: "HTMLMediaElement",
|
|
42
|
+
audio: "HTMLMediaElement"
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Unplugin for zed-gpui tree-shaking optimization
|
|
46
|
+
* Removes unused zed-gpui methods from the bundle
|
|
47
|
+
*/
|
|
48
|
+
const zedGpuiPlugin = createUnplugin((options = {}) => {
|
|
49
|
+
const opts = {
|
|
50
|
+
...defaultOptions,
|
|
51
|
+
...options
|
|
52
|
+
};
|
|
53
|
+
const usedMethods = {
|
|
54
|
+
unknown: /* @__PURE__ */ new Set(),
|
|
55
|
+
byPrototype: /* @__PURE__ */ new Map()
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
name: "unplugin-zed-gpui",
|
|
59
|
+
transform(code, id) {
|
|
60
|
+
if (hasElementPrototypeAssign(code)) {
|
|
61
|
+
if (opts.debug) {
|
|
62
|
+
console.log(`[zed-gpui] Processing element file: ${id}`);
|
|
63
|
+
console.log(`[zed-gpui] Used methods:`, formatUsedMethods(usedMethods));
|
|
64
|
+
}
|
|
65
|
+
return transformElementFile(code, usedMethods, opts);
|
|
66
|
+
}
|
|
67
|
+
if (shouldProcessFile(id)) analyzeUsage(code, usedMethods, opts);
|
|
68
|
+
return null;
|
|
69
|
+
},
|
|
70
|
+
buildEnd() {
|
|
71
|
+
usedMethods.unknown.clear();
|
|
72
|
+
usedMethods.byPrototype.clear();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Check if a file should be analyzed for zed-gpui usage
|
|
78
|
+
*/
|
|
79
|
+
function shouldProcessFile(id) {
|
|
80
|
+
if (id.includes("node_modules") || id.includes("dist")) return false;
|
|
81
|
+
return /\.(ts|js|tsx|jsx)$/.test(id);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Analyze code to find zed-gpui method usage
|
|
85
|
+
*/
|
|
86
|
+
function analyzeUsage(code, usedMethods, options) {
|
|
87
|
+
try {
|
|
88
|
+
const ast = parse(code, {
|
|
89
|
+
sourceType: "module",
|
|
90
|
+
plugins: ["typescript", "jsx"]
|
|
91
|
+
});
|
|
92
|
+
let hasZedGpuiImport = false;
|
|
93
|
+
const program = ast.program;
|
|
94
|
+
for (const node of program.body) if (t.isImportDeclaration(node)) {
|
|
95
|
+
const source = node.source.value;
|
|
96
|
+
if (source === options.zedGpuiPackageName || source.startsWith(options.zedGpuiPackageName + "/")) {
|
|
97
|
+
hasZedGpuiImport = true;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!hasZedGpuiImport && !hasZedGpuiUsage(code)) return;
|
|
102
|
+
scanNodeForMethodCalls(program, usedMethods, /* @__PURE__ */ new Map());
|
|
103
|
+
if (options.debug && (usedMethods.unknown.size > 0 || usedMethods.byPrototype.size > 0)) console.log(`[zed-gpui] Found methods in file:`, formatUsedMethods(usedMethods));
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (options.debug) console.warn(`[zed-gpui] Failed to parse:`, error);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Quick check if code might contain zed-gpui usage
|
|
110
|
+
*/
|
|
111
|
+
function hasZedGpuiUsage(code) {
|
|
112
|
+
return /\.\s*([a-z_][a-zA-Z0-9_]*)\s*\(/.test(code);
|
|
113
|
+
}
|
|
114
|
+
function hasElementPrototypeAssign(code) {
|
|
115
|
+
return code.includes("Object.assign") && /HTML[A-Za-z]*Element\.prototype/.test(code);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Recursively scan AST nodes for method calls
|
|
119
|
+
*/
|
|
120
|
+
function scanNodeForMethodCalls(node, usedMethods, bindings) {
|
|
121
|
+
if (t.isProgram(node) || t.isBlockStatement(node)) {
|
|
122
|
+
const scopedBindings = new Map(bindings);
|
|
123
|
+
for (const child of node.body) scanNodeForMethodCalls(child, usedMethods, scopedBindings);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (t.isFunctionDeclaration(node) || t.isFunctionExpression(node) || t.isArrowFunctionExpression(node)) {
|
|
127
|
+
const scopedBindings = new Map(bindings);
|
|
128
|
+
for (const param of node.params) bindElementType(param, scopedBindings);
|
|
129
|
+
scanNodeForMethodCalls(node.body, usedMethods, scopedBindings);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (t.isVariableDeclaration(node)) {
|
|
133
|
+
for (const declaration of node.declarations) {
|
|
134
|
+
if (declaration.init) scanNodeForMethodCalls(declaration.init, usedMethods, bindings);
|
|
135
|
+
if (t.isIdentifier(declaration.id)) {
|
|
136
|
+
const elementType = getElementTypeFromTypeAnnotation(declaration.id) ?? (declaration.init ? inferElementType(declaration.init, bindings) : void 0);
|
|
137
|
+
if (elementType) bindings.set(declaration.id.name, elementType);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (t.isAssignmentExpression(node)) {
|
|
143
|
+
scanNodeForMethodCalls(node.right, usedMethods, bindings);
|
|
144
|
+
if (t.isIdentifier(node.left)) {
|
|
145
|
+
const elementType = inferElementType(node.right, bindings);
|
|
146
|
+
if (elementType) bindings.set(node.left.name, elementType);
|
|
147
|
+
} else scanNodeForMethodCalls(node.left, usedMethods, bindings);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (t.isCallExpression(node) && t.isMemberExpression(node.callee) && !t.isSuper(node.callee.object)) {
|
|
151
|
+
const property = node.callee.property;
|
|
152
|
+
if (t.isIdentifier(property) && /^[a-z][a-zA-Z0-9_]*$/.test(property.name)) addUsedMethod(usedMethods, inferElementType(node.callee.object, bindings), property.name);
|
|
153
|
+
}
|
|
154
|
+
for (const key in node) {
|
|
155
|
+
if (!Object.prototype.hasOwnProperty.call(node, key)) continue;
|
|
156
|
+
const child = node[key];
|
|
157
|
+
if (Array.isArray(child)) child.forEach((item) => item?.type && scanNodeForMethodCalls(item, usedMethods, bindings));
|
|
158
|
+
else if (child?.type) scanNodeForMethodCalls(child, usedMethods, bindings);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function bindElementType(node, bindings) {
|
|
162
|
+
if (t.isIdentifier(node)) {
|
|
163
|
+
const elementType = getElementTypeFromTypeAnnotation(node);
|
|
164
|
+
if (elementType) bindings.set(node.name, elementType);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function addUsedMethod(usedMethods, elementType, methodName) {
|
|
168
|
+
if (!elementType) {
|
|
169
|
+
usedMethods.unknown.add(methodName);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (!usedMethods.byPrototype.has(elementType)) usedMethods.byPrototype.set(elementType, /* @__PURE__ */ new Set());
|
|
173
|
+
usedMethods.byPrototype.get(elementType).add(methodName);
|
|
174
|
+
}
|
|
175
|
+
function inferElementType(node, bindings) {
|
|
176
|
+
if (t.isIdentifier(node)) return bindings.get(node.name);
|
|
177
|
+
if (t.isTSAsExpression(node) || t.isTSTypeAssertion(node)) return getElementTypeFromTsType(node.typeAnnotation) ?? inferElementType(node.expression, bindings);
|
|
178
|
+
if (t.isCallExpression(node)) {
|
|
179
|
+
if (t.isIdentifier(node.callee)) {
|
|
180
|
+
if (node.callee.name === "h" && t.isStringLiteral(node.arguments[0])) return tagElementTypes[node.arguments[0].value] ?? "HTMLElement";
|
|
181
|
+
return factoryElementTypes[node.callee.name];
|
|
182
|
+
}
|
|
183
|
+
if (t.isMemberExpression(node.callee)) {
|
|
184
|
+
if (t.isMemberExpression(node.callee) && t.isIdentifier(node.callee.property, { name: "createElement" }) && t.isIdentifier(node.callee.object, { name: "document" }) && t.isStringLiteral(node.arguments[0])) return tagElementTypes[node.arguments[0].value] ?? "HTMLElement";
|
|
185
|
+
return inferElementType(node.callee.object, bindings);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function getElementTypeFromTypeAnnotation(node) {
|
|
190
|
+
return node.typeAnnotation && t.isTSTypeAnnotation(node.typeAnnotation) ? getElementTypeFromTsType(node.typeAnnotation.typeAnnotation) : void 0;
|
|
191
|
+
}
|
|
192
|
+
function getElementTypeFromTsType(node) {
|
|
193
|
+
return t.isTSTypeReference(node) && t.isIdentifier(node.typeName) && isElementType(node.typeName.name) ? node.typeName.name : void 0;
|
|
194
|
+
}
|
|
195
|
+
function isElementType(name) {
|
|
196
|
+
return name === "HTMLElement" || /^HTML[A-Za-z]*Element$/.test(name);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Transform element.ts to remove unused methods
|
|
200
|
+
*/
|
|
201
|
+
function transformElementFile(code, usedMethods, options) {
|
|
202
|
+
try {
|
|
203
|
+
const ast = parse(code, {
|
|
204
|
+
sourceType: "module",
|
|
205
|
+
plugins: ["typescript"]
|
|
206
|
+
});
|
|
207
|
+
let modified = false;
|
|
208
|
+
const prototypeMethods = /* @__PURE__ */ new Map();
|
|
209
|
+
for (const node of ast.program.body) {
|
|
210
|
+
if (!t.isExpressionStatement(node) || !t.isCallExpression(node.expression)) continue;
|
|
211
|
+
const targetPrototype = getAssignedPrototype(node.expression.arguments[0]);
|
|
212
|
+
const sourceArg = unwrapExpression(node.expression.arguments[1]);
|
|
213
|
+
if (!targetPrototype || !t.isObjectExpression(sourceArg)) continue;
|
|
214
|
+
prototypeMethods.set(targetPrototype, new Set(sourceArg.properties.map((prop) => t.isObjectProperty(prop) || t.isObjectMethod(prop) ? getPropertyName(prop.key) : void 0).filter((methodName) => !!methodName)));
|
|
215
|
+
}
|
|
216
|
+
for (const node of ast.program.body) {
|
|
217
|
+
if (!t.isExpressionStatement(node) || !t.isCallExpression(node.expression)) continue;
|
|
218
|
+
const callExpr = node.expression;
|
|
219
|
+
if (!t.isMemberExpression(callExpr.callee) || !t.isIdentifier(callExpr.callee.object, { name: "Object" }) || !t.isIdentifier(callExpr.callee.property, { name: "assign" }) || callExpr.arguments.length < 2) continue;
|
|
220
|
+
const targetPrototype = getAssignedPrototype(callExpr.arguments[0]);
|
|
221
|
+
const sourceArg = unwrapExpression(callExpr.arguments[1]);
|
|
222
|
+
if (!targetPrototype || !t.isObjectExpression(sourceArg)) continue;
|
|
223
|
+
const originalProperties = sourceArg.properties.length;
|
|
224
|
+
sourceArg.properties = sourceArg.properties.filter((prop) => {
|
|
225
|
+
if (!t.isObjectProperty(prop) && !t.isObjectMethod(prop)) return true;
|
|
226
|
+
const methodName = getPropertyName(prop.key);
|
|
227
|
+
if (!methodName || isMethodUsed(targetPrototype, methodName, usedMethods, prototypeMethods)) return true;
|
|
228
|
+
if (options.debug) console.log(`[zed-gpui] Removing unused method: ${targetPrototype}.${methodName}`);
|
|
229
|
+
return false;
|
|
230
|
+
});
|
|
231
|
+
if (sourceArg.properties.length !== originalProperties) {
|
|
232
|
+
modified = true;
|
|
233
|
+
if (options.debug) console.log(`[zed-gpui] Removed ${originalProperties - sourceArg.properties.length} unused methods from ${targetPrototype}`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (modified) return { code: generate(ast, {}, code).code };
|
|
237
|
+
return null;
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.error("[zed-gpui] Failed to transform element file:", error);
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function getAssignedPrototype(node) {
|
|
244
|
+
return t.isMemberExpression(node) && t.isIdentifier(node.object) && t.isIdentifier(node.property, { name: "prototype" }) && isElementType(node.object.name) ? node.object.name : void 0;
|
|
245
|
+
}
|
|
246
|
+
function unwrapExpression(node) {
|
|
247
|
+
while (t.isTSAsExpression(node) || t.isTSTypeAssertion(node) || t.isTSNonNullExpression(node)) node = node.expression;
|
|
248
|
+
return node;
|
|
249
|
+
}
|
|
250
|
+
function getPropertyName(node) {
|
|
251
|
+
if (t.isIdentifier(node)) return node.name;
|
|
252
|
+
if (t.isStringLiteral(node)) return node.value;
|
|
253
|
+
}
|
|
254
|
+
function isMethodUsed(prototypeName, methodName, usedMethods, prototypeMethods) {
|
|
255
|
+
if (usedMethods.unknown.has(methodName) || usedMethods.byPrototype.get(prototypeName)?.has(methodName)) return true;
|
|
256
|
+
if (prototypeName !== "HTMLElement") return false;
|
|
257
|
+
if (keepHTMLElementMethods.has(methodName)) return true;
|
|
258
|
+
for (const [usedPrototype, methods] of usedMethods.byPrototype) if (usedPrototype !== "HTMLElement" && methods.has(methodName) && !prototypeMethods.get(usedPrototype)?.has(methodName)) return true;
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
function formatUsedMethods(usedMethods) {
|
|
262
|
+
return {
|
|
263
|
+
unknown: Array.from(usedMethods.unknown).sort(),
|
|
264
|
+
byPrototype: Object.fromEntries(Array.from(usedMethods.byPrototype.entries()).map(([prototype, methods]) => [prototype, Array.from(methods).sort()]))
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
//#endregion
|
|
2
268
|
export { zedGpuiPlugin as default, zedGpuiPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unplugin-zed-gpui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Unplugin for zed-gpui tree-shaking optimization - removes unused zed-gpui methods from bundle",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Kasukabe Tsumugi",
|
|
@@ -8,51 +8,15 @@
|
|
|
8
8
|
},
|
|
9
9
|
"license": "MIT",
|
|
10
10
|
"type": "module",
|
|
11
|
-
"main": "./dist/index.
|
|
12
|
-
"module": "./dist/index.
|
|
11
|
+
"main": "./dist/index.cjs",
|
|
12
|
+
"module": "./dist/index.mjs",
|
|
13
13
|
"types": "./dist/index.d.ts",
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./dist/index.d.ts",
|
|
17
|
-
"import": "./dist/index.
|
|
17
|
+
"import": "./dist/index.mjs",
|
|
18
18
|
"require": "./dist/index.cjs",
|
|
19
|
-
"default": "./dist/index.
|
|
20
|
-
},
|
|
21
|
-
"./noble": {
|
|
22
|
-
"types": "./dist/noble.d.ts",
|
|
23
|
-
"import": "./dist/noble.js",
|
|
24
|
-
"require": "./dist/noble.cjs",
|
|
25
|
-
"default": "./dist/noble.js"
|
|
26
|
-
},
|
|
27
|
-
"./vite": {
|
|
28
|
-
"types": "./dist/vite.d.ts",
|
|
29
|
-
"import": "./dist/vite.mjs",
|
|
30
|
-
"require": "./dist/vite.cjs",
|
|
31
|
-
"default": "./dist/vite.mjs"
|
|
32
|
-
},
|
|
33
|
-
"./webpack": {
|
|
34
|
-
"types": "./dist/webpack.d.ts",
|
|
35
|
-
"import": "./dist/webpack.mjs",
|
|
36
|
-
"require": "./dist/webpack.cjs",
|
|
37
|
-
"default": "./dist/webpack.mjs"
|
|
38
|
-
},
|
|
39
|
-
"./rollup": {
|
|
40
|
-
"types": "./dist/rollup.d.ts",
|
|
41
|
-
"import": "./dist/rollup.mjs",
|
|
42
|
-
"require": "./dist/rollup.cjs",
|
|
43
|
-
"default": "./dist/rollup.mjs"
|
|
44
|
-
},
|
|
45
|
-
"./esbuild": {
|
|
46
|
-
"types": "./dist/esbuild.d.ts",
|
|
47
|
-
"import": "./dist/esbuild.mjs",
|
|
48
|
-
"require": "./dist/esbuild.cjs",
|
|
49
|
-
"default": "./dist/esbuild.mjs"
|
|
50
|
-
},
|
|
51
|
-
"./rspack": {
|
|
52
|
-
"types": "./dist/rspack.d.ts",
|
|
53
|
-
"import": "./dist/rspack.mjs",
|
|
54
|
-
"require": "./dist/rspack.cjs",
|
|
55
|
-
"default": "./dist/rspack.mjs"
|
|
19
|
+
"default": "./dist/index.mjs"
|
|
56
20
|
}
|
|
57
21
|
},
|
|
58
22
|
"files": [
|
|
@@ -72,9 +36,6 @@
|
|
|
72
36
|
"unplugin": "^1.0.0"
|
|
73
37
|
},
|
|
74
38
|
"devDependencies": {
|
|
75
|
-
"@babel/generator": "^8.0.0",
|
|
76
|
-
"@babel/parser": "^8.0.0",
|
|
77
|
-
"@babel/types": "^8.0.0",
|
|
78
39
|
"@types/node": "^25.9.1",
|
|
79
40
|
"tsdown": "^0.22.3",
|
|
80
41
|
"typescript": "^6.0.3",
|
|
@@ -85,6 +46,11 @@
|
|
|
85
46
|
"url": "https://github.com/baendlorel/gpui-ts",
|
|
86
47
|
"directory": "packages/unplugin-zed-gpui-treeshake"
|
|
87
48
|
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@babel/generator": "^8.0.0",
|
|
51
|
+
"@babel/parser": "^8.0.0",
|
|
52
|
+
"@babel/types": "^8.0.0"
|
|
53
|
+
},
|
|
88
54
|
"scripts": {
|
|
89
55
|
"build": "tsdown",
|
|
90
56
|
"dev": "tsdown --watch"
|
package/dist/esbuild.cjs
DELETED
package/dist/esbuild.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"esbuild.cjs","names":["zedGpuiPlugin"],"sources":["../src/esbuild.ts"],"sourcesContent":["import { zedGpuiPlugin } from './index.js';\n\nexport default zedGpuiPlugin.esbuild;\n"],"mappings":";AAEA,IAAA,8CAAeA,CAAAA,CAAAA,cAAc"}
|
package/dist/esbuild.d.cts
DELETED
package/dist/esbuild.d.cts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"esbuild.d.cts","names":[],"sources":["../src/esbuild.ts"],"mappings":""}
|