@dune2/babel 0.4.2 → 1.0.1

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.
@@ -0,0 +1,181 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) {
13
+ __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
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
+
27
+ //#endregion
28
+ let _babel_types = require("@babel/types");
29
+ _babel_types = __toESM(_babel_types);
30
+
31
+ //#region src/createStore/shared.ts
32
+ /**
33
+ * 检查 selector 参数的返回值类型
34
+ * 如果返回值是对象类型,则将 useSnapshot 转换为 useShallowSnapshot
35
+ */
36
+ function handleSelectorArgument(init) {
37
+ const selector = init.arguments[0];
38
+ if (_babel_types.default.isFunctionExpression(selector) || _babel_types.default.isArrowFunctionExpression(selector)) {
39
+ const body = selector.body;
40
+ if (_babel_types.default.isBlockStatement(body)) {
41
+ const returnStmt = body.body.find((stmt) => _babel_types.default.isReturnStatement(stmt));
42
+ if (returnStmt && _babel_types.default.isReturnStatement(returnStmt) && _babel_types.default.isObjectExpression(returnStmt.argument)) return true;
43
+ } else if (_babel_types.default.isObjectExpression(body)) return true;
44
+ }
45
+ return false;
46
+ }
47
+
48
+ //#endregion
49
+ //#region src/createStore/handleIdentifierSnapshot.ts
50
+ /**
51
+ * 处理 store.useSnapshot() 的变量声明
52
+ * 示例: const state = store.useSnapshot()
53
+ * 将会转换为:
54
+ * function selector(state) { return { _prop: state.a.b } }
55
+ * const state = store.useShallowSnapshot(selector)
56
+ */
57
+ function handleIdentifierSnapshot(path) {
58
+ const { id, init } = path.node;
59
+ if (!_babel_types.default.isCallExpression(init) || !_babel_types.default.isIdentifier(id)) return;
60
+ if (!_babel_types.default.isMemberExpression(init.callee)) return;
61
+ const callee = init.callee;
62
+ if (!_babel_types.default.isIdentifier(callee.property) || callee.property.name !== "useSnapshot") return;
63
+ if (init.arguments.length > 0) {
64
+ if (handleSelectorArgument(init)) callee.property.name = "useShallowSnapshot";
65
+ return;
66
+ }
67
+ const memberAccessors = [];
68
+ const accessorMap = /* @__PURE__ */ new Map();
69
+ {
70
+ const binding = path.scope.getOwnBinding(id.name);
71
+ const arr = [];
72
+ binding === null || binding === void 0 || binding.referencePaths.forEach((refPath) => {
73
+ const { memberExprStart, nodePath, accessKey } = findMemberExpression(refPath);
74
+ if (memberExprStart && nodePath && accessKey) arr.push({
75
+ memberExprStart,
76
+ nodePath,
77
+ accessKey
78
+ });
79
+ });
80
+ if (!arr.length || arr.length !== (binding === null || binding === void 0 ? void 0 : binding.referencePaths.length)) return;
81
+ arr.forEach((item) => {
82
+ const { memberExprStart, nodePath, accessKey } = item;
83
+ let propIdentifier = accessorMap.get(accessKey);
84
+ if (!propIdentifier) {
85
+ propIdentifier = path.scope.generateUidIdentifier("prop_");
86
+ accessorMap.set(accessKey, propIdentifier);
87
+ memberAccessors.push({
88
+ node: _babel_types.default.cloneDeepWithoutLoc(memberExprStart),
89
+ identifier: propIdentifier
90
+ });
91
+ }
92
+ nodePath.replaceWith(_babel_types.default.memberExpression(_babel_types.default.cloneWithoutLoc(id), _babel_types.default.cloneDeepWithoutLoc(propIdentifier)));
93
+ });
94
+ if (!memberAccessors.length) return;
95
+ }
96
+ const selectorName = path.scope.generateUidIdentifier("selector_");
97
+ const selector = _babel_types.default.functionDeclaration(selectorName, [_babel_types.default.identifier(id.name)], _babel_types.default.blockStatement([_babel_types.default.returnStatement(_babel_types.default.objectExpression(memberAccessors.map((accessor) => {
98
+ return _babel_types.default.objectProperty(accessor.identifier, accessor.node);
99
+ })))]));
100
+ path.parentPath.insertBefore(selector);
101
+ callee.property.name = "useShallowSnapshot";
102
+ init.arguments = [selectorName];
103
+ }
104
+ /**
105
+ * 查找成员表达式链
106
+ * 例如: a.b.c 会找到最后一个成员表达式 a.b.c
107
+ *
108
+ * @param path - 当前节点路径
109
+ * @returns {
110
+ * memberExprStart - 成员表达式的起始节点
111
+ * nodePath - 当前节点路径
112
+ * accessKey - 完整的访问路径字符串
113
+ * }
114
+ */
115
+ function findMemberExpression(path) {
116
+ let current = path;
117
+ let memberExprStart;
118
+ let accessKey = "";
119
+ while (current === null || current === void 0 ? void 0 : current.parentPath) {
120
+ const parent = current.parentPath;
121
+ const node = parent.node;
122
+ if ((_babel_types.default.isMemberExpression(node) || _babel_types.default.isOptionalMemberExpression(node)) && _babel_types.default.isIdentifier(node.property)) {
123
+ memberExprStart = node;
124
+ current = parent;
125
+ accessKey += "." + node.property.name;
126
+ } else break;
127
+ }
128
+ return {
129
+ memberExprStart,
130
+ nodePath: current,
131
+ accessKey
132
+ };
133
+ }
134
+
135
+ //#endregion
136
+ //#region src/createStore/handleObjectPattern.ts
137
+ /**
138
+ * 处理 store.useSnapshot() 的变量声明
139
+ * 示例: const { a, c: { name } } = store.useSnapshot()
140
+ * 将会转换为:
141
+ * function selector({ a, c: { name } } ) { return { a, c: { name } } }
142
+ * const { a, c: { name } } = store.useShallowSnapshot(selector)
143
+ */
144
+ function handleObjectPattern(path) {
145
+ const { id, init } = path.node;
146
+ if (!_babel_types.default.isCallExpression(init) || !_babel_types.default.isObjectPattern(id)) return;
147
+ if (!_babel_types.default.isMemberExpression(init.callee)) return;
148
+ const callee = init.callee;
149
+ if (!_babel_types.default.isIdentifier(callee.property) || callee.property.name !== "useSnapshot") return;
150
+ if (init.arguments.length > 0) {
151
+ if (handleSelectorArgument(init)) callee.property.name = "useShallowSnapshot";
152
+ return;
153
+ }
154
+ const selectorName = path.scope.generateUidIdentifier("selector_");
155
+ const selector = _babel_types.default.functionDeclaration(selectorName, [_babel_types.default.cloneDeepWithoutLoc(id)], _babel_types.default.blockStatement([_babel_types.default.returnStatement(_babel_types.default.objectExpression(id.properties.map((v) => {
156
+ if (_babel_types.default.isRestElement(v)) {
157
+ if (!_babel_types.default.isIdentifier(v.argument)) throw path.buildCodeFrameError("Rest element in object pattern must be a simple identifier");
158
+ return _babel_types.default.spreadElement(_babel_types.default.cloneDeepWithoutLoc(v.argument));
159
+ }
160
+ return _babel_types.default.cloneDeepWithoutLoc(v);
161
+ })))]));
162
+ path.parentPath.insertBefore(selector);
163
+ callee.property.name = "useShallowSnapshot";
164
+ init.arguments = [selectorName];
165
+ }
166
+
167
+ //#endregion
168
+ //#region src/createStore/index.ts
169
+ const createStorePlugin = (api) => {
170
+ return {
171
+ name: "create-store",
172
+ visitor: { VariableDeclarator(path) {
173
+ handleIdentifierSnapshot(path);
174
+ handleObjectPattern(path);
175
+ } }
176
+ };
177
+ };
178
+
179
+ //#endregion
180
+ exports.createStorePlugin = createStorePlugin;
181
+ //# sourceMappingURL=createStore.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createStore.cjs","names":["t","t","t"],"sources":["../src/createStore/shared.ts","../src/createStore/handleIdentifierSnapshot.ts","../src/createStore/handleObjectPattern.ts","../src/createStore/index.ts"],"sourcesContent":["import type { CallExpression } from \"@babel/types\";\nimport t from \"@babel/types\";\n\n/**\n * 检查 selector 参数的返回值类型\n * 如果返回值是对象类型,则将 useSnapshot 转换为 useShallowSnapshot\n */\nexport function handleSelectorArgument(init: CallExpression) {\n const selector = init.arguments[0];\n if (\n t.isFunctionExpression(selector) ||\n t.isArrowFunctionExpression(selector)\n ) {\n const body = selector.body;\n if (t.isBlockStatement(body)) {\n const returnStmt = body.body.find((stmt) => t.isReturnStatement(stmt));\n if (\n returnStmt &&\n t.isReturnStatement(returnStmt) &&\n t.isObjectExpression(returnStmt.argument)\n ) {\n return true;\n }\n } else if (t.isObjectExpression(body)) {\n return true;\n }\n }\n return false;\n}\n","import type { NodePath } from \"@babel/traverse\";\nimport type {\n Identifier,\n MemberExpression,\n OptionalMemberExpression,\n VariableDeclarator,\n} from \"@babel/types\";\nimport t from \"@babel/types\";\nimport { handleSelectorArgument } from \"./shared\";\n/**\n * 处理 store.useSnapshot() 的变量声明\n * 示例: const state = store.useSnapshot()\n * 将会转换为:\n * function selector(state) { return { _prop: state.a.b } }\n * const state = store.useShallowSnapshot(selector)\n */\nexport function handleIdentifierSnapshot(path: NodePath<VariableDeclarator>) {\n const { id, init } = path.node;\n\n // 预检查:确保是 CallExpression 且变量是标识符\n if (!t.isCallExpression(init) || !t.isIdentifier(id)) {\n return;\n }\n if (!t.isMemberExpression(init.callee)) {\n return;\n }\n\n // 检查是否为 store.useSnapshot 调用\n const callee = init.callee;\n if (\n !t.isIdentifier(callee.property) ||\n callee.property.name !== \"useSnapshot\"\n ) {\n return;\n }\n\n // 如果已经有 selector 参数,则需要检查返回值类型\n // 如果返回值是对象类型,则转换为 useShallowSnapshot\n if (init.arguments.length > 0) {\n if (handleSelectorArgument(init)) {\n callee.property.name = \"useShallowSnapshot\";\n }\n return;\n }\n\n // 初始化成员访问器数组和访问器映射\n // memberAccessors 用于存储所有的成员访问表达式\n // accessorMap 用于缓存已处理过的访问路径,避免重复创建\n const memberAccessors: MemberAccessor[] = [];\n const accessorMap = new Map<string, Identifier>();\n {\n // 获取变量的绑定信息,用于查找所有引用\n const binding = path.scope.getOwnBinding(id.name);\n\n // 存储所有有效的成员表达式访问\n const arr: ReturnType<typeof findMemberExpression>[] = [];\n\n // 第一次遍历:收集所有有效的成员表达式\n binding?.referencePaths.forEach((refPath) => {\n const { memberExprStart, nodePath, accessKey } =\n findMemberExpression(refPath);\n if (memberExprStart && nodePath && accessKey) {\n arr.push({ memberExprStart, nodePath, accessKey });\n }\n });\n\n // 如果存在无效的成员表达式访问,则不进行转换\n if (!arr.length || arr.length !== binding?.referencePaths.length) {\n return;\n }\n\n // 第二次遍历:处理每个成员表达式\n // 1. 为每个唯一的访问路径生成标识符\n // 2. 收集成员访问器信息\n // 3. 替换原始表达式为新的访问方式\n arr.forEach((item) => {\n const { memberExprStart, nodePath, accessKey } = item;\n let propIdentifier = accessorMap.get(accessKey);\n if (!propIdentifier) {\n // 生成唯一的属性标识符\n propIdentifier = path.scope.generateUidIdentifier(\"prop_\");\n accessorMap.set(accessKey, propIdentifier);\n memberAccessors.push({\n node: t.cloneDeepWithoutLoc(memberExprStart!),\n identifier: propIdentifier,\n });\n }\n\n // 替换原始的成员表达式为新的访问方式\n nodePath!.replaceWith(\n t.memberExpression(\n t.cloneWithoutLoc(id),\n t.cloneDeepWithoutLoc(propIdentifier),\n ),\n );\n });\n\n if (!memberAccessors.length) {\n return;\n }\n }\n\n // 生成选择器函数\n // 创建一个新的函数,返回包含所有访问路径的对象\n const selectorName = path.scope.generateUidIdentifier(\"selector_\");\n const selector = t.functionDeclaration(\n selectorName,\n [t.identifier(id.name)],\n t.blockStatement([\n t.returnStatement(\n t.objectExpression(\n memberAccessors.map((accessor) => {\n return t.objectProperty(accessor.identifier, accessor.node);\n }),\n ),\n ),\n ]),\n );\n path.parentPath.insertBefore(selector);\n\n // 修改原始调用为 useShallowSnapshot\n callee.property.name = \"useShallowSnapshot\";\n init.arguments = [selectorName];\n}\n\ntype MemberAccessor = {\n node: MemberExpression | OptionalMemberExpression;\n identifier: Identifier;\n};\n\n/**\n * 查找成员表达式链\n * 例如: a.b.c 会找到最后一个成员表达式 a.b.c\n *\n * @param path - 当前节点路径\n * @returns {\n * memberExprStart - 成员表达式的起始节点\n * nodePath - 当前节点路径\n * accessKey - 完整的访问路径字符串\n * }\n */\nfunction findMemberExpression(path: NodePath) {\n let current: NodePath | null = path;\n let memberExprStart: MemberAccessor[\"node\"] | undefined;\n let accessKey = \"\";\n\n while (current?.parentPath) {\n const parent = current.parentPath;\n const node = parent.node;\n\n if (\n (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) &&\n t.isIdentifier(node.property)\n ) {\n memberExprStart = node;\n current = parent;\n accessKey += \".\" + node.property.name;\n } else {\n break; // 如果不是成员表达式,立即停止向上查找\n }\n }\n\n return { memberExprStart, nodePath: current, accessKey };\n}\n","import type { NodePath } from \"@babel/traverse\";\nimport type { VariableDeclarator } from \"@babel/types\";\nimport t from \"@babel/types\";\nimport { handleSelectorArgument } from \"./shared\";\n\n/**\n * 处理 store.useSnapshot() 的变量声明\n * 示例: const { a, c: { name } } = store.useSnapshot()\n * 将会转换为:\n * function selector({ a, c: { name } } ) { return { a, c: { name } } }\n * const { a, c: { name } } = store.useShallowSnapshot(selector)\n */\nexport function handleObjectPattern(path: NodePath<VariableDeclarator>) {\n const { id, init } = path.node;\n\n // 预检查:确保是 CallExpression 且变量是 ObjectPattern\n if (!t.isCallExpression(init) || !t.isObjectPattern(id)) {\n return;\n }\n if (!t.isMemberExpression(init.callee)) {\n return;\n }\n\n // 检查是否为 store.useSnapshot 调用\n const callee = init.callee;\n if (\n !t.isIdentifier(callee.property) ||\n callee.property.name !== \"useSnapshot\"\n ) {\n return;\n }\n // 如果已经有 selector 参数,则不需要转换\n if (init.arguments.length > 0) {\n if (handleSelectorArgument(init)) {\n callee.property.name = \"useShallowSnapshot\";\n }\n return;\n }\n\n // 进入主流程\n // 进入主流程\n const selectorName = path.scope.generateUidIdentifier(\"selector_\");\n\n // 创建 selector 函数,使用相同的解构模式\n const selector = t.functionDeclaration(\n selectorName,\n [t.cloneDeepWithoutLoc(id)],\n t.blockStatement([\n t.returnStatement(\n t.objectExpression(\n id.properties.map((v) => {\n if (t.isRestElement(v)) {\n if (!t.isIdentifier(v.argument)) {\n throw path.buildCodeFrameError(\n \"Rest element in object pattern must be a simple identifier\",\n );\n }\n return t.spreadElement(t.cloneDeepWithoutLoc(v.argument));\n }\n return t.cloneDeepWithoutLoc(v);\n }),\n ),\n ),\n ]),\n );\n\n // 插入 selector 函数声明\n path.parentPath.insertBefore(selector);\n\n // 修改为使用 useShallowSnapshot 并传入选择器\n callee.property.name = \"useShallowSnapshot\";\n init.arguments = [selectorName];\n}\n","import type babel from \"@babel/core\";\nimport type { PluginObj } from \"@babel/core\";\nimport { handleIdentifierSnapshot } from \"./handleIdentifierSnapshot\";\nimport { handleObjectPattern } from \"./handleObjectPattern\";\n\nexport const createStorePlugin = (api: typeof babel): PluginObj => {\n return {\n name: \"create-store\",\n visitor: {\n VariableDeclarator(path) {\n handleIdentifierSnapshot(path);\n handleObjectPattern(path);\n },\n },\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import babel, { PluginObj } from "@babel/core";
2
+
3
+ //#region src/createStore/index.d.ts
4
+ declare const createStorePlugin: (api: typeof babel) => PluginObj;
5
+ //#endregion
6
+ export { createStorePlugin };
7
+ //# sourceMappingURL=createStore.d.cts.map
@@ -0,0 +1,7 @@
1
+ import babel, { PluginObj } from "@babel/core";
2
+
3
+ //#region src/createStore/index.d.ts
4
+ declare const createStorePlugin: (api: typeof babel) => PluginObj;
5
+ //#endregion
6
+ export { createStorePlugin };
7
+ //# sourceMappingURL=createStore.d.mts.map
@@ -0,0 +1,153 @@
1
+ import t from "@babel/types";
2
+
3
+ //#region src/createStore/shared.ts
4
+ /**
5
+ * 检查 selector 参数的返回值类型
6
+ * 如果返回值是对象类型,则将 useSnapshot 转换为 useShallowSnapshot
7
+ */
8
+ function handleSelectorArgument(init) {
9
+ const selector = init.arguments[0];
10
+ if (t.isFunctionExpression(selector) || t.isArrowFunctionExpression(selector)) {
11
+ const body = selector.body;
12
+ if (t.isBlockStatement(body)) {
13
+ const returnStmt = body.body.find((stmt) => t.isReturnStatement(stmt));
14
+ if (returnStmt && t.isReturnStatement(returnStmt) && t.isObjectExpression(returnStmt.argument)) return true;
15
+ } else if (t.isObjectExpression(body)) return true;
16
+ }
17
+ return false;
18
+ }
19
+
20
+ //#endregion
21
+ //#region src/createStore/handleIdentifierSnapshot.ts
22
+ /**
23
+ * 处理 store.useSnapshot() 的变量声明
24
+ * 示例: const state = store.useSnapshot()
25
+ * 将会转换为:
26
+ * function selector(state) { return { _prop: state.a.b } }
27
+ * const state = store.useShallowSnapshot(selector)
28
+ */
29
+ function handleIdentifierSnapshot(path) {
30
+ const { id, init } = path.node;
31
+ if (!t.isCallExpression(init) || !t.isIdentifier(id)) return;
32
+ if (!t.isMemberExpression(init.callee)) return;
33
+ const callee = init.callee;
34
+ if (!t.isIdentifier(callee.property) || callee.property.name !== "useSnapshot") return;
35
+ if (init.arguments.length > 0) {
36
+ if (handleSelectorArgument(init)) callee.property.name = "useShallowSnapshot";
37
+ return;
38
+ }
39
+ const memberAccessors = [];
40
+ const accessorMap = /* @__PURE__ */ new Map();
41
+ {
42
+ const binding = path.scope.getOwnBinding(id.name);
43
+ const arr = [];
44
+ binding === null || binding === void 0 || binding.referencePaths.forEach((refPath) => {
45
+ const { memberExprStart, nodePath, accessKey } = findMemberExpression(refPath);
46
+ if (memberExprStart && nodePath && accessKey) arr.push({
47
+ memberExprStart,
48
+ nodePath,
49
+ accessKey
50
+ });
51
+ });
52
+ if (!arr.length || arr.length !== (binding === null || binding === void 0 ? void 0 : binding.referencePaths.length)) return;
53
+ arr.forEach((item) => {
54
+ const { memberExprStart, nodePath, accessKey } = item;
55
+ let propIdentifier = accessorMap.get(accessKey);
56
+ if (!propIdentifier) {
57
+ propIdentifier = path.scope.generateUidIdentifier("prop_");
58
+ accessorMap.set(accessKey, propIdentifier);
59
+ memberAccessors.push({
60
+ node: t.cloneDeepWithoutLoc(memberExprStart),
61
+ identifier: propIdentifier
62
+ });
63
+ }
64
+ nodePath.replaceWith(t.memberExpression(t.cloneWithoutLoc(id), t.cloneDeepWithoutLoc(propIdentifier)));
65
+ });
66
+ if (!memberAccessors.length) return;
67
+ }
68
+ const selectorName = path.scope.generateUidIdentifier("selector_");
69
+ const selector = t.functionDeclaration(selectorName, [t.identifier(id.name)], t.blockStatement([t.returnStatement(t.objectExpression(memberAccessors.map((accessor) => {
70
+ return t.objectProperty(accessor.identifier, accessor.node);
71
+ })))]));
72
+ path.parentPath.insertBefore(selector);
73
+ callee.property.name = "useShallowSnapshot";
74
+ init.arguments = [selectorName];
75
+ }
76
+ /**
77
+ * 查找成员表达式链
78
+ * 例如: a.b.c 会找到最后一个成员表达式 a.b.c
79
+ *
80
+ * @param path - 当前节点路径
81
+ * @returns {
82
+ * memberExprStart - 成员表达式的起始节点
83
+ * nodePath - 当前节点路径
84
+ * accessKey - 完整的访问路径字符串
85
+ * }
86
+ */
87
+ function findMemberExpression(path) {
88
+ let current = path;
89
+ let memberExprStart;
90
+ let accessKey = "";
91
+ while (current === null || current === void 0 ? void 0 : current.parentPath) {
92
+ const parent = current.parentPath;
93
+ const node = parent.node;
94
+ if ((t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) && t.isIdentifier(node.property)) {
95
+ memberExprStart = node;
96
+ current = parent;
97
+ accessKey += "." + node.property.name;
98
+ } else break;
99
+ }
100
+ return {
101
+ memberExprStart,
102
+ nodePath: current,
103
+ accessKey
104
+ };
105
+ }
106
+
107
+ //#endregion
108
+ //#region src/createStore/handleObjectPattern.ts
109
+ /**
110
+ * 处理 store.useSnapshot() 的变量声明
111
+ * 示例: const { a, c: { name } } = store.useSnapshot()
112
+ * 将会转换为:
113
+ * function selector({ a, c: { name } } ) { return { a, c: { name } } }
114
+ * const { a, c: { name } } = store.useShallowSnapshot(selector)
115
+ */
116
+ function handleObjectPattern(path) {
117
+ const { id, init } = path.node;
118
+ if (!t.isCallExpression(init) || !t.isObjectPattern(id)) return;
119
+ if (!t.isMemberExpression(init.callee)) return;
120
+ const callee = init.callee;
121
+ if (!t.isIdentifier(callee.property) || callee.property.name !== "useSnapshot") return;
122
+ if (init.arguments.length > 0) {
123
+ if (handleSelectorArgument(init)) callee.property.name = "useShallowSnapshot";
124
+ return;
125
+ }
126
+ const selectorName = path.scope.generateUidIdentifier("selector_");
127
+ const selector = t.functionDeclaration(selectorName, [t.cloneDeepWithoutLoc(id)], t.blockStatement([t.returnStatement(t.objectExpression(id.properties.map((v) => {
128
+ if (t.isRestElement(v)) {
129
+ if (!t.isIdentifier(v.argument)) throw path.buildCodeFrameError("Rest element in object pattern must be a simple identifier");
130
+ return t.spreadElement(t.cloneDeepWithoutLoc(v.argument));
131
+ }
132
+ return t.cloneDeepWithoutLoc(v);
133
+ })))]));
134
+ path.parentPath.insertBefore(selector);
135
+ callee.property.name = "useShallowSnapshot";
136
+ init.arguments = [selectorName];
137
+ }
138
+
139
+ //#endregion
140
+ //#region src/createStore/index.ts
141
+ const createStorePlugin = (api) => {
142
+ return {
143
+ name: "create-store",
144
+ visitor: { VariableDeclarator(path) {
145
+ handleIdentifierSnapshot(path);
146
+ handleObjectPattern(path);
147
+ } }
148
+ };
149
+ };
150
+
151
+ //#endregion
152
+ export { createStorePlugin };
153
+ //# sourceMappingURL=createStore.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createStore.mjs","names":[],"sources":["../src/createStore/shared.ts","../src/createStore/handleIdentifierSnapshot.ts","../src/createStore/handleObjectPattern.ts","../src/createStore/index.ts"],"sourcesContent":["import type { CallExpression } from \"@babel/types\";\nimport t from \"@babel/types\";\n\n/**\n * 检查 selector 参数的返回值类型\n * 如果返回值是对象类型,则将 useSnapshot 转换为 useShallowSnapshot\n */\nexport function handleSelectorArgument(init: CallExpression) {\n const selector = init.arguments[0];\n if (\n t.isFunctionExpression(selector) ||\n t.isArrowFunctionExpression(selector)\n ) {\n const body = selector.body;\n if (t.isBlockStatement(body)) {\n const returnStmt = body.body.find((stmt) => t.isReturnStatement(stmt));\n if (\n returnStmt &&\n t.isReturnStatement(returnStmt) &&\n t.isObjectExpression(returnStmt.argument)\n ) {\n return true;\n }\n } else if (t.isObjectExpression(body)) {\n return true;\n }\n }\n return false;\n}\n","import type { NodePath } from \"@babel/traverse\";\nimport type {\n Identifier,\n MemberExpression,\n OptionalMemberExpression,\n VariableDeclarator,\n} from \"@babel/types\";\nimport t from \"@babel/types\";\nimport { handleSelectorArgument } from \"./shared\";\n/**\n * 处理 store.useSnapshot() 的变量声明\n * 示例: const state = store.useSnapshot()\n * 将会转换为:\n * function selector(state) { return { _prop: state.a.b } }\n * const state = store.useShallowSnapshot(selector)\n */\nexport function handleIdentifierSnapshot(path: NodePath<VariableDeclarator>) {\n const { id, init } = path.node;\n\n // 预检查:确保是 CallExpression 且变量是标识符\n if (!t.isCallExpression(init) || !t.isIdentifier(id)) {\n return;\n }\n if (!t.isMemberExpression(init.callee)) {\n return;\n }\n\n // 检查是否为 store.useSnapshot 调用\n const callee = init.callee;\n if (\n !t.isIdentifier(callee.property) ||\n callee.property.name !== \"useSnapshot\"\n ) {\n return;\n }\n\n // 如果已经有 selector 参数,则需要检查返回值类型\n // 如果返回值是对象类型,则转换为 useShallowSnapshot\n if (init.arguments.length > 0) {\n if (handleSelectorArgument(init)) {\n callee.property.name = \"useShallowSnapshot\";\n }\n return;\n }\n\n // 初始化成员访问器数组和访问器映射\n // memberAccessors 用于存储所有的成员访问表达式\n // accessorMap 用于缓存已处理过的访问路径,避免重复创建\n const memberAccessors: MemberAccessor[] = [];\n const accessorMap = new Map<string, Identifier>();\n {\n // 获取变量的绑定信息,用于查找所有引用\n const binding = path.scope.getOwnBinding(id.name);\n\n // 存储所有有效的成员表达式访问\n const arr: ReturnType<typeof findMemberExpression>[] = [];\n\n // 第一次遍历:收集所有有效的成员表达式\n binding?.referencePaths.forEach((refPath) => {\n const { memberExprStart, nodePath, accessKey } =\n findMemberExpression(refPath);\n if (memberExprStart && nodePath && accessKey) {\n arr.push({ memberExprStart, nodePath, accessKey });\n }\n });\n\n // 如果存在无效的成员表达式访问,则不进行转换\n if (!arr.length || arr.length !== binding?.referencePaths.length) {\n return;\n }\n\n // 第二次遍历:处理每个成员表达式\n // 1. 为每个唯一的访问路径生成标识符\n // 2. 收集成员访问器信息\n // 3. 替换原始表达式为新的访问方式\n arr.forEach((item) => {\n const { memberExprStart, nodePath, accessKey } = item;\n let propIdentifier = accessorMap.get(accessKey);\n if (!propIdentifier) {\n // 生成唯一的属性标识符\n propIdentifier = path.scope.generateUidIdentifier(\"prop_\");\n accessorMap.set(accessKey, propIdentifier);\n memberAccessors.push({\n node: t.cloneDeepWithoutLoc(memberExprStart!),\n identifier: propIdentifier,\n });\n }\n\n // 替换原始的成员表达式为新的访问方式\n nodePath!.replaceWith(\n t.memberExpression(\n t.cloneWithoutLoc(id),\n t.cloneDeepWithoutLoc(propIdentifier),\n ),\n );\n });\n\n if (!memberAccessors.length) {\n return;\n }\n }\n\n // 生成选择器函数\n // 创建一个新的函数,返回包含所有访问路径的对象\n const selectorName = path.scope.generateUidIdentifier(\"selector_\");\n const selector = t.functionDeclaration(\n selectorName,\n [t.identifier(id.name)],\n t.blockStatement([\n t.returnStatement(\n t.objectExpression(\n memberAccessors.map((accessor) => {\n return t.objectProperty(accessor.identifier, accessor.node);\n }),\n ),\n ),\n ]),\n );\n path.parentPath.insertBefore(selector);\n\n // 修改原始调用为 useShallowSnapshot\n callee.property.name = \"useShallowSnapshot\";\n init.arguments = [selectorName];\n}\n\ntype MemberAccessor = {\n node: MemberExpression | OptionalMemberExpression;\n identifier: Identifier;\n};\n\n/**\n * 查找成员表达式链\n * 例如: a.b.c 会找到最后一个成员表达式 a.b.c\n *\n * @param path - 当前节点路径\n * @returns {\n * memberExprStart - 成员表达式的起始节点\n * nodePath - 当前节点路径\n * accessKey - 完整的访问路径字符串\n * }\n */\nfunction findMemberExpression(path: NodePath) {\n let current: NodePath | null = path;\n let memberExprStart: MemberAccessor[\"node\"] | undefined;\n let accessKey = \"\";\n\n while (current?.parentPath) {\n const parent = current.parentPath;\n const node = parent.node;\n\n if (\n (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) &&\n t.isIdentifier(node.property)\n ) {\n memberExprStart = node;\n current = parent;\n accessKey += \".\" + node.property.name;\n } else {\n break; // 如果不是成员表达式,立即停止向上查找\n }\n }\n\n return { memberExprStart, nodePath: current, accessKey };\n}\n","import type { NodePath } from \"@babel/traverse\";\nimport type { VariableDeclarator } from \"@babel/types\";\nimport t from \"@babel/types\";\nimport { handleSelectorArgument } from \"./shared\";\n\n/**\n * 处理 store.useSnapshot() 的变量声明\n * 示例: const { a, c: { name } } = store.useSnapshot()\n * 将会转换为:\n * function selector({ a, c: { name } } ) { return { a, c: { name } } }\n * const { a, c: { name } } = store.useShallowSnapshot(selector)\n */\nexport function handleObjectPattern(path: NodePath<VariableDeclarator>) {\n const { id, init } = path.node;\n\n // 预检查:确保是 CallExpression 且变量是 ObjectPattern\n if (!t.isCallExpression(init) || !t.isObjectPattern(id)) {\n return;\n }\n if (!t.isMemberExpression(init.callee)) {\n return;\n }\n\n // 检查是否为 store.useSnapshot 调用\n const callee = init.callee;\n if (\n !t.isIdentifier(callee.property) ||\n callee.property.name !== \"useSnapshot\"\n ) {\n return;\n }\n // 如果已经有 selector 参数,则不需要转换\n if (init.arguments.length > 0) {\n if (handleSelectorArgument(init)) {\n callee.property.name = \"useShallowSnapshot\";\n }\n return;\n }\n\n // 进入主流程\n // 进入主流程\n const selectorName = path.scope.generateUidIdentifier(\"selector_\");\n\n // 创建 selector 函数,使用相同的解构模式\n const selector = t.functionDeclaration(\n selectorName,\n [t.cloneDeepWithoutLoc(id)],\n t.blockStatement([\n t.returnStatement(\n t.objectExpression(\n id.properties.map((v) => {\n if (t.isRestElement(v)) {\n if (!t.isIdentifier(v.argument)) {\n throw path.buildCodeFrameError(\n \"Rest element in object pattern must be a simple identifier\",\n );\n }\n return t.spreadElement(t.cloneDeepWithoutLoc(v.argument));\n }\n return t.cloneDeepWithoutLoc(v);\n }),\n ),\n ),\n ]),\n );\n\n // 插入 selector 函数声明\n path.parentPath.insertBefore(selector);\n\n // 修改为使用 useShallowSnapshot 并传入选择器\n callee.property.name = \"useShallowSnapshot\";\n init.arguments = [selectorName];\n}\n","import type babel from \"@babel/core\";\nimport type { PluginObj } from \"@babel/core\";\nimport { handleIdentifierSnapshot } from \"./handleIdentifierSnapshot\";\nimport { handleObjectPattern } from \"./handleObjectPattern\";\n\nexport const createStorePlugin = (api: typeof babel): PluginObj => {\n return {\n name: \"create-store\",\n visitor: {\n VariableDeclarator(path) {\n handleIdentifierSnapshot(path);\n handleObjectPattern(path);\n },\n },\n };\n};\n"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -1,176 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/i18n/tFunction.ts
2
- var tFunctionPlugin = (api) => {
3
- const { types: t } = api;
4
- const tFunction = t.identifier("t");
5
- return {
6
- name: "tFunctionPlugin",
7
- visitor: {
8
- TaggedTemplateExpression(path) {
9
- const { tag, quasi } = path.node;
10
- if (tag.type !== "Identifier" || tag.name !== "t") {
11
- return;
12
- }
13
- const { quasis, expressions } = quasi;
14
- let id = "";
15
- let slots = {};
16
- let hasSlots = false;
17
- quasis.forEach((v, i) => {
18
- id += v.value.raw;
19
- const exp = expressions[i];
20
- if (t.isExpression(exp)) {
21
- const varName = t.isIdentifier(exp) ? exp.name : i;
22
- id += `{${varName}}`;
23
- slots[varName] = exp;
24
- hasSlots = true;
25
- }
26
- });
27
- const args = [t.stringLiteral(id)];
28
- if (hasSlots) {
29
- const slotsObj = t.objectExpression(
30
- Object.entries(slots).map(([key, value]) => {
31
- return t.objectProperty(t.identifier(key), value);
32
- })
33
- );
34
- args.push(slotsObj);
35
- }
36
- path.replaceWith(t.callExpression(tFunction, args));
37
- }
38
- }
39
- };
40
- };
41
-
42
- // src/i18n/trans.ts
43
- var transPlugin = (api) => {
44
- const { types: t } = api;
45
- const TransJSXIdent = t.jsxIdentifier("Trans");
46
- const idJSXIdent = t.jsxIdentifier("id");
47
- const messageJSXIdent = t.jsxIdentifier("message");
48
- const valuesJSXIdent = t.jsxIdentifier("values");
49
- const componentsJSXIdent = t.jsxIdentifier("components");
50
- return {
51
- name: "transPlugin",
52
- visitor: {
53
- JSXElement(path) {
54
- const { openingElement } = path.node;
55
- if (!t.isJSXIdentifier(openingElement.name, TransJSXIdent)) {
56
- return;
57
- }
58
- let id = "";
59
- let userDefinedId = false;
60
- openingElement.attributes.forEach((attr) => {
61
- if (userDefinedId) {
62
- return;
63
- }
64
- if (!t.isJSXAttribute(attr) || !t.isJSXIdentifier(attr.name, idJSXIdent)) {
65
- return;
66
- }
67
- let idExpr;
68
- if (t.isJSXExpressionContainer(attr.value) && t.isStringLiteral(attr.value.expression)) {
69
- idExpr = attr.value.expression;
70
- } else if (t.isStringLiteral(attr.value)) {
71
- idExpr = attr.value;
72
- }
73
- if (!idExpr) {
74
- throw path.buildCodeFrameError(
75
- `Trans id attribute must be static string`,
76
- Error
77
- );
78
- }
79
- id = idExpr.value;
80
- userDefinedId = true;
81
- });
82
- const { msg, vars, components } = workChildren(path.node.children, t);
83
- if (!userDefinedId) {
84
- id = msg;
85
- }
86
- path.node.children = [];
87
- if (!userDefinedId) {
88
- openingElement.attributes.push(
89
- t.jsxAttribute(idJSXIdent, t.stringLiteral(id))
90
- );
91
- }
92
- if (id !== msg) {
93
- openingElement.attributes.push(
94
- t.jsxAttribute(messageJSXIdent, t.stringLiteral(msg))
95
- );
96
- }
97
- const valuesAttr = exprMapToJSXAttribute(valuesJSXIdent, vars, t);
98
- if (valuesAttr) {
99
- openingElement.attributes.push(valuesAttr);
100
- }
101
- const componentsAttr = exprMapToJSXAttribute(
102
- componentsJSXIdent,
103
- components,
104
- t
105
- );
106
- if (componentsAttr) {
107
- openingElement.attributes.push(componentsAttr);
108
- }
109
- }
110
- }
111
- };
112
- };
113
- function workChildren(children, t, vars = {}, components = {}, i = 0) {
114
- let msg = "";
115
- children.forEach((child, index) => {
116
- if (t.isJSXText(child)) {
117
- const text = child.value.replace(/^\n\s*/, "").replace(/\s*\n$/, "").replace(/\n\s*$/, " ");
118
- msg += text;
119
- return;
120
- }
121
- if (t.isJSXExpressionContainer(child)) {
122
- if (t.isJSXEmptyExpression(child.expression)) {
123
- return;
124
- }
125
- let varName = "";
126
- if (t.isIdentifier(child.expression)) {
127
- varName = child.expression.name;
128
- } else {
129
- varName = i + "";
130
- i++;
131
- }
132
- vars[varName] = child.expression;
133
- msg += `{${varName}}`;
134
- return;
135
- }
136
- if (t.isJSXElement(child)) {
137
- if (child.children.length) {
138
- msg += `<${i}>`;
139
- const { msg: childMsg, i: childI } = workChildren(
140
- child.children,
141
- t,
142
- vars,
143
- components,
144
- i + 1
145
- );
146
- components[i] = child;
147
- msg += childMsg;
148
- msg += `</${i}>`;
149
- i = childI;
150
- } else {
151
- msg += `<${i}/>`;
152
- components[i] = child;
153
- i++;
154
- }
155
- return;
156
- }
157
- });
158
- return { msg, i, vars, components };
159
- }
160
- function exprMapToJSXAttribute(keyIdentifier, exprMap, t) {
161
- const props = [];
162
- Object.entries(exprMap).forEach(([key, value]) => {
163
- props.push(t.objectProperty(t.identifier(key), value));
164
- });
165
- if (props.length) {
166
- return t.jsxAttribute(
167
- keyIdentifier,
168
- t.jsxExpressionContainer(t.objectExpression(props))
169
- );
170
- }
171
- }
172
-
173
-
174
-
175
- exports.tFunctionPlugin = tFunctionPlugin; exports.transPlugin = transPlugin;
176
- //# sourceMappingURL=index.cjs.map
package/dist/index.d.cts CHANGED
@@ -1,7 +1 @@
1
- import babel, { PluginObj } from '@babel/core';
2
-
3
- declare const tFunctionPlugin: (api: typeof babel) => PluginObj;
4
-
5
- declare const transPlugin: (api: typeof babel) => PluginObj;
6
-
7
- export { tFunctionPlugin, transPlugin };
1
+ export { };
@@ -0,0 +1 @@
1
+ export { };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ export { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dune2/babel",
3
- "version": "0.4.2",
3
+ "version": "1.0.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/liaoyinglong/next-tools.git",
@@ -9,9 +9,9 @@
9
9
  "type": "module",
10
10
  "exports": {
11
11
  ".": {
12
+ "types": "./dist/index.d.ts",
12
13
  "import": "./dist/index.js",
13
- "require": "./dist/index.cjs",
14
- "types": "./dist/index.d.ts"
14
+ "require": "./dist/index.cjs"
15
15
  },
16
16
  "./package.json": "./package.json"
17
17
  },
@@ -31,14 +31,14 @@
31
31
  "@types/babel__generator": "7.6.8",
32
32
  "@types/babel__traverse": "7.20.6",
33
33
  "@types/debug": "4.1.7",
34
- "tsup": "8"
34
+ "tsdown": "^0.19.0"
35
35
  },
36
36
  "publishConfig": {
37
37
  "access": "public"
38
38
  },
39
39
  "scripts": {
40
40
  "prebuild": "tsc --diagnostics",
41
- "build": "tsup --clean --splitting",
41
+ "build": "tsdown --clean --splitting",
42
42
  "build-fast": "pnpm run build --no-dts",
43
43
  "dev": "pnpm run build-fast --watch",
44
44
  "test": "vitest run",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/i18n/tFunction.ts","../src/i18n/trans.ts"],"names":[],"mappings":"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","sourcesContent":["import type babel from \"@babel/core\";\nimport type { PluginObj } from \"@babel/core\";\nimport type { Expression } from \"@babel/types\";\n\nexport const tFunctionPlugin = (api: typeof babel): PluginObj => {\n const { types: t } = api;\n\n const tFunction = t.identifier(\"t\");\n\n return {\n name: \"tFunctionPlugin\",\n visitor: {\n TaggedTemplateExpression(path) {\n const { tag, quasi } = path.node;\n if (tag.type !== \"Identifier\" || tag.name !== \"t\") {\n // not t function\n return;\n }\n const { quasis, expressions } = quasi;\n let id = \"\";\n let slots: Record<string, Expression> = {};\n let hasSlots = false;\n\n quasis.forEach((v, i) => {\n id += v.value.raw;\n const exp = expressions[i];\n if (t.isExpression(exp)) {\n // 能获取到变量名的情况,用变量名,否则用索引\n // t`Refresh inbox ${name}` => name\n // t`Refresh inbox ${obj.name}` => 0\n const varName = t.isIdentifier(exp) ? exp.name : i;\n id += `{${varName}}`;\n slots[varName] = exp;\n hasSlots = true;\n }\n });\n\n // 组装新\n // t(id,{ [key]: value })\n const args: Expression[] = [t.stringLiteral(id)];\n if (hasSlots) {\n const slotsObj = t.objectExpression(\n Object.entries(slots).map(([key, value]) => {\n return t.objectProperty(t.identifier(key), value);\n }),\n );\n args.push(slotsObj);\n }\n path.replaceWith(t.callExpression(tFunction, args));\n },\n },\n };\n};\n","import type babel from \"@babel/core\";\nimport type { PluginObj } from \"@babel/core\";\nimport type {\n Expression,\n JSXAttribute,\n JSXElement,\n JSXIdentifier,\n ObjectProperty,\n StringLiteral,\n} from \"@babel/types\";\n\nexport const transPlugin = (api: typeof babel): PluginObj => {\n const { types: t } = api;\n\n const TransJSXIdent = t.jsxIdentifier(\"Trans\");\n const idJSXIdent = t.jsxIdentifier(\"id\");\n const messageJSXIdent = t.jsxIdentifier(\"message\");\n const valuesJSXIdent = t.jsxIdentifier(\"values\");\n const componentsJSXIdent = t.jsxIdentifier(\"components\");\n\n return {\n name: \"transPlugin\",\n visitor: {\n JSXElement(path) {\n const { openingElement } = path.node;\n if (!t.isJSXIdentifier(openingElement.name, TransJSXIdent)) {\n // 不是 Trans 组件\n return;\n }\n let id = \"\";\n let userDefinedId = false;\n\n openingElement.attributes.forEach((attr) => {\n if (userDefinedId) {\n return;\n }\n if (\n !t.isJSXAttribute(attr) ||\n !t.isJSXIdentifier(attr.name, idJSXIdent)\n ) {\n // 不是 <Trans id=\"xxx\" ></Trans>\n return;\n }\n let idExpr: StringLiteral | undefined;\n if (\n t.isJSXExpressionContainer(attr.value) &&\n t.isStringLiteral(attr.value.expression)\n ) {\n idExpr = attr.value.expression;\n } else if (t.isStringLiteral(attr.value)) {\n idExpr = attr.value;\n }\n\n if (!idExpr) {\n // 不支持 id 属性为变量 或者 模版字符串\n throw path.buildCodeFrameError(\n `Trans id attribute must be static string`,\n Error,\n );\n }\n id = idExpr.value;\n userDefinedId = true;\n });\n\n const { msg, vars, components } = workChildren(path.node.children, t);\n if (!userDefinedId) {\n // 外部没有指定 id,则使用从 children 中提取的文本\n id = msg;\n }\n\n // 清空 children,Trans 组件编译后没有 children\n path.node.children = [];\n // 添加 id props\n if (!userDefinedId) {\n openingElement.attributes.push(\n t.jsxAttribute(idJSXIdent, t.stringLiteral(id)),\n );\n }\n // 添加 message props\n if (id !== msg) {\n openingElement.attributes.push(\n t.jsxAttribute(messageJSXIdent, t.stringLiteral(msg)),\n );\n }\n // 添加 values props\n const valuesAttr = exprMapToJSXAttribute(valuesJSXIdent, vars, t);\n if (valuesAttr) {\n openingElement.attributes.push(valuesAttr);\n }\n // 添加 components props\n const componentsAttr = exprMapToJSXAttribute(\n componentsJSXIdent,\n components,\n t,\n );\n if (componentsAttr) {\n openingElement.attributes.push(componentsAttr);\n }\n },\n },\n };\n};\n\nfunction workChildren(\n children: JSXElement[\"children\"],\n t: typeof babel.types,\n vars: Record<string, Expression> = {},\n components: Record<string, Expression> = {},\n i: number = 0,\n) {\n let msg = \"\";\n children.forEach((child, index) => {\n if (t.isJSXText(child)) {\n // 开头 和 结尾 babel 都会包括回车,如果有的话\n const text = child.value\n // 换行 + 空格 开头\n .replace(/^\\n\\s*/, \"\")\n // 空格 + 换行 结尾\n .replace(/\\s*\\n$/, \"\")\n // 换行 + 空格 结尾\n .replace(/\\n\\s*$/, \" \");\n msg += text;\n return;\n }\n if (t.isJSXExpressionContainer(child)) {\n if (t.isJSXEmptyExpression(child.expression)) {\n // 空表达式,直接忽略\n // case: <Trans>hello {}</Trans>\n return;\n }\n let varName = \"\";\n if (t.isIdentifier(child.expression)) {\n // 能获取到变量名的情况,用变量名,否则用索引\n // case: <Trans>hello {name}</Trans>\n varName = child.expression.name;\n } else {\n // 直接用 索引\n // case: <Trans>hello {user.name}</Trans>\n varName = i + \"\";\n i++;\n }\n vars[varName] = child.expression;\n msg += `{${varName}}`;\n return;\n }\n if (t.isJSXElement(child)) {\n if (child.children.length) {\n // case: <Trans>hello <a>world</a></Trans>\n // 中的 <a>world</a>\n msg += `<${i}>`;\n const { msg: childMsg, i: childI } = workChildren(\n child.children,\n t,\n vars,\n components,\n i + 1,\n );\n components[i] = child;\n msg += childMsg;\n msg += `</${i}>`;\n i = childI;\n } else {\n // case: <Trans>hello <br/> world</Trans>\n msg += `<${i}/>`;\n components[i] = child;\n i++;\n }\n return;\n }\n });\n\n return { msg, i, vars, components };\n}\n\nfunction exprMapToJSXAttribute(\n keyIdentifier: JSXIdentifier,\n exprMap: Record<string, Expression>,\n\n t: typeof babel.types,\n): JSXAttribute | undefined {\n const props: ObjectProperty[] = [];\n Object.entries(exprMap).forEach(([key, value]) => {\n props.push(t.objectProperty(t.identifier(key), value));\n });\n if (props.length) {\n return t.jsxAttribute(\n keyIdentifier,\n t.jsxExpressionContainer(t.objectExpression(props)),\n );\n }\n}\n"]}
package/dist/index.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import babel, { PluginObj } from '@babel/core';
2
-
3
- declare const tFunctionPlugin: (api: typeof babel) => PluginObj;
4
-
5
- declare const transPlugin: (api: typeof babel) => PluginObj;
6
-
7
- export { tFunctionPlugin, transPlugin };
package/dist/index.js DELETED
@@ -1,176 +0,0 @@
1
- // src/i18n/tFunction.ts
2
- var tFunctionPlugin = (api) => {
3
- const { types: t } = api;
4
- const tFunction = t.identifier("t");
5
- return {
6
- name: "tFunctionPlugin",
7
- visitor: {
8
- TaggedTemplateExpression(path) {
9
- const { tag, quasi } = path.node;
10
- if (tag.type !== "Identifier" || tag.name !== "t") {
11
- return;
12
- }
13
- const { quasis, expressions } = quasi;
14
- let id = "";
15
- let slots = {};
16
- let hasSlots = false;
17
- quasis.forEach((v, i) => {
18
- id += v.value.raw;
19
- const exp = expressions[i];
20
- if (t.isExpression(exp)) {
21
- const varName = t.isIdentifier(exp) ? exp.name : i;
22
- id += `{${varName}}`;
23
- slots[varName] = exp;
24
- hasSlots = true;
25
- }
26
- });
27
- const args = [t.stringLiteral(id)];
28
- if (hasSlots) {
29
- const slotsObj = t.objectExpression(
30
- Object.entries(slots).map(([key, value]) => {
31
- return t.objectProperty(t.identifier(key), value);
32
- })
33
- );
34
- args.push(slotsObj);
35
- }
36
- path.replaceWith(t.callExpression(tFunction, args));
37
- }
38
- }
39
- };
40
- };
41
-
42
- // src/i18n/trans.ts
43
- var transPlugin = (api) => {
44
- const { types: t } = api;
45
- const TransJSXIdent = t.jsxIdentifier("Trans");
46
- const idJSXIdent = t.jsxIdentifier("id");
47
- const messageJSXIdent = t.jsxIdentifier("message");
48
- const valuesJSXIdent = t.jsxIdentifier("values");
49
- const componentsJSXIdent = t.jsxIdentifier("components");
50
- return {
51
- name: "transPlugin",
52
- visitor: {
53
- JSXElement(path) {
54
- const { openingElement } = path.node;
55
- if (!t.isJSXIdentifier(openingElement.name, TransJSXIdent)) {
56
- return;
57
- }
58
- let id = "";
59
- let userDefinedId = false;
60
- openingElement.attributes.forEach((attr) => {
61
- if (userDefinedId) {
62
- return;
63
- }
64
- if (!t.isJSXAttribute(attr) || !t.isJSXIdentifier(attr.name, idJSXIdent)) {
65
- return;
66
- }
67
- let idExpr;
68
- if (t.isJSXExpressionContainer(attr.value) && t.isStringLiteral(attr.value.expression)) {
69
- idExpr = attr.value.expression;
70
- } else if (t.isStringLiteral(attr.value)) {
71
- idExpr = attr.value;
72
- }
73
- if (!idExpr) {
74
- throw path.buildCodeFrameError(
75
- `Trans id attribute must be static string`,
76
- Error
77
- );
78
- }
79
- id = idExpr.value;
80
- userDefinedId = true;
81
- });
82
- const { msg, vars, components } = workChildren(path.node.children, t);
83
- if (!userDefinedId) {
84
- id = msg;
85
- }
86
- path.node.children = [];
87
- if (!userDefinedId) {
88
- openingElement.attributes.push(
89
- t.jsxAttribute(idJSXIdent, t.stringLiteral(id))
90
- );
91
- }
92
- if (id !== msg) {
93
- openingElement.attributes.push(
94
- t.jsxAttribute(messageJSXIdent, t.stringLiteral(msg))
95
- );
96
- }
97
- const valuesAttr = exprMapToJSXAttribute(valuesJSXIdent, vars, t);
98
- if (valuesAttr) {
99
- openingElement.attributes.push(valuesAttr);
100
- }
101
- const componentsAttr = exprMapToJSXAttribute(
102
- componentsJSXIdent,
103
- components,
104
- t
105
- );
106
- if (componentsAttr) {
107
- openingElement.attributes.push(componentsAttr);
108
- }
109
- }
110
- }
111
- };
112
- };
113
- function workChildren(children, t, vars = {}, components = {}, i = 0) {
114
- let msg = "";
115
- children.forEach((child, index) => {
116
- if (t.isJSXText(child)) {
117
- const text = child.value.replace(/^\n\s*/, "").replace(/\s*\n$/, "").replace(/\n\s*$/, " ");
118
- msg += text;
119
- return;
120
- }
121
- if (t.isJSXExpressionContainer(child)) {
122
- if (t.isJSXEmptyExpression(child.expression)) {
123
- return;
124
- }
125
- let varName = "";
126
- if (t.isIdentifier(child.expression)) {
127
- varName = child.expression.name;
128
- } else {
129
- varName = i + "";
130
- i++;
131
- }
132
- vars[varName] = child.expression;
133
- msg += `{${varName}}`;
134
- return;
135
- }
136
- if (t.isJSXElement(child)) {
137
- if (child.children.length) {
138
- msg += `<${i}>`;
139
- const { msg: childMsg, i: childI } = workChildren(
140
- child.children,
141
- t,
142
- vars,
143
- components,
144
- i + 1
145
- );
146
- components[i] = child;
147
- msg += childMsg;
148
- msg += `</${i}>`;
149
- i = childI;
150
- } else {
151
- msg += `<${i}/>`;
152
- components[i] = child;
153
- i++;
154
- }
155
- return;
156
- }
157
- });
158
- return { msg, i, vars, components };
159
- }
160
- function exprMapToJSXAttribute(keyIdentifier, exprMap, t) {
161
- const props = [];
162
- Object.entries(exprMap).forEach(([key, value]) => {
163
- props.push(t.objectProperty(t.identifier(key), value));
164
- });
165
- if (props.length) {
166
- return t.jsxAttribute(
167
- keyIdentifier,
168
- t.jsxExpressionContainer(t.objectExpression(props))
169
- );
170
- }
171
- }
172
- export {
173
- tFunctionPlugin,
174
- transPlugin
175
- };
176
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/i18n/tFunction.ts","../src/i18n/trans.ts"],"sourcesContent":["import type babel from \"@babel/core\";\nimport type { PluginObj } from \"@babel/core\";\nimport type { Expression } from \"@babel/types\";\n\nexport const tFunctionPlugin = (api: typeof babel): PluginObj => {\n const { types: t } = api;\n\n const tFunction = t.identifier(\"t\");\n\n return {\n name: \"tFunctionPlugin\",\n visitor: {\n TaggedTemplateExpression(path) {\n const { tag, quasi } = path.node;\n if (tag.type !== \"Identifier\" || tag.name !== \"t\") {\n // not t function\n return;\n }\n const { quasis, expressions } = quasi;\n let id = \"\";\n let slots: Record<string, Expression> = {};\n let hasSlots = false;\n\n quasis.forEach((v, i) => {\n id += v.value.raw;\n const exp = expressions[i];\n if (t.isExpression(exp)) {\n // 能获取到变量名的情况,用变量名,否则用索引\n // t`Refresh inbox ${name}` => name\n // t`Refresh inbox ${obj.name}` => 0\n const varName = t.isIdentifier(exp) ? exp.name : i;\n id += `{${varName}}`;\n slots[varName] = exp;\n hasSlots = true;\n }\n });\n\n // 组装新\n // t(id,{ [key]: value })\n const args: Expression[] = [t.stringLiteral(id)];\n if (hasSlots) {\n const slotsObj = t.objectExpression(\n Object.entries(slots).map(([key, value]) => {\n return t.objectProperty(t.identifier(key), value);\n }),\n );\n args.push(slotsObj);\n }\n path.replaceWith(t.callExpression(tFunction, args));\n },\n },\n };\n};\n","import type babel from \"@babel/core\";\nimport type { PluginObj } from \"@babel/core\";\nimport type {\n Expression,\n JSXAttribute,\n JSXElement,\n JSXIdentifier,\n ObjectProperty,\n StringLiteral,\n} from \"@babel/types\";\n\nexport const transPlugin = (api: typeof babel): PluginObj => {\n const { types: t } = api;\n\n const TransJSXIdent = t.jsxIdentifier(\"Trans\");\n const idJSXIdent = t.jsxIdentifier(\"id\");\n const messageJSXIdent = t.jsxIdentifier(\"message\");\n const valuesJSXIdent = t.jsxIdentifier(\"values\");\n const componentsJSXIdent = t.jsxIdentifier(\"components\");\n\n return {\n name: \"transPlugin\",\n visitor: {\n JSXElement(path) {\n const { openingElement } = path.node;\n if (!t.isJSXIdentifier(openingElement.name, TransJSXIdent)) {\n // 不是 Trans 组件\n return;\n }\n let id = \"\";\n let userDefinedId = false;\n\n openingElement.attributes.forEach((attr) => {\n if (userDefinedId) {\n return;\n }\n if (\n !t.isJSXAttribute(attr) ||\n !t.isJSXIdentifier(attr.name, idJSXIdent)\n ) {\n // 不是 <Trans id=\"xxx\" ></Trans>\n return;\n }\n let idExpr: StringLiteral | undefined;\n if (\n t.isJSXExpressionContainer(attr.value) &&\n t.isStringLiteral(attr.value.expression)\n ) {\n idExpr = attr.value.expression;\n } else if (t.isStringLiteral(attr.value)) {\n idExpr = attr.value;\n }\n\n if (!idExpr) {\n // 不支持 id 属性为变量 或者 模版字符串\n throw path.buildCodeFrameError(\n `Trans id attribute must be static string`,\n Error,\n );\n }\n id = idExpr.value;\n userDefinedId = true;\n });\n\n const { msg, vars, components } = workChildren(path.node.children, t);\n if (!userDefinedId) {\n // 外部没有指定 id,则使用从 children 中提取的文本\n id = msg;\n }\n\n // 清空 children,Trans 组件编译后没有 children\n path.node.children = [];\n // 添加 id props\n if (!userDefinedId) {\n openingElement.attributes.push(\n t.jsxAttribute(idJSXIdent, t.stringLiteral(id)),\n );\n }\n // 添加 message props\n if (id !== msg) {\n openingElement.attributes.push(\n t.jsxAttribute(messageJSXIdent, t.stringLiteral(msg)),\n );\n }\n // 添加 values props\n const valuesAttr = exprMapToJSXAttribute(valuesJSXIdent, vars, t);\n if (valuesAttr) {\n openingElement.attributes.push(valuesAttr);\n }\n // 添加 components props\n const componentsAttr = exprMapToJSXAttribute(\n componentsJSXIdent,\n components,\n t,\n );\n if (componentsAttr) {\n openingElement.attributes.push(componentsAttr);\n }\n },\n },\n };\n};\n\nfunction workChildren(\n children: JSXElement[\"children\"],\n t: typeof babel.types,\n vars: Record<string, Expression> = {},\n components: Record<string, Expression> = {},\n i: number = 0,\n) {\n let msg = \"\";\n children.forEach((child, index) => {\n if (t.isJSXText(child)) {\n // 开头 和 结尾 babel 都会包括回车,如果有的话\n const text = child.value\n // 换行 + 空格 开头\n .replace(/^\\n\\s*/, \"\")\n // 空格 + 换行 结尾\n .replace(/\\s*\\n$/, \"\")\n // 换行 + 空格 结尾\n .replace(/\\n\\s*$/, \" \");\n msg += text;\n return;\n }\n if (t.isJSXExpressionContainer(child)) {\n if (t.isJSXEmptyExpression(child.expression)) {\n // 空表达式,直接忽略\n // case: <Trans>hello {}</Trans>\n return;\n }\n let varName = \"\";\n if (t.isIdentifier(child.expression)) {\n // 能获取到变量名的情况,用变量名,否则用索引\n // case: <Trans>hello {name}</Trans>\n varName = child.expression.name;\n } else {\n // 直接用 索引\n // case: <Trans>hello {user.name}</Trans>\n varName = i + \"\";\n i++;\n }\n vars[varName] = child.expression;\n msg += `{${varName}}`;\n return;\n }\n if (t.isJSXElement(child)) {\n if (child.children.length) {\n // case: <Trans>hello <a>world</a></Trans>\n // 中的 <a>world</a>\n msg += `<${i}>`;\n const { msg: childMsg, i: childI } = workChildren(\n child.children,\n t,\n vars,\n components,\n i + 1,\n );\n components[i] = child;\n msg += childMsg;\n msg += `</${i}>`;\n i = childI;\n } else {\n // case: <Trans>hello <br/> world</Trans>\n msg += `<${i}/>`;\n components[i] = child;\n i++;\n }\n return;\n }\n });\n\n return { msg, i, vars, components };\n}\n\nfunction exprMapToJSXAttribute(\n keyIdentifier: JSXIdentifier,\n exprMap: Record<string, Expression>,\n\n t: typeof babel.types,\n): JSXAttribute | undefined {\n const props: ObjectProperty[] = [];\n Object.entries(exprMap).forEach(([key, value]) => {\n props.push(t.objectProperty(t.identifier(key), value));\n });\n if (props.length) {\n return t.jsxAttribute(\n keyIdentifier,\n t.jsxExpressionContainer(t.objectExpression(props)),\n );\n }\n}\n"],"mappings":"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","names":[]}