@rectify-dev/babel-transform-rectify-jsx 2.0.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/index.cjs ADDED
@@ -0,0 +1,180 @@
1
+ 'use strict';
2
+
3
+ var __defProp = Object.defineProperty;
4
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
5
+
6
+ // src/index.ts
7
+ function jsxMemberToMemberExpr(name, t) {
8
+ const obj = t.isJSXMemberExpression(name.object) ? jsxMemberToMemberExpr(name.object, t) : t.identifier(name.object.name);
9
+ return t.memberExpression(obj, t.identifier(name.property.name));
10
+ }
11
+ __name(jsxMemberToMemberExpr, "jsxMemberToMemberExpr");
12
+ function jsxNameToExpression(name, t) {
13
+ if (t.isJSXIdentifier(name)) {
14
+ return /^[a-z]/.test(name.name) ? t.stringLiteral(name.name) : t.identifier(name.name);
15
+ }
16
+ if (t.isJSXMemberExpression(name)) {
17
+ return jsxMemberToMemberExpr(name, t);
18
+ }
19
+ return t.stringLiteral(`${name.namespace.name}:${name.name.name}`);
20
+ }
21
+ __name(jsxNameToExpression, "jsxNameToExpression");
22
+ function cleanJSXText(raw) {
23
+ const lines = raw.split(/\r\n|\n|\r/);
24
+ let lastNonEmpty = 0;
25
+ for (let i = 0; i < lines.length; i++) {
26
+ if (/[^ \t]/.test(lines[i])) lastNonEmpty = i;
27
+ }
28
+ let result = "";
29
+ for (let i = 0; i < lines.length; i++) {
30
+ let line = lines[i].replace(/\t/g, " ");
31
+ if (i !== 0) line = line.replace(/^[ ]+/, "");
32
+ if (i !== lines.length - 1) line = line.replace(/[ ]+$/, "");
33
+ if (line) {
34
+ if (i !== lastNonEmpty) line += " ";
35
+ result += line;
36
+ }
37
+ }
38
+ return result || null;
39
+ }
40
+ __name(cleanJSXText, "cleanJSXText");
41
+ function buildProps(attributes, children, t) {
42
+ const properties = [];
43
+ for (const attr of attributes) {
44
+ if (t.isJSXSpreadAttribute(attr)) {
45
+ properties.push(t.spreadElement(attr.argument));
46
+ continue;
47
+ }
48
+ const keyName = t.isJSXIdentifier(attr.name) ? attr.name.name : `${attr.name.namespace.name}:${attr.name.name.name}`;
49
+ const key = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(keyName) ? t.identifier(keyName) : t.stringLiteral(keyName);
50
+ let value;
51
+ if (attr.value == null) {
52
+ value = t.booleanLiteral(true);
53
+ } else if (t.isJSXExpressionContainer(attr.value)) {
54
+ value = attr.value.expression;
55
+ } else {
56
+ value = attr.value;
57
+ }
58
+ properties.push(t.objectProperty(key, value));
59
+ }
60
+ if (children.length === 1) {
61
+ properties.push(t.objectProperty(t.identifier("children"), children[0]));
62
+ } else if (children.length > 1) {
63
+ properties.push(
64
+ t.objectProperty(t.identifier("children"), t.arrayExpression(children))
65
+ );
66
+ }
67
+ if (properties.length === 0) return t.nullLiteral();
68
+ return t.objectExpression(properties);
69
+ }
70
+ __name(buildProps, "buildProps");
71
+ function buildChildren(children, t) {
72
+ const result = [];
73
+ for (const child of children) {
74
+ if (t.isJSXText(child)) {
75
+ const clean = cleanJSXText(child.value);
76
+ if (clean !== null) result.push(t.stringLiteral(clean));
77
+ } else if (t.isJSXExpressionContainer(child)) {
78
+ if (!t.isJSXEmptyExpression(child.expression)) {
79
+ result.push(child.expression);
80
+ }
81
+ } else if (t.isJSXSpreadChild(child)) {
82
+ result.push(child.expression);
83
+ } else {
84
+ result.push(child);
85
+ }
86
+ }
87
+ return result;
88
+ }
89
+ __name(buildChildren, "buildChildren");
90
+ var RECTIFY_CORE = "@rectify-dev/core/jsx-runtime";
91
+ function ensureImports(path, state, t) {
92
+ if (!state.usedJsx) return;
93
+ const alreadyBound = /* @__PURE__ */ new Set();
94
+ let runtimeDecl = null;
95
+ path.traverse({
96
+ ImportDeclaration(p) {
97
+ for (const spec of p.node.specifiers) {
98
+ if (t.isImportSpecifier(spec) || t.isImportDefaultSpecifier(spec) || t.isImportNamespaceSpecifier(spec)) {
99
+ alreadyBound.add(spec.local.name);
100
+ }
101
+ }
102
+ if (p.node.source.value === RECTIFY_CORE) {
103
+ runtimeDecl = p.node;
104
+ }
105
+ }
106
+ });
107
+ const toAdd = [];
108
+ if (!alreadyBound.has("jsx")) {
109
+ toAdd.push(t.importSpecifier(t.identifier("jsx"), t.identifier("jsx")));
110
+ }
111
+ if (state.usedFragment && !alreadyBound.has("Fragment")) {
112
+ toAdd.push(
113
+ t.importSpecifier(t.identifier("Fragment"), t.identifier("Fragment"))
114
+ );
115
+ }
116
+ if (toAdd.length === 0) return;
117
+ if (runtimeDecl) {
118
+ runtimeDecl.specifiers.push(...toAdd);
119
+ } else {
120
+ path.unshiftContainer(
121
+ "body",
122
+ t.importDeclaration(toAdd, t.stringLiteral(RECTIFY_CORE))
123
+ );
124
+ }
125
+ }
126
+ __name(ensureImports, "ensureImports");
127
+ function rectifyBabelPlugin({ types: t }) {
128
+ return {
129
+ name: "babel-plugin-rectify",
130
+ manipulateOptions(_opts, parserOpts) {
131
+ if (!parserOpts.plugins.includes("jsx")) parserOpts.plugins.push("jsx");
132
+ if (!parserOpts.plugins.includes("typescript")) parserOpts.plugins.push("typescript");
133
+ },
134
+ visitor: {
135
+ Program: {
136
+ enter(_path, state) {
137
+ state.usedJsx = false;
138
+ state.usedFragment = false;
139
+ },
140
+ exit(path, state) {
141
+ ensureImports(path, state, t);
142
+ }
143
+ },
144
+ JSXElement: {
145
+ exit(path, state) {
146
+ state.usedJsx = true;
147
+ const { openingElement, children } = path.node;
148
+ const typeExpr = jsxNameToExpression(openingElement.name, t);
149
+ if (t.isIdentifier(typeExpr) && typeExpr.name === "Fragment") {
150
+ state.usedFragment = true;
151
+ }
152
+ const childExprs = buildChildren(children, t);
153
+ const propsArg = buildProps(openingElement.attributes, childExprs, t);
154
+ path.replaceWith(
155
+ t.callExpression(t.identifier("jsx"), [typeExpr, propsArg])
156
+ );
157
+ }
158
+ },
159
+ JSXFragment: {
160
+ exit(path, state) {
161
+ state.usedJsx = true;
162
+ state.usedFragment = true;
163
+ const childExprs = buildChildren(path.node.children, t);
164
+ const propsArg = buildProps([], childExprs, t);
165
+ path.replaceWith(
166
+ t.callExpression(t.identifier("jsx"), [
167
+ t.identifier("Fragment"),
168
+ propsArg
169
+ ])
170
+ );
171
+ }
172
+ }
173
+ }
174
+ };
175
+ }
176
+ __name(rectifyBabelPlugin, "rectifyBabelPlugin");
177
+
178
+ module.exports = rectifyBabelPlugin;
179
+ //# sourceMappingURL=index.cjs.map
180
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { PluginObj, PluginPass } from \"@babel/core\";\nimport type {\n Expression,\n Identifier,\n MemberExpression,\n ObjectProperty,\n SpreadElement,\n ImportDeclaration,\n ImportSpecifier,\n JSXElement,\n JSXIdentifier,\n JSXMemberExpression,\n JSXNamespacedName,\n} from \"@babel/types\";\n\ntype BabelTypes = typeof import(\"@babel/types\");\ntype Babel = { types: BabelTypes };\ntype State = PluginPass & { usedJsx: boolean; usedFragment: boolean };\n\n// ─── JSX name → JS expression ────────────────────────────────────────────────\n\n/**\n * Convert a JSXMemberExpression (e.g. `Ctx.Provider`) to a MemberExpression.\n * All parts of a member chain are treated as identifiers, not string literals.\n */\nfunction jsxMemberToMemberExpr(\n name: JSXMemberExpression,\n t: BabelTypes,\n): MemberExpression {\n const obj: Identifier | MemberExpression = t.isJSXMemberExpression(name.object)\n ? jsxMemberToMemberExpr(name.object, t)\n : t.identifier(name.object.name);\n return t.memberExpression(obj, t.identifier(name.property.name));\n}\n\n/**\n * Convert a JSX element name to a JS expression:\n * - Lowercase first char → string literal (intrinsic element, e.g. \"div\")\n * - Uppercase first char → identifier (component, e.g. MyComponent)\n * - Member expression → member expr (e.g. Ctx.Provider)\n * - Namespaced → string literal (e.g. \"svg:circle\")\n */\nfunction jsxNameToExpression(\n name: JSXIdentifier | JSXMemberExpression | JSXNamespacedName,\n t: BabelTypes,\n): Expression {\n if (t.isJSXIdentifier(name)) {\n return /^[a-z]/.test(name.name)\n ? t.stringLiteral(name.name)\n : t.identifier(name.name);\n }\n if (t.isJSXMemberExpression(name)) {\n return jsxMemberToMemberExpr(name, t);\n }\n // JSXNamespacedName → \"ns:name\"\n return t.stringLiteral(`${name.namespace.name}:${name.name.name}`);\n}\n\n// ─── JSX text whitespace trimming ────────────────────────────────────────────\n\n/**\n * Mirrors Babel's JSX text trimming:\n * - Split by newline\n * - Trim trailing spaces on the first line, leading spaces on the last\n * - Trim both sides of every middle line\n * - Discard empty lines; join survivors with a trailing space except the last\n */\nfunction cleanJSXText(raw: string): string | null {\n const lines = raw.split(/\\r\\n|\\n|\\r/);\n let lastNonEmpty = 0;\n for (let i = 0; i < lines.length; i++) {\n if (/[^ \\t]/.test(lines[i])) lastNonEmpty = i;\n }\n\n let result = \"\";\n for (let i = 0; i < lines.length; i++) {\n let line = lines[i].replace(/\\t/g, \" \");\n if (i !== 0) line = line.replace(/^[ ]+/, \"\");\n if (i !== lines.length - 1) line = line.replace(/[ ]+$/, \"\");\n if (line) {\n if (i !== lastNonEmpty) line += \" \";\n result += line;\n }\n }\n return result || null;\n}\n\n// ─── Props builder ────────────────────────────────────────────────────────────\n\nfunction buildProps(\n attributes: JSXElement[\"openingElement\"][\"attributes\"],\n children: Expression[],\n t: BabelTypes,\n): Expression {\n const properties: Array<ObjectProperty | SpreadElement> = [];\n\n for (const attr of attributes) {\n if (t.isJSXSpreadAttribute(attr)) {\n properties.push(t.spreadElement(attr.argument));\n continue;\n }\n\n const keyName = t.isJSXIdentifier(attr.name)\n ? attr.name.name\n : `${attr.name.namespace.name}:${attr.name.name.name}`;\n const key = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(keyName)\n ? t.identifier(keyName)\n : t.stringLiteral(keyName);\n\n let value: Expression;\n if (attr.value == null) {\n value = t.booleanLiteral(true);\n } else if (t.isJSXExpressionContainer(attr.value)) {\n value = attr.value.expression as Expression;\n } else {\n // StringLiteral (most common) or rare JSXElement/JSXFragment attr value\n value = attr.value as Expression;\n }\n properties.push(t.objectProperty(key, value));\n }\n\n if (children.length === 1) {\n properties.push(t.objectProperty(t.identifier(\"children\"), children[0]));\n } else if (children.length > 1) {\n properties.push(\n t.objectProperty(t.identifier(\"children\"), t.arrayExpression(children)),\n );\n }\n\n if (properties.length === 0) return t.nullLiteral();\n return t.objectExpression(properties);\n}\n\n// ─── Children builder ─────────────────────────────────────────────────────────\n\n/**\n * Because we use the `exit` visitor, child JSXElement / JSXFragment nodes have\n * already been replaced with CallExpressions by the time the parent runs.\n * The `else` branch handles those already-replaced expressions.\n */\nfunction buildChildren(\n children: JSXElement[\"children\"],\n t: BabelTypes,\n): Expression[] {\n const result: Expression[] = [];\n for (const child of children) {\n if (t.isJSXText(child)) {\n const clean = cleanJSXText(child.value);\n if (clean !== null) result.push(t.stringLiteral(clean));\n } else if (t.isJSXExpressionContainer(child)) {\n if (!t.isJSXEmptyExpression(child.expression)) {\n result.push(child.expression as Expression);\n }\n } else if (t.isJSXSpreadChild(child)) {\n result.push(child.expression);\n } else {\n // Already-transformed CallExpression (was JSXElement/JSXFragment)\n result.push(child as unknown as Expression);\n }\n }\n return result;\n}\n\n// ─── Auto-import helper ───────────────────────────────────────────────────────\n\nconst RECTIFY_CORE = \"@rectify-dev/core/jsx-runtime\";\n\nfunction ensureImports(\n path: import(\"@babel/core\").NodePath<import(\"@babel/types\").Program>,\n state: State,\n t: BabelTypes,\n): void {\n if (!state.usedJsx) return;\n\n // Collect every local name already bound by any import in this file.\n const alreadyBound = new Set<string>();\n let runtimeDecl: ImportDeclaration | null = null;\n\n path.traverse({\n ImportDeclaration(p) {\n for (const spec of p.node.specifiers) {\n if (t.isImportSpecifier(spec) || t.isImportDefaultSpecifier(spec) || t.isImportNamespaceSpecifier(spec)) {\n alreadyBound.add(spec.local.name);\n }\n }\n if (p.node.source.value === RECTIFY_CORE) {\n runtimeDecl = p.node;\n }\n },\n });\n\n const toAdd: ImportSpecifier[] = [];\n if (!alreadyBound.has(\"jsx\")) {\n toAdd.push(t.importSpecifier(t.identifier(\"jsx\"), t.identifier(\"jsx\")));\n }\n if (state.usedFragment && !alreadyBound.has(\"Fragment\")) {\n toAdd.push(\n t.importSpecifier(t.identifier(\"Fragment\"), t.identifier(\"Fragment\")),\n );\n }\n if (toAdd.length === 0) return;\n\n if (runtimeDecl) {\n (runtimeDecl as ImportDeclaration).specifiers.push(...toAdd);\n } else {\n path.unshiftContainer(\n \"body\",\n t.importDeclaration(toAdd, t.stringLiteral(RECTIFY_CORE)),\n );\n }\n}\n\n// ─── Plugin ───────────────────────────────────────────────────────────────────\n\nexport default function rectifyBabelPlugin({ types: t }: Babel): PluginObj<State> {\n return {\n name: \"babel-plugin-rectify\",\n\n manipulateOptions(_opts: any, parserOpts: any) {\n // Enable JSX and TypeScript parsing so Babel can parse .tsx/.jsx files.\n if (!parserOpts.plugins.includes(\"jsx\")) parserOpts.plugins.push(\"jsx\");\n if (!parserOpts.plugins.includes(\"typescript\")) parserOpts.plugins.push(\"typescript\");\n },\n\n visitor: {\n Program: {\n enter(_path, state) {\n state.usedJsx = false;\n state.usedFragment = false;\n },\n exit(path, state) {\n ensureImports(path, state, t);\n },\n },\n\n JSXElement: {\n exit(path, state) {\n state.usedJsx = true;\n\n const { openingElement, children } = path.node;\n const typeExpr = jsxNameToExpression(openingElement.name, t);\n\n // Detect explicit <Fragment> usage\n if (t.isIdentifier(typeExpr) && typeExpr.name === \"Fragment\") {\n state.usedFragment = true;\n }\n\n const childExprs = buildChildren(children, t);\n const propsArg = buildProps(openingElement.attributes, childExprs, t);\n\n path.replaceWith(\n t.callExpression(t.identifier(\"jsx\"), [typeExpr, propsArg]),\n );\n },\n },\n\n JSXFragment: {\n exit(path, state) {\n state.usedJsx = true;\n state.usedFragment = true;\n\n const childExprs = buildChildren(path.node.children, t);\n const propsArg = buildProps([], childExprs, t);\n\n path.replaceWith(\n t.callExpression(t.identifier(\"jsx\"), [\n t.identifier(\"Fragment\"),\n propsArg,\n ]),\n );\n },\n },\n },\n };\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import * as _babel_types from '@babel/types';
2
+ import { PluginObj, PluginPass } from '@babel/core';
3
+
4
+ type BabelTypes = typeof _babel_types;
5
+ type Babel = {
6
+ types: BabelTypes;
7
+ };
8
+ type State = PluginPass & {
9
+ usedJsx: boolean;
10
+ usedFragment: boolean;
11
+ };
12
+ declare function rectifyBabelPlugin({ types: t }: Babel): PluginObj<State>;
13
+
14
+ export { rectifyBabelPlugin as default };
@@ -0,0 +1,14 @@
1
+ import * as _babel_types from '@babel/types';
2
+ import { PluginObj, PluginPass } from '@babel/core';
3
+
4
+ type BabelTypes = typeof _babel_types;
5
+ type Babel = {
6
+ types: BabelTypes;
7
+ };
8
+ type State = PluginPass & {
9
+ usedJsx: boolean;
10
+ usedFragment: boolean;
11
+ };
12
+ declare function rectifyBabelPlugin({ types: t }: Babel): PluginObj<State>;
13
+
14
+ export { rectifyBabelPlugin as default };
package/dist/index.js ADDED
@@ -0,0 +1,178 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/index.ts
5
+ function jsxMemberToMemberExpr(name, t) {
6
+ const obj = t.isJSXMemberExpression(name.object) ? jsxMemberToMemberExpr(name.object, t) : t.identifier(name.object.name);
7
+ return t.memberExpression(obj, t.identifier(name.property.name));
8
+ }
9
+ __name(jsxMemberToMemberExpr, "jsxMemberToMemberExpr");
10
+ function jsxNameToExpression(name, t) {
11
+ if (t.isJSXIdentifier(name)) {
12
+ return /^[a-z]/.test(name.name) ? t.stringLiteral(name.name) : t.identifier(name.name);
13
+ }
14
+ if (t.isJSXMemberExpression(name)) {
15
+ return jsxMemberToMemberExpr(name, t);
16
+ }
17
+ return t.stringLiteral(`${name.namespace.name}:${name.name.name}`);
18
+ }
19
+ __name(jsxNameToExpression, "jsxNameToExpression");
20
+ function cleanJSXText(raw) {
21
+ const lines = raw.split(/\r\n|\n|\r/);
22
+ let lastNonEmpty = 0;
23
+ for (let i = 0; i < lines.length; i++) {
24
+ if (/[^ \t]/.test(lines[i])) lastNonEmpty = i;
25
+ }
26
+ let result = "";
27
+ for (let i = 0; i < lines.length; i++) {
28
+ let line = lines[i].replace(/\t/g, " ");
29
+ if (i !== 0) line = line.replace(/^[ ]+/, "");
30
+ if (i !== lines.length - 1) line = line.replace(/[ ]+$/, "");
31
+ if (line) {
32
+ if (i !== lastNonEmpty) line += " ";
33
+ result += line;
34
+ }
35
+ }
36
+ return result || null;
37
+ }
38
+ __name(cleanJSXText, "cleanJSXText");
39
+ function buildProps(attributes, children, t) {
40
+ const properties = [];
41
+ for (const attr of attributes) {
42
+ if (t.isJSXSpreadAttribute(attr)) {
43
+ properties.push(t.spreadElement(attr.argument));
44
+ continue;
45
+ }
46
+ const keyName = t.isJSXIdentifier(attr.name) ? attr.name.name : `${attr.name.namespace.name}:${attr.name.name.name}`;
47
+ const key = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(keyName) ? t.identifier(keyName) : t.stringLiteral(keyName);
48
+ let value;
49
+ if (attr.value == null) {
50
+ value = t.booleanLiteral(true);
51
+ } else if (t.isJSXExpressionContainer(attr.value)) {
52
+ value = attr.value.expression;
53
+ } else {
54
+ value = attr.value;
55
+ }
56
+ properties.push(t.objectProperty(key, value));
57
+ }
58
+ if (children.length === 1) {
59
+ properties.push(t.objectProperty(t.identifier("children"), children[0]));
60
+ } else if (children.length > 1) {
61
+ properties.push(
62
+ t.objectProperty(t.identifier("children"), t.arrayExpression(children))
63
+ );
64
+ }
65
+ if (properties.length === 0) return t.nullLiteral();
66
+ return t.objectExpression(properties);
67
+ }
68
+ __name(buildProps, "buildProps");
69
+ function buildChildren(children, t) {
70
+ const result = [];
71
+ for (const child of children) {
72
+ if (t.isJSXText(child)) {
73
+ const clean = cleanJSXText(child.value);
74
+ if (clean !== null) result.push(t.stringLiteral(clean));
75
+ } else if (t.isJSXExpressionContainer(child)) {
76
+ if (!t.isJSXEmptyExpression(child.expression)) {
77
+ result.push(child.expression);
78
+ }
79
+ } else if (t.isJSXSpreadChild(child)) {
80
+ result.push(child.expression);
81
+ } else {
82
+ result.push(child);
83
+ }
84
+ }
85
+ return result;
86
+ }
87
+ __name(buildChildren, "buildChildren");
88
+ var RECTIFY_CORE = "@rectify-dev/core/jsx-runtime";
89
+ function ensureImports(path, state, t) {
90
+ if (!state.usedJsx) return;
91
+ const alreadyBound = /* @__PURE__ */ new Set();
92
+ let runtimeDecl = null;
93
+ path.traverse({
94
+ ImportDeclaration(p) {
95
+ for (const spec of p.node.specifiers) {
96
+ if (t.isImportSpecifier(spec) || t.isImportDefaultSpecifier(spec) || t.isImportNamespaceSpecifier(spec)) {
97
+ alreadyBound.add(spec.local.name);
98
+ }
99
+ }
100
+ if (p.node.source.value === RECTIFY_CORE) {
101
+ runtimeDecl = p.node;
102
+ }
103
+ }
104
+ });
105
+ const toAdd = [];
106
+ if (!alreadyBound.has("jsx")) {
107
+ toAdd.push(t.importSpecifier(t.identifier("jsx"), t.identifier("jsx")));
108
+ }
109
+ if (state.usedFragment && !alreadyBound.has("Fragment")) {
110
+ toAdd.push(
111
+ t.importSpecifier(t.identifier("Fragment"), t.identifier("Fragment"))
112
+ );
113
+ }
114
+ if (toAdd.length === 0) return;
115
+ if (runtimeDecl) {
116
+ runtimeDecl.specifiers.push(...toAdd);
117
+ } else {
118
+ path.unshiftContainer(
119
+ "body",
120
+ t.importDeclaration(toAdd, t.stringLiteral(RECTIFY_CORE))
121
+ );
122
+ }
123
+ }
124
+ __name(ensureImports, "ensureImports");
125
+ function rectifyBabelPlugin({ types: t }) {
126
+ return {
127
+ name: "babel-plugin-rectify",
128
+ manipulateOptions(_opts, parserOpts) {
129
+ if (!parserOpts.plugins.includes("jsx")) parserOpts.plugins.push("jsx");
130
+ if (!parserOpts.plugins.includes("typescript")) parserOpts.plugins.push("typescript");
131
+ },
132
+ visitor: {
133
+ Program: {
134
+ enter(_path, state) {
135
+ state.usedJsx = false;
136
+ state.usedFragment = false;
137
+ },
138
+ exit(path, state) {
139
+ ensureImports(path, state, t);
140
+ }
141
+ },
142
+ JSXElement: {
143
+ exit(path, state) {
144
+ state.usedJsx = true;
145
+ const { openingElement, children } = path.node;
146
+ const typeExpr = jsxNameToExpression(openingElement.name, t);
147
+ if (t.isIdentifier(typeExpr) && typeExpr.name === "Fragment") {
148
+ state.usedFragment = true;
149
+ }
150
+ const childExprs = buildChildren(children, t);
151
+ const propsArg = buildProps(openingElement.attributes, childExprs, t);
152
+ path.replaceWith(
153
+ t.callExpression(t.identifier("jsx"), [typeExpr, propsArg])
154
+ );
155
+ }
156
+ },
157
+ JSXFragment: {
158
+ exit(path, state) {
159
+ state.usedJsx = true;
160
+ state.usedFragment = true;
161
+ const childExprs = buildChildren(path.node.children, t);
162
+ const propsArg = buildProps([], childExprs, t);
163
+ path.replaceWith(
164
+ t.callExpression(t.identifier("jsx"), [
165
+ t.identifier("Fragment"),
166
+ propsArg
167
+ ])
168
+ );
169
+ }
170
+ }
171
+ }
172
+ };
173
+ }
174
+ __name(rectifyBabelPlugin, "rectifyBabelPlugin");
175
+
176
+ export { rectifyBabelPlugin as default };
177
+ //# sourceMappingURL=index.js.map
178
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PluginObj, PluginPass } from \"@babel/core\";\nimport type {\n Expression,\n Identifier,\n MemberExpression,\n ObjectProperty,\n SpreadElement,\n ImportDeclaration,\n ImportSpecifier,\n JSXElement,\n JSXIdentifier,\n JSXMemberExpression,\n JSXNamespacedName,\n} from \"@babel/types\";\n\ntype BabelTypes = typeof import(\"@babel/types\");\ntype Babel = { types: BabelTypes };\ntype State = PluginPass & { usedJsx: boolean; usedFragment: boolean };\n\n// ─── JSX name → JS expression ────────────────────────────────────────────────\n\n/**\n * Convert a JSXMemberExpression (e.g. `Ctx.Provider`) to a MemberExpression.\n * All parts of a member chain are treated as identifiers, not string literals.\n */\nfunction jsxMemberToMemberExpr(\n name: JSXMemberExpression,\n t: BabelTypes,\n): MemberExpression {\n const obj: Identifier | MemberExpression = t.isJSXMemberExpression(name.object)\n ? jsxMemberToMemberExpr(name.object, t)\n : t.identifier(name.object.name);\n return t.memberExpression(obj, t.identifier(name.property.name));\n}\n\n/**\n * Convert a JSX element name to a JS expression:\n * - Lowercase first char → string literal (intrinsic element, e.g. \"div\")\n * - Uppercase first char → identifier (component, e.g. MyComponent)\n * - Member expression → member expr (e.g. Ctx.Provider)\n * - Namespaced → string literal (e.g. \"svg:circle\")\n */\nfunction jsxNameToExpression(\n name: JSXIdentifier | JSXMemberExpression | JSXNamespacedName,\n t: BabelTypes,\n): Expression {\n if (t.isJSXIdentifier(name)) {\n return /^[a-z]/.test(name.name)\n ? t.stringLiteral(name.name)\n : t.identifier(name.name);\n }\n if (t.isJSXMemberExpression(name)) {\n return jsxMemberToMemberExpr(name, t);\n }\n // JSXNamespacedName → \"ns:name\"\n return t.stringLiteral(`${name.namespace.name}:${name.name.name}`);\n}\n\n// ─── JSX text whitespace trimming ────────────────────────────────────────────\n\n/**\n * Mirrors Babel's JSX text trimming:\n * - Split by newline\n * - Trim trailing spaces on the first line, leading spaces on the last\n * - Trim both sides of every middle line\n * - Discard empty lines; join survivors with a trailing space except the last\n */\nfunction cleanJSXText(raw: string): string | null {\n const lines = raw.split(/\\r\\n|\\n|\\r/);\n let lastNonEmpty = 0;\n for (let i = 0; i < lines.length; i++) {\n if (/[^ \\t]/.test(lines[i])) lastNonEmpty = i;\n }\n\n let result = \"\";\n for (let i = 0; i < lines.length; i++) {\n let line = lines[i].replace(/\\t/g, \" \");\n if (i !== 0) line = line.replace(/^[ ]+/, \"\");\n if (i !== lines.length - 1) line = line.replace(/[ ]+$/, \"\");\n if (line) {\n if (i !== lastNonEmpty) line += \" \";\n result += line;\n }\n }\n return result || null;\n}\n\n// ─── Props builder ────────────────────────────────────────────────────────────\n\nfunction buildProps(\n attributes: JSXElement[\"openingElement\"][\"attributes\"],\n children: Expression[],\n t: BabelTypes,\n): Expression {\n const properties: Array<ObjectProperty | SpreadElement> = [];\n\n for (const attr of attributes) {\n if (t.isJSXSpreadAttribute(attr)) {\n properties.push(t.spreadElement(attr.argument));\n continue;\n }\n\n const keyName = t.isJSXIdentifier(attr.name)\n ? attr.name.name\n : `${attr.name.namespace.name}:${attr.name.name.name}`;\n const key = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/.test(keyName)\n ? t.identifier(keyName)\n : t.stringLiteral(keyName);\n\n let value: Expression;\n if (attr.value == null) {\n value = t.booleanLiteral(true);\n } else if (t.isJSXExpressionContainer(attr.value)) {\n value = attr.value.expression as Expression;\n } else {\n // StringLiteral (most common) or rare JSXElement/JSXFragment attr value\n value = attr.value as Expression;\n }\n properties.push(t.objectProperty(key, value));\n }\n\n if (children.length === 1) {\n properties.push(t.objectProperty(t.identifier(\"children\"), children[0]));\n } else if (children.length > 1) {\n properties.push(\n t.objectProperty(t.identifier(\"children\"), t.arrayExpression(children)),\n );\n }\n\n if (properties.length === 0) return t.nullLiteral();\n return t.objectExpression(properties);\n}\n\n// ─── Children builder ─────────────────────────────────────────────────────────\n\n/**\n * Because we use the `exit` visitor, child JSXElement / JSXFragment nodes have\n * already been replaced with CallExpressions by the time the parent runs.\n * The `else` branch handles those already-replaced expressions.\n */\nfunction buildChildren(\n children: JSXElement[\"children\"],\n t: BabelTypes,\n): Expression[] {\n const result: Expression[] = [];\n for (const child of children) {\n if (t.isJSXText(child)) {\n const clean = cleanJSXText(child.value);\n if (clean !== null) result.push(t.stringLiteral(clean));\n } else if (t.isJSXExpressionContainer(child)) {\n if (!t.isJSXEmptyExpression(child.expression)) {\n result.push(child.expression as Expression);\n }\n } else if (t.isJSXSpreadChild(child)) {\n result.push(child.expression);\n } else {\n // Already-transformed CallExpression (was JSXElement/JSXFragment)\n result.push(child as unknown as Expression);\n }\n }\n return result;\n}\n\n// ─── Auto-import helper ───────────────────────────────────────────────────────\n\nconst RECTIFY_CORE = \"@rectify-dev/core/jsx-runtime\";\n\nfunction ensureImports(\n path: import(\"@babel/core\").NodePath<import(\"@babel/types\").Program>,\n state: State,\n t: BabelTypes,\n): void {\n if (!state.usedJsx) return;\n\n // Collect every local name already bound by any import in this file.\n const alreadyBound = new Set<string>();\n let runtimeDecl: ImportDeclaration | null = null;\n\n path.traverse({\n ImportDeclaration(p) {\n for (const spec of p.node.specifiers) {\n if (t.isImportSpecifier(spec) || t.isImportDefaultSpecifier(spec) || t.isImportNamespaceSpecifier(spec)) {\n alreadyBound.add(spec.local.name);\n }\n }\n if (p.node.source.value === RECTIFY_CORE) {\n runtimeDecl = p.node;\n }\n },\n });\n\n const toAdd: ImportSpecifier[] = [];\n if (!alreadyBound.has(\"jsx\")) {\n toAdd.push(t.importSpecifier(t.identifier(\"jsx\"), t.identifier(\"jsx\")));\n }\n if (state.usedFragment && !alreadyBound.has(\"Fragment\")) {\n toAdd.push(\n t.importSpecifier(t.identifier(\"Fragment\"), t.identifier(\"Fragment\")),\n );\n }\n if (toAdd.length === 0) return;\n\n if (runtimeDecl) {\n (runtimeDecl as ImportDeclaration).specifiers.push(...toAdd);\n } else {\n path.unshiftContainer(\n \"body\",\n t.importDeclaration(toAdd, t.stringLiteral(RECTIFY_CORE)),\n );\n }\n}\n\n// ─── Plugin ───────────────────────────────────────────────────────────────────\n\nexport default function rectifyBabelPlugin({ types: t }: Babel): PluginObj<State> {\n return {\n name: \"babel-plugin-rectify\",\n\n manipulateOptions(_opts: any, parserOpts: any) {\n // Enable JSX and TypeScript parsing so Babel can parse .tsx/.jsx files.\n if (!parserOpts.plugins.includes(\"jsx\")) parserOpts.plugins.push(\"jsx\");\n if (!parserOpts.plugins.includes(\"typescript\")) parserOpts.plugins.push(\"typescript\");\n },\n\n visitor: {\n Program: {\n enter(_path, state) {\n state.usedJsx = false;\n state.usedFragment = false;\n },\n exit(path, state) {\n ensureImports(path, state, t);\n },\n },\n\n JSXElement: {\n exit(path, state) {\n state.usedJsx = true;\n\n const { openingElement, children } = path.node;\n const typeExpr = jsxNameToExpression(openingElement.name, t);\n\n // Detect explicit <Fragment> usage\n if (t.isIdentifier(typeExpr) && typeExpr.name === \"Fragment\") {\n state.usedFragment = true;\n }\n\n const childExprs = buildChildren(children, t);\n const propsArg = buildProps(openingElement.attributes, childExprs, t);\n\n path.replaceWith(\n t.callExpression(t.identifier(\"jsx\"), [typeExpr, propsArg]),\n );\n },\n },\n\n JSXFragment: {\n exit(path, state) {\n state.usedJsx = true;\n state.usedFragment = true;\n\n const childExprs = buildChildren(path.node.children, t);\n const propsArg = buildProps([], childExprs, t);\n\n path.replaceWith(\n t.callExpression(t.identifier(\"jsx\"), [\n t.identifier(\"Fragment\"),\n propsArg,\n ]),\n );\n },\n },\n },\n };\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@rectify-dev/babel-transform-rectify-jsx",
3
+ "version": "2.0.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "main": "./dist/index.js",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "require": "./dist/index.cjs"
20
+ }
21
+ },
22
+ "devDependencies": {
23
+ "@babel/core": "^7.29.0",
24
+ "@babel/types": "^7.29.0",
25
+ "@types/babel__core": "^7.20.5",
26
+ "tsup": "^8.5.1",
27
+ "typescript": "^5.9.3"
28
+ },
29
+ "peerDependencies": {
30
+ "@babel/core": ">=7"
31
+ },
32
+ "scripts": {
33
+ "build": "tsup",
34
+ "dev": "tsup --watch"
35
+ }
36
+ }