@stylexjs/babel-plugin 0.1.0-beta.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/.babelrc ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "assumptions": {
3
+ "iterableIsArray": true
4
+ },
5
+ "presets": [
6
+ "@babel/preset-typescript",
7
+ [
8
+ "@babel/preset-env",
9
+ {
10
+ "exclude": ["@babel/plugin-transform-typeof-symbol"],
11
+ "targets": "defaults"
12
+ }
13
+ ],
14
+ "@babel/preset-react"
15
+ ]
16
+ }
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ jest.autoMockOff();
11
+
12
+ const { parse } = require('@babel/parser');
13
+ const traverse = require('@babel/traverse').default;
14
+ const { evaluate } = require('../src/utils/evaluate-path');
15
+
16
+ function evaluateFirstStatement(code, functions) {
17
+ const ast = parse(code);
18
+ let result;
19
+ traverse(ast, {
20
+ Program(path) {
21
+ const statements = path.get('body');
22
+ const statement = statements[0];
23
+ if (!statement) {
24
+ return;
25
+ }
26
+ if (statement.isVariableDeclaration()) {
27
+ const valuePath = statement.get('declarations')[0].get('init');
28
+ result = evaluate(valuePath, functions);
29
+ } else {
30
+ result = evaluate(statement, functions);
31
+ }
32
+ },
33
+ });
34
+ if (result === undefined || result.confident === false) {
35
+ return { confident: false };
36
+ } else {
37
+ return result.value;
38
+ }
39
+ }
40
+
41
+ describe('custom path evaluation works as expected', () => {
42
+ test('Evaluates Primitive Value expressions', () => {
43
+ expect(evaluateFirstStatement('1 + 2', {})).toBe(3);
44
+ expect(evaluateFirstStatement('1 - 2', {})).toBe(-1);
45
+ expect(evaluateFirstStatement('1 * 2', {})).toBe(2);
46
+ expect(evaluateFirstStatement('1 / 2', {})).toBe(0.5);
47
+ expect(evaluateFirstStatement('1 % 2', {})).toBe(1);
48
+ expect(evaluateFirstStatement('1 ** 2', {})).toBe(1);
49
+ expect(evaluateFirstStatement('1 << 2', {})).toBe(4);
50
+ expect(evaluateFirstStatement('1 >> 2', {})).toBe(0);
51
+ expect(evaluateFirstStatement('1 & 2', {})).toBe(0);
52
+ expect(evaluateFirstStatement('1 | 2', {})).toBe(3);
53
+ expect(evaluateFirstStatement('1 ^ 2', {})).toBe(3);
54
+ expect(evaluateFirstStatement('1 && 2', {})).toBe(2);
55
+ expect(evaluateFirstStatement('1 || 2', {})).toBe(1);
56
+
57
+ expect(evaluateFirstStatement('null', {})).toBe(null);
58
+ expect(evaluateFirstStatement('undefined', {})).toBe(undefined);
59
+ expect(evaluateFirstStatement('true', {})).toBe(true);
60
+ expect(evaluateFirstStatement('false', {})).toBe(false);
61
+ expect(evaluateFirstStatement('let x = "hello";', {})).toBe('hello');
62
+ });
63
+ test('Evaluates Simple Arrays and Objects', () => {
64
+ expect(evaluateFirstStatement('const x = {};', {})).toEqual({});
65
+ expect(
66
+ evaluateFirstStatement('const x = {name: "Name", age: 43};', {})
67
+ ).toEqual({ name: 'Name', age: 43 });
68
+
69
+ expect(evaluateFirstStatement('const x = [];', {})).toEqual([]);
70
+ expect(evaluateFirstStatement('const x = [1, 2, 3];', {})).toEqual([
71
+ 1, 2, 3,
72
+ ]);
73
+ expect(evaluateFirstStatement('const x = [1, 2, 3, 4, 5];', {})).toEqual([
74
+ 1, 2, 3, 4, 5,
75
+ ]);
76
+ });
77
+ test('Evaluates Objects with spreads', () => {
78
+ expect(
79
+ evaluateFirstStatement(
80
+ 'const x = {name: "Name", ...({hero: true}), age: 43};',
81
+ {}
82
+ )
83
+ ).toEqual({ name: 'Name', hero: true, age: 43 });
84
+
85
+ expect(
86
+ evaluateFirstStatement(
87
+ 'const x = {name: "Name", ...({name: "StyleX", age: 1}), age: 43};',
88
+ {}
89
+ )
90
+ ).toEqual({ name: 'StyleX', age: 43 });
91
+ });
92
+
93
+ test('Evaluates built-in functions', () => {
94
+ expect(evaluateFirstStatement('const x = Math.max(1, 2, 3);', {})).toBe(3);
95
+ expect(evaluateFirstStatement('const x = Math.min(1, 2, 3);', {})).toBe(1);
96
+ });
97
+
98
+ test('Evaluates custom functions', () => {
99
+ function makeArray(...args) {
100
+ return [...args].reverse();
101
+ }
102
+
103
+ expect(
104
+ evaluateFirstStatement('const x = makeArray(1, 2, 3);', {
105
+ identifiers: {
106
+ makeArray: { fn: makeArray },
107
+ },
108
+ })
109
+ ).toEqual([3, 2, 1]);
110
+
111
+ expect(
112
+ evaluateFirstStatement('const x = stylex.makeArray(1, 2, 3);', {
113
+ memberExpressions: { stylex: { makeArray: { fn: makeArray } } },
114
+ })
115
+ ).toEqual([3, 2, 1]);
116
+ });
117
+
118
+ test('Evaluates custom functions that return non-static values', () => {
119
+ class MyClass {
120
+ constructor(value) {
121
+ this.value = value;
122
+ }
123
+ }
124
+ function makeClass(value) {
125
+ return new MyClass(value);
126
+ }
127
+
128
+ expect(
129
+ evaluateFirstStatement('const x = makeClass("Hello");', {
130
+ identifiers: { makeClass: { fn: makeClass } },
131
+ })
132
+ ).toEqual(new MyClass('Hello'));
133
+ });
134
+
135
+ test('Evaluates custom functions used as spread values', () => {
136
+ function makeObj(value) {
137
+ return { spreadValue: value };
138
+ }
139
+
140
+ expect(
141
+ evaluateFirstStatement(
142
+ 'const x = {name: "Name", ...makeObj("Hello"), age: 30};',
143
+ {
144
+ identifiers: {
145
+ makeObj: { fn: makeObj },
146
+ },
147
+ }
148
+ )
149
+ ).toEqual({ name: 'Name', spreadValue: 'Hello', age: 30 });
150
+ });
151
+
152
+ test('Evaluates custom functions that take paths', () => {
153
+ function getNode(path) {
154
+ const { type, value } = path.node;
155
+ return { type, value };
156
+ }
157
+
158
+ expect(
159
+ evaluateFirstStatement('const x = getNode("Hello");', {
160
+ identifiers: { getNode: { fn: getNode, takesPath: true } },
161
+ })
162
+ ).toEqual({ type: 'StringLiteral', value: 'Hello' });
163
+ });
164
+ });
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ 'use strict';
9
+
10
+ jest.autoMockOff();
11
+
12
+ const { transformSync } = require('@babel/core');
13
+ const stylexPlugin = require('../src/index');
14
+
15
+ function transform(source, opts = {}) {
16
+ return transformSync(source, {
17
+ filename: opts.filename,
18
+ parserOpts: {
19
+ flow: {
20
+ all: true,
21
+ },
22
+ },
23
+ plugins: [stylexPlugin, opts],
24
+ });
25
+ }
26
+
27
+ describe('@stylexjs/babel-plugin', () => {
28
+ describe('[metadata] plugin metadata', () => {
29
+ test('stylex metadata is correctly set', () => {
30
+ const output = transform(`
31
+ import stylex from 'stylex';
32
+ const styles = stylex.create({
33
+ foo: {
34
+ color: 'red',
35
+ height: 5,
36
+ ':hover': {
37
+ start: 10,
38
+ },
39
+ '@media (min-width: 1000px)': {
40
+ end: 5
41
+ }
42
+ },
43
+ });
44
+
45
+ const name = stylex.keyframes({
46
+ from: {
47
+ start: 0,
48
+ },
49
+ to: {
50
+ start: 100,
51
+ }
52
+ });
53
+ `);
54
+
55
+ expect(output.metadata).toMatchInlineSnapshot(`
56
+ {
57
+ "stylex": [
58
+ [
59
+ "x1e2nbdu",
60
+ {
61
+ "ltr": ".x1e2nbdu{color:red}",
62
+ "rtl": null,
63
+ },
64
+ 1,
65
+ ],
66
+ [
67
+ "x1ycjhwn",
68
+ {
69
+ "ltr": ".x1ycjhwn{height:5px}",
70
+ "rtl": null,
71
+ },
72
+ 1,
73
+ ],
74
+ [
75
+ "x15uk0yd",
76
+ {
77
+ "ltr": ".x15uk0yd:hover{left:10px}",
78
+ "rtl": ".x15uk0yd:hover{right:10px}",
79
+ },
80
+ 8,
81
+ ],
82
+ [
83
+ "x10tbbcl",
84
+ {
85
+ "ltr": "@media (min-width: 1000px){.x10tbbcl.x10tbbcl{right:5px}}",
86
+ "rtl": "@media (min-width: 1000px){.x10tbbcl.x10tbbcl{left:5px}}",
87
+ },
88
+ 2,
89
+ ],
90
+ [
91
+ "x18kvd1d-B",
92
+ {
93
+ "ltr": "@keyframes x18kvd1d-B{from{left:0;}to{left:100px;}}",
94
+ "rtl": "@keyframes x18kvd1d-B{from{right:0;}to{right:100px;}}",
95
+ },
96
+ 1,
97
+ ],
98
+ ],
99
+ }
100
+ `);
101
+ });
102
+ });
103
+ });