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"