ember-codemod-v1-to-v2 0.3.2 → 0.4.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.
package/README.md CHANGED
@@ -8,7 +8,6 @@ _Codemod to convert Ember addons to v2 addon format_
8
8
  ## Features
9
9
 
10
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
11
  - Preserves your code whenever possible
13
12
  - Supports [`ember-cli-typescript`](https://docs.ember-cli-typescript.com/) and [`glint`](https://typed-ember.gitbook.io/glint/)
14
13
  - Focuses on maintainability and extensibility
@@ -43,7 +42,7 @@ Step 5. Celebrate.
43
42
 
44
43
  <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
44
 
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>
45
+ <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.mjs` (addon only), `tsconfig.json`, etc.</sup>
47
46
 
48
47
 
49
48
  ### Arguments
@@ -116,7 +115,7 @@ You can also look at another codemod called [`ember-addon-migrator`](https://git
116
115
 
117
116
  ## Contributing
118
117
 
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. ⭐
118
+ If you have an open-sourced addon (v1 or v2) that I can use as a reference, 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
119
 
121
120
 
122
121
  ## Credits
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember-codemod-v1-to-v2",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "description": "Codemod to convert Ember addons to v2 addon format",
5
5
  "keywords": [
6
6
  "codemod",
@@ -45,16 +45,16 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@babel/core": "^7.20.12",
48
+ "@babel/core": "^7.21.0",
49
49
  "@babel/eslint-parser": "^7.19.1",
50
- "glob": "^8.1.0",
50
+ "glob": "^9.2.1",
51
51
  "lodash.template": "^4.5.0",
52
52
  "strip-json-comments": "^5.0.0",
53
- "yargs": "^17.6.2"
53
+ "yargs": "^17.7.1"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@sondr3/minitest": "^0.1.1",
57
- "eslint": "^8.33.0",
57
+ "eslint": "^8.35.0",
58
58
  "eslint-config-prettier": "^8.6.0",
59
59
  "eslint-plugin-import": "^2.27.5",
60
60
  "eslint-plugin-n": "^15.6.1",
@@ -13,8 +13,8 @@
13
13
  # misc
14
14
  /coverage/
15
15
  !.*
16
- .*/
17
16
  .eslintcache
17
+ .lint-todo/
18
18
 
19
19
  # ember-try
20
20
  /.node_modules.ember-try/
@@ -1,18 +1,17 @@
1
1
  # See https://help.github.com/ignore-files/ for more about ignoring files.
2
2
 
3
3
  # compiled output
4
- /dist/
5
- /tmp/
4
+ dist/
6
5
 
7
6
  # dependencies
8
- /bower_components/
9
- /node_modules/
7
+ node_modules/
10
8
 
11
9
  # misc
12
10
  /.env*
13
11
  /.pnp*
12
+ /.pnpm-debug.log
14
13
  /.sass-cache
15
- /.eslintcache
14
+ .eslintcache
16
15
  /connect.lock
17
16
  /coverage/
18
17
  /libpeerconnection.log
@@ -22,11 +21,5 @@
22
21
 
23
22
  # ember-try
24
23
  /.node_modules.ember-try/
25
- /bower.json.ember-try
26
- /npm-shrinkwrap.json.ember-try
27
24
  /package.json.ember-try
28
- /package-lock.json.ember-try
29
25
  /yarn.lock.ember-try
30
-
31
- # broccoli-debug
32
- /DEBUG/
@@ -30,10 +30,6 @@
30
30
  "repository": "",
31
31
  "license": "MIT",
32
32
  "author": "",
33
- "workspaces": [
34
- "<%= options.locations.addon %>",
35
- "<%= options.locations.testApp %>"
36
- ],
37
33
  "scripts": {
38
34
  "build": "pnpm --filter <%= options.packages.addon.name %> build",
39
35
  "lint": "pnpm --filter '*' lint",
@@ -9,7 +9,6 @@ import {
9
9
  updateAddonTsconfigJson,
10
10
  updateTestAppPackageJson,
11
11
  updateTestAppTsconfigJson,
12
- useRelativePaths,
13
12
  } from './steps/index.js';
14
13
 
15
14
  export function migrateEmberAddon(codemodOptions) {
@@ -23,7 +22,6 @@ export function migrateEmberAddon(codemodOptions) {
23
22
 
24
23
  // Prepare for migration
25
24
  const context = analyzeAddon(options);
26
- useRelativePaths(options);
27
25
 
28
26
  // Preserve code
29
27
  moveAddonFiles(options);
@@ -34,7 +32,7 @@ export function migrateEmberAddon(codemodOptions) {
34
32
  createFilesFromBlueprint(context, options);
35
33
 
36
34
  // Fine-tune individual files
37
- updateAddonPackageJson(options);
35
+ updateAddonPackageJson(context, options);
38
36
  updateAddonTsconfigJson(options);
39
37
  updateTestAppPackageJson(options);
40
38
  updateTestAppTsconfigJson(options);
@@ -1,21 +1,21 @@
1
- import glob from 'glob';
2
-
3
1
  import { decideVersion } from '../../../utils/blueprints.js';
4
- import { renameDirectory } from '../../../utils/files.js';
2
+ import { findFiles, renameDirectory } from '../../../utils/files.js';
5
3
 
6
4
  function getAppReexports(options) {
7
5
  const { projectRoot } = options;
8
6
 
9
- const filePaths = glob.sync('app/**/*.js', {
7
+ const filePaths = findFiles('app/**/*.js', {
10
8
  cwd: projectRoot,
11
9
  });
12
10
 
13
- return filePaths.map((filePath) => {
14
- return renameDirectory(filePath, {
15
- from: 'app',
16
- to: '',
17
- });
18
- });
11
+ return filePaths
12
+ .map((filePath) => {
13
+ return renameDirectory(filePath, {
14
+ from: 'app',
15
+ to: '',
16
+ });
17
+ })
18
+ .sort();
19
19
  }
20
20
 
21
21
  function getProjectRootDevDependencies(options) {
@@ -25,10 +25,27 @@ function getProjectRootDevDependencies(options) {
25
25
  };
26
26
  }
27
27
 
28
+ function getPublicAssets(options) {
29
+ const { projectRoot } = options;
30
+
31
+ const filePaths = findFiles('public/**/*', {
32
+ cwd: projectRoot,
33
+ });
34
+
35
+ return filePaths
36
+ .map((filePath) => {
37
+ return renameDirectory(filePath, {
38
+ from: 'public',
39
+ to: '',
40
+ });
41
+ })
42
+ .sort();
43
+ }
44
+
28
45
  function getPublicEntrypoints(options) {
29
46
  const { projectRoot } = options;
30
47
 
31
- const filePaths = glob.sync('{addon,addon-test-support}/**/*.{js,ts}', {
48
+ const filePaths = findFiles('{addon,addon-test-support}/**/*.{js,ts}', {
32
49
  cwd: projectRoot,
33
50
  });
34
51
 
@@ -55,6 +72,7 @@ export function analyzeAddon(options) {
55
72
  return {
56
73
  addon: {
57
74
  appReexports: getAppReexports(options),
75
+ publicAssets: getPublicAssets(options),
58
76
  publicEntrypoints: getPublicEntrypoints(options),
59
77
  },
60
78
  projectRoot: {
@@ -1,20 +1,8 @@
1
1
  import { readFileSync } from 'node:fs';
2
- import { dirname, join } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
2
+ import { join } from 'node:path';
4
3
 
5
- import glob from 'glob';
6
-
7
- import { processTemplate } from '../../../utils/blueprints.js';
8
- import { createFiles } from '../../../utils/files.js';
9
-
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = dirname(__filename);
12
-
13
- function getBlueprintRoot() {
14
- const codemodRoot = join(__dirname, '../../../..');
15
-
16
- return join(codemodRoot, 'src/blueprints/ember-addon');
17
- }
4
+ import { blueprintRoot, processTemplate } from '../../../utils/blueprints.js';
5
+ import { createFiles, findFiles } from '../../../utils/files.js';
18
6
 
19
7
  function getFilePath(blueprintFilePath, options) {
20
8
  const { locations } = options;
@@ -43,15 +31,11 @@ function getFilesToSkip(options) {
43
31
  }
44
32
 
45
33
  export function createFilesFromBlueprint(context, options) {
46
- const blueprintRoot = getBlueprintRoot();
47
-
48
34
  const filesToSkip = getFilesToSkip(options);
49
35
 
50
- const blueprintFilePaths = glob.sync('**/*', {
36
+ const blueprintFilePaths = findFiles('**/*', {
51
37
  cwd: blueprintRoot,
52
- dot: true,
53
- ignore: filesToSkip,
54
- nodir: true,
38
+ ignoreList: filesToSkip,
55
39
  });
56
40
 
57
41
  const fileMapping = new Map(
@@ -1,7 +1,26 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
 
4
- import glob from 'glob';
4
+ import { findFiles, unionize } from '../../../utils/files.js';
5
+
6
+ function validatePackageJson({ name, version }) {
7
+ if (!name) {
8
+ throw new SyntaxError('Package name is missing.');
9
+ }
10
+
11
+ if (name.includes('/')) {
12
+ // eslint-disable-next-line no-unused-vars
13
+ const [_scope, packageName] = name.split('/');
14
+
15
+ if (!packageName) {
16
+ throw new SyntaxError('Package name is missing.');
17
+ }
18
+ }
19
+
20
+ if (!version) {
21
+ throw new SyntaxError('Package version is missing.');
22
+ }
23
+ }
5
24
 
6
25
  function analyzePackageJson(codemodOptions) {
7
26
  const { projectRoot } = codemodOptions;
@@ -20,13 +39,7 @@ function analyzePackageJson(codemodOptions) {
20
39
  version,
21
40
  } = JSON.parse(packageJsonFile);
22
41
 
23
- if (!name) {
24
- throw new SyntaxError('Package name is missing.');
25
- }
26
-
27
- if (!version) {
28
- throw new SyntaxError('Package version is missing.');
29
- }
42
+ validatePackageJson({ name, version });
30
43
 
31
44
  const projectDependencies = new Map([
32
45
  ...Object.entries(dependencies ?? {}),
@@ -51,11 +64,19 @@ function analyzePackageJson(codemodOptions) {
51
64
  function analyzePackageManager(codemodOptions) {
52
65
  const { projectRoot } = codemodOptions;
53
66
 
54
- const lockFiles = glob.sync('{package-lock.json,pnpm-lock.yaml,yarn.lock}', {
67
+ const mapping = new Map([
68
+ ['package-lock.json', 'npm'],
69
+ ['pnpm-lock.yaml', 'pnpm'],
70
+ ['yarn.lock', 'yarn'],
71
+ ]);
72
+
73
+ const lockFiles = [...mapping.keys()];
74
+
75
+ const filePaths = findFiles(unionize(lockFiles), {
55
76
  cwd: projectRoot,
56
77
  });
57
78
 
58
- if (lockFiles.length !== 1) {
79
+ if (filePaths.length !== 1) {
59
80
  console.warn('WARNING: Package manager is unknown. Yarn will be assumed.');
60
81
 
61
82
  return {
@@ -65,12 +86,12 @@ function analyzePackageManager(codemodOptions) {
65
86
  };
66
87
  }
67
88
 
68
- const [lockFile] = lockFiles;
89
+ const packageManager = mapping.get(filePaths[0]);
69
90
 
70
91
  return {
71
- isNpm: lockFile === 'package-lock.json',
72
- isPnpm: lockFile === 'pnpm-lock.yaml',
73
- isYarn: lockFile === 'yarn.lock',
92
+ isNpm: packageManager === 'npm',
93
+ isPnpm: packageManager === 'pnpm',
94
+ isYarn: packageManager === 'yarn',
74
95
  };
75
96
  }
76
97
 
@@ -81,13 +102,7 @@ function deriveAddonLocation(addonPackage) {
81
102
  }
82
103
 
83
104
  // eslint-disable-next-line no-unused-vars
84
- const [scope, packageName] = addonPackage.name.split('/');
85
-
86
- if (!packageName) {
87
- throw new SyntaxError(
88
- `ERROR: In package.json, the package name \`${addonPackage.name}\` is not valid.`
89
- );
90
- }
105
+ const [_scope, packageName] = addonPackage.name.split('/');
91
106
 
92
107
  return packageName;
93
108
  }
@@ -8,4 +8,3 @@ export * from './update-addon-package-json.js';
8
8
  export * from './update-addon-tsconfig-json.js';
9
9
  export * from './update-test-app-package-json.js';
10
10
  export * from './update-test-app-tsconfig-json.js';
11
- export * from './use-relative-paths.js';
@@ -1,14 +1,15 @@
1
- import glob from 'glob';
2
-
3
- import { mapFilePaths, moveFiles, removeFiles } from '../../../utils/files.js';
1
+ import {
2
+ findFiles,
3
+ mapFilePaths,
4
+ moveFiles,
5
+ removeFiles,
6
+ } from '../../../utils/files.js';
4
7
 
5
8
  function moveAddonFolder(options) {
6
9
  const { locations, projectRoot } = options;
7
10
 
8
- const filePaths = glob.sync('addon/**/*', {
11
+ const filePaths = findFiles('addon/**/*', {
9
12
  cwd: projectRoot,
10
- dot: true,
11
- nodir: true,
12
13
  });
13
14
 
14
15
  const pathMapping = mapFilePaths(filePaths, {
@@ -22,10 +23,8 @@ function moveAddonFolder(options) {
22
23
  function moveAddonTestSupportFolder(options) {
23
24
  const { locations, projectRoot } = options;
24
25
 
25
- const filePaths = glob.sync('addon-test-support/**/*', {
26
+ const filePaths = findFiles('addon-test-support/**/*', {
26
27
  cwd: projectRoot,
27
- dot: true,
28
- nodir: true,
29
28
  });
30
29
 
31
30
  const pathMapping = mapFilePaths(filePaths, {
@@ -39,10 +38,8 @@ function moveAddonTestSupportFolder(options) {
39
38
  function moveBlueprintsFolder(options) {
40
39
  const { locations, projectRoot } = options;
41
40
 
42
- const filePaths = glob.sync('blueprints/**/*', {
41
+ const filePaths = findFiles('blueprints/**/*', {
43
42
  cwd: projectRoot,
44
- dot: true,
45
- nodir: true,
46
43
  });
47
44
 
48
45
  const pathMapping = mapFilePaths(filePaths, {
@@ -53,13 +50,26 @@ function moveBlueprintsFolder(options) {
53
50
  moveFiles(pathMapping, options);
54
51
  }
55
52
 
53
+ function movePublicFolder(options) {
54
+ const { locations, projectRoot } = options;
55
+
56
+ const filePaths = findFiles('public/**/*', {
57
+ cwd: projectRoot,
58
+ });
59
+
60
+ const pathMapping = mapFilePaths(filePaths, {
61
+ from: 'public',
62
+ to: `${locations.addon}/public`,
63
+ });
64
+
65
+ moveFiles(pathMapping, options);
66
+ }
67
+
56
68
  function removeAppFolder(options) {
57
69
  const { projectRoot } = options;
58
70
 
59
- const filePaths = glob.sync('app/**/*', {
71
+ const filePaths = findFiles('app/**/*', {
60
72
  cwd: projectRoot,
61
- dot: true,
62
- nodir: true,
63
73
  });
64
74
 
65
75
  removeFiles(filePaths, options);
@@ -69,5 +79,6 @@ export function moveAddonFiles(options) {
69
79
  moveAddonFolder(options);
70
80
  moveAddonTestSupportFolder(options);
71
81
  moveBlueprintsFolder(options);
82
+ movePublicFolder(options);
72
83
  removeAppFolder(options);
73
84
  }
@@ -1,26 +1,18 @@
1
- import glob from 'glob';
2
-
3
1
  import {
4
2
  copyFiles,
3
+ findFiles,
5
4
  mapFilePaths,
6
5
  moveFiles,
7
6
  removeFiles,
7
+ unionize,
8
8
  } from '../../../utils/files.js';
9
9
 
10
- function globPattern(files) {
11
- if (files.length <= 1) {
12
- return files.join(',');
13
- }
14
-
15
- return `{${files.join(',')}}`;
16
- }
17
-
18
10
  function copyToAddon(options) {
19
11
  const { locations, projectRoot } = options;
20
12
 
21
13
  const files = ['LICENSE.md', 'README.md'];
22
14
 
23
- const filePaths = glob.sync(globPattern(files), {
15
+ const filePaths = findFiles(unionize(files), {
24
16
  cwd: projectRoot,
25
17
  });
26
18
 
@@ -55,7 +47,7 @@ function moveToAddonAndTestApp(options) {
55
47
  files.add('tsconfig.json');
56
48
  }
57
49
 
58
- const filePaths = glob.sync(globPattern([...files]), {
50
+ const filePaths = findFiles(unionize([...files]), {
59
51
  cwd: projectRoot,
60
52
  });
61
53
 
@@ -86,7 +78,7 @@ function moveToTestApp(options) {
86
78
  'testem.js',
87
79
  ];
88
80
 
89
- const filePaths = glob.sync(globPattern(files), {
81
+ const filePaths = findFiles(unionize(files), {
90
82
  cwd: projectRoot,
91
83
  });
92
84
 
@@ -103,7 +95,7 @@ function removeFromProjectRoot(options) {
103
95
 
104
96
  const files = ['.npmignore', 'index.js'];
105
97
 
106
- const filePaths = glob.sync(globPattern(files), {
98
+ const filePaths = findFiles(unionize(files), {
107
99
  cwd: projectRoot,
108
100
  });
109
101
 
@@ -1,17 +1,13 @@
1
1
  import { readFileSync, writeFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
 
4
- import glob from 'glob';
5
-
6
- import { mapFilePaths, moveFiles } from '../../../utils/files.js';
4
+ import { findFiles, mapFilePaths, moveFiles } from '../../../utils/files.js';
7
5
 
8
6
  function moveTestsFolder(options) {
9
7
  const { locations, projectRoot } = options;
10
8
 
11
- let filePaths = glob.sync('tests/dummy/**/*', {
9
+ let filePaths = findFiles('tests/dummy/**/*', {
12
10
  cwd: projectRoot,
13
- dot: true,
14
- nodir: true,
15
11
  });
16
12
 
17
13
  let pathMapping = mapFilePaths(filePaths, {
@@ -21,11 +17,9 @@ function moveTestsFolder(options) {
21
17
 
22
18
  moveFiles(pathMapping, options);
23
19
 
24
- filePaths = glob.sync('tests/**/*', {
20
+ filePaths = findFiles('tests/**/*', {
25
21
  cwd: projectRoot,
26
- dot: true,
27
- ignore: 'tests/dummy/**/*',
28
- nodir: true,
22
+ ignoreList: ['tests/dummy/**/*'],
29
23
  });
30
24
 
31
25
  pathMapping = mapFilePaths(filePaths, {
@@ -43,10 +37,8 @@ function moveTypesFolder(options) {
43
37
  return;
44
38
  }
45
39
 
46
- let filePaths = glob.sync('types/dummy/**/*', {
40
+ let filePaths = findFiles('types/dummy/**/*', {
47
41
  cwd: projectRoot,
48
- dot: true,
49
- nodir: true,
50
42
  });
51
43
 
52
44
  let pathMapping = mapFilePaths(filePaths, {
@@ -56,11 +48,9 @@ function moveTypesFolder(options) {
56
48
 
57
49
  moveFiles(pathMapping, options);
58
50
 
59
- filePaths = glob.sync('types/**/*', {
51
+ filePaths = findFiles('types/**/*', {
60
52
  cwd: projectRoot,
61
- dot: true,
62
- ignore: 'types/dummy/**/*',
63
- nodir: true,
53
+ ignoreList: ['types/dummy/**/*'],
64
54
  });
65
55
 
66
56
  pathMapping = mapFilePaths(filePaths, {
@@ -76,10 +66,8 @@ function renameDummy(options) {
76
66
 
77
67
  // File extensions had been specified, partly to encode assumptions
78
68
  // about Ember, and partly to avoid corrupting non-text files
79
- const filePaths = glob.sync(`${locations.testApp}/**/*.{d.ts,html,js,ts}`, {
69
+ const filePaths = findFiles(`${locations.testApp}/**/*.{d.ts,html,js,ts}`, {
80
70
  cwd: projectRoot,
81
- dot: true,
82
- nodir: true,
83
71
  });
84
72
 
85
73
  filePaths.forEach((filePath) => {
@@ -20,7 +20,7 @@ function updateDependencies(packageJson, options) {
20
20
 
21
21
  const packagesToInstall = ['@embroider/addon-shim'];
22
22
 
23
- packagesToInstall.forEach((packageName) => {
23
+ packagesToInstall.sort().forEach((packageName) => {
24
24
  const version = decideVersion(packageName, options);
25
25
 
26
26
  dependencies.set(packageName, version);
@@ -46,28 +46,23 @@ function updateDevDependencies(packageJson, options) {
46
46
  */
47
47
  devDependencies.clear();
48
48
 
49
- const packagesToInstall = packages.addon.hasTypeScript
50
- ? [
51
- '@babel/core',
52
- '@babel/plugin-proposal-class-properties',
53
- '@babel/plugin-proposal-decorators',
54
- '@babel/preset-typescript',
55
- '@embroider/addon-dev',
56
- 'rollup',
57
- 'rollup-plugin-copy',
58
- 'rollup-plugin-ts',
59
- ]
60
- : [
61
- '@babel/core',
62
- '@babel/plugin-proposal-class-properties',
63
- '@babel/plugin-proposal-decorators',
64
- '@embroider/addon-dev',
65
- '@rollup/plugin-babel',
66
- 'rollup',
67
- 'rollup-plugin-copy',
68
- ];
69
-
70
- packagesToInstall.forEach((packageName) => {
49
+ const packagesToInstall = new Set([
50
+ '@babel/core',
51
+ '@babel/plugin-proposal-class-properties',
52
+ '@babel/plugin-proposal-decorators',
53
+ '@embroider/addon-dev',
54
+ '@rollup/plugin-babel',
55
+ 'rollup',
56
+ 'rollup-plugin-copy',
57
+ ]);
58
+
59
+ if (packages.addon.hasTypeScript) {
60
+ packagesToInstall.add('@babel/preset-typescript');
61
+ packagesToInstall.add('rollup-plugin-ts');
62
+ packagesToInstall.delete('@rollup/plugin-babel');
63
+ }
64
+
65
+ [...packagesToInstall].sort().forEach((packageName) => {
71
66
  const version = decideVersion(packageName, options);
72
67
 
73
68
  devDependencies.set(packageName, version);
@@ -76,32 +71,64 @@ function updateDevDependencies(packageJson, options) {
76
71
  packageJson['devDependencies'] = convertToObject(devDependencies);
77
72
  }
78
73
 
79
- function updateOtherFields(packageJson, options) {
74
+ function updateOtherFields(packageJson, context, options) {
80
75
  const { packages } = options;
76
+ const hasPublicAssets = context.addon.publicAssets.length > 0;
77
+
78
+ if (hasPublicAssets) {
79
+ const publicAssetMapping = context.addon.publicAssets.reduce(
80
+ (accumulator, filePath) => {
81
+ const from = `./public/${filePath}`;
82
+ const to = `/${packages.addon.name}/${filePath}`;
83
+
84
+ accumulator[from] = to;
85
+
86
+ return accumulator;
87
+ },
88
+ {}
89
+ );
90
+
91
+ packageJson['ember-addon'] = {
92
+ 'app-js': {},
93
+ main: 'addon-main.cjs',
94
+ 'public-assets': publicAssetMapping,
95
+ type: 'addon',
96
+ version: 2,
97
+ };
98
+ } else {
99
+ packageJson['ember-addon'] = {
100
+ 'app-js': {},
101
+ main: 'addon-main.cjs',
102
+ type: 'addon',
103
+ version: 2,
104
+ };
105
+ }
81
106
 
82
- packageJson['ember-addon'] = {
83
- 'app-js': {},
84
- main: 'addon-main.cjs',
85
- type: 'addon',
86
- version: 2,
87
- };
88
-
89
- packageJson['exports'] = packages.addon.hasTypeScript
90
- ? {
91
- '.': './dist/index.js',
92
- './*': {
93
- types: './dist/*.d.ts',
94
- default: './dist/*.js',
95
- },
96
- './addon-main.js': './addon-main.cjs',
97
- }
98
- : {
99
- '.': './dist/index.js',
100
- './*': './dist/*.js',
101
- './addon-main.js': './addon-main.cjs',
102
- };
103
-
104
- packageJson['files'] = ['addon-main.cjs', 'dist'];
107
+ if (packages.addon.hasTypeScript) {
108
+ packageJson['exports'] = {
109
+ '.': './dist/index.js',
110
+ './*': {
111
+ /*
112
+ This object has an order dependency. The `default` key must appear last.
113
+ */
114
+ types: './dist/*.d.ts',
115
+ default: './dist/*.js',
116
+ },
117
+ './addon-main.js': './addon-main.cjs',
118
+ };
119
+ } else {
120
+ packageJson['exports'] = {
121
+ '.': './dist/index.js',
122
+ './*': './dist/*.js',
123
+ './addon-main.js': './addon-main.cjs',
124
+ };
125
+ }
126
+
127
+ if (hasPublicAssets) {
128
+ packageJson['files'] = ['addon-main.cjs', 'dist', 'public'];
129
+ } else {
130
+ packageJson['files'] = ['addon-main.cjs', 'dist'];
131
+ }
105
132
 
106
133
  if (packages.addon.hasTypeScript) {
107
134
  packageJson['typesVersions'] = {
@@ -126,7 +153,7 @@ function updateScripts(packageJson) {
126
153
  packageJson['scripts'] = convertToObject(scripts);
127
154
  }
128
155
 
129
- export function updateAddonPackageJson(options) {
156
+ export function updateAddonPackageJson(context, options) {
130
157
  const { locations, projectRoot } = options;
131
158
 
132
159
  const oldPath = join(projectRoot, locations.addon, 'package.json');
@@ -136,7 +163,7 @@ export function updateAddonPackageJson(options) {
136
163
  updateDependencies(packageJson, options);
137
164
  updateDevDependencies(packageJson, options);
138
165
  updateScripts(packageJson);
139
- updateOtherFields(packageJson, options);
166
+ updateOtherFields(packageJson, context, options);
140
167
 
141
168
  const newFile = JSON.stringify(packageJson, null, 2) + '\n';
142
169
 
@@ -10,22 +10,26 @@ function moveDependenciesToDevDependencies(packageJson, options) {
10
10
  const dependencies = convertToMap(packageJson['dependencies']);
11
11
  const devDependencies = convertToMap(packageJson['devDependencies']);
12
12
 
13
- const packagesToMove = packages.addon.hasTypeScript
14
- ? [
15
- 'ember-auto-import',
16
- 'ember-cli-babel',
17
- 'ember-cli-htmlbars',
18
- 'ember-cli-typescript',
19
- ]
20
- : ['ember-auto-import', 'ember-cli-babel', 'ember-cli-htmlbars'];
21
-
22
- packagesToMove.forEach((packageName) => {
23
- const version = decideVersion(packageName, options);
24
-
25
- devDependencies.set(packageName, version);
26
-
27
- dependencies.delete(packageName);
28
- });
13
+ const packagesToMove = new Set([
14
+ 'ember-auto-import',
15
+ 'ember-cli-babel',
16
+ 'ember-cli-htmlbars',
17
+ ]);
18
+
19
+ if (packages.addon.hasTypeScript) {
20
+ packagesToMove.add('ember-cli-typescript');
21
+ }
22
+
23
+ [...packagesToMove]
24
+ .filter((packageName) => dependencies.has(packageName))
25
+ .sort()
26
+ .forEach((packageName) => {
27
+ const version = decideVersion(packageName, options);
28
+
29
+ devDependencies.set(packageName, version);
30
+
31
+ dependencies.delete(packageName);
32
+ });
29
33
 
30
34
  packageJson['dependencies'] = convertToObject(dependencies);
31
35
  packageJson['devDependencies'] = convertToObject(devDependencies);
@@ -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/ember-addon');
11
+ }
12
+
13
+ export const blueprintRoot = getBlueprintRoot();
@@ -1,17 +1,17 @@
1
1
  const latestVersions = new Map([
2
- ['@babel/core', '7.20.12'],
2
+ ['@babel/core', '7.21.0'],
3
3
  ['@babel/plugin-proposal-class-properties', '7.18.6'],
4
- ['@babel/plugin-proposal-decorators', '7.20.13'],
5
- ['@babel/preset-typescript', '7.18.6'],
4
+ ['@babel/plugin-proposal-decorators', '7.21.0'],
5
+ ['@babel/preset-typescript', '7.21.0'],
6
6
  ['@embroider/addon-dev', '3.0.0'],
7
7
  ['@embroider/addon-shim', '1.8.4'],
8
8
  ['@rollup/plugin-babel', '6.0.3'],
9
9
  ['concurrently', '7.6.0'],
10
- ['ember-auto-import', '2.6.0'],
10
+ ['ember-auto-import', '2.6.1'],
11
11
  ['ember-cli-babel', '7.26.11'],
12
12
  ['ember-cli-htmlbars', '6.2.0'],
13
- ['prettier', '2.8.3'],
14
- ['rollup', '3.12.0'],
13
+ ['prettier', '2.8.4'],
14
+ ['rollup', '3.18.0'],
15
15
  ['rollup-plugin-copy', '3.4.0'],
16
16
  ['rollup-plugin-ts', '3.2.0'],
17
17
  ]);
@@ -1,2 +1,3 @@
1
+ export * from './blueprints/blueprint-root.js';
1
2
  export * from './blueprints/decide-version.js';
2
3
  export * from './blueprints/process-template.js';
@@ -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
+ }
@@ -1,5 +1,6 @@
1
1
  export * from './files/copy-files.js';
2
2
  export * from './files/create-files.js';
3
+ export * from './files/find-files.js';
3
4
  export * from './files/map-file-paths.js';
4
5
  export * from './files/move-files.js';
5
6
  export * from './files/remove-directory-if-empty.js';
@@ -1,89 +0,0 @@
1
- import { readFileSync, writeFileSync } from 'node:fs';
2
- import { dirname, join, relative } from 'node:path';
3
-
4
- import glob from 'glob';
5
-
6
- function normalizeRelativePath(relativePath) {
7
- if (!relativePath.startsWith('..')) {
8
- return `./${relativePath}`;
9
- }
10
-
11
- return relativePath;
12
- }
13
-
14
- function updateFile(oldFile, { filePath, projectName, projectRoot }) {
15
- const regex = new RegExp(`(?:'|")(${projectName}/(.*/)*(.*))(?:'|")`, 'g');
16
- const matchResults = [...oldFile.matchAll(regex)];
17
-
18
- let newFile = oldFile;
19
-
20
- matchResults.forEach((matchResult) => {
21
- // eslint-disable-next-line no-unused-vars
22
- const [_, oldPath, remainingDirectories, fileName] = matchResult;
23
-
24
- const from = dirname(filePath);
25
- const to = join(projectRoot, remainingDirectories);
26
-
27
- const relativePath = join(relative(from, to), fileName);
28
- const newPath = normalizeRelativePath(relativePath);
29
-
30
- newFile = newFile.replace(oldPath, newPath);
31
- });
32
-
33
- return newFile;
34
- }
35
-
36
- function useRelativePathInAddonFolder(options) {
37
- const { packages, projectRoot } = options;
38
-
39
- // File extensions had been specified, partly to encode assumptions
40
- // about Ember, and partly to avoid corrupting non-text files
41
- const filePaths = glob.sync('addon/**/*.{d.ts,js,ts}', {
42
- cwd: projectRoot,
43
- dot: true,
44
- nodir: true,
45
- });
46
-
47
- filePaths.forEach((filePath) => {
48
- const oldPath = join(projectRoot, filePath);
49
- const oldFile = readFileSync(oldPath, 'utf8');
50
-
51
- const newFile = updateFile(oldFile, {
52
- filePath,
53
- projectName: packages.addon.name,
54
- projectRoot: 'addon',
55
- });
56
-
57
- writeFileSync(oldPath, newFile, 'utf8');
58
- });
59
- }
60
-
61
- function useRelativePathInTestsDummyFolder(options) {
62
- const { projectRoot } = options;
63
-
64
- // File extensions had been specified, partly to encode assumptions
65
- // about Ember, and partly to avoid corrupting non-text files
66
- const filePaths = glob.sync('tests/dummy/**/*.{d.ts,js,ts}', {
67
- cwd: projectRoot,
68
- dot: true,
69
- nodir: true,
70
- });
71
-
72
- filePaths.forEach((filePath) => {
73
- const oldPath = join(projectRoot, filePath);
74
- const oldFile = readFileSync(oldPath, 'utf8');
75
-
76
- const newFile = updateFile(oldFile, {
77
- filePath,
78
- projectName: 'dummy',
79
- projectRoot: 'tests/dummy/app',
80
- });
81
-
82
- writeFileSync(oldPath, newFile, 'utf8');
83
- });
84
- }
85
-
86
- export function useRelativePaths(options) {
87
- useRelativePathInAddonFolder(options);
88
- useRelativePathInTestsDummyFolder(options);
89
- }