ember-codemod-remove-ember-css-modules 1.2.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,9 +8,6 @@ _Codemod to replace `ember-css-modules` with `embroider-css-modules`_
8
8
  1. [Usage](#usage)
9
9
  - [Arguments](#arguments)
10
10
  - [Limitations](#limitations)
11
- 1. [How to refactor code](#how-to-refactor-code)
12
- - [Remove code inheritance](#remove-code-inheritance)
13
- - [Remove complex string concatenations](#remove-complex-string-concatenations)
14
11
  1. [Compatibility](#compatibility)
15
12
  1. [Contributing](#contributing)
16
13
  1. [License](#license)
@@ -21,30 +18,30 @@ _Codemod to replace `ember-css-modules` with `embroider-css-modules`_
21
18
  The codemod helps you:
22
19
 
23
20
  - Remove `ember-css-modules` syntax from an Embroider app
24
- - Set up `embroider-css-modules` on an Embroider app
25
21
  - Remove `ember-css-modules` syntax from a v2 addon
26
22
 
27
- It takes [`glint`](https://typed-ember.gitbook.io/glint/) into account, and preserves your code whenever possible.
23
+ It preserves your code whenever possible.
28
24
 
29
25
 
30
26
  ## Usage
31
27
 
32
28
  You can find a migration example in [`ember-container-query`](https://github.com/ijlee2/ember-container-query/pull/167).
33
29
 
34
- Step 1. Quickly migrate to [`embroider-css-modules`](https://github.com/ijlee2/embroider-css-modules).<sup>1</sup>
30
+ Step 1. Quickly remove `ember-css-modules` syntax.<sup>1</sup>
35
31
 
36
32
  ```sh
37
33
  cd <path/to/your/project>
38
34
  npx ember-codemod-remove-ember-css-modules <arguments>
39
35
  ```
40
36
 
41
- Step 2. Review the project.
37
+ Manually remove the remaining instances of `local-class` attributes and `{{local-class}}` helpers.
42
38
 
43
- - [x] Update the configuration files.<sup>2</sup>
44
- - [x] Remove the remaining instances of `local-class` attributes and `{{local-class}}` helpers from `ember-css-modules`.
39
+ Step 2. Update project configurations.<sup>2</sup>
40
+
41
+ - [x] Set up CSS modules (see the guides for [apps](../../docs/written-guides/set-up-css-modules-apps-built-with-webpack.md) and [v2 addons](../../docs/written-guides/set-up-css-modules-v2-addons.md)).
45
42
  - [x] Confirm that you can run all scripts in `package.json`.
46
43
 
47
- <sup>1. Some prerequisites for running the codemod: First, migrate to the Octane layout (flat or nested). You can leverage codemods for [classic](https://github.com/ember-codemods/ember-component-template-colocation-migrator) and [pod](https://github.com/ijlee2/ember-codemod-pod-to-octane) layouts. Second, [refactor code](#how-to-refactor-code) to help the codemod update templates correctly.</sup>
44
+ <sup>1. Some prerequisites for running the codemod: First, migrate to the Octane layout (flat or nested). You can leverage codemods for [classic](https://github.com/ember-codemods/ember-component-template-colocation-migrator) and [pod](https://github.com/ijlee2/ember-codemod-pod-to-octane) layouts. Second, [refactor code](../../docs/refactor-code.md) to help the codemod update templates correctly.</sup>
48
45
 
49
46
  <sup>2. Files such as `.eslintrc.js`, `.prettierrc.js`, `.stylelintrc.js`, `.template-lintrc.js`, `ember-cli-build.js`, `package.json`, `postcss.config.js`, `tsconfig.json`, etc.</sup>
50
47
 
@@ -63,7 +60,7 @@ npx ember-codemod-remove-ember-css-modules --type v2-addon
63
60
 
64
61
  <summary>Optional: Specify the component structure</summary>
65
62
 
66
- By default, an Octane project has the flat component structure. Pass `--component-structure` to indicate otherwise.
63
+ By default, an Embroider project has the flat component structure. Pass `--component-structure` to indicate otherwise.
67
64
 
68
65
  ```sh
69
66
  npx ember-codemod-remove-ember-css-modules --component-structure nested
@@ -92,7 +89,7 @@ The codemod is designed to cover typical uses of `ember-css-modules`. It is not
92
89
 
93
90
  <summary>V2 Addons</summary>
94
91
 
95
- The codemod updates components only. Please see [Set up CSS modules (v2 addons)](../../docs/written-guides/set-up-css-modules-v2-addons.md) to set up `embroider-css-modules`.
92
+ The codemod updates components only.
96
93
 
97
94
  </details>
98
95
 
@@ -109,167 +106,6 @@ pnpm build
109
106
  ```
110
107
 
111
108
 
112
- ## How to refactor code
113
-
114
- ### Remove code inheritance
115
-
116
- `ember-css-modules` allows composing (really, inheriting) CSS code in two ways:
117
-
118
- - `composes: ... from '...';` in `*.css`
119
- - `{{local-class ... from="..."}}` in `*.hbs`
120
-
121
- The first syntax will continue to work in an Embroider app, provided that the import path is either `global` or a relative path.
122
-
123
- ```css
124
- /* app/components/ui/form/textarea.css */
125
- .textarea {
126
- composes: input from "./input.css";
127
- }
128
-
129
- .is-disabled {
130
- composes: input-disabled from global;
131
- }
132
-
133
- /* These do not work */
134
- .textarea {
135
- composes: input from "my-app/components/ui/form/input.css";
136
- }
137
-
138
- .textarea {
139
- composes: input from "my-v2-addon/components/ui/form/input.css";
140
- }
141
- ```
142
-
143
- The second syntax isn't supported by the `{{local}}` helper from `embroider-css-modules`, so you will need to update the template and stylesheet accordingly.
144
-
145
- However, note that the presence of `composes` (in a set of related components) may indicate a premature abstraction and an incorrect component design. Ideally, you might duplicate the CSS, then refactor the components. If short on time, you can import the relevant `styles` object in the backing class.
146
-
147
- <details>
148
-
149
- <summary>Before, with <code>ember-css-modules</code></summary>
150
-
151
- Case 1:
152
-
153
- ```hbs
154
- {{! app/components/ui/form/textarea.hbs }}
155
- <textarea
156
- class={{local-class "input" from="my-app/components/ui/form/input.css"}}
157
- />
158
- ```
159
-
160
- Case 2:
161
-
162
- ```css
163
- /* app/components/ui/form/textarea.css */
164
- .textarea {
165
- composes: input from "my-app/components/ui/form/input.css";
166
- }
167
- ```
168
-
169
- ```hbs
170
- {{! app/components/ui/form/textarea.hbs }}
171
- <textarea
172
- local-class="textarea"
173
- />
174
- ```
175
-
176
- </details>
177
-
178
- <details>
179
-
180
- <summary>After, with <code>embroider-css-modules</code></summary>
181
-
182
- ```ts
183
- /* app/components/ui/form/textarea.ts */
184
- import Component from '@glimmer/component';
185
-
186
- import inputStyles from './input.css';
187
- import styles from './textarea.css';
188
-
189
- export default class UiFormTextareaComponent extends Component {
190
- inputStyles = inputStyles;
191
- styles = styles;
192
- }
193
- ```
194
-
195
- ```hbs
196
- {{! app/components/ui/form/textarea.hbs }}
197
- <textarea
198
- class={{this.inputStyles.input}}
199
- />
200
- ```
201
-
202
- </details>
203
-
204
-
205
- ### Remove complex string concatenations
206
-
207
- In `ember-css-modules`, a string can represent multiple local class names via concatenation. In `embroider-css-modules`, each string represents exactly one.
208
-
209
- <details>
210
-
211
- <summary>Before, with <code>ember-css-modules</code></summary>
212
-
213
- ```hbs
214
- {{! app/components/ui/form/textarea.hbs }}
215
- <textarea
216
- local-class="
217
- textarea
218
- {{if (or @isDisabled @isReadOnly) 'is-disabled'}}
219
- "
220
- />
221
- ```
222
-
223
- </details>
224
-
225
- <details>
226
-
227
- <summary>After, with <code>embroider-css-modules</code></summary>
228
-
229
- ```hbs
230
- {{! app/components/ui/form/textarea.hbs }}
231
- <textarea
232
- class={{local-class
233
- this.styles
234
- "textarea"
235
- (if (or @isDisabled @isReadOnly) "is-disabled")
236
- }}
237
- />
238
- ```
239
-
240
- </details>
241
-
242
- The codemod may fail to update complex expressions. Refactor templates to provide hints. For example, remove nested conditionals (apply them outside the HTML element) and use the `{{concat}}` helper to group substrings.
243
-
244
- <details>
245
-
246
- <summary>Before refactor, with <code>ember-css-modules</code></summary>
247
-
248
- ```hbs
249
- {{! app/components/ui/form/phone.hbs }}
250
- <input
251
- local-class="input flag-{{@country}}"
252
- type="tel"
253
- />
254
- ```
255
-
256
- </details>
257
-
258
- <details>
259
-
260
- <summary>After refactor, with <code>ember-css-modules</code></summary>
261
-
262
- ```hbs
263
- {{! app/components/ui/form/phone.hbs }}
264
- <input
265
- local-class="input {{concat 'flag-' @country}}"
266
- type="tel"
267
- />
268
- ```
269
-
270
- </details>
271
-
272
-
273
109
  ## Compatibility
274
110
 
275
111
  - Node.js v18 or above
@@ -1,12 +1,7 @@
1
1
  import { createOptions } from '../../utils/steps/create-options.js';
2
- import { analyzeProject, importStylesInComponents, importStylesInRoutes, moveStylesheets, updateAppAppJs, updateComponentTemplates, updatePackageJson, updateRouteTemplates, } from './steps/index.js';
2
+ import { analyzeProject, importStylesInComponents, importStylesInRoutes, moveStylesheets, updateComponentTemplates, updateRouteTemplates, } from './steps/index.js';
3
3
  export function migrateEmberApp(codemodOptions) {
4
4
  const options = createOptions(codemodOptions);
5
- const { hasEmberCssModules } = options.project;
6
- // Guarantee idempotency
7
- if (!hasEmberCssModules) {
8
- return;
9
- }
10
5
  // Prepare for migration
11
6
  const context = analyzeProject(options);
12
7
  // Import styles in classes
@@ -16,7 +11,4 @@ export function migrateEmberApp(codemodOptions) {
16
11
  // Update templates
17
12
  updateComponentTemplates(context, options);
18
13
  updateRouteTemplates(context, options);
19
- // Fine-tune individual files
20
- updateAppAppJs(options);
21
- updatePackageJson(options);
22
14
  }
@@ -2,7 +2,5 @@ export * from './analyze-project.js';
2
2
  export * from './import-styles-in-components.js';
3
3
  export * from './import-styles-in-routes.js';
4
4
  export * from './move-stylesheets.js';
5
- export * from './update-app-app-js.js';
6
5
  export * from './update-component-templates.js';
7
- export * from './update-package-json.js';
8
6
  export * from './update-route-templates.js';
@@ -1,4 +1,11 @@
1
1
  import { createFiles, findFiles, mapFilePaths, moveFiles, } from '@codemod-utils/files';
2
+ function canSkip(options) {
3
+ const { projectRoot } = options;
4
+ const filePaths = findFiles('app/assets/app.css', {
5
+ projectRoot,
6
+ });
7
+ return filePaths.length === 1;
8
+ }
2
9
  function moveRouteStylesheets(options) {
3
10
  const { projectRoot } = options;
4
11
  const filePaths = findFiles('app/styles/**/*.css', {
@@ -12,6 +19,9 @@ function moveRouteStylesheets(options) {
12
19
  moveFiles(pathMapping, options);
13
20
  }
14
21
  function moveAppCssToAssets(options) {
22
+ if (canSkip(options)) {
23
+ return;
24
+ }
15
25
  const { projectRoot } = options;
16
26
  const filePaths = findFiles('app/styles/app.css', {
17
27
  projectRoot,
@@ -1,2 +1 @@
1
1
  export * from './blueprints/blueprints-root.js';
2
- export * from './blueprints/get-version.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-codemod-remove-ember-css-modules",
3
- "version": "1.2.0",
3
+ "version": "2.0.1",
4
4
  "description": "Codemod to replace ember-css-modules with embroider-css-modules",
5
5
  "keywords": [
6
6
  "codemod",
@@ -26,26 +26,26 @@
26
26
  "dist"
27
27
  ],
28
28
  "dependencies": {
29
- "@codemod-utils/ast-javascript": "^1.2.3",
30
- "@codemod-utils/ast-template": "^1.1.1",
31
- "@codemod-utils/blueprints": "^1.1.1",
32
- "@codemod-utils/ember-cli-string": "^1.1.1",
33
- "@codemod-utils/files": "^1.1.1",
34
- "@codemod-utils/json": "^1.1.4",
29
+ "@codemod-utils/ast-javascript": "^1.2.4",
30
+ "@codemod-utils/ast-template": "^1.1.2",
31
+ "@codemod-utils/blueprints": "^1.1.2",
32
+ "@codemod-utils/ember-cli-string": "^1.1.2",
33
+ "@codemod-utils/files": "^2.0.0",
34
+ "@codemod-utils/json": "^1.1.5",
35
35
  "yargs": "^17.7.2"
36
36
  },
37
37
  "devDependencies": {
38
- "@codemod-utils/tests": "^1.1.2",
38
+ "@codemod-utils/tests": "^1.1.3",
39
39
  "@sondr3/minitest": "^0.1.2",
40
- "@types/node": "^18.19.23",
40
+ "@types/node": "^18.19.24",
41
41
  "@types/yargs": "^17.0.32",
42
42
  "concurrently": "^8.2.2",
43
43
  "eslint": "^8.57.0",
44
44
  "prettier": "^3.2.5",
45
45
  "typescript": "^5.4.2",
46
+ "@shared-configs/prettier": "0.0.0",
46
47
  "@shared-configs/eslint-config-node": "0.0.0",
47
- "@shared-configs/typescript": "0.0.0",
48
- "@shared-configs/prettier": "0.0.0"
48
+ "@shared-configs/typescript": "0.0.0"
49
49
  },
50
50
  "engines": {
51
51
  "node": "18.* || >= 20"
@@ -1,46 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { extname, join } from 'node:path';
3
- import { AST } from '@codemod-utils/ast-javascript';
4
- import { createFiles, findFiles } from '@codemod-utils/files';
5
- function addCssEntryPoint(file, data) {
6
- const traverse = AST.traverse(data.isTypeScript);
7
- const ast = traverse(file, {
8
- visitProgram(path) {
9
- const nodesToAdd = [
10
- AST.builders.importDeclaration([], AST.builders.literal('./assets/app.css')),
11
- AST.builders.noop(),
12
- ];
13
- path.value.body.unshift(...nodesToAdd);
14
- return false;
15
- },
16
- });
17
- return AST.print(ast);
18
- }
19
- export function updateAppAppJs(options) {
20
- const { projectRoot } = options;
21
- const filePaths = findFiles('app/app.{js,ts}', {
22
- projectRoot,
23
- });
24
- if (filePaths.length !== 1) {
25
- console.warn('WARNING: updateAppAppJs could not find app.{js,ts} in the app folder. Will skip this step.\n');
26
- return;
27
- }
28
- const filePath = filePaths[0];
29
- const fileExtension = extname(filePath);
30
- const data = {
31
- isTypeScript: fileExtension === '.ts',
32
- };
33
- try {
34
- let file = readFileSync(join(projectRoot, filePath), 'utf8');
35
- file = addCssEntryPoint(file, data);
36
- const fileMap = new Map([[filePath, file]]);
37
- createFiles(fileMap, options);
38
- }
39
- catch (error) {
40
- let message = `WARNING: updateAppAppJs could not update \`${filePath}\`. Please update the file manually.`;
41
- if (error instanceof Error) {
42
- message += ` (${error.message})`;
43
- }
44
- console.warn(`${message}\n`);
45
- }
46
- }
@@ -1,47 +0,0 @@
1
- import { writeFileSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- import { convertToMap, convertToObject, readPackageJson, } from '@codemod-utils/json';
4
- import { getVersion } from '../../../utils/blueprints.js';
5
- function updateDevDependencies(packageJson, options) {
6
- const { project } = options;
7
- const devDependencies = convertToMap(packageJson['devDependencies']);
8
- const packagesToDelete = ['ember-css-modules'];
9
- packagesToDelete.forEach((packageName) => {
10
- devDependencies.delete(packageName);
11
- });
12
- const packagesToInstall = new Set([
13
- '@embroider/compat',
14
- '@embroider/core',
15
- '@embroider/webpack',
16
- 'autoprefixer',
17
- 'embroider-css-modules',
18
- 'postcss',
19
- 'postcss-loader',
20
- 'webpack',
21
- ]);
22
- if (project.hasTypeScript) {
23
- packagesToInstall.add('type-css-modules');
24
- }
25
- [...packagesToInstall].sort().forEach((packageName) => {
26
- const version = getVersion(packageName, options);
27
- devDependencies.set(packageName, version);
28
- });
29
- packageJson['devDependencies'] = convertToObject(devDependencies);
30
- }
31
- function updateScripts(packageJson, options) {
32
- const { project } = options;
33
- const scripts = convertToMap(packageJson.scripts);
34
- if (project.hasTypeScript) {
35
- scripts.set('prelint:types', 'type-css-modules --src app');
36
- }
37
- packageJson['scripts'] = convertToObject(scripts);
38
- }
39
- export function updatePackageJson(options) {
40
- const { projectRoot } = options;
41
- const packageJson = readPackageJson(options);
42
- updateDevDependencies(packageJson, options);
43
- updateScripts(packageJson, options);
44
- const destination = join(projectRoot, 'package.json');
45
- const file = JSON.stringify(packageJson, null, 2) + '\n';
46
- writeFileSync(destination, file, 'utf8');
47
- }
@@ -1,19 +0,0 @@
1
- import { decideVersion } from '@codemod-utils/blueprints';
2
- const latestVersions = new Map([
3
- ['@embroider/compat', '3.2.1'],
4
- ['@embroider/core', '3.2.1'],
5
- ['@embroider/webpack', '3.1.5'],
6
- ['autoprefixer', '10.4.15'],
7
- ['embroider-css-modules', '1.0.0'],
8
- ['postcss', '8.4.29'],
9
- ['postcss-loader', '7.3.3'],
10
- ['type-css-modules', '1.0.0'],
11
- ['webpack', '5.88.2'],
12
- ]);
13
- export function getVersion(packageName, options) {
14
- const { project } = options;
15
- return decideVersion(packageName, {
16
- dependencies: project.dependencies,
17
- latestVersions,
18
- });
19
- }