ember-codemod-remove-ember-css-modules 0.1.4 → 0.2.0-alpha.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.
Files changed (53) 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 +30 -25
  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 -44
  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 -438
  34. package/src/migration/ember-app/steps/update-app-app-js.js +0 -65
  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 -59
  37. package/src/migration/ember-app/steps/update-route-templates.js +0 -22
  38. package/src/utils/abstract-syntax-tree/handlebars.js +0 -20
  39. package/src/utils/abstract-syntax-tree/javascript.js +0 -103
  40. package/src/utils/abstract-syntax-tree.js +0 -2
  41. package/src/utils/blueprints/blueprints-root.js +0 -8
  42. package/src/utils/blueprints/get-version.js +0 -16
  43. package/src/utils/string/ember-cli-string-utils/camelize.js +0 -12
  44. package/src/utils/string/ember-cli-string-utils/classify.js +0 -14
  45. package/src/utils/string/entity-name/parse.js +0 -19
  46. /package/{src/blueprints → blueprints}/ember-cli/component/javascript.js +0 -0
  47. /package/{src/blueprints → blueprints}/ember-cli/component/typescript.ts +0 -0
  48. /package/{src/blueprints → blueprints}/ember-cli/controller/javascript.js +0 -0
  49. /package/{src/blueprints → blueprints}/ember-cli/controller/typescript.ts +0 -0
  50. /package/{src → dist/src}/migration/ember-app/steps/index.js +0 -0
  51. /package/{src → dist/src}/migration/index.js +0 -0
  52. /package/{src → dist/src}/utils/blueprints.js +0 -0
  53. /package/{src → dist/src}/utils/string.js +0 -0
@@ -0,0 +1,354 @@
1
+ /* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-non-null-assertion */
2
+ import { readFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { ASTHandlebars as AST } from '@codemod-utils/ast';
5
+ import { createFiles } from '@codemod-utils/files';
6
+ function sanitizeClassAndLocalClassAttributes(file) {
7
+ function removeAttributeWithoutValue(attributeName, attributes) {
8
+ const attributeIndex = attributes.findIndex(
9
+ // @ts-ignore: Assume that types from external packages are correct
10
+ (attribute) => attribute.name === attributeName);
11
+ if (attributeIndex === -1) {
12
+ return;
13
+ }
14
+ const attribute = attributes[attributeIndex];
15
+ // @ts-ignore: Assume that types from external packages are correct
16
+ if (attribute.isValueless) {
17
+ attributes.splice(attributeIndex, 1);
18
+ return;
19
+ }
20
+ // @ts-ignore: Assume that types from external packages are correct
21
+ if (attribute.value.type !== 'TextNode') {
22
+ return;
23
+ }
24
+ // @ts-ignore: Assume that types from external packages are correct
25
+ const attributeValue = attribute.value.chars.trim();
26
+ if (attributeValue === '') {
27
+ attributes.splice(attributeIndex, 1);
28
+ return;
29
+ }
30
+ }
31
+ const traverse = AST.traverse();
32
+ const ast = traverse(file, {
33
+ ElementNode(node) {
34
+ const { attributes } = node;
35
+ removeAttributeWithoutValue('class', attributes);
36
+ removeAttributeWithoutValue('local-class', attributes);
37
+ },
38
+ });
39
+ return AST.print(ast);
40
+ }
41
+ function mergeClassAndLocalClassAttributes(file, data) {
42
+ const traverse = AST.traverse();
43
+ const ast = traverse(file, {
44
+ ElementNode(node) {
45
+ // Check that both class and local-class attributes exist
46
+ const { attributes } = node;
47
+ const localClassAttributeIndex = attributes.findIndex((attribute) => attribute.name === 'local-class');
48
+ const classAttributeIndex = attributes.findIndex((attribute) => attribute.name === 'class');
49
+ if (localClassAttributeIndex === -1 || classAttributeIndex === -1) {
50
+ return;
51
+ }
52
+ // Merge attributes only when both have TextNode values
53
+ const localClassAttribute = attributes[localClassAttributeIndex];
54
+ const classAttribute = attributes[classAttributeIndex];
55
+ if (localClassAttribute.value.type !== 'TextNode' ||
56
+ classAttribute.value.type !== 'TextNode') {
57
+ return;
58
+ }
59
+ const localClassAttributeValue = localClassAttribute.value.chars.trim();
60
+ const classAttributeValue = classAttribute.value.chars.trim();
61
+ // Update the class attribute
62
+ const localClassNames = localClassAttributeValue.split(/\s+/);
63
+ let params;
64
+ if (localClassNames.length === 1) {
65
+ params = [
66
+ AST.builders.path(`this.${data.__styles__}.${localClassNames[0]}`),
67
+ AST.builders.string(` ${classAttributeValue}`),
68
+ ];
69
+ }
70
+ else {
71
+ params = [
72
+ AST.builders.sexpr('local-class', [
73
+ AST.builders.path(`this.${data.__styles__}`),
74
+ ...localClassNames.map(AST.builders.string),
75
+ ]),
76
+ AST.builders.string(` ${classAttributeValue}`),
77
+ ];
78
+ }
79
+ attributes[classAttributeIndex].value = AST.builders.mustache(AST.builders.path('concat'), params);
80
+ // Remove the local-class attribute
81
+ attributes.splice(localClassAttributeIndex, 1);
82
+ },
83
+ });
84
+ return AST.print(ast);
85
+ }
86
+ function removeLocalClassHelpers(file, data) {
87
+ /*
88
+ The {{local-class}} helper from ember-css-modules allows
89
+ 1 positional argument. The argument's value is presumed
90
+ to be a concatenated string or `undefined`.
91
+ */
92
+ function canRemoveLocalClassHelper(path) {
93
+ // @ts-ignore: Assume that types from external packages are correct
94
+ const hasFromArgument = path.hash.pairs.some((pair) => pair.key === 'from');
95
+ if (hasFromArgument) {
96
+ throw new RangeError(
97
+ // @ts-ignore: Assume that types from external packages are correct
98
+ `Unable to handle the {{local-class}} helper's \`from\` key. See lines ${path.loc.start.line}-${path.loc.end.line}.`);
99
+ }
100
+ // @ts-ignore: Assume that types from external packages are correct
101
+ const param = path.params[0];
102
+ if (param === undefined) {
103
+ return true;
104
+ }
105
+ if (param.type !== 'StringLiteral') {
106
+ return false;
107
+ }
108
+ const value = param.value.trim();
109
+ return value === '';
110
+ }
111
+ const traverse = AST.traverse();
112
+ const ast = traverse(file, {
113
+ // @ts-ignore: Assume that types from external packages are correct
114
+ AttrNode(node) {
115
+ if (node.name !== 'class') {
116
+ return;
117
+ }
118
+ const hasLocalClassHelper = node.value.type === 'MustacheStatement' &&
119
+ // @ts-ignore: Assume that types from external packages are correct
120
+ node.value.path.original === 'local-class';
121
+ if (!hasLocalClassHelper) {
122
+ return;
123
+ }
124
+ if (canRemoveLocalClassHelper(node.value)) {
125
+ return null;
126
+ }
127
+ // @ts-ignore: Assume that types from external packages are correct
128
+ const param = node.value.params[0];
129
+ if (param.type !== 'StringLiteral') {
130
+ return;
131
+ }
132
+ const localClassNames = param.value.trim().split(/\s+/);
133
+ if (localClassNames.length === 1) {
134
+ node.value = AST.builders.mustache(AST.builders.path(`this.${data.__styles__}.${localClassNames[0]}`));
135
+ return;
136
+ }
137
+ node.value = AST.builders.mustache(AST.builders.path('local-class'), [
138
+ AST.builders.path(`this.${data.__styles__}`),
139
+ ...localClassNames.map(AST.builders.string),
140
+ ]);
141
+ },
142
+ SubExpression(node) {
143
+ // @ts-ignore: Assume that types from external packages are correct
144
+ const hasLocalClassHelper = node.path.original === 'local-class';
145
+ if (!hasLocalClassHelper) {
146
+ return;
147
+ }
148
+ if (canRemoveLocalClassHelper(node)) {
149
+ return AST.builders.string('');
150
+ }
151
+ const param = node.params[0];
152
+ if (param.type !== 'StringLiteral') {
153
+ return node;
154
+ }
155
+ const localClassNames = param.value.trim().split(/\s+/);
156
+ if (localClassNames.length === 1) {
157
+ return AST.builders.path(`this.${data.__styles__}.${localClassNames[0]}`);
158
+ }
159
+ return AST.builders.sexpr(AST.builders.path('local-class'), [
160
+ AST.builders.path(`this.${data.__styles__}`),
161
+ ...localClassNames.map(AST.builders.string),
162
+ ]);
163
+ },
164
+ });
165
+ return AST.print(ast);
166
+ }
167
+ function removeLocalClassAttributes(file, data) {
168
+ function transformParam(param) {
169
+ // @ts-ignore: Assume that types from external packages are correct
170
+ switch (param.type) {
171
+ case 'StringLiteral': {
172
+ // @ts-ignore: Assume that types from external packages are correct
173
+ const localClassNames = param.value.trim().split(/\s+/);
174
+ if (localClassNames.length === 1) {
175
+ // @ts-ignore: Assume that types from external packages are correct
176
+ param.value = localClassNames[0];
177
+ }
178
+ else {
179
+ param = AST.builders.sexpr('array', localClassNames.map(AST.builders.string));
180
+ }
181
+ break;
182
+ }
183
+ case 'SubExpression': {
184
+ // @ts-ignore: Assume that types from external packages are correct
185
+ switch (param.path.original) {
186
+ case 'if':
187
+ case 'unless': {
188
+ // @ts-ignore: Assume that types from external packages are correct
189
+ const subparams = param.params.map(transformParam);
190
+ // @ts-ignore: Assume that types from external packages are correct
191
+ param = AST.builders.sexpr(param.path.original, subparams);
192
+ break;
193
+ }
194
+ }
195
+ break;
196
+ }
197
+ }
198
+ return param;
199
+ }
200
+ // @ts-ignore: Assume that types from external packages are correct
201
+ function transformPart(part) {
202
+ // @ts-ignore: Assume that types from external packages are correct
203
+ switch (part.type) {
204
+ case 'MustacheStatement': {
205
+ // @ts-ignore: Assume that types from external packages are correct
206
+ switch (part.path.original) {
207
+ case 'concat': {
208
+ // eslint-disable-next-line no-inner-declarations
209
+ function hasPathExpression(params) {
210
+ // @ts-ignore: Assume that types from external packages are correct
211
+ return params.some((param) => param.type === 'PathExpression');
212
+ }
213
+ // @ts-ignore: Assume that types from external packages are correct
214
+ if (hasPathExpression(part.params)) {
215
+ return AST.builders.mustache(AST.builders.path('get'), [
216
+ AST.builders.path(`this.${data.__styles__}`),
217
+ // @ts-ignore: Assume that types from external packages are correct
218
+ AST.builders.sexpr(part.path.original, part.params),
219
+ ]);
220
+ }
221
+ // @ts-ignore: Assume that types from external packages are correct
222
+ const params = part.params.map(transformParam);
223
+ return AST.builders.mustache('local-class', [
224
+ AST.builders.path(`this.${data.__styles__}`),
225
+ ...params,
226
+ ]);
227
+ }
228
+ case 'if':
229
+ case 'unless': {
230
+ // @ts-ignore: Assume that types from external packages are correct
231
+ const params = part.params.map(transformParam);
232
+ return AST.builders.mustache('local-class', [
233
+ AST.builders.path(`this.${data.__styles__}`),
234
+ // @ts-ignore: Assume that types from external packages are correct
235
+ AST.builders.sexpr(part.path.original, params),
236
+ ]);
237
+ }
238
+ default: {
239
+ return AST.builders.mustache(AST.builders.path('get'), [
240
+ AST.builders.path(`this.${data.__styles__}`),
241
+ // @ts-ignore: Assume that types from external packages are correct
242
+ part.path,
243
+ ]);
244
+ }
245
+ }
246
+ }
247
+ case 'TextNode': {
248
+ // @ts-ignore: Assume that types from external packages are correct
249
+ const value = part.chars.trim();
250
+ if (value === '') {
251
+ return part;
252
+ }
253
+ const localClassNames = value.split(/\s+/);
254
+ if (localClassNames.length === 1) {
255
+ return AST.builders.mustache(AST.builders.path(`this.${data.__styles__}.${localClassNames[0]}`));
256
+ }
257
+ return AST.builders.mustache(AST.builders.path('local-class'), [
258
+ AST.builders.path(`this.${data.__styles__}`),
259
+ ...localClassNames.map(AST.builders.string),
260
+ ]);
261
+ }
262
+ }
263
+ }
264
+ function transformParts(parts) {
265
+ const numParts = parts.length;
266
+ return parts.reduce((accumulator, part, index) => {
267
+ // @ts-ignore: Assume that types from external packages are correct
268
+ accumulator.push(transformPart(part));
269
+ if (index < numParts - 1) {
270
+ // @ts-ignore: Assume that types from external packages are correct
271
+ accumulator.push(AST.builders.text(' '));
272
+ }
273
+ return accumulator;
274
+ }, []);
275
+ }
276
+ const traverse = AST.traverse();
277
+ const ast = traverse(file, {
278
+ ElementNode(node) {
279
+ // Check if the local-class attribute (still) exists
280
+ const { attributes } = node;
281
+ const localClassAttributeIndex = attributes.findIndex((attribute) => attribute.name === 'local-class');
282
+ if (localClassAttributeIndex === -1) {
283
+ return;
284
+ }
285
+ // Change the local-class attribute to class
286
+ const localClassAttribute = attributes[localClassAttributeIndex];
287
+ switch (localClassAttribute.value.type) {
288
+ case 'ConcatStatement': {
289
+ localClassAttribute.name = 'class';
290
+ // @ts-ignore: Assume that types from external packages are correct
291
+ localClassAttribute.value.parts = transformParts(localClassAttribute.value.parts);
292
+ break;
293
+ }
294
+ case 'MustacheStatement': {
295
+ localClassAttribute.name = 'class';
296
+ // @ts-ignore: Assume that types from external packages are correct
297
+ localClassAttribute.value = transformPart(localClassAttribute.value);
298
+ break;
299
+ }
300
+ case 'TextNode': {
301
+ localClassAttribute.name = 'class';
302
+ // @ts-ignore: Assume that types from external packages are correct
303
+ localClassAttribute.value = transformPart(localClassAttribute.value);
304
+ break;
305
+ }
306
+ }
307
+ },
308
+ HashPair(node) {
309
+ if (node.key !== 'local-class') {
310
+ return;
311
+ }
312
+ node.key = 'class';
313
+ node.value = AST.builders.sexpr('local-class', [
314
+ AST.builders.path(`this.${data.__styles__}`),
315
+ // @ts-ignore: Assume that types from external packages are correct
316
+ transformParam(node.value),
317
+ ]);
318
+ },
319
+ });
320
+ return AST.print(ast);
321
+ }
322
+ function updateTemplate(entityName, { customizations, options }) {
323
+ const { getFilePath } = customizations;
324
+ const { __styles__, projectRoot } = options;
325
+ const filePath = getFilePath(entityName);
326
+ const data = {
327
+ __styles__,
328
+ };
329
+ try {
330
+ let file = readFileSync(join(projectRoot, filePath), 'utf8');
331
+ file = sanitizeClassAndLocalClassAttributes(file);
332
+ file = mergeClassAndLocalClassAttributes(file, data);
333
+ file = removeLocalClassHelpers(file, data);
334
+ file = removeLocalClassAttributes(file, data);
335
+ const fileMap = new Map([[filePath, file]]);
336
+ createFiles(fileMap, options);
337
+ }
338
+ catch (error) {
339
+ let message = `WARNING: updateTemplate could not update \`${filePath}\`. Please update the file manually.`;
340
+ if (error instanceof Error) {
341
+ message += ` (${error.message})`;
342
+ }
343
+ console.warn(`${message}\n`);
344
+ }
345
+ }
346
+ export function updateTemplates(entities, options) {
347
+ for (const [entityName, extensions] of entities) {
348
+ const hasTemplate = extensions.has('.hbs');
349
+ if (!hasTemplate) {
350
+ continue;
351
+ }
352
+ updateTemplate(entityName, options);
353
+ }
354
+ }
@@ -0,0 +1,46 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { extname, join } from 'node:path';
3
+ import { ASTJavaScript as AST } from '@codemod-utils/ast';
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
+ }
@@ -0,0 +1,22 @@
1
+ import { join } from 'node:path';
2
+ import { updateTemplates } from './shared/update-templates.js';
3
+ function getFilePath(options) {
4
+ const { componentStructure } = options;
5
+ return function (entityName) {
6
+ let filePath = join('app/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
+ }
@@ -0,0 +1,38 @@
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(['embroider-css-modules']);
13
+ if (project.hasTypeScript) {
14
+ packagesToInstall.add('type-css-modules');
15
+ }
16
+ [...packagesToInstall].sort().forEach((packageName) => {
17
+ const version = getVersion(packageName, options);
18
+ devDependencies.set(packageName, version);
19
+ });
20
+ packageJson['devDependencies'] = convertToObject(devDependencies);
21
+ }
22
+ function updateScripts(packageJson, options) {
23
+ const { project } = options;
24
+ const scripts = convertToMap(packageJson.scripts);
25
+ if (project.hasTypeScript) {
26
+ scripts.set('prelint:types', 'type-css-modules --src app');
27
+ }
28
+ packageJson['scripts'] = convertToObject(scripts);
29
+ }
30
+ export function updatePackageJson(options) {
31
+ const { projectRoot } = options;
32
+ const packageJson = readPackageJson(options);
33
+ updateDevDependencies(packageJson, options);
34
+ updateScripts(packageJson, options);
35
+ const destination = join(projectRoot, 'package.json');
36
+ const file = JSON.stringify(packageJson, null, 2) + '\n';
37
+ writeFileSync(destination, file, 'utf8');
38
+ }
@@ -0,0 +1,18 @@
1
+ import { join } from 'node:path';
2
+ import { updateTemplates } from './shared/update-templates.js';
3
+ function getFilePath() {
4
+ return function (entityName) {
5
+ let filePath = join('app/templates', entityName);
6
+ filePath += '.hbs';
7
+ return filePath;
8
+ };
9
+ }
10
+ export function updateRouteTemplates(context, options) {
11
+ const customizations = {
12
+ getFilePath: getFilePath(),
13
+ };
14
+ updateTemplates(context.routes, {
15
+ customizations,
16
+ options,
17
+ });
18
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import { join } from 'node:path';
2
+ import { getFilePath } from '@codemod-utils/blueprints';
3
+ const fileURL = import.meta.url;
4
+ export const blueprintsRoot = join(getFilePath(fileURL), '../../../../blueprints');
@@ -0,0 +1,13 @@
1
+ import { decideVersion } from '@codemod-utils/blueprints';
2
+ const latestVersions = new Map([
3
+ ['embroider-css-modules', '0.1.6'],
4
+ ['type-css-modules', '0.1.4'],
5
+ ['webpack', '5.86.0'],
6
+ ]);
7
+ export function getVersion(packageName, options) {
8
+ const { project } = options;
9
+ return decideVersion(packageName, {
10
+ dependencies: project.dependencies,
11
+ latestVersions,
12
+ });
13
+ }
@@ -0,0 +1,11 @@
1
+ /* https://github.com/ember-cli/ember-cli-string-utils/blob/v1.1.0/index.js */
2
+ const STRING_CAMELIZE_REGEXP = /(-|_|\.|\s)+(.)?/g;
3
+ export function camelize(value) {
4
+ return value
5
+ .replace(STRING_CAMELIZE_REGEXP, function (_match, _separator, character) {
6
+ return character ? character.toUpperCase() : '';
7
+ })
8
+ .replace(/^([A-Z])/, function (match) {
9
+ return match.toLowerCase();
10
+ });
11
+ }
@@ -0,0 +1,10 @@
1
+ /* https://github.com/ember-cli/ember-cli-string-utils/blob/v1.1.0/index.js */
2
+ import { camelize } from './camelize.js';
3
+ export function classify(value) {
4
+ const tokens = value.split('.');
5
+ const tokensTransformed = tokens.map((token) => {
6
+ const camelized = camelize(token);
7
+ return camelized.charAt(0).toUpperCase() + camelized.substring(1);
8
+ });
9
+ return tokensTransformed.join('.');
10
+ }
@@ -1,6 +1,5 @@
1
1
  /* https://github.com/emberjs/ember.js/blob/v4.12.0/blueprints/component/index.js#L255-L256 */
2
2
  import { classify } from '../ember-cli-string-utils/classify.js';
3
-
4
3
  export function classifyEntityName(entityName) {
5
- return classify(entityName.replace(/\//g, '-'));
4
+ return classify(entityName.replace(/\//g, '-'));
6
5
  }
@@ -1,10 +1,7 @@
1
1
  /* https://github.com/emberjs/ember.js/blob/v4.12.0/blueprints/component-test/index.js#L13-L16 */
2
2
  import { classify } from '../ember-cli-string-utils/classify.js';
3
-
4
3
  export function doubleColonizeEntityName(entityName) {
5
- const tokens = entityName.split('/');
6
-
7
- const tokensTransformed = tokens.map(classify);
8
-
9
- return tokensTransformed.join('::');
4
+ const tokens = entityName.split('/');
5
+ const tokensTransformed = tokens.map(classify);
6
+ return tokensTransformed.join('::');
10
7
  }
@@ -0,0 +1,15 @@
1
+ import { parse } from 'node:path';
2
+ import { classifyEntityName } from './classify.js';
3
+ import { doubleColonizeEntityName } from './double-colonize.js';
4
+ export function parseEntityName(entityName) {
5
+ const classifiedName = classifyEntityName(entityName);
6
+ const doubleColonizedName = doubleColonizeEntityName(entityName);
7
+ const { name: fileName } = parse(entityName);
8
+ const entity = {
9
+ classifiedName,
10
+ doubleColonizedName,
11
+ fileName,
12
+ name: entityName,
13
+ };
14
+ return entity;
15
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-codemod-remove-ember-css-modules",
3
- "version": "0.1.4",
3
+ "version": "0.2.0-alpha.1",
4
4
  "description": "Codemod to replace ember-css-modules with embroider-css-modules",
5
5
  "keywords": [
6
6
  "codemod",
@@ -16,42 +16,47 @@
16
16
  },
17
17
  "license": "MIT",
18
18
  "author": "Isaac J. Lee",
19
- "main": "src/index.js",
20
19
  "type": "module",
21
- "bin": "./bin/ember-codemod-remove-ember-css-modules.js",
22
- "files": [
23
- "bin/",
24
- "src/"
25
- ],
20
+ "main": "dist/src/index.js",
21
+ "bin": "dist/bin/ember-codemod-remove-ember-css-modules.js",
26
22
  "directories": {
27
23
  "test": "tests"
28
24
  },
25
+ "files": [
26
+ "blueprints",
27
+ "dist"
28
+ ],
29
+ "scripts": {
30
+ "build": "tsc --project tsconfig.build.json && chmod +x dist/bin/ember-codemod-remove-ember-css-modules.js",
31
+ "lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
32
+ "lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
33
+ "lint:js": "eslint . --cache",
34
+ "lint:js:fix": "eslint . --fix",
35
+ "lint:types": "tsc --noEmit",
36
+ "prepare": "pnpm build",
37
+ "test": "tsc --build && mt dist-for-testing --quiet"
38
+ },
29
39
  "dependencies": {
30
- "@babel/parser": "^7.22.4",
31
- "@codemod-utils/blueprints": "^0.1.1",
32
- "@codemod-utils/files": "^0.1.0",
33
- "@codemod-utils/json": "^0.1.1",
34
- "ember-template-recast": "^6.1.4",
35
- "recast": "^0.23.2",
40
+ "@codemod-utils/ast": "^0.2.0",
41
+ "@codemod-utils/blueprints": "^0.2.0",
42
+ "@codemod-utils/files": "^0.4.1",
43
+ "@codemod-utils/json": "^0.3.1",
36
44
  "yargs": "^17.7.2"
37
45
  },
38
46
  "devDependencies": {
39
- "@codemod-utils/tests": "^0.1.0",
47
+ "@codemod-utils/tests": "^0.2.2",
48
+ "@shared-configs/eslint-config": "workspace:*",
49
+ "@shared-configs/prettier": "workspace:*",
50
+ "@shared-configs/typescript": "workspace:*",
40
51
  "@sondr3/minitest": "^0.1.1",
41
- "concurrently": "^8.1.0",
52
+ "@types/node": "^16.11.7",
53
+ "@types/yargs": "^17.0.24",
54
+ "concurrently": "^8.2.0",
42
55
  "eslint": "^8.42.0",
43
56
  "prettier": "^2.8.8",
44
- "@shared-configs/eslint-config": "0.0.0",
45
- "@shared-configs/prettier": "0.0.0"
57
+ "typescript": "^5.1.3"
46
58
  },
47
59
  "engines": {
48
60
  "node": "16.* || >= 18"
49
- },
50
- "scripts": {
51
- "lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
52
- "lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
53
- "lint:js": "eslint . --cache",
54
- "lint:js:fix": "eslint . --fix",
55
- "test": "mt tests --quiet"
56
61
  }
57
- }
62
+ }