babel-plugin-vasille 0.99.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/README.md +122 -0
- package/lib/call.js +51 -0
- package/lib/expression.js +517 -0
- package/lib/index.js +11 -0
- package/lib/internal.js +25 -0
- package/lib/jsx-detect.js +60 -0
- package/lib/jsx.js +364 -0
- package/lib/lib.js +90 -0
- package/lib/mesh.js +929 -0
- package/lib/transformer.js +88 -0
- package/lib-node/call.js +78 -0
- package/lib-node/expression.js +552 -0
- package/lib-node/index.js +14 -0
- package/lib-node/internal.js +52 -0
- package/lib-node/jsx-detect.js +88 -0
- package/lib-node/jsx.js +391 -0
- package/lib-node/lib.js +124 -0
- package/lib-node/mesh.js +971 -0
- package/lib-node/transformer.js +114 -0
- package/package.json +47 -0
package/lib/internal.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
export class StackedStates {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.maps = [];
|
|
5
|
+
this.push();
|
|
6
|
+
}
|
|
7
|
+
push() {
|
|
8
|
+
this.maps.push(new Map());
|
|
9
|
+
}
|
|
10
|
+
pop() {
|
|
11
|
+
this.maps.pop();
|
|
12
|
+
}
|
|
13
|
+
get(name) {
|
|
14
|
+
for (let i = this.maps.length - 1; i >= 0; i--) {
|
|
15
|
+
if (this.maps[i].has(name)) {
|
|
16
|
+
return this.maps[i].get(name);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
set(name, state) {
|
|
22
|
+
this.maps[this.maps.length - 1].set(name, state);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export const ctx = t.identifier("Vasille");
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
export function exprHasJsx(node) {
|
|
3
|
+
if (t.isBinaryExpression(node)) {
|
|
4
|
+
return (t.isExpression(node.left) && exprHasJsx(node.left)) || exprHasJsx(node.right);
|
|
5
|
+
}
|
|
6
|
+
if (t.isConditionalExpression(node)) {
|
|
7
|
+
return exprHasJsx(node.consequent) || exprHasJsx(node.alternate);
|
|
8
|
+
}
|
|
9
|
+
if (t.isLogicalExpression(node)) {
|
|
10
|
+
return exprHasJsx(node.left) || exprHasJsx(node.right);
|
|
11
|
+
}
|
|
12
|
+
if (t.isSequenceExpression(node)) {
|
|
13
|
+
return node.expressions.some(item => exprHasJsx(item));
|
|
14
|
+
}
|
|
15
|
+
if (t.isParenthesizedExpression(node)) {
|
|
16
|
+
return exprHasJsx(node.expression);
|
|
17
|
+
}
|
|
18
|
+
if (t.isDoExpression(node)) {
|
|
19
|
+
return bodyHasJsx(node.body);
|
|
20
|
+
}
|
|
21
|
+
return t.isJSXElement(node) || t.isJSXFragment(node);
|
|
22
|
+
}
|
|
23
|
+
export function statementHasJsx(statement) {
|
|
24
|
+
if (t.isExpressionStatement(statement)) {
|
|
25
|
+
return exprHasJsx(statement.expression);
|
|
26
|
+
}
|
|
27
|
+
if (t.isBlockStatement(statement)) {
|
|
28
|
+
return bodyHasJsx(statement);
|
|
29
|
+
}
|
|
30
|
+
if (t.isDoWhileStatement(statement)) {
|
|
31
|
+
return statementHasJsx(statement.body);
|
|
32
|
+
}
|
|
33
|
+
if (t.isForInStatement(statement)) {
|
|
34
|
+
return statementHasJsx(statement.body);
|
|
35
|
+
}
|
|
36
|
+
if (t.isSwitchStatement(statement)) {
|
|
37
|
+
return statement.cases.some(_case => {
|
|
38
|
+
return _case.consequent.some(statementHasJsx);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (t.isWhileStatement(statement)) {
|
|
42
|
+
return statementHasJsx(statement.body);
|
|
43
|
+
}
|
|
44
|
+
if (t.isForOfStatement(statement)) {
|
|
45
|
+
return statementHasJsx(statement.body);
|
|
46
|
+
}
|
|
47
|
+
if (t.isLabeledStatement(statement)) {
|
|
48
|
+
return statementHasJsx(statement.body);
|
|
49
|
+
}
|
|
50
|
+
if (t.isReturnStatement(statement)) {
|
|
51
|
+
return !!statement.argument && exprHasJsx(statement.argument);
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
export function bodyHasJsx(node) {
|
|
56
|
+
if (t.isExpression(node)) {
|
|
57
|
+
return exprHasJsx(node);
|
|
58
|
+
}
|
|
59
|
+
return node.body.some(statementHasJsx);
|
|
60
|
+
}
|
package/lib/jsx.js
ADDED
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { ctx } from "./internal.js";
|
|
3
|
+
import { exprCall } from "./lib.js";
|
|
4
|
+
import { compose, meshExpression } from "./mesh.js";
|
|
5
|
+
import { bodyHasJsx } from "./jsx-detect.js";
|
|
6
|
+
export function transformJsx(path, internal) {
|
|
7
|
+
if (t.isJSXElement(path.node)) {
|
|
8
|
+
return [transformJsxElement(path, internal)];
|
|
9
|
+
}
|
|
10
|
+
return transformJsxArray(path.get("children"), internal);
|
|
11
|
+
}
|
|
12
|
+
export function transformJsxArray(paths, internal) {
|
|
13
|
+
const result = [];
|
|
14
|
+
for (const path of paths) {
|
|
15
|
+
if (t.isJSXElement(path.node) || t.isJSXFragment(path.node)) {
|
|
16
|
+
result.push(...transformJsx(path, internal));
|
|
17
|
+
}
|
|
18
|
+
else if (t.isJSXText(path.node)) {
|
|
19
|
+
if (!/^\s+$/.test(path.node.value)) {
|
|
20
|
+
const fixed = path.node.value
|
|
21
|
+
.replace(/\n\s+$/m, "")
|
|
22
|
+
.replace(/^\s*\n\s+/m, "")
|
|
23
|
+
.replace(/\s*\n\s*/gm, "\n");
|
|
24
|
+
result.push(t.expressionStatement(t.callExpression(t.memberExpression(ctx, t.identifier("text")), [t.stringLiteral(fixed)])));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else if (t.isJSXExpressionContainer(path.node)) {
|
|
28
|
+
const value = transformJsxExpressionContainer(path, internal, false, false);
|
|
29
|
+
result.push(t.expressionStatement(t.callExpression(t.memberExpression(ctx, t.identifier("text")), [value])));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
throw path.buildCodeFrameError("Vasille: Spread child is not supported");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function transformJsxExpressionContainer(path, internal, acceptSlots, isInternalSlot) {
|
|
38
|
+
if (!t.isExpression(path.node.expression)) {
|
|
39
|
+
return t.booleanLiteral(true);
|
|
40
|
+
}
|
|
41
|
+
if (acceptSlots &&
|
|
42
|
+
(t.isFunctionExpression(path.node.expression) || t.isArrowFunctionExpression(path.node.expression)) &&
|
|
43
|
+
bodyHasJsx(path.node.expression.body)) {
|
|
44
|
+
compose(path.get("expression"), internal, isInternalSlot);
|
|
45
|
+
if (!isInternalSlot) {
|
|
46
|
+
if (path.node.expression.params.length < 1) {
|
|
47
|
+
path.node.expression.params.push(t.identifier(internal.prefix));
|
|
48
|
+
}
|
|
49
|
+
path.node.expression.params.push(ctx);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
path.node.expression.params.unshift(ctx);
|
|
53
|
+
}
|
|
54
|
+
return path.node.expression;
|
|
55
|
+
}
|
|
56
|
+
else if (isInternalSlot &&
|
|
57
|
+
(t.isFunctionExpression(path.node.expression) || t.isArrowFunctionExpression(path.node.expression))) {
|
|
58
|
+
path.node.expression.params.unshift(ctx);
|
|
59
|
+
}
|
|
60
|
+
let call = exprCall(path.get("expression"), path.node.expression, internal);
|
|
61
|
+
if (!call &&
|
|
62
|
+
t.isIdentifier(path.node.expression) &&
|
|
63
|
+
internal.stack.get(path.node.expression.name) === 3 /* VariableState.ReactiveObject */) {
|
|
64
|
+
call = t.callExpression(t.memberExpression(internal.id, t.identifier("rop")), [path.node.expression]);
|
|
65
|
+
}
|
|
66
|
+
return call !== null && call !== void 0 ? call : path.node.expression;
|
|
67
|
+
}
|
|
68
|
+
function id(str) {
|
|
69
|
+
if (/^[\w_]+$/.test(str)) {
|
|
70
|
+
return t.identifier(str);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return t.stringLiteral(str);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function transformJsxElement(path, internal) {
|
|
77
|
+
var _a, _b;
|
|
78
|
+
const name = path.node.openingElement.name;
|
|
79
|
+
if (t.isJSXIdentifier(name) && name.name[0].toLowerCase() === name.name[0]) {
|
|
80
|
+
const opening = path.get("openingElement");
|
|
81
|
+
const attrs = [];
|
|
82
|
+
const events = [];
|
|
83
|
+
const bind = [];
|
|
84
|
+
const classElements = [];
|
|
85
|
+
const classObject = [];
|
|
86
|
+
const classStatic = [];
|
|
87
|
+
const styleObject = [];
|
|
88
|
+
const styleStatic = [];
|
|
89
|
+
for (const attrPath of opening.get("attributes")) {
|
|
90
|
+
const attr = attrPath.node;
|
|
91
|
+
if (t.isJSXAttribute(attr)) {
|
|
92
|
+
const name = attr.name;
|
|
93
|
+
if (t.isJSXIdentifier(name)) {
|
|
94
|
+
if (name.name.startsWith("on")) {
|
|
95
|
+
if (t.isJSXExpressionContainer(attr.value) && t.isExpression(attr.value.expression)) {
|
|
96
|
+
const path = attrPath.get("value");
|
|
97
|
+
if (t.isExpression(path.node.expression)) {
|
|
98
|
+
meshExpression(path.get("expression"), internal);
|
|
99
|
+
}
|
|
100
|
+
events.push(t.objectProperty(id(name.name.substring(2)), path.node.expression));
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
throw attrPath
|
|
104
|
+
.get("value")
|
|
105
|
+
.buildCodeFrameError("Vasille: Expected event handler.");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (name.name === "class") {
|
|
109
|
+
// class={[..]}
|
|
110
|
+
if (t.isJSXExpressionContainer(attr.value) && t.isArrayExpression(attr.value.expression)) {
|
|
111
|
+
const valuePath = attrPath.get("value");
|
|
112
|
+
const arrayExprPath = valuePath.get("expression");
|
|
113
|
+
for (const elementPath of arrayExprPath.get("elements")) {
|
|
114
|
+
const item = elementPath.node;
|
|
115
|
+
if (t.isExpression(item)) {
|
|
116
|
+
// class={[cond && "string"]}
|
|
117
|
+
if (t.isLogicalExpression(item) && item.operator === "&&" && t.isStringLiteral(item.right)) {
|
|
118
|
+
const call = exprCall(elementPath.get("left"), item.left, internal);
|
|
119
|
+
classObject.push(t.objectProperty(id(item.right.value), call !== null && call !== void 0 ? call : item.left));
|
|
120
|
+
}
|
|
121
|
+
// class={[{..}]}
|
|
122
|
+
else if (t.isObjectExpression(item)) {
|
|
123
|
+
for (const propPath of elementPath.get("properties")) {
|
|
124
|
+
// class={[{a: b}]}
|
|
125
|
+
if (t.isObjectProperty(propPath.node)) {
|
|
126
|
+
const prop = propPath;
|
|
127
|
+
const value = (_a = exprCall(prop.get("value"), prop.node.value, internal)) !== null && _a !== void 0 ? _a : prop.node.value;
|
|
128
|
+
if (t.isExpression(prop.node.key) && !t.isIdentifier(prop.node.key)) {
|
|
129
|
+
meshExpression(prop.get("key"), internal);
|
|
130
|
+
}
|
|
131
|
+
classObject.push(t.objectProperty(prop.node.key, value));
|
|
132
|
+
}
|
|
133
|
+
// class={[{...a}]}
|
|
134
|
+
else if (t.isSpreadElement(propPath.node)) {
|
|
135
|
+
classObject.push(propPath.node);
|
|
136
|
+
}
|
|
137
|
+
// class={[{a(){}}]}
|
|
138
|
+
else {
|
|
139
|
+
throw propPath.buildCodeFrameError("Vasille: Methods are not alllowed here");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// class={[".."]}
|
|
144
|
+
else if (t.isStringLiteral(elementPath.node)) {
|
|
145
|
+
classStatic.push(elementPath.node.value);
|
|
146
|
+
}
|
|
147
|
+
// class={[..]}
|
|
148
|
+
else {
|
|
149
|
+
const call = exprCall(elementPath, item, internal);
|
|
150
|
+
classElements.push(call !== null && call !== void 0 ? call : item);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// class={[...array]}
|
|
154
|
+
else {
|
|
155
|
+
classElements.push(elementPath.node);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// class={"a b"}
|
|
160
|
+
else if (t.isJSXExpressionContainer(attr.value) && t.isStringLiteral(attr.value.expression)) {
|
|
161
|
+
attrs.push(t.objectProperty(t.identifier("class"), attr.value.expression));
|
|
162
|
+
}
|
|
163
|
+
// class={`a ${b}`}
|
|
164
|
+
else if (t.isJSXExpressionContainer(attr.value) && t.isTemplateLiteral(attr.value.expression)) {
|
|
165
|
+
const jsxAttrPath = attrPath;
|
|
166
|
+
const jsxContainerPath = jsxAttrPath.get("value");
|
|
167
|
+
const value = exprCall(jsxContainerPath.get("expression"), attr.value.expression, internal);
|
|
168
|
+
attrs.push(t.objectProperty(t.identifier("class"), value !== null && value !== void 0 ? value : attr.value.expression));
|
|
169
|
+
if (value) {
|
|
170
|
+
console.warn(attrPath.buildCodeFrameError("Vasille: This will slow down your application"));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// class="a b"
|
|
174
|
+
else if (t.isStringLiteral(attr.value)) {
|
|
175
|
+
const splitted = attr.value.value.split(" ");
|
|
176
|
+
for (const item of splitted) {
|
|
177
|
+
classStatic.push(item);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// class=<div/>
|
|
181
|
+
else {
|
|
182
|
+
throw attrPath.buildCodeFrameError('Vasille: Value of "class" attribute must be an array expression');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (name.name === "style") {
|
|
186
|
+
// style={{..}}
|
|
187
|
+
if (t.isJSXExpressionContainer(attr.value) && t.isObjectExpression(attr.value.expression)) {
|
|
188
|
+
const valuePath = attrPath.get("value");
|
|
189
|
+
const objectPath = valuePath.get("expression");
|
|
190
|
+
for (const propPath of objectPath.get("properties")) {
|
|
191
|
+
// style={{a: b}}
|
|
192
|
+
if (t.isObjectProperty(propPath.node)) {
|
|
193
|
+
const prop = propPath;
|
|
194
|
+
const value = (_b = exprCall(prop.get("value"), prop.node.value, internal)) !== null && _b !== void 0 ? _b : prop.node.value;
|
|
195
|
+
if (t.isExpression(prop.node.key) && !t.isIdentifier(prop.node.key)) {
|
|
196
|
+
meshExpression(prop.get("key"), internal);
|
|
197
|
+
}
|
|
198
|
+
// style={{a: "b"}} -> static in compile time
|
|
199
|
+
if (t.isIdentifier(prop.node.key) && t.isStringLiteral(prop.node.value)) {
|
|
200
|
+
styleStatic.push([prop.node.key, prop.node.value]);
|
|
201
|
+
}
|
|
202
|
+
// style={{a: 23}} -> static in compile time
|
|
203
|
+
else if (t.isIdentifier(prop.node.key) && t.isNumericLiteral(prop.node.value)) {
|
|
204
|
+
styleStatic.push([prop.node.key, t.stringLiteral(`${prop.node.value.value}px`)]);
|
|
205
|
+
}
|
|
206
|
+
// style={{a: [1, 2, 3]}} -> static in compile time
|
|
207
|
+
else if (t.isIdentifier(prop.node.key) &&
|
|
208
|
+
t.isArrayExpression(prop.node.value) &&
|
|
209
|
+
prop.node.value.elements.every(item => t.isNumericLiteral(item))) {
|
|
210
|
+
styleStatic.push([
|
|
211
|
+
prop.node.key,
|
|
212
|
+
t.stringLiteral(prop.node.value.elements
|
|
213
|
+
.map(item => {
|
|
214
|
+
return `${item.value}px`;
|
|
215
|
+
})
|
|
216
|
+
.join(" ")),
|
|
217
|
+
]);
|
|
218
|
+
}
|
|
219
|
+
// need processing in run time
|
|
220
|
+
else {
|
|
221
|
+
styleObject.push(t.objectProperty(prop.node.key, value));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// style={{...a}}
|
|
225
|
+
else if (t.isSpreadElement(propPath.node)) {
|
|
226
|
+
styleObject.push(propPath.node);
|
|
227
|
+
}
|
|
228
|
+
// style={{a(){}}}
|
|
229
|
+
else {
|
|
230
|
+
throw propPath.buildCodeFrameError("Vasille: Methods are not alllowed here");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
// style={".."}
|
|
235
|
+
else if (t.isJSXExpressionContainer(attr.value) && t.isStringLiteral(attr.value.expression)) {
|
|
236
|
+
attrs.push(t.objectProperty(t.identifier("style"), attr.value.expression));
|
|
237
|
+
}
|
|
238
|
+
// style={`a: ${b}px`}
|
|
239
|
+
else if (t.isJSXExpressionContainer(attr.value) && t.isTemplateLiteral(attr.value.expression)) {
|
|
240
|
+
const jsxAttrPath = attrPath;
|
|
241
|
+
const jsxContainerPath = jsxAttrPath.get("value");
|
|
242
|
+
const literalPath = jsxContainerPath.get("expression");
|
|
243
|
+
const value = exprCall(literalPath, attr.value.expression, internal);
|
|
244
|
+
attrs.push(t.objectProperty(t.identifier("style"), value !== null && value !== void 0 ? value : attr.value.expression));
|
|
245
|
+
if (value) {
|
|
246
|
+
console.warn(attrPath.buildCodeFrameError("Vasille: This will slow down your application"));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// style=<div/>
|
|
250
|
+
else {
|
|
251
|
+
throw attrPath.buildCodeFrameError('Vasille: Value of "style" attribute must be an object expression');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
if (t.isJSXExpressionContainer(attr.value)) {
|
|
256
|
+
attrs.push(t.objectProperty(id(name.name), t.isExpression(attr.value.expression) ? attr.value.expression : t.booleanLiteral(true)));
|
|
257
|
+
}
|
|
258
|
+
else if (t.isStringLiteral(attr.value)) {
|
|
259
|
+
attrs.push(t.objectProperty(id(name.name), attr.value));
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
throw attrPath.buildCodeFrameError("Vasille: Value of bind must be an expression or string");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (t.isJSXNamespacedName(name)) {
|
|
267
|
+
if (name.namespace.name === "bind") {
|
|
268
|
+
if (t.isJSXExpressionContainer(attr.value)) {
|
|
269
|
+
const value = t.isExpression(attr.value.expression)
|
|
270
|
+
? exprCall(attrPath.get("value"), attr.value.expression, internal)
|
|
271
|
+
: undefined;
|
|
272
|
+
bind.push(t.objectProperty(id(name.name.name), value !== null && value !== void 0 ? value : (t.isExpression(attr.value.expression) ? attr.value.expression : t.booleanLiteral(true))));
|
|
273
|
+
}
|
|
274
|
+
else if (t.isStringLiteral(attr.value)) {
|
|
275
|
+
bind.push(t.objectProperty(id(name.name.name), attr.value));
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
throw attrPath.buildCodeFrameError("Vasille: Value of bind must be an expression or string");
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
throw attrPath.buildCodeFrameError("Vasille: only bind namespace is supported");
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
throw attrPath.buildCodeFrameError("Vasille: Spread attribute is not allowed on HTML tags.");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (classStatic.length > 0) {
|
|
291
|
+
attrs.push(t.objectProperty(t.identifier("class"), t.stringLiteral(classStatic.join(" "))));
|
|
292
|
+
}
|
|
293
|
+
if (styleStatic.length > 0) {
|
|
294
|
+
attrs.push(t.objectProperty(t.identifier("style"), t.stringLiteral(styleStatic.map(([id, value]) => `${id.name}:${value.value}`).join(";"))));
|
|
295
|
+
}
|
|
296
|
+
const statements = transformJsxArray(path.get("children"), internal);
|
|
297
|
+
return t.expressionStatement(t.callExpression(t.memberExpression(ctx, t.identifier("tag")), [
|
|
298
|
+
t.stringLiteral(name.name),
|
|
299
|
+
t.objectExpression([
|
|
300
|
+
...(attrs.length > 0 ? [t.objectProperty(t.identifier("attr"), t.objectExpression(attrs))] : []),
|
|
301
|
+
...(events.length > 0 ? [t.objectProperty(t.identifier("events"), t.objectExpression(events))] : []),
|
|
302
|
+
...(bind.length > 0 ? [t.objectProperty(t.identifier("bind"), t.objectExpression(bind))] : []),
|
|
303
|
+
...(classElements.length > 0 || classObject.length
|
|
304
|
+
? [
|
|
305
|
+
t.objectProperty(t.identifier("class"), t.arrayExpression([
|
|
306
|
+
...classElements,
|
|
307
|
+
...(classObject.length > 0 ? [t.objectExpression(classObject)] : []),
|
|
308
|
+
])),
|
|
309
|
+
]
|
|
310
|
+
: []),
|
|
311
|
+
...(styleObject.length > 0 ? [t.objectProperty(t.identifier("style"), t.objectExpression(styleObject))] : []),
|
|
312
|
+
]),
|
|
313
|
+
...(statements.length > 0 ? [t.arrowFunctionExpression([ctx], t.blockStatement(statements))] : []),
|
|
314
|
+
]));
|
|
315
|
+
}
|
|
316
|
+
if (t.isJSXIdentifier(name)) {
|
|
317
|
+
const element = path.node;
|
|
318
|
+
const opening = path.get("openingElement");
|
|
319
|
+
const props = [];
|
|
320
|
+
let run;
|
|
321
|
+
for (const attrPath of opening.get("attributes")) {
|
|
322
|
+
const attr = attrPath.node;
|
|
323
|
+
// <A prop=../>
|
|
324
|
+
if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
|
|
325
|
+
// <A prop=".."/>
|
|
326
|
+
if (t.isStringLiteral(attr.value)) {
|
|
327
|
+
props.push(t.objectProperty(id(attr.name.name), attr.value));
|
|
328
|
+
}
|
|
329
|
+
// <A prop={..}/>
|
|
330
|
+
else if (t.isJSXExpressionContainer(attr.value)) {
|
|
331
|
+
const isSystem = internal.mapping.has(name.name);
|
|
332
|
+
const value = transformJsxExpressionContainer(attrPath.get("value"), internal, !isSystem || attr.name.name === "slot", isSystem && attr.name.name === "slot");
|
|
333
|
+
props.push(t.objectProperty(id(attr.name.name), value));
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
throw attrPath.buildCodeFrameError("Vasille: JSX Elements/Fragments are not supported here");
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
// <A {...arg}/>
|
|
340
|
+
else if (t.isJSXSpreadAttribute(attr)) {
|
|
341
|
+
props.push(t.spreadElement(attr.argument));
|
|
342
|
+
}
|
|
343
|
+
// <A space:name=../>
|
|
344
|
+
else {
|
|
345
|
+
throw attrPath.buildCodeFrameError("Vasille: Namespaced attributes names are not supported");
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (element.children.length === 1 &&
|
|
349
|
+
t.isJSXExpressionContainer(element.children[0]) &&
|
|
350
|
+
(t.isFunctionExpression(element.children[0].expression) ||
|
|
351
|
+
t.isArrowFunctionExpression(element.children[0].expression))) {
|
|
352
|
+
run = element.children[0].expression;
|
|
353
|
+
run.params.push(ctx);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
const statements = transformJsxArray(path.get("children"), internal);
|
|
357
|
+
if (statements.length > 0) {
|
|
358
|
+
run = t.arrowFunctionExpression([ctx], t.blockStatement(statements));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return t.expressionStatement(t.callExpression(t.identifier(name.name), [ctx, t.objectExpression(props), ...(run ? [run] : [])]));
|
|
362
|
+
}
|
|
363
|
+
throw path.buildCodeFrameError("Vasille: Unsupported tag detected, html lowercase tagnames and components are accepted");
|
|
364
|
+
}
|
package/lib/lib.js
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { checkNode, encodeName } from "./expression.js";
|
|
3
|
+
import { ctx } from "./internal.js";
|
|
4
|
+
import { calls } from "./call.js";
|
|
5
|
+
export function parseCalculateCall(path, internal) {
|
|
6
|
+
if (t.isCallExpression(path.node) && calls(path.node, ["calculate", "watch"], internal)) {
|
|
7
|
+
if (path.node.arguments.length !== 1) {
|
|
8
|
+
throw path.buildCodeFrameError("Vasille: Incorrect number of arguments");
|
|
9
|
+
}
|
|
10
|
+
if (t.isFunctionExpression(path.node.arguments[0]) || t.isArrowFunctionExpression(path.node.arguments[0])) {
|
|
11
|
+
if (path.node.arguments[0].params.length > 0) {
|
|
12
|
+
throw path.buildCodeFrameError("Vasille: Argument of calculate cannot have parameters");
|
|
13
|
+
}
|
|
14
|
+
const exprData = checkNode(path.get("arguments")[0], internal);
|
|
15
|
+
path.node.arguments[0].params = [...exprData.found.keys()].map(name => encodeName(name));
|
|
16
|
+
return [path.node.arguments[0], ...exprData.found.values()];
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
throw path.buildCodeFrameError("Vasille: Argument of calculate must be a function");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
export function exprCall(path, expr, internal) {
|
|
25
|
+
const calculateCall = parseCalculateCall(path, internal);
|
|
26
|
+
if (calculateCall) {
|
|
27
|
+
return t.callExpression(t.memberExpression(ctx, t.identifier("expr")), calculateCall);
|
|
28
|
+
}
|
|
29
|
+
const exprData = checkNode(path, internal);
|
|
30
|
+
return exprData.self
|
|
31
|
+
? exprData.self
|
|
32
|
+
: exprData.found.size > 0 && expr
|
|
33
|
+
? t.callExpression(t.memberExpression(ctx, t.identifier("expr")), [
|
|
34
|
+
t.arrowFunctionExpression([...exprData.found.keys()].map(name => encodeName(name)), expr),
|
|
35
|
+
...exprData.found.values(),
|
|
36
|
+
])
|
|
37
|
+
: null;
|
|
38
|
+
}
|
|
39
|
+
export function forwardOnlyExpr(path, expr, internal) {
|
|
40
|
+
if (t.isCallExpression(path.node) && calls(path.node, ["calculate"], internal)) {
|
|
41
|
+
if (path.node.arguments.length !== 1) {
|
|
42
|
+
throw path.buildCodeFrameError("Vasille: Incorrect number of arguments");
|
|
43
|
+
}
|
|
44
|
+
if (t.isFunctionExpression(path.node.arguments[0]) || t.isArrowFunctionExpression(path.node.arguments[0])) {
|
|
45
|
+
if (path.node.arguments[0].params.length > 0) {
|
|
46
|
+
throw path.buildCodeFrameError("Vasille: Argument of calculate cannot have parameters");
|
|
47
|
+
}
|
|
48
|
+
const exprData = checkNode(path.get("arguments")[0], internal);
|
|
49
|
+
path.node.arguments[0].params = [...exprData.found.keys()].map(name => encodeName(name));
|
|
50
|
+
return t.callExpression(t.memberExpression(internal.id, t.identifier("ex")), [
|
|
51
|
+
path.node.arguments[0],
|
|
52
|
+
...exprData.found.values(),
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
throw path.buildCodeFrameError("Vasille: Argument of calculate must be a function");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const calculateCall = parseCalculateCall(path, internal);
|
|
60
|
+
if (calculateCall) {
|
|
61
|
+
return t.callExpression(t.memberExpression(internal.id, t.identifier("ex")), calculateCall);
|
|
62
|
+
}
|
|
63
|
+
const exprData = checkNode(path, internal);
|
|
64
|
+
return exprData.self
|
|
65
|
+
? t.callExpression(t.memberExpression(internal.id, t.identifier("fo")), [exprData.self])
|
|
66
|
+
: exprData.found.size > 0 && expr
|
|
67
|
+
? t.callExpression(t.memberExpression(internal.id, t.identifier("ex")), [
|
|
68
|
+
t.arrowFunctionExpression([...exprData.found.keys()].map(name => encodeName(name)), expr),
|
|
69
|
+
...exprData.found.values(),
|
|
70
|
+
])
|
|
71
|
+
: null;
|
|
72
|
+
}
|
|
73
|
+
export function own(expr) {
|
|
74
|
+
return t.callExpression(t.memberExpression(ctx, t.identifier("own")), [expr]);
|
|
75
|
+
}
|
|
76
|
+
export function ref(expr) {
|
|
77
|
+
return t.callExpression(t.memberExpression(ctx, t.identifier("ref")), expr ? [expr] : []);
|
|
78
|
+
}
|
|
79
|
+
export function reactiveObject(init, internal) {
|
|
80
|
+
return t.callExpression(t.memberExpression(internal.id, t.identifier("ro")), [ctx, init]);
|
|
81
|
+
}
|
|
82
|
+
export function arrayModel(init, internal) {
|
|
83
|
+
return t.callExpression(t.memberExpression(internal.id, t.identifier("am")), [ctx, ...(init ? [init] : [])]);
|
|
84
|
+
}
|
|
85
|
+
export function setModel(args, internal) {
|
|
86
|
+
return t.callExpression(t.memberExpression(internal.id, t.identifier("sm")), [ctx, ...args]);
|
|
87
|
+
}
|
|
88
|
+
export function mapModel(args, internal) {
|
|
89
|
+
return t.callExpression(t.memberExpression(internal.id, t.identifier("mm")), [ctx, ...args]);
|
|
90
|
+
}
|