ember.nvp 1.14.0 → 1.16.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.
- package/.release-plan.json +37 -5
- package/CHANGELOG.md +31 -0
- package/README.md +28 -0
- package/package.json +2 -1
- package/packages/rolldown/package.json +2 -2
- package/packages/rolldown/src/transform.test.ts +3 -3
- package/packages/vite/package.json +4 -4
- package/packages/vite/src/ember.test.ts +38 -0
- package/packages/vite/src/ember.ts +38 -5
- package/src/bases/minimal-app/files/package.json +2 -2
- package/src/bases/minimal-extension/files/package.json +2 -2
- package/src/cli/generator.js +10 -0
- package/src/cli/index.js +19 -2
- package/src/cli/questions/layers.js +3 -2
- package/src/cli/questions/migration.js +69 -0
- package/src/index.js +1 -0
- package/src/layers/qunit/index.js +1 -1
- package/src/migration-from/addons.js +154 -0
- package/src/migration-from/app.js +1117 -0
- package/src/migration-from/at-ember/addon-blueprint/index.js +515 -0
- package/src/migration-from/at-ember/addon-blueprint/rollup.js +188 -0
- package/src/migration-from/at-ember/app-blueprint/index.js +60 -0
- package/src/migration-from/at-ember-tooling/classic-build-addon-blueprint/index.js +601 -0
- package/src/migration-from/at-ember-tooling/classic-build-app-blueprint/index.js +118 -0
- package/src/migration-from/babel.js +207 -0
- package/src/migration-from/ember-cli-build.js +238 -0
- package/src/migration-from/files.js +120 -0
- package/src/migration-from/findings.js +69 -0
- package/src/migration-from/index.js +81 -0
- package/src/migration-from/javascript.js +217 -0
- package/src/migration-from/layers.js +170 -0
- package/src/migration-from/library.js +311 -0
- package/src/utils/types.ts +69 -0
- package/test/ember.nvp/migration-from-fixtures.ts +506 -0
- package/test/ember.nvp/migration-from.test.ts +475 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { existsSync, globSync } from "node:fs";
|
|
2
|
+
import { join, sep } from "node:path";
|
|
3
|
+
import { readJSON } from "#utils/fs.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {object} Dependency
|
|
7
|
+
* @property {string} name
|
|
8
|
+
* @property {Record<string, any>} manifest
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Packages with the shape of a v1 addon that work without ember-cli
|
|
13
|
+
*/
|
|
14
|
+
const WORKS_WITHOUT_EMBER_CLI = new Set(["@embroider/macros"]);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ember-cli runs v1 addons as part of its build.
|
|
18
|
+
* ember.nvp builds without ember-cli, so a v1 addon never loads.
|
|
19
|
+
*
|
|
20
|
+
* @param {Record<string, any>} manifest
|
|
21
|
+
*/
|
|
22
|
+
export function isV1Addon(manifest) {
|
|
23
|
+
return (
|
|
24
|
+
Boolean(manifest.keywords?.includes("ember-addon")) &&
|
|
25
|
+
manifest["ember-addon"]?.version !== 2 &&
|
|
26
|
+
!WORKS_WITHOUT_EMBER_CLI.has(manifest.name)
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The manifests of the dependencies that are installed in the project.
|
|
32
|
+
*
|
|
33
|
+
* A migration decides from the project's own files.
|
|
34
|
+
* An install is extra: when there is one, it tells which dependencies are v1 addons,
|
|
35
|
+
* and which modules the addons add to an app.
|
|
36
|
+
*
|
|
37
|
+
* Only the top level of node_modules is read.
|
|
38
|
+
* Every package manager puts a project's direct dependencies there.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} directory the project
|
|
41
|
+
* @param {Record<string, string>} dependencies the dependencies to look for, by name
|
|
42
|
+
* @returns {Dependency[]} empty when the project has no node_modules
|
|
43
|
+
*/
|
|
44
|
+
export function installedDependencies(directory, dependencies) {
|
|
45
|
+
let modules = join(directory, "node_modules");
|
|
46
|
+
|
|
47
|
+
if (!existsSync(modules)) return [];
|
|
48
|
+
|
|
49
|
+
/** @type {Dependency[]} */
|
|
50
|
+
let found = [];
|
|
51
|
+
|
|
52
|
+
for (let folder of globSync(["*", "@*/*"], { cwd: modules })) {
|
|
53
|
+
let name = folder.split(sep).join("/");
|
|
54
|
+
|
|
55
|
+
if (!(name in dependencies)) continue;
|
|
56
|
+
|
|
57
|
+
let manifest = readJSON(join(modules, folder, "package.json"));
|
|
58
|
+
|
|
59
|
+
if (manifest) found.push({ name, manifest });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return found.sort((a, b) => a.name.localeCompare(b.name));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @param {Dependency[]} dependencies
|
|
67
|
+
* @returns {string[]} such as `ember-power-select@6.0.1`
|
|
68
|
+
*/
|
|
69
|
+
export function v1AddonsIn(dependencies) {
|
|
70
|
+
/** @type {string[]} */
|
|
71
|
+
let v1 = [];
|
|
72
|
+
|
|
73
|
+
for (let { name, manifest } of dependencies) {
|
|
74
|
+
if (isV1Addon(manifest)) v1.push(`${name}@${manifest.version}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return v1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @typedef {object} AppModule
|
|
82
|
+
* @property {string} addon the package that provides it
|
|
83
|
+
* @property {string} path such as `services/session`
|
|
84
|
+
* @property {string | undefined} specifier the module to import it from
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Modules that v2 addons merge into an app through `ember-addon.app-js`.
|
|
89
|
+
*
|
|
90
|
+
* `@embroider/compat` merges them.
|
|
91
|
+
* An ember.nvp app does not, so the app must register the ones it looks up by name.
|
|
92
|
+
*
|
|
93
|
+
* @param {Dependency[]} dependencies
|
|
94
|
+
* @returns {AppModule[]}
|
|
95
|
+
*/
|
|
96
|
+
export function appModulesIn(dependencies) {
|
|
97
|
+
/** @type {AppModule[]} */
|
|
98
|
+
let modules = [];
|
|
99
|
+
|
|
100
|
+
for (let { name, manifest } of dependencies) {
|
|
101
|
+
let appJs = manifest["ember-addon"]?.["app-js"] ?? {};
|
|
102
|
+
|
|
103
|
+
for (let [appPath, file] of Object.entries(appJs)) {
|
|
104
|
+
modules.push({
|
|
105
|
+
addon: name,
|
|
106
|
+
path: appPath.replace(/^\.\//, "").replace(/\.\w+$/, ""),
|
|
107
|
+
specifier: exportedAs(name, manifest, String(file)),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return modules;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The specifier that reaches `target` through the package's `exports`.
|
|
117
|
+
*
|
|
118
|
+
* exports: { "./*": "./dist/*.js" }, target: ./dist/_app_/services/x.js
|
|
119
|
+
* → pkg/_app_/services/x
|
|
120
|
+
*
|
|
121
|
+
* @param {string} name
|
|
122
|
+
* @param {Record<string, any>} manifest
|
|
123
|
+
* @param {string} target a file in the package, such as `./dist/_app_/services/x.js`
|
|
124
|
+
* @returns {string | undefined}
|
|
125
|
+
*/
|
|
126
|
+
function exportedAs(name, manifest, target) {
|
|
127
|
+
let exports = manifest.exports;
|
|
128
|
+
|
|
129
|
+
if (!exports) return `${name}/${target.replace(/^\.\//, "")}`;
|
|
130
|
+
if (typeof exports !== "object") return;
|
|
131
|
+
|
|
132
|
+
for (let [key, value] of Object.entries(exports)) {
|
|
133
|
+
let path = typeof value === "string" ? value : (value?.import ?? value?.default);
|
|
134
|
+
|
|
135
|
+
if (typeof path !== "string" || typeof key !== "string") continue;
|
|
136
|
+
|
|
137
|
+
if (!path.includes("*")) {
|
|
138
|
+
if (path === target) return `${name}/${key.replace(/^\.\//, "")}`;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let [before = "", after = ""] = path.split("*");
|
|
143
|
+
|
|
144
|
+
if (
|
|
145
|
+
target.startsWith(before) &&
|
|
146
|
+
target.endsWith(after) &&
|
|
147
|
+
target.length >= before.length + after.length
|
|
148
|
+
) {
|
|
149
|
+
let matched = target.slice(before.length, target.length - after.length);
|
|
150
|
+
|
|
151
|
+
return `${name}/${key.replace(/^\.\//, "").replace("*", matched)}`;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|