ember-codemod-remove-ember-css-modules 4.0.2 → 4.0.4

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
@@ -31,7 +31,7 @@ Step 1. Quickly remove `ember-css-modules` syntax.<sup>1</sup>
31
31
 
32
32
  ```sh
33
33
  cd <path/to/your/project>
34
- npx ember-codemod-remove-ember-css-modules <arguments>
34
+ pnpx ember-codemod-remove-ember-css-modules <arguments>
35
35
  ```
36
36
 
37
37
  Manually remove the remaining instances of `local-class` attributes and `{{local-class}}` helpers.
@@ -51,8 +51,8 @@ Step 2. Update project configurations.<sup>2</sup>
51
51
  You must pass `--type` to indicate what type of project you have.
52
52
 
53
53
  ```sh
54
- npx ember-codemod-remove-ember-css-modules --type app
55
- npx ember-codemod-remove-ember-css-modules --type v2-addon
54
+ pnpx ember-codemod-remove-ember-css-modules --type app
55
+ pnpx ember-codemod-remove-ember-css-modules --type v2-addon
56
56
  ```
57
57
 
58
58
 
@@ -63,7 +63,7 @@ npx ember-codemod-remove-ember-css-modules --type v2-addon
63
63
  By default, an Embroider project has the flat component structure. Pass `--component-structure` to indicate otherwise.
64
64
 
65
65
  ```sh
66
- npx ember-codemod-remove-ember-css-modules --component-structure nested
66
+ pnpx ember-codemod-remove-ember-css-modules --component-structure nested
67
67
  ```
68
68
 
69
69
  </details>
@@ -75,7 +75,7 @@ npx ember-codemod-remove-ember-css-modules --component-structure nested
75
75
  Pass `--root` to run the codemod somewhere else (i.e. not in the current directory).
76
76
 
77
77
  ```sh
78
- npx ember-codemod-remove-ember-css-modules --root <path/to/your/project>
78
+ pnpx ember-codemod-remove-ember-css-modules --root <path/to/your/project>
79
79
  ```
80
80
 
81
81
  </details>
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
2
1
  import { readFileSync } from 'node:fs';
3
2
  import { join } from 'node:path';
4
3
  import { AST } from '@codemod-utils/ast-javascript';
@@ -20,22 +19,25 @@ function removeTemplateOnlyComponentMethod(file, data) {
20
19
  const traverse = AST.traverse(data.isTypeScript);
21
20
  const ast = traverse(file, {
22
21
  visitCallExpression(path) {
23
- if (path.value.callee.name !== 'templateOnlyComponent') {
22
+ // @ts-expect-error: Incorrect type
23
+ if (path.node.callee.name !== 'templateOnlyComponent') {
24
24
  return false;
25
25
  }
26
26
  const superClass = AST.builders.identifier('Component');
27
27
  if (data.isTypeScript) {
28
- superClass.typeAnnotation = path.value.typeParameters;
28
+ // @ts-expect-error: Incorrect type
29
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
30
+ superClass.typeAnnotation = path.node.typeParameters;
29
31
  }
30
32
  return AST.builders.classExpression(null, AST.builders.classBody([
31
33
  AST.builders.classProperty(AST.builders.identifier('styles'), AST.builders.identifier('styles')),
32
34
  ]), superClass);
33
35
  },
34
36
  visitImportDeclaration(path) {
35
- if (path.value.source.value !== '@ember/component/template-only') {
37
+ if (path.node.source.value !== '@ember/component/template-only') {
36
38
  return false;
37
39
  }
38
- const defaultImport = path.value.specifiers.find((specifier) => specifier.type === 'ImportDefaultSpecifier');
40
+ const defaultImport = path.node.specifiers?.find((specifier) => specifier.type === 'ImportDefaultSpecifier');
39
41
  if (defaultImport?.local?.name !== 'templateOnlyComponent') {
40
42
  return false;
41
43
  }
@@ -55,6 +57,7 @@ function importStylesInClass(file, data) {
55
57
  if (!lastImportDeclarationPath) {
56
58
  lastImportDeclarationPath = path;
57
59
  // @ts-expect-error: Incorrect type
60
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
58
61
  }
59
62
  else if (path.node.start > lastImportDeclarationPath.node.start) {
60
63
  lastImportDeclarationPath = path;
@@ -64,9 +67,12 @@ function importStylesInClass(file, data) {
64
67
  });
65
68
  // Append the styles import
66
69
  // @ts-expect-error: Incorrect type
70
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
67
71
  const nodes = ast.program.body;
68
72
  // @ts-expect-error: Incorrect type
73
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
69
74
  const index = lastImportDeclarationPath?.name ?? -1;
75
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
70
76
  nodes.splice(index + 1, 0, AST.builders.importDeclaration([AST.builders.importDefaultSpecifier(AST.builders.identifier('styles'))], AST.builders.literal(`./${data.fileName}.css`)));
71
77
  return AST.print(ast);
72
78
  }
@@ -1,27 +1,23 @@
1
- /* eslint-disable @typescript-eslint/explicit-function-return-type, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */
2
1
  import { readFileSync } from 'node:fs';
3
2
  import { join } from 'node:path';
4
3
  import { AST } from '@codemod-utils/ast-template';
5
4
  import { createFiles } from '@codemod-utils/files';
6
5
  function sanitizeClassAndLocalClassAttributes(file) {
7
6
  function removeAttributeWithoutValue(attributeName, attributes) {
8
- const attributeIndex = attributes.findIndex(
9
- // @ts-expect-error: Incorrect type
10
- (attribute) => attribute.name === attributeName);
7
+ const attributeIndex = attributes.findIndex((attribute) => {
8
+ return attribute.name === attributeName;
9
+ });
11
10
  if (attributeIndex === -1) {
12
11
  return;
13
12
  }
14
13
  const attribute = attributes[attributeIndex];
15
- // @ts-expect-error: Incorrect type
16
14
  if (attribute.isValueless) {
17
15
  attributes.splice(attributeIndex, 1);
18
16
  return;
19
17
  }
20
- // @ts-expect-error: Incorrect type
21
18
  if (attribute.value.type !== 'TextNode') {
22
19
  return;
23
20
  }
24
- // @ts-expect-error: Incorrect type
25
21
  const attributeValue = attribute.value.chars.trim();
26
22
  if (attributeValue === '') {
27
23
  attributes.splice(attributeIndex, 1);
@@ -44,8 +40,12 @@ function mergeClassAndLocalClassAttributes(file) {
44
40
  ElementNode(node) {
45
41
  // Check that both class and local-class attributes exist
46
42
  const { attributes } = node;
47
- const localClassAttributeIndex = attributes.findIndex((attribute) => attribute.name === 'local-class');
48
- const classAttributeIndex = attributes.findIndex((attribute) => attribute.name === 'class');
43
+ const localClassAttributeIndex = attributes.findIndex((attribute) => {
44
+ return attribute.name === 'local-class';
45
+ });
46
+ const classAttributeIndex = attributes.findIndex((attribute) => {
47
+ return attribute.name === 'class';
48
+ });
49
49
  if (localClassAttributeIndex === -1 || classAttributeIndex === -1) {
50
50
  return;
51
51
  }
@@ -91,32 +91,33 @@ function removeLocalClassHelpers(file) {
91
91
  */
92
92
  function canRemoveLocalClassHelper(path) {
93
93
  // @ts-expect-error: Incorrect type
94
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
94
95
  const hasFromArgument = path.hash.pairs.some((pair) => pair.key === 'from');
95
96
  if (hasFromArgument) {
96
- throw new RangeError(
97
- // @ts-expect-error: Incorrect type
98
- `Unable to handle the {{local-class}} helper's \`from\` key. See lines ${path.loc.start.line}-${path.loc.end.line}.`);
97
+ throw new RangeError(`Unable to handle the {{local-class}} helper's \`from\` key. See lines ${path.loc.start.line}-${path.loc.end.line}.`);
99
98
  }
100
99
  // @ts-expect-error: Incorrect type
100
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
101
101
  const param = path.params[0];
102
102
  if (param === undefined) {
103
103
  return true;
104
104
  }
105
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
105
106
  if (param.type !== 'StringLiteral') {
106
107
  return false;
107
108
  }
109
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
108
110
  const value = param.value.trim();
109
111
  return value === '';
110
112
  }
111
113
  const traverse = AST.traverse();
112
114
  const ast = traverse(file, {
113
- // @ts-expect-error: Incorrect type
114
115
  AttrNode(node) {
115
116
  if (node.name !== 'class') {
116
117
  return;
117
118
  }
118
119
  const hasLocalClassHelper = node.value.type === 'MustacheStatement' &&
119
- // @ts-expect-error: Incorrect type
120
+ node.value.path.type === 'PathExpression' &&
120
121
  node.value.path.original === 'local-class';
121
122
  if (!hasLocalClassHelper) {
122
123
  return;
@@ -125,23 +126,32 @@ function removeLocalClassHelpers(file) {
125
126
  return null;
126
127
  }
127
128
  // @ts-expect-error: Incorrect type
129
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
128
130
  const param = node.value.params[0];
131
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
129
132
  if (param.type !== 'StringLiteral') {
130
133
  return;
131
134
  }
135
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
132
136
  const localClassNames = param.value.trim().split(/\s+/);
137
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
133
138
  if (localClassNames.length === 1) {
134
- node.value = AST.builders.mustache(AST.builders.path(`this.styles.${localClassNames[0]}`));
139
+ node.value = AST.builders.mustache(
140
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
141
+ AST.builders.path(`this.styles.${localClassNames[0]}`));
135
142
  return;
136
143
  }
137
144
  node.value = AST.builders.mustache(AST.builders.path('local'), [
138
145
  AST.builders.path('this.styles'),
146
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
139
147
  ...localClassNames.map(AST.builders.string),
140
148
  ]);
149
+ return;
141
150
  },
142
151
  MustacheStatement(node) {
143
- if (node.path.type !== 'PathExpression' ||
144
- node.path.original !== 'local-class') {
152
+ const hasLocalClassHelper = node.path.type === 'PathExpression' &&
153
+ node.path.original === 'local-class';
154
+ if (!hasLocalClassHelper) {
145
155
  return;
146
156
  }
147
157
  const param = node.params[0];
@@ -158,8 +168,8 @@ function removeLocalClassHelpers(file) {
158
168
  ]);
159
169
  },
160
170
  SubExpression(node) {
161
- // @ts-expect-error: Incorrect type
162
- const hasLocalClassHelper = node.path.original === 'local-class';
171
+ const hasLocalClassHelper = node.path.type === 'PathExpression' &&
172
+ node.path.original === 'local-class';
163
173
  if (!hasLocalClassHelper) {
164
174
  return;
165
175
  }
@@ -183,60 +193,56 @@ function removeLocalClassHelpers(file) {
183
193
  return AST.print(ast);
184
194
  }
185
195
  function removeLocalClassAttributes(file) {
186
- function transformParam(param) {
187
- // @ts-expect-error: Incorrect type
188
- switch (param.type) {
196
+ function transformExpression(expression) {
197
+ switch (expression.type) {
189
198
  case 'StringLiteral': {
190
- // @ts-expect-error: Incorrect type
191
- const localClassNames = param.value.trim().split(/\s+/);
199
+ const localClassNames = expression.value.trim().split(/\s+/);
192
200
  if (localClassNames.length === 1) {
193
- // @ts-expect-error: Incorrect type
194
- param.value = localClassNames[0];
201
+ expression.value = localClassNames[0];
195
202
  }
196
203
  else {
197
- param = AST.builders.sexpr('array', localClassNames.map(AST.builders.string));
204
+ expression = AST.builders.sexpr('array', localClassNames.map(AST.builders.string));
198
205
  }
199
206
  break;
200
207
  }
201
208
  case 'SubExpression': {
202
- // @ts-expect-error: Incorrect type
203
- switch (param.path.original) {
209
+ if (expression.path.type !== 'PathExpression') {
210
+ break;
211
+ }
212
+ switch (expression.path.original) {
204
213
  case 'if':
205
214
  case 'unless': {
206
- // @ts-expect-error: Incorrect type
207
- const subparams = param.params.map(transformParam);
208
- // @ts-expect-error: Incorrect type
209
- param = AST.builders.sexpr(param.path.original, subparams);
215
+ const subparams = expression.params.map(transformExpression);
216
+ expression = AST.builders.sexpr(expression.path.original, subparams);
210
217
  break;
211
218
  }
212
219
  }
213
220
  break;
214
221
  }
215
222
  }
216
- return param;
223
+ return expression;
217
224
  }
218
- // @ts-expect-error: Incorrect type
219
225
  function transformPart(part) {
220
- // @ts-expect-error: Incorrect type
221
226
  switch (part.type) {
222
227
  case 'MustacheStatement': {
223
- // @ts-expect-error: Incorrect type
228
+ if (part.path.type === 'SubExpression') {
229
+ return AST.builders.mustache(AST.builders.path('get'), [
230
+ AST.builders.path('this.styles'),
231
+ part.path,
232
+ ]);
233
+ }
224
234
  switch (part.path.original) {
225
235
  case 'concat': {
226
236
  function hasPathExpression(params) {
227
- // @ts-expect-error: Incorrect type
228
237
  return params.some((param) => param.type === 'PathExpression');
229
238
  }
230
- // @ts-expect-error: Incorrect type
231
239
  if (hasPathExpression(part.params)) {
232
240
  return AST.builders.mustache(AST.builders.path('get'), [
233
241
  AST.builders.path('this.styles'),
234
- // @ts-expect-error: Incorrect type
235
242
  AST.builders.sexpr(part.path.original, part.params),
236
243
  ]);
237
244
  }
238
- // @ts-expect-error: Incorrect type
239
- const params = part.params.map(transformParam);
245
+ const params = part.params.map(transformExpression);
240
246
  return AST.builders.mustache('local', [
241
247
  AST.builders.path('this.styles'),
242
248
  ...params,
@@ -244,25 +250,21 @@ function removeLocalClassAttributes(file) {
244
250
  }
245
251
  case 'if':
246
252
  case 'unless': {
247
- // @ts-expect-error: Incorrect type
248
- const params = part.params.map(transformParam);
253
+ const params = part.params.map(transformExpression);
249
254
  return AST.builders.mustache('local', [
250
255
  AST.builders.path('this.styles'),
251
- // @ts-expect-error: Incorrect type
252
256
  AST.builders.sexpr(part.path.original, params),
253
257
  ]);
254
258
  }
255
259
  default: {
256
260
  return AST.builders.mustache(AST.builders.path('get'), [
257
261
  AST.builders.path('this.styles'),
258
- // @ts-expect-error: Incorrect type
259
262
  part.path,
260
263
  ]);
261
264
  }
262
265
  }
263
266
  }
264
267
  case 'TextNode': {
265
- // @ts-expect-error: Incorrect type
266
268
  const value = part.chars.trim();
267
269
  if (value === '') {
268
270
  return part;
@@ -281,10 +283,8 @@ function removeLocalClassAttributes(file) {
281
283
  function transformParts(parts) {
282
284
  const numParts = parts.length;
283
285
  return parts.reduce((accumulator, part, index) => {
284
- // @ts-expect-error: Incorrect type
285
286
  accumulator.push(transformPart(part));
286
287
  if (index < numParts - 1) {
287
- // @ts-expect-error: Incorrect type
288
288
  accumulator.push(AST.builders.text(' '));
289
289
  }
290
290
  return accumulator;
@@ -310,13 +310,11 @@ function removeLocalClassAttributes(file) {
310
310
  }
311
311
  case 'MustacheStatement': {
312
312
  localClassAttribute.name = 'class';
313
- // @ts-expect-error: Incorrect type
314
313
  localClassAttribute.value = transformPart(localClassAttribute.value);
315
314
  break;
316
315
  }
317
316
  case 'TextNode': {
318
317
  localClassAttribute.name = 'class';
319
- // @ts-expect-error: Incorrect type
320
318
  localClassAttribute.value = transformPart(localClassAttribute.value);
321
319
  break;
322
320
  }
@@ -327,17 +325,13 @@ function removeLocalClassAttributes(file) {
327
325
  return;
328
326
  }
329
327
  node.key = 'class';
330
- const newValue = transformParam(node.value);
331
- // @ts-expect-error: Incorrect type
328
+ const newValue = transformExpression(node.value);
332
329
  if (newValue.type === 'StringLiteral') {
333
- node.value = AST.builders.path(
334
- // @ts-expect-error: Incorrect type
335
- `this.styles.${newValue.value}`);
330
+ node.value = AST.builders.path(`this.styles.${newValue.value}`);
336
331
  return;
337
332
  }
338
333
  node.value = AST.builders.sexpr('local', [
339
334
  AST.builders.path('this.styles'),
340
- // @ts-expect-error: Incorrect type
341
335
  newValue,
342
336
  ]);
343
337
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-codemod-remove-ember-css-modules",
3
- "version": "4.0.2",
3
+ "version": "4.0.4",
4
4
  "description": "Codemod to replace ember-css-modules with embroider-css-modules",
5
5
  "keywords": [
6
6
  "codemod",
@@ -26,23 +26,23 @@
26
26
  "dependencies": {
27
27
  "@codemod-utils/ast-javascript": "^3.0.1",
28
28
  "@codemod-utils/ast-template": "^3.0.1",
29
- "@codemod-utils/blueprints": "^3.0.2",
29
+ "@codemod-utils/blueprints": "^3.1.0",
30
30
  "@codemod-utils/ember": "^4.1.1",
31
31
  "@codemod-utils/files": "^4.0.1",
32
- "@codemod-utils/package-json": "^4.0.1",
32
+ "@codemod-utils/package-json": "^4.0.2",
33
33
  "yargs": "^18.0.0"
34
34
  },
35
35
  "devDependencies": {
36
- "@codemod-utils/tests": "^3.0.1",
36
+ "@codemod-utils/tests": "^3.0.2",
37
37
  "@sondr3/minitest": "^0.1.2",
38
- "@types/node": "^22.19.15",
38
+ "@types/node": "^22.19.17",
39
39
  "@types/yargs": "^17.0.35",
40
40
  "concurrently": "^9.2.1",
41
41
  "eslint": "^9.39.4",
42
- "prettier": "^3.8.1",
42
+ "prettier": "^3.8.3",
43
43
  "typescript": "^5.9.3",
44
- "@shared-configs/eslint-config-node": "0.0.0",
45
44
  "@shared-configs/typescript": "0.0.0",
45
+ "@shared-configs/eslint-config-node": "0.0.0",
46
46
  "@shared-configs/prettier": "0.0.0"
47
47
  },
48
48
  "engines": {