Repository: alloy-framework/alloy
Pull request #62 (2025-03-13 00:31:55)

Package json improvements

github-actions[bot]: <!--chronus-github-change-commenter-->
All changed packages have been documented.
 - :white_check_mark: `@alloy-js/core`
 - :white_check_mark: `@alloy-js/typescript`

<details>
<summary>Show changes</summary>

### `@alloy-js/core` - _fix_ [✏️](https://github.com/bterlson/alloy/edit/package-json-improvements/.chronus/changes/package-json-improvements-2025-2-12-17-29-56.md?pr=/alloy-framework/alloy/pull/62)
> Fix writeOutput failing to make new files
### `@alloy-js/typescript` - _feature_ [✏️](https://github.com/bterlson/alloy/edit/package-json-improvements/.chronus/changes/package-json-improvements-2025-2-12-17-31-17.md?pr=/alloy-framework/alloy/pull/62)
> Improve TypeScript's PackageJson component. It can now be used outside of a PackageDirectory.
</details>

pkg-pr-new[bot]: 
[Open in Stackblitz](https://pkg.pr.new/template/b225f4d4-2de6-4d3b-9e81-2748a9760167)


<details><summary><b>@alloy-js/babel-plugin</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/babel-plugin@62
```

</p></details>
      
    

<details><summary><b>@alloy-js/babel-plugin-jsx-dom-expressions</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/babel-plugin-jsx-dom-expressions@62
```

</p></details>
      
    

<details><summary><b>@alloy-js/core</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/core@62
```

</p></details>
      
    

<details><summary><b>@alloy-js/babel-preset</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/babel-preset@62
```

</p></details>
      
    

<details><summary><b>@alloy-js/csharp</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/csharp@62
```

</p></details>
      
    

<details><summary><b>@alloy-js/java</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/java@62
```

</p></details>
      
    

<details><summary><b>@alloy-js/json</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/json@62
```

</p></details>
      
    

<details><summary><b>@alloy-js/prettier-plugin-alloy</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/prettier-plugin-alloy@62
```

</p></details>
      
    

<details><summary><b>@alloy-js/typescript</b></summary><p>

```
npm i https://pkg.pr.new/alloy-framework/alloy/@alloy-js/typescript@62
```

</p></details>
      
    

_commit: <a href="https://github.com/alloy-framework/alloy/runs/38676327292"><code>c516de0</code></a>_


Patch:
diff --git a/.chronus/changes/package-json-improvements-2025-2-12-17-29-56.md b/.chronus/changes/package-json-improvements-2025-2-12-17-29-56.md
new file mode 100644
index 0000000..a677495
--- /dev/null
+++ b/.chronus/changes/package-json-improvements-2025-2-12-17-29-56.md
@@ -0,0 +1,7 @@
+---
+changeKind: fix
+packages:
+  - "@alloy-js/core"
+---
+
+Fix writeOutput failing to make new files
\ No newline at end of file
diff --git a/.chronus/changes/package-json-improvements-2025-2-12-17-31-17.md b/.chronus/changes/package-json-improvements-2025-2-12-17-31-17.md
new file mode 100644
index 0000000..d4903a6
--- /dev/null
+++ b/.chronus/changes/package-json-improvements-2025-2-12-17-31-17.md
@@ -0,0 +1,7 @@
+---
+changeKind: feature
+packages:
+  - "@alloy-js/typescript"
+---
+
+Improve TypeScript's PackageJson component. It can now be used outside of a PackageDirectory.
\ No newline at end of file
diff --git a/eslint.config.js b/eslint.config.js
index d3898c3..86e8dd1 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -1,6 +1,6 @@
 // @ts-check
 import eslint from "@eslint/js";
-import vitest from "eslint-plugin-vitest";
+import vitest from "@vitest/eslint-plugin";
 import { dirname } from "path";
 import tsEslint from "typescript-eslint";
 import { fileURLToPath } from "url";
diff --git a/package.json b/package.json
index 643d971..412baaf 100644
--- a/package.json
+++ b/package.json
@@ -22,9 +22,10 @@
     "@chronus/chronus": "^0.17.0",
     "@chronus/github": "^0.4.9",
     "@chronus/github-pr-commenter": "^0.5.9",
+    "@typescript-eslint/utils": "^8.26.1",
+    "@vitest/eslint-plugin": "catalog:",
     "concurrently": "catalog:",
     "eslint": "catalog:",
-    "eslint-plugin-vitest": "catalog:",
     "prettier": "catalog:",
     "prettier-plugin-organize-imports": "catalog:",
     "rimraf": "catalog:",
diff --git a/packages/core/src/write-output.ts b/packages/core/src/write-output.ts
index ea95652..d678cce 100644
--- a/packages/core/src/write-output.ts
+++ b/packages/core/src/write-output.ts
@@ -1,4 +1,4 @@
-import { mkdirSync, statSync, writeFileSync } from "node:fs";
+import { existsSync, mkdirSync, writeFileSync } from "node:fs";
 import { relative, resolve } from "pathe";
 import { OutputDirectory } from "./render.js";
 import { traverseOutput } from "./utils.js";
@@ -10,7 +10,7 @@ export function writeOutput(output: OutputDirectory, basePath: string = "") {
   traverseOutput(output, {
     visitDirectory(directory) {
       const path = resolve(basePath, directory.path);
-      if (statSync(path)) {
+      if (existsSync(path)) {
         return;
       }
       // eslint-disable-next-line no-console
@@ -19,7 +19,7 @@ export function writeOutput(output: OutputDirectory, basePath: string = "") {
     },
     visitFile(file) {
       const path = resolve(basePath, file.path);
-      if (statSync(path)) {
+      if (existsSync(path)) {
         // eslint-disable-next-line no-console
         console.log("overwrite", relative(process.cwd(), path));
       } else {
diff --git a/packages/typescript/src/components/PackageDirectory.tsx b/packages/typescript/src/components/PackageDirectory.tsx
index 8dc02a6..8a1ef5c 100644
--- a/packages/typescript/src/components/PackageDirectory.tsx
+++ b/packages/typescript/src/components/PackageDirectory.tsx
@@ -7,6 +7,7 @@ import {
   shallowRef,
   SourceDirectory,
   SourceDirectoryContext,
+  splitProps,
   useBinder,
   useContext,
   useScope,
@@ -14,17 +15,10 @@ import {
 import { join } from "pathe";
 import { createTSPackageScope, TSPackageScope } from "../symbols/index.js";
 import { modulePath } from "../utils.js";
-import {
-  ExportPath,
-  PackageExports,
-  PackageJsonFile,
-  PackageJsonFileProps,
-} from "./PackageJson.js";
+import { PackageJsonFile, PackageJsonFileProps } from "./PackageJson.js";
 import { TSConfigJson } from "./TsConfigJson.js";
 
 export interface PackageDirectoryProps extends PackageJsonFileProps {
-  dependencies?: Record<string, string>;
-  exports?: PackageExports | ExportPath;
   tsConfig?: { outDir?: string };
   children?: Children;
   path?: string;
@@ -54,27 +48,23 @@ export function PackageDirectory(props: PackageDirectoryProps) {
     props.path ?? ".",
   );
 
-  if (props.exports) {
-    if (typeof props.exports === "string") {
-      packageContext.scope.addRawExport(".", props.exports);
-    } else {
-      for (const ex of Object.entries(props.exports)) {
-        packageContext.scope.addRawExport(ex[0], ex[1]);
-      }
-    }
+  const devDeps = props.devDependencies ?? {};
+  if (!devDeps["typescript"]) {
+    devDeps["typescript"] = "^5.5.2";
   }
 
-  if (props.dependencies) {
-    for (const dep of Object.entries(props.dependencies)) {
-      packageContext.scope.addRawDependency(dep[0], dep[1]);
-    }
-  }
+  const [_, pkgJsonProps] = splitProps(props, [
+    "tsConfig",
+    "children",
+    "path",
+    "devDependencies",
+  ]);
 
   return (
     <SourceDirectory path={props.path ?? "."}>
       <PackageContext.Provider value={packageContext}>
         <Scope value={packageContext.scope}>
-          <PackageJsonFile {...props} />
+          <PackageJsonFile {...pkgJsonProps} devDependencies={devDeps} />
           <TSConfigJson {...props.tsConfig} />
           {props.children}
         </Scope>
diff --git a/packages/typescript/src/components/PackageJson.tsx b/packages/typescript/src/components/PackageJson.tsx
index b6d29d8..c500e23 100644
--- a/packages/typescript/src/components/PackageJson.tsx
+++ b/packages/typescript/src/components/PackageJson.tsx
@@ -3,10 +3,47 @@ import { modulePath } from "../utils.js";
 import { usePackage } from "./PackageDirectory.js";
 
 export interface PackageJsonFileProps {
+  /** The name of the package */
   name: string;
+
+  /** The version of the package */
   version: string;
+
+  /** The description of the package */
+  description?: string;
+
+  /** The license of the package */
+  license?: string;
+
+  /** The author of the package */
+  author?: string;
+
+  /** The homepage of the package */
+  homepage?: string;
+
+  /** The repository of the package */
+  repository?: string | { type: string; url: string };
+
+  /** The keywords of the package */
+  keywords?: string[];
+
+  /** Whether this is a commonjs or module. Defaults to module. */
   type?: "module" | "commonjs";
+
+  /**
+   * The hard-coded dependencies of the package. References to external packages
+   * will add to the dependency list automatically. Only list dependencies here
+   * that are not referenced via refkey.
+   */
+  dependencies?: Record<string, string>;
+
+  /** The hard-coded exports of the package. */
+  exports?: PackageExports | ExportPath;
+
+  /** The dev dependencies of the package. */
   devDependencies?: Record<string, string>;
+
+  /** The scripts entries of the package. */
   scripts?: Record<string, string>;
 }
 
@@ -20,46 +57,68 @@ export interface PackageExports {
   [key: string]: ExportPath;
 }
 
+/**
+ * A file containing a package.json that defines a package. When placed inside a
+ * {@link PackageDirectory}, it will contain dependencies and exports for
+ * symbols defined inside the package. Additional dependencies and exports can
+ * be provided.
+ *
+ * @example
+ * ```tsx
+ * <PackageJsonFile name="my-package" version="1.0.0" />
+ * ```
+ */
 export function PackageJsonFile(props: PackageJsonFileProps) {
   const pkg = usePackage();
-  if (!pkg) {
-    throw new Error(
-      "Package json component needs to be inside a PackageDirectory",
-    );
-  }
 
   const jsonContent = memo(() => {
     const pkgJson = {
       name: props.name,
       version: props.version,
+      author: props.author,
+      description: props.description,
+      license: props.license,
+      homepage: props.homepage,
       type: props.type ?? "module",
-      dependencies: Object.fromEntries([
-        ...pkg.scope.rawDependencies.entries(),
-        ...Array.from(pkg.scope.dependencies).map((dependency) => [
-          dependency.name,
-          dependency.version,
-        ]),
-      ]),
-      devDependencies: {
-        ...props.devDependencies,
-        typescript: "^5.5.2",
-      },
+      dependencies:
+        props.dependencies || (pkg && pkg.scope.dependencies.size > 0) ?
+          Object.fromEntries([
+            ...Object.entries(props.dependencies ?? {}),
+            ...(pkg ?
+              Array.from(pkg.scope.dependencies).map((dependency) => [
+                dependency.name,
+                dependency.version,
+              ])
+            : []),
+          ])
+        : undefined,
+      devDependencies: props.devDependencies,
       scripts: props.scripts,
       exports: undefined as any,
     };
 
-    const exportsEntries: [string, ExportPath][] = [];
-    for (const [publicPath, module] of pkg.scope.exportedSymbols) {
-      exportsEntries.push([
-        publicPath,
-        modulePath(pkg.outFileMapper.value(module.name)),
-      ]);
-    }
+    if (typeof props.exports === "string") {
+      pkgJson.exports = props.exports;
+    } else {
+      const exportsEntries: [string, ExportPath][] = [];
+      for (const entry of Object.entries(props.exports ?? {})) {
+        exportsEntries.push(entry);
+      }
+
+      if (pkg) {
+        for (const [publicPath, module] of pkg.scope.exportedSymbols) {
+          exportsEntries.push([
+            publicPath,
+            modulePath(pkg.outFileMapper.value(module.name)),
+          ]);
+        }
+      }
 
-    pkgJson.exports =
-      exportsEntries.length === 0 ?
-        undefined
-      : Object.fromEntries(exportsEntries);
+      pkgJson.exports =
+        exportsEntries.length === 0 ?
+          undefined
+        : Object.fromEntries(exportsEntries);
+    }
 
     return JSON.stringify(pkgJson, null, 2);
   });
diff --git a/packages/typescript/src/symbols/ts-package-scope.ts b/packages/typescript/src/symbols/ts-package-scope.ts
index d76315e..5747991 100644
--- a/packages/typescript/src/symbols/ts-package-scope.ts
+++ b/packages/typescript/src/symbols/ts-package-scope.ts
@@ -1,8 +1,4 @@
 import { Binder, OutputScope, Refkey } from "@alloy-js/core";
-import {
-  ExportConditions,
-  PackageExports,
-} from "../components/PackageJson.jsx";
 import { modulePath } from "../utils.js";
 import { TSModuleScope } from "./ts-module-scope.js";
 
@@ -31,20 +27,6 @@ export interface TSPackageScope extends OutputScope {
    */
   dependencies: Set<TSPackageScope>;
 
-  /**
-   * Fixed dependencies of this package. Only use this for packages in which you
-   * do not intend to reference via the `Reference` component. Symbols from raw
-   * dependencies cannot be auto imported.
-   */
-  rawDependencies: Map<string, string>;
-
-  /**
-   * Fixed exports of this package. Only use this for exports which you want to
-   * add manually to the package. Otherwise use the `export` prop on
-   * `SourceFile` to add an export.
-   */
-  rawExports: PackageExports;
-
   /**
    * All of the modules contained within the package. These modules may or may not
    * be exported.
@@ -57,9 +39,7 @@ export interface TSPackageScope extends OutputScope {
   builtin?: boolean;
 
   addExport(publicPath: string, localModule: TSModuleScope): void;
-  addRawExport(publicPath: string, exportPath: string | ExportConditions): void;
   addDependency(pkg: TSPackageScope): void;
-  addRawDependency(packageName: string, version: string): void;
   addModule(module: TSModuleScope): void;
   findExportedSymbol(refkey: Refkey): [string, TSModuleScope] | null;
 }
@@ -78,8 +58,6 @@ export function createTSPackageScope(
     parent,
     exportedSymbols: new Map(),
     dependencies: new Set(),
-    rawDependencies: new Map(),
-    rawExports: {},
     modules: new Set(),
     version,
     path: path,
@@ -90,12 +68,6 @@ export function createTSPackageScope(
     addExport(publicPath, module) {
       this.exportedSymbols.set(modulePath(publicPath), module);
     },
-    addRawDependency(packageName, version) {
-      this.rawDependencies.set(packageName, version);
-    },
-    addRawExport(localPath, exportPath) {
-      this.rawExports[localPath] = exportPath;
-    },
     addModule(module) {
       this.modules.add(module);
     },
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 25b63de..bef42b8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -48,6 +48,9 @@ catalogs:
     '@types/node':
       specifier: ^20.14.12
       version: 20.14.15
+    '@vitest/eslint-plugin':
+      specifier: ^1.1.37
+      version: 1.1.37
     '@vue/reactivity':
       specifier: ^3.4.30
       version: 3.4.37
@@ -63,9 +66,6 @@ catalogs:
     eslint:
       specifier: ^9.9.0
       version: 9.9.0
-    eslint-plugin-vitest:
-      specifier: ^0.5.4
-      version: 0.5.4
     html-entities:
       specifier: 2.3.3
       version: 2.3.3
@@ -122,15 +122,18 @@ importers:
       '@chronus/github-pr-commenter':
         specifier: ^0.5.9
         version: 0.5.9
+      '@typescript-eslint/utils':
+        specifier: ^8.26.1
+        version: 8.26.1(eslint@9.9.0)(typescript@5.7.3)
+      '@vitest/eslint-plugin':
+        specifier: 'catalog:'
+        version: 1.1.37(@typescript-eslint/utils@8.26.1(eslint@9.9.0)(typescript@5.7.3))(eslint@9.9.0)(typescript@5.7.3)(vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0))
       concurrently:
         specifier: 'catalog:'
         version: 8.2.2
       eslint:
         specifier: 'catalog:'
         version: 9.9.0
-      eslint-plugin-vitest:
-        specifier: 'catalog:'
-        version: 0.5.4(eslint@9.9.0)(typescript@5.7.3)(vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0))
       prettier:
         specifier: 'catalog:'
         version: 3.3.3
@@ -148,7 +151,7 @@ importers:
         version: 8.1.0(eslint@9.9.0)(typescript@5.7.3)
       vitest:
         specifier: 'catalog:'
-        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   packages/babel-plugin-alloy:
     dependencies:
@@ -185,7 +188,7 @@ importers:
         version: 5.7.3
       vitest:
         specifier: 'catalog:'
-        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   packages/babel-plugin-jsx-dom-expressions:
     dependencies:
@@ -256,25 +259,74 @@ importers:
         version: 7.24.8(@babel/core@7.25.2)
       '@microsoft/api-extractor':
         specifier: ^7.47.7
-        version: 7.47.7(@types/node@22.2.0)
+        version: 7.47.7(@types/node@22.13.10)
+      '@rollup/plugin-babel':
+        specifier: 'catalog:'
+        version: 6.0.4(@babel/core@7.25.2)(@types/babel__core@7.20.5)(rollup@4.30.1)
+      '@rollup/plugin-typescript':
+        specifier: 'catalog:'
+        version: 11.1.6(rollup@4.30.1)(tslib@2.6.3)(typescript@5.7.3)
+      concurrently:
+        specifier: 'catalog:'
+        version: 8.2.2
+      typescript:
+        specifier: 'catalog:'
+        version: 5.7.3
+      vite:
+        specifier: 'catalog:'
+        version: 6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
+      vitest:
+        specifier: 'catalog:'
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
+
+  packages/create:
+    dependencies:
+      '@alloy-js/core':
+        specifier: workspace:~
+        version: link:../core
+      '@alloy-js/typescript':
+        specifier: workspace:~
+        version: link:../typescript
+    devDependencies:
+      '@alloy-js/babel-plugin':
+        specifier: workspace:~
+        version: link:../babel-plugin-alloy
+      '@babel/cli':
+        specifier: 'catalog:'
+        version: 7.24.8(@babel/core@7.25.2)
+      '@babel/preset-typescript':
+        specifier: 'catalog:'
+        version: 7.24.7(@babel/core@7.25.2)
       '@rollup/plugin-babel':
         specifier: 'catalog:'
         version: 6.0.4(@babel/core@7.25.2)(@types/babel__core@7.20.5)(rollup@4.30.1)
       '@rollup/plugin-typescript':
         specifier: 'catalog:'
         version: 11.1.6(rollup@4.30.1)(tslib@2.6.3)(typescript@5.7.3)
+      '@types/node':
+        specifier: 'catalog:'
+        version: 22.13.10
+      '@types/prompts':
+        specifier: ^2.4.9
+        version: 2.4.9
       concurrently:
         specifier: 'catalog:'
         version: 8.2.2
+      js-yaml:
+        specifier: ^4.1.0
+        version: 4.1.0
+      prompts:
+        specifier: ^2.4.2
+        version: 2.4.2
       typescript:
         specifier: 'catalog:'
         version: 5.7.3
       vite:
         specifier: 'catalog:'
-        version: 6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
       vitest:
         specifier: 'catalog:'
-        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   packages/csharp:
     dependencies:
@@ -299,7 +351,7 @@ importers:
         version: 7.24.7(@babel/core@7.25.2)
       '@microsoft/api-extractor':
         specifier: ^7.47.7
-        version: 7.47.7(@types/node@22.2.0)
+        version: 7.47.7(@types/node@22.13.10)
       '@rollup/plugin-babel':
         specifier: 'catalog:'
         version: 6.0.4(@babel/core@7.25.2)(@types/babel__core@7.20.5)(rollup@4.30.1)
@@ -314,7 +366,7 @@ importers:
         version: 5.7.3
       vitest:
         specifier: 'catalog:'
-        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   packages/docs:
     dependencies:
@@ -323,13 +375,13 @@ importers:
         version: 0.9.4(prettier@3.5.1)(typescript@5.5.4)
       '@astrojs/starlight':
         specifier: ^0.31.0
-        version: 0.31.0(astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))
+        version: 0.31.0(astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))
       astro:
         specifier: ^5.1.6
-        version: 5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
+        version: 5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
       astro-expressive-code:
         specifier: ^0.36.1
-        version: 0.36.1(astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))
+        version: 0.36.1(astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))
       sharp:
         specifier: ^0.32.5
         version: 0.32.6
@@ -351,10 +403,10 @@ importers:
         version: link:../typescript
       '@microsoft/api-extractor':
         specifier: ^7.47.7
-        version: 7.47.7(@types/node@22.2.0)
+        version: 7.47.7(@types/node@22.13.10)
       '@microsoft/api-extractor-model':
         specifier: ^7.29.6
-        version: 7.29.6(@types/node@22.2.0)
+        version: 7.29.6(@types/node@22.13.10)
       '@microsoft/tsdoc':
         specifier: ^0.15.0
         version: 0.15.0
@@ -385,7 +437,7 @@ importers:
         version: 7.24.7(@babel/core@7.25.2)
       '@microsoft/api-extractor':
         specifier: ^7.47.7
-        version: 7.47.7(@types/node@22.2.0)
+        version: 7.47.7(@types/node@22.13.10)
       '@rollup/plugin-babel':
         specifier: 'catalog:'
         version: 6.0.4(@babel/core@7.25.2)(@types/babel__core@7.20.5)(rollup@4.30.1)
@@ -400,7 +452,7 @@ importers:
         version: 5.7.3
       vitest:
         specifier: 'catalog:'
-        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   packages/json:
     dependencies:
@@ -422,7 +474,7 @@ importers:
         version: 7.24.7(@babel/core@7.25.2)
       '@microsoft/api-extractor':
         specifier: ^7.47.7
-        version: 7.47.7(@types/node@22.2.0)
+        version: 7.47.7(@types/node@22.13.10)
       '@rollup/plugin-babel':
         specifier: 'catalog:'
         version: 6.0.4(@babel/core@7.25.2)(@types/babel__core@7.20.5)(rollup@4.30.1)
@@ -437,7 +489,7 @@ importers:
         version: 5.7.3
       vitest:
         specifier: 'catalog:'
-        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   packages/prettier-plugin-alloy:
     devDependencies:
@@ -449,7 +501,7 @@ importers:
         version: 5.7.3
       vitest:
         specifier: 'catalog:'
-        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   packages/typescript:
     dependencies:
@@ -474,7 +526,7 @@ importers:
         version: 7.24.7(@babel/core@7.25.2)
       '@microsoft/api-extractor':
         specifier: ^7.47.7
-        version: 7.47.7(@types/node@22.2.0)
+        version: 7.47.7(@types/node@22.13.10)
       '@rollup/plugin-babel':
         specifier: 'catalog:'
         version: 6.0.4(@babel/core@7.25.2)(@types/babel__core@7.20.5)(rollup@4.30.1)
@@ -489,7 +541,7 @@ importers:
         version: 5.7.3
       vitest:
         specifier: 'catalog:'
-        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+        version: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   samples/basic-project:
     dependencies:
@@ -2105,8 +2157,11 @@ packages:
   '@types/node@20.14.15':
     resolution: {integrity: sha512-Fz1xDMCF/B00/tYSVMlmK7hVeLh7jE5f3B7X1/hmV0MJBwE27KlS7EvD/Yp+z1lm8mVhwV5w+n8jOZG8AfTlKw==}
 
-  '@types/node@22.2.0':
-    resolution: {integrity: sha512-bm6EG6/pCpkxDf/0gDNDdtDILMOHgaQBVOJGdwsqClnxA3xL6jtMv76rLBc006RVMWbmaf0xbmom4Z/5o2nRkQ==}
+  '@types/node@22.13.10':
+    resolution: {integrity: sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==}
+
+  '@types/prompts@2.4.9':
+    resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==}
 
   '@types/resolve@1.20.2':
     resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
@@ -2141,14 +2196,14 @@ packages:
       typescript:
         optional: true
 
-  '@typescript-eslint/scope-manager@7.18.0':
-    resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==}
-    engines: {node: ^18.18.0 || >=20.0.0}
-
   '@typescript-eslint/scope-manager@8.1.0':
     resolution: {integrity: sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
+  '@typescript-eslint/scope-manager@8.26.1':
+    resolution: {integrity: sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   '@typescript-eslint/type-utils@8.1.0':
     resolution: {integrity: sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -2158,22 +2213,13 @@ packages:
       typescript:
         optional: true
 
-  '@typescript-eslint/types@7.18.0':
-    resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==}
-    engines: {node: ^18.18.0 || >=20.0.0}
-
   '@typescript-eslint/types@8.1.0':
     resolution: {integrity: sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
-  '@typescript-eslint/typescript-estree@7.18.0':
-    resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==}
-    engines: {node: ^18.18.0 || >=20.0.0}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
+  '@typescript-eslint/types@8.26.1':
+    resolution: {integrity: sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
   '@typescript-eslint/typescript-estree@8.1.0':
     resolution: {integrity: sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==}
@@ -2184,11 +2230,11 @@ packages:
       typescript:
         optional: true
 
-  '@typescript-eslint/utils@7.18.0':
-    resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==}
-    engines: {node: ^18.18.0 || >=20.0.0}
+  '@typescript-eslint/typescript-estree@8.26.1':
+    resolution: {integrity: sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
     peerDependencies:
-      eslint: ^8.56.0
+      typescript: '>=4.8.4 <5.9.0'
 
   '@typescript-eslint/utils@8.1.0':
     resolution: {integrity: sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==}
@@ -2196,17 +2242,37 @@ packages:
     peerDependencies:
       eslint: ^8.57.0 || ^9.0.0
 
-  '@typescript-eslint/visitor-keys@7.18.0':
-    resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==}
-    engines: {node: ^18.18.0 || >=20.0.0}
+  '@typescript-eslint/utils@8.26.1':
+    resolution: {integrity: sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+    peerDependencies:
+      eslint: ^8.57.0 || ^9.0.0
+      typescript: '>=4.8.4 <5.9.0'
 
   '@typescript-eslint/visitor-keys@8.1.0':
     resolution: {integrity: sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
+  '@typescript-eslint/visitor-keys@8.26.1':
+    resolution: {integrity: sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   '@ungap/structured-clone@1.2.0':
     resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
 
+  '@vitest/eslint-plugin@1.1.37':
+    resolution: {integrity: sha512-cnlBV8zr0oaBu1Vk6ruqWzpPzFCtwY0yuwUQpNIeFOUl3UhXVwNUoOYfWkZzeToGuNBaXvIsr6/RgHrXiHXqXA==}
+    peerDependencies:
+      '@typescript-eslint/utils': ^8.24.0
+      eslint: '>= 8.57.0'
+      typescript: '>= 5.0.0'
+      vitest: '*'
+    peerDependenciesMeta:
+      typescript:
+        optional: true
+      vitest:
+        optional: true
+
   '@vitest/expect@3.0.4':
     resolution: {integrity: sha512-Nm5kJmYw6P2BxhJPkO3eKKhGYKRsnqJqf+r0yOGRKpEP+bSCBDsjXgiu1/5QFrnPMEgzfC38ZEjvCFgaNBC0Eg==}
 
@@ -2827,19 +2893,6 @@ packages:
     resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
     engines: {node: '>=12'}
 
-  eslint-plugin-vitest@0.5.4:
-    resolution: {integrity: sha512-um+odCkccAHU53WdKAw39MY61+1x990uXjSPguUCq3VcEHdqJrOb8OTMrbYlY6f9jAKx7x98kLVlIe3RJeJqoQ==}
-    engines: {node: ^18.0.0 || >= 20.0.0}
-    peerDependencies:
-      '@typescript-eslint/eslint-plugin': '*'
-      eslint: ^8.57.0 || ^9.0.0
-      vitest: '*'
-    peerDependenciesMeta:
-      '@typescript-eslint/eslint-plugin':
-        optional: true
-      vitest:
-        optional: true
-
   eslint-scope@8.0.2:
     resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -2852,6 +2905,10 @@ packages:
     resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
 
+  eslint-visitor-keys@4.2.0:
+    resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==}
+    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
+
   eslint@9.9.0:
     resolution: {integrity: sha512-JfiKJrbx0506OEerjK2Y1QlldtBxkAlLxT5OEcRF8uaQ86noDe2k31Vw9rnSWv+MXZHj7OOUV/dA0AhdLFcyvA==}
     engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
@@ -4570,6 +4627,12 @@ packages:
     peerDependencies:
       typescript: '>=4.2.0'
 
+  ts-api-utils@2.0.1:
+    resolution: {integrity: sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==}
+    engines: {node: '>=18.12'}
+    peerDependencies:
+      typescript: '>=4.8.4'
+
   tsconfck@3.1.4:
     resolution: {integrity: sha512-kdqWFGVJqe+KGYvlSO9NIaWn9jT1Ny4oKVzAJsKii5eoE9snzTJzL4+MMVOMn+fikWGFmKEylcXL710V/kIPJQ==}
     engines: {node: ^18 || >=20}
@@ -4649,8 +4712,8 @@ packages:
   undici-types@5.26.5:
     resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
 
-  undici-types@6.13.0:
-    resolution: {integrity: sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==}
+  undici-types@6.20.0:
+    resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
 
   undici@5.28.4:
     resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==}
@@ -5208,12 +5271,12 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@astrojs/mdx@4.0.5(astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))':
+  '@astrojs/mdx@4.0.5(astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))':
     dependencies:
       '@astrojs/markdown-remark': 6.0.1
       '@mdx-js/mdx': 3.1.0(acorn@8.14.0)
       acorn: 8.14.0
-      astro: 5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
+      astro: 5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
       es-module-lexer: 1.5.4
       estree-util-visit: 2.0.0
       hast-util-to-html: 9.0.4
@@ -5237,16 +5300,16 @@ snapshots:
       stream-replace-string: 2.0.0
       zod: 3.23.8
 
-  '@astrojs/starlight@0.31.0(astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))':
+  '@astrojs/starlight@0.31.0(astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))':
     dependencies:
-      '@astrojs/mdx': 4.0.5(astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))
+      '@astrojs/mdx': 4.0.5(astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))
       '@astrojs/sitemap': 3.2.1
       '@pagefind/default-ui': 1.3.0
       '@types/hast': 3.0.4
       '@types/js-yaml': 4.0.9
       '@types/mdast': 4.0.4
-      astro: 5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
-      astro-expressive-code: 0.40.0(astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))
+      astro: 5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
+      astro-expressive-code: 0.40.0(astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0))
       bcp-47: 2.1.0
       hast-util-from-html: 2.0.2
       hast-util-select: 6.0.2
@@ -6025,23 +6088,23 @@ snapshots:
       - acorn
       - supports-color
 
-  '@microsoft/api-extractor-model@7.29.6(@types/node@22.2.0)':
+  '@microsoft/api-extractor-model@7.29.6(@types/node@22.13.10)':
     dependencies:
       '@microsoft/tsdoc': 0.15.0
       '@microsoft/tsdoc-config': 0.17.0
-      '@rushstack/node-core-library': 5.7.0(@types/node@22.2.0)
+      '@rushstack/node-core-library': 5.7.0(@types/node@22.13.10)
     transitivePeerDependencies:
       - '@types/node'
 
-  '@microsoft/api-extractor@7.47.7(@types/node@22.2.0)':
+  '@microsoft/api-extractor@7.47.7(@types/node@22.13.10)':
     dependencies:
-      '@microsoft/api-extractor-model': 7.29.6(@types/node@22.2.0)
+      '@microsoft/api-extractor-model': 7.29.6(@types/node@22.13.10)
       '@microsoft/tsdoc': 0.15.0
       '@microsoft/tsdoc-config': 0.17.0
-      '@rushstack/node-core-library': 5.7.0(@types/node@22.2.0)
+      '@rushstack/node-core-library': 5.7.0(@types/node@22.13.10)
       '@rushstack/rig-package': 0.5.3
-      '@rushstack/terminal': 0.14.0(@types/node@22.2.0)
-      '@rushstack/ts-command-line': 4.22.6(@types/node@22.2.0)
+      '@rushstack/terminal': 0.14.0(@types/node@22.13.10)
+      '@rushstack/ts-command-line': 4.22.6(@types/node@22.13.10)
       lodash: 4.17.21
       minimatch: 3.0.8
       resolve: 1.22.8
@@ -6524,7 +6587,7 @@ snapshots:
   '@rollup/rollup-win32-x64-msvc@4.30.1':
     optional: true
 
-  '@rushstack/node-core-library@5.7.0(@types/node@22.2.0)':
+  '@rushstack/node-core-library@5.7.0(@types/node@22.13.10)':
     dependencies:
       ajv: 8.13.0
       ajv-draft-04: 1.0.0(ajv@8.13.0)
@@ -6535,23 +6598,23 @@ snapshots:
       resolve: 1.22.8
       semver: 7.5.4
     optionalDependencies:
-      '@types/node': 22.2.0
+      '@types/node': 22.13.10
 
   '@rushstack/rig-package@0.5.3':
     dependencies:
       resolve: 1.22.8
       strip-json-comments: 3.1.1
 
-  '@rushstack/terminal@0.14.0(@types/node@22.2.0)':
+  '@rushstack/terminal@0.14.0(@types/node@22.13.10)':
     dependencies:
-      '@rushstack/node-core-library': 5.7.0(@types/node@22.2.0)
+      '@rushstack/node-core-library': 5.7.0(@types/node@22.13.10)
       supports-color: 8.1.1
     optionalDependencies:
-      '@types/node': 22.2.0
+      '@types/node': 22.13.10
 
-  '@rushstack/ts-command-line@4.22.6(@types/node@22.2.0)':
+  '@rushstack/ts-command-line@4.22.6(@types/node@22.13.10)':
     dependencies:
-      '@rushstack/terminal': 0.14.0(@types/node@22.2.0)
+      '@rushstack/terminal': 0.14.0(@types/node@22.13.10)
       '@types/argparse': 1.0.38
       argparse: 1.0.10
       string-argv: 0.3.2
@@ -6708,15 +6771,20 @@ snapshots:
     dependencies:
       undici-types: 5.26.5
 
-  '@types/node@22.2.0':
+  '@types/node@22.13.10':
     dependencies:
-      undici-types: 6.13.0
+      undici-types: 6.20.0
+
+  '@types/prompts@2.4.9':
+    dependencies:
+      '@types/node': 22.13.10
+      kleur: 3.0.3
 
   '@types/resolve@1.20.2': {}
 
   '@types/sax@1.2.7':
     dependencies:
-      '@types/node': 22.2.0
+      '@types/node': 22.13.10
 
   '@types/unist@2.0.11': {}
 
@@ -6753,16 +6821,16 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/scope-manager@7.18.0':
-    dependencies:
-      '@typescript-eslint/types': 7.18.0
-      '@typescript-eslint/visitor-keys': 7.18.0
-
   '@typescript-eslint/scope-manager@8.1.0':
     dependencies:
       '@typescript-eslint/types': 8.1.0
       '@typescript-eslint/visitor-keys': 8.1.0
 
+  '@typescript-eslint/scope-manager@8.26.1':
+    dependencies:
+      '@typescript-eslint/types': 8.26.1
+      '@typescript-eslint/visitor-keys': 8.26.1
+
   '@typescript-eslint/type-utils@8.1.0(eslint@9.9.0)(typescript@5.7.3)':
     dependencies:
       '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.7.3)
@@ -6775,24 +6843,9 @@ snapshots:
       - eslint
       - supports-color
 
-  '@typescript-eslint/types@7.18.0': {}
-
   '@typescript-eslint/types@8.1.0': {}
 
-  '@typescript-eslint/typescript-estree@7.18.0(typescript@5.7.3)':
-    dependencies:
-      '@typescript-eslint/types': 7.18.0
-      '@typescript-eslint/visitor-keys': 7.18.0
-      debug: 4.3.6
-      globby: 11.1.0
-      is-glob: 4.0.3
-      minimatch: 9.0.5
-      semver: 7.6.3
-      ts-api-utils: 1.3.0(typescript@5.7.3)
-    optionalDependencies:
-      typescript: 5.7.3
-    transitivePeerDependencies:
-      - supports-color
+  '@typescript-eslint/types@8.26.1': {}
 
   '@typescript-eslint/typescript-estree@8.1.0(typescript@5.7.3)':
     dependencies:
@@ -6809,16 +6862,19 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/utils@7.18.0(eslint@9.9.0)(typescript@5.7.3)':
+  '@typescript-eslint/typescript-estree@8.26.1(typescript@5.7.3)':
     dependencies:
-      '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0)
-      '@typescript-eslint/scope-manager': 7.18.0
-      '@typescript-eslint/types': 7.18.0
-      '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.7.3)
-      eslint: 9.9.0
+      '@typescript-eslint/types': 8.26.1
+      '@typescript-eslint/visitor-keys': 8.26.1
+      debug: 4.4.0
+      fast-glob: 3.3.3
+      is-glob: 4.0.3
+      minimatch: 9.0.5
+      semver: 7.6.3
+      ts-api-utils: 2.0.1(typescript@5.7.3)
+      typescript: 5.7.3
     transitivePeerDependencies:
       - supports-color
-      - typescript
 
   '@typescript-eslint/utils@8.1.0(eslint@9.9.0)(typescript@5.7.3)':
     dependencies:
@@ -6831,18 +6887,37 @@ snapshots:
       - supports-color
       - typescript
 
-  '@typescript-eslint/visitor-keys@7.18.0':
+  '@typescript-eslint/utils@8.26.1(eslint@9.9.0)(typescript@5.7.3)':
     dependencies:
-      '@typescript-eslint/types': 7.18.0
-      eslint-visitor-keys: 3.4.3
+      '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0)
+      '@typescript-eslint/scope-manager': 8.26.1
+      '@typescript-eslint/types': 8.26.1
+      '@typescript-eslint/typescript-estree': 8.26.1(typescript@5.7.3)
+      eslint: 9.9.0
+      typescript: 5.7.3
+    transitivePeerDependencies:
+      - supports-color
 
   '@typescript-eslint/visitor-keys@8.1.0':
     dependencies:
       '@typescript-eslint/types': 8.1.0
       eslint-visitor-keys: 3.4.3
 
+  '@typescript-eslint/visitor-keys@8.26.1':
+    dependencies:
+      '@typescript-eslint/types': 8.26.1
+      eslint-visitor-keys: 4.2.0
+
   '@ungap/structured-clone@1.2.0': {}
 
+  '@vitest/eslint-plugin@1.1.37(@typescript-eslint/utils@8.26.1(eslint@9.9.0)(typescript@5.7.3))(eslint@9.9.0)(typescript@5.7.3)(vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0))':
+    dependencies:
+      '@typescript-eslint/utils': 8.26.1(eslint@9.9.0)(typescript@5.7.3)
+      eslint: 9.9.0
+    optionalDependencies:
+      typescript: 5.7.3
+      vitest: 3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
+
   '@vitest/expect@3.0.4':
     dependencies:
       '@vitest/spy': 3.0.4
@@ -6858,13 +6933,13 @@ snapshots:
     optionalDependencies:
       vite: 6.0.7(@types/node@20.14.15)(tsx@4.19.1)(yaml@2.7.0)
 
-  '@vitest/mocker@3.0.4(vite@6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0))':
+  '@vitest/mocker@3.0.4(vite@6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0))':
     dependencies:
       '@vitest/spy': 3.0.4
       estree-walker: 3.0.3
       magic-string: 0.30.17
     optionalDependencies:
-      vite: 6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+      vite: 6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   '@vitest/pretty-format@3.0.4':
     dependencies:
@@ -7044,17 +7119,17 @@ snapshots:
 
   astring@1.9.0: {}
 
-  astro-expressive-code@0.36.1(astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)):
+  astro-expressive-code@0.36.1(astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)):
     dependencies:
-      astro: 5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
+      astro: 5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
       rehype-expressive-code: 0.36.1
 
-  astro-expressive-code@0.40.0(astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)):
+  astro-expressive-code@0.40.0(astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)):
     dependencies:
-      astro: 5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
+      astro: 5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0)
       rehype-expressive-code: 0.40.0
 
-  astro@5.1.6(@types/node@22.2.0)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0):
+  astro@5.1.6(@types/node@22.13.10)(rollup@4.30.1)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.7.0):
     dependencies:
       '@astrojs/compiler': 2.10.3
       '@astrojs/internal-helpers': 0.4.2
@@ -7106,8 +7181,8 @@ snapshots:
       unist-util-visit: 5.0.0
       unstorage: 1.14.4
       vfile: 6.0.3
-      vite: 6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
-      vitefu: 1.0.5(vite@6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0))
+      vite: 6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
+      vitefu: 1.0.5(vite@6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0))
       which-pm: 3.0.0
       xxhash-wasm: 1.1.0
       yargs-parser: 21.1.1
@@ -7633,16 +7708,6 @@ snapshots:
 
   escape-string-regexp@5.0.0: {}
 
-  eslint-plugin-vitest@0.5.4(eslint@9.9.0)(typescript@5.7.3)(vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)):
-    dependencies:
-      '@typescript-eslint/utils': 7.18.0(eslint@9.9.0)(typescript@5.7.3)
-      eslint: 9.9.0
-    optionalDependencies:
-      vitest: 3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-
   eslint-scope@8.0.2:
     dependencies:
       esrecurse: 4.3.0
@@ -7652,6 +7717,8 @@ snapshots:
 
   eslint-visitor-keys@4.0.0: {}
 
+  eslint-visitor-keys@4.2.0: {}
+
   eslint@9.9.0:
     dependencies:
       '@eslint-community/eslint-utils': 4.4.0(eslint@9.9.0)
@@ -10003,6 +10070,10 @@ snapshots:
     dependencies:
       typescript: 5.7.3
 
+  ts-api-utils@2.0.1(typescript@5.7.3):
+    dependencies:
+      typescript: 5.7.3
+
   tsconfck@3.1.4(typescript@5.5.4):
     optionalDependencies:
       typescript: 5.5.4
@@ -10067,7 +10138,7 @@ snapshots:
 
   undici-types@5.26.5: {}
 
-  undici-types@6.13.0: {}
+  undici-types@6.20.0: {}
 
   undici@5.28.4:
     dependencies:
@@ -10223,13 +10294,13 @@ snapshots:
       - tsx
       - yaml
 
-  vite-node@3.0.4(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0):
+  vite-node@3.0.4(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0):
     dependencies:
       cac: 6.7.14
       debug: 4.4.0
       es-module-lexer: 1.6.0
       pathe: 2.0.2
-      vite: 6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+      vite: 6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
     transitivePeerDependencies:
       - '@types/node'
       - jiti
@@ -10255,20 +10326,20 @@ snapshots:
       tsx: 4.19.1
       yaml: 2.7.0
 
-  vite@6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0):
+  vite@6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0):
     dependencies:
       esbuild: 0.24.2
       postcss: 8.5.1
       rollup: 4.30.1
     optionalDependencies:
-      '@types/node': 22.2.0
+      '@types/node': 22.13.10
       fsevents: 2.3.3
       tsx: 4.19.1
       yaml: 2.7.0
 
-  vitefu@1.0.5(vite@6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)):
+  vitefu@1.0.5(vite@6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)):
     optionalDependencies:
-      vite: 6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+      vite: 6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
 
   vitest@3.0.4(@types/debug@4.1.12)(@types/node@20.14.15)(tsx@4.19.1)(yaml@2.7.0):
     dependencies:
@@ -10309,10 +10380,10 @@ snapshots:
       - tsx
       - yaml
 
-  vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0):
+  vitest@3.0.4(@types/debug@4.1.12)(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0):
     dependencies:
       '@vitest/expect': 3.0.4
-      '@vitest/mocker': 3.0.4(vite@6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0))
+      '@vitest/mocker': 3.0.4(vite@6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0))
       '@vitest/pretty-format': 3.0.4
       '@vitest/runner': 3.0.4
       '@vitest/snapshot': 3.0.4
@@ -10328,12 +10399,12 @@ snapshots:
       tinyexec: 0.3.2
       tinypool: 1.0.2
       tinyrainbow: 2.0.0
-      vite: 6.0.7(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
-      vite-node: 3.0.4(@types/node@22.2.0)(tsx@4.19.1)(yaml@2.7.0)
+      vite: 6.0.7(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
+      vite-node: 3.0.4(@types/node@22.13.10)(tsx@4.19.1)(yaml@2.7.0)
       why-is-node-running: 2.3.0
     optionalDependencies:
       '@types/debug': 4.1.12
-      '@types/node': 22.2.0
+      '@types/node': 22.13.10
     transitivePeerDependencies:
       - jiti
       - less


Test patch:
diff --git a/packages/typescript/test/package-external.test.tsx b/packages/typescript/test/package-external.test.tsx
index 5a14567..fd3964f 100644
--- a/packages/typescript/test/package-external.test.tsx
+++ b/packages/typescript/test/package-external.test.tsx
@@ -69,7 +69,95 @@ it("imports external packages", () => {
       "name": "greeting-lib",
       "version": "1.0.0",
       "type": "module",
-      "dependencies": {},
+      "devDependencies": {
+        "typescript": "^5.5.2"
+      },
+      "exports": {
+        ".": "./dist/index.js"
+      }
+    }
+  `);
+
+  expect(refFile.contents).toEqual(d`
+    import { getGreeting } from "greeting-lib";
+    
+    getGreeting();
+  `);
+});
+
+it("combines explicit dependencies with referenced dependencies", () => {
+  const res = render(
+    <Output>
+      <ts.PackageDirectory
+        name="greeting-lib"
+        path="greeting-lib"
+        version="1.0.0"
+      >
+        <ts.SourceFile path="greetings.ts">
+          <ts.FunctionDeclaration
+            name="getGreeting"
+            refkey={refkey("getGreeting")}
+          >
+            return "Hello world!";
+          </ts.FunctionDeclaration>
+        </ts.SourceFile>
+
+        <ts.SourceFile path="logGreetings.ts">
+          <ts.FunctionDeclaration
+            export
+            name="printGreeting"
+            refkey={refkey("printGreeting")}
+          >
+            console.log("Hello world!");
+          </ts.FunctionDeclaration>
+        </ts.SourceFile>
+
+        <ts.BarrelFile export="." />
+      </ts.PackageDirectory>
+
+      <ts.PackageDirectory
+        name="consumer"
+        path="consumer"
+        version="1.0.0"
+        dependencies={{
+          foo: "bar",
+        }}
+      >
+        <ts.SourceFile export="." path="ref.ts">
+          <ts.Reference refkey={refkey("getGreeting")} />
+          ();
+        </ts.SourceFile>
+      </ts.PackageDirectory>
+    </Output>,
+  );
+
+  const consumerPkgJson = findFile(res, "consumer/package.json")!;
+  const greetingPkgJson = findFile(res, "greeting-lib/package.json")!;
+  const refFile = findFile(res, "consumer/ref.ts")!;
+
+  expect(consumerPkgJson.contents).toEqual(d`
+    {
+      "name": "consumer",
+      "version": "1.0.0",
+      "type": "module",
+      "dependencies": {
+        "foo": "bar",
+        "greeting-lib": "1.0.0"
+      },
+      "devDependencies": {
+        "typescript": "^5.5.2"
+      },
+      "exports": {
+        ".": "./dist/ref.js"
+      }
+    }
+  `);
+
+  expect(greetingPkgJson.contents).toEqual(d`
+    {
+      "name": "greeting-lib",
+      "version": "1.0.0",
+      "type": "module",
       "devDependencies": {
         "typescript": "^5.5.2"
       },
diff --git a/packages/typescript/test/package.test.tsx b/packages/typescript/test/package.test.tsx
index 8ec1169..ac43d61 100644
--- a/packages/typescript/test/package.test.tsx
+++ b/packages/typescript/test/package.test.tsx
@@ -60,7 +60,6 @@ it("exports source files", () => {
         "name": "greeting-js",
         "version": "1.0.0",
         "type": "module",
-        "dependencies": {},
         "devDependencies": {
           "typescript": "^5.5.2"
         },
@@ -72,3 +71,50 @@ it("exports source files", () => {
     `,
   });
 });
+
+it("combines ref'd exports with explicit exports", () => {
+  const res = render(
+    <Output>
+      <PackageDirectory
+        name="greeting-js"
+        path="."
+        version="1.0.0"
+        exports={{
+          "./foo": "./foo/test.js",
+        }}
+      >
+        <ts.SourceFile export="." path="index.ts">
+          <ts.FunctionDeclaration
+            export
+            name="printGreeting"
+            refkey={refkey("printGreeting")}
+          >
+            console.log(greeting);
+          </ts.FunctionDeclaration>
+        </ts.SourceFile>
+      </PackageDirectory>
+    </Output>,
+  );
+
+  assertFileContents(res, {
+    "index.ts": `
+      export function printGreeting() {
+        console.log(greeting);
+      }
+    `,
+    "package.json": `
+      {
+        "name": "greeting-js",
+        "version": "1.0.0",
+        "type": "module",
+        "devDependencies": {
+          "typescript": "^5.5.2"
+        },
+        "exports": {
+          "./foo": "./foo/test.js",
+          ".": "./dist/index.js"
+        }
+      }
+    `,
+  });
+});