rumious-babel-plugin 0.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.
- package/astGenerators.js +109 -0
- package/index.js +148 -0
- package/jsxProcessor.js +116 -0
- package/package.json +38 -0
- package/utils.js +6 -0
package/astGenerators.js
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
|
2
|
+
function generateAppendChild(t, target, child) {
|
3
|
+
return t.expressionStatement(
|
4
|
+
t.callExpression(t.memberExpression(target, t.identifier("appendChild")), [child])
|
5
|
+
);
|
6
|
+
}
|
7
|
+
|
8
|
+
function generateDynamicValueHandle(t, path, target, child, contextName) {
|
9
|
+
const tempId = path.scope.generateUidIdentifier("_rumious_dymanic_");
|
10
|
+
return [
|
11
|
+
t.variableDeclaration("const", [
|
12
|
+
t.variableDeclarator(
|
13
|
+
tempId,
|
14
|
+
t.callExpression(t.memberExpression(t.identifier("document"), t.identifier("createTextNode")), [
|
15
|
+
t.stringLiteral(""),
|
16
|
+
])
|
17
|
+
),
|
18
|
+
]),
|
19
|
+
generateAppendChild(t,target,tempId),
|
20
|
+
t.expressionStatement(
|
21
|
+
t.callExpression(t.memberExpression(t.identifier("window.RUMIOUS_JSX"), t.identifier("dynamicValue"), false), [
|
22
|
+
target,
|
23
|
+
tempId,
|
24
|
+
child,
|
25
|
+
t.identifier(contextName)
|
26
|
+
])
|
27
|
+
),
|
28
|
+
];
|
29
|
+
}
|
30
|
+
|
31
|
+
function generateCreateText(t, text) {
|
32
|
+
return t.callExpression(t.memberExpression(t.identifier("document"), t.identifier("createTextNode")), [
|
33
|
+
t.stringLiteral(text),
|
34
|
+
]);
|
35
|
+
}
|
36
|
+
|
37
|
+
function generateCreateEl(t, varName, tagName) {
|
38
|
+
return t.variableDeclaration("const", [
|
39
|
+
t.variableDeclarator(
|
40
|
+
varName,
|
41
|
+
t.callExpression(t.memberExpression(t.identifier("document"), t.identifier("createElement")), [
|
42
|
+
t.stringLiteral(tagName),
|
43
|
+
])
|
44
|
+
),
|
45
|
+
]);
|
46
|
+
}
|
47
|
+
|
48
|
+
function generateCreateFrag(t, varName) {
|
49
|
+
return t.variableDeclaration("const", [
|
50
|
+
t.variableDeclarator(
|
51
|
+
varName,
|
52
|
+
t.callExpression(t.memberExpression(t.identifier("document"), t.identifier("createDocumentFragment")), [
|
53
|
+
])
|
54
|
+
),
|
55
|
+
]);
|
56
|
+
}
|
57
|
+
|
58
|
+
|
59
|
+
function generateSetAttr(t, target, name, value) {
|
60
|
+
return t.expressionStatement(
|
61
|
+
t.callExpression(t.memberExpression(target, t.identifier("setAttribute")), [t.stringLiteral(name), value])
|
62
|
+
);
|
63
|
+
}
|
64
|
+
|
65
|
+
function generateSetProps(t, target, key, value) {
|
66
|
+
return t.expressionStatement(
|
67
|
+
t.assignmentExpression(
|
68
|
+
"=",
|
69
|
+
t.memberExpression(t.memberExpression(target, t.identifier("props")), typeof key === "string" ? t.stringLiteral(key) : key, true),
|
70
|
+
value
|
71
|
+
)
|
72
|
+
);
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
function generateAddDirective(t, target, directive, modifier, value, contextName) {
|
77
|
+
return t.expressionStatement(
|
78
|
+
t.callExpression(t.memberExpression(t.identifier("window.RUMIOUS_JSX"), t.identifier("addDirective"), false), [
|
79
|
+
target,
|
80
|
+
t.identifier(contextName),
|
81
|
+
t.stringLiteral(directive),
|
82
|
+
t.stringLiteral(modifier),
|
83
|
+
value,
|
84
|
+
])
|
85
|
+
);
|
86
|
+
}
|
87
|
+
|
88
|
+
function generateCreateComponent(t, varName, component){
|
89
|
+
return t.variableDeclaration("const", [
|
90
|
+
t.variableDeclarator(
|
91
|
+
varName,
|
92
|
+
t.callExpression(t.memberExpression(t.identifier("window.RUMIOUS_JSX"), t.identifier("createComponent")), [
|
93
|
+
component,
|
94
|
+
])
|
95
|
+
),
|
96
|
+
]);
|
97
|
+
}
|
98
|
+
|
99
|
+
module.exports = {
|
100
|
+
generateAppendChild,
|
101
|
+
generateDynamicValueHandle,
|
102
|
+
generateCreateText,
|
103
|
+
generateCreateEl,
|
104
|
+
generateSetAttr,
|
105
|
+
generateSetProps,
|
106
|
+
generateAddDirective,
|
107
|
+
generateCreateComponent,
|
108
|
+
generateCreateFrag
|
109
|
+
};
|
package/index.js
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
const { declare } = require('@babel/helper-plugin-utils');
|
2
|
+
const { randomName } = require('./utils');
|
3
|
+
const {
|
4
|
+
generateCreateEl,
|
5
|
+
generateAppendChild,
|
6
|
+
generateDynamicValueHandle,
|
7
|
+
generateCreateText,
|
8
|
+
generateCreateComponent,
|
9
|
+
generateCreateFrag
|
10
|
+
} = require('./astGenerators');
|
11
|
+
const {
|
12
|
+
processAttributes,
|
13
|
+
processProps,
|
14
|
+
jsxNameToExpression,
|
15
|
+
} = require('./jsxProcessor');
|
16
|
+
|
17
|
+
function attachSourceMeta(t, elId, node, filename) {
|
18
|
+
if (process.env.NODE_ENV !== 'development' || !node.loc) return [];
|
19
|
+
|
20
|
+
const { line, column } = node.loc.start;
|
21
|
+
|
22
|
+
return [
|
23
|
+
t.expressionStatement(
|
24
|
+
t.assignmentExpression(
|
25
|
+
"=",
|
26
|
+
t.memberExpression(elId, t.identifier("_source")),
|
27
|
+
t.objectExpression([
|
28
|
+
t.objectProperty(t.identifier("fileName"), t.stringLiteral(filename)),
|
29
|
+
t.objectProperty(t.identifier("line"), t.numericLiteral(line)),
|
30
|
+
t.objectProperty(t.identifier("column"), t.numericLiteral(column)),
|
31
|
+
])
|
32
|
+
)
|
33
|
+
)
|
34
|
+
];
|
35
|
+
}
|
36
|
+
|
37
|
+
function transformJSXElement(t, path, element, contextName, filename) {
|
38
|
+
const tagName = element.openingElement ? element.openingElement.name : null;
|
39
|
+
const isComponent = tagName && (t.isJSXMemberExpression(tagName) || /^[A-Z]/.test(tagName.name));
|
40
|
+
const isFragment = isComponent && tagName.name === "Fragment";
|
41
|
+
const elId = isFragment ? path.scope.generateUidIdentifier("rumious_frag") : path.scope.generateUidIdentifier("rumious_el");
|
42
|
+
const statements = [];
|
43
|
+
|
44
|
+
if (isFragment) {
|
45
|
+
statements.push(generateCreateFrag(t, elId));
|
46
|
+
statements.push(...attachSourceMeta(t, elId, element, filename));
|
47
|
+
|
48
|
+
if (!element.children || element.children.length === 0) {
|
49
|
+
return { elId: elId, statements };
|
50
|
+
}
|
51
|
+
|
52
|
+
for (const child of element.children) {
|
53
|
+
if (t.isJSXText(child)) {
|
54
|
+
const text = child.value;
|
55
|
+
if (text) {
|
56
|
+
const textNode = generateCreateText(t, text);
|
57
|
+
statements.push(generateAppendChild(t, elId, textNode));
|
58
|
+
}
|
59
|
+
} else if (t.isJSXExpressionContainer(child)) {
|
60
|
+
if (child.expression.type !== "NullLiteral" && child.expression.type !== "UndefinedLiteral") {
|
61
|
+
statements.push(...generateDynamicValueHandle(t, path, elId, child.expression, contextName));
|
62
|
+
}
|
63
|
+
} else if (t.isJSXElement(child) || t.isJSXFragment(child)) {
|
64
|
+
const nested = transformJSXElement(t, path, child, contextName, filename);
|
65
|
+
statements.push(...nested.statements);
|
66
|
+
statements.push(generateAppendChild(t, elId, nested.elId));
|
67
|
+
}
|
68
|
+
}
|
69
|
+
return { elId: elId, statements };
|
70
|
+
}
|
71
|
+
|
72
|
+
if (isComponent) {
|
73
|
+
statements.push(generateCreateComponent(t, elId, jsxNameToExpression(t, tagName)));
|
74
|
+
statements.push(...attachSourceMeta(t, elId, element, filename));
|
75
|
+
|
76
|
+
statements.push(
|
77
|
+
t.expressionStatement(
|
78
|
+
t.callExpression(t.memberExpression(elId, t.identifier("setup")), [t.identifier(contextName), jsxNameToExpression(t, tagName)])
|
79
|
+
)
|
80
|
+
);
|
81
|
+
statements.push(...processProps(t, elId, element.openingElement.attributes));
|
82
|
+
} else {
|
83
|
+
statements.push(generateCreateEl(t, elId, tagName ? tagName.name : "div"));
|
84
|
+
statements.push(...attachSourceMeta(t, elId, element, filename));
|
85
|
+
statements.push(...processAttributes(t, elId, element.openingElement.attributes, contextName));
|
86
|
+
}
|
87
|
+
|
88
|
+
for (const child of element.children) {
|
89
|
+
if (t.isJSXText(child)) {
|
90
|
+
const text = child.value;
|
91
|
+
if (text) {
|
92
|
+
const textNode = generateCreateText(t, text);
|
93
|
+
statements.push(generateAppendChild(t, elId, textNode));
|
94
|
+
}
|
95
|
+
} else if (t.isJSXExpressionContainer(child)) {
|
96
|
+
if (child.expression.type !== "NullLiteral" && child.expression.type !== "UndefinedLiteral") {
|
97
|
+
statements.push(...generateDynamicValueHandle(t, path, elId, child.expression, contextName));
|
98
|
+
}
|
99
|
+
} else if (t.isJSXElement(child) || t.isJSXFragment(child)) {
|
100
|
+
const nested = transformJSXElement(t, path, child, contextName, filename);
|
101
|
+
statements.push(...nested.statements);
|
102
|
+
statements.push(generateAppendChild(t, elId, nested.elId));
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
return { elId, statements };
|
107
|
+
}
|
108
|
+
|
109
|
+
module.exports = declare((api) => {
|
110
|
+
api.assertVersion(7);
|
111
|
+
const t = api.types;
|
112
|
+
|
113
|
+
return {
|
114
|
+
name: "rumious-babel-plugin",
|
115
|
+
visitor: {
|
116
|
+
JSXElement(path) {
|
117
|
+
const rootName = randomName("rumious_root");
|
118
|
+
const contextName = randomName("rumious_ctx");
|
119
|
+
const filename = path.hub.file.opts.filename || "unknown_file";
|
120
|
+
|
121
|
+
const { elId, statements } = transformJSXElement(t, path, path.node, contextName, filename);
|
122
|
+
|
123
|
+
statements.push(
|
124
|
+
t.expressionStatement(
|
125
|
+
t.callExpression(t.memberExpression(t.identifier(rootName), t.identifier("appendChild")), [elId])
|
126
|
+
)
|
127
|
+
);
|
128
|
+
statements.push(t.returnStatement(t.identifier(rootName)));
|
129
|
+
|
130
|
+
const fn = t.functionExpression(
|
131
|
+
null,
|
132
|
+
[t.identifier(rootName), t.identifier(contextName)],
|
133
|
+
t.blockStatement(statements.map((s) => t.cloneNode(s, true)))
|
134
|
+
);
|
135
|
+
|
136
|
+
const callTemplate = t.callExpression(
|
137
|
+
t.memberExpression(
|
138
|
+
t.memberExpression(t.identifier("window"), t.identifier("RUMIOUS_JSX")),
|
139
|
+
t.identifier("template")
|
140
|
+
),
|
141
|
+
[fn]
|
142
|
+
);
|
143
|
+
|
144
|
+
path.replaceWith(callTemplate);
|
145
|
+
},
|
146
|
+
},
|
147
|
+
};
|
148
|
+
});
|
package/jsxProcessor.js
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
const {
|
2
|
+
generateAddDirective,
|
3
|
+
generateSetAttr,
|
4
|
+
generateSetProps,
|
5
|
+
} = require('./astGenerators');
|
6
|
+
|
7
|
+
function processDirective(t, target, attr, directive, modifier, contextName) {
|
8
|
+
const value = attr.value ?
|
9
|
+
t.isStringLiteral(attr.value) ?
|
10
|
+
attr.value :
|
11
|
+
t.isJSXExpressionContainer(attr.value) ?
|
12
|
+
attr.value.expression :
|
13
|
+
t.stringLiteral("") :
|
14
|
+
t.booleanLiteral(true);
|
15
|
+
return generateAddDirective(t, target, directive, modifier, value, contextName);
|
16
|
+
}
|
17
|
+
|
18
|
+
function processNamespace(t, target, attr, contextName) {
|
19
|
+
const name = attr.name.name.name;
|
20
|
+
const namespace = attr.name.namespace.name;
|
21
|
+
if (["bind", "on"].includes(namespace)) {
|
22
|
+
return processDirective(t, target, attr, namespace, name, contextName);
|
23
|
+
}
|
24
|
+
const value = attr.value ?
|
25
|
+
t.isStringLiteral(attr.value) ?
|
26
|
+
attr.value :
|
27
|
+
t.isJSXExpressionContainer(attr.value) ?
|
28
|
+
attr.value.expression :
|
29
|
+
t.stringLiteral("") :
|
30
|
+
t.booleanLiteral(true);
|
31
|
+
return generateSetAttr(t, target, t.binaryExpression("+", t.stringLiteral(`${namespace}:`), t.stringLiteral(name)), value);
|
32
|
+
}
|
33
|
+
|
34
|
+
function processAttributes(t, elId, attributes, contextName) {
|
35
|
+
const statements = [];
|
36
|
+
const standaloneDirectives = ["ref", "model","inject"];
|
37
|
+
|
38
|
+
for (const attr of attributes) {
|
39
|
+
if (t.isJSXAttribute(attr) && !t.isJSXNamespacedName(attr.name)) {
|
40
|
+
const name = attr.name.name;
|
41
|
+
const value = attr.value ?
|
42
|
+
t.isStringLiteral(attr.value) ?
|
43
|
+
attr.value :
|
44
|
+
t.isJSXExpressionContainer(attr.value) ?
|
45
|
+
attr.value.expression :
|
46
|
+
t.stringLiteral("") :
|
47
|
+
t.booleanLiteral(true);
|
48
|
+
if (standaloneDirectives.includes(name)) {
|
49
|
+
statements.push(processDirective(t, elId, attr, name, "standalone", contextName));
|
50
|
+
} else {
|
51
|
+
statements.push(generateSetAttr(t, elId, name, value));
|
52
|
+
}
|
53
|
+
} else if (t.isJSXAttribute(attr) && t.isJSXNamespacedName(attr.name)) {
|
54
|
+
statements.push(processNamespace(t, elId, attr, contextName));
|
55
|
+
} else if (t.isJSXSpreadAttribute(attr)) {
|
56
|
+
const props = attr.argument;
|
57
|
+
const key = t.identifier("key");
|
58
|
+
const value = t.memberExpression(props, key, true);
|
59
|
+
statements.push(
|
60
|
+
t.forInStatement(
|
61
|
+
t.variableDeclaration("let", [t.variableDeclarator(key)]),
|
62
|
+
props,
|
63
|
+
t.blockStatement([
|
64
|
+
t.expressionStatement(t.callExpression(t.memberExpression(elId, t.identifier("setAttribute")), [key, value])),
|
65
|
+
])
|
66
|
+
)
|
67
|
+
);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
return statements;
|
71
|
+
}
|
72
|
+
|
73
|
+
function processProps(t, elId, props) {
|
74
|
+
const statements = [];
|
75
|
+
for (let prop of props) {
|
76
|
+
if (t.isJSXAttribute(prop)) {
|
77
|
+
const name = prop.name.name;
|
78
|
+
const value = prop.value ?
|
79
|
+
t.isStringLiteral(prop.value) ?
|
80
|
+
prop.value :
|
81
|
+
t.isJSXExpressionContainer(prop.value) ?
|
82
|
+
prop.value.expression :
|
83
|
+
t.stringLiteral("") :
|
84
|
+
t.booleanLiteral(true);
|
85
|
+
statements.push(generateSetProps(t, elId, name, value));
|
86
|
+
} else if (t.isJSXSpreadAttribute(prop)) {
|
87
|
+
const propExpr = prop.argument;
|
88
|
+
const key = t.identifier("key");
|
89
|
+
const value = t.memberExpression(propExpr, key, true);
|
90
|
+
statements.push(
|
91
|
+
t.forInStatement(
|
92
|
+
t.variableDeclaration("let", [t.variableDeclarator(key)]),
|
93
|
+
propExpr,
|
94
|
+
t.blockStatement([generateSetProps(t, elId, key, value)])
|
95
|
+
)
|
96
|
+
);
|
97
|
+
}
|
98
|
+
}
|
99
|
+
return statements;
|
100
|
+
}
|
101
|
+
|
102
|
+
function jsxNameToExpression(t, name) {
|
103
|
+
if (t.isJSXIdentifier(name)) return t.identifier(name.name);
|
104
|
+
if (t.isJSXMemberExpression(name)) {
|
105
|
+
return t.memberExpression(jsxNameToExpression(t, name.object), t.identifier(name.property.name));
|
106
|
+
}
|
107
|
+
return t.identifier("unknown");
|
108
|
+
}
|
109
|
+
|
110
|
+
module.exports = {
|
111
|
+
processDirective,
|
112
|
+
processNamespace,
|
113
|
+
processAttributes,
|
114
|
+
processProps,
|
115
|
+
jsxNameToExpression,
|
116
|
+
};
|
package/package.json
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
{
|
2
|
+
"name": "rumious-babel-plugin",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"description":"Babel plugin for Rumious ",
|
5
|
+
"main": "./index.js",
|
6
|
+
"keywords": [
|
7
|
+
"rumious",
|
8
|
+
"core",
|
9
|
+
"framework",
|
10
|
+
"babel",
|
11
|
+
"plugin",
|
12
|
+
"babel-plugin"
|
13
|
+
],
|
14
|
+
"scripts": {
|
15
|
+
},
|
16
|
+
"author": "smtdfc",
|
17
|
+
"license": "MIT",
|
18
|
+
"repository": {
|
19
|
+
"type": "git",
|
20
|
+
"url": "https://github.com/smtdfc/rumious"
|
21
|
+
},
|
22
|
+
"bugs": {
|
23
|
+
"url": "https://github.com/smtdfc/rumious/issues"
|
24
|
+
},
|
25
|
+
"homepage": "https://github.com/smtdfc/rumious#readme",
|
26
|
+
"files": [
|
27
|
+
"index.js",
|
28
|
+
"jsxProcessor.js",
|
29
|
+
"utils.js",
|
30
|
+
"astGenerators.js",
|
31
|
+
"README.md"
|
32
|
+
],
|
33
|
+
"engines": {
|
34
|
+
"node": ">=16"
|
35
|
+
},
|
36
|
+
"dependencies": {
|
37
|
+
}
|
38
|
+
}
|