'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var shiki = require('shiki');
var twoslash = require('@typescript/twoslash');
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
var htmlForTags = function htmlForTags(tags) {
var html = "";
tags.forEach(function (t) {
if (t.name === "annotate" && t.annotation) {
var meta = t.annotation.split(" - ");
var text = meta.pop();
var info = (meta[0] || "").trim();
var flipped = info.includes("right");
var settings = {
flipped: flipped,
arrowRot: flipped ? "90deg 20px 20px" : "90deg 20px 20px",
textDegree: "0deg",
top: t.line + "em"
};
if (info.includes("{")) {
var theInfo = "{" + info.split("{")[1];
try {
var specificSettings = JSON.parse(theInfo);
settings = _extends({}, settings, specificSettings);
} catch (error) {
throw new twoslash.TwoslashError("Could not parse annotation", "The annotation " + JSON.stringify(t) + " could convert '" + theInfo + "' into JSON", "Look at " + error.message + ".");
}
}
var arrowSVG = arrow(settings);
html += "\n
\n " + arrowSVG + "\n
" + text + "
\n
";
}
});
return html;
};
var arrow = function arrow(style) {
var leftInner = "M27 39C26.5 32.7511 21.9 17.5173 7.5 6.57333M16.5 4.04L0.999999 0.999998C3.16667 4.88444 7.5 13.16 7.5 15.1867";
var rightInner = "M1 39C1.5 32.7511 6.1 17.5173 20.5 6.57333M11.5 4.04L27 0.999998C24.8333 4.88444 20.5 13.16 20.5 15.1867";
var inner = style.flipped ? leftInner : rightInner;
var rot = style.arrowRot.split(" ");
return "";
};
/**
* We're given the text which lives inside the token, and this function will
* annotate it with twoslash metadata
*/
function createHighlightedString(ranges, text, targetedWord) {
if (targetedWord === void 0) {
targetedWord = "";
}
// Why the weird chars? We need to make sure that generic syntax isn't
// interpreted as html tags - to do that we need to switch out < to < - *but*
// making that transition changes the indexes because it's gone from 1 char to 4 chars
//
// So, use an obscure character to indicate a real < for HTML, then switch it after
var tag = function tag(x) {
return "\u21CD" + x + "\u21CF";
};
var makeTagFromRange = function makeTagFromRange(r, close) {
switch (r.classes) {
case "lsp":
// The LSP response lives inside a dom attribute, which _can_ have < inside it, so switch them ahead of time.
var lsp = htmlAttrReplacer(r.lsp || "");
var underLineTargetedWord = r.lsp === targetedWord ? "style=⇯border-bottom: solid 2px lightgrey;⇯" : "";
return close ? tag("/data-lsp") : tag("data-lsp lsp=\xBF" + lsp + "\xBF " + underLineTargetedWord);
case "query":
return tag((close ? "/" : "") + "data-highlight");
// handle both unknown and err variant as error-tag
// case "err": is not required, just to be useful for others
case "err":
default:
return tag((close ? "/" : "") + "data-err");
}
};
ranges.sort(function (a, b) {
// Order of precedence
// if two same offset meet, the lsp will be put as innermost than err and query
var precedenceOf = function precedenceOf(x) {
return ["err", "query", "lsp"].indexOf(x != null ? x : "");
};
var cmp = 0; // Can be desugared into,
// 1. compare based on smaller begin, !(cmp) means if it's 0 then
// 2. compare based on bigger end, ^ same thing again then
// 3. compare based on higher precedence
// && is so that if a step made cmp to something other than 0, it stops
/***1*/
!(cmp = a.begin - b.begin) &&
/*2*/
!(cmp = b.end - a.end) &&
/*3*/
!(cmp = precedenceOf(a.classes) - precedenceOf(b.classes));
return cmp;
}); // `Array.sort` works in place
// Marks how much of the text has been put into the output/html
var cursor = 0; // should be maximum of O(n) where n is length of ranges
var nest = function nest(data) {
var stack = "";
var top = data.shift(); // I have made sure data can't be empty
// parse from cursor to top.begin to make sure
// strings on the way are parsed
stack += text.substring(cursor, top.begin);
cursor = top.begin; // open tag
stack += makeTagFromRange(top); // if the data still have an element that's in the top's range
if (data.some(function (x) {
return x.begin < top.end;
})) {
stack += nest(data);
} else {
// othewise slice the text and set cursor
stack += text.substring(top.begin, top.end);
cursor = top.end;
} // close tag
stack += makeTagFromRange(top, true); // if the tag is complete but still have some data left in the range
if (data.length !== 0) {
stack += nest(data);
}
return stack;
}; // cloned because I don't feel comfortable modifying this as a side-effect from recursion
var data = JSON.parse(JSON.stringify(ranges));
var html = nest(data) + text.substring(cursor); // nested + leftover texts
return htmlAttrUnReplacer(replaceTripleArrow(stripHTML(html)));
} // HTML attributes have different rules,
var htmlAttrReplacer = function htmlAttrReplacer(str) {
return str.replace(/"/g, "⃟");
};
var htmlAttrUnReplacer = function htmlAttrUnReplacer(str) {
return str.replace(/⃟/g, '"');
}; // Inline strings which are shown at HTML level
var subTripleArrow = function subTripleArrow(str) {
return str.replace(//g, "⇏").replace(/'/g, "⇯");
};
var replaceTripleArrow = function replaceTripleArrow(str) {
return str.replace(/⇍/g, "<").replace(/⇏/g, ">").replace(/⇯/g, "'").replace(/¿/g, "'");
};
var replaceTripleArrowEncoded = function replaceTripleArrowEncoded(str) {
return str.replace(/⇍/g, "<").replace(/⇏/g, ">").replace(/⇯/g, "'");
};
function stripHTML(text) {
var table = {
"<": "lt",
'"': "quot",
"'": "apos",
"&": "amp",
"\r": "#13",
"\n": "#10"
};
return text.toString().replace(/[<"'\r\n&]/g, function (chr) {
return "&" + table[chr] + ";";
});
}
function escapeHtml(html) {
return html.replace(//g, ">");
}
/** Does anything in the object imply that we should highlight any lines? */
var shouldBeHighlightable = function shouldBeHighlightable(highlight) {
return !!Object.keys(highlight || {}).find(function (key) {
if (key.includes("-")) return true;
if (!isNaN(parseInt(key))) return true;
return false;
});
};
/** Returns a func for figuring out if this line should be highlighted */
var shouldHighlightLine = function shouldHighlightLine(highlight) {
var lines = [];
Object.keys(highlight || {}).find(function (key) {
if (!isNaN(parseInt(key))) lines.push(parseInt(key));
if (key.includes("-")) {
var _key$split = key.split("-"),
first = _key$split[0],
last = _key$split[1];
var lastIndex = parseInt(last) + 1;
for (var i = parseInt(first); i < lastIndex; i++) {
lines.push(i);
}
}
});
return function (line) {
return lines.includes(line);
};
};
/** A func for setting a consistent
*/
var preOpenerFromRenderingOptsWithExtras = function preOpenerFromRenderingOptsWithExtras(opts, meta, classes) {
var bg = opts.bg || "#fff";
var fg = opts.fg || "black";
var theme = opts.themeName || ""; // shiki + `class` from fence + with-title if title exists + classes
var classList = ["shiki", theme, meta["class"], meta.title ? "with-title" : ""].concat(classes || []).filter(Boolean).join(" ").trim();
var attributes = Object.entries(meta).filter(function (entry) {
// exclude types other than string, number, boolean
// exclude keys class, twoslash
// exclude falsy booleans
return ["string", "number", "boolean"].includes(typeof entry[1]) && !["class", "twoslash"].includes(entry[0]) && entry[1] !== false;
}).map(function (_ref) {
var key = _ref[0],
value = _ref[1];
return key + "=\"" + value + "\"";
}).join(" ").trim(); // prettier-ignore
return "
";
};
/** You don't have a language which shiki twoslash can handle, make a DOM compatible version */
function plainTextRenderer(code, options, meta) {
var html = "";
html += preOpenerFromRenderingOptsWithExtras(options, meta, []);
if (meta.title) {
html += "
" + meta.title + "
";
}
if (options.langId) {
html += "
" + options.langId + "
";
}
html += "
";
html += escapeHtml(code);
html = html.replace(/\n*$/, ""); // Get rid of final new lines
html += "
";
return html;
}
// What we're trying to do is merge two sets of information into a single tree for HTML
// 1: Syntax highlight info from shiki
// 2: Twoslash metadata like errors, identifiers etc
// Because shiki gives use a set of lines to work from, then the first thing which happens
// is converting twoslash data into the same format.
// Things which make it hard:
//
// - Twoslash results can be cut, so sometimes there is edge cases between twoslash results
// - Twoslash results can be multi-file
// - the DOM requires a flattened graph of html elements (e.g. spans can' be interspersed)
//
function twoslashRenderer(lines, options, twoslash, meta) {
var html = "";
var hasHighlight = meta.highlight && shouldBeHighlightable(meta.highlight);
var hl = shouldHighlightLine(meta.highlight);
if (twoslash.tags && twoslash.tags.length) html += "
";
html += preOpenerFromRenderingOptsWithExtras(options, meta, ["twoslash", "lsp"]);
if (meta.title) {
html += "
" + meta.title + "
";
}
if (options.langId) {
html += "
" + options.langId + "
";
}
html += "
";
var errorsGroupedByLine = groupBy(twoslash.errors, function (e) {
return e.line;
}) || new Map();
var staticQuickInfosGroupedByLine = groupBy(twoslash.staticQuickInfos, function (q) {
return q.line;
}) || new Map(); // A query is always about the line above it!
var queriesGroupedByLine = groupBy(twoslash.queries, function (q) {
return q.line - 1;
}) || new Map();
var tagsGroupedByLine = groupBy(twoslash.tags, function (q) {
return q.line - 1;
}) || new Map();
/**
* This is the index of the original twoslash code reference, it is not
* related to the HTML output
*/
var filePos = 0;
lines.forEach(function (l, i) {
var errors = errorsGroupedByLine.get(i) || [];
var lspValues = staticQuickInfosGroupedByLine.get(i) || [];
var queries = queriesGroupedByLine.get(i) || [];
var tags = tagsGroupedByLine.get(i) || [];
var hiClass = hasHighlight ? hl(i + 1) ? " highlight" : " dim" : "";
var prefix = "
";
if (l.length === 0 && i === 0) {
// Skip the first newline if it's blank
filePos += 1;
} else if (l.length === 0) {
var emptyLine = prefix + "
";
html += emptyLine;
filePos += 1;
} else {
html += prefix; // Keep track of the position of the current token in a line so we can match it up to the
// errors and lang serv identifiers
var tokenPos = 0;
l.forEach(function (token) {
var targetedQueryWord;
var tokenContent = ""; // Underlining particular words
var findTokenFunc = function findTokenFunc(start) {
return function (e) {
return start <= e.character && start + token.content.length >= e.character + e.length;
};
};
var errorsInToken = errors.filter(findTokenFunc(tokenPos));
var lspResponsesInToken = lspValues.filter(findTokenFunc(tokenPos));
var queriesInToken = queries.filter(findTokenFunc(tokenPos)); // Does this line have a word targeted by a query?
targetedQueryWord = targetedQueryWord || lspResponsesInToken.find(function (response) {
return response.text === (queries.length && queries[0].text);
});
var allTokens = [].concat(errorsInToken, lspResponsesInToken, queriesInToken);
var allTokensByStart = allTokens.sort(function (l, r) {
return (l.start || 0) - (r.start || 0);
});
if (allTokensByStart.length) {
var _targetedQueryWord;
var ranges = allTokensByStart.map(function (token) {
var range = {
begin: token.start - filePos,
end: token.start + token.length - filePos
}; // prettier-ignore
if ("renderedMessage" in token) range.classes = "err";
if ("kind" in token) range.classes = token.kind;
if ("targetString" in token) {
range.classes = "lsp";
var lspText = options.includeJSDocInHover && token.docs ? token.docs + "\n\n" + token.text : token.text;
range["lsp"] = lspText;
}
return range;
});
tokenContent += createHighlightedString(ranges, token.content, (_targetedQueryWord = targetedQueryWord) == null ? void 0 : _targetedQueryWord.text);
} else {
tokenContent += subTripleArrow(token.content);
}
html += "" + tokenContent + "";
tokenPos += token.content.length;
filePos += token.content.length;
});
html += "
"; // This is the \n which the
represents
filePos += 1;
} // Adding error messages to the line after
if (errors.length) {
var messages = errors.map(function (e) {
return escapeHtml(e.renderedMessage);
}).join("");
var codes = errors.map(function (e) {
return e.code;
}).join(" ");
html += "" + messages + "" + codes + "";
html += "" + messages + "";
} // Add queries to the next line
if (queries.length) {
queries.forEach(function (query) {
// This is used to wrap popovers and completions to improve styling options for users.
html += "
";
switch (query.kind) {
case "query":
{
var queryTextWithPrefix = escapeHtml(query.text);
var _lspValues = staticQuickInfosGroupedByLine.get(i) || [];
var targetedWord = _lspValues.find(function (response) {
return response.text === (queries.length && queries[0].text);
});
var halfWayAcrossTheTargetedWord = (targetedWord && targetedWord.character + (targetedWord == null ? void 0 : targetedWord.length) / 2) - 1 || 0;
html += "" + " ".repeat(halfWayAcrossTheTargetedWord) + "" + ("" + queryTextWithPrefix + "");
break;
}
case "completions":
{
if (!query.completions) {
html += "" + ("//" + "".padStart(query.offset - 2) + "^ - No completions found") + "";
} else {
var prefixed = query.completions.filter(function (c) {
return c.name.startsWith(query.completionsPrefix || "____");
});
var lis = prefixed.sort(function (l, r) {
return l.name.localeCompare(r.name);
}).map(function (c) {
var _query$completionsPre, _c$kindModifiers;
var after = c.name.substr(((_query$completionsPre = query.completionsPrefix) == null ? void 0 : _query$completionsPre.length) || 0);
var name = "" + (query.completionsPrefix || "") + "" + after + "";
var isDeprecated = (_c$kindModifiers = c.kindModifiers) == null ? void 0 : _c$kindModifiers.split(",").includes("deprecated");
var liClass = isDeprecated ? "deprecated" : "";
return "
" + name + "
";
}).join("");
html += " ".repeat(query.offset) + "
" + lis + "
";
}
}
}
html += "
";
});
} // Any tags (currently that's warn/error/log)
if (tags.length) {
tags.forEach(function (tag) {
if (!["error", "warn", "log"].includes(tag.name)) return; // This is used to wrap popovers and completions to improve styling options for users.
html += "
";
switch (tag.name) {
case "error":
html += errorSVG + "" + (tag.annotation || "N/A") + "";
break;
case "warn":
html += warningSVG + "" + (tag.annotation || "N/A") + "";
break;
case "log":
html += logSVG + "" + (tag.annotation || "N/A") + "";
break;
}
html += "
";
});
}
});
html = replaceTripleArrowEncoded(html.replace(/\n*$/, "")); // Get rid of final new lines
if (options.addTryButton) {
var playgroundLink = "Try";
html += "" + playgroundLink;
} else {
html += "";
}
html += "
"; // Attach annotations which live above of the code
if (twoslash.tags && twoslash.tags.length) {
html += htmlForTags(twoslash.tags);
html += "";
}
return html;
}
/** Returns a map where all the keys are the value in keyGetter */
function groupBy(list, keyGetter) {
var map = new Map();
list.forEach(function (item) {
var key = keyGetter(item);
var collection = map.get(key);
if (!collection) {
map.set(key, [item]);
} else {
collection.push(item);
}
});
return map;
}
var errorSVG = "";
var warningSVG = "";
var logSVG = "";
function defaultShikiRenderer(lines, options, meta) {
var html = "";
var hasHighlight = meta.highlight && shouldBeHighlightable(meta.highlight);
var hl = shouldHighlightLine(meta.highlight);
html += preOpenerFromRenderingOptsWithExtras(options, meta, []);
if (meta.title) {
html += "
" + meta.title + "
";
}
if (options.langId) {
html += "
" + options.langId + "
";
}
html += "
";
lines.forEach(function (l, i) {
if (l.length === 0) {
html += "";
} else {
var hiClass = hasHighlight ? hl(i) ? " highlight" : " dim" : "";
var prefix = "
";
html += prefix;
l.forEach(function (token) {
html += "" + escapeHtml(token.content) + "";
});
html += "
";
}
});
html = html.replace(/\n*$/, ""); // Get rid of final new lines
html += "
";
return html;
}
var tsconfig = {
compilerOptions: "The set of compiler options for your project",
allowJs: "Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files.",
allowSyntheticDefaultImports: "Allow 'import x from y' when a module doesn't have a default export.",
allowUmdGlobalAccess: "Allow accessing UMD globals from modules.",
allowUnreachableCode: "Disable error reporting for unreachable code.",
allowUnusedLabels: "Disable error reporting for unused labels.",
alwaysStrict: "Ensure 'use strict' is always emitted.",
assumeChangesOnlyAffectDirectDependencies: "Have recompiles in projects that use [`incremental`](#incremental) and `watch` mode assume that changes within a file will only affect files directly depending on it.",
baseUrl: "Specify the base directory to resolve non-relative module names.",
charset: "No longer supported. In early versions, manually set the text encoding for reading files.",
checkJs: "Enable error reporting in type-checked JavaScript files.",
clean: "Delete the outputs of all projects.",
composite: "Enable constraints that allow a TypeScript project to be used with project references.",
declaration: "Generate .d.ts files from TypeScript and JavaScript files in your project.",
declarationDir: "Specify the output directory for generated declaration files.",
declarationMap: "Create sourcemaps for d.ts files.",
diagnostics: "Output compiler performance information after building.",
disableFilenameBasedTypeAcquisition: "Disables inference for type acquisition by looking at filenames in a project.",
disableReferencedProjectLoad: "Reduce the number of projects loaded automatically by TypeScript.",
disableSizeLimit: "Remove the 20mb cap on total source code size for JavaScript files in the TypeScript language server.",
disableSolutionSearching: "Opt a project out of multi-project reference checking when editing.",
disableSourceOfProjectReferenceRedirect: "Disable preferring source files instead of declaration files when referencing composite projects.",
downlevelIteration: "Emit more compliant, but verbose and less performant JavaScript for iteration.",
emitBOM: "Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files.",
emitDeclarationOnly: "Only output d.ts files and not JavaScript files.",
emitDecoratorMetadata: "Emit design-type metadata for decorated declarations in source files.",
enable: "Disable the type acquisition for JavaScript projects.",
esModuleInterop: "Emit additional JavaScript to ease support for importing CommonJS modules. This enables [`allowSyntheticDefaultImports`](#allowSyntheticDefaultImports) for type compatibility.",
exactOptionalPropertyTypes: "Interpret optional property types as written, rather than adding `undefined`.",
exclude: "Filters results from the [`include`](#include) option.",
excludeDirectories: "Remove a list of directories from the watch process.",
excludeFiles: "Remove a list of files from the watch mode's processing.",
experimentalDecorators: "Enable experimental support for TC39 stage 2 draft decorators.",
explainFiles: "Print files read during the compilation including why it was included.",
extendedDiagnostics: "Output more detailed compiler performance information after building.",
"extends": "Specify one or more path or node module references to base configuration files from which settings are inherited.",
fallbackPolling: "Specify what approach the watcher should use if the system runs out of native file watchers.",
files: "Include a list of files. This does not support glob patterns, as opposed to [`include`](#include).",
force: "Build all projects, including those that appear to be up to date.",
forceConsistentCasingInFileNames: "Ensure that casing is correct in imports.",
generateCpuProfile: "Emit a v8 CPU profile of the compiler run for debugging.",
importHelpers: "Allow importing helper functions from tslib once per project, instead of including them per-file.",
importsNotUsedAsValues: "Specify emit/checking behavior for imports that are only used for types.",
include: "Specify a list of glob patterns that match files to be included in compilation.",
incremental: "Save .tsbuildinfo files to allow for incremental compilation of projects.",
inlineSourceMap: "Include sourcemap files inside the emitted JavaScript.",
inlineSources: "Include source code in the sourcemaps inside the emitted JavaScript.",
isolatedModules: "Ensure that each file can be safely transpiled without relying on other imports.",
jsx: "Specify what JSX code is generated.",
jsxFactory: "Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'.",
jsxFragmentFactory: "Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'.",
jsxImportSource: "Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.",
keyofStringsOnly: "Make keyof only return strings instead of string, numbers or symbols. Legacy option.",
lib: "Specify a set of bundled library declaration files that describe the target runtime environment.",
listEmittedFiles: "Print the names of emitted files after a compilation.",
listFiles: "Print all of the files read during the compilation.",
locale: "Set the language of the messaging from TypeScript. This does not affect emit.",
mapRoot: "Specify the location where debugger should locate map files instead of generated locations.",
maxNodeModuleJsDepth: "Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with [`allowJs`](#allowJs).",
module: "Specify what module code is generated.",
moduleDetection: "Control what method is used to detect the whether a JS file is a module.",
moduleResolution: "Specify how TypeScript looks up a file from a given module specifier.",
moduleSuffixes: "List of file name suffixes to search when resolving a module.",
newLine: "Set the newline character for emitting files.",
noEmit: "Disable emitting files from a compilation.",
noEmitHelpers: "Disable generating custom helper functions like `__extends` in compiled output.",
noEmitOnError: "Disable emitting files if any type checking errors are reported.",
noErrorTruncation: "Disable truncating types in error messages.",
noFallthroughCasesInSwitch: "Enable error reporting for fallthrough cases in switch statements.",
noImplicitAny: "Enable error reporting for expressions and declarations with an implied `any` type.",
noImplicitOverride: "Ensure overriding members in derived classes are marked with an override modifier.",
noImplicitReturns: "Enable error reporting for codepaths that do not explicitly return in a function.",
noImplicitThis: "Enable error reporting when `this` is given the type `any`.",
noImplicitUseStrict: "Disable adding 'use strict' directives in emitted JavaScript files.",
noLib: "Disable including any library files, including the default lib.d.ts.",
noPropertyAccessFromIndexSignature: "Enforces using indexed accessors for keys declared using an indexed type.",
noResolve: "Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project.",
noStrictGenericChecks: "Disable strict checking of generic signatures in function types.",
noUncheckedIndexedAccess: "Add `undefined` to a type when accessed using an index.",
noUnusedLocals: "Enable error reporting when local variables aren't read.",
noUnusedParameters: "Raise an error when a function parameter isn't read.",
out: "Deprecated setting. Use [`outFile`](#outFile) instead.",
outDir: "Specify an output folder for all emitted files.",
outFile: "Specify a file that bundles all outputs into one JavaScript file. If [`declaration`](#declaration) is true, also designates a file that bundles all .d.ts output.",
paths: "Specify a set of entries that re-map imports to additional lookup locations.",
plugins: "Specify a list of language service plugins to include.",
preserveConstEnums: "Disable erasing `const enum` declarations in generated code.",
preserveSymlinks: "Disable resolving symlinks to their realpath. This correlates to the same flag in node.",
preserveValueImports: "Preserve unused imported values in the JavaScript output that would otherwise be removed.",
preserveWatchOutput: "Disable wiping the console in watch mode.",
pretty: "Enable color and formatting in TypeScript's output to make compiler errors easier to read.",
reactNamespace: "Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit.",
references: "Specify an array of objects that specify paths for projects. Used in project references.",
removeComments: "Disable emitting comments.",
resolveJsonModule: "Enable importing .json files.",
rootDir: "Specify the root folder within your source files.",
rootDirs: "Allow multiple folders to be treated as one when resolving modules.",
skipDefaultLibCheck: "Skip type checking .d.ts files that are included with TypeScript.",
skipLibCheck: "Skip type checking all .d.ts files.",
sourceMap: "Create source map files for emitted JavaScript files.",
sourceRoot: "Specify the root path for debuggers to find the reference source code.",
strict: "Enable all strict type-checking options.",
strictBindCallApply: "Check that the arguments for `bind`, `call`, and `apply` methods match the original function.",
strictFunctionTypes: "When assigning functions, check to ensure parameters and the return values are subtype-compatible.",
strictNullChecks: "When type checking, take into account `null` and `undefined`.",
strictPropertyInitialization: "Check for class properties that are declared but not set in the constructor.",
stripInternal: "Disable emitting declarations that have `@internal` in their JSDoc comments.",
suppressExcessPropertyErrors: "Disable reporting of excess property errors during the creation of object literals.",
suppressImplicitAnyIndexErrors: "Suppress [`noImplicitAny`](#noImplicitAny) errors when indexing objects that lack index signatures.",
synchronousWatchDirectory: "Synchronously call callbacks and update the state of directory watchers on platforms that don`t support recursive watching natively.",
target: "Set the JavaScript language version for emitted JavaScript and include compatible library declarations.",
traceResolution: "Log paths used during the [`moduleResolution`](#moduleResolution) process.",
tsBuildInfoFile: "Specify the folder for .tsbuildinfo incremental compilation files.",
typeAcquisition: "Specify options for automatic acquisition of declaration files.",
typeRoots: "Specify multiple folders that act like `./node_modules/@types`.",
types: "Specify type package names to be included without being referenced in a source file.",
useDefineForClassFields: "Emit ECMAScript-standard-compliant class fields.",
useUnknownInCatchVariables: "Default catch clause variables as `unknown` instead of `any`.",
verbose: "Enable verbose logging.",
watchDirectory: "Specify how directories are watched on systems that lack recursive file-watching functionality.",
watchFile: "Specify how the TypeScript watch mode works."
};
/** Uses tmLanguage scopes to determine what the content of the token is */
var tokenIsJSONKey = function tokenIsJSONKey(token) {
if (!token.explanation) return false;
return token.explanation.find(function (e) {
return e.scopes.find(function (s) {
return s.scopeName.includes("support.type.property-name");
});
});
};
/** Can you look up the token in the tsconfig reference? */
var isKeyInTSConfig = function isKeyInTSConfig(token) {
if (token.content === '"') return;
var name = token.content.slice(1, token.content.length - 1);
return name in tsconfig;
};
/**
* Renders a TSConfig JSON object with additional LSP-ish information
* @param lines the result of shiki highlighting
* @param options shiki display options
*/
function tsconfigJSONRenderer(lines, options, meta) {
var html = "";
html += preOpenerFromRenderingOptsWithExtras(options, meta, ["tsconfig", "lsp"]);
if (meta.title) {
html += "
" + meta.title + "
";
}
if (options.langId) {
html += "
" + options.langId + "
";
}
html += "
";
lines.forEach(function (l) {
if (l.length === 0) {
html += "";
} else {
html += "
";
l.forEach(function (token) {
// This means we're looking at a token which could be '"module"', '"', '"compilerOptions"' etc
if (tokenIsJSONKey(token) && isKeyInTSConfig(token)) {
var key = token.content.slice(1, token.content.length - 1);
var oneliner = tsconfig[key]; // prettier-ignore
html += "\"" + escapeHtml(key) + "\"";
} else {
html += "" + escapeHtml(token.content) + "";
}
});
html += "
";
}
});
html = html.replace(/\n*$/, ""); // Get rid of final new lines
html += "
";
return html;
}
/**
* This gets filled in by the promise below, then should
* hopefully be more or less synchronous access by each parse
* of the highlighter
*/
var storedHighlighter = null;
/**
* Creates a *cached singleton* Shiki highlighter, this is an async call because of the call to WASM to get
* the regex parser set up.
*
* In other functions, passing a the result of this highlighter function is kind of optional but it's the author's
* opinion that you should be in control of the highlighter, and not this library.
*
*/
var createShikiHighlighter = function createShikiHighlighter(options) {
if (storedHighlighter) return Promise.resolve(storedHighlighter);
return shiki.getHighlighter(options).then(function (newHighlighter) {
storedHighlighter = newHighlighter;
return storedHighlighter;
});
};
/**
* Renders a code sample to HTML, automatically taking into account:
*
* - rendering overrides for twoslash and tsconfig
* - whether the language exists in shiki
*
* @param code the source code to render
* @param lang the language to use in highlighting
* @param info additional metadata which lives after the code-fence lang (e.g. `{ twoslash: true }`)
* @param shikiOptions user settings
* @param highlighter optional, but you should use it, highlighter
* @param twoslash optional, but required when info contains 'twoslash' as a string
*/
var renderCodeToHTML = function renderCodeToHTML(code, lang, meta, shikiOptions, highlighter, twoslash) {
if (!highlighter && !storedHighlighter) {
throw new Error("The highlighter object hasn't been initialised via `setupHighLighter` yet in shiki-twoslash");
} // Shiki does know the lang, so tokenize
var renderHighlighter = highlighter || storedHighlighter;
var renderOpts = _extends({
fg: renderHighlighter.getForegroundColor(),
bg: renderHighlighter.getBackgroundColor()
}, shikiOptions);
var tokens;
try {
// I'm a little unsure about why we need this, perhaps the jsx language
// upstream in shiki is broken?
var tmpLang = lang === "jsx" ? "tsx" : lang;
tokens = renderHighlighter.codeToThemedTokens(code, tmpLang);
} catch (error) {
// Shiki doesn't know this lang, so render it as plain text, but
// also add a note at the end as a HTML comment
var note = "";
return plainTextRenderer(code, renderOpts, meta) + note;
} // Twoslash specific renderer
if (lang && meta.twoslash && twoslash) {
return twoslashRenderer(tokens, _extends({}, renderOpts, {
langId: lang
}), twoslash, meta);
} // TSConfig renderer
if (lang && lang.startsWith("json") && meta.tsconfig) {
return tsconfigJSONRenderer(tokens, renderOpts, meta);
} // Otherwise just the normal shiki renderer
return defaultShikiRenderer(tokens, _extends({}, renderOpts, {
langId: lang
}), meta);
};
/**
* Runs Twoslash over the code passed in with a particular language as the default file.
*/
var runTwoSlash = function runTwoSlash(input, lang, settings) {
if (settings === void 0) {
settings = {};
}
var code = input; // Shiki doesn't handle a few filetype mappings, so do that ahead of time. Oddly enough, this also
// gets re-done at remark-shiki level
var replacer = {
json5: "json",
yml: "yaml"
}; // @ts-ignore
if (replacer[lang]) lang = replacer[lang];
var hasReactImport = /^import\s+React(?:.*)\s+from\s+('|")react\1/gm; // Add react import to code samples indicating they're needing react.
if (["tsx", "jsx"].includes(lang) && !settings.disableImplicitReactImport && !hasReactImport.test(code)) {
var reactImport = "import React from 'react'\n";
var cutString = "// ---cut---\n"; // ^ cutString taken directly from
// https://github.com/microsoft/TypeScript-Website/blob/0c8d98a69d520365c1909d536fa1323f03a8438c/packages/ts-twoslasher/src/index.ts#L694
if (code.includes(cutString)) {
code = code.split(cutString).map(function (item, index) {
return index == 0 ? reactImport.concat(item) : item;
}).join(cutString);
} else {
code = [reactImport, cutString, code].join("");
}
}
settings.customTags = ["annotate", "log", "warn", "error"];
var results = twoslash.twoslasher(code, lang, settings);
return results;
};
/** Set of renderers if you want to explicitly call one instead of using renderCodeToHTML */
var renderers = {
plainTextRenderer: plainTextRenderer,
defaultShikiRenderer: defaultShikiRenderer,
twoslashRenderer: twoslashRenderer,
tsconfigJSONRenderer: tsconfigJSONRenderer
};
exports.createShikiHighlighter = createShikiHighlighter;
exports.renderCodeToHTML = renderCodeToHTML;
exports.renderers = renderers;
exports.runTwoSlash = runTwoSlash;
//# sourceMappingURL=shiki-twoslash.cjs.development.js.map