diff --git a/package.json b/package.json index db177c3..16704e3 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "unbuild": "^2.0.0", "unplugin-vue-components": "^0.26.0", "vite": "^5.1.0", + "vite-tsconfig-paths": "^4.3.1", "vitest": "^1.2.2", "vue": "^3.4.16" }, diff --git a/packages/twoslash-protocol/LICENSE b/packages/twoslash-protocol/LICENSE new file mode 100644 index 0000000..60b9b29 --- /dev/null +++ b/packages/twoslash-protocol/LICENSE @@ -0,0 +1,18 @@ +The MIT License (MIT) + +Copyright (c) 2024-PRESENT Anthony Fu + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/twoslash-protocol/README.md b/packages/twoslash-protocol/README.md new file mode 100755 index 0000000..30669ed --- /dev/null +++ b/packages/twoslash-protocol/README.md @@ -0,0 +1,30 @@ +Twoslash Logo + +# twoslash-protocol + +[![npm version][npm-version-src]][npm-version-href] +[![npm downloads][npm-downloads-src]][npm-downloads-href] +[![bundle][bundle-src]][bundle-href] +[![JSDocs][jsdocs-src]][jsdocs-href] +[![License][license-src]][license-href] + +[📚 Documentation](https://twoslash.netlify.app/) + +The protocol for Twoslash interface, a universal layer to support different language services that describe common editor features. This package also includes some common utilities for working with the protocol. + +## License + +MIT License © [Anthony Fu](https://github.com/antfu + + + +[npm-version-src]: https://img.shields.io/npm/v/twoslash-protocol?style=flat&colorA=161514&colorB=EAB836 +[npm-version-href]: https://npmjs.com/package/twoslash-protocol +[npm-downloads-src]: https://img.shields.io/npm/dm/twoslash-protocol?style=flat&colorA=161514&colorB=E66041 +[npm-downloads-href]: https://npmjs.com/package/twoslash-protocol +[bundle-src]: https://img.shields.io/bundlephobia/minzip/twoslash-protocol?style=flat&colorA=161514&colorB=45627B&label=minzip +[bundle-href]: https://bundlephobia.com/result?p=twoslash-protocol +[license-src]: https://img.shields.io/github/license/twoslashes/twoslash.svg?style=flat&colorA=161514&colorB=45627B +[license-href]: https://github.com/twoslashes/twoslash/blob/main/LICENSE +[jsdocs-src]: https://img.shields.io/badge/jsdocs-reference-161514?style=flat&colorA=161514&colorB=EAB836 +[jsdocs-href]: https://www.jsdocs.io/package/twoslash-protocol diff --git a/packages/twoslash-protocol/build.config.ts b/packages/twoslash-protocol/build.config.ts new file mode 100644 index 0000000..d3c17be --- /dev/null +++ b/packages/twoslash-protocol/build.config.ts @@ -0,0 +1,13 @@ +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + entries: [ + 'src/index', + 'src/types', + ], + declaration: true, + clean: true, + rollup: { + emitCJS: true, + }, +}) diff --git a/packages/twoslash-protocol/package.json b/packages/twoslash-protocol/package.json new file mode 100755 index 0000000..da93159 --- /dev/null +++ b/packages/twoslash-protocol/package.json @@ -0,0 +1,50 @@ +{ + "name": "twoslash-protocol", + "type": "module", + "version": "0.1.2", + "description": "The protocol for the Twoslash interface", + "author": "Anthony Fu", + "license": "MIT", + "homepage": "https://github.com/twoslashes/twoslash", + "repository": { + "url": "https://github.com/twoslashes/twoslash", + "type": "git", + "directory": "packages/twoslash-protocol" + }, + "bugs": { + "url": "https://github.com/twoslashes/twoslash/issues" + }, + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.cjs" + }, + "./types": { + "types": "./dist/types.d.mts", + "import": "./dist/types.mjs", + "require": "./dist/types.cjs" + } + }, + "main": "dist/index.mjs", + "module": "dist/index.mjs", + "types": "dist/index.d.mts", + "typesVersions": { + "*": { + "./types": ["./dist/types.d.mts"], + "*": ["./dist/index.d.mts"] + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "unbuild", + "prepublishOnly": "nr build" + }, + "simple-git-hooks": { + "pre-commit": "pnpm lint-staged" + }, + "lint-staged": { + "*": "eslint --fix" + } +} diff --git a/packages/twoslash-protocol/src/index.ts b/packages/twoslash-protocol/src/index.ts new file mode 100644 index 0000000..ce4acb5 --- /dev/null +++ b/packages/twoslash-protocol/src/index.ts @@ -0,0 +1,2 @@ +export * from './types' +export * from './utils' diff --git a/packages/twoslash-protocol/src/types.ts b/packages/twoslash-protocol/src/types.ts new file mode 100644 index 0000000..679c9fc --- /dev/null +++ b/packages/twoslash-protocol/src/types.ts @@ -0,0 +1 @@ +export * from './types/index' diff --git a/packages/twoslash-protocol/src/types/index.ts b/packages/twoslash-protocol/src/types/index.ts new file mode 100644 index 0000000..ed0efaf --- /dev/null +++ b/packages/twoslash-protocol/src/types/index.ts @@ -0,0 +1,2 @@ +export * from './nodes' +export * from './returns' diff --git a/packages/twoslash/src/types/nodes.ts b/packages/twoslash-protocol/src/types/nodes.ts similarity index 90% rename from packages/twoslash/src/types/nodes.ts rename to packages/twoslash-protocol/src/types/nodes.ts index e5f04f5..103f026 100644 --- a/packages/twoslash/src/types/nodes.ts +++ b/packages/twoslash-protocol/src/types/nodes.ts @@ -1,5 +1,3 @@ -import type { CompletionEntry } from 'typescript' - /** * Basic node with start and length to represent a range in the code */ @@ -36,6 +34,11 @@ export interface NodeQuery extends Omit { type: 'query' } +export interface CompletionEntry { + name: string + kind?: string +} + export interface NodeCompletion extends NodeBase { type: 'completion' /** Results for completions at a particular point */ @@ -44,22 +47,20 @@ export interface NodeCompletion extends NodeBase { completionsPrefix: string } +export type ErrorLevel = 'warning' | 'error' | 'suggestion' | 'message' + export interface NodeError extends NodeBase { type: 'error' id?: string /** - * Error level: - * - * Warning = 0 - * Error = 1 - * Suggestion = 2 - * Message = 3 + * Error level + * When not provided, defaults to 'error' */ - level?: 0 | 1 | 2 | 3 + level?: ErrorLevel /** * Error code */ - code: number + code?: number | string /** * Error message */ diff --git a/packages/twoslash-protocol/src/types/returns.ts b/packages/twoslash-protocol/src/types/returns.ts new file mode 100644 index 0000000..08c521a --- /dev/null +++ b/packages/twoslash-protocol/src/types/returns.ts @@ -0,0 +1,20 @@ +import type { TwoslashNode } from './nodes' + +export interface TwoslashGenericResult { + /** + * The output code, could be TypeScript, but could also be a JS/JSON/d.ts + */ + code: string + + /** + * Extension of the output code + */ + extension?: string + + /** + * Nodes containing various bits of information about the code + */ + nodes: TwoslashNode[] +} + +export type TwoslashGenericFunction = (code: string, filename?: string, options?: Options) => TwoslashGenericResult diff --git a/packages/twoslash-protocol/src/utils.ts b/packages/twoslash-protocol/src/utils.ts new file mode 100644 index 0000000..a6530e4 --- /dev/null +++ b/packages/twoslash-protocol/src/utils.ts @@ -0,0 +1,139 @@ +import type { NodeStartLength, NodeWithoutPosition, Position, Range, TwoslashNode } from './types' + +export function isInRange(index: number, range: Range) { + return range[0] <= index && index <= range[1] +} + +export function isInRanges(index: number, ranges: Range[]) { + return ranges.find(range => isInRange(index, range)) +} + +/** + * Merge overlapping ranges + */ +export function mergeRanges(ranges: Range[]) { + ranges.sort((a, b) => a[0] - b[0]) + const merged: Range[] = [] + for (const range of ranges) { + const last = merged[merged.length - 1] + if (last && last[1] >= range[0]) + last[1] = Math.max(last[1], range[1]) + else + merged.push(range) + } + return merged +} + +/** + * Slipt a string into lines, each line preserves the line ending. + */ +export function splitLines(code: string, preserveEnding = false): [string, number][] { + const parts = code.split(/(\r?\n)/g) + let index = 0 + const lines: [string, number][] = [] + for (let i = 0; i < parts.length; i += 2) { + const line = preserveEnding + ? parts[i] + (parts[i + 1] || '') + : parts[i] + lines.push([line, index]) + index += parts[i].length + index += parts[i + 1]?.length || 0 + } + return lines +} + +/** + * Creates a converter between index and position in a code block. + */ +export function createPositionConverter(code: string) { + const lines = splitLines(code, true).map(([line]) => line) + + function indexToPos(index: number): Position { + let character = index + let line = 0 + for (const lineText of lines) { + if (character < lineText.length) + break + character -= lineText.length + line++ + } + return { line, character } + } + + function posToIndex(line: number, character: number) { + let index = 0 + for (let i = 0; i < line; i++) + index += lines[i].length + + index += character + return index + } + + return { + lines, + indexToPos, + posToIndex, + } +} + +/** + * Remove ranages for a string, and update nodes' `start` property accordingly + * + * Note that items in `nodes` will be mutated + */ +export function removeCodeRanges(code: string, removals: Range[], nodes: T[]): { code: string, removals: Range[], nodes: T[] } +export function removeCodeRanges(code: string, removals: Range[]): { code: string, removals: Range[], nodes: undefined } +export function removeCodeRanges(code: string, removals: Range[], nodes?: NodeStartLength[]) { + // Sort descending, so that we start removal from the end + const ranges = mergeRanges(removals) + .sort((a, b) => b[0] - a[0]) + + let outputCode = code + for (const remove of ranges) { + const removalLength = remove[1] - remove[0] + outputCode = outputCode.slice(0, remove[0]) + outputCode.slice(remove[1]) + nodes?.forEach((node) => { + // nodes before the range, do nothing + if (node.start + node.length <= remove[0]) + return undefined + + // remove nodes that are within in the range + else if (node.start < remove[1]) + node.start = -1 + + // move nodes after the range forward + else + node.start -= removalLength + }) + } + + return { + code: outputCode, + removals: ranges, + nodes, + } +} + +/** + * - Calculate nodes `line` and `character` properties to match the code + * - Remove nodes that has negative `start` property + * - Sort nodes by `start` + * + * Note that the nodes items will be mutated, clone them beforehand if not desired + */ +export function resolveNodePositions(nodes: NodeWithoutPosition[], code: string): TwoslashNode[] +export function resolveNodePositions(nodes: NodeWithoutPosition[], indexToPos: (index: number) => Position): TwoslashNode[] +export function resolveNodePositions(nodes: NodeWithoutPosition[], options: string | ((index: number) => Position)): TwoslashNode[] { + const indexToPos = typeof options === 'string' + ? createPositionConverter(options).indexToPos + : options + + const resolved = nodes + .filter(node => node.start >= 0) + .sort((a, b) => a.start - b.start || a.type.localeCompare(b.type)) as TwoslashNode[] + + resolved + .forEach(node => Object.assign(node, indexToPos(node.start))) + + return resolved +} diff --git a/packages/twoslash-vue/package.json b/packages/twoslash-vue/package.json index 39680bb..b39fb19 100644 --- a/packages/twoslash-vue/package.json +++ b/packages/twoslash-vue/package.json @@ -51,6 +51,7 @@ }, "dependencies": { "@vue/language-core": "^1.8.27", - "twoslash": "workspace:*" + "twoslash": "workspace:*", + "twoslash-protocol": "workspace:*" } } diff --git a/packages/twoslash-vue/src/index.ts b/packages/twoslash-vue/src/index.ts index 6b724c4..1dd55b9 100644 --- a/packages/twoslash-vue/src/index.ts +++ b/packages/twoslash-vue/src/index.ts @@ -13,16 +13,18 @@ import type { TwoslashReturnMeta, } from 'twoslash' import { - createPositionConverter, createTwoslasher as createTwoslasherBase, defaultCompilerOptions, defaultHandbookOptions, findFlagNotations, findQueryMarkers, getObjectHash, +} from 'twoslash' +import { + createPositionConverter, removeCodeRanges, resolveNodePositions, -} from 'twoslash' +} from 'twoslash-protocol' export interface VueSpecificOptions { /** diff --git a/packages/twoslash/package.json b/packages/twoslash/package.json index 3be2ba2..aa5941c 100755 --- a/packages/twoslash/package.json +++ b/packages/twoslash/package.json @@ -38,7 +38,8 @@ "typescript": "*" }, "dependencies": { - "@typescript/vfs": "1.5.0" + "@typescript/vfs": "1.5.0", + "twoslash-protocol": "workspace:*" }, "devDependencies": { "ohash": "^1.1.3" diff --git a/packages/twoslash/src/core.ts b/packages/twoslash/src/core.ts index 6e72fab..a31a0df 100644 --- a/packages/twoslash/src/core.ts +++ b/packages/twoslash/src/core.ts @@ -1,10 +1,12 @@ -import type { CompilerOptions, CompletionEntry, CompletionTriggerKind, JsxEmit } from 'typescript' +import type { CompilerOptions, CompletionEntry, CompletionTriggerKind, DiagnosticCategory, JsxEmit } from 'typescript' import { createFSBackedSystem, createSystem, createVirtualTypeScriptEnvironment } from '@typescript/vfs' +import type { ErrorLevel, NodeError, NodeWithoutPosition, Position, Range } from 'twoslash-protocol' +import { createPositionConverter, isInRange, isInRanges, removeCodeRanges, resolveNodePositions } from 'twoslash-protocol' import { TwoslashError } from './error' -import type { CompilerOptionDeclaration, CreateTwoslashOptions, NodeError, NodeWithoutPosition, Position, Range, TwoslashExecuteOptions, TwoslashInstance, TwoslashOptions, TwoslashReturn, TwoslashReturnMeta, VirtualFile } from './types' -import { createPositionConverter, findCutNotations, findFlagNotations, findQueryMarkers, getExtension, getIdentifierTextSpans, getObjectHash, isInRange, isInRanges, removeCodeRanges, removeTsExtension, resolveNodePositions, splitFiles, typesToExtension } from './utils' import { validateCodeForErrors } from './validation' import { defaultCompilerOptions, defaultHandbookOptions } from './defaults' +import type { CompilerOptionDeclaration, CreateTwoslashOptions, TwoslashExecuteOptions, TwoslashInstance, TwoslashOptions, TwoslashReturn, TwoslashReturnMeta, VirtualFile } from './types' +import { findCutNotations, findFlagNotations, findQueryMarkers, getExtension, getIdentifierTextSpans, getObjectHash, removeTsExtension, splitFiles, typesToExtension } from './utils' export * from './public' @@ -377,7 +379,7 @@ export function createTwoslasher(createOptions: CreateTwoslashOptions = {}): Two filename: file.filename, id: `err-${diagnostic.code}-${start}-${diagnostic.length}`, text: ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'), - level: diagnostic.category, + level: diagnosticCategoryToErrorLevel(diagnostic.category), }) } } @@ -513,3 +515,18 @@ export function twoslasher(code: string, lang?: string, opts?: Partial ({ id: e.id ?? '', - code: e.code, + code: e.code as number, start: e.start, length: e.length, line: e.line, character: e.character, renderedMessage: e.text, - category: e.level ?? 1, + category: errorLevelToCategory(e.level), })), playgroundURL: '', } } + +function errorLevelToCategory(level?: ErrorLevel) { + switch (level) { + case 'warning': return 0 + case 'suggestion': return 2 + case 'message': return 3 + case 'error': return 1 + } + return 1 +} diff --git a/packages/twoslash/src/public.ts b/packages/twoslash/src/public.ts index 21ffb1c..7add2c5 100644 --- a/packages/twoslash/src/public.ts +++ b/packages/twoslash/src/public.ts @@ -5,15 +5,9 @@ export * from './types' export * from './defaults' export { - createPositionConverter, - findCutNotations, findFlagNotations, findQueryMarkers, - - removeCodeRanges, - resolveNodePositions, - getObjectHash, } from './utils' diff --git a/packages/twoslash/src/types/index.ts b/packages/twoslash/src/types/index.ts index 94d887a..a778d37 100644 --- a/packages/twoslash/src/types/index.ts +++ b/packages/twoslash/src/types/index.ts @@ -1,5 +1,5 @@ export * from './instance' -export * from './nodes' export * from './options' export * from './returns' export * from './handbook-options' +export * from 'twoslash-protocol/types' diff --git a/packages/twoslash/src/types/options.ts b/packages/twoslash/src/types/options.ts index 7c51440..a43faa7 100644 --- a/packages/twoslash/src/types/options.ts +++ b/packages/twoslash/src/types/options.ts @@ -1,7 +1,7 @@ import type { VirtualTypeScriptEnvironment } from '@typescript/vfs' import type { CompilerOptions, CustomTransformers } from 'typescript' +import type { NodeWithoutPosition } from 'twoslash-protocol' import type { HandbookOptions } from './handbook-options' -import type { NodeWithoutPosition } from './nodes' import type { TwoslashReturnMeta } from './returns' export type TS = typeof import('typescript') diff --git a/packages/twoslash/src/types/returns.ts b/packages/twoslash/src/types/returns.ts index 258b6e1..a8abd63 100644 --- a/packages/twoslash/src/types/returns.ts +++ b/packages/twoslash/src/types/returns.ts @@ -1,18 +1,8 @@ import type { CompilerOptions } from 'typescript' +import type { NodeCompletion, NodeError, NodeHighlight, NodeHover, NodeQuery, NodeTag, Range, TwoslashGenericResult } from 'twoslash-protocol' import type { HandbookOptions } from './handbook-options' -import type { NodeCompletion, NodeError, NodeHighlight, NodeHover, NodeQuery, NodeTag, Range, TwoslashNode } from './nodes' - -export interface TwoslashReturn { - /** - * The output code, could be TypeScript, but could also be a JS/JSON/d.ts - */ - code: string - - /** - * Nodes containing various bits of information about the code - */ - nodes: TwoslashNode[] +export interface TwoslashReturn extends TwoslashGenericResult { /** * The meta information the twoslash run */ diff --git a/packages/twoslash/src/utils.ts b/packages/twoslash/src/utils.ts index ef9d863..cd33aae 100644 --- a/packages/twoslash/src/utils.ts +++ b/packages/twoslash/src/utils.ts @@ -1,7 +1,8 @@ import type { SourceFile } from 'typescript' import { objectHash } from 'ohash' +import type { Range, createPositionConverter } from 'twoslash-protocol' import { TwoslashError } from './error' -import type { CompilerOptionDeclaration, NodeStartLength, NodeWithoutPosition, ParsedFlagNotation, Position, Range, TwoslashNode, TwoslashReturnMeta, VirtualFile } from './types' +import type { CompilerOptionDeclaration, ParsedFlagNotation, TwoslashReturnMeta, VirtualFile } from './types' import { defaultHandbookOptions } from './defaults' import { reAnnonateMarkers, reConfigBoolean, reConfigValue, reCutAfter, reCutBefore, reCutEnd, reCutStart } from './regexp' @@ -75,34 +76,6 @@ export function getIdentifierTextSpans(ts: typeof import('typescript'), sourceFi } } -export function isInRange(index: number, range: Range) { - return range[0] <= index && index <= range[1] -} - -export function isInRanges(index: number, ranges: Range[]) { - return ranges.find(range => isInRange(index, range)) -} - -export function areRangesIntersecting(a: Range, b: Range) { - return isInRange(a[0], b) || isInRange(a[1], b) || isInRange(b[0], a) || isInRange(b[1], a) -} - -/** - * Merge overlapping ranges - */ -export function mergeRanges(ranges: Range[]) { - ranges.sort((a, b) => a[0] - b[0]) - const merged: Range[] = [] - for (const range of ranges) { - const last = merged[merged.length - 1] - if (last && last[1] >= range[0]) - last[1] = Math.max(last[1], range[1]) - else - merged.push(range) - } - return merged -} - export function getOptionValueFromMap(name: string, key: string, optMap: Map) { const result = optMap.get(key.toLowerCase()) if (result === undefined) { @@ -117,40 +90,6 @@ export function getOptionValueFromMap(name: string, key: string, optMap: Map match[0]) - - function indexToPos(index: number): Position { - let character = index - let line = 0 - for (const lineText of lines) { - if (character < lineText.length) - break - character -= lineText.length - line++ - } - return { line, character } - } - - function posToIndex(line: number, character: number) { - let index = 0 - for (let i = 0; i < line; i++) - index += lines[i].length - - index += character - return index - } - - return { - lines, - indexToPos, - posToIndex, - } -} - const reFilenamesMakers = /^\/\/\s?@filename: (.+)$/mg export function splitFiles(code: string, defaultFileName: string, root: string) { @@ -196,68 +135,6 @@ export function getExtension(fileName: string) { return fileName.split('.').pop()! } -/** - * Remove ranages for a string, and update nodes' `start` property accordingly - * - * Note that items in `nodes` will be mutated - */ -export function removeCodeRanges(code: string, removals: Range[], nodes: T[]): { code: string, removals: Range[], nodes: T[] } -export function removeCodeRanges(code: string, removals: Range[]): { code: string, removals: Range[], nodes: undefined } -export function removeCodeRanges(code: string, removals: Range[], nodes?: NodeStartLength[]) { - // Sort descending, so that we start removal from the end - const ranges = mergeRanges(removals) - .sort((a, b) => b[0] - a[0]) - - let outputCode = code - for (const remove of ranges) { - const removalLength = remove[1] - remove[0] - outputCode = outputCode.slice(0, remove[0]) + outputCode.slice(remove[1]) - nodes?.forEach((node) => { - // nodes before the range, do nothing - if (node.start + node.length <= remove[0]) - return undefined - - // remove nodes that are within in the range - else if (node.start < remove[1]) - node.start = -1 - - // move nodes after the range forward - else - node.start -= removalLength - }) - } - - return { - code: outputCode, - removals: ranges, - nodes, - } -} - -/** - * - Calculate nodes `line` and `character` properties to match the code - * - Remove nodes that has negative `start` property - * - Sort nodes by `start` - * - * Note that the nodes items will be mutated, clone them beforehand if not desired - */ -export function resolveNodePositions(nodes: NodeWithoutPosition[], code: string): TwoslashNode[] -export function resolveNodePositions(nodes: NodeWithoutPosition[], indexToPos: (index: number) => Position): TwoslashNode[] -export function resolveNodePositions(nodes: NodeWithoutPosition[], options: string | ((index: number) => Position)): TwoslashNode[] { - const indexToPos = typeof options === 'string' - ? createPositionConverter(options).indexToPos - : options - - const resolved = nodes - .filter(node => node.start >= 0) - .sort((a, b) => a.start - b.start || a.type.localeCompare(b.type)) as TwoslashNode[] - - resolved - .forEach(node => Object.assign(node, indexToPos(node.start))) - - return resolved -} - export function parseFlag( name: string, value: any, diff --git a/packages/twoslash/src/validation.ts b/packages/twoslash/src/validation.ts index e80c1ba..dca8a3d 100644 --- a/packages/twoslash/src/validation.ts +++ b/packages/twoslash/src/validation.ts @@ -1,4 +1,4 @@ -import type { NodeErrorWithoutPosition } from './types' +import type { NodeErrorWithoutPosition } from 'twoslash-protocol' import { TwoslashError } from './error' /** To ensure that errors are matched up right */ diff --git a/packages/twoslash/test/results/examples/compiler-errors.json b/packages/twoslash/test/results/examples/compiler-errors.json index c305122..2aadb06 100644 --- a/packages/twoslash/test/results/examples/compiler-errors.json +++ b/packages/twoslash/test/results/examples/compiler-errors.json @@ -18,7 +18,7 @@ "filename": "index.ts", "id": "err-7006-49-1", "text": "Parameter 's' implicitly has an 'any' type.", - "level": 1, + "level": "error", "line": 1, "character": 12 }, diff --git a/packages/twoslash/test/results/examples/errors-with-generics.json b/packages/twoslash/test/results/examples/errors-with-generics.json index a0f7fb1..ddd9756 100644 --- a/packages/twoslash/test/results/examples/errors-with-generics.json +++ b/packages/twoslash/test/results/examples/errors-with-generics.json @@ -47,7 +47,7 @@ "filename": "index.ts", "id": "err-2322-89-1", "text": "Type 'Record' is not assignable to type 'Record'.\n 'string' index signatures are incompatible.\n Type 'string' is not assignable to type 'number'.", - "level": 1, + "level": "error", "line": 2, "character": 0 }, diff --git a/packages/twoslash/test/results/examples/multi-file-errors.json b/packages/twoslash/test/results/examples/multi-file-errors.json index d0439a9..cfe2a3e 100644 --- a/packages/twoslash/test/results/examples/multi-file-errors.json +++ b/packages/twoslash/test/results/examples/multi-file-errors.json @@ -90,7 +90,7 @@ "filename": "error.ts", "id": "err-2345-225-7", "text": "Argument of type 'string' is not assignable to parameter of type 'number'.", - "level": 1, + "level": "error", "line": 11, "character": 7 } diff --git a/packages/twoslash/test/results/tests/cut-file-errors.json b/packages/twoslash/test/results/tests/cut-file-errors.json index d77c2b8..b4d5956 100644 --- a/packages/twoslash/test/results/tests/cut-file-errors.json +++ b/packages/twoslash/test/results/tests/cut-file-errors.json @@ -81,7 +81,7 @@ "filename": "index.ts", "id": "err-2339-599-4", "text": "Property 'code' does not exist on type 'NetworkState'.\n Property 'code' does not exist on type 'NetworkLoadingState'.", - "level": 1, + "level": "error", "line": 8, "character": 8 }, diff --git a/packages/twoslash/test/results/tests/files-with-json.json b/packages/twoslash/test/results/tests/files-with-json.json index 4a9444e..7b4824b 100644 --- a/packages/twoslash/test/results/tests/files-with-json.json +++ b/packages/twoslash/test/results/tests/files-with-json.json @@ -36,7 +36,7 @@ "filename": "index.ts", "id": "err-2367-271-18", "text": "This comparison appears to be unintentional because the types 'boolean' and 'number' have no overlap.", - "level": 1, + "level": "error", "line": 10, "character": 0 }, diff --git a/packages/twoslash/test/results/tests/large-cut.json b/packages/twoslash/test/results/tests/large-cut.json index 793e5dc..83e01f0 100644 --- a/packages/twoslash/test/results/tests/large-cut.json +++ b/packages/twoslash/test/results/tests/large-cut.json @@ -81,7 +81,7 @@ "filename": "index.ts", "id": "err-2339-609-4", "text": "Property 'code' does not exist on type 'NetworkState'.\n Property 'code' does not exist on type 'NetworkLoadingState'.", - "level": 1, + "level": "error", "line": 8, "character": 8 }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a1b886..4fe8fd9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -114,6 +114,9 @@ importers: vite: specifier: ^5.1.0 version: 5.1.0(@types/node@20.11.16)(sass@1.70.0) + vite-tsconfig-paths: + specifier: ^4.3.1 + version: 4.3.1(typescript@5.3.3)(vite@5.1.0) vitest: specifier: ^1.2.2 version: 1.2.2(@types/node@20.11.16) @@ -153,6 +156,9 @@ importers: '@typescript/vfs': specifier: 1.5.0 version: 1.5.0 + twoslash-protocol: + specifier: workspace:* + version: link:../twoslash-protocol typescript: specifier: '*' version: 5.3.3 @@ -208,6 +214,8 @@ importers: specifier: ^5.1.0 version: 5.1.0(@types/node@20.11.16)(sass@1.70.0) + packages/twoslash-protocol: {} + packages/twoslash-vue: dependencies: '@vue/language-core': @@ -216,6 +224,9 @@ importers: twoslash: specifier: workspace:* version: link:../twoslash + twoslash-protocol: + specifier: workspace:* + version: link:../twoslash-protocol typescript: specifier: '*' version: 5.3.3 @@ -3885,6 +3896,10 @@ packages: slash: 4.0.0 dev: true + /globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + dev: true + /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: true @@ -6093,6 +6108,19 @@ packages: typescript: 5.3.3 dev: true + /tsconfck@3.0.2(typescript@5.3.3): + resolution: {integrity: sha512-6lWtFjwuhS3XI4HsX4Zg0izOI3FU/AI9EGVlPEUMDIhvLPMD4wkiof0WCoDgW7qY+Dy198g4d9miAqUHWHFH6Q==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.3.3 + dev: true + /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true @@ -6490,6 +6518,23 @@ packages: - terser dev: true + /vite-tsconfig-paths@4.3.1(typescript@5.3.3)(vite@5.1.0): + resolution: {integrity: sha512-cfgJwcGOsIxXOLU/nELPny2/LUD/lcf1IbfyeKTv2bsupVbTH/xpFtdQlBmIP1GEK2CjjLxYhFfB+QODFAx5aw==} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true + dependencies: + debug: 4.3.4 + globrex: 0.1.2 + tsconfck: 3.0.2(typescript@5.3.3) + vite: 5.1.0(@types/node@20.11.16)(sass@1.70.0) + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /vite@5.1.0(@types/node@20.11.16)(sass@1.70.0): resolution: {integrity: sha512-STmSFzhY4ljuhz14bg9LkMTk3d98IO6DIArnTY6MeBwiD1Za2StcQtz7fzOUnRCqrHSD5+OS2reg4HOz1eoLnw==} engines: {node: ^18.0.0 || >=20.0.0} diff --git a/tsconfig.json b/tsconfig.json index ea59fb4..20e3cba 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,6 +12,12 @@ "paths": { "twoslash": [ "./packages/twoslash/src/index.ts" + ], + "twoslash-protocol/types": [ + "./packages/twoslash-protocol/src/types.ts" + ], + "twoslash-protocol": [ + "./packages/twoslash-protocol/src/index.ts" ] }, "resolveJsonModule": true, diff --git a/vitest.config.ts b/vitest.config.ts index 99bd61a..156359a 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,12 +1,10 @@ -import { fileURLToPath } from 'node:url' import { defineConfig } from 'vitest/config' +import tsconfigPaths from 'vite-tsconfig-paths' export default defineConfig({ - resolve: { - alias: { - twoslash: fileURLToPath(new URL('./packages/twoslash/src/index.ts', import.meta.url)), - }, - }, + plugins: [ + tsconfigPaths(), + ], test: { benchmark: { // reporters: ['default', 'json'],