ember-codemod-v1-to-v2 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 (36) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +129 -0
  3. package/bin/ember-codemod-v1-to-v2.js +42 -0
  4. package/package.json +67 -0
  5. package/src/blueprints/ember-addon/.prettierignore +25 -0
  6. package/src/blueprints/ember-addon/.prettierrc.js +5 -0
  7. package/src/blueprints/ember-addon/__addonLocation__/.eslintignore +8 -0
  8. package/src/blueprints/ember-addon/__addonLocation__/addon-main.js +5 -0
  9. package/src/blueprints/ember-addon/__addonLocation__/babel.config.json +8 -0
  10. package/src/blueprints/ember-addon/__addonLocation__/rollup.config.js +58 -0
  11. package/src/blueprints/ember-addon/__addonLocation__/rollup.config.mjs +55 -0
  12. package/src/blueprints/ember-addon/__addonLocation__/unpublished-development-types/index.d.ts +13 -0
  13. package/src/blueprints/ember-addon/__testAppLocation__/ember-cli-build.js +16 -0
  14. package/src/blueprints/ember-addon/__testAppLocation__/types/global.d.ts +7 -0
  15. package/src/blueprints/ember-addon/package.json +76 -0
  16. package/src/blueprints/ember-addon/pnpm-workspace.yaml +3 -0
  17. package/src/index.js +5 -0
  18. package/src/migration/ember-addon/index.js +41 -0
  19. package/src/migration/ember-addon/steps/analyze-addon.js +30 -0
  20. package/src/migration/ember-addon/steps/augment-options.js +111 -0
  21. package/src/migration/ember-addon/steps/create-files-from-blueprint.js +68 -0
  22. package/src/migration/ember-addon/steps/index.js +11 -0
  23. package/src/migration/ember-addon/steps/move-addon-files.js +79 -0
  24. package/src/migration/ember-addon/steps/move-project-root-files.js +126 -0
  25. package/src/migration/ember-addon/steps/move-test-app-files.js +103 -0
  26. package/src/migration/ember-addon/steps/update-addon-package-json.js +130 -0
  27. package/src/migration/ember-addon/steps/update-addon-tsconfig-json.js +42 -0
  28. package/src/migration/ember-addon/steps/update-test-app-package-json.js +85 -0
  29. package/src/migration/ember-addon/steps/update-test-app-tsconfig-json.js +47 -0
  30. package/src/migration/ember-addon/steps/use-relative-paths.js +88 -0
  31. package/src/migration/index.js +1 -0
  32. package/src/utils/convert-json-object.js +9 -0
  33. package/src/utils/decide-version.js +24 -0
  34. package/src/utils/files.js +88 -0
  35. package/src/utils/map-file-paths.js +20 -0
  36. package/src/utils/process-template.js +12 -0
package/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2023 Isaac J. Lee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,129 @@
1
+ [![This project uses GitHub Actions for continuous integration.](https://github.com/ijlee2/ember-codemod-v1-to-v2/actions/workflows/ci.yml/badge.svg)](https://github.com/ijlee2/ember-codemod-v1-to-v2/actions/workflows/ci.yml)
2
+
3
+ # ember-codemod-v1-to-v2
4
+
5
+ _Codemod to convert Ember addons to v2 addon format_
6
+
7
+
8
+ ## Features
9
+
10
+ - Scaffolds files according to [`@embroider/addon-blueprint`](https://github.com/embroider-build/addon-blueprint)
11
+ - Switches Ember's "magic" import paths to relative paths
12
+ - Preserves your code whenever possible
13
+ - Supports [`ember-cli-typescript`](https://docs.ember-cli-typescript.com/) and [`glint`](https://typed-ember.gitbook.io/glint/)
14
+ - Focuses on maintainbility and extensibility
15
+
16
+
17
+ ## Usage
18
+
19
+ You can check [`ember-container-query`](https://github.com/ijlee2/ember-container-query/pull/151) as a reference.
20
+
21
+ Step 1. Quickly migrate to [v2 format](https://github.com/embroider-build/embroider/blob/main/ADDON-AUTHOR-GUIDE.md).<sup>1</sup>
22
+
23
+ ```sh
24
+ cd <your/project/path>
25
+ npx ember-codemod-v1-to-v2 <arguments>
26
+ ```
27
+
28
+ Step 2. Review the addon package.
29
+
30
+ - [x] Update the configuration files.<sup>2</sup>
31
+ - [x] Colocate stylesheets (if any). Let each component import the relevant stylesheet in the backing class.
32
+ - [x] Confirm that you can run all scripts in `package.json`.
33
+
34
+ Step 3. Review the test-app package.
35
+
36
+ - [x] Update the configuration files.<sup>2</sup>
37
+ - [x] Rename the remaining instances of `dummy` to `test-app`.
38
+ - [x] Confirm that you can run all scripts in `package.json`.
39
+
40
+ Step 4. Review the workspace root including CI/CD.
41
+
42
+ Step 5. Celebrate.
43
+
44
+ <sup>1. Before running `ember-codemod-v1-to-v2`, consider [meeting the prerequisites](https://github.com/embroider-build/embroider/blob/v1.8.3/PORTING-ADDONS-TO-V2.md#part-3-prerequisites-for-v2-addon). You can run [`ember-codemod-pod-to-octane`](https://github.com/ijlee2/ember-codemod-pod-to-octane) to un-pod a v1 addon.</sup>
45
+
46
+ <sup>2. Files such as `.eslintrc.js`, `.gitignore`, `babel.config.json` (addon only), `config/environment.js` (test-app only), `ember-cli-build.js` (test-app only), `package.json`, `rollup.config.js` (addon only), `tsconfig.json`, etc.</sup>
47
+
48
+
49
+ ### Arguments
50
+
51
+ In most cases, I recommend running the codemod without any arguments (i.e. allow the default values). This is to help different Ember projects converge to one layout.
52
+
53
+ <details>
54
+ <summary>Optional: Specify the addon location</summary>
55
+
56
+ By default, the package name decides where the addon package lives. Pass `--addon-location` to override the logic. This may be useful if you have a scoped package.
57
+
58
+ ```sh
59
+ npx ember-codemod-v1-to-v2 --addon-location="packages/ui-buttons"
60
+ ```
61
+
62
+ </details>
63
+
64
+ <details>
65
+ <summary>Optional: Specify the project root</summary>
66
+
67
+ Pass `--root` to run the codemod on a project somewhere else (i.e. not in the current directory).
68
+
69
+ ```sh
70
+ npx ember-codemod-v1-to-v2 --root=<your/project/path>
71
+ ```
72
+
73
+ </details>
74
+
75
+ <details>
76
+ <summary>Optional: Specify the test-app location</summary>
77
+
78
+ By default, the test-app package lives in the folder `test-app`. Pass `--test-app-location` to override the logic.
79
+
80
+ ```sh
81
+ npx ember-codemod-v1-to-v2 --test-app-location="docs"
82
+ ```
83
+
84
+ </details>
85
+
86
+ <details>
87
+ <summary>Optional: Specify the test-app name</summary>
88
+
89
+ By default, the test-app package is named `test-app`. Pass `--test-app-name` to override the logic. This may be useful if you have a workspace with many addons.
90
+
91
+ ```sh
92
+ npx ember-codemod-v1-to-v2 --test-app-name="test-app-for-ui-buttons"
93
+ ```
94
+
95
+ </details>
96
+
97
+
98
+ ### Limitations
99
+
100
+ The codemod is designed to cover typical uses of an Ember addon. It is not designed to cover one-off cases (e.g. caused by a custom build).
101
+
102
+ To better meet your needs, consider cloning the repo and running the codemod locally.
103
+
104
+ ```sh
105
+ cd <your/cloned/repo>
106
+ ./bin/ember-codemod-v1-to-v2.js --root=<your/project/path>
107
+ ```
108
+
109
+ You can also look at another codemod called [`ember-addon-migrator`](https://github.com/NullVoxPopuli/ember-addon-migrator).
110
+
111
+
112
+ ## Compatibility
113
+
114
+ * Node.js v16 or above
115
+
116
+
117
+ ## Contributing
118
+
119
+ If you have an open-sourced addon that I can use as a test fixture, reach out to me on [Discord](https://discord.gg/emberjs) at `ijlee2`. Please star this project so that I can gauge its importance to you and the Ember community. ⭐
120
+
121
+
122
+ ## Credits
123
+
124
+ The codemod steps were based on [Migrating an Ember addon to the next-gen v2 format](https://www.kaliber5.de/de/blog/v2-addon_en) and [Guide: Porting an Addon to v2](https://github.com/embroider-build/embroider/blob/v1.8.3/PORTING-ADDONS-TO-V2.md). The blueprints were derived from [`@embroider/addon-blueprint`](https://github.com/embroider-build/addon-blueprint).
125
+
126
+
127
+ ## License
128
+
129
+ This project is licensed under the [MIT License](LICENSE.md).
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ import yargs from 'yargs';
5
+ import { hideBin } from 'yargs/helpers';
6
+
7
+ import { runCodemod } from '../src/index.js';
8
+
9
+ // Provide a title to the process in `ps`
10
+ process.title = 'ember-codemod-v1-to-v2';
11
+
12
+ // Set codemod options
13
+ const { argv } = yargs(hideBin(process.argv))
14
+ .option('addon-location', {
15
+ describe: 'Location of the addon package',
16
+ type: 'string',
17
+ })
18
+ .option('root', {
19
+ describe: 'Location of your Ember addon',
20
+ type: 'string',
21
+ })
22
+ .option('test-app-location', {
23
+ describe: 'Location of the test-app package',
24
+ type: 'string',
25
+ })
26
+ .option('test-app-name', {
27
+ describe: 'Name of the test-app package',
28
+ type: 'string',
29
+ });
30
+
31
+ function castEmptyStringToUndefined(string) {
32
+ return string === '' ? undefined : string;
33
+ }
34
+
35
+ const options = {
36
+ addonLocation: castEmptyStringToUndefined(argv['addon-location']),
37
+ projectRoot: argv['root'] ?? process.cwd(),
38
+ testAppLocation: castEmptyStringToUndefined(argv['test-app-location']),
39
+ testAppName: castEmptyStringToUndefined(argv['test-app-name']),
40
+ };
41
+
42
+ runCodemod(options);
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "ember-codemod-v1-to-v2",
3
+ "version": "0.1.0",
4
+ "description": "Codemod to convert Ember addons to v2 addon format",
5
+ "keywords": [
6
+ "codemod",
7
+ "ember-codemod",
8
+ "ember-octane",
9
+ "ember-polaris",
10
+ "ember-v2-addon",
11
+ "emberjs",
12
+ "embroider"
13
+ ],
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/ijlee2/ember-codemod-v1-to-v2.git"
17
+ },
18
+ "license": "MIT",
19
+ "author": "Isaac J. Lee",
20
+ "main": "src/index.js",
21
+ "type": "module",
22
+ "bin": "./bin/ember-codemod-v1-to-v2.js",
23
+ "files": [
24
+ "bin/",
25
+ "src/"
26
+ ],
27
+ "directories": {
28
+ "test": "tests"
29
+ },
30
+ "scripts": {
31
+ "changelog": "lerna-changelog",
32
+ "lint": "eslint . --cache --ext=.cjs,.js",
33
+ "lint:fix": "eslint . --ext=.cjs,.js --fix",
34
+ "start": "node ./src/index.js",
35
+ "test": "mt tests --quiet"
36
+ },
37
+ "changelog": {
38
+ "labels": {
39
+ "breaking": "Breaking Change",
40
+ "bug": "Bug Fix",
41
+ "enhance: code": "Enhancement",
42
+ "enhance: dependency": "Internal",
43
+ "enhance: documentation": "Documentation",
44
+ "user feedback": "User Feedback"
45
+ }
46
+ },
47
+ "dependencies": {
48
+ "@babel/core": "^7.20.12",
49
+ "@babel/eslint-parser": "^7.19.1",
50
+ "glob": "^8.1.0",
51
+ "lodash.template": "^4.5.0",
52
+ "yargs": "^17.6.2"
53
+ },
54
+ "devDependencies": {
55
+ "@sondr3/minitest": "^0.1.1",
56
+ "eslint": "^8.32.0",
57
+ "eslint-config-prettier": "^8.6.0",
58
+ "eslint-plugin-prettier": "^4.2.1",
59
+ "eslint-plugin-simple-import-sort": "^8.0.0",
60
+ "fixturify": "^3.0.0",
61
+ "lerna-changelog": "^2.2.0",
62
+ "prettier": "^2.8.3"
63
+ },
64
+ "engines": {
65
+ "node": ">= 16"
66
+ }
67
+ }
@@ -0,0 +1,25 @@
1
+ # unconventional js
2
+ /blueprints/*/files/
3
+ /vendor/
4
+
5
+ # compiled output
6
+ /dist/
7
+ /tmp/
8
+
9
+ # dependencies
10
+ /bower_components/
11
+ /node_modules/
12
+
13
+ # misc
14
+ /coverage/
15
+ !.*
16
+ .*/
17
+ .eslintcache
18
+
19
+ # ember-try
20
+ /.node_modules.ember-try/
21
+ /bower.json.ember-try
22
+ /npm-shrinkwrap.json.ember-try
23
+ /package.json.ember-try
24
+ /package-lock.json.ember-try
25
+ /yarn.lock.ember-try
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ singleQuote: true,
5
+ };
@@ -0,0 +1,8 @@
1
+ # unconventional js
2
+ /blueprints/*/files/
3
+
4
+ # compiled output
5
+ /dist/
6
+
7
+ # misc
8
+ /coverage/
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ const { addonV1Shim } = require('@embroider/addon-shim');
4
+
5
+ module.exports = addonV1Shim(__dirname);
@@ -0,0 +1,8 @@
1
+ {
2
+ <% if (options.packages.addon.hasTypeScript) { %> "presets": [["@babel/preset-typescript"]],
3
+ <% } %> "plugins": [
4
+ "@embroider/addon-dev/template-colocation-plugin",
5
+ ["@babel/plugin-proposal-decorators", { "legacy": true }],
6
+ "@babel/plugin-proposal-class-properties"
7
+ ]
8
+ }
@@ -0,0 +1,58 @@
1
+ import babel from '@rollup/plugin-babel';
2
+ import copy from 'rollup-plugin-copy';
3
+ import { Addon } from '@embroider/addon-dev/rollup';
4
+
5
+ const addon = new Addon({
6
+ srcDir: 'src',
7
+ destDir: 'dist',
8
+ });
9
+
10
+ export default {
11
+ // This provides defaults that work well alongside `publicEntrypoints` below.
12
+ // You can augment this if you need to.
13
+ output: addon.output(),
14
+
15
+ plugins: [
16
+ // These are the modules that users should be able to import from your
17
+ // addon. Anything not listed here may get optimized away.
18
+ addon.publicEntrypoints([<%= context.publicEntrypoints.map((filePath) => `'${filePath}'`).join(', ') %>]),
19
+
20
+ // These are the modules that should get reexported into the traditional
21
+ // "app" tree. Things in here should also be in publicEntrypoints above, but
22
+ // not everything in publicEntrypoints necessarily needs to go here.
23
+ addon.appReexports([<%= context.appReexports.map((filePath) => `'${filePath}'`).join(', ') %>]),
24
+
25
+ // Follow the V2 Addon rules about dependencies. Your code can import from
26
+ // `dependencies` and `peerDependencies` as well as standard Ember-provided
27
+ // package names.
28
+ addon.dependencies(),
29
+
30
+ // This babel config should *not* apply presets or compile away ES modules.
31
+ // It exists only to provide development niceties for you, like automatic
32
+ // template colocation.
33
+ //
34
+ // By default, this will load the actual babel config from the file
35
+ // babel.config.json.
36
+ babel({
37
+ babelHelpers: 'bundled',
38
+ }),
39
+
40
+ // Ensure that standalone .hbs files are properly integrated as Javascript.
41
+ addon.hbs(),
42
+
43
+ // addons are allowed to contain imports of .css files, which we want rollup
44
+ // to leave alone and keep in the published output.
45
+ addon.keepAssets(['**/*.css']),
46
+
47
+ // Remove leftover build artifacts when starting a new build.
48
+ addon.clean(),
49
+
50
+ // Copy Readme and License into published package
51
+ copy({
52
+ targets: [
53
+ { src: '../README.md', dest: '.' },
54
+ { src: '../LICENSE.md', dest: '.' },
55
+ ],
56
+ }),
57
+ ],
58
+ };
@@ -0,0 +1,55 @@
1
+ import typescript from 'rollup-plugin-ts';
2
+ import copy from 'rollup-plugin-copy';
3
+ import { Addon } from '@embroider/addon-dev/rollup';
4
+
5
+ const addon = new Addon({
6
+ srcDir: 'src',
7
+ destDir: 'dist',
8
+ });
9
+
10
+ export default {
11
+ // This provides defaults that work well alongside `publicEntrypoints` below.
12
+ // You can augment this if you need to.
13
+ output: addon.output(),
14
+
15
+ plugins: [
16
+ // These are the modules that users should be able to import from your
17
+ // addon. Anything not listed here may get optimized away.
18
+ addon.publicEntrypoints([<%= context.publicEntrypoints.map((filePath) => `'${filePath}'`).join(', ') %>]),
19
+
20
+ // These are the modules that should get reexported into the traditional
21
+ // "app" tree. Things in here should also be in publicEntrypoints above, but
22
+ // not everything in publicEntrypoints necessarily needs to go here.
23
+ addon.appReexports([<%= context.appReexports.map((filePath) => `'${filePath}'`).join(', ') %>]),
24
+
25
+ // Follow the V2 Addon rules about dependencies. Your code can import from
26
+ // `dependencies` and `peerDependencies` as well as standard Ember-provided
27
+ // package names.
28
+ addon.dependencies(),
29
+
30
+ // compile TypeScript to latest JavaScript, including Babel transpilation
31
+ typescript({
32
+ transpiler: 'babel',
33
+ browserslist: false,
34
+ transpileOnly: false,
35
+ }),
36
+
37
+ // Ensure that standalone .hbs files are properly integrated as Javascript.
38
+ addon.hbs(),
39
+
40
+ // addons are allowed to contain imports of .css files, which we want rollup
41
+ // to leave alone and keep in the published output.
42
+ addon.keepAssets(['**/*.css']),
43
+
44
+ // Remove leftover build artifacts when starting a new build.
45
+ addon.clean(),
46
+
47
+ // Copy Readme and License into published package
48
+ copy({
49
+ targets: [
50
+ { src: '../README.md', dest: '.' },
51
+ { src: '../LICENSE.md', dest: '.' },
52
+ ],
53
+ }),
54
+ ],
55
+ };
@@ -0,0 +1,13 @@
1
+ // Add any types here that you need for local development only.
2
+ // These will *not* be published as part of your addon, so be careful that your published code does not rely on them!
3
+
4
+ <% if (options.packages.addon.hasGlint) { %>import '@glint/environment-ember-loose';
5
+
6
+ declare module '@glint/environment-ember-loose/registry' {
7
+ // Remove this once entries have been added! 👇
8
+ // eslint-disable-next-line @typescript-eslint/no-empty-interface
9
+ export default interface Registry {
10
+ // Add any registry entries from other addons here that your addon itself uses (in non-strict mode templates)
11
+ // See https://typed-ember.gitbook.io/glint/using-glint/ember/using-addons
12
+ }
13
+ }<% } %>
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const EmberApp = require('ember-cli/lib/broccoli/ember-app');
4
+
5
+ module.exports = function (defaults) {
6
+ const app = new EmberApp(defaults, {
7
+ // Add options here
8
+ autoImport: {
9
+ watchDependencies: ['<%= options.packages.addon.name %>'],
10
+ },
11
+ });
12
+
13
+ const { maybeEmbroider } = require('@embroider/test-setup');
14
+
15
+ return maybeEmbroider(app);
16
+ };
@@ -0,0 +1,7 @@
1
+ // Types for compiled templates
2
+ declare module '<%= options.packages.testApp.name %>/templates/*' {
3
+ import { TemplateFactory } from 'ember-cli-htmlbars';
4
+
5
+ const tmpl: TemplateFactory;
6
+ export default tmpl;
7
+ }
@@ -0,0 +1,76 @@
1
+ <% if (options.packageManager.isNpm) { %>{
2
+ "name": "<%= options.packages.addon.name %>",
3
+ "version": "<%= options.packages.addon.version %>",
4
+ "private": true,
5
+ "repository": "",
6
+ "license": "MIT",
7
+ "author": "",
8
+ "workspaces": [
9
+ "<%= options.packages.addon.name %>",
10
+ "<%= options.packages.testApp.name %>"
11
+ ],
12
+ "scripts": {
13
+ "build": "npm run build --workspace <%= options.packages.addon.name %>",
14
+ "lint": "npm run lint --workspaces --if-present",
15
+ "lint:fix": "npm run lint:fix --workspaces --if-present",
16
+ "prepare": "npm run build",
17
+ "start": "concurrently 'npm:start:*' --restart-after 5000 --prefix-colors cyan,white,yellow",
18
+ "start:addon": "npm start --workspace <%= options.packages.addon.name %>",
19
+ "start:tests": "npm start --workspace <%= options.packages.testApp.name %>",
20
+ "test": "npm run test --workspaces --if-present"
21
+ },
22
+ "devDependencies": {
23
+ "concurrently": "<%= options.packages.addon.dependencies.get('concurrently') ?? '^7.6.0' %>",
24
+ "prettier": "<%= options.packages.addon.dependencies.get('prettier') ?? '^2.8.3' %>"
25
+ }
26
+ }<% } else if (options.packageManager.isPnpm) { %>{
27
+ "name": "<%= options.packages.addon.name %>",
28
+ "version": "<%= options.packages.addon.version %>",
29
+ "private": true,
30
+ "repository": "",
31
+ "license": "MIT",
32
+ "author": "",
33
+ "workspaces": [
34
+ "<%= options.packages.addon.name %>",
35
+ "<%= options.packages.testApp.name %>"
36
+ ],
37
+ "scripts": {
38
+ "build": "pnpm --filter <%= options.packages.addon.name %> build",
39
+ "lint": "pnpm --filter '*' lint",
40
+ "lint:fix": "pnpm --filter '*' lint:fix",
41
+ "prepare": "pnpm build",
42
+ "start": "concurrently 'npm:start:*' --restart-after 5000 --prefix-colors cyan,white,yellow",
43
+ "start:addon": "pnpm --filter <%= options.packages.addon.name %> start",
44
+ "start:test": "pnpm --filter <%= options.packages.testApp.name %> start",
45
+ "test": "pnpm --filter '*' test"
46
+ },
47
+ "devDependencies": {
48
+ "concurrently": "<%= options.packages.addon.dependencies.get('concurrently') ?? '^7.6.0' %>",
49
+ "prettier": "<%= options.packages.addon.dependencies.get('prettier') ?? '^2.8.3' %>"
50
+ }
51
+ }<% } else if (options.packageManager.isYarn) { %>{
52
+ "name": "<%= options.packages.addon.name %>",
53
+ "version": "<%= options.packages.addon.version %>",
54
+ "private": true,
55
+ "repository": "",
56
+ "license": "MIT",
57
+ "author": "",
58
+ "workspaces": [
59
+ "<%= options.packages.addon.name %>",
60
+ "<%= options.packages.testApp.name %>"
61
+ ],
62
+ "scripts": {
63
+ "build": "yarn workspace <%= options.packages.addon.name %> run build",
64
+ "lint": "yarn workspaces run lint",
65
+ "lint:fix": "yarn workspaces run lint:fix",
66
+ "prepare": "yarn build",
67
+ "start": "concurrently 'npm:start:*' --restart-after 5000 --prefix-colors cyan,white,yellow",
68
+ "start:addon": "yarn workspace <%= options.packages.addon.name %> run start",
69
+ "start:test": "yarn workspace <%= options.packages.testApp.name %> run start",
70
+ "test": "yarn workspaces run test"
71
+ },
72
+ "devDependencies": {
73
+ "concurrently": "<%= options.packages.addon.dependencies.get('concurrently') ?? '^7.6.0' %>",
74
+ "prettier": "<%= options.packages.addon.dependencies.get('prettier') ?? '^2.8.3' %>"
75
+ }
76
+ }<% } %>
@@ -0,0 +1,3 @@
1
+ packages:
2
+ - '<%= options.packages.addon.name %>'
3
+ - '<%= options.packages.testApp.name %>'
package/src/index.js ADDED
@@ -0,0 +1,5 @@
1
+ import { migrateEmberAddon } from './migration/index.js';
2
+
3
+ export function runCodemod(options) {
4
+ migrateEmberAddon(options);
5
+ }
@@ -0,0 +1,41 @@
1
+ import {
2
+ analyzeAddon,
3
+ augmentOptions,
4
+ createFilesFromBlueprint,
5
+ moveAddonFiles,
6
+ moveProjectRootFiles,
7
+ moveTestAppFiles,
8
+ updateAddonPackageJson,
9
+ updateAddonTsconfigJson,
10
+ updateTestAppPackageJson,
11
+ updateTestAppTsconfigJson,
12
+ useRelativePaths,
13
+ } from './steps/index.js';
14
+
15
+ export function migrateEmberAddon(options) {
16
+ const augmentedOptions = augmentOptions(options);
17
+ const { isV1Addon } = augmentedOptions.packages.addon;
18
+
19
+ // Guarantee idempotency
20
+ if (!isV1Addon) {
21
+ return;
22
+ }
23
+
24
+ // Prepare for migration
25
+ const context = analyzeAddon(augmentedOptions);
26
+ useRelativePaths(augmentedOptions);
27
+
28
+ // Preserve code
29
+ moveAddonFiles(augmentedOptions);
30
+ moveTestAppFiles(augmentedOptions);
31
+ moveProjectRootFiles(augmentedOptions);
32
+
33
+ // Get the latest code from blueprint
34
+ createFilesFromBlueprint(context, augmentedOptions);
35
+
36
+ // Fine-tune individual files
37
+ updateAddonPackageJson(augmentedOptions);
38
+ updateAddonTsconfigJson(augmentedOptions);
39
+ updateTestAppPackageJson(augmentedOptions);
40
+ updateTestAppTsconfigJson(augmentedOptions);
41
+ }
@@ -0,0 +1,30 @@
1
+ import { join } from 'node:path';
2
+
3
+ import glob from 'glob';
4
+
5
+ function getAppReexports(options) {
6
+ const { projectRoot } = options;
7
+
8
+ const filePaths = glob.sync('**/*.js', {
9
+ cwd: join(projectRoot, 'app'),
10
+ });
11
+
12
+ return filePaths;
13
+ }
14
+
15
+ function getPublicEntrypoints(options) {
16
+ const { projectRoot } = options;
17
+
18
+ const filePaths = glob.sync('**/*.{js,ts}', {
19
+ cwd: join(projectRoot, 'addon'),
20
+ });
21
+
22
+ return filePaths.map((filePath) => filePath.replace(/ts$/, 'js'));
23
+ }
24
+
25
+ export function analyzeAddon(options) {
26
+ const appReexports = getAppReexports(options);
27
+ const publicEntrypoints = getPublicEntrypoints(options);
28
+
29
+ return { appReexports, publicEntrypoints };
30
+ }