babel-plugin-vasille 0.99.1 → 0.99.3
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 +3 -3
- package/lib/call.js +19 -5
- package/lib/css-transformer.js +206 -0
- package/lib/expression.js +1 -1
- package/lib/index.js +2 -2
- package/lib/jsx.js +65 -27
- package/lib/lib.js +3 -3
- package/lib/mesh.js +16 -13
- package/lib/transformer.js +48 -4
- package/lib-node/call.js +22 -8
- package/lib-node/css-transformer.js +232 -0
- package/lib-node/expression.js +2 -2
- package/lib-node/index.js +2 -2
- package/lib-node/jsx.js +84 -46
- package/lib-node/lib.js +21 -21
- package/lib-node/mesh.js +55 -52
- package/lib-node/transformer.js +49 -5
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ $ npx degit vasille-js/example-javascript my-project
|
|
|
47
47
|
|
|
48
48
|
### Examples
|
|
49
49
|
* [TypeScript Example](https://github.com/vasille-js/example-typescript)
|
|
50
|
-
* [JavaScript Example](https://github.com/
|
|
50
|
+
* [JavaScript Example](https://github.com/vasille-js/example-javascript)
|
|
51
51
|
|
|
52
52
|
<hr>
|
|
53
53
|
|
|
@@ -104,8 +104,8 @@ All of these are supported:
|
|
|
104
104
|
* [x] `100%` Test Coverage for the JSX library.
|
|
105
105
|
* [x] Develop the `Vasille Babel Plugin`.
|
|
106
106
|
* [ ] `100%` Test Coverage fot babel plugin.
|
|
107
|
-
* [
|
|
108
|
-
* [ ] Add custom
|
|
107
|
+
* [x] Add CSS support (define styles in components).
|
|
108
|
+
* [ ] Add custom `input` components with 2-way value binding.
|
|
109
109
|
* [ ] Add router.
|
|
110
110
|
* [ ] Develop dev-tools extension for debugging.
|
|
111
111
|
* [ ] Develop a lot of libraries for the framework.
|
package/lib/call.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
|
-
import { ctx } from "./internal
|
|
2
|
+
import { ctx } from "./internal";
|
|
3
3
|
export const composeOnly = [
|
|
4
4
|
"forward",
|
|
5
5
|
"watch",
|
|
@@ -11,6 +11,16 @@ export const composeOnly = [
|
|
|
11
11
|
"setModel",
|
|
12
12
|
"reactiveObject",
|
|
13
13
|
];
|
|
14
|
+
export const styleOnly = [
|
|
15
|
+
"theme",
|
|
16
|
+
"dark",
|
|
17
|
+
"mobile",
|
|
18
|
+
"tablet",
|
|
19
|
+
"laptop",
|
|
20
|
+
"prefersDark",
|
|
21
|
+
"prefersLight",
|
|
22
|
+
"webStyleSheet",
|
|
23
|
+
];
|
|
14
24
|
export const requiresContext = ["awaited", "forward"];
|
|
15
25
|
const requiresContextSet = new Set(requiresContext);
|
|
16
26
|
export function calls(node, names, internal) {
|
|
@@ -27,9 +37,10 @@ export function calls(node, names, internal) {
|
|
|
27
37
|
}
|
|
28
38
|
return false;
|
|
29
39
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
const global = internal.stack.get(internal.global) === undefined;
|
|
41
|
+
const cssGlobal = internal.stack.get(internal.cssGlobal) === undefined;
|
|
42
|
+
if (!global && !cssGlobal) {
|
|
43
|
+
return;
|
|
33
44
|
}
|
|
34
45
|
const propName = t.isMemberExpression(callee)
|
|
35
46
|
? t.isIdentifier(callee.property)
|
|
@@ -39,12 +50,15 @@ export function calls(node, names, internal) {
|
|
|
39
50
|
: null
|
|
40
51
|
: null;
|
|
41
52
|
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object) && propName) {
|
|
42
|
-
if (callee.object.name === internal.global && set.has(propName)) {
|
|
53
|
+
if (global && callee.object.name === internal.global && set.has(propName)) {
|
|
43
54
|
if (requiresContextSet.has(callee.object.name) && t.isCallExpression(node)) {
|
|
44
55
|
node.arguments.unshift(ctx);
|
|
45
56
|
}
|
|
46
57
|
return callee.object.name;
|
|
47
58
|
}
|
|
59
|
+
if (cssGlobal && callee.object.name === internal.cssGlobal && set.has(propName)) {
|
|
60
|
+
return callee.object.name;
|
|
61
|
+
}
|
|
48
62
|
}
|
|
49
63
|
}
|
|
50
64
|
return false;
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { calls } from "./call";
|
|
3
|
+
function tryProcessProp(path, pseudo, media, internal) {
|
|
4
|
+
if (t.isObjectMethod(path.node)) {
|
|
5
|
+
throw path.buildCodeFrameError("Object methods not supported here");
|
|
6
|
+
}
|
|
7
|
+
if (t.isSpreadElement(path.node)) {
|
|
8
|
+
throw path.buildCodeFrameError("Spread element not suppored here");
|
|
9
|
+
}
|
|
10
|
+
return processProp(path, pseudo, media, internal);
|
|
11
|
+
}
|
|
12
|
+
const mediaDefaults = ["mobile", "tablet", "laptop", "prefersDark", "prefersLight"];
|
|
13
|
+
function processValue(name, path, pseudo, theme, media, mediaDefault, allowFallback, internal) {
|
|
14
|
+
if (calls(path.node, ["theme"], internal)) {
|
|
15
|
+
const call = path.node;
|
|
16
|
+
if (theme) {
|
|
17
|
+
throw path.buildCodeFrameError("Vasille: Theme seem the be defined twince");
|
|
18
|
+
}
|
|
19
|
+
if (t.isStringLiteral(call.arguments[0])) {
|
|
20
|
+
return processValue(name, path.get("arguments")[1], pseudo, `body.${call.arguments[0].value}`, media, mediaDefault, false, internal);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
throw path
|
|
24
|
+
.get("arguments")[0]
|
|
25
|
+
.buildCodeFrameError("Vasille: Expected string literal");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (calls(path.node, ["dark"], internal)) {
|
|
29
|
+
if (theme) {
|
|
30
|
+
throw path.buildCodeFrameError("Vasille: Theme seem the be defined twince");
|
|
31
|
+
}
|
|
32
|
+
return processValue(name, path.get("arguments")[0], pseudo, `.dark`, media, mediaDefault, false, internal);
|
|
33
|
+
}
|
|
34
|
+
let callee;
|
|
35
|
+
if ((callee = calls(path.node, mediaDefaults, internal))) {
|
|
36
|
+
const index = mediaDefaults.indexOf(callee) + 1;
|
|
37
|
+
if (mediaDefault.includes(index)) {
|
|
38
|
+
return processValue(name, path.get("arguments")[0], pseudo, theme, media, mediaDefault, false, internal);
|
|
39
|
+
}
|
|
40
|
+
return processValue(name, path.get("arguments")[0], pseudo, theme, media, [...mediaDefault, index], false, internal);
|
|
41
|
+
}
|
|
42
|
+
function composeRules(value) {
|
|
43
|
+
return mediaDefault.length
|
|
44
|
+
? mediaDefault.map(index => {
|
|
45
|
+
return {
|
|
46
|
+
defaultMediaRule: index,
|
|
47
|
+
mediaRule: media,
|
|
48
|
+
pseudo: pseudo,
|
|
49
|
+
theme: theme,
|
|
50
|
+
rule: `${name}:${value}`,
|
|
51
|
+
};
|
|
52
|
+
})
|
|
53
|
+
: [
|
|
54
|
+
{
|
|
55
|
+
defaultMediaRule: 0,
|
|
56
|
+
mediaRule: media,
|
|
57
|
+
pseudo: pseudo,
|
|
58
|
+
theme: theme,
|
|
59
|
+
rule: `${name}:${value}`,
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
if (t.isStringLiteral(path.node)) {
|
|
64
|
+
return composeRules(path.node.value);
|
|
65
|
+
}
|
|
66
|
+
if (t.isNumericLiteral(path.node)) {
|
|
67
|
+
return composeRules(`${path.node.value}px`);
|
|
68
|
+
}
|
|
69
|
+
if (t.isArrayExpression(path.node)) {
|
|
70
|
+
if (path.node.elements.every(item => t.isNumericLiteral(item))) {
|
|
71
|
+
return composeRules(path.node.elements.map(item => `${item.value}px`).join(" "));
|
|
72
|
+
}
|
|
73
|
+
else if (allowFallback) {
|
|
74
|
+
return [
|
|
75
|
+
...path.get("elements").map(path => {
|
|
76
|
+
if (t.isExpression(path.node)) {
|
|
77
|
+
return processValue(name, path, pseudo, theme, media, mediaDefault, false, internal);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
throw path.buildCodeFrameError("Vasille: Exprected expression");
|
|
81
|
+
}
|
|
82
|
+
}).flat(1),
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
throw path.buildCodeFrameError("Vasille: Only numbers arrays are suppored here");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
throw path.buildCodeFrameError("Vasille: Failed o parse value, it is not a string, number or array");
|
|
90
|
+
}
|
|
91
|
+
function processProp(path, pseudo, media, internal) {
|
|
92
|
+
let name;
|
|
93
|
+
if (t.isIdentifier(path.node.key)) {
|
|
94
|
+
name = path.node.key.name;
|
|
95
|
+
}
|
|
96
|
+
else if (t.isStringLiteral(path.node.key)) {
|
|
97
|
+
name = path.node.key.value;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw path.get("key").buildCodeFrameError("Vasille: Incompaible key, exprect idenifier or string literal");
|
|
101
|
+
}
|
|
102
|
+
if (name.startsWith("@")) {
|
|
103
|
+
if (media || pseudo) {
|
|
104
|
+
throw path.get("key").buildCodeFrameError("Vasille: Media queries allowed inly in the root of style");
|
|
105
|
+
}
|
|
106
|
+
if (t.isObjectExpression(path.node.value)) {
|
|
107
|
+
return path.get("value").get("properties").map(item => {
|
|
108
|
+
return tryProcessProp(item, "", name, internal);
|
|
109
|
+
}).flat(1);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
throw path.get("value").buildCodeFrameError("Vasille: Exprected object expression");
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (name.startsWith(":")) {
|
|
116
|
+
if (pseudo) {
|
|
117
|
+
throw path.get("key").buildCodeFrameError("Recursive pseudo classes are restriced");
|
|
118
|
+
}
|
|
119
|
+
if (t.isObjectExpression(path.node.value)) {
|
|
120
|
+
return path.get("value").get("properties").map(item => {
|
|
121
|
+
return tryProcessProp(item, name, media, internal);
|
|
122
|
+
}).flat(1);
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
throw path.get("value").buildCodeFrameError("Vasille: Exprected object expression");
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return processValue(name, path.get("value"), pseudo, "", media, [], true, internal);
|
|
129
|
+
}
|
|
130
|
+
export function findStyleInNode(path, internal) {
|
|
131
|
+
if (t.isExpressionStatement(path.node)) {
|
|
132
|
+
return findStyleInNode(path.get("expression"), internal);
|
|
133
|
+
}
|
|
134
|
+
if (t.isExportNamedDeclaration(path.node)) {
|
|
135
|
+
return findStyleInNode(path.get("declaration"), internal);
|
|
136
|
+
}
|
|
137
|
+
if (t.isVariableDeclaration(path.node) &&
|
|
138
|
+
path.node.declarations.length === 1 &&
|
|
139
|
+
calls(path.node.declarations[0].init, ["webStyleSheet"], internal)) {
|
|
140
|
+
const call = path.node.declarations[0].init;
|
|
141
|
+
const callPath = path
|
|
142
|
+
.get("declarations")[0]
|
|
143
|
+
.get("init");
|
|
144
|
+
const objPath = callPath.get("arguments")[0];
|
|
145
|
+
if (call.arguments.length !== 1) {
|
|
146
|
+
throw callPath.buildCodeFrameError("Vasille: webStyleSheet function has 1 parameter");
|
|
147
|
+
}
|
|
148
|
+
if (!t.isObjectExpression(call.arguments[0])) {
|
|
149
|
+
throw objPath.buildCodeFrameError("Vasille: expected object expression");
|
|
150
|
+
}
|
|
151
|
+
for (const path of objPath.get("properties")) {
|
|
152
|
+
if (!t.isObjectProperty(path.node)) {
|
|
153
|
+
throw path.buildCodeFrameError("Vasille: Expected object property");
|
|
154
|
+
}
|
|
155
|
+
const prop = path;
|
|
156
|
+
if (!t.isObjectExpression(prop.node.value)) {
|
|
157
|
+
throw prop.get("value").buildCodeFrameError("Vasille: Exprected object expression");
|
|
158
|
+
}
|
|
159
|
+
if (!(t.isIdentifier(prop.node.key) || t.isStringLiteral(prop.node.key))) {
|
|
160
|
+
throw prop.get("key").buildCodeFrameError("Vasille: Expected identifier of string literal");
|
|
161
|
+
}
|
|
162
|
+
const unsorted = [];
|
|
163
|
+
const sorted = {};
|
|
164
|
+
for (const path of prop.get("value").get("properties")) {
|
|
165
|
+
unsorted.push(...tryProcessProp(path, "", "", internal));
|
|
166
|
+
}
|
|
167
|
+
for (const rule of unsorted) {
|
|
168
|
+
if (!sorted[rule.defaultMediaRule]) {
|
|
169
|
+
sorted[rule.defaultMediaRule] = {};
|
|
170
|
+
}
|
|
171
|
+
const defaultMediaRule = sorted[rule.defaultMediaRule];
|
|
172
|
+
if (!defaultMediaRule[rule.mediaRule]) {
|
|
173
|
+
defaultMediaRule[rule.mediaRule] = {};
|
|
174
|
+
}
|
|
175
|
+
const mediaRule = defaultMediaRule[rule.mediaRule];
|
|
176
|
+
if (!mediaRule[rule.theme]) {
|
|
177
|
+
mediaRule[rule.theme] = {};
|
|
178
|
+
}
|
|
179
|
+
const theme = mediaRule[rule.theme];
|
|
180
|
+
if (!theme[rule.pseudo]) {
|
|
181
|
+
theme[rule.pseudo] = [];
|
|
182
|
+
}
|
|
183
|
+
theme[rule.pseudo].push(rule.rule);
|
|
184
|
+
}
|
|
185
|
+
const expressions = [];
|
|
186
|
+
for (const defaultMediaRule in sorted) {
|
|
187
|
+
for (const mediaRule in sorted[defaultMediaRule]) {
|
|
188
|
+
for (const theme in sorted[defaultMediaRule][mediaRule]) {
|
|
189
|
+
for (const pseudo in sorted[defaultMediaRule][mediaRule][theme]) {
|
|
190
|
+
const rulePack = sorted[defaultMediaRule][mediaRule][theme][pseudo].join(";");
|
|
191
|
+
const pseudoPack = pseudo ? `{}${pseudo}{${rulePack}}` : `{}{${rulePack}}`;
|
|
192
|
+
const themePack = theme ? `${theme} ${pseudoPack}` : pseudoPack;
|
|
193
|
+
const mediaRulePack = t.stringLiteral(mediaRule ? `${mediaRule}{${themePack}}` : themePack);
|
|
194
|
+
expressions.push(defaultMediaRule !== '0'
|
|
195
|
+
? t.arrayExpression([t.numericLiteral(parseInt(defaultMediaRule)), mediaRulePack])
|
|
196
|
+
: mediaRulePack);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
prop.get("value").replaceWith(t.arrayExpression(expressions));
|
|
202
|
+
}
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
}
|
package/lib/expression.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { trProgram } from "./transformer
|
|
1
|
+
import { trProgram } from "./transformer";
|
|
2
2
|
export default function () {
|
|
3
3
|
return {
|
|
4
4
|
name: "Vasille",
|
|
5
5
|
visitor: {
|
|
6
6
|
Program(path, params) {
|
|
7
|
-
trProgram(path, params.devMode !== false);
|
|
7
|
+
trProgram(path, params.opts.devMode !== false);
|
|
8
8
|
},
|
|
9
9
|
},
|
|
10
10
|
};
|
package/lib/jsx.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
|
-
import { ctx } from "./internal
|
|
3
|
-
import { exprCall } from "./lib
|
|
4
|
-
import { compose, meshExpression } from "./mesh
|
|
5
|
-
import { bodyHasJsx } from "./jsx-detect
|
|
2
|
+
import { ctx } from "./internal";
|
|
3
|
+
import { exprCall } from "./lib";
|
|
4
|
+
import { compose, meshExpression } from "./mesh";
|
|
5
|
+
import { bodyHasJsx } from "./jsx-detect";
|
|
6
6
|
export function transformJsx(path, internal) {
|
|
7
7
|
if (t.isJSXElement(path.node)) {
|
|
8
8
|
return [transformJsxElement(path, internal)];
|
|
@@ -21,12 +21,31 @@ export function transformJsxArray(paths, internal) {
|
|
|
21
21
|
.replace(/\n\s+$/m, "")
|
|
22
22
|
.replace(/^\s*\n\s+/m, "")
|
|
23
23
|
.replace(/\s*\n\s*/gm, "\n");
|
|
24
|
-
|
|
24
|
+
const call = t.callExpression(t.memberExpression(ctx, t.identifier("text")), [t.stringLiteral(fixed)]);
|
|
25
|
+
call.loc = path.node.loc;
|
|
26
|
+
if (call.loc) {
|
|
27
|
+
for (const char of path.node.value) {
|
|
28
|
+
if (!/\s/.test(char)) {
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
if (char === "\n") {
|
|
32
|
+
call.loc.start.column = 0;
|
|
33
|
+
call.loc.start.line++;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
call.loc.start.column++;
|
|
37
|
+
}
|
|
38
|
+
call.loc.start.index++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
result.push(t.expressionStatement(call));
|
|
25
42
|
}
|
|
26
43
|
}
|
|
27
44
|
else if (t.isJSXExpressionContainer(path.node)) {
|
|
28
45
|
const value = transformJsxExpressionContainer(path, internal, false, false);
|
|
29
|
-
|
|
46
|
+
const call = t.callExpression(t.memberExpression(ctx, t.identifier("text")), [value]);
|
|
47
|
+
call.loc = value.loc;
|
|
48
|
+
result.push(t.expressionStatement(call));
|
|
30
49
|
}
|
|
31
50
|
else {
|
|
32
51
|
throw path.buildCodeFrameError("Vasille: Spread child is not supported");
|
|
@@ -38,6 +57,7 @@ function transformJsxExpressionContainer(path, internal, acceptSlots, isInternal
|
|
|
38
57
|
if (!t.isExpression(path.node.expression)) {
|
|
39
58
|
return t.booleanLiteral(true);
|
|
40
59
|
}
|
|
60
|
+
const loc = path.node.expression.loc;
|
|
41
61
|
if (acceptSlots &&
|
|
42
62
|
(t.isFunctionExpression(path.node.expression) || t.isArrowFunctionExpression(path.node.expression)) &&
|
|
43
63
|
bodyHasJsx(path.node.expression.body)) {
|
|
@@ -51,6 +71,7 @@ function transformJsxExpressionContainer(path, internal, acceptSlots, isInternal
|
|
|
51
71
|
else {
|
|
52
72
|
path.node.expression.params.unshift(ctx);
|
|
53
73
|
}
|
|
74
|
+
path.node.expression.loc = loc;
|
|
54
75
|
return path.node.expression;
|
|
55
76
|
}
|
|
56
77
|
else if (isInternalSlot &&
|
|
@@ -63,15 +84,24 @@ function transformJsxExpressionContainer(path, internal, acceptSlots, isInternal
|
|
|
63
84
|
internal.stack.get(path.node.expression.name) === 3 /* VariableState.ReactiveObject */) {
|
|
64
85
|
call = t.callExpression(t.memberExpression(internal.id, t.identifier("rop")), [path.node.expression]);
|
|
65
86
|
}
|
|
66
|
-
|
|
87
|
+
const result = call !== null && call !== void 0 ? call : path.node.expression;
|
|
88
|
+
result.loc = loc;
|
|
89
|
+
return result;
|
|
67
90
|
}
|
|
68
|
-
function id
|
|
91
|
+
function idToProp(id, value, from) {
|
|
92
|
+
let str = t.isIdentifier(id) || t.isJSXIdentifier(id) ? id.name : id.value;
|
|
93
|
+
let expr;
|
|
94
|
+
if (from) {
|
|
95
|
+
str = str.substring(from);
|
|
96
|
+
}
|
|
69
97
|
if (/^[\w_]+$/.test(str)) {
|
|
70
|
-
|
|
98
|
+
expr = t.identifier(str);
|
|
71
99
|
}
|
|
72
100
|
else {
|
|
73
|
-
|
|
101
|
+
expr = t.stringLiteral(str);
|
|
74
102
|
}
|
|
103
|
+
expr.loc = id.loc;
|
|
104
|
+
return t.objectProperty(expr, value);
|
|
75
105
|
}
|
|
76
106
|
function transformJsxElement(path, internal) {
|
|
77
107
|
var _a, _b;
|
|
@@ -97,7 +127,7 @@ function transformJsxElement(path, internal) {
|
|
|
97
127
|
if (t.isExpression(path.node.expression)) {
|
|
98
128
|
meshExpression(path.get("expression"), internal);
|
|
99
129
|
}
|
|
100
|
-
events.push(
|
|
130
|
+
events.push(idToProp(name, path.node.expression, 2));
|
|
101
131
|
}
|
|
102
132
|
else {
|
|
103
133
|
throw attrPath
|
|
@@ -116,7 +146,7 @@ function transformJsxElement(path, internal) {
|
|
|
116
146
|
// class={[cond && "string"]}
|
|
117
147
|
if (t.isLogicalExpression(item) && item.operator === "&&" && t.isStringLiteral(item.right)) {
|
|
118
148
|
const call = exprCall(elementPath.get("left"), item.left, internal);
|
|
119
|
-
classObject.push(
|
|
149
|
+
classObject.push(idToProp(item.right, call !== null && call !== void 0 ? call : item.left));
|
|
120
150
|
}
|
|
121
151
|
// class={[{..}]}
|
|
122
152
|
else if (t.isObjectExpression(item)) {
|
|
@@ -142,7 +172,7 @@ function transformJsxElement(path, internal) {
|
|
|
142
172
|
}
|
|
143
173
|
// class={[".."]}
|
|
144
174
|
else if (t.isStringLiteral(elementPath.node)) {
|
|
145
|
-
classStatic.push(elementPath.node
|
|
175
|
+
classStatic.push(elementPath.node);
|
|
146
176
|
}
|
|
147
177
|
// class={[..]}
|
|
148
178
|
else {
|
|
@@ -172,10 +202,7 @@ function transformJsxElement(path, internal) {
|
|
|
172
202
|
}
|
|
173
203
|
// class="a b"
|
|
174
204
|
else if (t.isStringLiteral(attr.value)) {
|
|
175
|
-
|
|
176
|
-
for (const item of splitted) {
|
|
177
|
-
classStatic.push(item);
|
|
178
|
-
}
|
|
205
|
+
classStatic.push(attr.value);
|
|
179
206
|
}
|
|
180
207
|
// class=<div/>
|
|
181
208
|
else {
|
|
@@ -253,10 +280,10 @@ function transformJsxElement(path, internal) {
|
|
|
253
280
|
}
|
|
254
281
|
else {
|
|
255
282
|
if (t.isJSXExpressionContainer(attr.value)) {
|
|
256
|
-
attrs.push(
|
|
283
|
+
attrs.push(idToProp(name, t.isExpression(attr.value.expression) ? attr.value.expression : t.booleanLiteral(true)));
|
|
257
284
|
}
|
|
258
285
|
else if (t.isStringLiteral(attr.value)) {
|
|
259
|
-
attrs.push(
|
|
286
|
+
attrs.push(idToProp(name, attr.value));
|
|
260
287
|
}
|
|
261
288
|
else {
|
|
262
289
|
throw attrPath.buildCodeFrameError("Vasille: Value of bind must be an expression or string");
|
|
@@ -269,10 +296,10 @@ function transformJsxElement(path, internal) {
|
|
|
269
296
|
const value = t.isExpression(attr.value.expression)
|
|
270
297
|
? exprCall(attrPath.get("value"), attr.value.expression, internal)
|
|
271
298
|
: undefined;
|
|
272
|
-
bind.push(
|
|
299
|
+
bind.push(idToProp(name.name, value !== null && value !== void 0 ? value : (t.isExpression(attr.value.expression) ? attr.value.expression : t.booleanLiteral(true))));
|
|
273
300
|
}
|
|
274
301
|
else if (t.isStringLiteral(attr.value)) {
|
|
275
|
-
bind.push(
|
|
302
|
+
bind.push(idToProp(name.name, attr.value));
|
|
276
303
|
}
|
|
277
304
|
else {
|
|
278
305
|
throw attrPath.buildCodeFrameError("Vasille: Value of bind must be an expression or string");
|
|
@@ -288,13 +315,16 @@ function transformJsxElement(path, internal) {
|
|
|
288
315
|
}
|
|
289
316
|
}
|
|
290
317
|
if (classStatic.length > 0) {
|
|
291
|
-
|
|
318
|
+
const first = classStatic[0];
|
|
319
|
+
const value = classStatic.length === 1 ? classStatic[0] : t.stringLiteral(classStatic.map(item => item.value).join(" "));
|
|
320
|
+
value.loc = first.loc;
|
|
321
|
+
attrs.push(t.objectProperty(t.identifier("class"), value));
|
|
292
322
|
}
|
|
293
323
|
if (styleStatic.length > 0) {
|
|
294
324
|
attrs.push(t.objectProperty(t.identifier("style"), t.stringLiteral(styleStatic.map(([id, value]) => `${id.name}:${value.value}`).join(";"))));
|
|
295
325
|
}
|
|
296
326
|
const statements = transformJsxArray(path.get("children"), internal);
|
|
297
|
-
|
|
327
|
+
const call = t.callExpression(t.memberExpression(ctx, t.identifier("tag")), [
|
|
298
328
|
t.stringLiteral(name.name),
|
|
299
329
|
t.objectExpression([
|
|
300
330
|
...(attrs.length > 0 ? [t.objectProperty(t.identifier("attr"), t.objectExpression(attrs))] : []),
|
|
@@ -311,26 +341,32 @@ function transformJsxElement(path, internal) {
|
|
|
311
341
|
...(styleObject.length > 0 ? [t.objectProperty(t.identifier("style"), t.objectExpression(styleObject))] : []),
|
|
312
342
|
]),
|
|
313
343
|
...(statements.length > 0 ? [t.arrowFunctionExpression([ctx], t.blockStatement(statements))] : []),
|
|
314
|
-
])
|
|
344
|
+
]);
|
|
345
|
+
call.loc = path.node.loc;
|
|
346
|
+
return t.expressionStatement(call);
|
|
315
347
|
}
|
|
316
348
|
if (t.isJSXIdentifier(name)) {
|
|
317
349
|
const element = path.node;
|
|
318
350
|
const opening = path.get("openingElement");
|
|
319
351
|
const props = [];
|
|
320
352
|
let run;
|
|
353
|
+
const mapped = internal.mapping.get(name.name);
|
|
354
|
+
if (mapped === "Debug" && internal.stack.get(name.name) === undefined && !internal.devMode) {
|
|
355
|
+
return t.emptyStatement();
|
|
356
|
+
}
|
|
321
357
|
for (const attrPath of opening.get("attributes")) {
|
|
322
358
|
const attr = attrPath.node;
|
|
323
359
|
// <A prop=../>
|
|
324
360
|
if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
|
|
325
361
|
// <A prop=".."/>
|
|
326
362
|
if (t.isStringLiteral(attr.value)) {
|
|
327
|
-
props.push(
|
|
363
|
+
props.push(idToProp(attr.name, attr.value));
|
|
328
364
|
}
|
|
329
365
|
// <A prop={..}/>
|
|
330
366
|
else if (t.isJSXExpressionContainer(attr.value)) {
|
|
331
367
|
const isSystem = internal.mapping.has(name.name);
|
|
332
368
|
const value = transformJsxExpressionContainer(attrPath.get("value"), internal, !isSystem || attr.name.name === "slot", isSystem && attr.name.name === "slot");
|
|
333
|
-
props.push(
|
|
369
|
+
props.push(idToProp(attr.name, value));
|
|
334
370
|
}
|
|
335
371
|
else {
|
|
336
372
|
throw attrPath.buildCodeFrameError("Vasille: JSX Elements/Fragments are not supported here");
|
|
@@ -358,7 +394,9 @@ function transformJsxElement(path, internal) {
|
|
|
358
394
|
run = t.arrowFunctionExpression([ctx], t.blockStatement(statements));
|
|
359
395
|
}
|
|
360
396
|
}
|
|
361
|
-
|
|
397
|
+
const call = t.callExpression(t.identifier(name.name), [ctx, t.objectExpression(props), ...(run ? [run] : [])]);
|
|
398
|
+
call.loc = path.node.loc;
|
|
399
|
+
return t.expressionStatement(call);
|
|
362
400
|
}
|
|
363
401
|
throw path.buildCodeFrameError("Vasille: Unsupported tag detected, html lowercase tagnames and components are accepted");
|
|
364
402
|
}
|
package/lib/lib.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
|
-
import { checkNode, encodeName } from "./expression
|
|
3
|
-
import { ctx } from "./internal
|
|
4
|
-
import { calls } from "./call
|
|
2
|
+
import { checkNode, encodeName } from "./expression";
|
|
3
|
+
import { ctx } from "./internal";
|
|
4
|
+
import { calls } from "./call";
|
|
5
5
|
export function parseCalculateCall(path, internal) {
|
|
6
6
|
if (t.isCallExpression(path.node) && calls(path.node, ["calculate", "watch"], internal)) {
|
|
7
7
|
if (path.node.arguments.length !== 1) {
|
package/lib/mesh.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
|
-
import { calls, composeOnly } from "./call
|
|
3
|
-
import { ctx } from "./internal
|
|
4
|
-
import { bodyHasJsx } from "./jsx-detect
|
|
5
|
-
import { arrayModel, exprCall, forwardOnlyExpr, mapModel, own, parseCalculateCall, reactiveObject, ref, setModel, } from "./lib
|
|
6
|
-
import { transformJsx } from "./jsx
|
|
2
|
+
import { calls, composeOnly, styleOnly } from "./call";
|
|
3
|
+
import { ctx } from "./internal";
|
|
4
|
+
import { bodyHasJsx } from "./jsx-detect";
|
|
5
|
+
import { arrayModel, exprCall, forwardOnlyExpr, mapModel, own, parseCalculateCall, reactiveObject, ref, setModel, } from "./lib";
|
|
6
|
+
import { transformJsx } from "./jsx";
|
|
7
7
|
export function meshOrIgnoreAllExpressions(nodePaths, internal) {
|
|
8
8
|
for (const path of nodePaths) {
|
|
9
9
|
if (t.isExpression(path.node)) {
|
|
@@ -97,11 +97,20 @@ export function meshExpression(nodePath, internal) {
|
|
|
97
97
|
meshAllUnknown(path.get("elements"), internal);
|
|
98
98
|
break;
|
|
99
99
|
}
|
|
100
|
-
case "CallExpression":
|
|
100
|
+
case "CallExpression":
|
|
101
|
+
case "OptionalCallExpression": {
|
|
101
102
|
const path = nodePath;
|
|
102
103
|
const callsFn = calls(path.node, composeOnly, internal);
|
|
104
|
+
const callsStyleHint = calls(path.node, styleOnly, internal);
|
|
105
|
+
const callsStyleCreate = calls(path.node, ["webStyleSheet"], internal);
|
|
103
106
|
if (callsFn) {
|
|
104
|
-
throw path.buildCodeFrameError(`Vasille: Usage of
|
|
107
|
+
throw path.buildCodeFrameError(`Vasille: Usage of hint "${callsFn}" is restricted here`);
|
|
108
|
+
}
|
|
109
|
+
if (callsStyleHint) {
|
|
110
|
+
throw path.buildCodeFrameError(`Vasille: Usage of style hint "${callsStyleHint}" is restricted here`);
|
|
111
|
+
}
|
|
112
|
+
if (callsStyleCreate) {
|
|
113
|
+
throw path.buildCodeFrameError("Vasille: Styles can be created in moldule level code only");
|
|
105
114
|
}
|
|
106
115
|
meshOrIgnoreExpression(path.get("callee"), internal);
|
|
107
116
|
meshAllUnknown(path.get("arguments"), internal);
|
|
@@ -113,12 +122,6 @@ export function meshExpression(nodePath, internal) {
|
|
|
113
122
|
}
|
|
114
123
|
break;
|
|
115
124
|
}
|
|
116
|
-
case "OptionalCallExpression": {
|
|
117
|
-
const path = nodePath;
|
|
118
|
-
meshExpression(path.get("callee"), internal);
|
|
119
|
-
meshAllUnknown(path.get("arguments"), internal);
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
125
|
case "AssignmentExpression": {
|
|
123
126
|
const path = nodePath;
|
|
124
127
|
const left = path.node.left;
|