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
|
@@ -10,7 +10,7 @@ import { hasInspectorSupport, wireInspectorSupport } from "#utils/inspector-supp
|
|
|
10
10
|
describe("wireInspectorSupport", () => {
|
|
11
11
|
it("wires the generated shape (export default class extends Application)", () => {
|
|
12
12
|
const code = [
|
|
13
|
-
`import Application from "ember
|
|
13
|
+
`import Application from "@ember/application";`,
|
|
14
14
|
``,
|
|
15
15
|
`export default class App extends Application {`,
|
|
16
16
|
` modules = {`,
|
|
@@ -20,7 +20,7 @@ describe("wireInspectorSupport", () => {
|
|
|
20
20
|
].join("\n");
|
|
21
21
|
|
|
22
22
|
expect(wireInspectorSupport(code, "app/app.ts")).toMatchInlineSnapshot(`
|
|
23
|
-
"import Application from "ember
|
|
23
|
+
"import Application from "@ember/application";
|
|
24
24
|
import setupInspector from "@embroider/legacy-inspector-support/ember-source-4.12";
|
|
25
25
|
export default class App extends Application {
|
|
26
26
|
modules = { ...import.meta.glob("./router.*", { eager: true }) };
|
|
@@ -31,7 +31,7 @@ describe("wireInspectorSupport", () => {
|
|
|
31
31
|
|
|
32
32
|
it("wires a named class exported in a separate statement", () => {
|
|
33
33
|
const code = [
|
|
34
|
-
`import Application from "ember
|
|
34
|
+
`import Application from "@ember/application";`,
|
|
35
35
|
``,
|
|
36
36
|
`class App extends Application {`,
|
|
37
37
|
` modules = {};`,
|
|
@@ -41,7 +41,7 @@ describe("wireInspectorSupport", () => {
|
|
|
41
41
|
].join("\n");
|
|
42
42
|
|
|
43
43
|
expect(wireInspectorSupport(code, "app/app.js")).toMatchInlineSnapshot(`
|
|
44
|
-
"import Application from "ember
|
|
44
|
+
"import Application from "@ember/application";
|
|
45
45
|
import setupInspector from "@embroider/legacy-inspector-support/ember-source-4.12";
|
|
46
46
|
class App extends Application {
|
|
47
47
|
modules = { };
|
|
@@ -53,13 +53,13 @@ describe("wireInspectorSupport", () => {
|
|
|
53
53
|
|
|
54
54
|
it("wires an anonymous default-exported class", () => {
|
|
55
55
|
const code = [
|
|
56
|
-
`import Application from "ember
|
|
56
|
+
`import Application from "@ember/application";`,
|
|
57
57
|
``,
|
|
58
58
|
`export default class extends Application {}`,
|
|
59
59
|
].join("\n");
|
|
60
60
|
|
|
61
61
|
expect(wireInspectorSupport(code, "app/app.js")).toMatchInlineSnapshot(`
|
|
62
|
-
"import Application from "ember
|
|
62
|
+
"import Application from "@ember/application";
|
|
63
63
|
import setupInspector from "@embroider/legacy-inspector-support/ember-source-4.12";
|
|
64
64
|
export default class extends Application {
|
|
65
65
|
inspector = setupInspector(this);
|
|
@@ -69,7 +69,7 @@ describe("wireInspectorSupport", () => {
|
|
|
69
69
|
|
|
70
70
|
it("wires a class expression assigned to a variable", () => {
|
|
71
71
|
const code = [
|
|
72
|
-
`import Application from "ember
|
|
72
|
+
`import Application from "@ember/application";`,
|
|
73
73
|
``,
|
|
74
74
|
`const App = class extends Application {`,
|
|
75
75
|
` modules = {};`,
|
|
@@ -79,7 +79,7 @@ describe("wireInspectorSupport", () => {
|
|
|
79
79
|
].join("\n");
|
|
80
80
|
|
|
81
81
|
expect(wireInspectorSupport(code, "app/app.js")).toMatchInlineSnapshot(`
|
|
82
|
-
"import Application from "ember
|
|
82
|
+
"import Application from "@ember/application";
|
|
83
83
|
import setupInspector from "@embroider/legacy-inspector-support/ember-source-4.12";
|
|
84
84
|
const App = class extends Application {
|
|
85
85
|
modules = { };
|
|
@@ -108,14 +108,14 @@ describe("wireInspectorSupport", () => {
|
|
|
108
108
|
it("adds only the missing member when the import is already present", () => {
|
|
109
109
|
const code = [
|
|
110
110
|
`import wireUp from "@embroider/legacy-inspector-support/ember-source-4.12";`,
|
|
111
|
-
`import Application from "ember
|
|
111
|
+
`import Application from "@ember/application";`,
|
|
112
112
|
``,
|
|
113
113
|
`export default class App extends Application {}`,
|
|
114
114
|
].join("\n");
|
|
115
115
|
|
|
116
116
|
expect(wireInspectorSupport(code, "app/app.ts")).toMatchInlineSnapshot(`
|
|
117
117
|
"import wireUp from "@embroider/legacy-inspector-support/ember-source-4.12";
|
|
118
|
-
import Application from "ember
|
|
118
|
+
import Application from "@ember/application";
|
|
119
119
|
export default class App extends Application {
|
|
120
120
|
inspector = wireUp(this);
|
|
121
121
|
}"
|
|
@@ -124,7 +124,7 @@ describe("wireInspectorSupport", () => {
|
|
|
124
124
|
|
|
125
125
|
it("is idempotent", () => {
|
|
126
126
|
const code = [
|
|
127
|
-
`import Application from "ember
|
|
127
|
+
`import Application from "@ember/application";`,
|
|
128
128
|
``,
|
|
129
129
|
`export default class App extends Application {`,
|
|
130
130
|
` modules = {};`,
|
|
@@ -157,7 +157,7 @@ describe("wireInspectorSupport", () => {
|
|
|
157
157
|
describe("hasInspectorSupport", () => {
|
|
158
158
|
it("is false before wiring and true after", () => {
|
|
159
159
|
const code = [
|
|
160
|
-
`import Application from "ember
|
|
160
|
+
`import Application from "@ember/application";`,
|
|
161
161
|
``,
|
|
162
162
|
`export default class App extends Application {}`,
|
|
163
163
|
].join("\n");
|
|
@@ -169,7 +169,7 @@ describe("hasInspectorSupport", () => {
|
|
|
169
169
|
it("is false when only the import is present", () => {
|
|
170
170
|
const code = [
|
|
171
171
|
`import setupInspector from "@embroider/legacy-inspector-support/ember-source-4.12";`,
|
|
172
|
-
`import Application from "ember
|
|
172
|
+
`import Application from "@ember/application";`,
|
|
173
173
|
``,
|
|
174
174
|
`export default class App extends Application {}`,
|
|
175
175
|
].join("\n");
|
|
@@ -52,7 +52,7 @@ describe("layer: inspector-support", () => {
|
|
|
52
52
|
* - https://ember-primitives.pages.dev/6-utils/createService.md
|
|
53
53
|
* - https://ember-primitives.pages.dev/6-utils/createAsyncService.md
|
|
54
54
|
*/
|
|
55
|
-
import Application from 'ember
|
|
55
|
+
import Application from '@ember/application';
|
|
56
56
|
import setupInspector from "@embroider/legacy-inspector-support/ember-source-4.12";
|
|
57
57
|
export default class App extends Application {
|
|
58
58
|
modules = { ...import.meta.glob('./router.*', { eager: true }), ...import.meta.glob('./templates/**/*', { eager: true }), ...import.meta.glob('./services/**/*', { eager: true }) };
|
|
@@ -42,23 +42,23 @@ describe("layer: readme", () => {
|
|
|
42
42
|
|
|
43
43
|
### Installation
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
\`\`\`sh
|
|
46
46
|
pnpm install
|
|
47
|
-
|
|
47
|
+
\`\`\`
|
|
48
48
|
|
|
49
49
|
### Development
|
|
50
50
|
|
|
51
51
|
To start the local development server:
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
\`\`\`sh
|
|
54
54
|
pnpm dev
|
|
55
|
-
|
|
55
|
+
\`\`\`
|
|
56
56
|
|
|
57
57
|
or
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
\`\`\`sh
|
|
60
60
|
pnpm start
|
|
61
|
-
|
|
61
|
+
\`\`\`
|
|
62
62
|
|
|
63
63
|
## Features & Tooling
|
|
64
64
|
|
|
@@ -109,9 +109,9 @@ describe("layer: readme", () => {
|
|
|
109
109
|
|
|
110
110
|
To build the library:
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
\`\`\`sh
|
|
113
113
|
npm run build
|
|
114
|
-
|
|
114
|
+
\`\`\`
|
|
115
115
|
|
|
116
116
|
## Features & Tooling
|
|
117
117
|
|
|
@@ -156,29 +156,29 @@ describe("layer: readme", () => {
|
|
|
156
156
|
|
|
157
157
|
To start development:
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
\`\`\`sh
|
|
160
160
|
pnpm dev
|
|
161
|
-
|
|
161
|
+
\`\`\`
|
|
162
162
|
|
|
163
163
|
or
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
\`\`\`sh
|
|
166
166
|
pnpm start
|
|
167
|
-
|
|
167
|
+
\`\`\`
|
|
168
168
|
|
|
169
169
|
### Building
|
|
170
170
|
|
|
171
171
|
To build the library:
|
|
172
172
|
|
|
173
|
-
|
|
173
|
+
\`\`\`sh
|
|
174
174
|
pnpm build
|
|
175
|
-
|
|
175
|
+
\`\`\`
|
|
176
176
|
|
|
177
177
|
or
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
\`\`\`sh
|
|
180
180
|
pnpm build:watch
|
|
181
|
-
|
|
181
|
+
\`\`\`
|
|
182
182
|
|
|
183
183
|
## Features & Tooling
|
|
184
184
|
|
|
@@ -91,7 +91,7 @@ function appTests(ext: "ts" | "js") {
|
|
|
91
91
|
[`tests/application/welcome-test.g${ext}`]: `import { describe, expect } from "vitest";
|
|
92
92
|
import { applicationTest } from "ember-vitest";
|
|
93
93
|
import { visit } from "@ember/test-helpers";
|
|
94
|
-
import Application from "ember
|
|
94
|
+
import Application from "@ember/application";
|
|
95
95
|
|
|
96
96
|
import Router from "#app/router.${ext}";
|
|
97
97
|
import ApplicationTemplate from "#app/templates/application.g${ext}";
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { describe, it, beforeAll, afterAll, expect } from "vitest";
|
|
2
|
+
import { generate, listFiles } from "#test-helpers";
|
|
3
|
+
import { writeLibrarySource } from "./library-src-fixtures.ts";
|
|
4
|
+
import { execa } from "execa";
|
|
5
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
|
|
8
|
+
import type { Project } from "ember.nvp";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A library whose package also holds dev-only code (a demo app, in-package
|
|
12
|
+
* tests) keeps two of each build config: a permissive `tsconfig.json` and
|
|
13
|
+
* `babel.config.js` that editors and `tsc --noEmit` use over everything, and
|
|
14
|
+
* publish-only counterparts covering just what gets published. Either publish
|
|
15
|
+
* config can sit in the package root or in `config/`.
|
|
16
|
+
*
|
|
17
|
+
* These tests generate a real library, put the configs in each of those
|
|
18
|
+
* places, and run the real `pnpm build`.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A development babel config: strips TypeScript, but leaves `<template>` as the
|
|
23
|
+
* `@ember/template-compiler` call content-tag produced. Publishing this output
|
|
24
|
+
* would tie the artifact to one exact ember-source.
|
|
25
|
+
*/
|
|
26
|
+
const devBabelConfig = `export default {
|
|
27
|
+
plugins: [
|
|
28
|
+
["@babel/plugin-transform-typescript", { allExtensions: true, allowDeclareFields: true }],
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* A publish babel config: compiles templates to \`precompileTemplate\`, which is
|
|
35
|
+
* what a published library ships (the consuming app does the final compile).
|
|
36
|
+
*/
|
|
37
|
+
const publishBabelConfig = `export default {
|
|
38
|
+
plugins: [
|
|
39
|
+
["@babel/plugin-transform-typescript", { allExtensions: true, allowDeclareFields: true }],
|
|
40
|
+
["babel-plugin-ember-template-compilation", { targetFormat: "hbs" }],
|
|
41
|
+
["module:decorator-transforms", { runtime: { import: "decorator-transforms/runtime-esm" } }],
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The `tsconfig.json` such a library actually has: it covers the demo app as
|
|
48
|
+
* well as `src`, and deliberately has no `isolatedDeclarations` -- dev-only
|
|
49
|
+
* code shouldn't be held to a declaration-emit constraint. If the build reads
|
|
50
|
+
* this file rather than the publish tsconfig, the guard fails it, which is what
|
|
51
|
+
* makes every assertion below meaningful.
|
|
52
|
+
*/
|
|
53
|
+
const devTsconfig = `{
|
|
54
|
+
"extends": "@ember/library-tsconfig",
|
|
55
|
+
"include": ["src", "demo-app"],
|
|
56
|
+
"compilerOptions": {
|
|
57
|
+
"lib": ["esnext", "dom", "dom.iterable"],
|
|
58
|
+
"types": ["ember-source/types", "@glint/ember-tsc/types"]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Relative paths in a tsconfig resolve against the file itself, so the copy
|
|
65
|
+
* kept in `config/` has to reach back out to `src`.
|
|
66
|
+
*/
|
|
67
|
+
function publishTsconfig(directory: "." | "config"): string {
|
|
68
|
+
const src = directory === "config" ? "../src" : "./src";
|
|
69
|
+
|
|
70
|
+
return `{
|
|
71
|
+
"extends": "@ember/library-tsconfig",
|
|
72
|
+
"include": ["${src}"],
|
|
73
|
+
"compilerOptions": {
|
|
74
|
+
"rootDir": "${src}",
|
|
75
|
+
"lib": ["esnext", "dom", "dom.iterable"],
|
|
76
|
+
"isolatedDeclarations": true,
|
|
77
|
+
"types": ["ember-source/types", "@glint/ember-tsc/types"]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** `tsconfigOption` is a literal expression: a quoted path, or `false`. */
|
|
84
|
+
function tsdownConfig(tsconfigOption: string): string {
|
|
85
|
+
return `import { defineConfig } from "tsdown";
|
|
86
|
+
import { ember } from "@nullvoxpopuli/ember-rolldown";
|
|
87
|
+
|
|
88
|
+
export default defineConfig({
|
|
89
|
+
entry: ["./src/index.ts"],
|
|
90
|
+
tsconfig: ${tsconfigOption},
|
|
91
|
+
plugins: [ember()],
|
|
92
|
+
});
|
|
93
|
+
`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Every place a publish config can be found, so each layout starts clean. */
|
|
97
|
+
const BABEL_CONFIG_PATHS = ["babel.publish.config.js", "config/babel.publish.config.js"];
|
|
98
|
+
const TSCONFIG_PATHS = [
|
|
99
|
+
"tsconfig.publish.json",
|
|
100
|
+
"config/tsconfig.publish.json",
|
|
101
|
+
"config/tsconfig.json",
|
|
102
|
+
"tsconfig.base.json",
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
describe("publish configs", () => {
|
|
106
|
+
let project: Project;
|
|
107
|
+
|
|
108
|
+
beforeAll(async () => {
|
|
109
|
+
project = await generate({ type: "library", name: "my-lib", layers: ["typescript"] });
|
|
110
|
+
|
|
111
|
+
await writeLibrarySource(project, "typescript");
|
|
112
|
+
|
|
113
|
+
// A library that writes its own babel config declares the plugins it uses.
|
|
114
|
+
const manifest = JSON.parse((await project.read("package.json"))!);
|
|
115
|
+
|
|
116
|
+
manifest.devDependencies["@babel/core"] = "^7.28.10";
|
|
117
|
+
manifest.devDependencies["@babel/plugin-transform-typescript"] = "^7.28.10";
|
|
118
|
+
manifest.devDependencies["babel-plugin-ember-template-compilation"] = "^4.0.0";
|
|
119
|
+
|
|
120
|
+
await writeFile(
|
|
121
|
+
join(project.directory, "package.json"),
|
|
122
|
+
JSON.stringify(manifest, null, 2),
|
|
123
|
+
"utf-8",
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// Dev-only source: exports with no type annotations, which the publish
|
|
127
|
+
// tsconfig must not cover.
|
|
128
|
+
await mkdir(join(project.directory, "demo-app"), { recursive: true });
|
|
129
|
+
await writeFile(
|
|
130
|
+
join(project.directory, "demo-app", "app.gts"),
|
|
131
|
+
`export const anything = { not: "annotated" };\nexport default <template>demo</template>;\n`,
|
|
132
|
+
"utf-8",
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
await writeFile(join(project.directory, "tsconfig.json"), devTsconfig, "utf-8");
|
|
136
|
+
await writeFile(join(project.directory, "babel.config.js"), devBabelConfig, "utf-8");
|
|
137
|
+
|
|
138
|
+
const install = await execa("pnpm install", { cwd: project.directory, shell: true });
|
|
139
|
+
expect(install.exitCode).toBe(0);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
afterAll(async () => {
|
|
143
|
+
if (process.env.CI) return;
|
|
144
|
+
|
|
145
|
+
await rm(project.directory, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
/** Clears every publish config, so one test's layout can't satisfy the next. */
|
|
149
|
+
async function resetConfigs() {
|
|
150
|
+
for (const relative of [...BABEL_CONFIG_PATHS, ...TSCONFIG_PATHS]) {
|
|
151
|
+
await rm(join(project.directory, relative), { force: true });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
await rm(join(project.directory, "dist"), { recursive: true, force: true });
|
|
155
|
+
await mkdir(join(project.directory, "config"), { recursive: true });
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function runBuild() {
|
|
159
|
+
const build = await execa("pnpm build", {
|
|
160
|
+
cwd: project.directory,
|
|
161
|
+
shell: true,
|
|
162
|
+
reject: false,
|
|
163
|
+
all: true,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
return { build, output: await project.read("dist/index.js") };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Puts the publish configs in the requested places and runs the real build. */
|
|
170
|
+
async function buildWith({
|
|
171
|
+
babel,
|
|
172
|
+
tsconfig,
|
|
173
|
+
}: {
|
|
174
|
+
babel: "." | "config" | false;
|
|
175
|
+
tsconfig: "." | "config";
|
|
176
|
+
}) {
|
|
177
|
+
await resetConfigs();
|
|
178
|
+
|
|
179
|
+
if (babel !== false) {
|
|
180
|
+
const relative = join(babel, "babel.publish.config.js");
|
|
181
|
+
|
|
182
|
+
await writeFile(join(project.directory, relative), publishBabelConfig, "utf-8");
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const tsconfigRelative = join(tsconfig, "tsconfig.publish.json");
|
|
186
|
+
|
|
187
|
+
await writeFile(join(project.directory, tsconfigRelative), publishTsconfig(tsconfig), "utf-8");
|
|
188
|
+
await writeFile(
|
|
189
|
+
join(project.directory, "tsdown.config.js"),
|
|
190
|
+
tsdownConfig(`"./${tsconfigRelative}"`),
|
|
191
|
+
"utf-8",
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
return await runBuild();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (const babel of [".", "config"] as const) {
|
|
198
|
+
for (const tsconfig of [".", "config"] as const) {
|
|
199
|
+
const where = (directory: string) => (directory === "." ? "the package root" : "config/");
|
|
200
|
+
|
|
201
|
+
it(`builds with the babel config in ${where(babel)} and the tsconfig in ${where(tsconfig)}`, async () => {
|
|
202
|
+
const { build, output } = await buildWith({ babel, tsconfig });
|
|
203
|
+
|
|
204
|
+
expect(build.exitCode, build.all).toBe(0);
|
|
205
|
+
|
|
206
|
+
// The publish babel config ran: templates came out as
|
|
207
|
+
// precompileTemplate, which only its template-compilation step emits.
|
|
208
|
+
expect(output).toContain("precompileTemplate");
|
|
209
|
+
expect(output).not.toContain("createTemplateFactory");
|
|
210
|
+
|
|
211
|
+
// ...and the dev config, which has no template compilation, did not.
|
|
212
|
+
expect(output).not.toContain("@ember/template-compiler");
|
|
213
|
+
|
|
214
|
+
// Declarations emitted, so the guard read the publish tsconfig: the
|
|
215
|
+
// dev tsconfig.json covering demo-app/ has no isolatedDeclarations and
|
|
216
|
+
// would have failed the build.
|
|
217
|
+
expect(await listFiles(join(project.directory, "dist"))).toContain("index.d.ts");
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
it("falls back to the dev babel config when there is no publish one", async () => {
|
|
223
|
+
const { build, output } = await buildWith({ babel: false, tsconfig: "." });
|
|
224
|
+
|
|
225
|
+
expect(build.exitCode, build.all).toBe(0);
|
|
226
|
+
|
|
227
|
+
// Nothing compiled the template, so content-tag's output survives -- the
|
|
228
|
+
// artifact you don't want to publish, which is why the preference exists.
|
|
229
|
+
expect(output).toContain("@ember/template-compiler");
|
|
230
|
+
expect(output).not.toContain("precompileTemplate");
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Writes `files` into the project and builds with `tsconfigOption` as tsdown's
|
|
235
|
+
* `tsconfig`, for the cases about *which* tsconfig the guard ends up reading.
|
|
236
|
+
* The publish babel config is always present so these fail for tsconfig
|
|
237
|
+
* reasons only.
|
|
238
|
+
*/
|
|
239
|
+
async function buildWithTsconfigOption(
|
|
240
|
+
tsconfigOption: string,
|
|
241
|
+
files: Record<string, string> = {},
|
|
242
|
+
) {
|
|
243
|
+
await resetConfigs();
|
|
244
|
+
|
|
245
|
+
await writeFile(
|
|
246
|
+
join(project.directory, "babel.publish.config.js"),
|
|
247
|
+
publishBabelConfig,
|
|
248
|
+
"utf-8",
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
for (const [relative, contents] of Object.entries(files)) {
|
|
252
|
+
await writeFile(join(project.directory, relative), contents, "utf-8");
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
await writeFile(
|
|
256
|
+
join(project.directory, "tsdown.config.js"),
|
|
257
|
+
tsdownConfig(tsconfigOption),
|
|
258
|
+
"utf-8",
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
return await runBuild();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
it("fails when the publish tsconfig itself lacks isolatedDeclarations", async () => {
|
|
265
|
+
const { build } = await buildWithTsconfigOption(`"./tsconfig.publish.json"`, {
|
|
266
|
+
"tsconfig.publish.json": publishTsconfig(".").replace(
|
|
267
|
+
`"isolatedDeclarations": true,\n `,
|
|
268
|
+
"",
|
|
269
|
+
),
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
expect(build.exitCode).not.toBe(0);
|
|
273
|
+
expect(build.all).toContain('"compilerOptions.isolatedDeclarations": true');
|
|
274
|
+
expect(build.all).toContain("tsconfig.publish.json");
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("accepts a directory, reading the tsconfig.json inside it", async () => {
|
|
278
|
+
const { build } = await buildWithTsconfigOption(`"./config"`, {
|
|
279
|
+
"config/tsconfig.json": publishTsconfig("config"),
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
expect(build.exitCode, build.all).toBe(0);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("takes the flag from an extends chain", async () => {
|
|
286
|
+
const { build } = await buildWithTsconfigOption(`"./tsconfig.publish.json"`, {
|
|
287
|
+
"tsconfig.base.json": `{ "compilerOptions": { "isolatedDeclarations": true } }\n`,
|
|
288
|
+
"tsconfig.publish.json": publishTsconfig(".").replace(
|
|
289
|
+
`"extends": "@ember/library-tsconfig"`,
|
|
290
|
+
`"extends": ["@ember/library-tsconfig", "./tsconfig.base.json"]`,
|
|
291
|
+
),
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
expect(build.exitCode, build.all).toBe(0);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it("rejects tsconfig: false while declarations are on", async () => {
|
|
298
|
+
// No tsconfig means no isolatedDeclarations, so tsdown falls back to the
|
|
299
|
+
// tsc-based pipeline, which can't see compiled .gts and dies with
|
|
300
|
+
// "Source file not found". Fail with something actionable instead.
|
|
301
|
+
const { build } = await buildWithTsconfigOption("false");
|
|
302
|
+
|
|
303
|
+
expect(build.exitCode).not.toBe(0);
|
|
304
|
+
expect(build.all).toContain("`tsconfig: false` cannot be combined with declaration emit");
|
|
305
|
+
expect(build.all).not.toContain("Source file not found");
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it("allows tsconfig: false for a library that ships no types", async () => {
|
|
309
|
+
await resetConfigs();
|
|
310
|
+
|
|
311
|
+
await writeFile(
|
|
312
|
+
join(project.directory, "babel.publish.config.js"),
|
|
313
|
+
publishBabelConfig,
|
|
314
|
+
"utf-8",
|
|
315
|
+
);
|
|
316
|
+
await writeFile(
|
|
317
|
+
join(project.directory, "tsdown.config.js"),
|
|
318
|
+
`import { defineConfig } from "tsdown";
|
|
319
|
+
import { ember } from "@nullvoxpopuli/ember-rolldown";
|
|
320
|
+
|
|
321
|
+
export default defineConfig({
|
|
322
|
+
entry: ["./src/index.ts"],
|
|
323
|
+
tsconfig: false,
|
|
324
|
+
dts: false,
|
|
325
|
+
plugins: [ember()],
|
|
326
|
+
});
|
|
327
|
+
`,
|
|
328
|
+
"utf-8",
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
const { build } = await runBuild();
|
|
332
|
+
|
|
333
|
+
expect(build.exitCode, build.all).toBe(0);
|
|
334
|
+
expect(await listFiles(join(project.directory, "dist"))).not.toContain("index.d.ts");
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it("keeps dev-only source out of the build", async () => {
|
|
338
|
+
// demo-app/app.gts would be an isolated-declarations error, and builds fine
|
|
339
|
+
// only because the publish tsconfig doesn't cover it.
|
|
340
|
+
const { build } = await buildWith({ babel: ".", tsconfig: "." });
|
|
341
|
+
|
|
342
|
+
expect(build.exitCode, build.all).toBe(0);
|
|
343
|
+
expect(await listFiles(join(project.directory, "dist"))).toMatchInlineSnapshot(`
|
|
344
|
+
[
|
|
345
|
+
"index.d.ts",
|
|
346
|
+
"index.d.ts.map",
|
|
347
|
+
"index.js",
|
|
348
|
+
"index.js.map",
|
|
349
|
+
]
|
|
350
|
+
`);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from "rolldown";
|
|
2
|
-
|
|
3
|
-
import manifest from "./package.json" with { type: "json" };
|
|
4
|
-
|
|
5
|
-
const deps = [
|
|
6
|
-
...Object.keys(manifest.dependencies || {}),
|
|
7
|
-
...Object.keys(manifest.peerDependencies || {}),
|
|
8
|
-
];
|
|
9
|
-
|
|
10
|
-
export default defineConfig({
|
|
11
|
-
input: {
|
|
12
|
-
index: "index.ts",
|
|
13
|
-
"app-reexports": "src/app-reexports.ts",
|
|
14
|
-
},
|
|
15
|
-
output: {
|
|
16
|
-
format: "esm",
|
|
17
|
-
dir: "dist",
|
|
18
|
-
},
|
|
19
|
-
external(id) {
|
|
20
|
-
if (id.startsWith("node:")) return true;
|
|
21
|
-
if (deps.some((dep) => id.startsWith(dep))) return true;
|
|
22
|
-
},
|
|
23
|
-
});
|