From 858088ac3ecb9158f6db2b5a62274235df240130 Mon Sep 17 00:00:00 2001 From: Yoav Balasiano Date: Sat, 22 Apr 2023 14:34:44 +0300 Subject: [PATCH 1/5] Add new hover provider for debugging --- .vscode/launch.json | 57 +++++++++--------- src/components/title.ts | 1 + src/extension.ts | 24 +++----- src/format/prettify.ts | 10 ++++ src/provider/selectedTextHoverProvider.ts | 72 +++++++++++++++++++++++ src/test/suite/errorMessageMocks.ts | 40 +++++++++++++ src/test/suite/extension.test.ts | 32 +++++++--- tsconfig.json | 9 ++- 8 files changed, 187 insertions(+), 58 deletions(-) create mode 100644 src/format/prettify.ts create mode 100644 src/provider/selectedTextHoverProvider.ts create mode 100644 src/test/suite/errorMessageMocks.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index d4df9e9..b14a4d3 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,33 +3,32 @@ // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 { - "version": "0.2.0", - "configurations": [ - { - "name": "Run Extension", - "type": "extensionHost", - "request": "launch", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}" - ], - "outFiles": [ - "${workspaceFolder}/dist/**/*.js" - ], - "preLaunchTask": "${defaultBuildTask}" - }, - { - "name": "Extension Tests", - "type": "extensionHost", - "request": "launch", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}", - "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" - ], - "outFiles": [ - "${workspaceFolder}/out/**/*.js", - "${workspaceFolder}/dist/**/*.js" - ], - "preLaunchTask": "tasks: watch-tests" - } - ] + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension", + "type": "extensionHost", + "request": "launch", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/dist/**/*.js"], + "preLaunchTask": "${defaultBuildTask}", + "env": { + "VSCODE_DEBUG_MODE": "true" + } + }, + { + "name": "Extension Tests", + "type": "extensionHost", + "request": "launch", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" + ], + "outFiles": [ + "${workspaceFolder}/out/**/*.js", + "${workspaceFolder}/dist/**/*.js" + ], + "preLaunchTask": "tasks: watch-tests" + } + ] } diff --git a/src/components/title.ts b/src/components/title.ts index d18c8da..d0b61bb 100644 --- a/src/components/title.ts +++ b/src/components/title.ts @@ -14,6 +14,7 @@ export const title = (diagnostic: Diagnostic) => d/*html*/ ` ` : "" } +
`; diff --git a/src/extension.ts b/src/extension.ts index 857143a..aec5c6c 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -5,17 +5,20 @@ import { Range, window, } from "vscode"; +import { createConverter } from "vscode-languageclient/lib/common/codeConverter"; import { formatDiagnostic } from "./format/formatDiagnostic"; +import { prettify } from "./format/prettify"; import { hoverProvider } from "./provider/hoverProvider"; +import { registerSelectedTextHoverProvider } from "./provider/selectedTextHoverProvider"; import { uriStore } from "./provider/uriStore"; import { has } from "./utils"; -import { createConverter } from "vscode-languageclient/lib/common/codeConverter"; -import { format } from "prettier"; export function activate(context: ExtensionContext) { const registeredLanguages = new Set(); const converter = createConverter(); + registerSelectedTextHoverProvider(context); + context.subscriptions.push( languages.onDidChangeDiagnostics(async (e) => { e.uris.forEach((uri) => { @@ -35,10 +38,11 @@ export function activate(context: ExtensionContext) { : false ) .forEach(async (diagnostic) => { - // formatDiagnostic converts message based on LSP Diagnostic type, not VSCode Diagnostic type, so it can be used in other IDEs. // Here we convert VSCode Diagnostic to LSP Diagnostic to make formatDiagnostic recognize it. - const markdownString = new MarkdownString(formatDiagnostic(converter.asDiagnostic(diagnostic), prettify)); + const markdownString = new MarkdownString( + formatDiagnostic(converter.asDiagnostic(diagnostic), prettify) + ); markdownString.isTrusted = true; markdownString.supportHtml = true; @@ -51,7 +55,7 @@ export function activate(context: ExtensionContext) { }); uriStore[uri.path] = items; - if (hasTsDiagnostic && uri.scheme === "file") { + if (hasTsDiagnostic) { const editor = window.visibleTextEditors.find( (editor) => editor.document.uri.toString() === uri.toString() ); @@ -60,7 +64,6 @@ export function activate(context: ExtensionContext) { context.subscriptions.push( languages.registerHoverProvider( { - scheme: "file", language: editor.document.languageId, }, hoverProvider @@ -72,12 +75,3 @@ export function activate(context: ExtensionContext) { }) ); } - -function prettify(text: string) { - return format(text, { - parser: "typescript", - printWidth: 60, - singleAttributePerLine: false, - arrowParens: "avoid", - }); -} diff --git a/src/format/prettify.ts b/src/format/prettify.ts new file mode 100644 index 0000000..81d0fe6 --- /dev/null +++ b/src/format/prettify.ts @@ -0,0 +1,10 @@ +import { format } from "prettier"; + +export function prettify(text: string) { + return format(text, { + parser: "typescript", + printWidth: 60, + singleAttributePerLine: false, + arrowParens: "avoid", + }); +} diff --git a/src/provider/selectedTextHoverProvider.ts b/src/provider/selectedTextHoverProvider.ts new file mode 100644 index 0000000..59b2d6d --- /dev/null +++ b/src/provider/selectedTextHoverProvider.ts @@ -0,0 +1,72 @@ +import { ExtensionContext, MarkdownString, languages, window } from "vscode"; +import { createConverter } from "vscode-languageclient/lib/common/codeConverter"; +import { miniLine } from "../components"; +import { formatDiagnostic } from "../format/formatDiagnostic"; +import { prettify } from "../format/prettify"; +import { d } from "../utils"; + +const isDebugMode = () => process.env.VSCODE_DEBUG_MODE === "true"; + +/** + * Register an hover provider in debug only. + * It format selected text and help test things visually easier. + */ +export function registerSelectedTextHoverProvider(context: ExtensionContext) { + const converter = createConverter(); + + if (!isDebugMode()) { + return; + } + + context.subscriptions.push( + languages.registerHoverProvider( + { + language: "typescript", + pattern: "**/test/**/*.ts", + }, + { + provideHover(document, position) { + const editor = window.activeTextEditor; + const range = document.getWordRangeAtPosition(position); + const message = document.getText(editor!.selection); + + const contents = + range && message + ? [ + new MarkdownString( + debugHoverHeader + + formatDiagnostic( + converter.asDiagnostic({ + message, + range, + severity: 0, + source: "ts", + code: 1337, + }), + prettify + ) + ), + ] + : []; + + contents[0].isTrusted = true; + contents[0].supportHtml = true; + + return { + contents, + }; + }, + } + ) + ); +} + +const debugHoverHeader = d/*html*/ ` + + + Formatted selected text (debug only) + +
+
+ ${miniLine} +`; diff --git a/src/test/suite/errorMessageMocks.ts b/src/test/suite/errorMessageMocks.ts new file mode 100644 index 0000000..dfab595 --- /dev/null +++ b/src/test/suite/errorMessageMocks.ts @@ -0,0 +1,40 @@ +import { d } from "../../utils"; + +/** + * This file contains mocks of error messages, only some of them + * are used in tests but all of them can be used to test and debug + * the formatting visually, you can try to select them on debug and check the hover. + */ + +export const errorWithSpecialCharsInObjectKeys = d` +Type 'string' is not assignable to type '{ 'abc*bc': string; }'. +`; + +export const errorWithDashInObjectKeys = d` +Type '{ person: { 'first-name': string; }; }' is not assignable to type 'string'. +`; + +/** + * Formatting error from this issue: https://github.com/yoavbls/pretty-ts-errors/issues/20 + */ +export const errorWithMethodsWordInIt = d` +The 'this' context of type 'ElementHandle' is not assignable to method's 'this' of type 'ElementHandle'. + Type 'Node' is missing the following properties from type 'Element': attributes, classList, className, clientHeight, and 114 more. +`; + +const errorWithLongType = d` +Property 'isFlying' is missing in type '{ animal: { __typename?: "Animal" | undefined; id: string; name: string; age: number; isAlived: boolean; ... 8 more ...; attributes: { ...; } | ... 3 more ... | { ...; }; }; }' but required in type '{ animal: { __typename?: "Animal" | undefined; id: string; name: string; age: number; isAlived: boolean; isFlying: boolean; ... 8 more ...; attributes: { ...; } | ... 3 more ... | { ...; }; }; }'. +`; + +const errorWithTruncatedType2 = d` +Type '{ '!top': string[]; 'xsl:declaration': { attrs: { 'default-collation': null; 'exclude-result-prefixes': null; 'extension-element-prefixes': null; 'use-when': null; 'xpath-default-namespace': null; }; }; 'xsl:instruction': { ...; }; ... 49 more ...; 'xsl:literal-result-element': {}; }' is missing the following properties from type 'GraphQLSchema': description, extensions, astNode, extensionASTNodes, and 21 more. +`; + +const errorWithSimpleIndentations = d` +Type '(newIds: number[]) => void' is not assignable to type '(selectedId: string[]) => void'. + Types of parameters 'newIds' and 'selectedId' are incompatible. + Type 'string[]' is not assignable to type 'number[]'. + Type 'string' is not assignable to type 'number'. +`; + +("Property 'user' is missing in type '{ person: { username: string; email: string; }; }' but required in type '{ user: { name: string; email: `${string}@${string}.${string}`; age: number; }; }'."); diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index df5cdca..379e33d 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -3,11 +3,14 @@ import * as assert from "assert"; // You can import and use all API from the 'vscode' module // as well as import your extension to test it import * as vscode from "vscode"; +import { inlineCodeBlock } from "../../components"; import { addMissingParentheses } from "../../format/addMissingParentheses"; import { formatDiagnosticMessage } from "../../format/formatDiagnosticMessage"; -import { inlineCodeBlock } from "../../components"; -import { format } from "prettier"; -// import * as myExtension from '../../extension'; +import { prettify } from "../../format/prettify"; +import { + errorWithDashInObjectKeys, + errorWithSpecialCharsInObjectKeys, +} from "./errorMessageMocks"; suite("Extension Test Suite", () => { vscode.window.showInformationMessage("Start all tests."); @@ -21,12 +24,23 @@ suite("Extension Test Suite", () => { test("Special characters in object keys", () => { assert.strictEqual( - formatDiagnosticMessage("Type 'string' is not assignable to type '{ 'abc*bc': string; }'.", (text) => text), - 'Type ' + - inlineCodeBlock('string', 'type') + - ' is not assignable to type ' + - inlineCodeBlock("{ 'abc*bc': string; }", 'type') + - '.' + formatDiagnosticMessage(errorWithSpecialCharsInObjectKeys, prettify), + "Type " + + inlineCodeBlock("string", "type") + + " is not assignable to type " + + inlineCodeBlock("{ 'abc*bc': string; }", "type") + + "." + ); + }); + + test("Special method's word in the error", () => { + assert.strictEqual( + formatDiagnosticMessage(errorWithDashInObjectKeys, prettify), + "Type " + + inlineCodeBlock("{ person: { 'first-name': string; }; }", "type") + + " is not assignable to type " + + inlineCodeBlock("string", "type") + + "." ); }); }); diff --git a/tsconfig.json b/tsconfig.json index a2bc283..a783124 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,15 +2,14 @@ "compilerOptions": { "module": "commonjs", "target": "ES2021", - "lib": ["ES2021"], + "lib": ["ES2021", "ES2021.String"], "sourceMap": true, "rootDir": "src", "checkJs": true, - "strict": true /* enable all strict type-checking options */ + "strict": true /* enable all strict type-checking options */, /* Additional Checks */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, + "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */ }, "include": ["src/**/*.ts"] } From 7c57c6a7f630950e8e2058274aecd44d778fdc33 Mon Sep 17 00:00:00 2001 From: Yoav Balasiano Date: Sat, 22 Apr 2023 14:35:03 +0300 Subject: [PATCH 2/5] Fix formatting bugs with ' char --- src/format/formatDiagnosticMessage.ts | 33 ++++++++++++++++++++------- src/format/formatTypeBlock.ts | 12 ++++++---- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/format/formatDiagnosticMessage.ts b/src/format/formatDiagnosticMessage.ts index 45f0711..c087e81 100644 --- a/src/format/formatDiagnosticMessage.ts +++ b/src/format/formatDiagnosticMessage.ts @@ -7,7 +7,12 @@ const formatTypeScriptBlock = (_: string, code: string) => const formatSimpleTypeBlock = (_: string, code: string) => inlineCodeBlock(code, "type"); -const formatTypeOrModuleBlock = (_: string, prefix: string, code: string, format: (type: string) => string) => +const formatTypeOrModuleBlock = ( + _: string, + prefix: string, + code: string, + format: (type: string) => string +) => formatTypeBlock( prefix, ["module", "file", "file name"].includes(prefix.toLowerCase()) @@ -16,7 +21,10 @@ const formatTypeOrModuleBlock = (_: string, prefix: string, code: string, format format ); -export const formatDiagnosticMessage = (message: string, format: (type: string) => string) => +export const formatDiagnosticMessage = ( + message: string, + format: (type: string) => string +) => message // format declare module snippet .replaceAll( @@ -38,13 +46,21 @@ export const formatDiagnosticMessage = (message: string, format: (type: string) .replaceAll( /(types) '(.*?)' and '(.*?)'[\.]?/gi, (_: string, p1: string, p2: string, p3: string) => - `${formatTypeBlock(p1, p2, format)} and ${formatTypeBlock("", p3, format)}` + `${formatTypeBlock(p1, p2, format)} and ${formatTypeBlock( + "", + p3, + format + )}` ) // Format type annotation options .replaceAll( /type annotation must be '(.*?)' or '(.*?)'[\.]?/gi, (_: string, p1: string, p2: string, p3: string) => - `${formatTypeBlock(p1, p2, format)} or ${formatTypeBlock("", p3, format)}` + `${formatTypeBlock(p1, p2, format)} or ${formatTypeBlock( + "", + p3, + format + )}` ) .replaceAll( /(Overload \d of \d), '(.*?)', /gi, @@ -54,7 +70,7 @@ export const formatDiagnosticMessage = (message: string, format: (type: string) .replaceAll(/^'"[^"]*"'$/g, formatTypeScriptBlock) // Format types .replaceAll( - /(type|type alias|interface|module|file|file name) '(.*?)'(?=[\s.])/gi, + /(type|type alias|interface|module|file|file name|method's) '(.*?)'(?=[\s.])/gi, (_, p1: string, p2: string) => formatTypeOrModuleBlock(_, p1, p2, format) ) // Format reversed types @@ -80,6 +96,7 @@ export const formatDiagnosticMessage = (message: string, format: (type: string) (_, p1: string, p2: string) => `${p1} ${formatTypeScriptBlock("", p2)}` ) // Format regular code blocks - .replaceAll(/'((?:(?!:\s*}).)*?)'(?!\s*:)/g, (_: string, p1: string) => unstyledCodeBlock(p1)); - - + .replaceAll( + /'((?:(?!:\s*}).)*?)' (?!\s*:)/g, + (_: string, p1: string) => `${unstyledCodeBlock(p1)} ` + ); diff --git a/src/format/formatTypeBlock.ts b/src/format/formatTypeBlock.ts index d7a78aa..93159c7 100644 --- a/src/format/formatTypeBlock.ts +++ b/src/format/formatTypeBlock.ts @@ -5,7 +5,11 @@ import { } from "../components"; import { addMissingParentheses } from "./addMissingParentheses"; -export function formatTypeBlock(prefix: string, type: string, format: (type: string) => string) { +export function formatTypeBlock( + prefix: string, + type: string, + format: (type: string) => string +) { // Return a simple code block if it's just a parenthesis if (type.match(/^(\[\]|\{\})$/)) { return `${prefix} ${unstyledCodeBlock(type)}`; @@ -20,7 +24,7 @@ export function formatTypeBlock(prefix: string, type: string, format: (type: str return `${prefix} ${inlineCodeBlock(type, "type")}`; } - const prettyType = convertToOriginalType(prettifyType(convertToValidType(type), format)); + const prettyType = prettifyType(type, format); if (prettyType.includes("\n")) { return `${prefix}: ${multiLineCodeBlock(prettyType, "type")}`; @@ -34,9 +38,7 @@ export function formatTypeBlock(prefix: string, type: string, format: (type: str function prettifyType(type: string, format: (type: string) => string) { try { // Wrap type with valid statement, format it and extract the type back - return convertToOriginalType( - format(convertToValidType(type)) - ); + return convertToOriginalType(format(convertToValidType(type))); } catch (e) { return type; } From f6af46f4c1ead81025593c1cc14ffc2ecbb534bb Mon Sep 17 00:00:00 2001 From: Yoav Balasiano Date: Sat, 22 Apr 2023 14:35:24 +0300 Subject: [PATCH 3/5] Bump required vscode version to 1.77 because of background color variables --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 672d82a..ae9abcc 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "homepage": "https://github.com/yoavbls/pretty-ts-errors", "engines": { - "vscode": "^1.70.0" + "vscode": "^1.77.0" }, "categories": [ "Programming Languages", @@ -54,7 +54,7 @@ "scripts": { "vscode:prepublish": "npm run package", "compile": "node scripts/build", - "watch": "npm run compile --watch", + "watch": "npm run compile -- --watch", "build": "vsce package", "package": "node scripts/build -- --production", "compile-tests": "tsc -p . --outDir out", @@ -77,7 +77,6 @@ "eslint": "^8.20.0", "glob": "^8.0.3", "mocha": "^10.0.0", - "ts-loader": "^9.3.1", "typescript": "^5.0.4" }, "dependencies": { From 8022d8bc8a6bc626567364fcabc0ccfe2102e3e5 Mon Sep 17 00:00:00 2001 From: Yoav Balasiano Date: Sat, 22 Apr 2023 14:35:36 +0300 Subject: [PATCH 4/5] Readme images sizing fixes --- README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1b9b17c..0703ef6 100644 --- a/README.md +++ b/README.md @@ -13,17 +13,17 @@ [![Visual Studio Code](https://img.shields.io/badge/--007ACC?logo=visual%20studio%20code&logoColor=ffffff)](https://marketplace.visualstudio.com/items?itemName=yoavbls.pretty-ts-errors) [![GitHub license](https://badgen.net/github/license/yoavbls/pretty-ts-errors)](https://github.com/yoavbls/pretty-ts-errors/blob/main/LICENSE) ![visitor badge](https://visitor-badge.glitch.me/badge?page_id=pretty-ts-errors) [![GitHub stars](https://img.shields.io/github/stars/yoavbls/pretty-ts-errors.svg?style=social&label=Star)](https://GitHub.com/yoavbls/pretty-ts-errors/stargazers/) - + TypeScript errors become messier as the complexity of types increases. At some point, TypeScript will throw on you a shitty heap of parentheses and `"..."`. This extension will help you understand what's going on. For example, in this relatively simple error: -    +    ## Watch this - Watch theo's video + Watch theo's video ## Features @@ -56,20 +56,20 @@ Yes, these types include things like `... more ...`, `{ ... }`, etc in an incons ## Hype section - - + + - - + + - - + + From 42308a6cfe337af0bb5c69ba3485603e3b4e05df Mon Sep 17 00:00:00 2001 From: Yoav Balasiano Date: Sat, 22 Apr 2023 18:26:25 +0300 Subject: [PATCH 5/5] Fix #30 and add cover it with test --- src/format/formatDiagnosticMessage.ts | 6 +++--- src/format/formatTypeBlock.ts | 13 ++++++++++--- src/test/suite/errorMessageMocks.ts | 5 +++++ src/test/suite/extension.test.ts | 15 +++++++++++++-- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/format/formatDiagnosticMessage.ts b/src/format/formatDiagnosticMessage.ts index c087e81..c3e187e 100644 --- a/src/format/formatDiagnosticMessage.ts +++ b/src/format/formatDiagnosticMessage.ts @@ -34,9 +34,9 @@ export const formatDiagnosticMessage = ( ) // format missing props error .replaceAll( - /(is missing the following properties from type .*: )(.+?)(?=and|$)/g, - (_, pre, post) => - `${pre}
    ${post + /(is missing the following properties from type )'(.*)': (.+?)(?=and|$)/g, + (_, pre, type, post) => + `${pre}${formatTypeBlock("", type, format)}:
      ${post .split(", ") .filter(Boolean) .map((prop: string) => `
    • ${prop}
    • `) diff --git a/src/format/formatTypeBlock.ts b/src/format/formatTypeBlock.ts index 93159c7..d5cbb82 100644 --- a/src/format/formatTypeBlock.ts +++ b/src/format/formatTypeBlock.ts @@ -35,11 +35,18 @@ export function formatTypeBlock( /** * Try to make type prettier with prettier */ -function prettifyType(type: string, format: (type: string) => string) { +export function prettifyType( + type: string, + format: (type: string) => string, + options?: { throwOnError?: boolean } +) { try { // Wrap type with valid statement, format it and extract the type back return convertToOriginalType(format(convertToValidType(type))); } catch (e) { + if (options?.throwOnError) { + throw e; + } return type; } } @@ -49,7 +56,7 @@ const convertToValidType = (type: string) => // Add missing parentheses when the type ends with "..."" .replace(/(.*)\.\.\.$/, (_, p1) => addMissingParentheses(p1)) // Replace single parameter function destructuring because it's not a valid type - .replaceAll(/\((\{.*\})\:/g, (_, p1) => `(param: /* ${p1} */`) + // .replaceAll(/\((\{.*\})\:/g, (_, p1) => `(param: /* ${p1} */`) // Change `(...): return` which is invalid to `(...) => return` .replace(/^(\(.*\)): /, (_, p1) => `${p1} =>`) .replaceAll(/... (\d{0,}) more .../g, (_, p1) => `___${p1}MORE___`) @@ -64,6 +71,6 @@ const convertToOriginalType = (type: string) => .replaceAll(/___MORE___: (\d{0,});/g, (_, p1) => `... ${p1} more ...;`) .replaceAll(/___(\d{0,})MORE___/g, (_, p1) => `... ${p1} more ...`) .replaceAll(/... (\d{0,}) more .../g, (_, p1) => `/* ${p1} more */`) // ... x more ... not shown sell - .replaceAll(/\(param\: \/\* (\{ .* \}) \*\//g, (_, p1) => `(${p1}: `) + // .replaceAll(/\(param\: \/\* (\{ .* \}) \*\//g, (_, p1) => `(${p1}: `) .replace(/type x =[ ]?((.|\n)*);.*/g, "$1") .trim(); diff --git a/src/test/suite/errorMessageMocks.ts b/src/test/suite/errorMessageMocks.ts index dfab595..6ea4d41 100644 --- a/src/test/suite/errorMessageMocks.ts +++ b/src/test/suite/errorMessageMocks.ts @@ -22,6 +22,11 @@ The 'this' context of type 'ElementHandle' is not assignable to method's ' Type 'Node' is missing the following properties from type 'Element': attributes, classList, className, clientHeight, and 114 more. `; +const errorWithParamsDestructuring = d` +Argument of type '{ $ref: null; ref: (ref: any) => any; columns: ({ label: string; prop: string; } | { label: string; formatter: ({ ip_type }: any) => any; } | { actions: { label: string; disabled: ({ contract_id }: any) => boolean; handler({ contract_id }: any): void; }[]; })[]; ... 4 more ...; load(): Promise<...>; }' is not assignable to parameter of type 'VTableConfig'. + Property 'data' is missing in type '{ $ref: null; ref: (ref: any) => any; columns: ({ label: string; prop: string; } | { label: string; formatter: ({ ip_type }: any) => any; } | { actions: { label: string; disabled: ({ contract_id }: any) => boolean; handler({ contract_id }: any): void; }[]; })[]; ... 4 more ...; load(): Promise<...>; }' but required in type 'VTableConfig'. +`; + const errorWithLongType = d` Property 'isFlying' is missing in type '{ animal: { __typename?: "Animal" | undefined; id: string; name: string; age: number; isAlived: boolean; ... 8 more ...; attributes: { ...; } | ... 3 more ... | { ...; }; }; }' but required in type '{ animal: { __typename?: "Animal" | undefined; id: string; name: string; age: number; isAlived: boolean; isFlying: boolean; ... 8 more ...; attributes: { ...; } | ... 3 more ... | { ...; }; }; }'. `; diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 379e33d..7c6f389 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -6,7 +6,9 @@ import * as vscode from "vscode"; import { inlineCodeBlock } from "../../components"; import { addMissingParentheses } from "../../format/addMissingParentheses"; import { formatDiagnosticMessage } from "../../format/formatDiagnosticMessage"; +import { prettifyType } from "../../format/formatTypeBlock"; import { prettify } from "../../format/prettify"; +import { d } from "../../utils"; import { errorWithDashInObjectKeys, errorWithSpecialCharsInObjectKeys, @@ -28,7 +30,7 @@ suite("Extension Test Suite", () => { "Type " + inlineCodeBlock("string", "type") + " is not assignable to type " + - inlineCodeBlock("{ 'abc*bc': string; }", "type") + + inlineCodeBlock(`{ "abc*bc": string }`, "type") + "." ); }); @@ -37,10 +39,19 @@ suite("Extension Test Suite", () => { assert.strictEqual( formatDiagnosticMessage(errorWithDashInObjectKeys, prettify), "Type " + - inlineCodeBlock("{ person: { 'first-name': string; }; }", "type") + + inlineCodeBlock(`{ person: { "first-name": string } }`, "type") + " is not assignable to type " + inlineCodeBlock("string", "type") + "." ); }); + + test("Formatting type with params destructuring should succeed", () => { + prettifyType( + d` { $ref: null; ref: (ref: any) => any; columns: ({ label: string; prop: string; } | { label: string; formatter: ({ ip_type }: any) => any; } | { actions: { label: string; disabled: ({ contract_id }: any) => boolean; handler({ contract_id }: any): void; }[]; })[]; ... 4 more ...; load(): Promise<...>; } + `, + prettify, + { throwOnError: true } + ); + }); });