ember.nvp 1.3.0 → 1.5.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 +8 -14
- package/CHANGELOG.md +57 -0
- package/package.json +1 -1
- package/packages/rolldown/README.md +62 -3
- package/packages/rolldown/index.ts +2 -3
- package/packages/rolldown/package.json +12 -5
- package/packages/rolldown/src/app-reexports.ts +2 -2
- package/packages/rolldown/src/babel.test.ts +125 -2
- package/packages/rolldown/src/babel.ts +52 -7
- package/packages/rolldown/src/isolated-declarations.ts +28 -3
- package/packages/rolldown/src/plugin-like.ts +23 -0
- package/packages/rolldown/src/published-types.test.ts +102 -0
- package/packages/rolldown/src/transform.test.ts +50 -2
- package/packages/rolldown/src/transform.ts +8 -1
- package/packages/rolldown/tsdown.config.ts +11 -0
- package/src/bases/minimal-app/app.test.ts +102 -1
- package/src/bases/minimal-app/files/app/app.ts +1 -1
- package/src/bases/minimal-app/files/babel.config.js +17 -1
- package/src/bases/minimal-app/files/package.json +2 -2
- package/src/bases/minimal-extension/files/app/app.ts +1 -1
- package/src/bases/minimal-extension/files/babel.config.js +17 -1
- package/src/bases/minimal-extension/files/package.json +2 -2
- package/src/bases/minimal-library/files/package.json +1 -1
- package/src/layers/qunit/index.js +0 -1
- package/src/layers/qunit/library-files/tests/test-helper.ts +1 -1
- package/src/layers/readme/index.js +16 -16
- package/src/utils/babel.js +20 -2
- package/test/ember.nvp/inspector-support.test.ts +13 -13
- package/test/ember.nvp/layer-inspector-support.test.ts +1 -1
- package/test/ember.nvp/layer-readme.test.ts +16 -16
- package/test/ember.nvp/layer-vitest.test.ts +1 -1
- package/test/ember.nvp/publish-configs.test.ts +352 -0
- package/packages/rolldown/rolldown.config.js +0 -23
- package/packages/rolldown/src/isolated-declarations.test.ts +0 -122
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import { readdir, readFile, rm, stat } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { beforeAll, describe, expect, it } from "vitest";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* This package's own published shape: consumers write their build config in
|
|
9
|
+
* TypeScript, so `import { ember } from "@nullvoxpopuli/ember-rolldown"` has to
|
|
10
|
+
* carry types. Without them it is an implicit `any` (TS7016), and a config file
|
|
11
|
+
* silently stops being type-checked.
|
|
12
|
+
*/
|
|
13
|
+
const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
14
|
+
|
|
15
|
+
interface Manifest {
|
|
16
|
+
dependencies: Record<string, string>;
|
|
17
|
+
peerDependencies: Record<string, string>;
|
|
18
|
+
publishConfig: { exports: Record<string, Record<string, string>> };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function readManifest(): Promise<Manifest> {
|
|
22
|
+
return JSON.parse(await readFile(path.join(packageDir, "package.json"), "utf8")) as Manifest;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function exists(relative: string) {
|
|
26
|
+
return Boolean(await stat(path.join(packageDir, relative)).catch(() => null));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function declarations() {
|
|
30
|
+
const files = (await readdir(path.join(packageDir, "dist"))).filter((file) =>
|
|
31
|
+
file.endsWith(".d.ts"),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return Object.fromEntries(
|
|
35
|
+
await Promise.all(
|
|
36
|
+
files.map(
|
|
37
|
+
async (file) =>
|
|
38
|
+
[file, await readFile(path.join(packageDir, "dist", file), "utf8")] as const,
|
|
39
|
+
),
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe("published types", () => {
|
|
45
|
+
beforeAll(async () => {
|
|
46
|
+
// `clean` is on, but don't let these assertions depend on that: stale
|
|
47
|
+
// artifacts from an earlier build satisfy every one of them on their own
|
|
48
|
+
await rm(path.join(packageDir, "dist"), { recursive: true, force: true });
|
|
49
|
+
await execa("pnpm", ["build"], { cwd: packageDir });
|
|
50
|
+
}, 120_000);
|
|
51
|
+
|
|
52
|
+
it("every publishConfig export declares types, and they exist", async () => {
|
|
53
|
+
const manifest = await readManifest();
|
|
54
|
+
const entries = Object.entries(manifest.publishConfig.exports);
|
|
55
|
+
|
|
56
|
+
expect(entries.length).toBeGreaterThan(0);
|
|
57
|
+
|
|
58
|
+
for (const [subpath, conditions] of entries) {
|
|
59
|
+
expect(conditions, `${subpath} declares types`).toHaveProperty("types");
|
|
60
|
+
expect(await exists(conditions["types"]!), `${subpath} -> ${conditions["types"]}`).toBe(true);
|
|
61
|
+
expect(await exists(conditions["default"]!), `${subpath} -> ${conditions["default"]}`).toBe(
|
|
62
|
+
true,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A declaration may only reach for packages a consumer is guaranteed to have.
|
|
69
|
+
* Reference a devDependency and there are two ways to lose, both quiet:
|
|
70
|
+
* the specifier survives and consumers can't resolve it (`skipLibCheck` hides
|
|
71
|
+
* that, degrading the type to an error type), or the declaration bundler
|
|
72
|
+
* inlines the whole type surface — a ~200kB copy of rolldown's types, in the
|
|
73
|
+
* case that prompted this test, nominally distinct from the consumer's own.
|
|
74
|
+
*
|
|
75
|
+
* `ember()` returns plugins, so `RolldownPluginLike` exists to keep rolldown
|
|
76
|
+
* on the devDependency side of that line.
|
|
77
|
+
*/
|
|
78
|
+
it("declarations only reference packages consumers have", async () => {
|
|
79
|
+
const manifest = await readManifest();
|
|
80
|
+
const available = new Set([
|
|
81
|
+
...Object.keys(manifest.dependencies),
|
|
82
|
+
...Object.keys(manifest.peerDependencies),
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
for (const [file, contents] of Object.entries(await declarations())) {
|
|
86
|
+
const specifiers = [...contents.matchAll(/^import .* from "([^"]+)";$/gm)]
|
|
87
|
+
.map(([, specifier]) => specifier!)
|
|
88
|
+
.filter((specifier) => !specifier.startsWith("."));
|
|
89
|
+
|
|
90
|
+
for (const specifier of specifiers) {
|
|
91
|
+
const owner = specifier.startsWith("@")
|
|
92
|
+
? specifier.split("/").slice(0, 2).join("/")
|
|
93
|
+
: specifier.split("/")[0]!;
|
|
94
|
+
|
|
95
|
+
expect(available, `${file} imports ${specifier}`).toContain(owner);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// an inlined copy of a bundler's types, rather than an import of them
|
|
99
|
+
expect(contents, `${file} inlines rolldown's types`).not.toMatch(/interface PluginContext/);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
@@ -2,6 +2,7 @@ import { mkdtemp, mkdir, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { rolldown } from "rolldown";
|
|
5
|
+
import type { Plugin } from "rolldown";
|
|
5
6
|
import { describe, expect, it } from "vitest";
|
|
6
7
|
|
|
7
8
|
import { emberTransform } from "./transform.ts";
|
|
@@ -15,7 +16,10 @@ import { emberTransform } from "./transform.ts";
|
|
|
15
16
|
*/
|
|
16
17
|
async function bundle(
|
|
17
18
|
files: Record<string, string>,
|
|
18
|
-
{
|
|
19
|
+
{
|
|
20
|
+
input = ["index.ts"],
|
|
21
|
+
plugins = () => [],
|
|
22
|
+
}: { input?: string[]; plugins?: (dir: string) => Plugin[] } = {},
|
|
19
23
|
): Promise<string> {
|
|
20
24
|
const dir = await mkdtemp(path.join(tmpdir(), "ember-rolldown-build-"));
|
|
21
25
|
|
|
@@ -29,7 +33,7 @@ async function bundle(
|
|
|
29
33
|
|
|
30
34
|
const build = await rolldown({
|
|
31
35
|
input: input.map((relative) => path.join(dir, relative)),
|
|
32
|
-
plugins: [emberTransform()],
|
|
36
|
+
plugins: [emberTransform(), ...plugins(dir)],
|
|
33
37
|
external: (id) => !isLocal(id),
|
|
34
38
|
onwarn() {},
|
|
35
39
|
});
|
|
@@ -174,6 +178,50 @@ describe("emberTransform (full plugin via rolldown)", () => {
|
|
|
174
178
|
`);
|
|
175
179
|
});
|
|
176
180
|
|
|
181
|
+
it("resolves an absolute .gts specifier imported from a plugin's virtual module", async () => {
|
|
182
|
+
/**
|
|
183
|
+
* The shape a code-generating plugin emits: a virtual module (id prefixed
|
|
184
|
+
* with `\0`, so it exists nowhere on disk) whose generated source imports
|
|
185
|
+
* real files by absolute path, because it has no directory to be relative
|
|
186
|
+
* to. `path.dirname` of such an id is `"\0."`, so the specifier must not be
|
|
187
|
+
* resolved against the importer's directory.
|
|
188
|
+
*/
|
|
189
|
+
const registry = (dir: string): Plugin[] => {
|
|
190
|
+
const source = "./registry?virtual=views";
|
|
191
|
+
const virtualId = `\0${source}`;
|
|
192
|
+
|
|
193
|
+
return [
|
|
194
|
+
{
|
|
195
|
+
name: "test:virtual-registry",
|
|
196
|
+
resolveId(id) {
|
|
197
|
+
return id === source ? virtualId : null;
|
|
198
|
+
},
|
|
199
|
+
load(id) {
|
|
200
|
+
if (id !== virtualId) return null;
|
|
201
|
+
|
|
202
|
+
return [
|
|
203
|
+
`import example from '${path.join(dir, "components/view/example.gts")}';`,
|
|
204
|
+
`export const views = { example };`,
|
|
205
|
+
].join("\n");
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
];
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const code = await bundle(
|
|
212
|
+
{
|
|
213
|
+
"index.ts": `export { views } from './registry?virtual=views';`,
|
|
214
|
+
"components/view/example.gts": `<template>example</template>`,
|
|
215
|
+
},
|
|
216
|
+
{ plugins: registry },
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// The absolutely-specified .gts got compiled and bundled in.
|
|
220
|
+
expect(code).not.toContain("<template>");
|
|
221
|
+
expect(code).toContain("template(");
|
|
222
|
+
expect(code).toContain("example");
|
|
223
|
+
});
|
|
224
|
+
|
|
177
225
|
it("compiles a .gts module used directly as an entry (no importer)", async () => {
|
|
178
226
|
const code = await bundle(
|
|
179
227
|
{
|
|
@@ -93,7 +93,14 @@ export function emberTransform(): Plugin {
|
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
// An absolute specifier already names the file, so it needs no
|
|
97
|
+
// importer-relative resolution — and joining it onto the importer's
|
|
98
|
+
// directory would corrupt it. That is not hypothetical: a plugin's
|
|
99
|
+
// virtual module (id prefixed with `\0`) can generate imports of
|
|
100
|
+
// on-disk files by absolute path, and `path.dirname("\0./registry")`
|
|
101
|
+
// is `"\0."`, so joining yields `"\0./Users/.../thing.gts"` — a path
|
|
102
|
+
// no `existsSync`/`readFile` can accept (it has a null byte in it).
|
|
103
|
+
const fileName = path.isAbsolute(id) ? id : path.join(path.dirname(importer), id);
|
|
97
104
|
|
|
98
105
|
if (id.endsWith(".gts")) {
|
|
99
106
|
return {
|
|
@@ -3,8 +3,9 @@ import { generate, build, reapply } from "#test-helpers";
|
|
|
3
3
|
import { packageJson } from "ember-apply";
|
|
4
4
|
|
|
5
5
|
import type { Project } from "ember.nvp";
|
|
6
|
-
import { rm } from "node:fs/promises";
|
|
6
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
7
7
|
import { globSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
8
9
|
|
|
9
10
|
const expect = hardExpect.soft;
|
|
10
11
|
|
|
@@ -100,6 +101,106 @@ describe("typescript", () => {
|
|
|
100
101
|
});
|
|
101
102
|
});
|
|
102
103
|
|
|
104
|
+
const DEBUG_MARKERS = {
|
|
105
|
+
assert: "__debug_fixture_assert__",
|
|
106
|
+
deprecate: "__debug_fixture_deprecate__",
|
|
107
|
+
warn: "__debug_fixture_warn__",
|
|
108
|
+
isDevelopingApp: "__debug_fixture_is_developing_app__",
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Lives in app/services/ so that app.ts's eager
|
|
113
|
+
* `import.meta.glob("./services/**\/*")` pulls it into the build
|
|
114
|
+
* without needing to modify any generated files.
|
|
115
|
+
*/
|
|
116
|
+
const debugFixture = `
|
|
117
|
+
import { assert, deprecate, warn } from "@ember/debug";
|
|
118
|
+
import { isDevelopingApp, macroCondition } from "@embroider/macros";
|
|
119
|
+
|
|
120
|
+
assert("${DEBUG_MARKERS.assert}", true);
|
|
121
|
+
|
|
122
|
+
deprecate("${DEBUG_MARKERS.deprecate}", true, {
|
|
123
|
+
id: "debug-fixture",
|
|
124
|
+
until: "999.0.0",
|
|
125
|
+
for: "debug-fixture",
|
|
126
|
+
since: { available: "0.0.0", enabled: "0.0.0" },
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
warn("${DEBUG_MARKERS.warn}", true, { id: "debug-fixture" });
|
|
130
|
+
|
|
131
|
+
if (macroCondition(isDevelopingApp())) {
|
|
132
|
+
console.log("${DEBUG_MARKERS.isDevelopingApp}");
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Only .js files -- the sourcemaps (.map) contain the original
|
|
138
|
+
* source (with markers) even in production builds.
|
|
139
|
+
*/
|
|
140
|
+
async function builtJavaScript(project: Project): Promise<string> {
|
|
141
|
+
let files = globSync("dist/**/*.js", { cwd: project.directory });
|
|
142
|
+
|
|
143
|
+
hardExpect(files.length, "build produced JS files").toBeGreaterThan(0);
|
|
144
|
+
|
|
145
|
+
let contents = await Promise.all(
|
|
146
|
+
files.map((file) => readFile(join(project.directory, file), "utf-8")),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
return contents.join("\n");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
describe("debug macros", () => {
|
|
153
|
+
let project: Project;
|
|
154
|
+
|
|
155
|
+
beforeAll(async () => {
|
|
156
|
+
project = await generate({
|
|
157
|
+
type: "app",
|
|
158
|
+
layers: ["typescript"],
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await mkdir(join(project.directory, "app/services"), { recursive: true });
|
|
162
|
+
await writeFile(join(project.directory, "app/services/debug-fixture.ts"), debugFixture);
|
|
163
|
+
|
|
164
|
+
let { exitCode } = await project.install();
|
|
165
|
+
|
|
166
|
+
hardExpect(exitCode, "Install succeeds").toBe(0);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
afterAll(async () => {
|
|
170
|
+
await rm(project.directory, { recursive: true, force: true });
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("has the debug-macros babel plugin", async () => {
|
|
174
|
+
let content = await project.read("babel.config.js");
|
|
175
|
+
|
|
176
|
+
expect(content).toContain("babel-plugin-debug-macros");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("development build keeps debug code", async () => {
|
|
180
|
+
let { exitCode } = await build(project);
|
|
181
|
+
|
|
182
|
+
hardExpect(exitCode).toBe(0);
|
|
183
|
+
|
|
184
|
+
let output = await builtJavaScript(project);
|
|
185
|
+
|
|
186
|
+
for (let [name, marker] of Object.entries(DEBUG_MARKERS)) {
|
|
187
|
+
expect(output, `development build contains ${name}`).toContain(marker);
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("production build strips assert(), deprecate(), warn(), and if (macroCondition(isDevelopingApp()))", async () => {
|
|
192
|
+
let { exitCode } = await build(project, "production");
|
|
193
|
+
|
|
194
|
+
hardExpect(exitCode).toBe(0);
|
|
195
|
+
|
|
196
|
+
let output = await builtJavaScript(project);
|
|
197
|
+
|
|
198
|
+
for (let [name, marker] of Object.entries(DEBUG_MARKERS)) {
|
|
199
|
+
expect(output, `production build strips ${name}`).not.toContain(marker);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
103
204
|
describe("javascript", () => {
|
|
104
205
|
let project: Project;
|
|
105
206
|
beforeAll(async () => {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - https://ember-primitives.pages.dev/6-utils/createService.md
|
|
11
11
|
* - https://ember-primitives.pages.dev/6-utils/createAsyncService.md
|
|
12
12
|
*/
|
|
13
|
-
import Application from "ember
|
|
13
|
+
import Application from "@ember/application";
|
|
14
14
|
|
|
15
15
|
export default class App extends Application {
|
|
16
16
|
modules = {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { buildMacros } from "@embroider/macros/babel";
|
|
2
2
|
|
|
3
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
4
|
+
|
|
3
5
|
const macros = buildMacros({
|
|
4
6
|
configure(config) {
|
|
5
7
|
if (process.env.EMBER_ENV === "test") {
|
|
@@ -40,8 +42,22 @@ export default {
|
|
|
40
42
|
regenerator: false,
|
|
41
43
|
},
|
|
42
44
|
],
|
|
45
|
+
isProduction && [
|
|
46
|
+
"babel-plugin-debug-macros",
|
|
47
|
+
{
|
|
48
|
+
debugTools: {
|
|
49
|
+
isDebug: false,
|
|
50
|
+
source: "@ember/debug",
|
|
51
|
+
assertPredicateIndex: 1,
|
|
52
|
+
},
|
|
53
|
+
externalizeHelpers: {
|
|
54
|
+
module: "@ember/debug",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
"@ember/debug stripping",
|
|
58
|
+
],
|
|
43
59
|
...macros.babelMacros,
|
|
44
|
-
],
|
|
60
|
+
].filter(Boolean),
|
|
45
61
|
|
|
46
62
|
generatorOpts: {
|
|
47
63
|
compact: false,
|
|
@@ -29,8 +29,7 @@
|
|
|
29
29
|
"@embroider/router": "^3.0.6",
|
|
30
30
|
"@glimmer/component": "^2.1.1",
|
|
31
31
|
"decorator-transforms": "^2.3.2",
|
|
32
|
-
"ember-source": "~7.
|
|
33
|
-
"ember-strict-application-resolver": "^0.1.0"
|
|
32
|
+
"ember-source": "~7.2.0"
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
35
|
"@babel/core": "^7.29.7",
|
|
@@ -44,6 +43,7 @@
|
|
|
44
43
|
"@glint/tsserver-plugin": "^2.5.5",
|
|
45
44
|
"@nullvoxpopuli/ember-vite": "workspace:*",
|
|
46
45
|
"@rollup/plugin-babel": "^7.1.0",
|
|
46
|
+
"babel-plugin-debug-macros": "^2.0.0",
|
|
47
47
|
"babel-plugin-ember-template-compilation": "^4.0.0",
|
|
48
48
|
"typescript": "^6.0.3",
|
|
49
49
|
"vite": "^8.0.14"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - https://ember-primitives.pages.dev/6-utils/createService.md
|
|
11
11
|
* - https://ember-primitives.pages.dev/6-utils/createAsyncService.md
|
|
12
12
|
*/
|
|
13
|
-
import Application from "ember
|
|
13
|
+
import Application from "@ember/application";
|
|
14
14
|
|
|
15
15
|
export default class App extends Application {
|
|
16
16
|
modules = {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { buildMacros } from "@embroider/macros/babel";
|
|
2
2
|
|
|
3
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
4
|
+
|
|
3
5
|
const macros = buildMacros({
|
|
4
6
|
configure(config) {
|
|
5
7
|
if (process.env.EMBER_ENV === "test") {
|
|
@@ -40,8 +42,22 @@ export default {
|
|
|
40
42
|
regenerator: false,
|
|
41
43
|
},
|
|
42
44
|
],
|
|
45
|
+
isProduction && [
|
|
46
|
+
"babel-plugin-debug-macros",
|
|
47
|
+
{
|
|
48
|
+
debugTools: {
|
|
49
|
+
isDebug: false,
|
|
50
|
+
source: "@ember/debug",
|
|
51
|
+
assertPredicateIndex: 1,
|
|
52
|
+
},
|
|
53
|
+
externalizeHelpers: {
|
|
54
|
+
module: "@ember/debug",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
"@ember/debug stripping",
|
|
58
|
+
],
|
|
43
59
|
...macros.babelMacros,
|
|
44
|
-
],
|
|
60
|
+
].filter(Boolean),
|
|
45
61
|
|
|
46
62
|
generatorOpts: {
|
|
47
63
|
compact: false,
|
|
@@ -30,8 +30,7 @@
|
|
|
30
30
|
"@embroider/router": "^3.0.6",
|
|
31
31
|
"@glimmer/component": "^2.1.1",
|
|
32
32
|
"decorator-transforms": "^2.3.2",
|
|
33
|
-
"ember-source": "~7.
|
|
34
|
-
"ember-strict-application-resolver": "^0.1.0"
|
|
33
|
+
"ember-source": "~7.2.0"
|
|
35
34
|
},
|
|
36
35
|
"devDependencies": {
|
|
37
36
|
"@babel/core": "^7.29.7",
|
|
@@ -45,6 +44,7 @@
|
|
|
45
44
|
"@glint/tsserver-plugin": "^2.5.5",
|
|
46
45
|
"@nullvoxpopuli/ember-vite": "workspace:*",
|
|
47
46
|
"@rollup/plugin-babel": "^7.1.0",
|
|
47
|
+
"babel-plugin-debug-macros": "^2.0.0",
|
|
48
48
|
"babel-plugin-ember-template-compilation": "^4.0.0",
|
|
49
49
|
"typescript": "^6.0.3",
|
|
50
50
|
"vite": "^8.0.14"
|
|
@@ -28,7 +28,6 @@ const libraryDeps = {
|
|
|
28
28
|
"@embroider/macros": "^1.20.3",
|
|
29
29
|
"@nullvoxpopuli/ember-vite": "workspace:*",
|
|
30
30
|
"babel-plugin-ember-template-compilation": "^4.0.0",
|
|
31
|
-
"ember-strict-application-resolver": "^0.1.0",
|
|
32
31
|
vite: "^8.0.14",
|
|
33
32
|
};
|
|
34
33
|
const libraryTsDeps = {
|
|
@@ -4,7 +4,7 @@ import * as QUnit from "qunit";
|
|
|
4
4
|
import { setup } from "qunit-dom";
|
|
5
5
|
import { setupEmberOnerrorValidation, start as qunitStart } from "ember-qunit";
|
|
6
6
|
import { setTesting } from "@embroider/macros";
|
|
7
|
-
import EmberApp from "ember
|
|
7
|
+
import EmberApp from "@ember/application";
|
|
8
8
|
|
|
9
9
|
class Router extends EmberRouter {
|
|
10
10
|
location = "none";
|
|
@@ -21,23 +21,23 @@ An Ember application created with \`ember.nvp\`.
|
|
|
21
21
|
|
|
22
22
|
### Installation
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
\`\`\`sh
|
|
25
25
|
${project.packageManager} install
|
|
26
|
-
|
|
26
|
+
\`\`\`
|
|
27
27
|
|
|
28
28
|
### Development
|
|
29
29
|
|
|
30
30
|
To start the local development server:
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
\`\`\`sh
|
|
33
33
|
${project.runPrefix} dev
|
|
34
|
-
|
|
34
|
+
\`\`\`
|
|
35
35
|
|
|
36
36
|
or
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
\`\`\`sh
|
|
39
39
|
${project.runPrefix} start
|
|
40
|
-
|
|
40
|
+
\`\`\`
|
|
41
41
|
${layerDocsMarkdown}`;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -61,29 +61,29 @@ A browser extension using Ember created with \`ember.nvp\`.
|
|
|
61
61
|
|
|
62
62
|
To start development:
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
\`\`\`sh
|
|
65
65
|
${project.runPrefix} dev
|
|
66
|
-
|
|
66
|
+
\`\`\`
|
|
67
67
|
|
|
68
68
|
or
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
\`\`\`sh
|
|
71
71
|
${project.runPrefix} start
|
|
72
|
-
|
|
72
|
+
\`\`\`
|
|
73
73
|
|
|
74
74
|
### Building
|
|
75
75
|
|
|
76
76
|
To build the library:
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
\`\`\`sh
|
|
79
79
|
${project.runPrefix} build
|
|
80
|
-
|
|
80
|
+
\`\`\`
|
|
81
81
|
|
|
82
82
|
or
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
\`\`\`sh
|
|
85
85
|
${project.runPrefix} build:watch
|
|
86
|
-
|
|
86
|
+
\`\`\`
|
|
87
87
|
${layerDocsMarkdown}`;
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -107,9 +107,9 @@ An Ember library/addon created with \`ember.nvp\`.
|
|
|
107
107
|
|
|
108
108
|
To build the library:
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
\`\`\`sh
|
|
111
111
|
${project.runPrefix} build
|
|
112
|
-
|
|
112
|
+
\`\`\`
|
|
113
113
|
${layerDocsMarkdown}`;
|
|
114
114
|
}
|
|
115
115
|
|
package/src/utils/babel.js
CHANGED
|
@@ -65,15 +65,33 @@ export async function prependPlugin(project, plugin, configPath = "babel.config.
|
|
|
65
65
|
root
|
|
66
66
|
.find(j.Property, {
|
|
67
67
|
key: { name: "plugins" },
|
|
68
|
-
value: { type: "ArrayExpression" },
|
|
69
68
|
})
|
|
70
69
|
.forEach(
|
|
71
70
|
/**
|
|
72
71
|
* @param {any} path
|
|
73
72
|
*/
|
|
74
73
|
(path) => {
|
|
75
|
-
path.node.value
|
|
74
|
+
let array = pluginsArrayOf(path.node.value);
|
|
75
|
+
|
|
76
|
+
array?.elements.unshift(plugin);
|
|
76
77
|
},
|
|
77
78
|
);
|
|
78
79
|
});
|
|
79
80
|
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The plugins value may be the array itself, or the array with
|
|
84
|
+
* methods chained off of it: `[ ... ].filter(Boolean)`
|
|
85
|
+
*
|
|
86
|
+
* @param {any} node
|
|
87
|
+
* @returns {any | undefined} the underlying ArrayExpression
|
|
88
|
+
*/
|
|
89
|
+
function pluginsArrayOf(node) {
|
|
90
|
+
if (node.type === "ArrayExpression") return node;
|
|
91
|
+
|
|
92
|
+
if (node.type === "CallExpression" && node.callee.type === "MemberExpression") {
|
|
93
|
+
return pluginsArrayOf(node.callee.object);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|