ember-codemod-remove-ember-css-modules 0.1.5 → 0.2.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.
Files changed (50) hide show
  1. package/README.md +6 -1
  2. package/{bin → dist/bin}/ember-codemod-remove-ember-css-modules.js +9 -17
  3. package/{src → dist/src}/index.js +1 -2
  4. package/dist/src/migration/ember-app/index.js +21 -0
  5. package/dist/src/migration/ember-app/steps/analyze-app.js +98 -0
  6. package/dist/src/migration/ember-app/steps/create-options.js +24 -0
  7. package/dist/src/migration/ember-app/steps/import-styles-in-components.js +35 -0
  8. package/dist/src/migration/ember-app/steps/import-styles-in-routes.js +32 -0
  9. package/dist/src/migration/ember-app/steps/move-stylesheets.js +35 -0
  10. package/dist/src/migration/ember-app/steps/shared/import-styles.js +136 -0
  11. package/dist/src/migration/ember-app/steps/shared/update-templates.js +354 -0
  12. package/dist/src/migration/ember-app/steps/update-app-app-js.js +46 -0
  13. package/dist/src/migration/ember-app/steps/update-component-templates.js +22 -0
  14. package/dist/src/migration/ember-app/steps/update-package-json.js +38 -0
  15. package/dist/src/migration/ember-app/steps/update-route-templates.js +18 -0
  16. package/dist/src/types/index.js +1 -0
  17. package/dist/src/utils/blueprints/blueprints-root.js +4 -0
  18. package/dist/src/utils/blueprints/get-version.js +13 -0
  19. package/dist/src/utils/string/ember-cli-string-utils/camelize.js +11 -0
  20. package/dist/src/utils/string/ember-cli-string-utils/classify.js +10 -0
  21. package/{src → dist/src}/utils/string/entity-name/classify.js +1 -2
  22. package/{src → dist/src}/utils/string/entity-name/double-colonize.js +3 -6
  23. package/dist/src/utils/string/entity-name/parse.js +15 -0
  24. package/package.json +20 -14
  25. package/src/migration/ember-app/index.js +0 -37
  26. package/src/migration/ember-app/steps/analyze-app.js +0 -155
  27. package/src/migration/ember-app/steps/create-options.js +0 -30
  28. package/src/migration/ember-app/steps/import-styles-in-components.js +0 -43
  29. package/src/migration/ember-app/steps/import-styles-in-routes.js +0 -39
  30. package/src/migration/ember-app/steps/move-stylesheets.js +0 -51
  31. package/src/migration/ember-app/steps/shared/import-styles.js +0 -210
  32. package/src/migration/ember-app/steps/shared/index.js +0 -2
  33. package/src/migration/ember-app/steps/shared/update-templates.js +0 -445
  34. package/src/migration/ember-app/steps/update-app-app-js.js +0 -64
  35. package/src/migration/ember-app/steps/update-component-templates.js +0 -28
  36. package/src/migration/ember-app/steps/update-package-json.js +0 -61
  37. package/src/migration/ember-app/steps/update-route-templates.js +0 -22
  38. package/src/utils/blueprints/blueprints-root.js +0 -8
  39. package/src/utils/blueprints/get-version.js +0 -16
  40. package/src/utils/string/ember-cli-string-utils/camelize.js +0 -12
  41. package/src/utils/string/ember-cli-string-utils/classify.js +0 -14
  42. package/src/utils/string/entity-name/parse.js +0 -19
  43. /package/{src/blueprints → blueprints}/ember-cli/component/javascript.js +0 -0
  44. /package/{src/blueprints → blueprints}/ember-cli/component/typescript.ts +0 -0
  45. /package/{src/blueprints → blueprints}/ember-cli/controller/javascript.js +0 -0
  46. /package/{src/blueprints → blueprints}/ember-cli/controller/typescript.ts +0 -0
  47. /package/{src → dist/src}/migration/ember-app/steps/index.js +0 -0
  48. /package/{src → dist/src}/migration/index.js +0 -0
  49. /package/{src → dist/src}/utils/blueprints.js +0 -0
  50. /package/{src → dist/src}/utils/string.js +0 -0
@@ -1,37 +0,0 @@
1
- import {
2
- analyzeApp,
3
- createOptions,
4
- importStylesInComponents,
5
- importStylesInRoutes,
6
- moveStylesheets,
7
- updateAppAppJs,
8
- updateComponentTemplates,
9
- updatePackageJson,
10
- updateRouteTemplates,
11
- } from './steps/index.js';
12
-
13
- export function migrateEmberApp(codemodOptions) {
14
- const options = createOptions(codemodOptions);
15
- const { hasEmberCssModules } = options.project;
16
-
17
- // Guarantee idempotency
18
- if (!hasEmberCssModules) {
19
- return;
20
- }
21
-
22
- // Prepare for migration
23
- const context = analyzeApp(options);
24
-
25
- // Import styles in classes
26
- moveStylesheets(options);
27
- importStylesInComponents(context, options);
28
- importStylesInRoutes(context, options);
29
-
30
- // Update templates
31
- updateComponentTemplates(context, options);
32
- updateRouteTemplates(context, options);
33
-
34
- // Fine-tune individual files
35
- updateAppAppJs(options);
36
- updatePackageJson(options);
37
- }
@@ -1,155 +0,0 @@
1
- import { join, parse } from 'node:path';
2
-
3
- import { findFiles, renamePathByDirectory } from '@codemod-utils/files';
4
-
5
- function findAndRenameFiles(findOptions, replaceOptions) {
6
- const { globPattern, ignoreList, projectRoot } = findOptions;
7
- const { from, to } = replaceOptions;
8
-
9
- const filePaths = findFiles(globPattern, {
10
- ignoreList,
11
- projectRoot,
12
- });
13
-
14
- return filePaths.map((filePath) => {
15
- return renamePathByDirectory(filePath, { from, to });
16
- });
17
- }
18
-
19
- function analyzeEntities({
20
- classFilePaths,
21
- stylesheetFilePaths,
22
- templateFilePaths,
23
- }) {
24
- const filePaths = [
25
- ...classFilePaths,
26
- ...stylesheetFilePaths,
27
- ...templateFilePaths,
28
- ].sort();
29
-
30
- const entities = new Map();
31
-
32
- filePaths.forEach((filePath) => {
33
- const { dir, ext, name } = parse(filePath);
34
- const entityName = join(dir, name);
35
-
36
- if (entities.has(entityName)) {
37
- entities.get(entityName).add(ext);
38
-
39
- return;
40
- }
41
-
42
- entities.set(entityName, new Set([ext]));
43
- });
44
-
45
- return entities;
46
- }
47
-
48
- function analyzeComponents(options) {
49
- const { componentStructure, projectRoot } = options;
50
-
51
- const classFilePaths = findAndRenameFiles(
52
- {
53
- globPattern: 'app/components/**/*.{js,ts}',
54
- ignoreList: ['app/components/**/*.d.ts'],
55
- projectRoot,
56
- },
57
- {
58
- from: 'app/components',
59
- to: '',
60
- },
61
- );
62
-
63
- const stylesheetFilePaths = findAndRenameFiles(
64
- {
65
- globPattern: 'app/components/**/*.css',
66
- projectRoot,
67
- },
68
- {
69
- from: 'app/components',
70
- to: '',
71
- },
72
- );
73
-
74
- const templateFilePaths = findAndRenameFiles(
75
- {
76
- globPattern: 'app/components/**/*.hbs',
77
- projectRoot,
78
- },
79
- {
80
- from: 'app/components',
81
- to: '',
82
- },
83
- );
84
-
85
- const entities = analyzeEntities({
86
- classFilePaths,
87
- stylesheetFilePaths,
88
- templateFilePaths,
89
- });
90
-
91
- if (componentStructure === 'nested') {
92
- return new Map(
93
- [...entities.entries()].map(([entityName, extensions]) => {
94
- const newEntityName = entityName.replace(/\/index$/, '');
95
-
96
- return [newEntityName, extensions];
97
- }),
98
- );
99
- }
100
-
101
- return entities;
102
- }
103
-
104
- function analyzeRoutes(options) {
105
- const { projectRoot } = options;
106
-
107
- const classFilePaths = findAndRenameFiles(
108
- {
109
- globPattern: 'app/controllers/**/*.{js,ts}',
110
- ignoreList: ['app/controllers/**/*.d.ts'],
111
- projectRoot,
112
- },
113
- {
114
- from: 'app/controllers',
115
- to: '',
116
- },
117
- );
118
-
119
- const stylesheetFilePaths = findAndRenameFiles(
120
- {
121
- globPattern: 'app/styles/**/*.css',
122
- ignoreList: ['app/styles/app.css'],
123
- projectRoot,
124
- },
125
- {
126
- from: 'app/styles',
127
- to: '',
128
- },
129
- );
130
-
131
- const templateFilePaths = findAndRenameFiles(
132
- {
133
- globPattern: 'app/templates/**/*.hbs',
134
- ignoreList: ['app/templates/components/**/*'],
135
- projectRoot,
136
- },
137
- {
138
- from: 'app/templates',
139
- to: '',
140
- },
141
- );
142
-
143
- return analyzeEntities({
144
- classFilePaths,
145
- stylesheetFilePaths,
146
- templateFilePaths,
147
- });
148
- }
149
-
150
- export function analyzeApp(options) {
151
- return {
152
- components: analyzeComponents(options),
153
- routes: analyzeRoutes(options),
154
- };
155
- }
@@ -1,30 +0,0 @@
1
- import { readPackageJson } from '@codemod-utils/json';
2
-
3
- function analyzePackageJson(codemodOptions) {
4
- const { dependencies, devDependencies } = readPackageJson(codemodOptions);
5
-
6
- const projectDependencies = new Map([
7
- ...Object.entries(dependencies ?? {}),
8
- ...Object.entries(devDependencies ?? {}),
9
- ]);
10
-
11
- return {
12
- dependencies: projectDependencies,
13
- hasEmberCssModules: projectDependencies.has('ember-css-modules'),
14
- hasGlint: projectDependencies.has('@glint/core'),
15
- hasTypeScript: projectDependencies.has('typescript'),
16
- };
17
- }
18
-
19
- export function createOptions(codemodOptions) {
20
- const project = analyzePackageJson(codemodOptions);
21
-
22
- const options = {
23
- __styles__: 'styles',
24
- componentStructure: codemodOptions.componentStructure,
25
- project,
26
- projectRoot: codemodOptions.projectRoot,
27
- };
28
-
29
- return options;
30
- }
@@ -1,43 +0,0 @@
1
- import { join } from 'node:path';
2
-
3
- import { importStyles } from './shared/index.js';
4
-
5
- function getBlueprintFilePaths(options) {
6
- const { project } = options;
7
-
8
- if (project.hasTypeScript) {
9
- return ['ember-cli/component/typescript.ts'];
10
- }
11
-
12
- return ['ember-cli/component/javascript.js'];
13
- }
14
-
15
- function getFilePath(options) {
16
- const { componentStructure, project } = options;
17
-
18
- return function (entityName) {
19
- let filePath = join('app/components', entityName);
20
-
21
- if (componentStructure === 'nested') {
22
- filePath += '/index';
23
- }
24
-
25
- if (project.hasTypeScript) {
26
- filePath += '.ts';
27
- } else {
28
- filePath += '.js';
29
- }
30
-
31
- return filePath;
32
- };
33
- }
34
-
35
- export function importStylesInComponents(context, options) {
36
- const customizations = {
37
- blueprintFilePaths: getBlueprintFilePaths(options),
38
- entities: context.components,
39
- getFilePath: getFilePath(options),
40
- };
41
-
42
- importStyles(customizations, options);
43
- }
@@ -1,39 +0,0 @@
1
- import { join } from 'node:path';
2
-
3
- import { importStyles } from './shared/index.js';
4
-
5
- function getBlueprintFilePaths(options) {
6
- const { project } = options;
7
-
8
- if (project.hasTypeScript) {
9
- return ['ember-cli/controller/typescript.ts'];
10
- }
11
-
12
- return ['ember-cli/controller/javascript.js'];
13
- }
14
-
15
- function getFilePath(options) {
16
- const { project } = options;
17
-
18
- return function (entityName) {
19
- let filePath = join('app/controllers', entityName);
20
-
21
- if (project.hasTypeScript) {
22
- filePath += '.ts';
23
- } else {
24
- filePath += '.js';
25
- }
26
-
27
- return filePath;
28
- };
29
- }
30
-
31
- export function importStylesInRoutes(context, options) {
32
- const customizations = {
33
- blueprintFilePaths: getBlueprintFilePaths(options),
34
- entities: context.routes,
35
- getFilePath: getFilePath(options),
36
- };
37
-
38
- importStyles(customizations, options);
39
- }
@@ -1,51 +0,0 @@
1
- import {
2
- createFiles,
3
- findFiles,
4
- mapFilePaths,
5
- moveFiles,
6
- } from '@codemod-utils/files';
7
-
8
- function moveRouteStylesheets(options) {
9
- const { projectRoot } = options;
10
-
11
- const filePaths = findFiles('app/styles/**/*.css', {
12
- ignoreList: ['app/styles/app.css'],
13
- projectRoot,
14
- });
15
-
16
- const pathMapping = mapFilePaths(filePaths, {
17
- from: 'app/styles',
18
- to: 'app/controllers',
19
- });
20
-
21
- moveFiles(pathMapping, options);
22
- }
23
-
24
- function moveAppCssToAssets(options) {
25
- const { projectRoot } = options;
26
-
27
- const filePaths = findFiles('app/styles/app.css', {
28
- projectRoot,
29
- });
30
-
31
- const pathMapping = mapFilePaths(filePaths, {
32
- from: 'app/styles',
33
- to: 'app/assets',
34
- });
35
-
36
- moveFiles(pathMapping, options);
37
-
38
- const fileMapping = new Map([
39
- [
40
- 'app/styles/app.css',
41
- '/* Ember supports plain CSS out of the box. More info: https://cli.emberjs.com/release/advanced-use/stylesheets/ */\n',
42
- ],
43
- ]);
44
-
45
- createFiles(fileMapping, options);
46
- }
47
-
48
- export function moveStylesheets(options) {
49
- moveRouteStylesheets(options);
50
- moveAppCssToAssets(options);
51
- }
@@ -1,210 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { join, parse } from 'node:path';
3
-
4
- import { ASTJavaScript as AST } from '@codemod-utils/ast';
5
- import { processTemplate } from '@codemod-utils/blueprints';
6
- import { createFiles } from '@codemod-utils/files';
7
-
8
- import { blueprintsRoot } from '../../../../utils/blueprints.js';
9
- import { parseEntityName } from '../../../../utils/string.js';
10
-
11
- function removeTemplateOnlyComponentMethod(file, data) {
12
- const traverse = AST.traverse(data.isTypeScript);
13
-
14
- const ast = traverse(file, {
15
- visitCallExpression(path) {
16
- if (path.value.callee.name !== 'templateOnlyComponent') {
17
- return false;
18
- }
19
-
20
- const superClass = AST.builders.identifier('Component');
21
-
22
- if (data.isTypeScript) {
23
- superClass.typeAnnotation = path.value.typeParameters;
24
- }
25
-
26
- return AST.builders.classExpression(
27
- null,
28
- AST.builders.classBody([
29
- AST.builders.classProperty(
30
- AST.builders.identifier(data.__styles__),
31
- AST.builders.identifier(data.__styles__),
32
- ),
33
- ]),
34
- superClass,
35
- );
36
- },
37
-
38
- visitImportDeclaration(path) {
39
- if (path.value.source.value !== '@ember/component/template-only') {
40
- return false;
41
- }
42
-
43
- const defaultImport = path.value.specifiers.find(
44
- (specifier) => specifier.type === 'ImportDefaultSpecifier',
45
- );
46
-
47
- if (defaultImport?.local?.name !== 'templateOnlyComponent') {
48
- return false;
49
- }
50
-
51
- return AST.builders.importDeclaration(
52
- [
53
- AST.builders.importDefaultSpecifier(
54
- AST.builders.identifier('Component'),
55
- ),
56
- ],
57
- AST.builders.literal('@glimmer/component'),
58
- );
59
- },
60
- });
61
-
62
- return AST.print(ast);
63
- }
64
-
65
- function importStylesInClass(file, data) {
66
- const traverse = AST.traverse(data.isTypeScript);
67
-
68
- // Find the last import statement
69
- let lastImportDeclarationPath;
70
-
71
- const ast = traverse(file, {
72
- visitImportDeclaration(path) {
73
- if (!lastImportDeclarationPath) {
74
- lastImportDeclarationPath = path;
75
- } else if (path.node.start > lastImportDeclarationPath.node.start) {
76
- lastImportDeclarationPath = path;
77
- }
78
-
79
- return false;
80
- },
81
- });
82
-
83
- // Append the styles import
84
- const nodes = ast.program.body;
85
- const index = lastImportDeclarationPath?.name ?? -1;
86
-
87
- nodes.splice(
88
- index + 1,
89
- 0,
90
- AST.builders.importDeclaration(
91
- [
92
- AST.builders.importDefaultSpecifier(
93
- AST.builders.identifier(data.__styles__),
94
- ),
95
- ],
96
- AST.builders.literal(`./${data.fileName}.css`),
97
- ),
98
- );
99
-
100
- return AST.print(ast);
101
- }
102
-
103
- function addStylesAsClassProperty(file, data) {
104
- const traverse = AST.traverse(data.isTypeScript);
105
-
106
- const ast = traverse(file, {
107
- visitClassDeclaration(path) {
108
- const { body } = path.node.body;
109
-
110
- const nodesToAdd = [
111
- AST.builders.classProperty(
112
- AST.builders.identifier(data.__styles__),
113
- AST.builders.identifier(data.__styles__),
114
- ),
115
- ];
116
-
117
- if (body.length > 0) {
118
- nodesToAdd.push(AST.builders.noop());
119
- }
120
-
121
- body.unshift(...nodesToAdd);
122
-
123
- return false;
124
- },
125
- });
126
-
127
- return AST.print(ast);
128
- }
129
-
130
- function createClass(customizations, options) {
131
- const { blueprintFilePaths, entity, filePath } = customizations;
132
-
133
- const fileMapping = new Map(
134
- blueprintFilePaths.map((blueprintFilePath) => {
135
- const blueprintFile = readFileSync(
136
- join(blueprintsRoot, blueprintFilePath),
137
- 'utf8',
138
- );
139
-
140
- const file = processTemplate(blueprintFile, {
141
- entity,
142
- options,
143
- });
144
-
145
- return [filePath, file];
146
- }),
147
- );
148
-
149
- createFiles(fileMapping, options);
150
- }
151
-
152
- function updateClass(customizations, options) {
153
- const { filePath } = customizations;
154
- const { __styles__, projectRoot } = options;
155
-
156
- const { ext: fileExtension, name: fileName } = parse(filePath);
157
- const isTypeScript = fileExtension === '.ts';
158
-
159
- let file = readFileSync(join(projectRoot, filePath), 'utf8');
160
-
161
- try {
162
- file = removeTemplateOnlyComponentMethod(file, {
163
- __styles__,
164
- isTypeScript,
165
- });
166
-
167
- file = importStylesInClass(file, {
168
- __styles__,
169
- fileName,
170
- isTypeScript,
171
- });
172
-
173
- file = addStylesAsClassProperty(file, {
174
- __styles__,
175
- isTypeScript,
176
- });
177
-
178
- const fileMapping = new Map([[filePath, file]]);
179
-
180
- createFiles(fileMapping, options);
181
- } catch (e) {
182
- console.warn(
183
- `WARNING: updateClass could not update \`${filePath}\`. Please update the file manually. (${e.message})\n`,
184
- );
185
- }
186
- }
187
-
188
- export function importStyles(customizations, options) {
189
- const { blueprintFilePaths, entities, getFilePath } = customizations;
190
-
191
- for (const [entityName, extensions] of entities) {
192
- const hasClass = extensions.has('.js') || extensions.has('.ts');
193
- const hasStylesheet = extensions.has('.css');
194
-
195
- if (!hasStylesheet) {
196
- continue;
197
- }
198
-
199
- const entity = parseEntityName(entityName);
200
- const filePath = getFilePath(entityName);
201
-
202
- if (!hasClass) {
203
- createClass({ blueprintFilePaths, entity, filePath }, options);
204
-
205
- continue;
206
- }
207
-
208
- updateClass({ filePath }, options);
209
- }
210
- }
@@ -1,2 +0,0 @@
1
- export * from './import-styles.js';
2
- export * from './update-templates.js';