rollup-plugin-react-scoped-css 0.5.2 → 0.6.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/.eslintrc.yml ADDED
@@ -0,0 +1,29 @@
1
+ env:
2
+ browser: true
3
+ es2021: true
4
+ extends:
5
+ - eslint:recommended
6
+ - plugin:@typescript-eslint/eslint-recommended
7
+ - plugin:@typescript-eslint/recommended
8
+ - plugin:react/recommended
9
+ - plugin:prettier/recommended
10
+ - plugin:react/jsx-runtime
11
+ parser: '@typescript-eslint/parser'
12
+ parserOptions:
13
+ ecmaFeatures:
14
+ jsx: true
15
+ ecmaVersion: "latest"
16
+ sourceType: module
17
+ plugins:
18
+ - react
19
+ - '@typescript-eslint'
20
+ settings:
21
+ react:
22
+ version: "detect"
23
+ ignorePatterns:
24
+ - "**/node_modules/**"
25
+ - "**/__mocks__/**/*.js"
26
+ - "**/dist/**"
27
+ rules: {
28
+ "react/jsx-filename-extension": [1, { "extensions": [".jsx", ".tsx"] }]
29
+ }
@@ -16,4 +16,5 @@ jobs:
16
16
  cache: 'npm'
17
17
  - run: npm ci
18
18
  - run: npm run build --if-present
19
- - run: npm test
19
+ - run: npm test
20
+ - run: npm run lint
@@ -0,0 +1,8 @@
1
+ {
2
+ "editor.codeActionsOnSave": {
3
+ "source.fixAll.eslint": true,
4
+ "source.fixAll": false
5
+ },
6
+ "editor.formatOnSave": false,
7
+ "editor.defaultFormatter": "dbaeumer.vscode-eslint"
8
+ }
package/README.md CHANGED
@@ -25,19 +25,44 @@ export default function Sub() {
25
25
  h1 { color: red; }
26
26
  }
27
27
  ```
28
-
29
28
  And just like that the styles will be scoped to the component.
30
29
 
30
+ ## Technicality
31
+ since this plugin uses the engine of vue to scope the css to the components, the following sections come straight from the [vue documentation](https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors).
32
+
33
+ ### Deep selector
34
+ If you want a selector in scoped styles to be "deep", i.e. affecting child components, you can use the >>> combinator:
35
+ ```css
36
+ .a >>> .b { /* ... */ }
37
+ ```
38
+ The above will be compiled into:
39
+ ```css
40
+ .a[data-v-f3f3eg9] .b { /* ... */ }
41
+ ```
42
+ Some pre-processors, such as Sass, may not be able to parse >>> properly. In those cases you can use the /deep/ or ::v-deep combinator instead - both are aliases for >>> and work exactly the same. Based on the example above these two expressions will be compiled to the same output:
43
+ ```scss
44
+ .a::v-deep .b { /* ... */ }
45
+ /* or */
46
+ .a /deep/ .b { /* ... */ }
47
+ ```
48
+ ### Dynamically Generated Content
49
+ DOM content created with dangerouslySetInnerHTML are not affected by scoped styles, but you can still style them using deep selectors.
50
+
51
+ ### Also Keep in Mind
52
+ Scoped styles do not eliminate the need for classes. Due to the way browsers render various CSS selectors, p { color: red } will be many times slower when scoped (i.e. when combined with an attribute selector). If you use classes or ids instead, such as in .example { color: red }, then you virtually eliminate that performance hit.
53
+
54
+ Be careful with descendant selectors in recursive components! For a CSS rule with the selector .a .b, if the element that matches .a contains a recursive child component, then all .b in that child component will be matched by the rule.
55
+
31
56
  ## How to install
32
57
 
33
58
  ```sh
34
- npm i rollup-plugin-react-scoped-css
59
+ $ npm i rollup-plugin-react-scoped-css
35
60
  ```
36
61
 
37
62
  ### Simple Configuration
38
63
 
39
64
  in vite:
40
- ```
65
+ ```js
41
66
  // vite.config.js
42
67
  import { defineConfig } from 'vite'
43
68
  import reactRefresh from '@vitejs/plugin-react-refresh'
@@ -50,7 +75,7 @@ export default defineConfig({
50
75
  ```
51
76
 
52
77
  in rollup:
53
- ```
78
+ ```js
54
79
  // rollup.config.js
55
80
  import reactScopedCssPlugin from 'rollup-plugin-react-scoped-css';
56
81
 
@@ -63,7 +88,7 @@ export default {
63
88
 
64
89
  ### Customizing the plugin
65
90
  There are a few options available to customize how the plugin works
66
- ```
91
+ ```ts
67
92
  {
68
93
  /**
69
94
  * Which files should be included and parsed by the plugin
@@ -107,7 +132,7 @@ There are a few options available to customize how the plugin works
107
132
  ### With other rollup plugins
108
133
  Since this plugin works in two parts, you might need to expose the first part, then add any other plugin, and then expose the second part of the plugin. This part is automatically handled with vite thanks to the enforce attribute.
109
134
 
110
- ```
135
+ ```js
111
136
  const reactScopedPlugins = reactScopedCssPlugin()
112
137
  export default {
113
138
  //...
package/babel.config.js CHANGED
@@ -1,3 +1,7 @@
1
+ // eslint-disable-next-line no-undef
1
2
  module.exports = {
2
- presets: [['@babel/preset-env', {targets: {node: 'current'}}],'@babel/preset-typescript'],
3
- };
3
+ presets: [
4
+ ["@babel/preset-env", { targets: { node: "current" } }],
5
+ "@babel/preset-typescript",
6
+ ],
7
+ };
@@ -41,10 +41,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
41
41
  exports.astIterator = void 0;
42
42
  var isNode = function (obj) {
43
43
  var _a, _b, _c;
44
- return typeof obj === 'object' &&
45
- typeof ((_a = obj) === null || _a === void 0 ? void 0 : _a.end) === 'number' &&
46
- typeof ((_b = obj) === null || _b === void 0 ? void 0 : _b.start) === 'number' &&
47
- typeof ((_c = obj) === null || _c === void 0 ? void 0 : _c.type) === 'string';
44
+ return (typeof obj === "object" &&
45
+ typeof ((_a = obj) === null || _a === void 0 ? void 0 : _a.end) === "number" &&
46
+ typeof ((_b = obj) === null || _b === void 0 ? void 0 : _b.start) === "number" &&
47
+ typeof ((_c = obj) === null || _c === void 0 ? void 0 : _c.type) === "string");
48
48
  };
49
49
  var astIterator = function (ast) {
50
50
  var _a, _b, key, _c, _d, _i, nodeIndex, e_1_1;
@@ -64,7 +64,7 @@ var astIterator = function (ast) {
64
64
  if (!!_b.done) return [3 /*break*/, 10];
65
65
  key = _b.value;
66
66
  // Skip useless keys
67
- if (['end', 'start', 'type'].includes(key)) {
67
+ if (["end", "start", "type"].includes(key)) {
68
68
  return [3 /*break*/, 9];
69
69
  }
70
70
  if (!Array.isArray(ast[key])) return [3 /*break*/, 7];
@@ -1 +1 @@
1
- export declare const astTransformer: (ast: any, callback: Function) => any;
1
+ export declare const astTransformer: (ast: any, callback: (ast: any) => any) => any;
@@ -14,17 +14,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.astTransformer = void 0;
15
15
  var isNode = function (obj) {
16
16
  var _a, _b, _c;
17
- return typeof obj === 'object' &&
18
- typeof ((_a = obj) === null || _a === void 0 ? void 0 : _a.end) === 'number' &&
19
- typeof ((_b = obj) === null || _b === void 0 ? void 0 : _b.start) === 'number' &&
20
- typeof ((_c = obj) === null || _c === void 0 ? void 0 : _c.type) === 'string';
17
+ return (typeof obj === "object" &&
18
+ typeof ((_a = obj) === null || _a === void 0 ? void 0 : _a.end) === "number" &&
19
+ typeof ((_b = obj) === null || _b === void 0 ? void 0 : _b.start) === "number" &&
20
+ typeof ((_c = obj) === null || _c === void 0 ? void 0 : _c.type) === "string");
21
21
  };
22
22
  var astTransformer = function (ast, callback) {
23
23
  var e_1, _a;
24
24
  try {
25
25
  for (var _b = __values(Object.keys(ast)), _c = _b.next(); !_c.done; _c = _b.next()) {
26
26
  var key = _c.value;
27
- if (['end', 'start', 'type'].includes(key)) {
27
+ if (["end", "start", "type"].includes(key)) {
28
28
  continue;
29
29
  }
30
30
  if (Array.isArray(ast[key])) {
@@ -45,6 +45,6 @@ var astTransformer = function (ast, callback) {
45
45
  finally { if (e_1) throw e_1.error; }
46
46
  }
47
47
  var result = callback(ast);
48
- return typeof result !== 'undefined' ? result : ast;
48
+ return typeof result !== "undefined" ? result : ast;
49
49
  };
50
50
  exports.astTransformer = astTransformer;
package/dist/ast.utils.js CHANGED
@@ -27,13 +27,13 @@ var findImplementation = function (program) {
27
27
  try {
28
28
  for (var _b = __values((0, ast_iterator_1.astIterator)(program)), _c = _b.next(); !_c.done; _c = _b.next()) {
29
29
  var node = _c.value;
30
- if (node.type !== 'ImportDeclaration') {
30
+ if (node.type !== "ImportDeclaration") {
31
31
  continue;
32
32
  }
33
33
  if (node.specifiers.some(function (n) {
34
- return ['_jsxDEV', 'jsxRuntime'].includes(n.local.name);
35
- })
36
- || ['react/jsx-dev-runtime', 'react/jsx-runtime'].includes(node.source.value)) {
34
+ return ["_jsxDEV", "jsxRuntime"].includes(n.local.name);
35
+ }) ||
36
+ ["react/jsx-dev-runtime", "react/jsx-runtime"].includes(node.source.value)) {
37
37
  return jsx_parser_model_1.ParserImplementations.new;
38
38
  }
39
39
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { FilterPattern } from '@rollup/pluginutils';
2
- import type { Plugin } from 'rollup';
1
+ import { FilterPattern } from "@rollup/pluginutils";
2
+ import type { Plugin } from "rollup";
3
3
  export interface ReactScopedCssPluginOptions {
4
4
  /**
5
5
  * Which files should be included and parsed by the plugin
package/dist/index.js CHANGED
@@ -30,6 +30,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
30
30
  return result;
31
31
  };
32
32
  Object.defineProperty(exports, "__esModule", { value: true });
33
+ /* eslint-disable no-useless-escape */
33
34
  var path = __importStar(require("path"));
34
35
  var js_xxhash_1 = require("js-xxhash");
35
36
  var pluginutils_1 = require("@rollup/pluginutils");
@@ -37,17 +38,17 @@ var component_compiler_utils_1 = require("@vue/component-compiler-utils");
37
38
  var escodegen_1 = require("escodegen");
38
39
  var ast_utils_1 = require("./ast.utils");
39
40
  var getFilenameFromPath = function (filePath) {
40
- var parts = filePath.split('/');
41
- return parts[parts.length - 1].split('?')[0];
41
+ var parts = filePath.split("/");
42
+ return parts[parts.length - 1].split("?")[0];
42
43
  };
43
44
  var getHashFromPath = function (filePath) {
44
- var search = '?scope=';
45
+ var search = "?scope=";
45
46
  var hash = filePath.slice(filePath.indexOf(search) + search.length);
46
47
  return hash;
47
48
  };
48
49
  var generateHash = function (input, seed) {
49
50
  if (seed === void 0) { seed = 0; }
50
- var hashNum = (0, js_xxhash_1.xxHash32)(Buffer.from(input, 'utf8'), seed);
51
+ var hashNum = (0, js_xxhash_1.xxHash32)(Buffer.from(input, "utf8"), seed);
51
52
  return hashNum.toString(16);
52
53
  };
53
54
  var addAttributesToCss = function (src, fileName, hash) {
@@ -62,24 +63,24 @@ var addAttributesToCss = function (src, fileName, hash) {
62
63
  };
63
64
  function reactScopedCssPlugin(optionsIn) {
64
65
  if (optionsIn === void 0) { optionsIn = {}; }
65
- var options = __assign({ hashPrefix: 'v', styleFileSuffix: 'scoped', styleFileExtensions: ['scss', 'css', 'sass', 'less'], jsxFileExtensions: ['jsx', 'tsx'] }, optionsIn);
66
+ var options = __assign({ hashPrefix: "v", styleFileSuffix: "scoped", styleFileExtensions: ["scss", "css", "sass", "less"], jsxFileExtensions: ["jsx", "tsx"] }, optionsIn);
66
67
  if (!options.styleFileExtensions || !options.styleFileExtensions.length) {
67
- throw new Error('You need to provide at least one style file extension');
68
+ throw new Error("You need to provide at least one style file extension");
68
69
  }
69
70
  if (!options.jsxFileExtensions || !options.jsxFileExtensions.length) {
70
- throw new Error('You need to provide at least one jsx file extension');
71
+ throw new Error("You need to provide at least one jsx file extension");
71
72
  }
72
73
  var filter = (0, pluginutils_1.createFilter)(options.include, options.exclude);
73
74
  var scopedCssRegex = options.styleFileSuffix
74
- ? new RegExp(".".concat(options.styleFileSuffix, ".(").concat(options.styleFileExtensions.join('|'), ")$"))
75
- : new RegExp(".(".concat(options.styleFileExtensions.join('|'), ")$"));
75
+ ? new RegExp(".".concat(options.styleFileSuffix, ".(").concat(options.styleFileExtensions.join("|"), ")$"))
76
+ : new RegExp(".(".concat(options.styleFileExtensions.join("|"), ")$"));
76
77
  var scopedCssInFileRegex = options.styleFileSuffix
77
- ? new RegExp(".".concat(options.styleFileSuffix, ".(").concat(options.styleFileExtensions.join('|'), ")(\"|')"))
78
- : new RegExp(".(".concat(options.styleFileExtensions.join('|'), ")(\"|')"));
79
- var jsxRegex = new RegExp(".(".concat(options.jsxFileExtensions.join('|'), ")$"));
78
+ ? new RegExp(".".concat(options.styleFileSuffix, ".(").concat(options.styleFileExtensions.join("|"), ")(\"|')"))
79
+ : new RegExp(".(".concat(options.styleFileExtensions.join("|"), ")(\"|')"));
80
+ var jsxRegex = new RegExp(".(".concat(options.jsxFileExtensions.join("|"), ")$"));
80
81
  return [
81
82
  {
82
- name: 'rollup-plugin-react-scoped-css:pre',
83
+ name: "rollup-plugin-react-scoped-css:pre",
83
84
  resolveId: function (source, importer) {
84
85
  if (!importer) {
85
86
  return;
@@ -90,10 +91,10 @@ function reactScopedCssPlugin(optionsIn) {
90
91
  return url;
91
92
  }
92
93
  },
93
- enforce: 'pre'
94
+ enforce: "pre",
94
95
  },
95
96
  {
96
- name: 'rollup-plugin-react-scoped-css:post',
97
+ name: "rollup-plugin-react-scoped-css:post",
97
98
  transform: function (code, id) {
98
99
  if (!filter(id)) {
99
100
  return;
@@ -108,8 +109,8 @@ function reactScopedCssPlugin(optionsIn) {
108
109
  var importerHash = getHashFromPath(id);
109
110
  return addAttributesToCss(code, getFilenameFromPath(id), "data-".concat(options.hashPrefix, "-").concat(importerHash));
110
111
  }
111
- }
112
- }
112
+ },
113
+ },
113
114
  ];
114
115
  }
115
116
  exports.default = reactScopedCssPlugin;
@@ -42,14 +42,14 @@ var ClassicJsxParser = /** @class */ (function () {
42
42
  }
43
43
  ClassicJsxParser.prototype.isNodeReactFragment = function (node) {
44
44
  var _a, _b, _c, _d, _e, _f;
45
- return ((_c = (_b = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.object) === null || _c === void 0 ? void 0 : _c.name) === "React" &&
46
- ((_f = (_e = (_d = node === null || node === void 0 ? void 0 : node.arguments) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.property) === null || _f === void 0 ? void 0 : _f.name) === "Fragment";
45
+ return (((_c = (_b = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.object) === null || _c === void 0 ? void 0 : _c.name) === "React" &&
46
+ ((_f = (_e = (_d = node === null || node === void 0 ? void 0 : node.arguments) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.property) === null || _f === void 0 ? void 0 : _f.name) === "Fragment");
47
47
  };
48
48
  ClassicJsxParser.prototype.isNodeReactElement = function (node) {
49
49
  var _a, _b, _c, _d;
50
- return (node === null || node === void 0 ? void 0 : node.type) === 'CallExpression' &&
51
- ((_b = (_a = node === null || node === void 0 ? void 0 : node.callee) === null || _a === void 0 ? void 0 : _a.object) === null || _b === void 0 ? void 0 : _b.name) === 'React' &&
52
- ((_d = (_c = node === null || node === void 0 ? void 0 : node.callee) === null || _c === void 0 ? void 0 : _c.property) === null || _d === void 0 ? void 0 : _d.name) === 'createElement';
50
+ return ((node === null || node === void 0 ? void 0 : node.type) === "CallExpression" &&
51
+ ((_b = (_a = node === null || node === void 0 ? void 0 : node.callee) === null || _a === void 0 ? void 0 : _a.object) === null || _b === void 0 ? void 0 : _b.name) === "React" &&
52
+ ((_d = (_c = node === null || node === void 0 ? void 0 : node.callee) === null || _c === void 0 ? void 0 : _c.property) === null || _d === void 0 ? void 0 : _d.name) === "createElement");
53
53
  };
54
54
  ClassicJsxParser.prototype.extendNodeWithAttributes = function (node, attr) {
55
55
  var _this = this;
@@ -57,15 +57,21 @@ var ClassicJsxParser = /** @class */ (function () {
57
57
  var arg = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[1];
58
58
  return __assign(__assign({}, node), { arguments: node === null || node === void 0 ? void 0 : node.arguments.map(function (v, i) {
59
59
  if (i === 1) {
60
- if (v.type === 'ObjectExpression') {
61
- return __assign(__assign({}, v), { properties: __spreadArray(__spreadArray([], __read(arg.properties), false), [
62
- _this.createAttributeNode(attr)
63
- ], false) });
60
+ if (v.type === "ObjectExpression") {
61
+ return __assign(__assign({}, v), { properties: __spreadArray(__spreadArray([], __read(arg.properties), false), [_this.createAttributeNode(attr)], false) });
62
+ }
63
+ else if (v.type === "CallExpression" &&
64
+ v.callee.name === "_objectSpread") {
65
+ var args = __spreadArray([], __read(v.arguments), false);
66
+ args[0].properties = __spreadArray(__spreadArray([], __read(args[0].properties), false), [
67
+ _this.createAttributeNode(attr),
68
+ ], false);
69
+ return __assign(__assign({}, v), { arguments: args });
64
70
  }
65
71
  else {
66
72
  return {
67
- type: 'ObjectExpression',
68
- properties: [_this.createAttributeNode(attr)]
73
+ type: "ObjectExpression",
74
+ properties: [_this.createAttributeNode(attr)],
69
75
  };
70
76
  }
71
77
  }
@@ -74,20 +80,20 @@ var ClassicJsxParser = /** @class */ (function () {
74
80
  };
75
81
  ClassicJsxParser.prototype.createAttributeNode = function (attr) {
76
82
  return {
77
- type: 'Property',
83
+ type: "Property",
78
84
  method: false,
79
85
  shorthand: false,
80
86
  computed: false,
81
87
  key: {
82
- type: 'Identifier',
83
- name: "\"".concat(attr, "\"")
88
+ type: "Identifier",
89
+ name: "\"".concat(attr, "\""),
84
90
  },
85
91
  value: {
86
- type: 'Literal',
92
+ type: "Literal",
87
93
  value: true,
88
- raw: "true"
94
+ raw: "true",
89
95
  },
90
- kind: 'init'
96
+ kind: "init",
91
97
  };
92
98
  };
93
99
  return ClassicJsxParser;
@@ -42,13 +42,13 @@ var NewJsxParser = /** @class */ (function () {
42
42
  }
43
43
  NewJsxParser.prototype.isNodeReactFragment = function (node) {
44
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);
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
47
  };
48
48
  NewJsxParser.prototype.isNodeReactElement = function (node) {
49
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);
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
52
  };
53
53
  NewJsxParser.prototype.extendNodeWithAttributes = function (node, attr) {
54
54
  var _this = this;
@@ -56,15 +56,21 @@ var NewJsxParser = /** @class */ (function () {
56
56
  var arg = (_a = node === null || node === void 0 ? void 0 : node.arguments) === null || _a === void 0 ? void 0 : _a[1];
57
57
  return __assign(__assign({}, node), { arguments: node === null || node === void 0 ? void 0 : node.arguments.map(function (v, i) {
58
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) });
59
+ if (v.type === "ObjectExpression") {
60
+ return __assign(__assign({}, v), { properties: __spreadArray(__spreadArray([], __read(arg.properties), false), [_this.createAttributeNode(attr)], false) });
61
+ }
62
+ else if (v.type === "CallExpression" &&
63
+ v.callee.name === "_objectSpread") {
64
+ var args = __spreadArray([], __read(v.arguments), false);
65
+ args[0].properties = __spreadArray(__spreadArray([], __read(args[0].properties), false), [
66
+ _this.createAttributeNode(attr),
67
+ ], false);
68
+ return __assign(__assign({}, v), { arguments: args });
63
69
  }
64
70
  else {
65
71
  return {
66
- type: 'ObjectExpression',
67
- properties: [_this.createAttributeNode(attr)]
72
+ type: "ObjectExpression",
73
+ properties: [_this.createAttributeNode(attr)],
68
74
  };
69
75
  }
70
76
  }
@@ -73,20 +79,20 @@ var NewJsxParser = /** @class */ (function () {
73
79
  };
74
80
  NewJsxParser.prototype.createAttributeNode = function (attr) {
75
81
  return {
76
- type: 'Property',
82
+ type: "Property",
77
83
  method: false,
78
84
  shorthand: false,
79
85
  computed: false,
80
86
  key: {
81
- type: 'Identifier',
82
- name: "\"".concat(attr, "\"")
87
+ type: "Identifier",
88
+ name: "\"".concat(attr, "\""),
83
89
  },
84
90
  value: {
85
- type: 'Literal',
91
+ type: "Literal",
86
92
  value: true,
87
- raw: "true"
93
+ raw: "true",
88
94
  },
89
- kind: 'init'
95
+ kind: "init",
90
96
  };
91
97
  };
92
98
  return NewJsxParser;
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "rollup-plugin-react-scoped-css",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
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
+ "lint": "eslint '*/**/*.{js,jsx,ts,tsx}'",
10
11
  "test": "jest"
11
12
  },
12
13
  "repository": {
@@ -49,7 +50,15 @@
49
50
  "@types/escodegen": "0.0.7",
50
51
  "@types/estree": "0.0.50",
51
52
  "@types/jest": "^27.0.1",
53
+ "@typescript-eslint/eslint-plugin": "^5.5.0",
54
+ "@typescript-eslint/parser": "^5.5.0",
52
55
  "acorn": "^8.6.0",
56
+ "eslint": "^8.3.0",
57
+ "eslint-config-prettier": "^8.3.0",
58
+ "eslint-plugin-import": "^2.25.3",
59
+ "eslint-plugin-node": "^11.1.0",
60
+ "eslint-plugin-prettier": "^4.0.0",
61
+ "eslint-plugin-react": "^7.27.1",
53
62
  "jest": "^27.0.6",
54
63
  "semantic-release": "^18.0.1"
55
64
  }
@@ -3,11 +3,14 @@ import { resolve } from "path";
3
3
  import { parse } from "acorn";
4
4
  import { astIterator } from "./ast-iterator";
5
5
 
6
- describe('astIterator', () => {
7
- it('should iterate through all nodes', async () => {
6
+ describe("astIterator", () => {
7
+ it("should iterate through all nodes", async () => {
8
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 });
9
+ const file = await readFile(
10
+ resolve(__dirname, "./__mocks__/sample-code-file.js"),
11
+ { encoding: "utf-8" }
12
+ );
13
+ const ast = parse(file, { sourceType: "module", ecmaVersion: 2022 });
11
14
 
12
15
  for (const node of astIterator(ast)) {
13
16
  iterationCount++;
@@ -16,4 +19,4 @@ describe('astIterator', () => {
16
19
 
17
20
  expect(iterationCount).toBe(28);
18
21
  });
19
- })
22
+ });
@@ -1,27 +1,32 @@
1
-
2
1
  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
- }
2
+ return (
3
+ 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
+ };
8
9
 
9
10
  export const astIterator = function* (ast: any): IterableIterator<any> {
10
- if (!ast) { return }
11
+ if (!ast) {
12
+ return;
13
+ }
11
14
 
12
- for (let key of Object.keys(ast)) {
15
+ for (const key of Object.keys(ast)) {
13
16
  // Skip useless keys
14
- if (['end', 'start', 'type'].includes(key)) { continue; }
17
+ if (["end", "start", "type"].includes(key)) {
18
+ continue;
19
+ }
15
20
 
16
21
  // If key value is an array, iterate over it
17
22
  if (Array.isArray(ast[key])) {
18
- for (let nodeIndex in ast[key]) {
19
- yield *astIterator(ast[key][nodeIndex])
23
+ for (const nodeIndex in ast[key]) {
24
+ yield* astIterator(ast[key][nodeIndex]);
20
25
  }
21
- } else if(isNode(ast[key])) {
22
- yield *astIterator(ast[key])
26
+ } else if (isNode(ast[key])) {
27
+ yield* astIterator(ast[key]);
23
28
  }
24
29
  }
25
30
 
26
- yield ast
27
- }
31
+ yield ast;
32
+ };
@@ -3,18 +3,21 @@ import { resolve } from "path";
3
3
  import { parse } from "acorn";
4
4
  import { astTransformer } from "./ast-transformer";
5
5
 
6
- describe('astTransformer', () => {
7
- it('should iterate through all nodes', async () => {
6
+ describe("astTransformer", () => {
7
+ it("should iterate through all nodes", async () => {
8
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 });
9
+ const file = await readFile(
10
+ resolve(__dirname, "./__mocks__/sample-code-file.js"),
11
+ { encoding: "utf-8" }
12
+ );
13
+ const ast = parse(file, { sourceType: "module", ecmaVersion: 2022 });
11
14
 
12
15
  const newAst = astTransformer(ast, (node) => {
13
16
  iterationCount++;
14
17
  expect(node).toBeTruthy();
15
- })
18
+ });
16
19
 
17
20
  expect(newAst).toBeDefined();
18
21
  expect(iterationCount).toBe(28);
19
22
  });
20
- })
23
+ });
@@ -1,24 +1,28 @@
1
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
- }
2
+ return (
3
+ 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
+ };
7
9
 
8
- export const astTransformer = (ast: any, callback: Function) => {
9
- for (let key of Object.keys(ast)) {
10
- if (['end', 'start', 'type'].includes(key)) { continue; }
10
+ export const astTransformer = (ast: any, callback: (ast: any) => any) => {
11
+ for (const key of Object.keys(ast)) {
12
+ if (["end", "start", "type"].includes(key)) {
13
+ continue;
14
+ }
11
15
 
12
16
  if (Array.isArray(ast[key])) {
13
- for (let nodeIndex in ast[key]) {
14
- ast[key][nodeIndex] = astTransformer(ast[key][nodeIndex], callback)
17
+ for (const nodeIndex in ast[key]) {
18
+ ast[key][nodeIndex] = astTransformer(ast[key][nodeIndex], callback);
15
19
  }
16
- } else if(isNode(ast[key])) {
17
- ast[key] = astTransformer(ast[key], callback)
20
+ } else if (isNode(ast[key])) {
21
+ ast[key] = astTransformer(ast[key], callback);
18
22
  }
19
23
  }
20
24
 
21
25
  const result = callback(ast);
22
26
 
23
- return typeof result !== 'undefined' ? result : ast
24
- }
27
+ return typeof result !== "undefined" ? result : ast;
28
+ };
@@ -1,46 +1,61 @@
1
- import { resolve } from 'path'
2
- import { readFile } from 'fs/promises'
3
- import { parse } from 'acorn'
4
- import { generate } from 'escodegen'
5
- import { addHashAttributesToJsxTagsAst } from './ast.utils'
1
+ import { resolve } from "path";
2
+ import { readFile } from "fs/promises";
3
+ import { parse } from "acorn";
4
+ import { generate } from "escodegen";
5
+ import { addHashAttributesToJsxTagsAst } from "./ast.utils";
6
6
 
7
- describe('AST Utils', () => {
7
+ describe("AST Utils", () => {
8
8
  beforeEach(() => {
9
- global.implementation = null
10
- })
9
+ global.implementation = null;
10
+ });
11
11
 
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: ' ',
12
+ describe("classic implementation", () => {
13
+ it("Should add the attr to the right elements", async () => {
14
+ const compiled = await readFile(
15
+ resolve(__dirname, "./__mocks__/classic-compiled-jsx.js"),
16
+ { encoding: "utf-8" }
17
+ );
18
+ const compiledWithAttr = await readFile(
19
+ resolve(__dirname, "./__mocks__/classic-compiled-jsx-with-attr.js"),
20
+ { encoding: "utf-8" }
21
+ );
22
+ const ast = parse(compiled, { ecmaVersion: 2021, sourceType: "module" });
23
+ const modifiedAst = addHashAttributesToJsxTagsAst(ast, "data-v-123456");
24
+ const modifiedCompiled = generate(modifiedAst, {
25
+ format: {
26
+ indent: {
27
+ style: " ",
28
+ },
29
+ quotes: "double",
21
30
  },
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: ' ',
31
+ });
32
+
33
+ expect(modifiedCompiled).toEqual(compiledWithAttr);
34
+ });
35
+ });
36
+
37
+ describe("new implementation", () => {
38
+ it("Should add the attr to the right elements", async () => {
39
+ const compiled = await readFile(
40
+ resolve(__dirname, "./__mocks__/new-compiled-jsx.js"),
41
+ { encoding: "utf-8" }
42
+ );
43
+ const compiledWithAttr = await readFile(
44
+ resolve(__dirname, "./__mocks__/new-compiled-jsx-with-attr.js"),
45
+ { encoding: "utf-8" }
46
+ );
47
+ const ast = parse(compiled, { ecmaVersion: 2021, sourceType: "module" });
48
+ const modifiedAst = addHashAttributesToJsxTagsAst(ast, "data-v-123456");
49
+ const modifiedCompiled = generate(modifiedAst, {
50
+ format: {
51
+ indent: {
52
+ style: " ",
53
+ },
54
+ quotes: "double",
38
55
  },
39
- quotes: 'double',
40
- } })
41
-
42
- expect(modifiedCompiled).toEqual(compiledWithAttr)
43
- })
44
- })
45
-
46
- })
56
+ });
57
+
58
+ expect(modifiedCompiled).toEqual(compiledWithAttr);
59
+ });
60
+ });
61
+ });
package/src/ast.utils.ts CHANGED
@@ -1,52 +1,53 @@
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"
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";
6
6
 
7
7
  declare global {
8
- var implementation: null | ParserImplementations
8
+ // eslint-disable-next-line
9
+ var implementation: null | ParserImplementations;
9
10
  }
10
11
 
11
- global.implementation = null
12
+ global.implementation = null;
12
13
 
13
- const classicParser = new ClassicJsxParser()
14
- const newParser = new NewJsxParser()
14
+ const classicParser = new ClassicJsxParser();
15
+ const newParser = new NewJsxParser();
15
16
 
16
17
  let parser: JsxParser = classicParser;
17
18
 
18
19
  const findImplementation = (program: any) => {
19
- let implementation: ParserImplementations = ParserImplementations.classic;
20
- for (let node of astIterator(program)) {
21
- if (node.type !== 'ImportDeclaration') {
20
+ const implementation: ParserImplementations = ParserImplementations.classic;
21
+ for (const node of astIterator(program)) {
22
+ if (node.type !== "ImportDeclaration") {
22
23
  continue;
23
24
  }
24
25
 
25
26
  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)
27
+ node.specifiers.some((n: any) =>
28
+ ["_jsxDEV", "jsxRuntime"].includes(n.local.name)
29
+ ) ||
30
+ ["react/jsx-dev-runtime", "react/jsx-runtime"].includes(node.source.value)
29
31
  ) {
30
- return ParserImplementations.new
32
+ return ParserImplementations.new;
31
33
  }
32
34
  }
33
- return implementation
34
- }
35
+ return implementation;
36
+ };
35
37
 
36
38
  export function addHashAttributesToJsxTagsAst(program: any, attr: string) {
37
-
38
39
  // Once in the program, we can determine which parser to use
39
40
  if (global.implementation === null) {
40
- global.implementation = findImplementation(program)
41
+ global.implementation = findImplementation(program);
41
42
 
42
43
  if (global.implementation === ParserImplementations.new) {
43
- parser = newParser
44
+ parser = newParser;
44
45
  }
45
46
  }
46
47
 
47
48
  return astTransformer(program, (node: any) => {
48
49
  if (parser.isNodeReactElement(node) && !parser.isNodeReactFragment(node)) {
49
- return parser.extendNodeWithAttributes(node, attr)
50
+ return parser.extendNodeWithAttributes(node, attr);
50
51
  }
51
- })
52
- }
52
+ });
53
+ }
package/src/index.ts CHANGED
@@ -1,27 +1,28 @@
1
- import * as path from 'path';
2
- import { xxHash32 } from 'js-xxhash';
3
- import { createFilter, FilterPattern } from '@rollup/pluginutils';
4
- import { compileStyle } from '@vue/component-compiler-utils'
5
- import { generate } from 'escodegen'
1
+ /* eslint-disable no-useless-escape */
2
+ import * as path from "path";
3
+ import { xxHash32 } from "js-xxhash";
4
+ import { createFilter, FilterPattern } from "@rollup/pluginutils";
5
+ import { compileStyle } from "@vue/component-compiler-utils";
6
+ import { generate } from "escodegen";
6
7
 
7
- import type { Plugin } from 'rollup'
8
- import { addHashAttributesToJsxTagsAst } from './ast.utils';
8
+ import type { Plugin } from "rollup";
9
+ import { addHashAttributesToJsxTagsAst } from "./ast.utils";
9
10
 
10
11
  const getFilenameFromPath = (filePath: string) => {
11
- const parts = filePath.split('/')
12
- return parts[parts.length - 1].split('?')[0]
13
- }
12
+ const parts = filePath.split("/");
13
+ return parts[parts.length - 1].split("?")[0];
14
+ };
14
15
 
15
16
  const getHashFromPath = (filePath: string) => {
16
- const search = '?scope='
17
- const hash = filePath.slice(filePath.indexOf(search) + search.length)
18
- return hash
19
- }
17
+ const search = "?scope=";
18
+ const hash = filePath.slice(filePath.indexOf(search) + search.length);
19
+ return hash;
20
+ };
20
21
 
21
- const generateHash = (input: string, seed: number = 0) => {
22
- let hashNum = xxHash32(Buffer.from(input, 'utf8'), seed);
22
+ const generateHash = (input: string, seed = 0) => {
23
+ const hashNum = xxHash32(Buffer.from(input, "utf8"), seed);
23
24
  return hashNum.toString(16);
24
- }
25
+ };
25
26
 
26
27
  const addAttributesToCss = (src: string, fileName: string, hash: string) => {
27
28
  const { code } = compileStyle({
@@ -30,83 +31,93 @@ const addAttributesToCss = (src: string, fileName: string, hash: string) => {
30
31
  id: hash,
31
32
  scoped: true,
32
33
  trim: true,
33
- })
34
+ });
34
35
 
35
- return code
36
- }
36
+ return code;
37
+ };
37
38
 
38
39
  export interface ReactScopedCssPluginOptions {
39
40
  /**
40
41
  * Which files should be included and parsed by the plugin
41
42
  * Default: undefined
42
43
  */
43
- include?: FilterPattern
44
+ include?: FilterPattern;
44
45
 
45
46
  /**
46
47
  * Which files should be exluded and that should not be parsed by the plugin
47
48
  * Default: undefined
48
49
  */
49
- exclude?: FilterPattern
50
+ exclude?: FilterPattern;
50
51
 
51
52
  /**
52
53
  * If you want to customize the stylesheet file pattern
53
54
  * if undefined or '' is passed, all files will be evaluated
54
55
  * Default: 'scoped'
55
56
  */
56
- styleFileSuffix?: string
57
+ styleFileSuffix?: string;
57
58
 
58
59
  /**
59
60
  * If you want to customize the attribute prefix that is added to the jsx elements
60
61
  * Default: 'v'
61
62
  */
62
- hashPrefix?: string
63
+ hashPrefix?: string;
63
64
 
64
65
  /**
65
66
  * If you want to customize the stylesheet extensions
66
67
  * Default: ['scss', 'css', 'sass', 'less']
67
68
  */
68
- styleFileExtensions?: string[]
69
+ styleFileExtensions?: string[];
69
70
 
70
71
  /**
71
72
  * If you have jsx in other file extensions
72
73
  * Default: ['jsx', 'tsx']
73
74
  */
74
- jsxFileExtensions?: string[]
75
+ jsxFileExtensions?: string[];
75
76
  }
76
77
 
77
78
  export interface VitePartialPlugin extends Plugin {
78
- enforce?: "pre" | "post"
79
+ enforce?: "pre" | "post";
79
80
  }
80
81
 
81
- export default function reactScopedCssPlugin(optionsIn: ReactScopedCssPluginOptions = {}): VitePartialPlugin[] {
82
+ export default function reactScopedCssPlugin(
83
+ optionsIn: ReactScopedCssPluginOptions = {}
84
+ ): VitePartialPlugin[] {
82
85
  const options: Partial<ReactScopedCssPluginOptions> = {
83
- hashPrefix: 'v',
84
- styleFileSuffix: 'scoped',
85
- styleFileExtensions: ['scss', 'css', 'sass', 'less'],
86
- jsxFileExtensions: ['jsx', 'tsx'],
87
- ...optionsIn
88
- }
86
+ hashPrefix: "v",
87
+ styleFileSuffix: "scoped",
88
+ styleFileExtensions: ["scss", "css", "sass", "less"],
89
+ jsxFileExtensions: ["jsx", "tsx"],
90
+ ...optionsIn,
91
+ };
89
92
 
90
93
  if (!options.styleFileExtensions || !options.styleFileExtensions.length) {
91
- throw new Error('You need to provide at least one style file extension')
94
+ throw new Error("You need to provide at least one style file extension");
92
95
  }
93
96
 
94
97
  if (!options.jsxFileExtensions || !options.jsxFileExtensions.length) {
95
- throw new Error('You need to provide at least one jsx file extension')
98
+ throw new Error("You need to provide at least one jsx file extension");
96
99
  }
97
100
 
98
- const filter = createFilter( options.include, options.exclude );
99
- const scopedCssRegex = options.styleFileSuffix
100
- ? new RegExp(`\.${options.styleFileSuffix}\.(${options.styleFileExtensions.join('|')})$`)
101
- : new RegExp(`\.(${options.styleFileExtensions.join('|')})$`)
101
+ const filter = createFilter(options.include, options.exclude);
102
+ const scopedCssRegex = options.styleFileSuffix
103
+ ? new RegExp(
104
+ `\.${options.styleFileSuffix}\.(${options.styleFileExtensions.join(
105
+ "|"
106
+ )})$`
107
+ )
108
+ : new RegExp(`\.(${options.styleFileExtensions.join("|")})$`);
102
109
  const scopedCssInFileRegex = options.styleFileSuffix
103
- ? new RegExp(`\.${options.styleFileSuffix}\.(${options.styleFileExtensions.join('|')})(\"|\')`)
104
- : new RegExp(`\.(${options.styleFileExtensions.join('|')})(\"|\')`)
105
- const jsxRegex = new RegExp(`\.(${options.jsxFileExtensions.join('|')})$`)
110
+ ? new RegExp(
111
+ `\.${options.styleFileSuffix}\.(${options.styleFileExtensions.join(
112
+ "|"
113
+ )})(\"|\')`
114
+ )
115
+ : new RegExp(`\.(${options.styleFileExtensions.join("|")})(\"|\')`);
116
+ const jsxRegex = new RegExp(`\.(${options.jsxFileExtensions.join("|")})$`);
106
117
 
107
118
  return [
108
119
  {
109
- name: 'rollup-plugin-react-scoped-css:pre',
120
+ name: "rollup-plugin-react-scoped-css:pre",
110
121
  resolveId(source, importer) {
111
122
  if (!importer) {
112
123
  return;
@@ -114,30 +125,40 @@ export default function reactScopedCssPlugin(optionsIn: ReactScopedCssPluginOpti
114
125
 
115
126
  if (scopedCssRegex.test(source) && jsxRegex.test(importer)) {
116
127
  const importerHash = generateHash(importer);
117
- const url = path.resolve(path.dirname(importer), `${source}?scope=${importerHash}`)
118
- return url
128
+ const url = path.resolve(
129
+ path.dirname(importer),
130
+ `${source}?scope=${importerHash}`
131
+ );
132
+ return url;
119
133
  }
120
134
  },
121
- enforce: 'pre'
135
+ enforce: "pre",
122
136
  },
123
137
  {
124
- name: 'rollup-plugin-react-scoped-css:post',
138
+ name: "rollup-plugin-react-scoped-css:post",
125
139
  transform(code, id) {
126
140
  if (!filter(id)) {
127
141
  return;
128
142
  }
129
143
  if (scopedCssInFileRegex.test(code)) {
130
144
  const importerHash = generateHash(id);
131
- const program = this.parse(code)
132
- const newAst = addHashAttributesToJsxTagsAst(program, `data-${options.hashPrefix}-${importerHash}`)
133
- return generate(newAst)
145
+ const program = this.parse(code);
146
+ const newAst = addHashAttributesToJsxTagsAst(
147
+ program,
148
+ `data-${options.hashPrefix}-${importerHash}`
149
+ );
150
+ return generate(newAst);
134
151
  }
135
152
 
136
153
  if (scopedCssRegex.test(getFilenameFromPath(id))) {
137
154
  const importerHash = getHashFromPath(id);
138
- return addAttributesToCss(code, getFilenameFromPath(id), `data-${options.hashPrefix}-${importerHash}`)
155
+ return addAttributesToCss(
156
+ code,
157
+ getFilenameFromPath(id),
158
+ `data-${options.hashPrefix}-${importerHash}`
159
+ );
139
160
  }
140
- }
141
- }
142
- ]
143
- }
161
+ },
162
+ },
163
+ ];
164
+ }
@@ -2,57 +2,71 @@ import { JsxParser } from "./jsx-parser.model";
2
2
 
3
3
  export class ClassicJsxParser implements JsxParser {
4
4
  isNodeReactFragment(node: any) {
5
- return node?.arguments?.[0]?.object?.name === "React" &&
5
+ return (
6
+ node?.arguments?.[0]?.object?.name === "React" &&
6
7
  node?.arguments?.[0]?.property?.name === "Fragment"
8
+ );
7
9
  }
8
10
  isNodeReactElement(node: any) {
9
- return node?.type === 'CallExpression' &&
10
- node?.callee?.object?.name === 'React' &&
11
- node?.callee?.property?.name === 'createElement'
11
+ return (
12
+ node?.type === "CallExpression" &&
13
+ node?.callee?.object?.name === "React" &&
14
+ node?.callee?.property?.name === "createElement"
15
+ );
12
16
  }
13
17
 
14
18
  public extendNodeWithAttributes(node: any, attr: string) {
15
- const arg = node?.arguments?.[1]
19
+ const arg = node?.arguments?.[1];
16
20
  return {
17
21
  ...node,
18
22
  arguments: node?.arguments.map((v: any, i: number) => {
19
23
  if (i === 1) {
20
- if (v.type === 'ObjectExpression') {
21
- return {
22
- ...v,
23
- properties: [
24
- ...arg.properties,
25
- this.createAttributeNode(attr)
26
- ]
27
- }
28
- } else {
29
- return {
30
- type: 'ObjectExpression',
31
- properties: [this.createAttributeNode(attr)]
32
- }
33
- }
24
+ if (v.type === "ObjectExpression") {
25
+ return {
26
+ ...v,
27
+ properties: [...arg.properties, this.createAttributeNode(attr)],
28
+ };
29
+ } else if (
30
+ v.type === "CallExpression" &&
31
+ v.callee.name === "_objectSpread"
32
+ ) {
33
+ const args = [...v.arguments];
34
+ args[0].properties = [
35
+ ...args[0].properties,
36
+ this.createAttributeNode(attr),
37
+ ];
38
+ return {
39
+ ...v,
40
+ arguments: args,
41
+ };
42
+ } else {
43
+ return {
44
+ type: "ObjectExpression",
45
+ properties: [this.createAttributeNode(attr)],
46
+ };
34
47
  }
35
- return v
36
- })
37
- }
48
+ }
49
+ return v;
50
+ }),
51
+ };
38
52
  }
39
53
 
40
54
  private createAttributeNode(attr: string) {
41
55
  return {
42
- type: 'Property',
56
+ type: "Property",
43
57
  method: false,
44
58
  shorthand: false,
45
59
  computed: false,
46
60
  key: {
47
- type: 'Identifier',
48
- name: `"${attr}"`
61
+ type: "Identifier",
62
+ name: `"${attr}"`,
49
63
  },
50
64
  value: {
51
- type: 'Literal',
65
+ type: "Literal",
52
66
  value: true,
53
- raw: "true"
67
+ raw: "true",
54
68
  },
55
- kind: 'init'
56
- }
69
+ kind: "init",
70
+ };
57
71
  }
58
- }
72
+ }
@@ -1,10 +1,10 @@
1
1
  export interface JsxParser {
2
- isNodeReactElement: (node: any) => boolean
3
- isNodeReactFragment: (node: any) => boolean
4
- extendNodeWithAttributes: (node: any, attr: string) => any
2
+ isNodeReactElement: (node: any) => boolean;
3
+ isNodeReactFragment: (node: any) => boolean;
4
+ extendNodeWithAttributes: (node: any, attr: string) => any;
5
5
  }
6
6
 
7
7
  export enum ParserImplementations {
8
- new = 'new',
9
- classic = 'classic'
10
- }
8
+ new = "new",
9
+ classic = "classic",
10
+ }
@@ -2,57 +2,73 @@ import { JsxParser } from "./jsx-parser.model";
2
2
 
3
3
  export class NewJsxParser implements JsxParser {
4
4
  isNodeReactFragment(node: any) {
5
- return node.arguments?.[0]?.type === "Identifier" &&
6
- ['_Fragment', 'Fragment'].includes(node.arguments?.[0]?.name)
5
+ return (
6
+ node.arguments?.[0]?.type === "Identifier" &&
7
+ ["_Fragment", "Fragment"].includes(node.arguments?.[0]?.name)
8
+ );
7
9
  }
8
-
10
+
9
11
  isNodeReactElement(node: any) {
10
- return node?.type === 'CallExpression' &&
11
- ['_jsxDEV', '_jsx', '_jsxs', 'jsxDev', 'jsx', 'jsxs'].includes(node?.callee?.name)
12
+ return (
13
+ node?.type === "CallExpression" &&
14
+ ["_jsxDEV", "_jsx", "_jsxs", "jsxDev", "jsx", "jsxs"].includes(
15
+ node?.callee?.name
16
+ )
17
+ );
12
18
  }
13
19
 
14
20
  public extendNodeWithAttributes(node: any, attr: string) {
15
- const arg = node?.arguments?.[1]
21
+ const arg = node?.arguments?.[1];
16
22
  return {
17
23
  ...node,
18
24
  arguments: node?.arguments.map((v: any, i: number) => {
19
25
  if (i === 1) {
20
- if (v.type === 'ObjectExpression') {
21
- return {
22
- ...v,
23
- properties: [
24
- ...arg.properties,
25
- this.createAttributeNode(attr)
26
- ]
27
- }
28
- } else {
29
- return {
30
- type: 'ObjectExpression',
31
- properties: [this.createAttributeNode(attr)]
32
- }
33
- }
26
+ if (v.type === "ObjectExpression") {
27
+ return {
28
+ ...v,
29
+ properties: [...arg.properties, this.createAttributeNode(attr)],
30
+ };
31
+ } else if (
32
+ v.type === "CallExpression" &&
33
+ v.callee.name === "_objectSpread"
34
+ ) {
35
+ const args = [...v.arguments];
36
+ args[0].properties = [
37
+ ...args[0].properties,
38
+ this.createAttributeNode(attr),
39
+ ];
40
+ return {
41
+ ...v,
42
+ arguments: args,
43
+ };
44
+ } else {
45
+ return {
46
+ type: "ObjectExpression",
47
+ properties: [this.createAttributeNode(attr)],
48
+ };
34
49
  }
35
- return v
36
- })
37
- }
50
+ }
51
+ return v;
52
+ }),
53
+ };
38
54
  }
39
55
 
40
56
  private createAttributeNode(attr: string) {
41
57
  return {
42
- type: 'Property',
58
+ type: "Property",
43
59
  method: false,
44
60
  shorthand: false,
45
61
  computed: false,
46
62
  key: {
47
- type: 'Identifier',
48
- name: `"${attr}"`
63
+ type: "Identifier",
64
+ name: `"${attr}"`,
49
65
  },
50
66
  value: {
51
- type: 'Literal',
67
+ type: "Literal",
52
68
  value: true,
53
- raw: "true"
69
+ raw: "true",
54
70
  },
55
- kind: 'init'
56
- }
71
+ kind: "init",
72
+ };
57
73
  }
58
- }
74
+ }