ember.nvp 1.13.0 → 1.14.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.
@@ -2,8 +2,8 @@
2
2
  "solution": {
3
3
  "ember.nvp": {
4
4
  "impact": "minor",
5
- "oldVersion": "1.12.0",
6
- "newVersion": "1.13.0",
5
+ "oldVersion": "1.13.0",
6
+ "newVersion": "1.14.0",
7
7
  "tagName": "latest",
8
8
  "constraints": [
9
9
  {
@@ -23,5 +23,5 @@
23
23
  "oldVersion": "1.2.0"
24
24
  }
25
25
  },
26
- "description": "## Release (2026-09-30)\n\n* ember.nvp 1.13.0 (minor)\n\n#### :rocket: Enhancement\n* `ember.nvp`\n * [#154](https://github.com/NullVoxPopuli/ember.nvp/pull/154) Default the project type to the detected type on update ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n\n#### Committers: 1\n- @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n"
26
+ "description": "## Release (2026-09-30)\n\n* ember.nvp 1.14.0 (minor)\n\n#### :rocket: Enhancement\n* `ember.nvp`\n * [#156](https://github.com/NullVoxPopuli/ember.nvp/pull/156) Give TypeScript libraries with tests a publish tsconfig ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n\n#### Committers: 1\n- @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))\n"
27
27
  }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## Release (2026-09-30)
4
4
 
5
+ * ember.nvp 1.14.0 (minor)
6
+
7
+ #### :rocket: Enhancement
8
+ * `ember.nvp`
9
+ * [#156](https://github.com/NullVoxPopuli/ember.nvp/pull/156) Give TypeScript libraries with tests a publish tsconfig ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
10
+
11
+ #### Committers: 1
12
+ - @NullVoxPopuli's reduced-access machine account for AI usage ([@NullVoxPopuli-ai-agent](https://github.com/NullVoxPopuli-ai-agent))
13
+
14
+ ## Release (2026-09-30)
15
+
5
16
  * ember.nvp 1.13.0 (minor)
6
17
 
7
18
  #### :rocket: Enhancement
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ember.nvp",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "ember project generator, alternative to the official blueprints, but more modern -- hopefully one day to upstream back in to ember-cli / official blueprints",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,7 +1,8 @@
1
1
  import { applyFolderTo } from "#utils/fs.js";
2
2
  import { getLatest } from "#utils/npm.js";
3
3
  import { hasConfiguredPlugin, prependPlugin, removeConfiguredPlugin } from "#utils/babel.js";
4
- import { packageJson } from "ember-apply";
4
+ import { addTsdownConfigProperty } from "#utils/tsdown-config.js";
5
+ import { packageJson, tsconfig } from "ember-apply";
5
6
  import { join } from "node:path";
6
7
 
7
8
  const deps = {
@@ -39,6 +40,7 @@ const libraryTsDeps = {
39
40
  };
40
41
 
41
42
  const TEST_BABEL_CONFIG = "config/test/babel.config.js";
43
+ const PUBLISH_TSCONFIG = "config/tsconfig.publish.json";
42
44
 
43
45
  /**
44
46
  * @param {import('#utils/project.js').Project} project
@@ -72,6 +74,10 @@ export default {
72
74
 
73
75
  if (isLibrary) {
74
76
  await syncTestBabelConfig(project, ts);
77
+
78
+ if (ts) {
79
+ await usePublishTsconfig(project);
80
+ }
75
81
  }
76
82
 
77
83
  await packageJson.addDevDependencies(
@@ -141,6 +147,12 @@ export default {
141
147
  }
142
148
  }
143
149
 
150
+ if (project.isLibrary && project.wantsTypeScript && !project.hasFile(PUBLISH_TSCONFIG)) {
151
+ if (!explain) return false;
152
+
153
+ reasons.push(`${PUBLISH_TSCONFIG} is missing`);
154
+ }
155
+
144
156
  if (explain) {
145
157
  return {
146
158
  isSetup: reasons.length === 0,
@@ -203,3 +215,45 @@ async function syncTestBabelConfig(project, ts) {
203
215
  TEST_BABEL_CONFIG,
204
216
  );
205
217
  }
218
+
219
+ /**
220
+ * A library's tsconfig.json starts as its publish config:
221
+ * it covers only `src`, with `isolatedDeclarations` for the declarations tsdown emits.
222
+ *
223
+ * Tests live outside `src`, and editors, `lint:types`, and eslint read tsconfig.json.
224
+ * So in a TypeScript library, this layer:
225
+ * - widens tsconfig.json to `src` and `tests`, without the publish-only settings
226
+ * - moves those settings to `config/tsconfig.publish.json`, which the build uses
227
+ *
228
+ * @param {import('#utils/project.js').Project} project
229
+ */
230
+ async function usePublishTsconfig(project) {
231
+ await applyFolderTo(join(import.meta.dirname, "library-ts-files"), project);
232
+ await addTsdownConfigProperty(project, "tsconfig", `tsconfig: "./${PUBLISH_TSCONFIG}"`);
233
+
234
+ let config = await tsconfig.read(project.directory);
235
+
236
+ if (!needsWidening(config)) return;
237
+
238
+ await tsconfig.modify((json) => {
239
+ json.include ||= [];
240
+
241
+ if (!json.include.includes("tests")) {
242
+ json.include.push("tests");
243
+ }
244
+
245
+ delete json.compilerOptions?.rootDir;
246
+ delete json.compilerOptions?.isolatedDeclarations;
247
+ }, project.directory);
248
+ }
249
+
250
+ /**
251
+ * @param {Record<string, any>} config
252
+ */
253
+ function needsWidening(config) {
254
+ return (
255
+ !config.include?.includes("tests") ||
256
+ config.compilerOptions?.rootDir !== undefined ||
257
+ config.compilerOptions?.isolatedDeclarations !== undefined
258
+ );
259
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "include": ["../src"],
4
+ "compilerOptions": {
5
+ "rootDir": "../src",
6
+ "isolatedDeclarations": true
7
+ }
8
+ }
@@ -161,6 +161,7 @@ describe("layer: qunit", () => {
161
161
  "README.md",
162
162
  "config/test/babel.config.js",
163
163
  "config/test/testem.cjs",
164
+ "config/tsconfig.publish.json",
164
165
  "package.json",
165
166
  "src/index.ts",
166
167
  "tests/rendering/.gitkeep",
@@ -258,15 +259,38 @@ describe("layer: qunit", () => {
258
259
  `);
259
260
  });
260
261
 
261
- it("leaves the publish build config alone", async () => {
262
+ it("builds with a publish tsconfig, so tsconfig.json can cover the tests", async () => {
262
263
  expect(await project.read("tsdown.config.js")).toMatchInlineSnapshot(`
263
264
  "import { defineConfig } from "tsdown";
264
265
  import { ember } from "@nullvoxpopuli/ember-rolldown";
265
-
266
- export default defineConfig({
267
- entry: ["./src/index.ts"],
268
- plugins: [ember()],
269
- });
266
+ export default defineConfig({ entry: ["./src/index.ts"], plugins: [ember()], tsconfig: "./config/tsconfig.publish.json" })"
267
+ `);
268
+ expect(await project.read("config/tsconfig.publish.json")).toMatchInlineSnapshot(`
269
+ "{
270
+ "extends": "../tsconfig.json",
271
+ "include": ["../src"],
272
+ "compilerOptions": {
273
+ "rootDir": "../src",
274
+ "isolatedDeclarations": true
275
+ }
276
+ }
277
+ "
278
+ `);
279
+ expect(await project.read("tsconfig.json")).toMatchInlineSnapshot(`
280
+ "{
281
+ "extends": "@ember/library-tsconfig",
282
+ "include": ["src", "tests"],
283
+ "compilerOptions": {
284
+ "lib": ["esnext", "dom", "dom.iterable"],
285
+ "types": ["ember-source/types", "@glint/ember-tsc/types"],
286
+ },
287
+ "contentMappers": [
288
+ {
289
+ "package": "ember-content-mapper",
290
+ "extensions": [".gts", ".gjs"],
291
+ },
292
+ ],
293
+ }
270
294
  "
271
295
  `);
272
296
  });
@@ -292,6 +316,29 @@ describe("layer: qunit", () => {
292
316
  });
293
317
  });
294
318
 
319
+ describe("library (TypeScript) with eslint", () => {
320
+ it("lints the tests", { timeout: 300_000 }, async () => {
321
+ const project = await generate({
322
+ type: "library",
323
+ name: "my-lib",
324
+ layers: ["eslint-bundled", "qunit", "typescript"],
325
+ });
326
+ dirs.push(project.directory);
327
+
328
+ let install = await execa("pnpm install", { cwd: project.directory, shell: true });
329
+ expect(install.exitCode).toBe(0);
330
+
331
+ // eslint's project service cannot parse a file that no tsconfig includes
332
+ let lint = await execa("pnpm lint:eslint", {
333
+ cwd: project.directory,
334
+ shell: true,
335
+ reject: false,
336
+ all: true,
337
+ });
338
+ expect(lint.exitCode, lint.all).toBe(0);
339
+ });
340
+ });
341
+
295
342
  describe("library (JavaScript)", () => {
296
343
  let project: Project;
297
344