From 2ea741a4d4a3123b2eaafb87b73d7884c69ae23b Mon Sep 17 00:00:00 2001
From: Stainless Bot <107565488+stainless-bot@users.noreply.github.com>
Date: Tue, 1 Aug 2023 01:43:22 +0100
Subject: [PATCH] refactor: create build for deno.land (#93)

---
 .gitignore                   |   1 +
 .prettierignore              |   1 +
 build                        |  49 +++++----
 package.json                 |   1 +
 scripts/denoify.ts           | 190 +++++++++++++++++++++++++++++++++++
 src/_shims/fetch.deno.ts     |  23 +++++
 src/_shims/formdata.deno.ts  |  16 +++
 src/core.ts                  |   4 +-
 src/resources/completions.ts |   2 +-
 src/resources/index.ts       |   1 +
 src/uploads.ts               |  13 +--
 tsconfig.build.json          |   2 +-
 tsconfig.deno.json           |  21 ++++
 tsconfig.json                |   1 +
 yarn.lock                    |  47 +++++++++
 15 files changed, 342 insertions(+), 30 deletions(-)
 create mode 100644 scripts/denoify.ts
 create mode 100644 src/_shims/fetch.deno.ts
 create mode 100644 src/_shims/formdata.deno.ts
 create mode 100644 tsconfig.deno.json

diff --git a/.gitignore b/.gitignore
index def8d373..314b2462 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@ node_modules
 yarn-error.log
 codegen.log
 dist
+/deno
 /*.tgz
diff --git a/.prettierignore b/.prettierignore
index 18975ca7..804a75c6 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,3 +1,4 @@
 CHANGELOG.md
 /ecosystem-tests
 /node_modules
+/deno
diff --git a/build b/build
index d2a22f7a..5b999f3b 100755
--- a/build
+++ b/build
@@ -3,20 +3,12 @@ set -exuo pipefail
 
 node scripts/check-version.cjs
 
-RUNNER="yarn"
-if ! command -v yarn &> /dev/null; then
-  RUNNER="npx"
-fi
-
-$RUNNER tsc
-
 # Build into dist and will publish the package from there,
 # so that src/resources/foo.ts becomes <package root>/resources/foo.js
 # This way importing from `"@anthropic-ai/sdk/resources/foo"` works
 # even with `"moduleResolution": "node"`
 
-rm -rf dist
-mkdir dist
+rm -rf dist; mkdir dist
 # Copy src to dist/src and build from dist/src into dist, so that
 # the source map for index.js.map will refer to ./src/index.ts etc
 cp -rp src README.md dist
@@ -28,10 +20,10 @@ done
 node scripts/make-dist-package-json.cjs > dist/package.json
 
 # build to .js/.mjs/.d.ts files
-$RUNNER tsc-multi
+npm exec tsc-multi
 # copy over handwritten .js/.mjs/.d.ts files
 cp src/_shims/*.{d.ts,js,mjs} dist/_shims
-$RUNNER tsc-alias -p tsconfig.build.json
+npm exec tsc-alias -- -p tsconfig.build.json
 # we need to add exports = module.exports = Anthropic TypeScript to index.js;
 # No way to get that from index.ts because it would cause compile errors
 # when building .mjs
@@ -42,19 +34,36 @@ node scripts/fix-index-exports.cjs
 # the same export default statement)
 cp dist/index.d.ts dist/index.d.mts
 
+SED=(sed -i)
+if [[ "$OSTYPE" == "darwin"* ]]; then SED=(sed -i ''); fi
+
 # strip out lib="dom" and types="node" references; these are needed at build time,
 # but would pollute the user's TS environment
 REFERENCE_SUBS='s/^ *\/\/\/ *<reference *lib="dom".*//g;s/^ *\/\/\/ *<reference *types="node".*//g'
-if [[ "$OSTYPE" == "darwin"* ]]; then
-  find dist -type f -exec sed -i '' "${REFERENCE_SUBS}" {} +
-else
-  find dist -type f -exec sed -i "${REFERENCE_SUBS}" {} +
-fi
+find dist -type f -exec "${SED[@]}" "${REFERENCE_SUBS}" {} +
 
-$RUNNER prettier --loglevel=warn --write .
+npm exec prettier -- --loglevel=warn --write .
 
 # make sure that nothing crashes when we require the output CJS or
 # import the output ESM
-cd dist
-node -e 'require("@anthropic-ai/sdk")'
-node -e 'import("@anthropic-ai/sdk")' --input-type=module
+(cd dist && node -e 'require("@anthropic-ai/sdk")')
+(cd dist && node -e 'import("@anthropic-ai/sdk")' --input-type=module)
+
+if command -v deno &> /dev/null
+then
+  rm -rf deno; mkdir deno
+  cp -rp src/* README.md deno
+  rm deno/_shims/*.{d.ts,js,mjs,node.ts}
+  for file in deno/_shims/*.deno.ts; do
+    mv -- "$file" "${file%.deno.ts}.ts"
+  done
+  for file in LICENSE CHANGELOG.md; do
+    if [ -e "${file}" ]; then cp "${file}" deno; fi
+  done
+  npm exec ts-node -- scripts/denoify.ts
+  deno fmt deno
+  
+
+  # make sure that nothing crashes when we load the Deno module
+  (cd deno && deno run index.ts)
+fi
diff --git a/package.json b/package.json
index e71a533a..12ceb2c7 100644
--- a/package.json
+++ b/package.json
@@ -91,6 +91,7 @@
     "jest": "^29.4.0",
     "prettier": "rattrayalex/prettier#postfix-ternaries",
     "ts-jest": "^29.1.0",
+    "ts-morph": "^19.0.0",
     "ts-node": "^10.5.0",
     "tsc-alias": "^1.8.6",
     "tsc-multi": "^1.1.0",
diff --git a/scripts/denoify.ts b/scripts/denoify.ts
new file mode 100644
index 00000000..47e36c94
--- /dev/null
+++ b/scripts/denoify.ts
@@ -0,0 +1,190 @@
+import path from 'path';
+import * as tm from 'ts-morph';
+import { name as pkgName } from '../package.json';
+
+const rootDir = path.resolve(__dirname, '..');
+const denoDir = path.join(rootDir, 'deno');
+const tsConfigFilePath = path.join(rootDir, 'tsconfig.deno.json');
+
+function denoify() {
+  const project = new tm.Project({ tsConfigFilePath });
+
+  for (const file of project.getSourceFiles()) {
+    if (!file.getFilePath().startsWith(denoDir + '/')) continue;
+    for (const decl of [...file.getImportDeclarations(), ...file.getExportDeclarations()]) {
+      const moduleSpecifier = decl.getModuleSpecifier();
+      if (!moduleSpecifier) continue;
+      let specifier = moduleSpecifier.getLiteralValue().replace(/^node:/, '');
+      if (!specifier) continue;
+
+      if (nodeStdModules.has(specifier)) {
+        // convert node builtins to deno.land/std
+        specifier = `https://deno.land/std@0.177.0/node/${specifier}.ts`;
+      } else if (specifier.startsWith(pkgName + '/')) {
+        // convert self-referencing module specifiers to relative paths
+        specifier = file.getRelativePathAsModuleSpecifierTo(denoDir + specifier.substring(pkgName.length));
+      } else if (!decl.isModuleSpecifierRelative()) {
+        continue;
+      }
+
+      if (decl.isModuleSpecifierRelative()) {
+        // there may be CJS directory module specifiers that implicitly resolve
+        // to /index.ts.  Add an explicit /index.ts to the end
+        const sourceFile = decl.getModuleSpecifierSourceFile();
+        if (
+          sourceFile &&
+          /index\.[cm]?[jt]sx?$/.test(sourceFile.getFilePath()) &&
+          !/index(\.[cm]?[jt]sx?)?$/.test(specifier)
+        ) {
+          specifier += '/' + path.basename(sourceFile.getFilePath());
+        }
+      }
+      // add explicit .ts file extensions to relative module specifiers
+      specifier = specifier.replace(/(\.[^./]*)?$/, '.ts');
+      moduleSpecifier.replaceWithText(JSON.stringify(specifier));
+    }
+
+    let addedBuffer = false,
+      addedProcess = false;
+    file.forEachDescendant((node) => {
+      switch (node.getKind()) {
+        case tm.ts.SyntaxKind.ExportDeclaration: {
+          const decl: tm.ExportDeclaration = node as any;
+          if (decl.isTypeOnly()) return;
+          for (const named of decl.getNamedExports()) {
+            // Convert `export { Foo } from './foo.ts'`
+            // to `export { type Foo } from './foo.ts'`
+            // if `./foo.ts` only exports types for `Foo`
+            if (!named.isTypeOnly() && !hasValueDeclarations(named)) {
+              named.replaceWithText(`type ${named.getText()}`);
+            }
+          }
+          break;
+        }
+        case tm.ts.SyntaxKind.ImportEqualsDeclaration: {
+          const decl: tm.ImportEqualsDeclaration = node as any;
+          if (decl.isTypeOnly()) return;
+
+          const ref = decl.getModuleReference();
+          if (ref.getText().includes('SinglePageResponse')) {
+            debugger;
+          }
+          if (!hasValueDeclarations(ref)) {
+            const params = ref.getType().getTypeArguments();
+            if (params.length) {
+              const paramsStr = params.map((p: tm.TypeParameter) => p.getText()).join(', ');
+              const bindingsStr = params
+                .map((p: tm.TypeParameter) => p.getSymbol()?.getName() || p.getText())
+                .join(', ');
+              decl.replaceWithText(
+                `export type ${decl.getName()}<${paramsStr}> = ${ref.getText()}<${bindingsStr}>`,
+              );
+            } else {
+              decl.replaceWithText(`export type ${decl.getName()} = ${ref.getText()}`);
+            }
+          }
+          break;
+        }
+        case tm.ts.SyntaxKind.Identifier: {
+          const id = node as tm.Identifier;
+          if (!addedBuffer && id.getText() === 'Buffer') {
+            addedBuffer = true;
+            file?.addVariableStatement({
+              declarations: [
+                {
+                  name: 'Buffer',
+                  type: 'any',
+                },
+              ],
+              hasDeclareKeyword: true,
+            });
+            file?.addTypeAlias({
+              name: 'Buffer',
+              type: 'any',
+            });
+          }
+          if (!addedProcess && id.getText() === 'process') {
+            addedProcess = true;
+            file?.addVariableStatement({
+              declarations: [
+                {
+                  name: 'process',
+                  type: 'any',
+                },
+              ],
+              hasDeclareKeyword: true,
+            });
+          }
+        }
+      }
+    });
+  }
+
+  project.save();
+}
+
+const nodeStdModules = new Set([
+  'assert',
+  'assertion_error',
+  'async_hooks',
+  'buffer',
+  'child_process',
+  'cluster',
+  'console',
+  'constants',
+  'crypto',
+  'dgram',
+  'diagnostics_channel',
+  'dns',
+  'domain',
+  'events',
+  'fs',
+  'global',
+  'http',
+  'http2',
+  'https',
+  'inspector',
+  'module_all',
+  'module_esm',
+  'module',
+  'net',
+  'os',
+  'path',
+  'perf_hooks',
+  'process',
+  'punycode',
+  'querystring',
+  'readline',
+  'repl',
+  'stream',
+  'string_decoder',
+  'sys',
+  'timers',
+  'tls',
+  'tty',
+  'upstream_modules',
+  'url',
+  'util',
+  'v8',
+  'vm',
+  'wasi',
+  'worker_threads',
+  'zlib',
+]);
+
+const typeDeclarationKinds = new Set([
+  tm.ts.SyntaxKind.InterfaceDeclaration,
+  tm.ts.SyntaxKind.ModuleDeclaration,
+  tm.ts.SyntaxKind.TypeAliasDeclaration,
+]);
+
+function hasValueDeclarations(nodes?: tm.Node): boolean;
+function hasValueDeclarations(nodes?: tm.Node[]): boolean;
+function hasValueDeclarations(nodes?: tm.Node | tm.Node[]): boolean {
+  if (nodes && !Array.isArray(nodes)) {
+    return hasValueDeclarations(nodes.getType().getSymbol()?.getDeclarations());
+  }
+  return nodes ? nodes.some((n) => !typeDeclarationKinds.has(n.getKind())) : false;
+}
+
+denoify();
diff --git a/src/_shims/fetch.deno.ts b/src/_shims/fetch.deno.ts
new file mode 100644
index 00000000..fbc2a8dd
--- /dev/null
+++ b/src/_shims/fetch.deno.ts
@@ -0,0 +1,23 @@
+const _fetch = fetch;
+const _Request = Request;
+type _RequestInfo = RequestInfo;
+type _RequestInit = RequestInit;
+const _Response = Response;
+type _ResponseInit = ResponseInit;
+type _BodyInit = BodyInit;
+const _Headers = Headers;
+type _HeadersInit = HeadersInit;
+
+export const isPolyfilled = false;
+
+export {
+  _fetch as fetch,
+  _Request as Request,
+  type _RequestInfo as RequestInfo,
+  type _RequestInit as RequestInit,
+  _Response as Response,
+  type _ResponseInit as ResponseInit,
+  type _BodyInit as BodyInit,
+  _Headers as Headers,
+  type _HeadersInit as HeadersInit,
+};
diff --git a/src/_shims/formdata.deno.ts b/src/_shims/formdata.deno.ts
new file mode 100644
index 00000000..56e31b30
--- /dev/null
+++ b/src/_shims/formdata.deno.ts
@@ -0,0 +1,16 @@
+type _BlobPropertyBag = BlobPropertyBag;
+type _FilePropertyBag = FilePropertyBag;
+
+const _FormData = FormData;
+const _File = File;
+const _Blob = Blob;
+
+export const isPolyfilled = false;
+
+export {
+  _FormData as FormData,
+  _File as File,
+  _Blob as Blob,
+  type _BlobPropertyBag as BlobPropertyBag,
+  type _FilePropertyBag as FilePropertyBag,
+};
diff --git a/src/core.ts b/src/core.ts
index 78b7d4fd..de302bac 100644
--- a/src/core.ts
+++ b/src/core.ts
@@ -744,8 +744,8 @@ const isAbsoluteURL = (url: string): boolean => {
 
 const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
 
-const validatePositiveInteger = (name: string, n: number) => {
-  if (!Number.isInteger(n)) {
+const validatePositiveInteger = (name: string, n: unknown): number => {
+  if (typeof n !== 'number' || !Number.isInteger(n)) {
     throw new Error(`${name} must be an integer`);
   }
   if (n < 0) {
diff --git a/src/resources/completions.ts b/src/resources/completions.ts
index dcf8111e..6a15d317 100644
--- a/src/resources/completions.ts
+++ b/src/resources/completions.ts
@@ -2,7 +2,7 @@
 
 import * as Core from '@anthropic-ai/sdk/core';
 import { APIResource } from '@anthropic-ai/sdk/resource';
-import * as API from './';
+import * as API from './index';
 import { Stream } from '@anthropic-ai/sdk/streaming';
 
 export class Completions extends APIResource {
diff --git a/src/resources/index.ts b/src/resources/index.ts
index bf379d5f..90ae64fc 100644
--- a/src/resources/index.ts
+++ b/src/resources/index.ts
@@ -1,3 +1,4 @@
 // File generated from our OpenAPI spec by Stainless.
 
+export {} from './top-level';
 export { Completion, CompletionCreateParams, Completions } from './completions';
diff --git a/src/uploads.ts b/src/uploads.ts
index 79999cff..055878e3 100644
--- a/src/uploads.ts
+++ b/src/uploads.ts
@@ -1,14 +1,15 @@
 import { type RequestOptions } from './core';
 import { type Readable } from '@anthropic-ai/sdk/_shims/node-readable';
 import { type BodyInit } from '@anthropic-ai/sdk/_shims/fetch';
-import { FormData, File, type FilePropertyBag } from '@anthropic-ai/sdk/_shims/formdata';
+import { FormData, File, type Blob, type FilePropertyBag } from '@anthropic-ai/sdk/_shims/formdata';
 import { getMultipartRequestOptions } from '@anthropic-ai/sdk/_shims/getMultipartRequestOptions';
 import { fileFromPath } from '@anthropic-ai/sdk/_shims/fileFromPath';
 import { type FsReadStream, isFsReadStream } from '@anthropic-ai/sdk/_shims/node-readable';
 
 export { fileFromPath };
 
-export type BlobPart = string | ArrayBuffer | ArrayBufferView | BlobLike | Uint8Array | DataView;
+type BlobLikePart = string | ArrayBuffer | ArrayBufferView | BlobLike | Uint8Array | DataView;
+export type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | Uint8Array | DataView;
 
 /**
  * Typically, this is a native "File" class.
@@ -84,11 +85,11 @@ export const isUploadable = (value: any): value is Uploadable => {
   return isFileLike(value) || isResponseLike(value) || isFsReadStream(value);
 };
 
-export type ToFileInput = Uploadable | Exclude<BlobPart, string> | AsyncIterable<BlobPart>;
+export type ToFileInput = Uploadable | Exclude<BlobLikePart, string> | AsyncIterable<BlobLikePart>;
 
 /**
  * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats
- * @param value the raw content of the file.  Can be an {@link Uploadable}, {@link BlobPart}, or {@link AsyncIterable} of {@link BlobPart}s
+ * @param value the raw content of the file.  Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s
  * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible
  * @param {Object=} options additional properties
  * @param {string=} options.type the MIME type of the content
@@ -231,10 +232,10 @@ const addFormValue = async (form: FormData, key: string, value: unknown): Promis
 
   // TODO: make nested formats configurable
   if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
-    form.append(key, value);
+    form.append(key, String(value));
   } else if (isUploadable(value)) {
     const file = await toFile(value);
-    form.append(key, file);
+    form.append(key, file as File);
   } else if (Array.isArray(value)) {
     await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry)));
   } else if (typeof value === 'object') {
diff --git a/tsconfig.build.json b/tsconfig.build.json
index 2588b82d..9c9d8244 100644
--- a/tsconfig.build.json
+++ b/tsconfig.build.json
@@ -1,7 +1,7 @@
 {
   "extends": "./tsconfig.json",
   "include": ["dist/src"],
-  "exclude": [],
+  "exclude": ["dist/src/_shims/*.deno.ts"],
   "compilerOptions": {
     "rootDir": "./dist/src",
     "paths": {
diff --git a/tsconfig.deno.json b/tsconfig.deno.json
new file mode 100644
index 00000000..0c5e232e
--- /dev/null
+++ b/tsconfig.deno.json
@@ -0,0 +1,21 @@
+{
+  "extends": "./tsconfig.json",
+  "include": ["deno"],
+  "exclude": [],
+  "compilerOptions": {
+    "rootDir": "./deno",
+    "lib": ["es2020", "DOM"],
+    "paths": {
+      "@anthropic-ai/sdk/_shims/*": ["deno/_shims/*"],
+      "@anthropic-ai/sdk": ["deno/index.ts"],
+      "@anthropic-ai/sdk/*": ["deno/*"],
+      "digest-fetch": ["./typings/digest-fetch"]
+    },
+    "noEmit": true,
+    "declaration": true,
+    "declarationMap": true,
+    "outDir": "deno",
+    "pretty": true,
+    "sourceMap": true
+  }
+}
diff --git a/tsconfig.json b/tsconfig.json
index 1a7bd2df..6ec26e6a 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,5 +1,6 @@
 {
   "include": ["src", "tests", "examples"],
+  "exclude": ["src/_shims/*.deno.ts"],
   "compilerOptions": {
     "target": "es2019",
     "lib": ["es2020"],
diff --git a/yarn.lock b/yarn.lock
index 9629d1d7..d90e360a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -720,6 +720,16 @@
   dependencies:
     "@sinonjs/commons" "^3.0.0"
 
+"@ts-morph/common@~0.20.0":
+  version "0.20.0"
+  resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.20.0.tgz#3f161996b085ba4519731e4d24c35f6cba5b80af"
+  integrity sha512-7uKjByfbPpwuzkstL3L5MQyuXPSKdoNG93Fmi2JoDcTf3pEP731JdRFAduRVkOs8oqxPsXKA+ScrWkdQ8t/I+Q==
+  dependencies:
+    fast-glob "^3.2.12"
+    minimatch "^7.4.3"
+    mkdirp "^2.1.6"
+    path-browserify "^1.0.1"
+
 "@tsconfig/node10@^1.0.7":
   version "1.0.8"
   resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
@@ -1218,6 +1228,13 @@ brace-expansion@^1.1.7:
     balanced-match "^1.0.0"
     concat-map "0.0.1"
 
+brace-expansion@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+  integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+  dependencies:
+    balanced-match "^1.0.0"
+
 braces@^3.0.2, braces@~3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
@@ -1393,6 +1410,11 @@ co@^4.6.0:
   resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
   integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
 
+code-block-writer@^12.0.0:
+  version "12.0.0"
+  resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770"
+  integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==
+
 collapse-white-space@1.0.6, collapse-white-space@^1.0.2:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287"
@@ -2962,11 +2984,23 @@ minimatch@^3.0.4, minimatch@^3.1.2:
   dependencies:
     brace-expansion "^1.1.7"
 
+minimatch@^7.4.3:
+  version "7.4.6"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb"
+  integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==
+  dependencies:
+    brace-expansion "^2.0.1"
+
 minimist@1.2.6, minimist@^1.2.0, minimist@^1.2.6:
   version "1.2.6"
   resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
   integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
 
+mkdirp@^2.1.6:
+  version "2.1.6"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19"
+  integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==
+
 ms@2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
@@ -3142,6 +3176,11 @@ parse-srcset@ikatyang/parse-srcset#54eb9c1cb21db5c62b4d0e275d7249516df6f0ee:
   version "1.0.2"
   resolved "https://codeload.github.com/ikatyang/parse-srcset/tar.gz/54eb9c1cb21db5c62b4d0e275d7249516df6f0ee"
 
+path-browserify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
+  integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
+
 path-exists@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
@@ -3783,6 +3822,14 @@ ts-jest@^29.1.0:
     semver "7.x"
     yargs-parser "^21.0.1"
 
+ts-morph@^19.0.0:
+  version "19.0.0"
+  resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-19.0.0.tgz#43e95fb0156c3fe3c77c814ac26b7d0be2f93169"
+  integrity sha512-D6qcpiJdn46tUqV45vr5UGM2dnIEuTGNxVhg0sk5NX11orcouwj6i1bMqZIz2mZTZB1Hcgy7C3oEVhAT+f6mbQ==
+  dependencies:
+    "@ts-morph/common" "~0.20.0"
+    code-block-writer "^12.0.0"
+
 ts-node@^10.5.0:
   version "10.7.0"
   resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5"