ember-codemod-remove-ember-css-modules 1.1.3 → 2.0.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 +34 -176
- package/dist/bin/ember-codemod-remove-ember-css-modules.js +7 -0
- package/dist/src/index.js +11 -2
- package/dist/src/migration/ember-app/index.js +3 -10
- package/dist/src/migration/ember-app/steps/{analyze-app → analyze-project}/analyze-components.js +1 -1
- package/dist/src/migration/ember-app/steps/{analyze-app → analyze-project}/analyze-routes.js +1 -1
- package/dist/src/migration/ember-app/steps/analyze-project.js +7 -0
- package/dist/src/migration/ember-app/steps/import-styles-in-components.js +1 -1
- package/dist/src/migration/ember-app/steps/import-styles-in-routes.js +1 -1
- package/dist/src/migration/ember-app/steps/index.js +1 -4
- package/dist/src/migration/ember-app/steps/move-stylesheets.js +10 -0
- package/dist/src/migration/ember-app/steps/update-component-templates.js +1 -1
- package/dist/src/migration/ember-app/steps/update-route-templates.js +1 -1
- package/dist/src/migration/ember-v2-addon/index.js +8 -0
- package/dist/src/migration/ember-v2-addon/steps/analyze-project/analyze-components.js +43 -0
- package/dist/src/migration/ember-v2-addon/steps/analyze-project/index.js +1 -0
- package/dist/src/migration/ember-v2-addon/steps/analyze-project.js +7 -0
- package/dist/src/migration/ember-v2-addon/steps/import-styles-in-components.js +35 -0
- package/dist/src/migration/ember-v2-addon/steps/index.js +3 -0
- package/dist/src/migration/ember-v2-addon/steps/update-component-templates.js +22 -0
- package/dist/src/migration/index.js +1 -0
- package/dist/src/utils/blueprints.js +0 -1
- package/dist/src/{migration/ember-app → utils}/steps/create-options.js +5 -4
- package/dist/src/{migration/ember-app → utils}/steps/import-styles/create-class.js +1 -1
- package/dist/src/{migration/ember-app → utils}/steps/import-styles/update-class.js +16 -0
- package/package.json +6 -6
- package/dist/src/migration/ember-app/steps/analyze-app.js +0 -7
- package/dist/src/migration/ember-app/steps/update-app-app-js.js +0 -46
- package/dist/src/migration/ember-app/steps/update-package-json.js +0 -47
- package/dist/src/utils/blueprints/get-version.js +0 -19
- /package/dist/src/migration/ember-app/steps/{analyze-app → analyze-project}/index.js +0 -0
- /package/dist/src/{migration/ember-app/steps/analyze-app → utils/steps/analyze-project}/analyze-file-paths.js +0 -0
- /package/dist/src/{migration/ember-app → utils}/steps/import-styles/index.js +0 -0
- /package/dist/src/{migration/ember-app → utils}/steps/update-templates/index.js +0 -0
- /package/dist/src/{migration/ember-app → utils}/steps/update-templates/update-template.js +0 -0
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)
|
|
@@ -18,235 +15,96 @@ _Codemod to replace `ember-css-modules` with `embroider-css-modules`_
|
|
|
18
15
|
|
|
19
16
|
## Features
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
18
|
+
The codemod helps you:
|
|
19
|
+
|
|
20
|
+
- Remove `ember-css-modules` syntax from an Embroider app
|
|
21
|
+
- Remove `ember-css-modules` syntax from a v2 addon
|
|
22
|
+
|
|
23
|
+
It preserves your code whenever possible.
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
## Usage
|
|
27
27
|
|
|
28
|
-
You can
|
|
28
|
+
You can find a migration example in [`ember-container-query`](https://github.com/ijlee2/ember-container-query/pull/167).
|
|
29
29
|
|
|
30
|
-
Step 1. Quickly
|
|
30
|
+
Step 1. Quickly remove `ember-css-modules` syntax.<sup>1</sup>
|
|
31
31
|
|
|
32
32
|
```sh
|
|
33
33
|
cd <path/to/your/project>
|
|
34
34
|
npx 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.
|
|
38
|
+
|
|
39
|
+
Step 2. Update project configurations.
|
|
38
40
|
|
|
39
|
-
- [x]
|
|
40
|
-
- [x] Remove the remaining instances of `local-class` attributes and `{{local-class}}` helpers from `ember-css-modules`.
|
|
41
|
+
- [x] Set up CSS modules (see the guides for [apps](../../docs/written-guides/set-up-css-modules-apps.md) and [v2 addons](../../docs/written-guides/set-up-css-modules-v2-addons.md)).
|
|
41
42
|
- [x] Confirm that you can run all scripts in `package.json`.
|
|
42
43
|
|
|
43
|
-
<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](
|
|
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>
|
|
44
45
|
|
|
45
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>
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
### Arguments
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
<summary>Optional: Specify the component structure</summary>
|
|
52
|
-
|
|
53
|
-
By default, an Octane project has the flat component structure. Pass `--component-structure` to indicate otherwise.
|
|
51
|
+
You must pass `--type` to indicate what type of project you have.
|
|
54
52
|
|
|
55
53
|
```sh
|
|
56
|
-
npx ember-codemod-remove-ember-css-modules --
|
|
54
|
+
npx ember-codemod-remove-ember-css-modules --type app
|
|
55
|
+
npx ember-codemod-remove-ember-css-modules --type v2-addon
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
</details>
|
|
60
58
|
|
|
61
59
|
<details>
|
|
62
|
-
<summary>Optional: Specify the project root</summary>
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```sh
|
|
67
|
-
npx ember-codemod-remove-ember-css-modules --root=<path/to/your/project>
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
</details>
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
### Limitations
|
|
74
|
-
|
|
75
|
-
The codemod is designed to cover typical uses of `ember-css-modules`. It is not designed to cover one-off cases.
|
|
61
|
+
<summary>Optional: Specify the component structure</summary>
|
|
76
62
|
|
|
77
|
-
|
|
63
|
+
By default, an Embroider project has the flat component structure. Pass `--component-structure` to indicate otherwise.
|
|
78
64
|
|
|
79
65
|
```sh
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# Compile TypeScript
|
|
83
|
-
pnpm build
|
|
84
|
-
|
|
85
|
-
# Run codemod
|
|
86
|
-
./dist/bin/ember-codemod-remove-ember-css-modules.js --root=<path/to/your/project>
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
## How to refactor code
|
|
91
|
-
|
|
92
|
-
### Remove code inheritance
|
|
93
|
-
|
|
94
|
-
`ember-css-modules` allows composing (really, inheriting) CSS code in two ways:
|
|
95
|
-
|
|
96
|
-
- `composes: ... from '...';` in `*.css`
|
|
97
|
-
- `{{local-class ... from="..."}}` in `*.hbs`
|
|
98
|
-
|
|
99
|
-
The first syntax will continue to work in an Embroider app, provided that the import path is either `global` or a relative path.
|
|
100
|
-
|
|
101
|
-
```css
|
|
102
|
-
/* app/components/ui/form/textarea.css */
|
|
103
|
-
.textarea {
|
|
104
|
-
composes: input from "./input.css";
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.is-disabled {
|
|
108
|
-
composes: input-disabled from global;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/* These do not work */
|
|
112
|
-
.textarea {
|
|
113
|
-
composes: input from "my-app/components/ui/form/input.css";
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
.textarea {
|
|
117
|
-
composes: input from "my-v2-addon/components/ui/form/input.css";
|
|
118
|
-
}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
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.
|
|
122
|
-
|
|
123
|
-
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.
|
|
124
|
-
|
|
125
|
-
<details>
|
|
126
|
-
|
|
127
|
-
<summary>Before, with <code>ember-css-modules</code></summary>
|
|
128
|
-
|
|
129
|
-
Case 1:
|
|
130
|
-
|
|
131
|
-
```hbs
|
|
132
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
133
|
-
<textarea
|
|
134
|
-
class={{local-class "input" from="my-app/components/ui/form/input.css"}}
|
|
135
|
-
/>
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
Case 2:
|
|
139
|
-
|
|
140
|
-
```css
|
|
141
|
-
/* app/components/ui/form/textarea.css */
|
|
142
|
-
.textarea {
|
|
143
|
-
composes: input from "my-app/components/ui/form/input.css";
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
```hbs
|
|
148
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
149
|
-
<textarea
|
|
150
|
-
local-class="textarea"
|
|
151
|
-
/>
|
|
66
|
+
npx ember-codemod-remove-ember-css-modules --component-structure nested
|
|
152
67
|
```
|
|
153
68
|
|
|
154
69
|
</details>
|
|
155
70
|
|
|
156
71
|
<details>
|
|
157
72
|
|
|
158
|
-
<summary>
|
|
159
|
-
|
|
160
|
-
```ts
|
|
161
|
-
/* app/components/ui/form/textarea.ts */
|
|
162
|
-
import Component from '@glimmer/component';
|
|
163
|
-
|
|
164
|
-
import inputStyles from './input.css';
|
|
165
|
-
import styles from './textarea.css';
|
|
73
|
+
<summary>Optional: Specify the project root</summary>
|
|
166
74
|
|
|
167
|
-
|
|
168
|
-
inputStyles = inputStyles;
|
|
169
|
-
styles = styles;
|
|
170
|
-
}
|
|
171
|
-
```
|
|
75
|
+
Pass `--root` to run the codemod on a project somewhere else (i.e. not in the current directory).
|
|
172
76
|
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
<textarea
|
|
176
|
-
class={{this.inputStyles.input}}
|
|
177
|
-
/>
|
|
77
|
+
```sh
|
|
78
|
+
npx ember-codemod-remove-ember-css-modules --root <path/to/your/project>
|
|
178
79
|
```
|
|
179
80
|
|
|
180
81
|
</details>
|
|
181
82
|
|
|
182
83
|
|
|
183
|
-
###
|
|
84
|
+
### Limitations
|
|
184
85
|
|
|
185
|
-
|
|
86
|
+
The codemod is designed to cover typical uses of `ember-css-modules`. It is not designed to cover one-off cases.
|
|
186
87
|
|
|
187
88
|
<details>
|
|
188
89
|
|
|
189
|
-
<summary>
|
|
190
|
-
|
|
191
|
-
```hbs
|
|
192
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
193
|
-
<textarea
|
|
194
|
-
local-class="
|
|
195
|
-
textarea
|
|
196
|
-
{{if (or @isDisabled @isReadOnly) 'is-disabled'}}
|
|
197
|
-
"
|
|
198
|
-
/>
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
</details>
|
|
202
|
-
|
|
203
|
-
<details>
|
|
90
|
+
<summary>V2 Addons</summary>
|
|
204
91
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
```hbs
|
|
208
|
-
{{! app/components/ui/form/textarea.hbs }}
|
|
209
|
-
<textarea
|
|
210
|
-
class={{local-class
|
|
211
|
-
this.styles
|
|
212
|
-
"textarea"
|
|
213
|
-
(if (or @isDisabled @isReadOnly) "is-disabled")
|
|
214
|
-
}}
|
|
215
|
-
/>
|
|
216
|
-
```
|
|
92
|
+
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`.
|
|
217
93
|
|
|
218
94
|
</details>
|
|
219
95
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
<details>
|
|
223
|
-
|
|
224
|
-
<summary>Before refactor, with <code>ember-css-modules</code></summary>
|
|
225
|
-
|
|
226
|
-
```hbs
|
|
227
|
-
{{! app/components/ui/form/phone.hbs }}
|
|
228
|
-
<input
|
|
229
|
-
local-class="input flag-{{@country}}"
|
|
230
|
-
type="tel"
|
|
231
|
-
/>
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
</details>
|
|
96
|
+
To better meet your needs, consider cloning the repo and running the codemod locally.
|
|
235
97
|
|
|
236
|
-
|
|
98
|
+
```sh
|
|
99
|
+
cd <path/to/cloned/repo>
|
|
237
100
|
|
|
238
|
-
|
|
101
|
+
# Compile TypeScript
|
|
102
|
+
pnpm build
|
|
239
103
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
<input
|
|
243
|
-
local-class="input {{concat 'flag-' @country}}"
|
|
244
|
-
type="tel"
|
|
245
|
-
/>
|
|
104
|
+
# Run codemod
|
|
105
|
+
./dist/bin/ember-codemod-remove-ember-css-modules.js --root=<path/to/your/project>
|
|
246
106
|
```
|
|
247
107
|
|
|
248
|
-
</details>
|
|
249
|
-
|
|
250
108
|
|
|
251
109
|
## Compatibility
|
|
252
110
|
|
|
@@ -17,10 +17,17 @@ const argv = yargs(hideBin(process.argv))
|
|
|
17
17
|
.option('root', {
|
|
18
18
|
describe: 'Location of your Ember project',
|
|
19
19
|
type: 'string',
|
|
20
|
+
})
|
|
21
|
+
.option('type', {
|
|
22
|
+
choices: ['app', 'v2-addon'],
|
|
23
|
+
demandOption: true,
|
|
24
|
+
describe: 'Type of your Ember project',
|
|
25
|
+
type: 'string',
|
|
20
26
|
})
|
|
21
27
|
.parseSync();
|
|
22
28
|
const codemodOptions = {
|
|
23
29
|
componentStructure: argv['component-structure'],
|
|
24
30
|
projectRoot: argv['root'] ?? process.cwd(),
|
|
31
|
+
projectType: argv['type'],
|
|
25
32
|
};
|
|
26
33
|
removeEmberCssModules(codemodOptions);
|
package/dist/src/index.js
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import { migrateEmberApp } from './migration/index.js';
|
|
1
|
+
import { migrateEmberApp, migrateEmberV2Addon } from './migration/index.js';
|
|
2
2
|
export function removeEmberCssModules(codemodOptions) {
|
|
3
|
-
|
|
3
|
+
switch (codemodOptions.projectType) {
|
|
4
|
+
case 'app': {
|
|
5
|
+
migrateEmberApp(codemodOptions);
|
|
6
|
+
break;
|
|
7
|
+
}
|
|
8
|
+
case 'v2-addon': {
|
|
9
|
+
migrateEmberV2Addon(codemodOptions);
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
4
13
|
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createOptions } from '../../utils/steps/create-options.js';
|
|
2
|
+
import { analyzeProject, importStylesInComponents, importStylesInRoutes, moveStylesheets, updateComponentTemplates, updateRouteTemplates, } from './steps/index.js';
|
|
2
3
|
export function migrateEmberApp(codemodOptions) {
|
|
3
4
|
const options = createOptions(codemodOptions);
|
|
4
|
-
const { hasEmberCssModules } = options.project;
|
|
5
|
-
// Guarantee idempotency
|
|
6
|
-
if (!hasEmberCssModules) {
|
|
7
|
-
return;
|
|
8
|
-
}
|
|
9
5
|
// Prepare for migration
|
|
10
|
-
const context =
|
|
6
|
+
const context = analyzeProject(options);
|
|
11
7
|
// Import styles in classes
|
|
12
8
|
moveStylesheets(options);
|
|
13
9
|
importStylesInComponents(context, options);
|
|
@@ -15,7 +11,4 @@ export function migrateEmberApp(codemodOptions) {
|
|
|
15
11
|
// Update templates
|
|
16
12
|
updateComponentTemplates(context, options);
|
|
17
13
|
updateRouteTemplates(context, options);
|
|
18
|
-
// Fine-tune individual files
|
|
19
|
-
updateAppAppJs(options);
|
|
20
|
-
updatePackageJson(options);
|
|
21
14
|
}
|
package/dist/src/migration/ember-app/steps/{analyze-app → analyze-project}/analyze-components.js
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findFiles, renamePathByDirectory } from '@codemod-utils/files';
|
|
2
|
-
import { analyzeFilePaths } from '
|
|
2
|
+
import { analyzeFilePaths } from '../../../../utils/steps/analyze-project/analyze-file-paths.js';
|
|
3
3
|
export function analyzeComponents(options) {
|
|
4
4
|
const { componentStructure, projectRoot } = options;
|
|
5
5
|
const classFilePaths = findFiles('app/components/**/*.{js,ts}', {
|
package/dist/src/migration/ember-app/steps/{analyze-app → analyze-project}/analyze-routes.js
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { findFiles, renamePathByDirectory } from '@codemod-utils/files';
|
|
2
|
-
import { analyzeFilePaths } from '
|
|
2
|
+
import { analyzeFilePaths } from '../../../../utils/steps/analyze-project/analyze-file-paths.js';
|
|
3
3
|
export function analyzeRoutes(options) {
|
|
4
4
|
const { projectRoot } = options;
|
|
5
5
|
const classFilePaths = findFiles('app/controllers/**/*.{js,ts}', {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
-
import { importStyles } from '
|
|
2
|
+
import { importStyles } from '../../../utils/steps/import-styles/index.js';
|
|
3
3
|
function getBlueprintFilePaths(options) {
|
|
4
4
|
const { project } = options;
|
|
5
5
|
if (project.hasTypeScript) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
-
import { importStyles } from '
|
|
2
|
+
import { importStyles } from '../../../utils/steps/import-styles/index.js';
|
|
3
3
|
function getBlueprintFilePaths(options) {
|
|
4
4
|
const { project } = options;
|
|
5
5
|
if (project.hasTypeScript) {
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
export * from './analyze-
|
|
2
|
-
export * from './create-options.js';
|
|
1
|
+
export * from './analyze-project.js';
|
|
3
2
|
export * from './import-styles-in-components.js';
|
|
4
3
|
export * from './import-styles-in-routes.js';
|
|
5
4
|
export * from './move-stylesheets.js';
|
|
6
|
-
export * from './update-app-app-js.js';
|
|
7
5
|
export * from './update-component-templates.js';
|
|
8
|
-
export * from './update-package-json.js';
|
|
9
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,5 +1,5 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
-
import { updateTemplates } from '
|
|
2
|
+
import { updateTemplates } from '../../../utils/steps/update-templates/index.js';
|
|
3
3
|
function getFilePath(options) {
|
|
4
4
|
const { componentStructure } = options;
|
|
5
5
|
return function (entityName) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
|
-
import { updateTemplates } from '
|
|
2
|
+
import { updateTemplates } from '../../../utils/steps/update-templates/index.js';
|
|
3
3
|
function getFilePath() {
|
|
4
4
|
return function (entityName) {
|
|
5
5
|
let filePath = join('app/templates', entityName);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createOptions } from '../../utils/steps/create-options.js';
|
|
2
|
+
import { analyzeProject, importStylesInComponents, updateComponentTemplates, } from './steps/index.js';
|
|
3
|
+
export function migrateEmberV2Addon(codemodOptions) {
|
|
4
|
+
const options = createOptions(codemodOptions);
|
|
5
|
+
const context = analyzeProject(options);
|
|
6
|
+
importStylesInComponents(context, options);
|
|
7
|
+
updateComponentTemplates(context, options);
|
|
8
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { findFiles, renamePathByDirectory } from '@codemod-utils/files';
|
|
2
|
+
import { analyzeFilePaths } from '../../../../utils/steps/analyze-project/analyze-file-paths.js';
|
|
3
|
+
export function analyzeComponents(options) {
|
|
4
|
+
const { componentStructure, projectRoot } = options;
|
|
5
|
+
const classFilePaths = findFiles('src/components/**/*.{js,ts}', {
|
|
6
|
+
ignoreList: ['src/components/**/*.d.ts'],
|
|
7
|
+
projectRoot,
|
|
8
|
+
}).map((filePath) => {
|
|
9
|
+
return renamePathByDirectory(filePath, {
|
|
10
|
+
from: 'src/components',
|
|
11
|
+
to: '',
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
const stylesheetFilePaths = findFiles('src/components/**/*.css', {
|
|
15
|
+
projectRoot,
|
|
16
|
+
}).map((filePath) => {
|
|
17
|
+
return renamePathByDirectory(filePath, {
|
|
18
|
+
from: 'src/components',
|
|
19
|
+
to: '',
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
const templateFilePaths = findFiles('src/components/**/*.hbs', {
|
|
23
|
+
projectRoot,
|
|
24
|
+
}).map((filePath) => {
|
|
25
|
+
return renamePathByDirectory(filePath, {
|
|
26
|
+
from: 'src/components',
|
|
27
|
+
to: '',
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
const filePaths = [
|
|
31
|
+
...classFilePaths,
|
|
32
|
+
...stylesheetFilePaths,
|
|
33
|
+
...templateFilePaths,
|
|
34
|
+
].sort();
|
|
35
|
+
const entities = analyzeFilePaths(filePaths);
|
|
36
|
+
if (componentStructure === 'nested') {
|
|
37
|
+
return new Map(Array.from(entities.entries()).map(([entityName, extensions]) => {
|
|
38
|
+
const newEntityName = entityName.replace(/\/index$/, '');
|
|
39
|
+
return [newEntityName, extensions];
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
return entities;
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './analyze-components.js';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { importStyles } from '../../../utils/steps/import-styles/index.js';
|
|
3
|
+
function getBlueprintFilePaths(options) {
|
|
4
|
+
const { project } = options;
|
|
5
|
+
if (project.hasTypeScript) {
|
|
6
|
+
return ['ember-cli/component/typescript.ts'];
|
|
7
|
+
}
|
|
8
|
+
return ['ember-cli/component/javascript.js'];
|
|
9
|
+
}
|
|
10
|
+
function getFilePath(options) {
|
|
11
|
+
const { componentStructure, project } = options;
|
|
12
|
+
return function (entityName) {
|
|
13
|
+
let filePath = join('src/components', entityName);
|
|
14
|
+
if (componentStructure === 'nested') {
|
|
15
|
+
filePath += '/index';
|
|
16
|
+
}
|
|
17
|
+
if (project.hasTypeScript) {
|
|
18
|
+
filePath += '.ts';
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
filePath += '.js';
|
|
22
|
+
}
|
|
23
|
+
return filePath;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function importStylesInComponents(context, options) {
|
|
27
|
+
const customizations = {
|
|
28
|
+
blueprintFilePaths: getBlueprintFilePaths(options),
|
|
29
|
+
getFilePath: getFilePath(options),
|
|
30
|
+
};
|
|
31
|
+
importStyles(context.components, {
|
|
32
|
+
customizations,
|
|
33
|
+
options,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import { updateTemplates } from '../../../utils/steps/update-templates/index.js';
|
|
3
|
+
function getFilePath(options) {
|
|
4
|
+
const { componentStructure } = options;
|
|
5
|
+
return function (entityName) {
|
|
6
|
+
let filePath = join('src/components', entityName);
|
|
7
|
+
if (componentStructure === 'nested') {
|
|
8
|
+
filePath += '/index';
|
|
9
|
+
}
|
|
10
|
+
filePath += '.hbs';
|
|
11
|
+
return filePath;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function updateComponentTemplates(context, options) {
|
|
15
|
+
const customizations = {
|
|
16
|
+
getFilePath: getFilePath(options),
|
|
17
|
+
};
|
|
18
|
+
updateTemplates(context.components, {
|
|
19
|
+
customizations,
|
|
20
|
+
options,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
@@ -13,11 +13,12 @@ function analyzePackageJson(codemodOptions) {
|
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
export function createOptions(codemodOptions) {
|
|
16
|
+
const { componentStructure, projectRoot, projectType } = codemodOptions;
|
|
16
17
|
const project = analyzePackageJson(codemodOptions);
|
|
17
|
-
|
|
18
|
-
componentStructure
|
|
18
|
+
return {
|
|
19
|
+
componentStructure,
|
|
19
20
|
project,
|
|
20
|
-
projectRoot
|
|
21
|
+
projectRoot,
|
|
22
|
+
projectType,
|
|
21
23
|
};
|
|
22
|
-
return options;
|
|
23
24
|
}
|
|
@@ -3,7 +3,7 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { processTemplate } from '@codemod-utils/blueprints';
|
|
4
4
|
import { classify, doubleColonize } from '@codemod-utils/ember-cli-string';
|
|
5
5
|
import { createFiles, parseFilePath } from '@codemod-utils/files';
|
|
6
|
-
import { blueprintsRoot } from '
|
|
6
|
+
import { blueprintsRoot } from '../../blueprints.js';
|
|
7
7
|
export function createClass(entityName, { customizations, options }) {
|
|
8
8
|
const { blueprintFilePaths, getFilePath } = customizations;
|
|
9
9
|
const entity = {
|
|
@@ -3,6 +3,19 @@ import { readFileSync } from 'node:fs';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { AST } from '@codemod-utils/ast-javascript';
|
|
5
5
|
import { createFiles, parseFilePath } from '@codemod-utils/files';
|
|
6
|
+
function canSkip(file, data) {
|
|
7
|
+
const traverse = AST.traverse(data.isTypeScript);
|
|
8
|
+
let canSkip = false;
|
|
9
|
+
traverse(file, {
|
|
10
|
+
visitImportDeclaration(path) {
|
|
11
|
+
if (path.node.source.value === `./${data.fileName}.css`) {
|
|
12
|
+
canSkip = true;
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
return canSkip;
|
|
18
|
+
}
|
|
6
19
|
function removeTemplateOnlyComponentMethod(file, data) {
|
|
7
20
|
const traverse = AST.traverse(data.isTypeScript);
|
|
8
21
|
const ast = traverse(file, {
|
|
@@ -86,6 +99,9 @@ export function updateClass(entityName, { customizations, options }) {
|
|
|
86
99
|
};
|
|
87
100
|
try {
|
|
88
101
|
let file = readFileSync(join(projectRoot, filePath), 'utf8');
|
|
102
|
+
if (canSkip(file, data)) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
89
105
|
file = removeTemplateOnlyComponentMethod(file, data);
|
|
90
106
|
file = importStylesInClass(file, data);
|
|
91
107
|
file = addStylesAsClassProperty(file, data);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember-codemod-remove-ember-css-modules",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Codemod to replace ember-css-modules with embroider-css-modules",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codemod",
|
|
@@ -37,15 +37,15 @@
|
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@codemod-utils/tests": "^1.1.2",
|
|
39
39
|
"@sondr3/minitest": "^0.1.2",
|
|
40
|
-
"@types/node": "^18.19.
|
|
40
|
+
"@types/node": "^18.19.23",
|
|
41
41
|
"@types/yargs": "^17.0.32",
|
|
42
42
|
"concurrently": "^8.2.2",
|
|
43
|
-
"eslint": "^8.
|
|
43
|
+
"eslint": "^8.57.0",
|
|
44
44
|
"prettier": "^3.2.5",
|
|
45
|
-
"typescript": "^5.
|
|
46
|
-
"@shared-configs/
|
|
45
|
+
"typescript": "^5.4.2",
|
|
46
|
+
"@shared-configs/eslint-config-node": "0.0.0",
|
|
47
47
|
"@shared-configs/prettier": "0.0.0",
|
|
48
|
-
"@shared-configs/
|
|
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
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|