ember-codemod-remove-global-styles 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,8 +5,38 @@
5
5
  _Codemod to localize global styles_
6
6
 
7
7
 
8
+ ## Why use it?
9
+
10
+ Moving from global styles to CSS modules can be tedious and error-prone. Run this codemod to get started.
11
+
12
+ The codemod:
13
+
14
+ - Statically analyzes code (no need to build projects)
15
+ - Supports v1 apps (classic, Webpack), v2 apps (Vite)
16
+ - Light and fast
17
+
18
+
8
19
  ## Usage
9
20
 
21
+ Step 1. Quickly migrate.<sup>1,2</sup>
22
+
23
+ ```sh
24
+ cd <path/to/your/project>
25
+ pnpx ember-codemod-remove-global-styles <arguments>
26
+ ```
27
+
28
+ Step 2. Review the package.
29
+
30
+ - [x] Fix format and lint errors.<sup>3</sup>
31
+ - [x] Run tests.
32
+
33
+ <sup>1. The codemod assumes that your apps and addons follow the Octane layout (flat or nested). If not, you can run codemods to move away from [classic](https://github.com/ember-codemods/ember-component-template-colocation-migrator) and [pod](https://github.com/ijlee2/ember-codemod-pod-to-octane).</sup>
34
+
35
+ <sup>2. The codemod assumes a single CSS file, where you have defined all global styles that you own. You can obtain such a file by exploring the `dist/assets` folder.</sup>
36
+
37
+ <sup>3. If you need lint configs that support `*.module.css`, you can install packages from [`@ijlee2-frontend-configs`](https://github.com/ijlee2/frontend-configs).</sup>
38
+
39
+
10
40
  ### Arguments
11
41
 
12
42
  You must pass `--src` to indicate the location of your global stylesheet.
@@ -5,7 +5,10 @@ export class Processor {
5
5
  this.args = args;
6
6
  }
7
7
  getLocalClass(className) {
8
- return this.args.isHbs ? `this.styles.${className}` : `styles.${className}`;
8
+ return `${this.getStyles()}.${className}`;
9
+ }
10
+ getStyles() {
11
+ return this.args.isHbs ? 'this.styles' : 'styles';
9
12
  }
10
13
  isLocal(className) {
11
14
  return this.args.classToStyles.has(className);
@@ -69,20 +72,37 @@ export class Processor {
69
72
  ? AST.builders.path(this.getLocalClass(className))
70
73
  : nodeValue;
71
74
  }
72
- const hasLocalClass = classNames.some(this.isLocal.bind(this));
73
- if (!hasLocalClass) {
75
+ const allGlobal = classNames.every((className) => !this.isLocal(className));
76
+ if (allGlobal) {
74
77
  return nodeValue;
75
78
  }
76
- const parts = classNames
77
- .map((className) => {
78
- return this.isLocal(className)
79
- ? [
80
- AST.builders.path(this.getLocalClass(className)),
81
- AST.builders.string(' '),
82
- ]
83
- : [AST.builders.string(`${className} `), AST.builders.string(' ')];
84
- })
85
- .flat();
79
+ const allLocal = classNames.every(this.isLocal.bind(this));
80
+ if (allLocal) {
81
+ const parts = [
82
+ AST.builders.path(this.getStyles()),
83
+ ...classNames.map((className) => AST.builders.string(className)),
84
+ ];
85
+ return AST.builders.sexpr(AST.builders.path('local'), parts);
86
+ }
87
+ const parts = [];
88
+ const globalClasses = [];
89
+ classNames.forEach((className) => {
90
+ if (!this.isLocal(className)) {
91
+ globalClasses.push(className);
92
+ return;
93
+ }
94
+ if (globalClasses.length > 0) {
95
+ parts.push(AST.builders.string(globalClasses.join(' ')));
96
+ parts.push(AST.builders.string(' '));
97
+ }
98
+ parts.push(AST.builders.path(this.getLocalClass(className)));
99
+ parts.push(AST.builders.string(' '));
100
+ globalClasses.length = 0;
101
+ });
102
+ if (globalClasses.length > 0) {
103
+ parts.push(AST.builders.string(globalClasses.join(' ')));
104
+ parts.push(AST.builders.string(' '));
105
+ }
86
106
  // Remove space at the end
87
107
  parts.splice(-1);
88
108
  return AST.builders.sexpr(AST.builders.path('concat'), parts);
@@ -125,20 +145,37 @@ export class Processor {
125
145
  ? AST.builders.mustache(this.getLocalClass(className))
126
146
  : nodeValue;
127
147
  }
128
- const hasLocalClass = classNames.some(this.isLocal.bind(this));
129
- if (!hasLocalClass) {
148
+ const allGlobal = classNames.every((className) => !this.isLocal(className));
149
+ if (allGlobal) {
130
150
  return nodeValue;
131
151
  }
132
- const parts = classNames
133
- .map((className) => {
134
- return this.isLocal(className)
135
- ? [
136
- AST.builders.path(this.getLocalClass(className)),
137
- AST.builders.string(' '),
138
- ]
139
- : [AST.builders.string(className), AST.builders.string(' ')];
140
- })
141
- .flat();
152
+ const allLocal = classNames.every(this.isLocal.bind(this));
153
+ if (allLocal) {
154
+ const parts = [
155
+ AST.builders.path(this.getStyles()),
156
+ ...classNames.map((className) => AST.builders.string(className)),
157
+ ];
158
+ return AST.builders.mustache(AST.builders.path('local'), parts);
159
+ }
160
+ const parts = [];
161
+ const globalClasses = [];
162
+ classNames.forEach((className) => {
163
+ if (!this.isLocal(className)) {
164
+ globalClasses.push(className);
165
+ return;
166
+ }
167
+ if (globalClasses.length > 0) {
168
+ parts.push(AST.builders.string(globalClasses.join(' ')));
169
+ parts.push(AST.builders.string(' '));
170
+ }
171
+ parts.push(AST.builders.path(this.getLocalClass(className)));
172
+ parts.push(AST.builders.string(' '));
173
+ globalClasses.length = 0;
174
+ });
175
+ if (globalClasses.length > 0) {
176
+ parts.push(AST.builders.string(globalClasses.join(' ')));
177
+ parts.push(AST.builders.string(' '));
178
+ }
142
179
  // Remove space at the end
143
180
  parts.splice(-1);
144
181
  return AST.builders.mustache(AST.builders.path('concat'), parts);
@@ -1,4 +1,6 @@
1
1
  export function extractClasses(selector) {
2
2
  const matches = Array.from(selector.matchAll(/\.([\w-]+)/g));
3
- return matches.map((results) => results[1]);
3
+ return matches
4
+ .map((results) => results[1])
5
+ .map((selector) => selector.trim());
4
6
  }
@@ -1,5 +1,5 @@
1
1
  export function extractRootClass(selector) {
2
- const matches = selector.match(/^\.([\w-]+).*$/);
2
+ const matches = selector.match(/^\.([\w-]+)/);
3
3
  if (matches === null) {
4
4
  return undefined;
5
5
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-codemod-remove-global-styles",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Codemod to localize global styles",
5
5
  "keywords": [
6
6
  "codemod",
@@ -43,8 +43,8 @@
43
43
  "prettier": "^3.6.2",
44
44
  "typescript": "^5.9.3",
45
45
  "@shared-configs/prettier": "0.0.0",
46
- "@shared-configs/typescript": "0.0.0",
47
- "@shared-configs/eslint-config-node": "0.0.0"
46
+ "@shared-configs/eslint-config-node": "0.0.0",
47
+ "@shared-configs/typescript": "0.0.0"
48
48
  },
49
49
  "engines": {
50
50
  "node": "20.* || >= 22"