rollup-plugin-react-scoped-css 0.4.0 → 0.5.2

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.
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __read = (this && this.__read) || function (o, n) {
14
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
15
+ if (!m) return o;
16
+ var i = m.call(o), r, ar = [], e;
17
+ try {
18
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
19
+ }
20
+ catch (error) { e = { error: error }; }
21
+ finally {
22
+ try {
23
+ if (r && !r.done && (m = i["return"])) m.call(i);
24
+ }
25
+ finally { if (e) throw e.error; }
26
+ }
27
+ return ar;
28
+ };
29
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
30
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
31
+ if (ar || !(i in from)) {
32
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
33
+ ar[i] = from[i];
34
+ }
35
+ }
36
+ return to.concat(ar || Array.prototype.slice.call(from));
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.NewJsxParser = void 0;
40
+ var NewJsxParser = /** @class */ (function () {
41
+ function NewJsxParser() {
42
+ }
43
+ NewJsxParser.prototype.isNodeReactFragment = function (node) {
44
+ var _a, _b, _c, _d;
45
+ return ((_b = (_a = node.arguments) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.type) === "Identifier" &&
46
+ ['_Fragment', 'Fragment'].includes((_d = (_c = node.arguments) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.name);
47
+ };
48
+ NewJsxParser.prototype.isNodeReactElement = function (node) {
49
+ var _a;
50
+ return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' &&
51
+ ['_jsxDEV', '_jsx', '_jsxs', 'jsxDev', 'jsx', 'jsxs'].includes((_a = node === null || node === void 0 ? void 0 : node.callee) === null || _a === void 0 ? void 0 : _a.name);
52
+ };
53
+ NewJsxParser.prototype.extendNodeWithAttributes = function (node, attr) {
54
+ var _this = this;
55
+ var _a;
56
+ var arg = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[1];
57
+ return __assign(__assign({}, node), { arguments: node === null || node === void 0 ? void 0 : node.arguments.map(function (v, i) {
58
+ if (i === 1) {
59
+ if (v.type === 'ObjectExpression') {
60
+ return __assign(__assign({}, v), { properties: __spreadArray(__spreadArray([], __read(arg.properties), false), [
61
+ _this.createAttributeNode(attr)
62
+ ], false) });
63
+ }
64
+ else {
65
+ return {
66
+ type: 'ObjectExpression',
67
+ properties: [_this.createAttributeNode(attr)]
68
+ };
69
+ }
70
+ }
71
+ return v;
72
+ }) });
73
+ };
74
+ NewJsxParser.prototype.createAttributeNode = function (attr) {
75
+ return {
76
+ type: 'Property',
77
+ method: false,
78
+ shorthand: false,
79
+ computed: false,
80
+ key: {
81
+ type: 'Identifier',
82
+ name: "\"".concat(attr, "\"")
83
+ },
84
+ value: {
85
+ type: 'Literal',
86
+ value: true,
87
+ raw: "true"
88
+ },
89
+ kind: 'init'
90
+ };
91
+ };
92
+ return NewJsxParser;
93
+ }());
94
+ exports.NewJsxParser = NewJsxParser;
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "rollup-plugin-react-scoped-css",
3
- "version": "0.4.0",
3
+ "version": "0.5.2",
4
4
  "description": "A rollup plugin designed to allow scoped css to be run in react (Compatible with vite and rollup)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tsc",
9
9
  "build:watch": "tsc --watch",
10
- "prepare": "npm run build && npm test",
11
10
  "test": "jest"
12
11
  },
13
12
  "repository": {
@@ -42,9 +41,16 @@
42
41
  "devDependencies": {
43
42
  "@babel/preset-env": "^7.15.0",
44
43
  "@babel/preset-typescript": "^7.15.0",
44
+ "@semantic-release/commit-analyzer": "^9.0.2",
45
+ "@semantic-release/git": "^10.0.1",
46
+ "@semantic-release/github": "^8.0.2",
47
+ "@semantic-release/npm": "^8.0.3",
48
+ "@semantic-release/release-notes-generator": "^10.0.3",
45
49
  "@types/escodegen": "0.0.7",
46
50
  "@types/estree": "0.0.50",
47
51
  "@types/jest": "^27.0.1",
48
- "jest": "^27.0.6"
52
+ "acorn": "^8.6.0",
53
+ "jest": "^27.0.6",
54
+ "semantic-release": "^18.0.1"
49
55
  }
50
56
  }
@@ -0,0 +1,101 @@
1
+ import {
2
+ j as jsxRuntime,
3
+ r as react,
4
+ R as ReactDOM,
5
+ a as React
6
+ } from "./vendor.1137a3d7.js";
7
+ var index = "body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n monospace;\n}\n";
8
+ var App$1 = ".sub {\n color: green;\n}";
9
+ var App_scoped = ".App {\n text-align: center;\n}\n\n.sub {\n color: blue !important;\n}\n\n.App-logo {\n height: 40vmin;\n pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .App-logo {\n animation: App-logo-spin infinite 20s linear;\n }\n}\n\n.App-header {\n background-color: #282c34;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: white;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\nbutton {\n font-size: calc(10px + 2vmin);\n}\n";
10
+ var logo = "/assets/logo.ecc203fb.svg";
11
+ var Sub_scoped = ".sub {\n color: red;\n}\n.sub__test {\n margin: 0;\n}\n.sub h2 {\n font-weight: 300;\n font-size: 3rem;\n}\n\nh2 {\n font-size: 10rem;\n}\n\n.drawer {\n width: 400px;\n}\n.drawer__list-item {\n padding: 0;\n}\n.drawer__list-item-icon {\n margin-right: 1rem;\n}\n.drawer__link {\n display: flex;\n width: 300px;\n padding: 1rem;\n align-items: center;\n text-decoration: none;\n border: 0;\n outline: 0;\n background: transparent;\n font-family: \"Quicksand\", \"Roboto\", sans-serif;\n font-size: 1rem;\n font-weight: 400;\n}\n.drawer__link:hover {\n background-color: #fafafa;\n}";
12
+ const jsx = jsxRuntime.exports.jsx;
13
+ const jsxs = jsxRuntime.exports.jsxs;
14
+ const Fragment = jsxRuntime.exports.Fragment;
15
+ function Sub() {
16
+ return jsx("div", {
17
+ className: "sub",
18
+ children: jsx("h2", {
19
+ children: "Sub",
20
+ "data-v-123456": true
21
+ }),
22
+ "data-v-123456": true
23
+ });
24
+ }
25
+ function App() {
26
+ const [count, setCount] = react.exports.useState(0);
27
+ return jsx(Fragment, {
28
+ children: jsxs("div", {
29
+ className: "App",
30
+ children: [
31
+ jsxs("header", {
32
+ className: "App-header",
33
+ children: [
34
+ jsx("img", {
35
+ src: logo,
36
+ className: "App-logo",
37
+ alt: "logo",
38
+ "data-v-123456": true
39
+ }),
40
+ jsx("p", {
41
+ children: "Hello Vite + React!",
42
+ "data-v-123456": true
43
+ }),
44
+ jsx("p", {
45
+ children: jsxs("button", {
46
+ type: "button",
47
+ onClick: () => setCount(count2 => count2 + 1),
48
+ children: [
49
+ "count is: ",
50
+ count
51
+ ],
52
+ "data-v-123456": true
53
+ }),
54
+ "data-v-123456": true
55
+ }),
56
+ jsxs("p", {
57
+ children: [
58
+ "Edit ",
59
+ jsx("code", {
60
+ children: "App.jsx",
61
+ "data-v-123456": true
62
+ }),
63
+ " and save to test HMR updates."
64
+ ],
65
+ "data-v-123456": true
66
+ }),
67
+ jsxs("p", {
68
+ children: [
69
+ jsx("a", {
70
+ className: "App-link",
71
+ href: "https://reactjs.org",
72
+ target: "_blank",
73
+ rel: "noopener noreferrer",
74
+ children: "Learn React",
75
+ "data-v-123456": true
76
+ }),
77
+ " | ",
78
+ jsx("a", {
79
+ className: "App-link",
80
+ href: "https://vitejs.dev/guide/features.html",
81
+ target: "_blank",
82
+ rel: "noopener noreferrer",
83
+ children: "Vite Docs",
84
+ "data-v-123456": true
85
+ })
86
+ ],
87
+ "data-v-123456": true
88
+ })
89
+ ],
90
+ "data-v-123456": true
91
+ }),
92
+ jsx(Fragment, { children: jsx(Sub, { "data-v-123456": true }) })
93
+ ],
94
+ "data-v-123456": true
95
+ })
96
+ });
97
+ }
98
+ ReactDOM.render(jsx(React.StrictMode, {
99
+ children: jsx(App, { "data-v-123456": true }),
100
+ "data-v-123456": true
101
+ }), document.getElementById("root"));
@@ -0,0 +1,64 @@
1
+ import { j as jsxRuntime, r as react, R as ReactDOM, a as React } from "./vendor.1137a3d7.js";
2
+ var index = "body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n monospace;\n}\n";
3
+ var App$1 = ".sub {\n color: green;\n}";
4
+ var App_scoped = ".App {\n text-align: center;\n}\n\n.sub {\n color: blue !important;\n}\n\n.App-logo {\n height: 40vmin;\n pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .App-logo {\n animation: App-logo-spin infinite 20s linear;\n }\n}\n\n.App-header {\n background-color: #282c34;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: white;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\nbutton {\n font-size: calc(10px + 2vmin);\n}\n";
5
+ var logo = "/assets/logo.ecc203fb.svg";
6
+ var Sub_scoped = '.sub {\n color: red;\n}\n.sub__test {\n margin: 0;\n}\n.sub h2 {\n font-weight: 300;\n font-size: 3rem;\n}\n\nh2 {\n font-size: 10rem;\n}\n\n.drawer {\n width: 400px;\n}\n.drawer__list-item {\n padding: 0;\n}\n.drawer__list-item-icon {\n margin-right: 1rem;\n}\n.drawer__link {\n display: flex;\n width: 300px;\n padding: 1rem;\n align-items: center;\n text-decoration: none;\n border: 0;\n outline: 0;\n background: transparent;\n font-family: "Quicksand", "Roboto", sans-serif;\n font-size: 1rem;\n font-weight: 400;\n}\n.drawer__link:hover {\n background-color: #fafafa;\n}';
7
+ const jsx = jsxRuntime.exports.jsx;
8
+ const jsxs = jsxRuntime.exports.jsxs;
9
+ const Fragment = jsxRuntime.exports.Fragment;
10
+ function Sub() {
11
+ return /* @__PURE__ */ jsx("div", {
12
+ className: "sub",
13
+ children: /* @__PURE__ */ jsx("h2", {
14
+ children: "Sub"
15
+ })
16
+ });
17
+ }
18
+ function App() {
19
+ const [count, setCount] = react.exports.useState(0);
20
+ return /* @__PURE__ */ jsx(Fragment, {
21
+ children: /* @__PURE__ */ jsxs("div", {
22
+ className: "App",
23
+ children: [/* @__PURE__ */ jsxs("header", {
24
+ className: "App-header",
25
+ children: [/* @__PURE__ */ jsx("img", {
26
+ src: logo,
27
+ className: "App-logo",
28
+ alt: "logo"
29
+ }), /* @__PURE__ */ jsx("p", {
30
+ children: "Hello Vite + React!"
31
+ }), /* @__PURE__ */ jsx("p", {
32
+ children: /* @__PURE__ */ jsxs("button", {
33
+ type: "button",
34
+ onClick: () => setCount((count2) => count2 + 1),
35
+ children: ["count is: ", count]
36
+ })
37
+ }), /* @__PURE__ */ jsxs("p", {
38
+ children: ["Edit ", /* @__PURE__ */ jsx("code", {
39
+ children: "App.jsx"
40
+ }), " and save to test HMR updates."]
41
+ }), /* @__PURE__ */ jsxs("p", {
42
+ children: [/* @__PURE__ */ jsx("a", {
43
+ className: "App-link",
44
+ href: "https://reactjs.org",
45
+ target: "_blank",
46
+ rel: "noopener noreferrer",
47
+ children: "Learn React"
48
+ }), " | ", /* @__PURE__ */ jsx("a", {
49
+ className: "App-link",
50
+ href: "https://vitejs.dev/guide/features.html",
51
+ target: "_blank",
52
+ rel: "noopener noreferrer",
53
+ children: "Vite Docs"
54
+ })]
55
+ })]
56
+ }), /* @__PURE__ */ jsx(Fragment, {
57
+ children: /* @__PURE__ */ jsx(Sub, {})
58
+ })]
59
+ })
60
+ });
61
+ }
62
+ ReactDOM.render(/* @__PURE__ */ jsx(React.StrictMode, {
63
+ children: /* @__PURE__ */ jsx(App, {})
64
+ }), document.getElementById("root"));
@@ -0,0 +1,4 @@
1
+ let array = [1, 2, 3];
2
+
3
+ const multiply = (arr) => arr.map(x => x * 2);
4
+ const newArray = multiply(array);
@@ -0,0 +1,19 @@
1
+ import { readFile } from "fs/promises";
2
+ import { resolve } from "path";
3
+ import { parse } from "acorn";
4
+ import { astIterator } from "./ast-iterator";
5
+
6
+ describe('astIterator', () => {
7
+ it('should iterate through all nodes', async () => {
8
+ let iterationCount = 0;
9
+ const file = await readFile(resolve(__dirname, './__mocks__/sample-code-file.js'), { encoding: 'utf-8' })
10
+ const ast = parse(file, { sourceType: 'module', ecmaVersion: 2022 });
11
+
12
+ for (const node of astIterator(ast)) {
13
+ iterationCount++;
14
+ expect(node).toBeTruthy();
15
+ }
16
+
17
+ expect(iterationCount).toBe(28);
18
+ });
19
+ })
@@ -0,0 +1,27 @@
1
+
2
+ const isNode = (obj: any) => {
3
+ return typeof obj === 'object' &&
4
+ typeof (obj as any)?.end === 'number' &&
5
+ typeof (obj as any)?.start === 'number' &&
6
+ typeof (obj as any)?.type === 'string'
7
+ }
8
+
9
+ export const astIterator = function* (ast: any): IterableIterator<any> {
10
+ if (!ast) { return }
11
+
12
+ for (let key of Object.keys(ast)) {
13
+ // Skip useless keys
14
+ if (['end', 'start', 'type'].includes(key)) { continue; }
15
+
16
+ // If key value is an array, iterate over it
17
+ if (Array.isArray(ast[key])) {
18
+ for (let nodeIndex in ast[key]) {
19
+ yield *astIterator(ast[key][nodeIndex])
20
+ }
21
+ } else if(isNode(ast[key])) {
22
+ yield *astIterator(ast[key])
23
+ }
24
+ }
25
+
26
+ yield ast
27
+ }
@@ -0,0 +1,20 @@
1
+ import { readFile } from "fs/promises";
2
+ import { resolve } from "path";
3
+ import { parse } from "acorn";
4
+ import { astTransformer } from "./ast-transformer";
5
+
6
+ describe('astTransformer', () => {
7
+ it('should iterate through all nodes', async () => {
8
+ let iterationCount = 0;
9
+ const file = await readFile(resolve(__dirname, './__mocks__/sample-code-file.js'), { encoding: 'utf-8' })
10
+ const ast = parse(file, { sourceType: 'module', ecmaVersion: 2022 });
11
+
12
+ const newAst = astTransformer(ast, (node) => {
13
+ iterationCount++;
14
+ expect(node).toBeTruthy();
15
+ })
16
+
17
+ expect(newAst).toBeDefined();
18
+ expect(iterationCount).toBe(28);
19
+ });
20
+ })
@@ -0,0 +1,24 @@
1
+ const isNode = (obj: any) => {
2
+ return typeof obj === 'object' &&
3
+ typeof (obj as any)?.end === 'number' &&
4
+ typeof (obj as any)?.start === 'number' &&
5
+ typeof (obj as any)?.type === 'string'
6
+ }
7
+
8
+ export const astTransformer = (ast: any, callback: Function) => {
9
+ for (let key of Object.keys(ast)) {
10
+ if (['end', 'start', 'type'].includes(key)) { continue; }
11
+
12
+ if (Array.isArray(ast[key])) {
13
+ for (let nodeIndex in ast[key]) {
14
+ ast[key][nodeIndex] = astTransformer(ast[key][nodeIndex], callback)
15
+ }
16
+ } else if(isNode(ast[key])) {
17
+ ast[key] = astTransformer(ast[key], callback)
18
+ }
19
+ }
20
+
21
+ const result = callback(ast);
22
+
23
+ return typeof result !== 'undefined' ? result : ast
24
+ }
@@ -5,18 +5,42 @@ import { generate } from 'escodegen'
5
5
  import { addHashAttributesToJsxTagsAst } from './ast.utils'
6
6
 
7
7
  describe('AST Utils', () => {
8
- it('Should add the attr to the right elements', async () => {
9
- const compiled = await readFile(resolve(__dirname, './__mocks__/compiled-jsx.js'), { encoding: 'utf-8' })
10
- const compiledWithAttr = await readFile(resolve(__dirname, './__mocks__/compiled-jsx-with-attr.js'), { encoding: 'utf-8' })
11
- const ast = parse(compiled, { ecmaVersion: 2021, sourceType: "module" })
12
- const modifiedAst = addHashAttributesToJsxTagsAst(ast, 'data-v-123456')
13
- const modifiedCompiled = generate(modifiedAst, { format: {
14
- indent: {
15
- style: ' ',
16
- },
17
- quotes: 'double',
18
- } })
8
+ beforeEach(() => {
9
+ global.implementation = null
10
+ })
19
11
 
20
- expect(modifiedCompiled).toEqual(compiledWithAttr)
12
+ describe('classic implementation', () => {
13
+ it('Should add the attr to the right elements', async () => {
14
+ const compiled = await readFile(resolve(__dirname, './__mocks__/classic-compiled-jsx.js'), { encoding: 'utf-8' })
15
+ const compiledWithAttr = await readFile(resolve(__dirname, './__mocks__/classic-compiled-jsx-with-attr.js'), { encoding: 'utf-8' })
16
+ const ast = parse(compiled, { ecmaVersion: 2021, sourceType: "module" })
17
+ const modifiedAst = addHashAttributesToJsxTagsAst(ast, 'data-v-123456')
18
+ const modifiedCompiled = generate(modifiedAst, { format: {
19
+ indent: {
20
+ style: ' ',
21
+ },
22
+ quotes: 'double',
23
+ } })
24
+
25
+ expect(modifiedCompiled).toEqual(compiledWithAttr)
26
+ })
27
+ })
28
+
29
+ describe('new implementation', () => {
30
+ it('Should add the attr to the right elements', async () => {
31
+ const compiled = await readFile(resolve(__dirname, './__mocks__/new-compiled-jsx.js'), { encoding: 'utf-8' })
32
+ const compiledWithAttr = await readFile(resolve(__dirname, './__mocks__/new-compiled-jsx-with-attr.js'), { encoding: 'utf-8' })
33
+ const ast = parse(compiled, { ecmaVersion: 2021, sourceType: "module" })
34
+ const modifiedAst = addHashAttributesToJsxTagsAst(ast, 'data-v-123456')
35
+ const modifiedCompiled = generate(modifiedAst, { format: {
36
+ indent: {
37
+ style: ' ',
38
+ },
39
+ quotes: 'double',
40
+ } })
41
+
42
+ expect(modifiedCompiled).toEqual(compiledWithAttr)
43
+ })
21
44
  })
45
+
22
46
  })
package/src/ast.utils.ts CHANGED
@@ -1,111 +1,52 @@
1
- /**
2
- * Traverses the AST tree and calls callback for each node.
3
- * -
4
- * @param ast The ast tree
5
- * @param callback Callback function to be called for each node
6
- * @returns
7
- */
8
- function traverse(ast: any, callback: Function) {
9
- for (let key of Object.keys(ast)) {
10
- if (['end', 'start', 'type'].includes(key)) { continue; }
1
+ import { astIterator } from "./ast-iterator"
2
+ import { astTransformer } from "./ast-transformer"
3
+ import { ClassicJsxParser } from "./parsers/classic-parser"
4
+ import { JsxParser, ParserImplementations } from "./parsers/jsx-parser.model"
5
+ import { NewJsxParser } from "./parsers/new-parser"
11
6
 
12
- if (Array.isArray(ast[key])) {
13
- for (let nodeIndex in ast[key]) {
14
- ast[key][nodeIndex] = traverse(ast[key][nodeIndex], callback)
15
- }
16
- } else if(isNode(ast[key])) {
17
- ast[key] = traverse(ast[key], callback)
18
- }
19
- }
20
-
21
- const result = callback(ast);
22
-
23
- return typeof result !== 'undefined' ? result : ast
7
+ declare global {
8
+ var implementation: null | ParserImplementations
24
9
  }
25
10
 
26
- function isNode(obj: unknown) {
27
- return typeof obj === 'object' &&
28
- typeof (obj as any)?.end === 'number' &&
29
- typeof (obj as any)?.start === 'number' &&
30
- typeof (obj as any)?.type === 'string'
31
- }
11
+ global.implementation = null
32
12
 
33
- function isElementWithOldJsxTransform(node: any) {
34
- return node?.type === 'CallExpression' &&
35
- node?.callee?.object?.name === 'React' &&
36
- node?.callee?.property?.name === 'createElement'
37
- }
13
+ const classicParser = new ClassicJsxParser()
14
+ const newParser = new NewJsxParser()
38
15
 
39
- function isElementWithNewJsxTransform(node: any) {
40
- return node?.type === 'CallExpression' &&
41
- ['_jsxDEV', '_jsx'].includes(node?.callee?.name)
42
- }
16
+ let parser: JsxParser = classicParser;
43
17
 
44
- function isFragmentWithOldJsxTransform(node: any) {
45
- return node?.arguments?.[0]?.object?.name === "React" &&
46
- node?.arguments?.[0]?.property?.name === "Fragment"
47
- }
18
+ const findImplementation = (program: any) => {
19
+ let implementation: ParserImplementations = ParserImplementations.classic;
20
+ for (let node of astIterator(program)) {
21
+ if (node.type !== 'ImportDeclaration') {
22
+ continue;
23
+ }
48
24
 
49
- function isFragmentWithNewJsxTransform(node: any) {
50
- return node.arguments?.[0]?.type === "Identifier" &&
51
- node.arguments?.[0]?.name === "_Fragment"
25
+ if (
26
+ node.specifiers.some((n: any) =>
27
+ ['_jsxDEV', 'jsxRuntime'].includes(n.local.name))
28
+ || ['react/jsx-dev-runtime', 'react/jsx-runtime'].includes(node.source.value)
29
+ ) {
30
+ return ParserImplementations.new
31
+ }
32
+ }
33
+ return implementation
52
34
  }
53
35
 
54
- function isFragment(node: any) {
55
- return isFragmentWithOldJsxTransform(node) ||
56
- isFragmentWithNewJsxTransform(node)
57
- }
36
+ export function addHashAttributesToJsxTagsAst(program: any, attr: string) {
58
37
 
59
- function isReactElement(node: any) {
60
- return isElementWithOldJsxTransform(node) ||
61
- isElementWithNewJsxTransform(node)
62
- }
38
+ // Once in the program, we can determine which parser to use
39
+ if (global.implementation === null) {
40
+ global.implementation = findImplementation(program)
63
41
 
64
- function createAttributeNode(attr: string) {
65
- return {
66
- type: 'Property',
67
- method: false,
68
- shorthand: false,
69
- computed: false,
70
- key: {
71
- type: 'Identifier',
72
- name: `"${attr}"`
73
- },
74
- value: {
75
- type: 'Literal',
76
- value: true,
77
- raw: "true"
78
- },
79
- kind: 'init'
42
+ if (global.implementation === ParserImplementations.new) {
43
+ parser = newParser
44
+ }
80
45
  }
81
- }
82
46
 
83
- export function addHashAttributesToJsxTagsAst(program: any, attr: string) {
84
- return traverse(program, (node: any) => {
85
- if (isReactElement(node) && !isFragment(node)) {
86
- const arg = node?.arguments?.[1]
87
- return {
88
- ...node,
89
- arguments: node?.arguments.map((v: any, i: number) => {
90
- if (i === 1) {
91
- if (v.type === 'ObjectExpression') {
92
- return {
93
- ...v,
94
- properties: [
95
- ...arg.properties,
96
- createAttributeNode(attr)
97
- ]
98
- }
99
- } else {
100
- return {
101
- type: 'ObjectExpression',
102
- properties: [createAttributeNode(attr)]
103
- }
104
- }
105
- }
106
- return v
107
- })
108
- }
47
+ return astTransformer(program, (node: any) => {
48
+ if (parser.isNodeReactElement(node) && !parser.isNodeReactFragment(node)) {
49
+ return parser.extendNodeWithAttributes(node, attr)
109
50
  }
110
51
  })
111
52
  }
package/src/index.ts CHANGED
@@ -126,7 +126,6 @@ export default function reactScopedCssPlugin(optionsIn: ReactScopedCssPluginOpti
126
126
  if (!filter(id)) {
127
127
  return;
128
128
  }
129
-
130
129
  if (scopedCssInFileRegex.test(code)) {
131
130
  const importerHash = generateHash(id);
132
131
  const program = this.parse(code)