feature: vor und nachteile

This commit is contained in:
Hikyu
2026-05-31 13:54:31 +02:00
parent 552a947a1c
commit e3dad17446
23270 changed files with 3024794 additions and 200 deletions
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2021 Pine Wu
Copyright (c) 2023 Anthony Fu <https://github.com/antfu>
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.
+9
View File
@@ -0,0 +1,9 @@
# @shikijs/twoslash
A [shiki](https://github.com/shikijs/shiki) transformer for [TypeScript Twoslash](https://www.typescriptlang.org/dev/twoslash/).
[Documentations](https://shiki.style/packages/twoslash)
## License
MIT
+289
View File
@@ -0,0 +1,289 @@
import { CodeToHastOptions, ShikiTransformerContext, ShikiTransformerContextCommon, ShikiTransformer } from '@shikijs/types';
import { TwoslashReturn, TwoslashExecuteOptions, TwoslashGenericFunction, TwoslashOptions, NodeError, NodeTag, NodeQuery, NodeCompletion, NodeHover, NodeHighlight } from 'twoslash';
import { ElementContent, Element, Text } from 'hast';
type TwoslashShikiReturn = Pick<TwoslashReturn, 'nodes' | 'code'> & {
meta?: Partial<Pick<TwoslashReturn['meta'], 'extension'>>;
};
type TwoslashShikiFunction = (code: string, lang?: string, options?: TwoslashExecuteOptions) => TwoslashShikiReturn;
declare module '@shikijs/core' {
interface ShikiTransformerContextMeta {
twoslash?: TwoslashShikiReturn;
}
}
interface TransformerTwoslashOptions {
/**
* Languages to apply this transformer to
*/
langs?: string[];
/**
* Requires `twoslash` to be presented in the code block meta to apply this transformer
*
* @default false
*/
explicitTrigger?: boolean | RegExp;
/**
* Triggers that skip Twoslash transformation on the code block meta
*
* @default ['notwoslash', 'no-twoslash']
*/
disableTriggers?: (string | RegExp)[];
/**
* Mapping from language alias to language name
*/
langAlias?: Record<string, string>;
/**
* Custom filter function to apply this transformer to
* When specified, `langs`, `explicitTrigger`, and `disableTriggers` will be ignored
*/
filter?: (lang: string, code: string, options: CodeToHastOptions) => boolean;
/**
* Custom instance of twoslasher function
*/
twoslasher?: TwoslashShikiFunction | TwoslashGenericFunction;
/**
* Options to pass to twoslash
*/
twoslashOptions?: TwoslashOptions;
/**
* Custom renderers to decide how each info should be rendered
*/
renderer?: TwoslashRenderer;
/**
* A map to store code for `@include` directive
* Provide your own instance if you want to clear the map between each transformation
*/
includesMap?: Map<string, string>;
/**
* Strictly throw when there is an error
* @default true
*/
throws?: boolean;
/**
* Custom error handler for twoslash errors
* When specified, `throws` will be ignored
* Optionally return a string to replace the code
*/
onTwoslashError?: (error: unknown, code: string, lang: string, options: CodeToHastOptions) => string | void;
/**
* Custom error handler for Shiki errors
* When specified, `throws` will be ignored
*/
onShikiError?: (error: unknown, code: string, lang: string) => void;
}
interface TwoslashRenderer {
lineError?: (this: ShikiTransformerContext, error: NodeError) => ElementContent[];
lineCustomTag?: (this: ShikiTransformerContext, tag: NodeTag) => ElementContent[];
lineQuery?: (this: ShikiTransformerContext, query: NodeQuery, targetNode?: Element | Text) => ElementContent[];
lineCompletion?: (this: ShikiTransformerContext, query: NodeCompletion) => ElementContent[];
nodeStaticInfo: (this: ShikiTransformerContext, info: NodeHover, node: Element | Text) => Partial<ElementContent>;
nodeError?: (this: ShikiTransformerContext, error: NodeError, node: Element | Text) => Partial<ElementContent>;
nodeQuery?: (this: ShikiTransformerContext, query: NodeQuery, node: Element | Text) => Partial<ElementContent>;
nodeCompletion?: (this: ShikiTransformerContext, query: NodeCompletion, node: Element | Text) => Partial<ElementContent>;
nodesError?: (this: ShikiTransformerContext, error: NodeError, nodes: ElementContent[]) => ElementContent[];
nodesHighlight?: (this: ShikiTransformerContext, highlight: NodeHighlight, nodes: ElementContent[]) => ElementContent[];
}
declare class ShikiTwoslashError extends Error {
constructor(message: string);
}
type CompletionItem = NonNullable<NodeCompletion['completions']>[number];
declare const defaultCompletionIcons: Record<string, Element | undefined>;
declare const defaultCustomTagIcons: Record<string, Element | undefined>;
/**
* The default renderer aligning with the original `@shikijs/twoslash` output.
*/
declare function rendererClassic(): TwoslashRenderer;
interface RendererRichOptions {
/**
* Render JSDoc comments in hover popup.
*
* @default true
*/
jsdoc?: boolean;
/**
* Custom icons for completion items.
* A map from completion item kind to a HAST node.
*
* If `false`, no icons will be rendered.
* @default defaultCompletionIcons
*/
completionIcons?: Partial<Record<string, ElementContent>> | false;
/**
* Custom icons for custom tags lines.
* A map from tag name to a HAST node.
*
* If `false`, no icons will be rendered.
* @default defaultCustomTagIcons
*/
customTagIcons?: Partial<Record<string, ElementContent>> | false;
/**
* Custom formatter for the type info text.
* Note that it might not be valid TypeScript syntax.
*
* @default defaultHoverInfoProcessor
*/
processHoverInfo?: (info: string) => string;
/**
* Custom formatter for the docs text (can be markdown).
*
* @default undefined
*/
processHoverDocs?: (docs: string) => string;
/**
* The way errors should be rendered.
*
* - `'line'`: Render the error line after the line of code
* - `'hover'`: Render the error in the hover popup
*
* @default 'line'
*/
errorRendering?: 'line' | 'hover';
/**
* Classes added to injected elements
*/
classExtra?: string;
/**
* Language for syntax highlight.
* @default the language of the code block
*/
lang?: string;
/**
* Custom function to render markdown.
*
* By default it pass-through the markdown.
*/
renderMarkdown?: (this: ShikiTransformerContextCommon, markdown: string) => ElementContent[];
/**
* Custom function to render inline markdown.
*
* By default it pass-through the markdown.
*/
renderMarkdownInline?: (this: ShikiTransformerContextCommon, markdown: string, context: string) => ElementContent[];
/**
* The way query should be rendered.
* - `'popup'`: Render the query in the absolute popup
* - `'line'`: Render the query line after the line of code
* @default 'popup'
*/
queryRendering?: 'popup' | 'line';
/**
* Extensions for the genreated HAST tree.
*/
hast?: {
/**
* The <code> block for in the hover popup.
*/
popupTypes?: HastExtension;
/**
* The documentation block in the hover popup. Can be markdown rendered if `renderMarkdown` is provided.
*/
popupDocs?: HastExtension;
/**
* The container of jsdoc tags in the hover popup.
*/
popupDocsTags?: HastExtension;
/**
* The token for the hover informaton.
*/
hoverToken?: HastExtension;
/**
* The container of the hover popup.
*/
hoverPopup?: HastExtension;
/**
* The container of error popup.
*/
popupError?: HastExtension;
/**
* Custom function to compose the hover token.
*/
hoverCompose?: (parts: {
popup: Element;
token: Text | Element;
}) => ElementContent[];
/**
* The token for the query informaton.
*/
queryToken?: HastExtension;
/**
* The container of the query popup.
*/
queryPopup?: HastExtension;
/**
* Custom function to compose the hover token.
*/
queryCompose?: (parts: {
popup: Element;
token: Text | Element;
}) => ElementContent[];
/**
* The token for the completion informaton.
*/
completionToken?: HastExtension;
/**
* The cursor element in the completion popup.
*/
completionCursor?: HastExtension;
/**
* The container of the completion popup.
*/
completionPopup?: HastExtension;
/**
* Custom function to compose the completion token.
*/
completionCompose?: (parts: {
popup: Element;
cursor: Element;
}) => ElementContent[];
/**
* The token for the error informaton.
*/
errorToken?: HastExtension;
/**
* The container of the error popup.
* Only used when `errorRendering` is set to `'hover'`.
*/
errorPopup?: HastExtension;
/**
* Custom function to compose the error token.
* Only used when `errorRendering` is set to `'hover'`.
*/
errorCompose?: (parts: {
popup: Element;
token: Text | Element;
}) => ElementContent[];
/**
* The wrapper for the highlighted nodes.
*/
nodesHighlight?: HastExtension;
};
}
interface HastExtension {
tagName?: string;
properties?: Element['properties'];
class?: string;
children?: (input: ElementContent[]) => ElementContent[];
}
/**
* An alternative renderer that providers better prefixed class names,
* with syntax highlight for the info text.
*/
declare function rendererRich(options?: RendererRichOptions): TwoslashRenderer;
/**
* The default hover info processor, which will do some basic cleanup
*/
declare function defaultHoverInfoProcessor(type: string): string;
/**
* This file is the core of the @shikijs/twoslash package,
* Decoupled from twoslash's implementation and allowing to introduce custom implementation or cache system.
*/
declare function defaultTwoslashOptions(): TwoslashExecuteOptions;
declare function createTransformerFactory(defaultTwoslasher: TwoslashShikiFunction | TwoslashGenericFunction, defaultRenderer?: TwoslashRenderer): (options?: TransformerTwoslashOptions) => ShikiTransformer;
export { type CompletionItem, type HastExtension, type RendererRichOptions, ShikiTwoslashError, type TransformerTwoslashOptions, type TwoslashRenderer, type TwoslashShikiFunction, type TwoslashShikiReturn, createTransformerFactory, defaultCompletionIcons, defaultCustomTagIcons, defaultHoverInfoProcessor, defaultTwoslashOptions, rendererClassic, rendererRich };
+289
View File
@@ -0,0 +1,289 @@
import { CodeToHastOptions, ShikiTransformerContext, ShikiTransformerContextCommon, ShikiTransformer } from '@shikijs/types';
import { TwoslashReturn, TwoslashExecuteOptions, TwoslashGenericFunction, TwoslashOptions, NodeError, NodeTag, NodeQuery, NodeCompletion, NodeHover, NodeHighlight } from 'twoslash';
import { ElementContent, Element, Text } from 'hast';
type TwoslashShikiReturn = Pick<TwoslashReturn, 'nodes' | 'code'> & {
meta?: Partial<Pick<TwoslashReturn['meta'], 'extension'>>;
};
type TwoslashShikiFunction = (code: string, lang?: string, options?: TwoslashExecuteOptions) => TwoslashShikiReturn;
declare module '@shikijs/core' {
interface ShikiTransformerContextMeta {
twoslash?: TwoslashShikiReturn;
}
}
interface TransformerTwoslashOptions {
/**
* Languages to apply this transformer to
*/
langs?: string[];
/**
* Requires `twoslash` to be presented in the code block meta to apply this transformer
*
* @default false
*/
explicitTrigger?: boolean | RegExp;
/**
* Triggers that skip Twoslash transformation on the code block meta
*
* @default ['notwoslash', 'no-twoslash']
*/
disableTriggers?: (string | RegExp)[];
/**
* Mapping from language alias to language name
*/
langAlias?: Record<string, string>;
/**
* Custom filter function to apply this transformer to
* When specified, `langs`, `explicitTrigger`, and `disableTriggers` will be ignored
*/
filter?: (lang: string, code: string, options: CodeToHastOptions) => boolean;
/**
* Custom instance of twoslasher function
*/
twoslasher?: TwoslashShikiFunction | TwoslashGenericFunction;
/**
* Options to pass to twoslash
*/
twoslashOptions?: TwoslashOptions;
/**
* Custom renderers to decide how each info should be rendered
*/
renderer?: TwoslashRenderer;
/**
* A map to store code for `@include` directive
* Provide your own instance if you want to clear the map between each transformation
*/
includesMap?: Map<string, string>;
/**
* Strictly throw when there is an error
* @default true
*/
throws?: boolean;
/**
* Custom error handler for twoslash errors
* When specified, `throws` will be ignored
* Optionally return a string to replace the code
*/
onTwoslashError?: (error: unknown, code: string, lang: string, options: CodeToHastOptions) => string | void;
/**
* Custom error handler for Shiki errors
* When specified, `throws` will be ignored
*/
onShikiError?: (error: unknown, code: string, lang: string) => void;
}
interface TwoslashRenderer {
lineError?: (this: ShikiTransformerContext, error: NodeError) => ElementContent[];
lineCustomTag?: (this: ShikiTransformerContext, tag: NodeTag) => ElementContent[];
lineQuery?: (this: ShikiTransformerContext, query: NodeQuery, targetNode?: Element | Text) => ElementContent[];
lineCompletion?: (this: ShikiTransformerContext, query: NodeCompletion) => ElementContent[];
nodeStaticInfo: (this: ShikiTransformerContext, info: NodeHover, node: Element | Text) => Partial<ElementContent>;
nodeError?: (this: ShikiTransformerContext, error: NodeError, node: Element | Text) => Partial<ElementContent>;
nodeQuery?: (this: ShikiTransformerContext, query: NodeQuery, node: Element | Text) => Partial<ElementContent>;
nodeCompletion?: (this: ShikiTransformerContext, query: NodeCompletion, node: Element | Text) => Partial<ElementContent>;
nodesError?: (this: ShikiTransformerContext, error: NodeError, nodes: ElementContent[]) => ElementContent[];
nodesHighlight?: (this: ShikiTransformerContext, highlight: NodeHighlight, nodes: ElementContent[]) => ElementContent[];
}
declare class ShikiTwoslashError extends Error {
constructor(message: string);
}
type CompletionItem = NonNullable<NodeCompletion['completions']>[number];
declare const defaultCompletionIcons: Record<string, Element | undefined>;
declare const defaultCustomTagIcons: Record<string, Element | undefined>;
/**
* The default renderer aligning with the original `@shikijs/twoslash` output.
*/
declare function rendererClassic(): TwoslashRenderer;
interface RendererRichOptions {
/**
* Render JSDoc comments in hover popup.
*
* @default true
*/
jsdoc?: boolean;
/**
* Custom icons for completion items.
* A map from completion item kind to a HAST node.
*
* If `false`, no icons will be rendered.
* @default defaultCompletionIcons
*/
completionIcons?: Partial<Record<string, ElementContent>> | false;
/**
* Custom icons for custom tags lines.
* A map from tag name to a HAST node.
*
* If `false`, no icons will be rendered.
* @default defaultCustomTagIcons
*/
customTagIcons?: Partial<Record<string, ElementContent>> | false;
/**
* Custom formatter for the type info text.
* Note that it might not be valid TypeScript syntax.
*
* @default defaultHoverInfoProcessor
*/
processHoverInfo?: (info: string) => string;
/**
* Custom formatter for the docs text (can be markdown).
*
* @default undefined
*/
processHoverDocs?: (docs: string) => string;
/**
* The way errors should be rendered.
*
* - `'line'`: Render the error line after the line of code
* - `'hover'`: Render the error in the hover popup
*
* @default 'line'
*/
errorRendering?: 'line' | 'hover';
/**
* Classes added to injected elements
*/
classExtra?: string;
/**
* Language for syntax highlight.
* @default the language of the code block
*/
lang?: string;
/**
* Custom function to render markdown.
*
* By default it pass-through the markdown.
*/
renderMarkdown?: (this: ShikiTransformerContextCommon, markdown: string) => ElementContent[];
/**
* Custom function to render inline markdown.
*
* By default it pass-through the markdown.
*/
renderMarkdownInline?: (this: ShikiTransformerContextCommon, markdown: string, context: string) => ElementContent[];
/**
* The way query should be rendered.
* - `'popup'`: Render the query in the absolute popup
* - `'line'`: Render the query line after the line of code
* @default 'popup'
*/
queryRendering?: 'popup' | 'line';
/**
* Extensions for the genreated HAST tree.
*/
hast?: {
/**
* The <code> block for in the hover popup.
*/
popupTypes?: HastExtension;
/**
* The documentation block in the hover popup. Can be markdown rendered if `renderMarkdown` is provided.
*/
popupDocs?: HastExtension;
/**
* The container of jsdoc tags in the hover popup.
*/
popupDocsTags?: HastExtension;
/**
* The token for the hover informaton.
*/
hoverToken?: HastExtension;
/**
* The container of the hover popup.
*/
hoverPopup?: HastExtension;
/**
* The container of error popup.
*/
popupError?: HastExtension;
/**
* Custom function to compose the hover token.
*/
hoverCompose?: (parts: {
popup: Element;
token: Text | Element;
}) => ElementContent[];
/**
* The token for the query informaton.
*/
queryToken?: HastExtension;
/**
* The container of the query popup.
*/
queryPopup?: HastExtension;
/**
* Custom function to compose the hover token.
*/
queryCompose?: (parts: {
popup: Element;
token: Text | Element;
}) => ElementContent[];
/**
* The token for the completion informaton.
*/
completionToken?: HastExtension;
/**
* The cursor element in the completion popup.
*/
completionCursor?: HastExtension;
/**
* The container of the completion popup.
*/
completionPopup?: HastExtension;
/**
* Custom function to compose the completion token.
*/
completionCompose?: (parts: {
popup: Element;
cursor: Element;
}) => ElementContent[];
/**
* The token for the error informaton.
*/
errorToken?: HastExtension;
/**
* The container of the error popup.
* Only used when `errorRendering` is set to `'hover'`.
*/
errorPopup?: HastExtension;
/**
* Custom function to compose the error token.
* Only used when `errorRendering` is set to `'hover'`.
*/
errorCompose?: (parts: {
popup: Element;
token: Text | Element;
}) => ElementContent[];
/**
* The wrapper for the highlighted nodes.
*/
nodesHighlight?: HastExtension;
};
}
interface HastExtension {
tagName?: string;
properties?: Element['properties'];
class?: string;
children?: (input: ElementContent[]) => ElementContent[];
}
/**
* An alternative renderer that providers better prefixed class names,
* with syntax highlight for the info text.
*/
declare function rendererRich(options?: RendererRichOptions): TwoslashRenderer;
/**
* The default hover info processor, which will do some basic cleanup
*/
declare function defaultHoverInfoProcessor(type: string): string;
/**
* This file is the core of the @shikijs/twoslash package,
* Decoupled from twoslash's implementation and allowing to introduce custom implementation or cache system.
*/
declare function defaultTwoslashOptions(): TwoslashExecuteOptions;
declare function createTransformerFactory(defaultTwoslasher: TwoslashShikiFunction | TwoslashGenericFunction, defaultRenderer?: TwoslashRenderer): (options?: TransformerTwoslashOptions) => ShikiTransformer;
export { type CompletionItem, type HastExtension, type RendererRichOptions, ShikiTwoslashError, type TransformerTwoslashOptions, type TwoslashRenderer, type TwoslashShikiFunction, type TwoslashShikiReturn, createTransformerFactory, defaultCompletionIcons, defaultCustomTagIcons, defaultHoverInfoProcessor, defaultTwoslashOptions, rendererClassic, rendererRich };
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
import { ShikiTransformer } from '@shikijs/types';
import { CreateTwoslashOptions } from 'twoslash';
import { TransformerTwoslashOptions, RendererRichOptions } from './core.mjs';
export { CompletionItem, HastExtension, ShikiTwoslashError, TwoslashRenderer, TwoslashShikiFunction, TwoslashShikiReturn, createTransformerFactory, defaultCompletionIcons, defaultCustomTagIcons, defaultHoverInfoProcessor, defaultTwoslashOptions, rendererClassic, rendererRich } from './core.mjs';
import 'hast';
interface TransformerTwoslashIndexOptions extends TransformerTwoslashOptions, Pick<CreateTwoslashOptions, 'cache'> {
/**
* Options for the default rich renderer.
*
* Available when no custom renderer is provided.
*/
rendererRich?: RendererRichOptions;
}
/**
* Factory function to create a Shiki transformer for twoslash integrations.
*/
declare function transformerTwoslash(options?: TransformerTwoslashIndexOptions): ShikiTransformer;
export { RendererRichOptions, type TransformerTwoslashIndexOptions, TransformerTwoslashOptions, transformerTwoslash };
+20
View File
@@ -0,0 +1,20 @@
import { ShikiTransformer } from '@shikijs/types';
import { CreateTwoslashOptions } from 'twoslash';
import { TransformerTwoslashOptions, RendererRichOptions } from './core.js';
export { CompletionItem, HastExtension, ShikiTwoslashError, TwoslashRenderer, TwoslashShikiFunction, TwoslashShikiReturn, createTransformerFactory, defaultCompletionIcons, defaultCustomTagIcons, defaultHoverInfoProcessor, defaultTwoslashOptions, rendererClassic, rendererRich } from './core.js';
import 'hast';
interface TransformerTwoslashIndexOptions extends TransformerTwoslashOptions, Pick<CreateTwoslashOptions, 'cache'> {
/**
* Options for the default rich renderer.
*
* Available when no custom renderer is provided.
*/
rendererRich?: RendererRichOptions;
}
/**
* Factory function to create a Shiki transformer for twoslash integrations.
*/
declare function transformerTwoslash(options?: TransformerTwoslashIndexOptions): ShikiTransformer;
export { RendererRichOptions, type TransformerTwoslashIndexOptions, TransformerTwoslashOptions, transformerTwoslash };
+13
View File
@@ -0,0 +1,13 @@
import { createTwoslasher } from 'twoslash';
import { createTransformerFactory, rendererRich } from './core.mjs';
export { ShikiTwoslashError, defaultCompletionIcons, defaultCustomTagIcons, defaultHoverInfoProcessor, defaultTwoslashOptions, rendererClassic } from './core.mjs';
import '@shikijs/core';
function transformerTwoslash(options = {}) {
return createTransformerFactory(
createTwoslasher({ cache: options?.cache }),
rendererRich(options.rendererRich)
)(options);
}
export { createTransformerFactory, rendererRich, transformerTwoslash };
+68
View File
@@ -0,0 +1,68 @@
{
"name": "@shikijs/twoslash",
"type": "module",
"version": "1.29.2",
"description": "Shiki transformer for twoslash",
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
"license": "MIT",
"homepage": "https://github.com/shikijs/shiki#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/shikijs/shiki.git",
"directory": "packages/twoslash"
},
"bugs": "https://github.com/shikijs/shiki/issues",
"keywords": [
"shiki",
"twoslash"
],
"sideEffects": false,
"exports": {
".": {
"types": "./dist/index.d.mts",
"default": "./dist/index.mjs"
},
"./core": {
"types": "./dist/core.d.mts",
"default": "./dist/core.mjs"
},
"./style-rich.css": "./style-rich.css",
"./style-classic.css": "./style-classic.css",
"./*": "./dist/*"
},
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.mts",
"typesVersions": {
"*": {
"./core": [
"./dist/core.d.mts"
],
"*": [
"./dist/*",
"./*"
]
}
},
"files": [
"*.css",
"dist"
],
"dependencies": {
"twoslash": "^0.2.12",
"@shikijs/core": "1.29.2",
"@shikijs/types": "1.29.2"
},
"devDependencies": {
"@iconify-json/carbon": "^1.2.5",
"@iconify-json/codicon": "^1.2.8",
"hast-util-from-html": "^2.0.3",
"typescript": "^5.7.3",
"@shikijs/twoslash": "1.29.2"
},
"scripts": {
"build": "unbuild",
"dev": "unbuild --stub",
"test": "vitest"
}
}
+267
View File
@@ -0,0 +1,267 @@
/** When you mouse over the pre, show the underlines */
pre.twoslash:hover data-lsp {
border-color: #747474;
}
/** The tooltip-like which provides the LSP response */
pre.twoslash data-lsp:hover::before {
content: attr(lsp);
position: absolute;
transform: translate(0, 1rem);
background-color: #3f3f3f;
color: #fff;
text-align: left;
padding: 5px 8px;
border-radius: 2px;
font-family:
'JetBrains Mono',
Menlo,
Monaco,
Consolas,
Courier New,
monospace;
font-size: 14px;
white-space: pre-wrap;
z-index: 100;
}
pre .code-container {
overflow: auto;
}
/* The try button */
pre .code-container > a {
position: absolute;
right: 8px;
bottom: 8px;
border-radius: 4px;
border: 1px solid #719af4;
padding: 0 8px;
color: #719af4;
text-decoration: none;
opacity: 0;
transition-timing-function: ease;
transition: opacity 0.3s;
}
/* Respect no animations */
@media (prefers-reduced-motion: reduce) {
pre .code-container > a {
transition: none;
}
}
pre .code-container > a:hover {
color: white;
background-color: #719af4;
}
pre .code-container:hover a {
opacity: 1;
}
pre code {
font-size: 15px;
font-family:
'JetBrains Mono',
Menlo,
Monaco,
Consolas,
Courier New,
monospace;
white-space: pre;
-webkit-overflow-scrolling: touch;
}
pre code a {
text-decoration: none;
}
pre data-err {
/* Extracted from VS Code */
background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
repeat-x bottom left;
padding-bottom: 3px;
}
pre .query {
margin-bottom: 10px;
color: #137998;
display: inline-block;
}
/* In order to have the 'popped out' style design and to not break the layout
/* we need to place a fake and un-selectable copy of the error which _isn't_ broken out
/* behind the actual error message.
/* This sections keeps both of those two in in sync */
pre .error,
pre .error-behind {
margin-left: -14px;
margin-top: 8px;
margin-bottom: 4px;
padding: 6px;
padding-left: 14px;
width: calc(100% - 20px);
white-space: pre-wrap;
display: block;
}
pre .error {
position: absolute;
background-color: #fee;
border-left: 2px solid #bf1818;
/* Give the space to the error code */
display: flex;
align-items: center;
color: black;
}
pre .error .code {
display: none;
}
pre .error-behind {
user-select: none;
visibility: transparent;
color: #fee;
}
/* Queries */
pre .arrow {
/* Transparent background */
background-color: #3f3f3f;
position: relative;
top: -7px;
margin-left: 0.1rem;
/* Edges */
border-left: 1px solid #3f3f3f;
border-top: 1px solid #3f3f3f;
transform: translateY(25%) rotate(45deg);
/* Size */
height: 8px;
width: 8px;
}
pre .popover {
margin-bottom: 10px;
background-color: #3f3f3f;
color: #fff;
display: inline-block;
padding: 0 0.5rem 0.3rem;
margin-top: 10px;
border-radius: 3px;
}
/* Completion */
pre .inline-completions ul.dropdown {
display: inline-block;
position: absolute;
width: 240px;
background-color: #3f3f3f;
color: #fff;
font-family: var(--code-font);
font-size: 0.8rem;
margin: 0 0 0 -1px;
padding: 4px 0 0 0;
border-left: 4px solid #4b9edd;
}
pre .inline-completions ul.dropdown::before {
background-color: #4b9edd;
width: 2px;
position: absolute;
top: -1.4em;
height: 1.4em;
left: -4px;
content: ' ';
}
pre .inline-completions ul.dropdown li {
overflow-x: hidden;
padding-left: 4px;
margin-bottom: 4px;
}
pre .inline-completions ul.dropdown li.deprecated {
text-decoration: line-through;
}
pre .inline-completions ul.dropdown li span.result-found {
color: #4b9edd;
}
pre .inline-completions ul.dropdown li span.result {
width: 100px;
color: black;
display: inline-block;
}
.dark-theme .markdown pre {
background-color: #d8d8d8;
border-color: #ddd;
filter: invert(98%) hue-rotate(180deg);
}
data-lsp {
/* Ensures there's no 1px jump when the hover happens */
border-bottom: 1px dotted transparent;
/* Fades in unobtrusively */
transition-timing-function: ease;
transition: border-color 0.3s;
}
/* Respect people's wishes to not have animations */
@media (prefers-reduced-motion: reduce) {
data-lsp {
transition: none;
}
}
/** Annotations support, providing a tool for meta commentary */
.tag-container {
position: relative;
}
.tag-container .twoslash-annotation {
position: absolute;
font-family:
'JetBrains Mono',
Menlo,
Monaco,
Consolas,
Courier New,
monospace;
right: -10px;
/** Default annotation text to 200px */
width: 200px;
color: #187abf;
background-color: #fcf3d9 bb;
}
.tag-container .twoslash-annotation p {
text-align: left;
font-size: 0.8rem;
line-height: 0.9rem;
}
.tag-container .twoslash-annotation svg {
float: left;
margin-left: -44px;
}
.tag-container .twoslash-annotation.left {
right: auto;
left: -200px;
}
.tag-container .twoslash-annotation.left svg {
float: right;
margin-right: -5px;
}
/** Support for showing console log/warn/errors inline */
pre .logger {
display: flex;
align-items: center;
color: black;
padding: 6px;
padding-left: 8px;
width: calc(100% - 19px);
white-space: pre-wrap;
}
pre .logger svg {
margin-right: 9px;
}
pre .logger.error-log {
background-color: #fee;
border-left: 2px solid #bf1818;
}
pre .logger.warn-log {
background-color: #ffe;
border-left: 2px solid #eae662;
}
pre .logger.log-log {
background-color: #e9e9e9;
border-left: 2px solid #ababab;
}
pre .logger.log-log svg {
margin-left: 6px;
margin-right: 9px;
}
+288
View File
@@ -0,0 +1,288 @@
/* ===== Basic ===== */
:root {
--twoslash-border-color: #8888;
--twoslash-underline-color: currentColor;
--twoslash-highlighted-border: #c37d0d50;
--twoslash-highlighted-bg: #c37d0d20;
--twoslash-popup-bg: #f8f8f8;
--twoslash-popup-color: inherit;
--twoslash-popup-shadow: rgba(0, 0, 0, 0.08) 0px 1px 4px;
--twoslash-docs-color: #888;
--twoslash-docs-font: sans-serif;
--twoslash-code-font: inherit;
--twoslash-code-font-size: 1em;
--twoslash-matched-color: inherit;
--twoslash-unmatched-color: #888;
--twoslash-cursor-color: #8888;
--twoslash-error-color: #d45656;
--twoslash-error-bg: #d4565620;
--twoslash-warn-color: #c37d0d;
--twoslash-warn-bg: #c37d0d20;
--twoslash-tag-color: #3772cf;
--twoslash-tag-bg: #3772cf20;
--twoslash-tag-warn-color: var(--twoslash-warn-color);
--twoslash-tag-warn-bg: var(--twoslash-warn-bg);
--twoslash-tag-annotate-color: #1ba673;
--twoslash-tag-annotate-bg: #1ba67320;
}
/* Respect people's wishes to not have animations */
@media (prefers-reduced-motion: reduce) {
.twoslash * {
transition: none !important;
}
}
/* ===== Hover Info ===== */
.twoslash:hover .twoslash-hover {
border-color: var(--twoslash-underline-color);
}
.twoslash .twoslash-hover {
border-bottom: 1px dotted transparent;
transition-timing-function: ease;
transition: border-color 0.3s;
position: relative;
}
.twoslash .twoslash-popup-container {
position: absolute;
opacity: 0;
display: inline-flex;
flex-direction: column;
transform: translateY(1.1em);
background: var(--twoslash-popup-bg);
color: var(--twoslash-popup-color);
border: 1px solid var(--twoslash-border-color);
transition: opacity 0.3s;
border-radius: 4px;
pointer-events: none;
z-index: 10;
user-select: none;
text-align: left;
box-shadow: var(--twoslash-popup-shadow);
}
.twoslash .twoslash-query-presisted .twoslash-popup-container {
z-index: 9;
transform: translateY(1.5em);
}
.twoslash .twoslash-hover:hover .twoslash-popup-container,
.twoslash .twoslash-error-hover:hover .twoslash-popup-container,
.twoslash .twoslash-query-presisted .twoslash-popup-container,
.twoslash .twoslash-query-line .twoslash-popup-container {
opacity: 1;
pointer-events: auto;
}
.twoslash .twoslash-popup-container:hover {
user-select: auto;
}
.twoslash .twoslash-popup-arrow {
position: absolute;
top: -4px;
left: 1em;
border-top: 1px solid var(--twoslash-border-color);
border-right: 1px solid var(--twoslash-border-color);
background: var(--twoslash-popup-bg);
transform: rotate(-45deg);
width: 6px;
height: 6px;
pointer-events: none;
}
.twoslash .twoslash-popup-code,
.twoslash .twoslash-popup-error,
.twoslash .twoslash-popup-docs {
padding: 6px 8px !important;
}
.twoslash .twoslash-popup-code {
font-family: var(--twoslash-code-font);
font-size: var(--twoslash-code-font-size);
}
.twoslash .twoslash-popup-docs {
color: var(--twoslash-docs-color);
font-family: var(--twoslash-docs-font);
font-size: 0.8em;
border-top: 1px solid var(--twoslash-border-color);
}
.twoslash .twoslash-popup-error {
color: var(--twoslash-error-color);
background-color: var(--twoslash-error-bg);
font-family: var(--twoslash-docs-font);
font-size: 0.8em;
}
.twoslash .twoslash-popup-docs-tags {
display: flex;
flex-direction: column;
font-family: var(--twoslash-docs-font);
}
.twoslash .twoslash-popup-docs-tags,
.twoslash .twoslash-popup-docs-tag-name {
margin-right: 0.5em;
}
.twoslash .twoslash-popup-docs-tag-name {
font-family: var(--twoslash-code-font);
}
/* ===== Query Line ===== */
.twoslash .twoslash-query-line .twoslash-popup-container {
position: relative;
margin-bottom: 1.4em;
transform: translateY(0.6em);
}
/* ===== Error Line ===== */
.twoslash .twoslash-error-line {
position: relative;
background-color: var(--twoslash-error-bg);
border-left: 3px solid var(--twoslash-error-color);
color: var(--twoslash-error-color);
padding: 6px 12px;
margin: 0.2em 0;
min-width: 100%;
width: max-content;
}
.twoslash .twoslash-error-line.twoslash-error-level-warning {
background-color: var(--twoslash-warn-bg);
border-left: 3px solid var(--twoslash-warn-color);
color: var(--twoslash-warn-color);
}
.twoslash .twoslash-error {
background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
repeat-x bottom left;
padding-bottom: 2px;
}
.twoslash .twoslash-error.twoslash-error-level-warning {
background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c37d0d'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E")
repeat-x bottom left;
padding-bottom: 2px;
}
/* ===== Completeions ===== */
.twoslash .twoslash-completion-cursor {
position: relative;
}
.twoslash .twoslash-completion-cursor .twoslash-completion-list {
user-select: none;
position: absolute;
top: 0;
left: 0;
transform: translate(0, 1.2em);
margin: 3px 0 0 -1px;
display: inline-block;
z-index: 8;
box-shadow: var(--twoslash-popup-shadow);
background: var(--twoslash-popup-bg);
border: 1px solid var(--twoslash-border-color);
}
.twoslash-completion-list {
width: 240px;
font-size: 0.8rem;
padding: 4px;
display: flex;
flex-direction: column;
gap: 4px;
}
.twoslash-completion-list:hover {
user-select: auto;
}
.twoslash-completion-list::before {
background-color: var(--twoslash-cursor-color);
width: 2px;
position: absolute;
top: -1.6em;
height: 1.4em;
left: -1px;
content: ' ';
}
.twoslash-completion-list li {
overflow: hidden;
display: flex;
align-items: center;
gap: 0.25em;
line-height: 1em;
}
.twoslash-completion-list li span.twoslash-completions-unmatched {
color: var(--twoslash-unmatched-color);
}
.twoslash-completion-list .deprecated {
text-decoration: line-through;
opacity: 0.5;
}
.twoslash-completion-list li span.twoslash-completions-matched {
color: var(--twoslash-matched-color);
}
/* Highlights */
.twoslash-highlighted {
background-color: var(--twoslash-highlighted-bg);
border: 1px solid var(--twoslash-highlighted-border);
padding: 1px 2px;
margin: -1px -3px;
border-radius: 4px;
}
/* Icons */
.twoslash-completion-list .twoslash-completions-icon {
color: var(--twoslash-unmatched-color);
width: 1em;
flex: none;
}
/* Custom Tags */
.twoslash .twoslash-tag-line {
position: relative;
background-color: var(--twoslash-tag-bg);
border-left: 3px solid var(--twoslash-tag-color);
color: var(--twoslash-tag-color);
padding: 6px 10px;
margin: 0.2em 0;
display: flex;
align-items: center;
gap: 0.3em;
min-width: 100%;
width: max-content;
}
.twoslash .twoslash-tag-line .twoslash-tag-icon {
width: 1.1em;
color: inherit;
}
.twoslash .twoslash-tag-line.twoslash-tag-error-line {
background-color: var(--twoslash-error-bg);
border-left: 3px solid var(--twoslash-error-color);
color: var(--twoslash-error-color);
}
.twoslash .twoslash-tag-line.twoslash-tag-warn-line {
background-color: var(--twoslash-tag-warn-bg);
border-left: 3px solid var(--twoslash-tag-warn-color);
color: var(--twoslash-tag-warn-color);
}
.twoslash .twoslash-tag-line.twoslash-tag-annotate-line {
background-color: var(--twoslash-tag-annotate-bg);
border-left: 3px solid var(--twoslash-tag-annotate-color);
color: var(--twoslash-tag-annotate-color);
}