ember.nvp 0.6.0 → 1.0.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 (85) hide show
  1. package/.github/workflows/ci.yml +17 -2
  2. package/.release-plan.json +29 -5
  3. package/CHANGELOG.md +73 -0
  4. package/package.json +3 -2
  5. package/packages/build-tooling-utils/README.md +37 -0
  6. package/packages/build-tooling-utils/index.ts +2 -0
  7. package/packages/build-tooling-utils/package.json +42 -0
  8. package/packages/build-tooling-utils/rolldown.config.js +18 -0
  9. package/packages/build-tooling-utils/src/extensions.ts +18 -0
  10. package/packages/build-tooling-utils/src/maybe-babel.ts +146 -0
  11. package/packages/rolldown/README.md +120 -0
  12. package/packages/rolldown/index.ts +60 -0
  13. package/packages/rolldown/package.json +59 -0
  14. package/packages/rolldown/rolldown.config.js +21 -0
  15. package/packages/rolldown/src/babel.ts +136 -0
  16. package/packages/rolldown/src/config.ts +50 -0
  17. package/packages/rolldown/src/externals.ts +83 -0
  18. package/packages/rolldown/src/isolated-declarations.ts +65 -0
  19. package/packages/rolldown/src/transform.ts +162 -0
  20. package/packages/vite/README.md +7 -21
  21. package/packages/vite/index.ts +1 -1
  22. package/packages/vite/package.json +4 -6
  23. package/packages/vite/src/ember.ts +129 -15
  24. package/packages/vite/src/test-html.ts +86 -0
  25. package/src/bases/minimal-app/files/app/router.ts +1 -0
  26. package/src/bases/minimal-app/files/tsconfig.json +1 -0
  27. package/src/bases/minimal-app/index.js +2 -2
  28. package/src/bases/minimal-library/files/README.md +41 -0
  29. package/src/bases/minimal-library/files/package.json +49 -0
  30. package/src/bases/minimal-library/files/tsconfig.json +10 -0
  31. package/src/bases/minimal-library/files/tsdown.config.js +7 -0
  32. package/src/bases/minimal-library/index.js +158 -2
  33. package/src/cli/index.js +21 -2
  34. package/src/cli/questions/layers.js +5 -2
  35. package/src/cli/questions/project-type.js +0 -5
  36. package/src/layers/are-the-types-wrong/index.js +74 -0
  37. package/src/layers/git/files/gitignore +14 -1
  38. package/src/layers/git/index.js +6 -5
  39. package/src/layers/github-actions/index.js +12 -8
  40. package/src/layers/index.js +1 -1
  41. package/src/layers/inspector-support/index.js +101 -0
  42. package/src/layers/prettier/files/.prettierignore +4 -0
  43. package/src/layers/publint/index.js +68 -0
  44. package/src/layers/qunit/files/tests/unit/macros-test.ts +2 -2
  45. package/src/layers/qunit/index.js +107 -7
  46. package/src/layers/qunit/library-files/config/test/babel.config.js +41 -0
  47. package/src/layers/qunit/library-files/config/test/testem.cjs +26 -0
  48. package/src/layers/qunit/library-files/tests/test-helper.ts +36 -0
  49. package/src/layers/qunit/library-files/tests/unit/.gitkeep +0 -0
  50. package/src/layers/qunit/library-files/vite.config.mjs +6 -0
  51. package/src/layers/typescript/index.js +43 -7
  52. package/src/layers/vitest/files/vitest.config.mjs +11 -11
  53. package/src/layers/vitest/index.js +70 -32
  54. package/src/utils/babel.js +9 -6
  55. package/src/utils/fs.js +44 -3
  56. package/src/utils/inspector-support.js +196 -0
  57. package/src/utils/npm.js +21 -7
  58. package/src/utils/remove-types.js +5 -0
  59. package/src/utils/rewrite-imports.js +157 -0
  60. package/src/utils/tsdown-config.js +85 -0
  61. package/src/utils/types.ts +5 -1
  62. package/test/ember.nvp/base-library.test.ts +236 -0
  63. package/test/ember.nvp/generator-replace-or-update.test.ts +2 -3
  64. package/test/ember.nvp/inspector-support.test.ts +179 -0
  65. package/test/ember.nvp/layer-inspector-support.test.ts +69 -0
  66. package/test/ember.nvp/layer-publish-checks.test.ts +109 -0
  67. package/test/ember.nvp/layer-qunit.test.ts +381 -16
  68. package/test/ember.nvp/layer-vitest.test.ts +250 -0
  69. package/test/ember.nvp/layers.test.ts +16 -0
  70. package/test/ember.nvp/library-src-fixtures.ts +81 -0
  71. package/test/ember.nvp/permutations/app-1.test.ts +3 -0
  72. package/test/ember.nvp/permutations/app-2.test.ts +3 -0
  73. package/test/ember.nvp/permutations/library-1.test.ts +3 -0
  74. package/test/ember.nvp/permutations/library-2.test.ts +3 -0
  75. package/test/ember.nvp/permutations/shared.ts +239 -0
  76. package/test/ember.nvp/rewrite-imports.test.ts +235 -0
  77. package/test/test-helpers/permutate.test.ts +17 -0
  78. package/test/test-helpers.ts +46 -8
  79. package/tsconfig.json +1 -0
  80. package/packages/vite/src/maybe-babel.ts +0 -219
  81. package/src/layers/qunit/files/run-tests.mjs +0 -30
  82. package/src/layers/vitest/files/tests/test-helper.ts +0 -5
  83. package/test/ember.nvp/permutations.test.ts +0 -200
  84. /package/src/{layers/vitest/files/tests/integration/.gitkeep → bases/minimal-library/files/src/index.ts} +0 -0
  85. /package/src/layers/{vitest/files/tests/unit → qunit/library-files/tests/rendering}/.gitkeep +0 -0
@@ -0,0 +1,69 @@
1
+ import { describe, it, afterAll, expect } from "vitest";
2
+ import { generate, build, expectIsSetup, layers } from "#test-helpers";
3
+ import { execa } from "execa";
4
+ import { readFile, rm } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+
7
+ const inspectorSupport = layers.find((layer) => layer.name === "inspector-support");
8
+
9
+ describe("layer: inspector-support", () => {
10
+ const dirs: string[] = [];
11
+
12
+ afterAll(async () => {
13
+ if (process.env.CI) return;
14
+
15
+ for (const dir of dirs) {
16
+ await rm(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
17
+ }
18
+ });
19
+
20
+ it("wires a TypeScript app, which still builds", async () => {
21
+ const project = await generate({ type: "app", layers: ["typescript", "inspector-support"] });
22
+ dirs.push(project.directory);
23
+
24
+ expect(inspectorSupport).toBeTruthy();
25
+ await expectIsSetup(project, inspectorSupport!);
26
+
27
+ const install = await execa("pnpm install", { cwd: project.directory, shell: true });
28
+ expect(install.exitCode).toBe(0);
29
+
30
+ const result = await build(project);
31
+ expect(result.exitCode).toBe(0);
32
+ });
33
+
34
+ it("wires a JavaScript app (no typescript layer), which still builds", async () => {
35
+ const project = await generate({ type: "app", layers: ["inspector-support"] });
36
+ dirs.push(project.directory);
37
+
38
+ expect(inspectorSupport).toBeTruthy();
39
+ await expectIsSetup(project, inspectorSupport!);
40
+
41
+ const appFile = await readFile(join(project.directory, "app/app.js"), "utf8");
42
+ expect(appFile).toMatchInlineSnapshot(`
43
+ "/**
44
+ * Looking for services that come from addons?
45
+ *
46
+ * See: https://github.com/embroider-build/embroider/issues/2659
47
+ *
48
+ * We currently don't support app-tree merging from libraries.
49
+ *
50
+ * For services, I highly recommend looking in to either of
51
+ * - https://github.com/chancancode/ember-polaris-service-
52
+ * - https://ember-primitives.pages.dev/6-utils/createService.md
53
+ * - https://ember-primitives.pages.dev/6-utils/createAsyncService.md
54
+ */
55
+ import Application from 'ember-strict-application-resolver';
56
+ import setupInspector from "@embroider/legacy-inspector-support/ember-source-4.12";
57
+ export default class App extends Application {
58
+ modules = { ...import.meta.glob('./router.*', { eager: true }), ...import.meta.glob('./templates/**/*', { eager: true }), ...import.meta.glob('./services/**/*', { eager: true }) };
59
+ inspector = setupInspector(this);
60
+ }"
61
+ `);
62
+
63
+ const install = await execa("pnpm install", { cwd: project.directory, shell: true });
64
+ expect(install.exitCode).toBe(0);
65
+
66
+ const result = await build(project);
67
+ expect(result.exitCode).toBe(0);
68
+ });
69
+ });
@@ -0,0 +1,109 @@
1
+ import { describe, it, beforeAll, afterAll, expect } from "vitest";
2
+ import { generate, pinYukuParser } from "#test-helpers";
3
+ import { execa } from "execa";
4
+ import { readFile, rm } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+
7
+ import type { Project } from "ember.nvp";
8
+
9
+ /**
10
+ * publint and are-the-types-wrong run inside the library's own build
11
+ * (tsdown), so the real assertion is their report lines in `pnpm build`
12
+ * output.
13
+ */
14
+
15
+ async function read(project: Project, filePath: string): Promise<string> {
16
+ return readFile(join(project.directory, filePath), "utf-8");
17
+ }
18
+
19
+ describe("layers: publint + are-the-types-wrong", () => {
20
+ const dirs: string[] = [];
21
+
22
+ afterAll(async () => {
23
+ if (process.env.CI) return;
24
+
25
+ for (const dir of dirs) {
26
+ await rm(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
27
+ }
28
+ });
29
+
30
+ describe("TypeScript library", () => {
31
+ let project: Project;
32
+
33
+ beforeAll(async () => {
34
+ project = await generate({
35
+ type: "library",
36
+ name: "my-lib",
37
+ layers: ["typescript", "publint", "are-the-types-wrong"],
38
+ });
39
+ dirs.push(project.directory);
40
+ });
41
+
42
+ it("wires both checks into the build", async () => {
43
+ expect(await read(project, "tsdown.config.js")).toMatchInlineSnapshot(`
44
+ "import { defineConfig } from "tsdown";
45
+ import { ember } from "@nullvoxpopuli/ember-rolldown";
46
+ export default defineConfig({ entry: ["./src/index.ts"], plugins: [ember()], attw: { profile: "esm-only" }, publint: true })"
47
+ `);
48
+ });
49
+
50
+ it("both checks run and pass in the build", async () => {
51
+ await pinYukuParser(project);
52
+
53
+ let install = await execa("pnpm install", { cwd: project.directory, shell: true });
54
+ expect(install.exitCode).toBe(0);
55
+
56
+ let build = await execa("pnpm build", {
57
+ cwd: project.directory,
58
+ shell: true,
59
+ all: true,
60
+ // assertions match the report lines as plain text
61
+ env: { FORCE_COLOR: "0" },
62
+ });
63
+ expect(build.exitCode).toBe(0);
64
+
65
+ expect(build.all).toContain("[publint] No issues found");
66
+ expect(build.all).toContain("[attw] No problems found");
67
+ });
68
+ });
69
+
70
+ describe("JavaScript library", () => {
71
+ let project: Project;
72
+
73
+ beforeAll(async () => {
74
+ project = await generate({
75
+ type: "library",
76
+ name: "my-lib",
77
+ layers: ["publint", "are-the-types-wrong"],
78
+ });
79
+ dirs.push(project.directory);
80
+ });
81
+
82
+ it("wires publint only (no declarations to check)", async () => {
83
+ expect(await read(project, "tsdown.config.js")).toMatchInlineSnapshot(`
84
+ "import { defineConfig } from "tsdown";
85
+ import { ember } from "@nullvoxpopuli/ember-rolldown";
86
+ export default defineConfig({ entry: ["./src/index.js"], dts: false, plugins: [ember()], publint: true })"
87
+ `);
88
+ });
89
+
90
+ it("publint runs and passes in the build", async () => {
91
+ await pinYukuParser(project);
92
+
93
+ let install = await execa("pnpm install", { cwd: project.directory, shell: true });
94
+ expect(install.exitCode).toBe(0);
95
+
96
+ let build = await execa("pnpm build", {
97
+ cwd: project.directory,
98
+ shell: true,
99
+ all: true,
100
+ // assertions match the report lines as plain text
101
+ env: { FORCE_COLOR: "0" },
102
+ });
103
+ expect(build.exitCode).toBe(0);
104
+
105
+ expect(build.all).toContain("[publint] No issues found");
106
+ expect(build.all).not.toContain("[attw]");
107
+ });
108
+ });
109
+ });
@@ -1,15 +1,141 @@
1
- import { describe, it, afterAll, expect } from "vitest";
2
- import { generate } from "#test-helpers";
3
- import { rimraf } from "rimraf";
1
+ import { describe, it, beforeAll, afterAll, expect } from "vitest";
2
+ import { generate, pinYukuParser } from "#test-helpers";
3
+ import { writeLibrarySource } from "./library-src-fixtures.ts";
4
4
  import { execa } from "execa";
5
+ import { mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
6
+ import { dirname, join, relative, sep } from "node:path";
7
+
8
+ import type { Project } from "ember.nvp";
9
+
10
+ async function listFiles(directory: string): Promise<string[]> {
11
+ const entries = await readdir(directory, { withFileTypes: true, recursive: true });
12
+
13
+ return entries
14
+ .filter((entry) => entry.isFile())
15
+ .map((entry) => relative(directory, join(entry.parentPath, entry.name)))
16
+ .filter((path) => !path.split(sep).includes("node_modules"))
17
+ .filter((path) => !path.startsWith(`dist${sep}`))
18
+ .sort();
19
+ }
20
+
21
+ async function read(project: Project, filePath: string): Promise<string> {
22
+ return readFile(join(project.directory, filePath), "utf-8");
23
+ }
24
+
25
+ async function installAndTest(project: Project) {
26
+ await pinYukuParser(project);
27
+
28
+ let install = await execa("pnpm install", { cwd: project.directory, shell: true });
29
+ expect(install.exitCode).toBe(0);
30
+
31
+ let test = await execa("pnpm test", { cwd: project.directory, shell: true });
32
+ expect(test.exitCode).toBe(0);
33
+ }
5
34
 
6
35
  /**
7
- * The replace-or-update question only matters when a project already exists
8
- * at the target path. These tests generate a project, assert the baseline
9
- * state, then regenerate over it the way the CLI does once the user has
10
- * answered the question, and assert the resulting project output is correct
11
- * for each answer.
36
+ * The layer ships testing infrastructure only; the tests exercising the
37
+ * base's example exports are generated here, in both flavors.
12
38
  */
39
+ const exampleTests = {
40
+ typescript: {
41
+ "tests/rendering/greeting-test.gts": `import { render } from "@ember/test-helpers";
42
+ import { module, test } from "qunit";
43
+ import { setupRenderingTest } from "ember-qunit";
44
+
45
+ import Greeting from "#src/components/greeting.gts";
46
+
47
+ module("Rendering | Greeting", function (hooks) {
48
+ setupRenderingTest(hooks);
49
+
50
+ test("it renders", async function (assert) {
51
+ await render(<template><Greeting @name="Tomster" /></template>);
52
+
53
+ assert.dom("p").hasText("Hello, Tomster!");
54
+ });
55
+ });
56
+ `,
57
+ "tests/rendering/badge-test.gts": `import { render } from "@ember/test-helpers";
58
+ import { module, test } from "qunit";
59
+ import { setupRenderingTest } from "ember-qunit";
60
+
61
+ import { Badge } from "#src/components/badge.gts";
62
+
63
+ module("Rendering | Badge", function (hooks) {
64
+ setupRenderingTest(hooks);
65
+
66
+ test("it renders its content", async function (assert) {
67
+ await render(<template><Badge>New</Badge></template>);
68
+
69
+ assert.dom("span.badge").hasText("New");
70
+ });
71
+ });
72
+ `,
73
+ "tests/unit/math-test.ts": `import { module, test } from "qunit";
74
+
75
+ import { add } from "#src/utils/math.ts";
76
+
77
+ module("Unit | add", function () {
78
+ test("adds two numbers", function (assert) {
79
+ assert.strictEqual(add(1, 2), 3);
80
+ });
81
+ });
82
+ `,
83
+ },
84
+ javascript: {
85
+ "tests/rendering/greeting-test.gjs": `import { render } from "@ember/test-helpers";
86
+ import { module, test } from "qunit";
87
+ import { setupRenderingTest } from "ember-qunit";
88
+
89
+ import Greeting from "#src/components/greeting.gjs";
90
+
91
+ module("Rendering | Greeting", function (hooks) {
92
+ setupRenderingTest(hooks);
93
+
94
+ test("it renders", async function (assert) {
95
+ await render(<template><Greeting @name="Tomster" /></template>);
96
+
97
+ assert.dom("p").hasText("Hello, Tomster!");
98
+ });
99
+ });
100
+ `,
101
+ "tests/rendering/badge-test.gjs": `import { render } from "@ember/test-helpers";
102
+ import { module, test } from "qunit";
103
+ import { setupRenderingTest } from "ember-qunit";
104
+
105
+ import { Badge } from "#src/components/badge.gjs";
106
+
107
+ module("Rendering | Badge", function (hooks) {
108
+ setupRenderingTest(hooks);
109
+
110
+ test("it renders its content", async function (assert) {
111
+ await render(<template><Badge>New</Badge></template>);
112
+
113
+ assert.dom("span.badge").hasText("New");
114
+ });
115
+ });
116
+ `,
117
+ "tests/unit/math-test.js": `import { module, test } from "qunit";
118
+
119
+ import { add } from "#src/utils/math.js";
120
+
121
+ module("Unit | add", function () {
122
+ test("adds two numbers", function (assert) {
123
+ assert.strictEqual(add(1, 2), 3);
124
+ });
125
+ });
126
+ `,
127
+ },
128
+ };
129
+
130
+ async function writeExampleTests(project: Project, flavor: keyof typeof exampleTests) {
131
+ for (let [filePath, contents] of Object.entries(exampleTests[flavor])) {
132
+ let target = join(project.directory, filePath);
133
+
134
+ await mkdir(dirname(target), { recursive: true });
135
+ await writeFile(target, contents);
136
+ }
137
+ }
138
+
13
139
  describe("layer: qunit", () => {
14
140
  const dirs: string[] = [];
15
141
 
@@ -17,18 +143,257 @@ describe("layer: qunit", () => {
17
143
  if (process.env.CI) return;
18
144
 
19
145
  for (const dir of dirs) {
20
- await rimraf(dir, { maxRetries: 3, retryDelay: 100 });
146
+ await rm(dir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
21
147
  }
22
148
  });
23
149
 
24
- it("it boots and run tests", async () => {
25
- const project = await generate({ type: "app", layers: ["qunit"] });
26
- dirs.push(project.directory);
150
+ describe("app", () => {
151
+ it("it boots and run tests", async () => {
152
+ const project = await generate({ type: "app", layers: ["qunit"] });
153
+ dirs.push(project.directory);
154
+
155
+ await installAndTest(project);
156
+ });
157
+ });
158
+
159
+ describe("library (TypeScript)", () => {
160
+ let project: Project;
161
+
162
+ beforeAll(async () => {
163
+ project = await generate({
164
+ type: "library",
165
+ name: "my-lib",
166
+ layers: ["qunit", "typescript"],
167
+ });
168
+ dirs.push(project.directory);
169
+ });
170
+
171
+ it("generates the expected files, without any index.html", async () => {
172
+ let files = await listFiles(project.directory);
173
+
174
+ expect(files.some((file) => file.endsWith("index.html"))).toBe(false);
175
+ expect(files).toMatchInlineSnapshot(`
176
+ [
177
+ ".gitignore",
178
+ "README.md",
179
+ "config/test/babel.config.js",
180
+ "config/test/testem.cjs",
181
+ "package.json",
182
+ "src/index.ts",
183
+ "tests/rendering/.gitkeep",
184
+ "tests/test-helper.ts",
185
+ "tests/unit/.gitkeep",
186
+ "tsconfig.json",
187
+ "tsdown.config.js",
188
+ "vite.config.mjs",
189
+ ]
190
+ `);
191
+ });
192
+
193
+ it("generates the test build config", async () => {
194
+ expect(await read(project, "vite.config.mjs")).toMatchInlineSnapshot(`
195
+ "import { defineConfig } from "vite";
196
+ import { ember } from "@nullvoxpopuli/ember-vite";
197
+
198
+ export default defineConfig({
199
+ plugins: [ember({ babel: { configFile: "./config/test/babel.config.js" } })],
200
+ });
201
+ "
202
+ `);
203
+ expect(await read(project, "config/test/babel.config.js")).toMatchInlineSnapshot(`
204
+ "import { buildMacros } from "@embroider/macros/babel";
205
+
206
+ const macros = buildMacros({
207
+ configure(config) {
208
+ if (process.env.EMBER_ENV === "test") {
209
+ config.enableRuntimeMode();
210
+ }
211
+ },
212
+ });
213
+
214
+ export default {
215
+ plugins: [
216
+ [
217
+ "@babel/plugin-transform-typescript",
218
+ {
219
+ allExtensions: true,
220
+ onlyRemoveTypeImports: true,
221
+ allowDeclareFields: true,
222
+ },
223
+ ],
224
+ [
225
+ "babel-plugin-ember-template-compilation",
226
+ {
227
+ transforms: [...macros.templateMacros],
228
+ },
229
+ ],
230
+ [
231
+ "module:decorator-transforms",
232
+ {
233
+ runtime: {
234
+ import: import.meta.resolve("decorator-transforms/runtime-esm"),
235
+ },
236
+ },
237
+ ],
238
+ ...macros.babelMacros,
239
+ ],
240
+
241
+ generatorOpts: {
242
+ compact: false,
243
+ },
244
+ };
245
+ "
246
+ `);
247
+ expect(await read(project, "config/test/testem.cjs")).toMatchInlineSnapshot(`
248
+ ""use strict";
249
+
250
+ if (typeof module !== "undefined") {
251
+ module.exports = {
252
+ test_page: "tests/index.html?hidepassed",
253
+ cwd: "dist",
254
+ disable_watching: true,
255
+ launch_in_ci: ["Chrome"],
256
+ launch_in_dev: ["Chrome"],
257
+ browser_start_timeout: 120,
258
+ browser_args: {
259
+ Chrome: {
260
+ ci: [
261
+ // --no-sandbox is needed when running Chrome inside a container
262
+ process.env.CI ? "--no-sandbox" : null,
263
+ "--headless",
264
+ "--disable-dev-shm-usage",
265
+ "--disable-software-rasterizer",
266
+ "--mute-audio",
267
+ "--remote-debugging-port=0",
268
+ "--window-size=1440,900",
269
+ ].filter(Boolean),
270
+ },
271
+ },
272
+ };
273
+ }
274
+ "
275
+ `);
276
+ });
277
+
278
+ it("leaves the publish build config alone", async () => {
279
+ expect(await read(project, "tsdown.config.js")).toMatchInlineSnapshot(`
280
+ "import { defineConfig } from "tsdown";
281
+ import { ember } from "@nullvoxpopuli/ember-rolldown";
282
+
283
+ export default defineConfig({
284
+ entry: ["./src/index.ts"],
285
+ plugins: [ember()],
286
+ });
287
+ "
288
+ `);
289
+ });
290
+
291
+ it("installs, and tests generated against the library's exports pass", async () => {
292
+ await writeLibrarySource(project, "typescript");
293
+ await writeExampleTests(project, "typescript");
294
+ await installAndTest(project);
295
+ });
296
+
297
+ it("the publish build still ships precompileTemplate", async () => {
298
+ let build = await execa("pnpm build", { cwd: project.directory, shell: true });
299
+ expect(build.exitCode).toBe(0);
300
+
301
+ let output = await read(project, "dist/index.js");
302
+
303
+ expect(output).toContain("precompileTemplate");
304
+ expect(output).not.toContain("createTemplateFactory");
305
+ });
306
+ });
307
+
308
+ describe("library (JavaScript)", () => {
309
+ let project: Project;
310
+
311
+ beforeAll(async () => {
312
+ project = await generate({ type: "library", name: "my-lib", layers: ["qunit"] });
313
+ dirs.push(project.directory);
314
+ });
315
+
316
+ it("generates the expected files, without any index.html", async () => {
317
+ let files = await listFiles(project.directory);
318
+
319
+ expect(files.some((file) => file.endsWith("index.html"))).toBe(false);
320
+ expect(files).toMatchInlineSnapshot(`
321
+ [
322
+ ".gitignore",
323
+ "README.md",
324
+ "config/test/babel.config.js",
325
+ "config/test/testem.cjs",
326
+ "package.json",
327
+ "src/index.js",
328
+ "tests/rendering/.gitkeep",
329
+ "tests/test-helper.js",
330
+ "tests/unit/.gitkeep",
331
+ "tsdown.config.js",
332
+ "vite.config.mjs",
333
+ ]
334
+ `);
335
+ });
336
+
337
+ it("has no TypeScript leftovers in the test build config", async () => {
338
+ expect(await read(project, "config/test/babel.config.js")).toMatchInlineSnapshot(`
339
+ "import { buildMacros } from "@embroider/macros/babel";
340
+
341
+ const macros = buildMacros({
342
+ configure(config) {
343
+ if (process.env.EMBER_ENV === "test") {
344
+ config.enableRuntimeMode();
345
+ }
346
+ },
347
+ });
348
+
349
+ export default {
350
+ plugins: [[
351
+ "babel-plugin-ember-template-compilation",
352
+ {
353
+ transforms: [...macros.templateMacros],
354
+ },
355
+ ], [
356
+ "module:decorator-transforms",
357
+ {
358
+ runtime: {
359
+ import: import.meta.resolve("decorator-transforms/runtime-esm"),
360
+ },
361
+ },
362
+ ], ...macros.babelMacros],
363
+
364
+ generatorOpts: {
365
+ compact: false,
366
+ },
367
+ };
368
+ "
369
+ `);
370
+ expect(await read(project, "tsdown.config.js")).toMatchInlineSnapshot(`
371
+ "import { defineConfig } from "tsdown";
372
+ import { ember } from "@nullvoxpopuli/ember-rolldown";
373
+
374
+ export default defineConfig({
375
+ entry: ["./src/index.js"],
376
+ dts: false,
377
+ plugins: [ember()],
378
+ });
379
+ "
380
+ `);
381
+ });
382
+
383
+ it("installs, and tests generated against the library's exports pass", async () => {
384
+ await writeLibrarySource(project, "javascript");
385
+ await writeExampleTests(project, "javascript");
386
+ await installAndTest(project);
387
+ });
388
+
389
+ it("the publish build still ships precompileTemplate", async () => {
390
+ let build = await execa("pnpm build", { cwd: project.directory, shell: true });
391
+ expect(build.exitCode).toBe(0);
27
392
 
28
- let install = await execa("pnpm install", { cwd: project.directory, shell: true });
29
- expect(install.exitCode).toBe(0);
393
+ let output = await read(project, "dist/index.js");
30
394
 
31
- let test = await execa("pnpm test", { cwd: project.directory, shell: true });
32
- expect(test.exitCode).toBe(0);
395
+ expect(output).toContain("precompileTemplate");
396
+ expect(output).not.toContain("createTemplateFactory");
397
+ });
33
398
  });
34
399
  });