From fa4eebba089badc7590c6ad7dc3a60c252702282 Mon Sep 17 00:00:00 2001 From: Ben Tefay Date: Fri, 6 May 2022 12:18:10 +1000 Subject: [PATCH] Improve IDE integration for inferred object properties to support Go To Definition, Rename Symbol, etc. (#1117) * Increase test coverage for type inference of optional object properties * Add test showing that Go To Definition is broken on object properties * Fix Go To Definition for inferred object properties * Fix Go To Definition for inferred merged object properties * Improve languageServerFeatures test names * Fix Go To Definition for inferred pick object properties * Fix Go To Definition for inferred omit object properties * Exclude languageServerFeatures tests from deno * Fix keyof issue * 3.14.5 * Remove tc dep Co-authored-by: Colin McDonnell --- deno/build.mjs | 6 +- deno/lib/__tests__/object.test.ts | 52 +++++ deno/lib/types.ts | 25 +-- package.json | 3 +- .../languageServerFeatures.source.ts | 76 +++++++ src/__tests__/languageServerFeatures.test.ts | 206 ++++++++++++++++++ src/__tests__/object.test.ts | 52 +++++ src/types.ts | 25 +-- yarn.lock | 61 +++++- 9 files changed, 458 insertions(+), 48 deletions(-) create mode 100644 src/__tests__/languageServerFeatures.source.ts create mode 100644 src/__tests__/languageServerFeatures.test.ts diff --git a/deno/build.mjs b/deno/build.mjs index 0c84533c7..dfb4ac192 100644 --- a/deno/build.mjs +++ b/deno/build.mjs @@ -23,7 +23,11 @@ const projectRoot = process.cwd(); const nodeSrcRoot = join(projectRoot, "src"); const denoLibRoot = join(projectRoot, "deno", "lib"); -const skipList = [join(nodeSrcRoot, "__tests__", "object-in-es5-env.test.ts")]; +const skipList = [ + join(nodeSrcRoot, "__tests__", "object-in-es5-env.test.ts"), + join(nodeSrcRoot, "__tests__", "languageServerFeatures.test.ts"), + join(nodeSrcRoot, "__tests__", "languageServerFeatures.source.ts"), +]; const walkAndBuild = (/** @type string */ dir) => { for (const entry of readdirSync(join(nodeSrcRoot, dir), { withFileTypes: true, diff --git a/deno/lib/__tests__/object.test.ts b/deno/lib/__tests__/object.test.ts index fac2b9ffd..75a5c1237 100644 --- a/deno/lib/__tests__/object.test.ts +++ b/deno/lib/__tests__/object.test.ts @@ -216,6 +216,46 @@ test("test inferred merged type", async () => { f1; }); +test("inferred merged object type with optional properties", async () => { + const Merged = z + .object({ a: z.string(), b: z.string().optional() }) + .merge(z.object({ a: z.string().optional(), b: z.string() })); + type Merged = z.infer; + const f1: util.AssertEqual = true; + f1; +}); + +test("inferred unioned object type with optional properties", async () => { + const Unioned = z.union([ + z.object({ a: z.string(), b: z.string().optional() }), + z.object({ a: z.string().optional(), b: z.string() }), + ]); + type Unioned = z.infer; + const f1: util.AssertEqual< + Unioned, + { a: string; b?: string } | { a?: string; b: string } + > = true; + f1; +}); + +test("inferred partial object type with optional properties", async () => { + const Partial = z + .object({ a: z.string(), b: z.string().optional() }) + .partial(); + type Partial = z.infer; + const f1: util.AssertEqual = true; + f1; +}); + +test("inferred picked object type with optional properties", async () => { + const Picked = z + .object({ a: z.string(), b: z.string().optional() }) + .pick({ b: true }); + type Picked = z.infer; + const f1: util.AssertEqual = true; + f1; +}); + test("inferred type for unknown/any keys", () => { const myType = z.object({ anyOptional: z.any().optional(), @@ -308,3 +348,15 @@ test("constructor key", () => { }) ).toThrow(); }); + +test("constructor key", () => { + const Example = z.object({ + prop: z.string(), + opt: z.number().optional(), + arr: z.string().array(), + }); + + type Example = z.infer; + const f1: util.AssertEqual = true; + f1; +}); diff --git a/deno/lib/types.ts b/deno/lib/types.ts index ee8bd6f27..a8a3754fd 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -1363,17 +1363,12 @@ export namespace objectUtil { [k in Exclude]: U[k]; } & V; - type optionalKeys = { - [k in keyof T]: undefined extends T[k] ? k : never; - }[keyof T]; - - // type requiredKeys = Exclude>; - type requiredKeys = { + export type requiredKeys = { [k in keyof T]: undefined extends T[k] ? never : k; }[keyof T]; export type addQuestionMarks = { - [k in optionalKeys]?: T[k]; + [k in keyof T]?: T[k]; } & { [k in requiredKeys]: T[k] }; export type identity = T; @@ -1398,9 +1393,7 @@ export namespace objectUtil { }; } -export type extendShape = { - [k in Exclude]: A[k]; -} & { [k in keyof B]: B[k] }; +export type extendShape = Omit & B; const AugmentFactory = (def: Def) => @@ -1712,11 +1705,7 @@ export class ZodObject< pick( mask: Mask - ): ZodObject< - objectUtil.noNever<{ [k in keyof Mask]: k extends keyof T ? T[k] : never }>, - UnknownKeys, - Catchall - > { + ): ZodObject>, UnknownKeys, Catchall> { const shape: any = {}; util.objectKeys(mask).map((key) => { shape[key] = this.shape[key]; @@ -1729,11 +1718,7 @@ export class ZodObject< omit( mask: Mask - ): ZodObject< - objectUtil.noNever<{ [k in keyof T]: k extends keyof Mask ? never : T[k] }>, - UnknownKeys, - Catchall - > { + ): ZodObject, UnknownKeys, Catchall> { const shape: any = {}; util.objectKeys(this.shape).map((key) => { if (util.objectKeys(mask).indexOf(key) === -1) { diff --git a/package.json b/package.json index e48cdc607..1a650649b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zod", - "version": "3.14.4", + "version": "3.14.5", "description": "TypeScript-first schema declaration and validation library with static type inference", "main": "./lib/index.js", "types": "./index.d.ts", @@ -87,6 +87,7 @@ "pretty-quick": "^3.1.3", "rollup": "^2.70.1", "ts-jest": "^27.1.3", + "ts-morph": "^14.0.0", "ts-node": "^10.7.0", "tslib": "^2.3.1", "typescript": "^4.6.2" diff --git a/src/__tests__/languageServerFeatures.source.ts b/src/__tests__/languageServerFeatures.source.ts new file mode 100644 index 000000000..f2e99a0c5 --- /dev/null +++ b/src/__tests__/languageServerFeatures.source.ts @@ -0,0 +1,76 @@ +import * as z from "../index"; + +export const filePath = __filename; + +// z.object() + +export const Test = z.object({ + f1: z.number(), +}); + +export type Test = z.infer; + +export const instanceOfTest: Test = { + f1: 1, +}; + +// z.object().merge() + +export const TestMerge = z + .object({ + f2: z.string().optional(), + }) + .merge(Test); + +export type TestMerge = z.infer; + +export const instanceOfTestMerge: TestMerge = { + f1: 1, + f2: "string", +}; + +// z.union() + +export const TestUnion = z.union([ + z.object({ + f2: z.string().optional(), + }), + Test, +]); + +export type TestUnion = z.infer; + +export const instanceOfTestUnion: TestUnion = { + f1: 1, + f2: "string", +}; + +// z.object().partial() + +export const TestPartial = Test.partial(); + +export type TestPartial = z.infer; + +export const instanceOfTestPartial: TestPartial = { + f1: 1, +}; + +// z.object().pick() + +export const TestPick = TestMerge.pick({ f1: true }); + +export type TestPick = z.infer; + +export const instanceOfTestPick: TestPick = { + f1: 1, +}; + +// z.object().omit() + +export const TestOmit = TestMerge.omit({ f2: true }); + +export type TestOmit = z.infer; + +export const instanceOfTestOmit: TestOmit = { + f1: 1, +}; diff --git a/src/__tests__/languageServerFeatures.test.ts b/src/__tests__/languageServerFeatures.test.ts new file mode 100644 index 000000000..0d065f760 --- /dev/null +++ b/src/__tests__/languageServerFeatures.test.ts @@ -0,0 +1,206 @@ +// @ts-ignore TS6133 +import { expect, fit } from "@jest/globals"; +import { filePath } from "./languageServerFeatures.source"; +import { Project, Node, SyntaxKind } from "ts-morph"; +import path from "path"; + +// The following tool is helpful for understanding the TypeScript AST associated with these tests: +// https://ts-ast-viewer.com/ (just copy the contents of languageServerFeatures.source into the viewer) + +describe("Executing Go To Definition (and therefore Find Usages and Rename Refactoring) using an IDE works on inferred object properties", () => { + // Compile file developmentEnvironment.source + const project = new Project({ + tsConfigFilePath: path.join(__dirname, "..", "..", "tsconfig.json"), + skipAddingFilesFromTsConfig: true, + }); + const sourceFile = project.addSourceFileAtPath(filePath); + + test("works for object properties inferred from z.object()", () => { + // Find usage of Test.f1 property + const instanceVariable = + sourceFile.getVariableDeclarationOrThrow("instanceOfTest"); + const propertyBeingAssigned = getPropertyBeingAssigned( + instanceVariable, + "f1" + ); + + // Find definition of Test.f1 property + const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; + const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( + SyntaxKind.VariableDeclaration + ); + + // Assert that find definition returned the Zod definition of Test + expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); + expect(parentOfProperty?.getName()).toEqual("Test"); + }); + + test("works for first object properties inferred from z.object().merge()", () => { + // Find usage of TestMerge.f1 property + const instanceVariable = sourceFile.getVariableDeclarationOrThrow( + "instanceOfTestMerge" + ); + const propertyBeingAssigned = getPropertyBeingAssigned( + instanceVariable, + "f1" + ); + + // Find definition of TestMerge.f1 property + const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; + const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( + SyntaxKind.VariableDeclaration + ); + + // Assert that find definition returned the Zod definition of Test + expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); + expect(parentOfProperty?.getName()).toEqual("Test"); + }); + + test("works for second object properties inferred from z.object().merge()", () => { + // Find usage of TestMerge.f2 property + const instanceVariable = sourceFile.getVariableDeclarationOrThrow( + "instanceOfTestMerge" + ); + const propertyBeingAssigned = getPropertyBeingAssigned( + instanceVariable, + "f2" + ); + + // Find definition of TestMerge.f2 property + const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; + const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( + SyntaxKind.VariableDeclaration + ); + + // Assert that find definition returned the Zod definition of TestMerge + expect(definitionOfProperty?.getText()).toEqual( + "f2: z.string().optional()" + ); + expect(parentOfProperty?.getName()).toEqual("TestMerge"); + }); + + test("works for first object properties inferred from z.union()", () => { + // Find usage of TestUnion.f1 property + const instanceVariable = sourceFile.getVariableDeclarationOrThrow( + "instanceOfTestUnion" + ); + const propertyBeingAssigned = getPropertyBeingAssigned( + instanceVariable, + "f1" + ); + + // Find definition of TestUnion.f1 property + const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; + const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( + SyntaxKind.VariableDeclaration + ); + + // Assert that find definition returned the Zod definition of Test + expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); + expect(parentOfProperty?.getName()).toEqual("Test"); + }); + + test("works for second object properties inferred from z.union()", () => { + // Find usage of TestUnion.f2 property + const instanceVariable = sourceFile.getVariableDeclarationOrThrow( + "instanceOfTestUnion" + ); + const propertyBeingAssigned = getPropertyBeingAssigned( + instanceVariable, + "f2" + ); + + // Find definition of TestUnion.f2 property + const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; + const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( + SyntaxKind.VariableDeclaration + ); + + // Assert that find definition returned the Zod definition of TestUnion + expect(definitionOfProperty?.getText()).toEqual( + "f2: z.string().optional()" + ); + expect(parentOfProperty?.getName()).toEqual("TestUnion"); + }); + + test("works for object properties inferred from z.object().partial()", () => { + // Find usage of TestPartial.f1 property + const instanceVariable = sourceFile.getVariableDeclarationOrThrow( + "instanceOfTestPartial" + ); + const propertyBeingAssigned = getPropertyBeingAssigned( + instanceVariable, + "f1" + ); + + // Find definition of TestPartial.f1 property + const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; + const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( + SyntaxKind.VariableDeclaration + ); + + // Assert that find definition returned the Zod definition of Test + expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); + expect(parentOfProperty?.getName()).toEqual("Test"); + }); + + test("works for object properties inferred from z.object().pick()", () => { + // Find usage of TestPick.f1 property + const instanceVariable = + sourceFile.getVariableDeclarationOrThrow("instanceOfTestPick"); + const propertyBeingAssigned = getPropertyBeingAssigned( + instanceVariable, + "f1" + ); + + // Find definition of TestPick.f1 property + const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; + const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( + SyntaxKind.VariableDeclaration + ); + + // Assert that find definition returned the Zod definition of Test + expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); + expect(parentOfProperty?.getName()).toEqual("Test"); + }); + + test("works for object properties inferred from z.object().omit()", () => { + // Find usage of TestOmit.f1 property + const instanceVariable = + sourceFile.getVariableDeclarationOrThrow("instanceOfTestOmit"); + const propertyBeingAssigned = getPropertyBeingAssigned( + instanceVariable, + "f1" + ); + + // Find definition of TestOmit.f1 property + const definitionOfProperty = propertyBeingAssigned?.getDefinitionNodes()[0]; + const parentOfProperty = definitionOfProperty?.getFirstAncestorByKind( + SyntaxKind.VariableDeclaration + ); + + // Assert that find definition returned the Zod definition of Test + expect(definitionOfProperty?.getText()).toEqual("f1: z.number()"); + expect(parentOfProperty?.getName()).toEqual("Test"); + }); +}); + +const getPropertyBeingAssigned = (node: Node, name: string) => { + const propertyAssignment = node.forEachDescendant((descendent) => + Node.isPropertyAssignment(descendent) && descendent.getName() == name + ? descendent + : undefined + ); + + if (propertyAssignment == null) + fail(`Could not find property assignment with name ${name}`); + + const propertyLiteral = propertyAssignment.getFirstDescendantByKind( + SyntaxKind.Identifier + ); + + if (propertyLiteral == null) + fail(`Could not find property literal with name ${name}`); + + return propertyLiteral; +}; diff --git a/src/__tests__/object.test.ts b/src/__tests__/object.test.ts index fc01e6397..100d7a633 100644 --- a/src/__tests__/object.test.ts +++ b/src/__tests__/object.test.ts @@ -215,6 +215,46 @@ test("test inferred merged type", async () => { f1; }); +test("inferred merged object type with optional properties", async () => { + const Merged = z + .object({ a: z.string(), b: z.string().optional() }) + .merge(z.object({ a: z.string().optional(), b: z.string() })); + type Merged = z.infer; + const f1: util.AssertEqual = true; + f1; +}); + +test("inferred unioned object type with optional properties", async () => { + const Unioned = z.union([ + z.object({ a: z.string(), b: z.string().optional() }), + z.object({ a: z.string().optional(), b: z.string() }), + ]); + type Unioned = z.infer; + const f1: util.AssertEqual< + Unioned, + { a: string; b?: string } | { a?: string; b: string } + > = true; + f1; +}); + +test("inferred partial object type with optional properties", async () => { + const Partial = z + .object({ a: z.string(), b: z.string().optional() }) + .partial(); + type Partial = z.infer; + const f1: util.AssertEqual = true; + f1; +}); + +test("inferred picked object type with optional properties", async () => { + const Picked = z + .object({ a: z.string(), b: z.string().optional() }) + .pick({ b: true }); + type Picked = z.infer; + const f1: util.AssertEqual = true; + f1; +}); + test("inferred type for unknown/any keys", () => { const myType = z.object({ anyOptional: z.any().optional(), @@ -307,3 +347,15 @@ test("constructor key", () => { }) ).toThrow(); }); + +test("constructor key", () => { + const Example = z.object({ + prop: z.string(), + opt: z.number().optional(), + arr: z.string().array(), + }); + + type Example = z.infer; + const f1: util.AssertEqual = true; + f1; +}); diff --git a/src/types.ts b/src/types.ts index 360e7fc49..877cda9d3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1363,17 +1363,12 @@ export namespace objectUtil { [k in Exclude]: U[k]; } & V; - type optionalKeys = { - [k in keyof T]: undefined extends T[k] ? k : never; - }[keyof T]; - - // type requiredKeys = Exclude>; - type requiredKeys = { + export type requiredKeys = { [k in keyof T]: undefined extends T[k] ? never : k; }[keyof T]; export type addQuestionMarks = { - [k in optionalKeys]?: T[k]; + [k in keyof T]?: T[k]; } & { [k in requiredKeys]: T[k] }; export type identity = T; @@ -1398,9 +1393,7 @@ export namespace objectUtil { }; } -export type extendShape = { - [k in Exclude]: A[k]; -} & { [k in keyof B]: B[k] }; +export type extendShape = Omit & B; const AugmentFactory = (def: Def) => @@ -1712,11 +1705,7 @@ export class ZodObject< pick( mask: Mask - ): ZodObject< - objectUtil.noNever<{ [k in keyof Mask]: k extends keyof T ? T[k] : never }>, - UnknownKeys, - Catchall - > { + ): ZodObject>, UnknownKeys, Catchall> { const shape: any = {}; util.objectKeys(mask).map((key) => { shape[key] = this.shape[key]; @@ -1729,11 +1718,7 @@ export class ZodObject< omit( mask: Mask - ): ZodObject< - objectUtil.noNever<{ [k in keyof T]: k extends keyof Mask ? never : T[k] }>, - UnknownKeys, - Catchall - > { + ): ZodObject, UnknownKeys, Catchall> { const shape: any = {}; util.objectKeys(this.shape).map((key) => { if (util.objectKeys(mask).indexOf(key) === -1) { diff --git a/yarn.lock b/yarn.lock index fe52ffe54..b544138e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -828,6 +828,16 @@ resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@ts-morph/common@~0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.13.0.tgz#77dea1565baaf002d1bc2c20e05d1fb3349008a9" + integrity sha512-fEJ6j7Cu8yiWjA4UmybOBH9Efgb/64ZTWuvCF4KysGu4xz8ettfyaqFt8WZ1btCxXsGZJjZ2/3svOF6rL+UFdQ== + dependencies: + fast-glob "^3.2.11" + minimatch "^5.0.1" + mkdirp "^1.0.4" + 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" @@ -1394,6 +1404,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.1, braces@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" @@ -1609,6 +1626,13 @@ co@^4.6.0: resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +code-block-writer@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-11.0.0.tgz#5956fb186617f6740e2c3257757fea79315dd7d4" + integrity sha512-GEqWvEWWsOvER+g9keO4ohFoD3ymwyCnqY3hoTr7GZipYFwEhMHJw+TtV0rfgRhNImM6QWZGO2XYjlJVyYT62w== + dependencies: + tslib "2.3.1" + collect-v8-coverage@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" @@ -2267,7 +2291,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.9: +fast-glob@^3.2.11, fast-glob@^3.2.9: version "3.2.11" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== @@ -3664,11 +3688,23 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mri@^1.1.5: version "1.2.0" resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" @@ -3924,6 +3960,11 @@ parse5@6.0.1: resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== +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@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" @@ -4633,6 +4674,14 @@ ts-jest@^27.1.3: semver "7.x" yargs-parser "20.x" +ts-morph@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-14.0.0.tgz#6bffb7e4584cf6a9aebce2066bf4258e1d03f9fa" + integrity sha512-tO8YQ1dP41fw8GVmeQAdNsD8roZi1JMqB7YwZrqU856DvmG5/710e41q2XauzTYrygH9XmMryaFeLo+kdCziyA== + dependencies: + "@ts-morph/common" "~0.13.0" + code-block-writer "^11.0.0" + ts-node@^10.7.0: version "10.7.0" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" @@ -4681,16 +4730,16 @@ tsconfig-paths@^3.9.0: minimist "^1.2.0" strip-bom "^3.0.0" +tslib@2.3.1, tslib@^2.1.0, tslib@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0, tslib@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - tsutils@^3.21.0: version "3.21.0" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz"