ember-codemod-remove-ember-css-modules 0.1.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 (48) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +222 -0
  3. package/bin/ember-codemod-remove-ember-css-modules.js +34 -0
  4. package/package.json +58 -0
  5. package/src/blueprints/ember-cli/component/javascript.js +7 -0
  6. package/src/blueprints/ember-cli/component/typescript.ts +26 -0
  7. package/src/blueprints/ember-cli/controller/javascript.js +7 -0
  8. package/src/blueprints/ember-cli/controller/typescript.ts +7 -0
  9. package/src/index.js +5 -0
  10. package/src/migration/ember-app/index.js +37 -0
  11. package/src/migration/ember-app/steps/analyze-app.js +155 -0
  12. package/src/migration/ember-app/steps/create-options.js +44 -0
  13. package/src/migration/ember-app/steps/import-styles-in-components.js +43 -0
  14. package/src/migration/ember-app/steps/import-styles-in-routes.js +39 -0
  15. package/src/migration/ember-app/steps/index.js +9 -0
  16. package/src/migration/ember-app/steps/move-stylesheets.js +51 -0
  17. package/src/migration/ember-app/steps/shared/import-styles.js +211 -0
  18. package/src/migration/ember-app/steps/shared/index.js +2 -0
  19. package/src/migration/ember-app/steps/shared/update-templates.js +437 -0
  20. package/src/migration/ember-app/steps/update-app-app-js.js +64 -0
  21. package/src/migration/ember-app/steps/update-component-templates.js +28 -0
  22. package/src/migration/ember-app/steps/update-package-json.js +58 -0
  23. package/src/migration/ember-app/steps/update-route-templates.js +22 -0
  24. package/src/migration/index.js +1 -0
  25. package/src/utils/abstract-syntax-tree/handlebars.js +20 -0
  26. package/src/utils/abstract-syntax-tree/javascript.js +109 -0
  27. package/src/utils/abstract-syntax-tree.js +2 -0
  28. package/src/utils/blueprints/blueprint-root.js +13 -0
  29. package/src/utils/blueprints/decide-version.js +25 -0
  30. package/src/utils/blueprints/process-template.js +12 -0
  31. package/src/utils/blueprints.js +3 -0
  32. package/src/utils/files/copy-files.js +19 -0
  33. package/src/utils/files/create-files.js +17 -0
  34. package/src/utils/files/find-files.js +28 -0
  35. package/src/utils/files/map-file-paths.js +25 -0
  36. package/src/utils/files/move-files.js +22 -0
  37. package/src/utils/files/remove-directory-if-empty.js +19 -0
  38. package/src/utils/files/remove-files.js +15 -0
  39. package/src/utils/files.js +7 -0
  40. package/src/utils/json/convert-to-map.js +3 -0
  41. package/src/utils/json/convert-to-object.js +5 -0
  42. package/src/utils/json.js +2 -0
  43. package/src/utils/string/ember-cli-string-utils/camelize.js +12 -0
  44. package/src/utils/string/ember-cli-string-utils/classify.js +14 -0
  45. package/src/utils/string/entity-name/classify.js +6 -0
  46. package/src/utils/string/entity-name/double-colonize.js +10 -0
  47. package/src/utils/string/entity-name/parse.js +19 -0
  48. package/src/utils/string.js +5 -0
@@ -0,0 +1,109 @@
1
+ import { parse as babelParser } from '@babel/parser';
2
+ import { parse, print, types, visit } from 'recast';
3
+
4
+ /* https://github.com/benjamn/recast/blob/v1.4.0/lib/options.ts */
5
+ const formattingOptions = {
6
+ quote: 'single',
7
+ };
8
+
9
+ /* https://github.com/facebook/jscodeshift/blob/v0.14.0/parser/babel5Compat.js */
10
+ const jsOptions = {
11
+ sourceType: 'module',
12
+ allowHashBang: true,
13
+ ecmaVersion: Infinity,
14
+ allowImportExportEverywhere: true,
15
+ allowReturnOutsideFunction: true,
16
+ startLine: 1,
17
+ tokens: true,
18
+ plugins: [
19
+ 'estree',
20
+ 'jsx',
21
+ 'asyncGenerators',
22
+ 'classProperties',
23
+ 'doExpressions',
24
+ 'exportExtensions',
25
+ 'functionBind',
26
+ 'functionSent',
27
+ 'objectRestSpread',
28
+ 'dynamicImport',
29
+ 'nullishCoalescingOperator',
30
+ 'optionalChaining',
31
+ [
32
+ 'decorators',
33
+ {
34
+ decoratorsBeforeExport: false,
35
+ },
36
+ ],
37
+ ],
38
+ };
39
+
40
+ /* https://github.com/facebook/jscodeshift/blob/v0.14.0/parser/tsOptions.js */
41
+ const tsOptions = {
42
+ sourceType: 'module',
43
+ allowImportExportEverywhere: true,
44
+ allowReturnOutsideFunction: true,
45
+ startLine: 1,
46
+ tokens: true,
47
+ plugins: [
48
+ 'asyncGenerators',
49
+ 'bigInt',
50
+ 'classPrivateMethods',
51
+ 'classPrivateProperties',
52
+ 'classProperties',
53
+ 'decorators-legacy',
54
+ 'doExpressions',
55
+ 'dynamicImport',
56
+ 'exportDefaultFrom',
57
+ 'exportExtensions',
58
+ 'exportNamespaceFrom',
59
+ 'functionBind',
60
+ 'functionSent',
61
+ 'importMeta',
62
+ 'nullishCoalescingOperator',
63
+ 'numericSeparator',
64
+ 'objectRestSpread',
65
+ 'optionalCatchBinding',
66
+ 'optionalChaining',
67
+ ['pipelineOperator', { proposal: 'minimal' }],
68
+ 'throwExpressions',
69
+ 'typescript',
70
+ ],
71
+ };
72
+
73
+ function getParseOptions(hasTypeScript) {
74
+ return {
75
+ parser: {
76
+ parse(file) {
77
+ return babelParser(file, hasTypeScript ? tsOptions : jsOptions);
78
+ },
79
+ },
80
+ };
81
+ }
82
+
83
+ function traverseJavaScript(file, visitMethods) {
84
+ const ast = parse(file, getParseOptions(false));
85
+
86
+ visit(ast, visitMethods);
87
+
88
+ return ast;
89
+ }
90
+
91
+ function traverseTypeScript(file, visitMethods) {
92
+ const ast = parse(file, getParseOptions(true));
93
+
94
+ visit(ast, visitMethods);
95
+
96
+ return ast;
97
+ }
98
+
99
+ const tools = {
100
+ builders: types.builders,
101
+ print(ast) {
102
+ return print(ast, formattingOptions).code;
103
+ },
104
+ traverse(hasTypeScript) {
105
+ return hasTypeScript ? traverseTypeScript : traverseJavaScript;
106
+ },
107
+ };
108
+
109
+ export default tools;
@@ -0,0 +1,2 @@
1
+ export { default as ASTHandlebars } from './abstract-syntax-tree/handlebars.js';
2
+ export { default as ASTJavaScript } from './abstract-syntax-tree/javascript.js';
@@ -0,0 +1,13 @@
1
+ import { dirname, join } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+
7
+ function getBlueprintRoot() {
8
+ const srcDirectory = join(__dirname, '../..');
9
+
10
+ return join(srcDirectory, 'blueprints');
11
+ }
12
+
13
+ export const blueprintRoot = getBlueprintRoot();
@@ -0,0 +1,25 @@
1
+ const latestVersions = new Map([
2
+ ['embroider-css-modules', '0.1.0'],
3
+ ['type-css-modules', '0.1.0'],
4
+ ['webpack', '5.78.0'],
5
+ ]);
6
+
7
+ export function decideVersion(packageName, options) {
8
+ const { project } = options;
9
+
10
+ const installedVersion = project.dependencies.get(packageName);
11
+
12
+ if (installedVersion) {
13
+ return installedVersion;
14
+ }
15
+
16
+ const latestVersion = latestVersions.get(packageName);
17
+
18
+ if (!latestVersion) {
19
+ throw new RangeError(
20
+ `ERROR: The latest version of \`${packageName}\` is unknown.\n`
21
+ );
22
+ }
23
+
24
+ return `^${latestVersion}`;
25
+ }
@@ -0,0 +1,12 @@
1
+ /* https://github.com/ember-cli/ember-cli/blob/v4.11.0/lib/utilities/process-template.js */
2
+ import template from 'lodash.template';
3
+
4
+ export function processTemplate(file, data) {
5
+ const settings = {
6
+ escape: /<%-([\s\S]+?)%>/g,
7
+ evaluate: /<%([\s\S]+?)%>/g,
8
+ interpolate: /<%=([\s\S]+?)%>/g,
9
+ };
10
+
11
+ return template(file, settings)(data);
12
+ }
@@ -0,0 +1,3 @@
1
+ export * from './blueprints/blueprint-root.js';
2
+ export * from './blueprints/decide-version.js';
3
+ export * from './blueprints/process-template.js';
@@ -0,0 +1,19 @@
1
+ import { copyFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+
4
+ export function copyFiles(pathMapping, options) {
5
+ const { projectRoot } = options;
6
+
7
+ pathMapping.forEach((newPath, oldPath) => {
8
+ const oldAbsolutePath = join(projectRoot, oldPath);
9
+
10
+ const newAbsolutePath = join(projectRoot, newPath);
11
+ const newDirectory = dirname(newAbsolutePath);
12
+
13
+ if (!existsSync(newDirectory)) {
14
+ mkdirSync(newDirectory, { recursive: true });
15
+ }
16
+
17
+ copyFileSync(oldAbsolutePath, newAbsolutePath);
18
+ });
19
+ }
@@ -0,0 +1,17 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+
4
+ export function createFiles(fileMapping, options) {
5
+ const { projectRoot } = options;
6
+
7
+ fileMapping.forEach((file, newPath) => {
8
+ const newAbsolutePath = join(projectRoot, newPath);
9
+ const newDirectory = dirname(newAbsolutePath);
10
+
11
+ if (!existsSync(newDirectory)) {
12
+ mkdirSync(newDirectory, { recursive: true });
13
+ }
14
+
15
+ writeFileSync(newAbsolutePath, file, 'utf8');
16
+ });
17
+ }
@@ -0,0 +1,28 @@
1
+ import { globSync } from 'glob';
2
+
3
+ export function findFiles(pattern, { cwd, ignoreList = [] }) {
4
+ if (!pattern) {
5
+ throw new RangeError('ERROR: The glob pattern is unknown.\n');
6
+ }
7
+
8
+ if (!cwd) {
9
+ throw new RangeError('ERROR: The current working directory is unknown.\n');
10
+ }
11
+
12
+ const filePaths = globSync(pattern, {
13
+ cwd,
14
+ dot: true,
15
+ ignore: ignoreList,
16
+ nodir: true,
17
+ });
18
+
19
+ return filePaths;
20
+ }
21
+
22
+ export function unionize(files) {
23
+ if (files.length <= 1) {
24
+ return files.join(',');
25
+ }
26
+
27
+ return `{${files.join(',')}}`;
28
+ }
@@ -0,0 +1,25 @@
1
+ import { join } from 'node:path';
2
+
3
+ export function renameDirectory(oldPath, { from, to }) {
4
+ if (from === '') {
5
+ return join(to, oldPath);
6
+ }
7
+
8
+ if (!oldPath.startsWith(`${from}/`)) {
9
+ return oldPath;
10
+ }
11
+
12
+ return join(to, oldPath.replace(`${from}/`, ''));
13
+ }
14
+
15
+ export function mapFilePaths(filePaths, directory) {
16
+ const { from, to } = directory;
17
+
18
+ return new Map(
19
+ filePaths.map((filePath) => {
20
+ const newPath = renameDirectory(filePath, { from, to });
21
+
22
+ return [filePath, newPath];
23
+ })
24
+ );
25
+ }
@@ -0,0 +1,22 @@
1
+ import { existsSync, mkdirSync, renameSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+
4
+ import { removeDirectoryIfEmpty } from './remove-directory-if-empty.js';
5
+
6
+ export function moveFiles(pathMapping, options) {
7
+ const { projectRoot } = options;
8
+
9
+ pathMapping.forEach((newPath, oldPath) => {
10
+ const oldAbsolutePath = join(projectRoot, oldPath);
11
+
12
+ const newAbsolutePath = join(projectRoot, newPath);
13
+ const newDirectory = dirname(newAbsolutePath);
14
+
15
+ if (!existsSync(newDirectory)) {
16
+ mkdirSync(newDirectory, { recursive: true });
17
+ }
18
+
19
+ renameSync(oldAbsolutePath, newAbsolutePath);
20
+ removeDirectoryIfEmpty({ oldPath, projectRoot });
21
+ });
22
+ }
@@ -0,0 +1,19 @@
1
+ import { readdirSync, rmSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+
4
+ export function removeDirectoryIfEmpty({ oldPath, projectRoot }) {
5
+ const directories = dirname(oldPath).split('/');
6
+ const depth = directories.length;
7
+
8
+ for (let i = 0; i < depth; i++) {
9
+ const directory = join(projectRoot, ...directories);
10
+ const numFilesLeft = readdirSync(directory).length;
11
+
12
+ if (numFilesLeft > 0) {
13
+ continue;
14
+ }
15
+
16
+ rmSync(directory, { recursive: true });
17
+ directories.pop();
18
+ }
19
+ }
@@ -0,0 +1,15 @@
1
+ import { rmSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ import { removeDirectoryIfEmpty } from './remove-directory-if-empty.js';
5
+
6
+ export function removeFiles(oldPaths, options) {
7
+ const { projectRoot } = options;
8
+
9
+ oldPaths.forEach((oldPath) => {
10
+ const oldAbsolutePath = join(projectRoot, oldPath);
11
+
12
+ rmSync(oldAbsolutePath);
13
+ removeDirectoryIfEmpty({ oldPath, projectRoot });
14
+ });
15
+ }
@@ -0,0 +1,7 @@
1
+ export * from './files/copy-files.js';
2
+ export * from './files/create-files.js';
3
+ export * from './files/find-files.js';
4
+ export * from './files/map-file-paths.js';
5
+ export * from './files/move-files.js';
6
+ export * from './files/remove-directory-if-empty.js';
7
+ export * from './files/remove-files.js';
@@ -0,0 +1,3 @@
1
+ export function convertToMap(object = {}) {
2
+ return new Map(Object.entries(object));
3
+ }
@@ -0,0 +1,5 @@
1
+ export function convertToObject(map) {
2
+ const sortedMap = new Map([...map.entries()].sort());
3
+
4
+ return Object.fromEntries(sortedMap);
5
+ }
@@ -0,0 +1,2 @@
1
+ export * from './json/convert-to-map.js';
2
+ export * from './json/convert-to-object.js';
@@ -0,0 +1,12 @@
1
+ /* https://github.com/ember-cli/ember-cli-string-utils/blob/v1.1.0/index.js */
2
+ const STRING_CAMELIZE_REGEXP = /(-|_|\.|\s)+(.)?/g;
3
+
4
+ export function camelize(string) {
5
+ return string
6
+ .replace(STRING_CAMELIZE_REGEXP, function (_match, _separator, character) {
7
+ return character ? character.toUpperCase() : '';
8
+ })
9
+ .replace(/^([A-Z])/, function (match) {
10
+ return match.toLowerCase();
11
+ });
12
+ }
@@ -0,0 +1,14 @@
1
+ /* https://github.com/ember-cli/ember-cli-string-utils/blob/v1.1.0/index.js */
2
+ import { camelize } from './camelize.js';
3
+
4
+ export function classify(string) {
5
+ const tokens = string.split('.');
6
+
7
+ const tokensTransformed = tokens.map((token) => {
8
+ const camelized = camelize(token);
9
+
10
+ return camelized.charAt(0).toUpperCase() + camelized.substring(1);
11
+ });
12
+
13
+ return tokensTransformed.join('.');
14
+ }
@@ -0,0 +1,6 @@
1
+ /* https://github.com/emberjs/ember.js/blob/v4.12.0/blueprints/component/index.js#L255-L256 */
2
+ import { classify } from '../ember-cli-string-utils/classify.js';
3
+
4
+ export function classifyEntityName(entityName) {
5
+ return classify(entityName.replace(/\//g, '-'));
6
+ }
@@ -0,0 +1,10 @@
1
+ /* https://github.com/emberjs/ember.js/blob/v4.12.0/blueprints/component-test/index.js#L13-L16 */
2
+ import { classify } from '../ember-cli-string-utils/classify.js';
3
+
4
+ export function doubleColonizeEntityName(entityName) {
5
+ const tokens = entityName.split('/');
6
+
7
+ const tokensTransformed = tokens.map(classify);
8
+
9
+ return tokensTransformed.join('::');
10
+ }
@@ -0,0 +1,19 @@
1
+ import { parse } from 'node:path';
2
+
3
+ import { classifyEntityName } from './classify.js';
4
+ import { doubleColonizeEntityName } from './double-colonize.js';
5
+
6
+ export function parseEntityName(entityName) {
7
+ const classifiedName = classifyEntityName(entityName);
8
+ const doubleColonizedName = doubleColonizeEntityName(entityName);
9
+ const { name: fileName } = parse(entityName);
10
+
11
+ const entity = {
12
+ classifiedName,
13
+ doubleColonizedName,
14
+ fileName,
15
+ name: entityName,
16
+ };
17
+
18
+ return entity;
19
+ }
@@ -0,0 +1,5 @@
1
+ export * from './string/ember-cli-string-utils/camelize.js';
2
+ export * from './string/ember-cli-string-utils/classify.js';
3
+ export * from './string/entity-name/classify.js';
4
+ export * from './string/entity-name/double-colonize.js';
5
+ export * from './string/entity-name/parse.js';