feima-vite-plugins 0.0.1 → 0.1.0
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/defineOptionsNameCheck.d.ts +4 -0
- package/dist/defineOptionsNameCheck.d.ts.map +1 -0
- package/dist/defineOptionsNameCheck.js +140 -0
- package/dist/fvxeTableIdCheck.d.ts +4 -0
- package/dist/fvxeTableIdCheck.d.ts.map +1 -0
- package/dist/fvxeTableIdCheck.js +119 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -118
- package/package.json +6 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineOptionsNameCheck.d.ts","sourceRoot":"","sources":["../src/defineOptionsNameCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AA6ClD,iBAAS,sBAAsB,IAAI,MAAM,CAkHxC;AACD,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { parse as parseSFC } from "@vue/compiler-sfc";
|
|
4
|
+
import { parse as parseJS } from "@babel/parser";
|
|
5
|
+
import traverse from "@babel/traverse";
|
|
6
|
+
function extractDefineOptionsName(code) {
|
|
7
|
+
const sfc = parseSFC(code);
|
|
8
|
+
const scriptSetup = sfc.descriptor.scriptSetup;
|
|
9
|
+
if (!scriptSetup)
|
|
10
|
+
return null;
|
|
11
|
+
const ast = parseJS(scriptSetup.content, {
|
|
12
|
+
sourceType: "module",
|
|
13
|
+
plugins: ["typescript", "jsx"],
|
|
14
|
+
});
|
|
15
|
+
let name = null;
|
|
16
|
+
traverse(ast, {
|
|
17
|
+
CallExpression(path) {
|
|
18
|
+
const callee = path.node.callee;
|
|
19
|
+
if (callee.type === "Identifier" && callee.name === "defineOptions") {
|
|
20
|
+
const arg = path.node.arguments[0];
|
|
21
|
+
if (arg && arg.type === "ObjectExpression") {
|
|
22
|
+
for (const prop of arg.properties) {
|
|
23
|
+
if (prop.type === "ObjectProperty" &&
|
|
24
|
+
((prop.key.type === "Identifier" && prop.key.name === "name") ||
|
|
25
|
+
(prop.key.type === "StringLiteral" &&
|
|
26
|
+
prop.key.value === "name"))) {
|
|
27
|
+
if (prop.value.type === "StringLiteral") {
|
|
28
|
+
name = prop.value.value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
return name;
|
|
37
|
+
}
|
|
38
|
+
function defineOptionsNameCheck() {
|
|
39
|
+
const nameMap = new Map();
|
|
40
|
+
let root = "";
|
|
41
|
+
let errorMsgs = [];
|
|
42
|
+
function clearFile(file) {
|
|
43
|
+
for (const [, files] of nameMap) {
|
|
44
|
+
files.delete(file);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function collectFromFile(file) {
|
|
48
|
+
if (!file.endsWith(".vue"))
|
|
49
|
+
return;
|
|
50
|
+
const code = fs.readFileSync(file, "utf-8");
|
|
51
|
+
const name = extractDefineOptionsName(code);
|
|
52
|
+
if (name) {
|
|
53
|
+
if (!nameMap.has(name))
|
|
54
|
+
nameMap.set(name, new Set());
|
|
55
|
+
nameMap.get(name).add(file);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function showErrorOverlay(server, message) {
|
|
59
|
+
server.ws.send({
|
|
60
|
+
type: "error",
|
|
61
|
+
err: {
|
|
62
|
+
message,
|
|
63
|
+
stack: "",
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function clearErrorOverlay(server) {
|
|
68
|
+
server.ws.send({ type: "full-reload" });
|
|
69
|
+
}
|
|
70
|
+
function report(server) {
|
|
71
|
+
let hasDuplicate = false;
|
|
72
|
+
let message = "";
|
|
73
|
+
if (errorMsgs.length) {
|
|
74
|
+
message += errorMsgs.join("\n") + "\n\n";
|
|
75
|
+
}
|
|
76
|
+
for (const [name, files] of nameMap) {
|
|
77
|
+
if (files.size > 1) {
|
|
78
|
+
hasDuplicate = true;
|
|
79
|
+
message +=
|
|
80
|
+
`组件 defineOptions name 重复: "${name}"\n` +
|
|
81
|
+
[...files].map((f) => ` - ${path.relative(root, f)}`).join("\n") +
|
|
82
|
+
"\n\n";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if ((hasDuplicate || errorMsgs.length) && server) {
|
|
86
|
+
console.error("\n🚨 " + message);
|
|
87
|
+
showErrorOverlay(server, message);
|
|
88
|
+
}
|
|
89
|
+
if (!hasDuplicate && errorMsgs.length === 0 && server) {
|
|
90
|
+
clearErrorOverlay(server);
|
|
91
|
+
}
|
|
92
|
+
errorMsgs = [];
|
|
93
|
+
return hasDuplicate || errorMsgs.length > 0;
|
|
94
|
+
}
|
|
95
|
+
function scanAll(dir) {
|
|
96
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
97
|
+
for (const entry of entries) {
|
|
98
|
+
const full = path.join(dir, entry.name);
|
|
99
|
+
if (entry.isDirectory()) {
|
|
100
|
+
scanAll(full);
|
|
101
|
+
}
|
|
102
|
+
else if (full.endsWith(".vue")) {
|
|
103
|
+
collectFromFile(full);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
name: "vite-plugin-defineoptions-name-check",
|
|
109
|
+
configResolved(config) {
|
|
110
|
+
root = config.root;
|
|
111
|
+
},
|
|
112
|
+
configureServer(server) {
|
|
113
|
+
if (process.env.NODE_ENV !== "development") {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
scanAll(path.join(root, "src"));
|
|
117
|
+
report(server);
|
|
118
|
+
server.watcher.on("change", (file) => {
|
|
119
|
+
if (!file.endsWith(".vue"))
|
|
120
|
+
return;
|
|
121
|
+
clearFile(file);
|
|
122
|
+
collectFromFile(file);
|
|
123
|
+
report(server);
|
|
124
|
+
});
|
|
125
|
+
server.watcher.on("add", (file) => {
|
|
126
|
+
if (!file.endsWith(".vue"))
|
|
127
|
+
return;
|
|
128
|
+
collectFromFile(file);
|
|
129
|
+
report(server);
|
|
130
|
+
});
|
|
131
|
+
server.watcher.on("unlink", (file) => {
|
|
132
|
+
if (!file.endsWith(".vue"))
|
|
133
|
+
return;
|
|
134
|
+
clearFile(file);
|
|
135
|
+
report(server);
|
|
136
|
+
});
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
export default defineOptionsNameCheck;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fvxeTableIdCheck.d.ts","sourceRoot":"","sources":["../src/fvxeTableIdCheck.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAOlD,iBAAS,gBAAgB,IAAI,MAAM,CAwIlC;AACD,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
const TABLE_REG = /<(f-vxe-table|FVxeTable)[^>]*\s+id\s*=\s*["']([^"']+)["'][^>]*>/g;
|
|
4
|
+
function fvxeTableIdCheck() {
|
|
5
|
+
const idMap = new Map();
|
|
6
|
+
let root = "";
|
|
7
|
+
let errorMsgs = [];
|
|
8
|
+
function containsChinese(str) {
|
|
9
|
+
return /[\u4e00-\u9fa5]/.test(str);
|
|
10
|
+
}
|
|
11
|
+
function clearFile(file) {
|
|
12
|
+
for (const [, files] of idMap) {
|
|
13
|
+
files.delete(file);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function collectFromFile(file) {
|
|
17
|
+
if (!file.endsWith(".vue"))
|
|
18
|
+
return;
|
|
19
|
+
const code = fs.readFileSync(file, "utf-8");
|
|
20
|
+
let match;
|
|
21
|
+
while ((match = TABLE_REG.exec(code))) {
|
|
22
|
+
const id = match[2];
|
|
23
|
+
if (containsChinese(id)) {
|
|
24
|
+
errorMsgs.push(`FVxeTable id 不能包含中文: "${id}" (文件: ${path.relative(root, file)})`);
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (!idMap.has(id))
|
|
28
|
+
idMap.set(id, new Set());
|
|
29
|
+
idMap.get(id).add(file);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function showErrorOverlay(server, message) {
|
|
33
|
+
server.ws.send({
|
|
34
|
+
type: "error",
|
|
35
|
+
err: {
|
|
36
|
+
message,
|
|
37
|
+
stack: "",
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function clearErrorOverlay(server) {
|
|
42
|
+
server.ws.send({ type: "full-reload" });
|
|
43
|
+
}
|
|
44
|
+
function report(server) {
|
|
45
|
+
let hasDuplicate = false;
|
|
46
|
+
let message = "";
|
|
47
|
+
if (errorMsgs.length) {
|
|
48
|
+
message += errorMsgs.join("\n") + "\n\n";
|
|
49
|
+
}
|
|
50
|
+
for (const [id, files] of idMap) {
|
|
51
|
+
if (files.size > 1) {
|
|
52
|
+
hasDuplicate = true;
|
|
53
|
+
message +=
|
|
54
|
+
`FVxeTable id 重复: "${id}"\n` +
|
|
55
|
+
[...files].map((f) => ` - ${path.relative(root, f)}`).join("\n") +
|
|
56
|
+
"\n\n";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if ((hasDuplicate || errorMsgs.length) && server) {
|
|
60
|
+
console.error("\n🚨 " + message);
|
|
61
|
+
showErrorOverlay(server, message);
|
|
62
|
+
}
|
|
63
|
+
if (!hasDuplicate && errorMsgs.length === 0 && server) {
|
|
64
|
+
clearErrorOverlay(server);
|
|
65
|
+
}
|
|
66
|
+
errorMsgs = [];
|
|
67
|
+
return hasDuplicate || errorMsgs.length > 0;
|
|
68
|
+
}
|
|
69
|
+
function scanAll(dir) {
|
|
70
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
71
|
+
for (const entry of entries) {
|
|
72
|
+
const full = path.join(dir, entry.name);
|
|
73
|
+
if (entry.isDirectory()) {
|
|
74
|
+
scanAll(full);
|
|
75
|
+
}
|
|
76
|
+
else if (full.endsWith(".vue")) {
|
|
77
|
+
collectFromFile(full);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
name: "vite-plugin-fvxe-table-id-check",
|
|
83
|
+
configResolved(config) {
|
|
84
|
+
root = config.root;
|
|
85
|
+
},
|
|
86
|
+
configureServer(server) {
|
|
87
|
+
// 仅在开发环境生效
|
|
88
|
+
if (process.env.NODE_ENV !== "development") {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// 1️⃣ 启动时全量扫描
|
|
92
|
+
scanAll(path.join(root, "src"));
|
|
93
|
+
report(server);
|
|
94
|
+
// 2️⃣ 监听文件修改
|
|
95
|
+
server.watcher.on("change", (file) => {
|
|
96
|
+
if (!file.endsWith(".vue"))
|
|
97
|
+
return;
|
|
98
|
+
clearFile(file);
|
|
99
|
+
collectFromFile(file);
|
|
100
|
+
report(server);
|
|
101
|
+
});
|
|
102
|
+
// 3️⃣ 监听新增文件
|
|
103
|
+
server.watcher.on("add", (file) => {
|
|
104
|
+
if (!file.endsWith(".vue"))
|
|
105
|
+
return;
|
|
106
|
+
collectFromFile(file);
|
|
107
|
+
report(server);
|
|
108
|
+
});
|
|
109
|
+
// 4️⃣ 监听删除文件
|
|
110
|
+
server.watcher.on("unlink", (file) => {
|
|
111
|
+
if (!file.endsWith(".vue"))
|
|
112
|
+
return;
|
|
113
|
+
clearFile(file);
|
|
114
|
+
report(server);
|
|
115
|
+
});
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
export default fvxeTableIdCheck;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
export { default as fvxeTableIdCheck } from "./fvxeTableIdCheck";
|
|
2
|
+
export { default as defineOptionsNameCheck } from "./defineOptionsNameCheck";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,OAAO,IAAI,sBAAsB,EAAE,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,118 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const TABLE_REG = /<(f-vxe-table|FVxeTable)[^>]*\s+id\s*=\s*["']([^"']+)["'][^>]*>/g;
|
|
4
|
-
export function fvxeTableIdCheck() {
|
|
5
|
-
const idMap = new Map();
|
|
6
|
-
let root = "";
|
|
7
|
-
let errorMsgs = [];
|
|
8
|
-
function containsChinese(str) {
|
|
9
|
-
return /[\u4e00-\u9fa5]/.test(str);
|
|
10
|
-
}
|
|
11
|
-
function clearFile(file) {
|
|
12
|
-
for (const [, files] of idMap) {
|
|
13
|
-
files.delete(file);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
function collectFromFile(file) {
|
|
17
|
-
if (!file.endsWith(".vue"))
|
|
18
|
-
return;
|
|
19
|
-
const code = fs.readFileSync(file, "utf-8");
|
|
20
|
-
let match;
|
|
21
|
-
while ((match = TABLE_REG.exec(code))) {
|
|
22
|
-
const id = match[2];
|
|
23
|
-
if (containsChinese(id)) {
|
|
24
|
-
errorMsgs.push(`FVxeTable id 不能包含中文: "${id}" (文件: ${path.relative(root, file)})`);
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
if (!idMap.has(id))
|
|
28
|
-
idMap.set(id, new Set());
|
|
29
|
-
idMap.get(id).add(file);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function showErrorOverlay(server, message) {
|
|
33
|
-
server.ws.send({
|
|
34
|
-
type: "error",
|
|
35
|
-
err: {
|
|
36
|
-
message,
|
|
37
|
-
stack: "",
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
function clearErrorOverlay(server) {
|
|
42
|
-
server.ws.send({ type: "full-reload" });
|
|
43
|
-
}
|
|
44
|
-
function report(server) {
|
|
45
|
-
let hasDuplicate = false;
|
|
46
|
-
let message = "";
|
|
47
|
-
if (errorMsgs.length) {
|
|
48
|
-
message += errorMsgs.join("\n") + "\n\n";
|
|
49
|
-
}
|
|
50
|
-
for (const [id, files] of idMap) {
|
|
51
|
-
if (files.size > 1) {
|
|
52
|
-
hasDuplicate = true;
|
|
53
|
-
message +=
|
|
54
|
-
`FVxeTable id 重复: "${id}"\n` +
|
|
55
|
-
[...files].map((f) => ` - ${path.relative(root, f)}`).join("\n") +
|
|
56
|
-
"\n\n";
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if ((hasDuplicate || errorMsgs.length) && server) {
|
|
60
|
-
console.error("\n🚨 " + message);
|
|
61
|
-
showErrorOverlay(server, message);
|
|
62
|
-
}
|
|
63
|
-
if (!hasDuplicate && errorMsgs.length === 0 && server) {
|
|
64
|
-
clearErrorOverlay(server);
|
|
65
|
-
}
|
|
66
|
-
errorMsgs = [];
|
|
67
|
-
return hasDuplicate || errorMsgs.length > 0;
|
|
68
|
-
}
|
|
69
|
-
function scanAll(dir) {
|
|
70
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
71
|
-
for (const entry of entries) {
|
|
72
|
-
const full = path.join(dir, entry.name);
|
|
73
|
-
if (entry.isDirectory()) {
|
|
74
|
-
scanAll(full);
|
|
75
|
-
}
|
|
76
|
-
else if (full.endsWith(".vue")) {
|
|
77
|
-
collectFromFile(full);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return {
|
|
82
|
-
name: "vite-plugin-fvxe-table-id-check",
|
|
83
|
-
configResolved(config) {
|
|
84
|
-
root = config.root;
|
|
85
|
-
},
|
|
86
|
-
configureServer(server) {
|
|
87
|
-
// 仅在开发环境生效
|
|
88
|
-
if (process.env.NODE_ENV !== "development") {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
// 1️⃣ 启动时全量扫描
|
|
92
|
-
scanAll(path.join(root, "src"));
|
|
93
|
-
report(server);
|
|
94
|
-
// 2️⃣ 监听文件修改
|
|
95
|
-
server.watcher.on("change", (file) => {
|
|
96
|
-
if (!file.endsWith(".vue"))
|
|
97
|
-
return;
|
|
98
|
-
clearFile(file);
|
|
99
|
-
collectFromFile(file);
|
|
100
|
-
report(server);
|
|
101
|
-
});
|
|
102
|
-
// 3️⃣ 监听新增文件
|
|
103
|
-
server.watcher.on("add", (file) => {
|
|
104
|
-
if (!file.endsWith(".vue"))
|
|
105
|
-
return;
|
|
106
|
-
collectFromFile(file);
|
|
107
|
-
report(server);
|
|
108
|
-
});
|
|
109
|
-
// 4️⃣ 监听删除文件
|
|
110
|
-
server.watcher.on("unlink", (file) => {
|
|
111
|
-
if (!file.endsWith(".vue"))
|
|
112
|
-
return;
|
|
113
|
-
clearFile(file);
|
|
114
|
-
report(server);
|
|
115
|
-
});
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
}
|
|
1
|
+
export { default as fvxeTableIdCheck } from "./fvxeTableIdCheck";
|
|
2
|
+
export { default as defineOptionsNameCheck } from "./defineOptionsNameCheck";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "feima-vite-plugins",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "Vite 插件集合
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Feima Vite 插件集合",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://git.fmszh.com/feima/feima-vite-plugins.git"
|
|
@@ -36,7 +36,11 @@
|
|
|
36
36
|
"vite": "^5.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
+
"@babel/parser": "^7.28.5",
|
|
40
|
+
"@babel/traverse": "^7.28.5",
|
|
41
|
+
"@types/babel__traverse": "^7.28.0",
|
|
39
42
|
"@types/node": "^20.0.0",
|
|
43
|
+
"@vue/compiler-sfc": "^3.5.26",
|
|
40
44
|
"typescript": "^5.0.0"
|
|
41
45
|
},
|
|
42
46
|
"peerDependencies": {
|