843 lines
22 KiB
JavaScript
843 lines
22 KiB
JavaScript
|
|
'use strict';
|
||
|
|
|
||
|
|
const twoslashProtocol = require('twoslash-protocol');
|
||
|
|
|
||
|
|
const defaultCompilerOptions = {
|
||
|
|
strict: true,
|
||
|
|
module: 99,
|
||
|
|
target: 99,
|
||
|
|
allowJs: true,
|
||
|
|
skipDefaultLibCheck: true,
|
||
|
|
skipLibCheck: true,
|
||
|
|
moduleDetection: 3
|
||
|
|
};
|
||
|
|
const defaultHandbookOptions = {
|
||
|
|
errors: [],
|
||
|
|
noErrors: false,
|
||
|
|
noErrorsCutted: false,
|
||
|
|
noErrorValidation: false,
|
||
|
|
noStaticSemanticInfo: false,
|
||
|
|
showEmit: false,
|
||
|
|
showEmittedFile: void 0,
|
||
|
|
keepNotations: false
|
||
|
|
};
|
||
|
|
|
||
|
|
var __defProp = Object.defineProperty;
|
||
|
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
||
|
|
var __publicField = (obj, key, value) => {
|
||
|
|
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
||
|
|
return value;
|
||
|
|
};
|
||
|
|
class TwoslashError extends Error {
|
||
|
|
constructor(title, description, recommendation, code) {
|
||
|
|
let message = `
|
||
|
|
## ${title}
|
||
|
|
|
||
|
|
${description}
|
||
|
|
`;
|
||
|
|
if (recommendation)
|
||
|
|
message += `
|
||
|
|
${recommendation}`;
|
||
|
|
if (code)
|
||
|
|
message += `
|
||
|
|
${code}`;
|
||
|
|
super(message);
|
||
|
|
__publicField(this, "title");
|
||
|
|
__publicField(this, "description");
|
||
|
|
__publicField(this, "recommendation");
|
||
|
|
__publicField(this, "code");
|
||
|
|
this.title = title;
|
||
|
|
this.description = description;
|
||
|
|
this.recommendation = recommendation;
|
||
|
|
this.code = code;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const defaults = Object.freeze({
|
||
|
|
ignoreUnknown: false,
|
||
|
|
respectType: false,
|
||
|
|
respectFunctionNames: false,
|
||
|
|
respectFunctionProperties: false,
|
||
|
|
unorderedObjects: true,
|
||
|
|
unorderedArrays: false,
|
||
|
|
unorderedSets: false,
|
||
|
|
excludeKeys: void 0,
|
||
|
|
excludeValues: void 0,
|
||
|
|
replacer: void 0
|
||
|
|
});
|
||
|
|
function objectHash(object, options) {
|
||
|
|
if (options) {
|
||
|
|
options = { ...defaults, ...options };
|
||
|
|
} else {
|
||
|
|
options = defaults;
|
||
|
|
}
|
||
|
|
const hasher = createHasher(options);
|
||
|
|
hasher.dispatch(object);
|
||
|
|
return hasher.toString();
|
||
|
|
}
|
||
|
|
const defaultPrototypesKeys = Object.freeze([
|
||
|
|
"prototype",
|
||
|
|
"__proto__",
|
||
|
|
"constructor"
|
||
|
|
]);
|
||
|
|
function createHasher(options) {
|
||
|
|
let buff = "";
|
||
|
|
let context = /* @__PURE__ */ new Map();
|
||
|
|
const write = (str) => {
|
||
|
|
buff += str;
|
||
|
|
};
|
||
|
|
return {
|
||
|
|
toString() {
|
||
|
|
return buff;
|
||
|
|
},
|
||
|
|
getContext() {
|
||
|
|
return context;
|
||
|
|
},
|
||
|
|
dispatch(value) {
|
||
|
|
if (options.replacer) {
|
||
|
|
value = options.replacer(value);
|
||
|
|
}
|
||
|
|
const type = value === null ? "null" : typeof value;
|
||
|
|
return this[type](value);
|
||
|
|
},
|
||
|
|
object(object) {
|
||
|
|
if (object && typeof object.toJSON === "function") {
|
||
|
|
return this.object(object.toJSON());
|
||
|
|
}
|
||
|
|
const objString = Object.prototype.toString.call(object);
|
||
|
|
let objType = "";
|
||
|
|
const objectLength = objString.length;
|
||
|
|
if (objectLength < 10) {
|
||
|
|
objType = "unknown:[" + objString + "]";
|
||
|
|
} else {
|
||
|
|
objType = objString.slice(8, objectLength - 1);
|
||
|
|
}
|
||
|
|
objType = objType.toLowerCase();
|
||
|
|
let objectNumber = null;
|
||
|
|
if ((objectNumber = context.get(object)) === void 0) {
|
||
|
|
context.set(object, context.size);
|
||
|
|
} else {
|
||
|
|
return this.dispatch("[CIRCULAR:" + objectNumber + "]");
|
||
|
|
}
|
||
|
|
if (typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(object)) {
|
||
|
|
write("buffer:");
|
||
|
|
return write(object.toString("utf8"));
|
||
|
|
}
|
||
|
|
if (objType !== "object" && objType !== "function" && objType !== "asyncfunction") {
|
||
|
|
if (this[objType]) {
|
||
|
|
this[objType](object);
|
||
|
|
} else if (!options.ignoreUnknown) {
|
||
|
|
this.unkown(object, objType);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
let keys = Object.keys(object);
|
||
|
|
if (options.unorderedObjects) {
|
||
|
|
keys = keys.sort();
|
||
|
|
}
|
||
|
|
let extraKeys = [];
|
||
|
|
if (options.respectType !== false && !isNativeFunction(object)) {
|
||
|
|
extraKeys = defaultPrototypesKeys;
|
||
|
|
}
|
||
|
|
if (options.excludeKeys) {
|
||
|
|
keys = keys.filter((key) => {
|
||
|
|
return !options.excludeKeys(key);
|
||
|
|
});
|
||
|
|
extraKeys = extraKeys.filter((key) => {
|
||
|
|
return !options.excludeKeys(key);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
write("object:" + (keys.length + extraKeys.length) + ":");
|
||
|
|
const dispatchForKey = (key) => {
|
||
|
|
this.dispatch(key);
|
||
|
|
write(":");
|
||
|
|
if (!options.excludeValues) {
|
||
|
|
this.dispatch(object[key]);
|
||
|
|
}
|
||
|
|
write(",");
|
||
|
|
};
|
||
|
|
for (const key of keys) {
|
||
|
|
dispatchForKey(key);
|
||
|
|
}
|
||
|
|
for (const key of extraKeys) {
|
||
|
|
dispatchForKey(key);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
array(arr, unordered) {
|
||
|
|
unordered = unordered === void 0 ? options.unorderedArrays !== false : unordered;
|
||
|
|
write("array:" + arr.length + ":");
|
||
|
|
if (!unordered || arr.length <= 1) {
|
||
|
|
for (const entry of arr) {
|
||
|
|
this.dispatch(entry);
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const contextAdditions = /* @__PURE__ */ new Map();
|
||
|
|
const entries = arr.map((entry) => {
|
||
|
|
const hasher = createHasher(options);
|
||
|
|
hasher.dispatch(entry);
|
||
|
|
for (const [key, value] of hasher.getContext()) {
|
||
|
|
contextAdditions.set(key, value);
|
||
|
|
}
|
||
|
|
return hasher.toString();
|
||
|
|
});
|
||
|
|
context = contextAdditions;
|
||
|
|
entries.sort();
|
||
|
|
return this.array(entries, false);
|
||
|
|
},
|
||
|
|
date(date) {
|
||
|
|
return write("date:" + date.toJSON());
|
||
|
|
},
|
||
|
|
symbol(sym) {
|
||
|
|
return write("symbol:" + sym.toString());
|
||
|
|
},
|
||
|
|
unkown(value, type) {
|
||
|
|
write(type);
|
||
|
|
if (!value) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
write(":");
|
||
|
|
if (value && typeof value.entries === "function") {
|
||
|
|
return this.array(
|
||
|
|
Array.from(value.entries()),
|
||
|
|
true
|
||
|
|
/* ordered */
|
||
|
|
);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
error(err) {
|
||
|
|
return write("error:" + err.toString());
|
||
|
|
},
|
||
|
|
boolean(bool) {
|
||
|
|
return write("bool:" + bool);
|
||
|
|
},
|
||
|
|
string(string) {
|
||
|
|
write("string:" + string.length + ":");
|
||
|
|
write(string);
|
||
|
|
},
|
||
|
|
function(fn) {
|
||
|
|
write("fn:");
|
||
|
|
if (isNativeFunction(fn)) {
|
||
|
|
this.dispatch("[native]");
|
||
|
|
} else {
|
||
|
|
this.dispatch(fn.toString());
|
||
|
|
}
|
||
|
|
if (options.respectFunctionNames !== false) {
|
||
|
|
this.dispatch("function-name:" + String(fn.name));
|
||
|
|
}
|
||
|
|
if (options.respectFunctionProperties) {
|
||
|
|
this.object(fn);
|
||
|
|
}
|
||
|
|
},
|
||
|
|
number(number) {
|
||
|
|
return write("number:" + number);
|
||
|
|
},
|
||
|
|
xml(xml) {
|
||
|
|
return write("xml:" + xml.toString());
|
||
|
|
},
|
||
|
|
null() {
|
||
|
|
return write("Null");
|
||
|
|
},
|
||
|
|
undefined() {
|
||
|
|
return write("Undefined");
|
||
|
|
},
|
||
|
|
regexp(regex) {
|
||
|
|
return write("regex:" + regex.toString());
|
||
|
|
},
|
||
|
|
uint8array(arr) {
|
||
|
|
write("uint8array:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
uint8clampedarray(arr) {
|
||
|
|
write("uint8clampedarray:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
int8array(arr) {
|
||
|
|
write("int8array:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
uint16array(arr) {
|
||
|
|
write("uint16array:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
int16array(arr) {
|
||
|
|
write("int16array:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
uint32array(arr) {
|
||
|
|
write("uint32array:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
int32array(arr) {
|
||
|
|
write("int32array:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
float32array(arr) {
|
||
|
|
write("float32array:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
float64array(arr) {
|
||
|
|
write("float64array:");
|
||
|
|
return this.dispatch(Array.prototype.slice.call(arr));
|
||
|
|
},
|
||
|
|
arraybuffer(arr) {
|
||
|
|
write("arraybuffer:");
|
||
|
|
return this.dispatch(new Uint8Array(arr));
|
||
|
|
},
|
||
|
|
url(url) {
|
||
|
|
return write("url:" + url.toString());
|
||
|
|
},
|
||
|
|
map(map) {
|
||
|
|
write("map:");
|
||
|
|
const arr = [...map];
|
||
|
|
return this.array(arr, options.unorderedSets !== false);
|
||
|
|
},
|
||
|
|
set(set) {
|
||
|
|
write("set:");
|
||
|
|
const arr = [...set];
|
||
|
|
return this.array(arr, options.unorderedSets !== false);
|
||
|
|
},
|
||
|
|
file(file) {
|
||
|
|
write("file:");
|
||
|
|
return this.dispatch([file.name, file.size, file.type, file.lastModfied]);
|
||
|
|
},
|
||
|
|
blob() {
|
||
|
|
if (options.ignoreUnknown) {
|
||
|
|
return write("[blob]");
|
||
|
|
}
|
||
|
|
throw new Error(
|
||
|
|
'Hashing Blob objects is currently not supported\nUse "options.replacer" or "options.ignoreUnknown"\n'
|
||
|
|
);
|
||
|
|
},
|
||
|
|
domwindow() {
|
||
|
|
return write("domwindow");
|
||
|
|
},
|
||
|
|
bigint(number) {
|
||
|
|
return write("bigint:" + number.toString());
|
||
|
|
},
|
||
|
|
/* Node.js standard native objects */
|
||
|
|
process() {
|
||
|
|
return write("process");
|
||
|
|
},
|
||
|
|
timer() {
|
||
|
|
return write("timer");
|
||
|
|
},
|
||
|
|
pipe() {
|
||
|
|
return write("pipe");
|
||
|
|
},
|
||
|
|
tcp() {
|
||
|
|
return write("tcp");
|
||
|
|
},
|
||
|
|
udp() {
|
||
|
|
return write("udp");
|
||
|
|
},
|
||
|
|
tty() {
|
||
|
|
return write("tty");
|
||
|
|
},
|
||
|
|
statwatcher() {
|
||
|
|
return write("statwatcher");
|
||
|
|
},
|
||
|
|
securecontext() {
|
||
|
|
return write("securecontext");
|
||
|
|
},
|
||
|
|
connection() {
|
||
|
|
return write("connection");
|
||
|
|
},
|
||
|
|
zlib() {
|
||
|
|
return write("zlib");
|
||
|
|
},
|
||
|
|
context() {
|
||
|
|
return write("context");
|
||
|
|
},
|
||
|
|
nodescript() {
|
||
|
|
return write("nodescript");
|
||
|
|
},
|
||
|
|
httpparser() {
|
||
|
|
return write("httpparser");
|
||
|
|
},
|
||
|
|
dataview() {
|
||
|
|
return write("dataview");
|
||
|
|
},
|
||
|
|
signal() {
|
||
|
|
return write("signal");
|
||
|
|
},
|
||
|
|
fsevent() {
|
||
|
|
return write("fsevent");
|
||
|
|
},
|
||
|
|
tlswrap() {
|
||
|
|
return write("tlswrap");
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}
|
||
|
|
const nativeFunc = "[native code] }";
|
||
|
|
const nativeFuncLength = nativeFunc.length;
|
||
|
|
function isNativeFunction(f) {
|
||
|
|
if (typeof f !== "function") {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return Function.prototype.toString.call(f).slice(-nativeFuncLength) === nativeFunc;
|
||
|
|
}
|
||
|
|
|
||
|
|
const reConfigBoolean = /^\/\/\s?@(\w+)$/gm;
|
||
|
|
const reConfigValue = /^\/\/\s?@(\w+):\s?(.+)$/gm;
|
||
|
|
const reAnnonateMarkers = /^\s*\/\/\s*\^(\?|\||\^+)( .*)?$/gm;
|
||
|
|
const reCutBefore = /^[\t\v\f ]*\/\/\s?---cut(-before)?---\r?\n/gm;
|
||
|
|
const reCutAfter = /^[\t\v\f ]*\/\/\s?---cut-after---$/gm;
|
||
|
|
const reCutStart = /^[\t\v\f ]*\/\/\s?---cut-start---$/gm;
|
||
|
|
const reCutEnd = /^[\t\v\f ]*\/\/\s?---cut-end---\r?\n/gm;
|
||
|
|
const reFilenamesMakers = /^[\t\v\f ]*\/\/\s?@filename: (.+)$/gm;
|
||
|
|
|
||
|
|
function getObjectHash(obj) {
|
||
|
|
return objectHash(obj);
|
||
|
|
}
|
||
|
|
function parsePrimitive(value, type) {
|
||
|
|
if (typeof value === type)
|
||
|
|
return value;
|
||
|
|
switch (type) {
|
||
|
|
case "number":
|
||
|
|
return +value;
|
||
|
|
case "string":
|
||
|
|
return value;
|
||
|
|
case "boolean":
|
||
|
|
return value.toLowerCase() === "true" || value.length === 0;
|
||
|
|
}
|
||
|
|
throw new TwoslashError(
|
||
|
|
`Unknown primitive value in compiler flag`,
|
||
|
|
`The only recognized primitives are number, string and boolean. Got ${type} with ${value}.`,
|
||
|
|
`This is likely a typo.`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
function typesToExtension(types) {
|
||
|
|
const map = {
|
||
|
|
js: "js",
|
||
|
|
javascript: "js",
|
||
|
|
ts: "ts",
|
||
|
|
typescript: "ts",
|
||
|
|
tsx: "tsx",
|
||
|
|
jsx: "jsx",
|
||
|
|
json: "json",
|
||
|
|
jsn: "json",
|
||
|
|
map: "json",
|
||
|
|
mts: "ts",
|
||
|
|
cts: "ts",
|
||
|
|
mjs: "js",
|
||
|
|
cjs: "js"
|
||
|
|
};
|
||
|
|
if (map[types])
|
||
|
|
return map[types];
|
||
|
|
throw new TwoslashError(
|
||
|
|
`Unknown TypeScript extension given to Twoslash`,
|
||
|
|
`Received ${types} but Twoslash only accepts: ${Object.keys(map)} `,
|
||
|
|
``
|
||
|
|
);
|
||
|
|
}
|
||
|
|
function getIdentifierTextSpans(ts, sourceFile, fileOffset) {
|
||
|
|
const textSpans = [];
|
||
|
|
checkChildren(sourceFile);
|
||
|
|
return textSpans;
|
||
|
|
function checkChildren(node) {
|
||
|
|
ts.forEachChild(node, (child) => {
|
||
|
|
if (ts.isIdentifier(child)) {
|
||
|
|
const text = child.getText(sourceFile);
|
||
|
|
const start = child.getStart(sourceFile, false) + fileOffset;
|
||
|
|
const end = start + text.length;
|
||
|
|
textSpans.push([start, end, text]);
|
||
|
|
}
|
||
|
|
checkChildren(child);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
function getOptionValueFromMap(name, key, optMap) {
|
||
|
|
const result = optMap.get(key.toLowerCase());
|
||
|
|
if (result === void 0) {
|
||
|
|
const keys = Array.from(optMap.keys());
|
||
|
|
throw new TwoslashError(
|
||
|
|
`Invalid inline compiler value`,
|
||
|
|
`Got ${key} for ${name} but it is not a supported value by the TS compiler.`,
|
||
|
|
`Allowed values: ${keys.join(",")}`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
function splitFiles(code, defaultFileName, root) {
|
||
|
|
const matches = Array.from(code.matchAll(reFilenamesMakers));
|
||
|
|
const allFilenames = matches.map((match) => match[1].trimEnd());
|
||
|
|
let currentFileName = allFilenames.includes(defaultFileName) ? "__index__.ts" : defaultFileName;
|
||
|
|
const files = [];
|
||
|
|
let index = 0;
|
||
|
|
for (const match of matches) {
|
||
|
|
const offset = match.index;
|
||
|
|
const content = code.slice(index, offset);
|
||
|
|
if (content) {
|
||
|
|
files.push({
|
||
|
|
offset: index,
|
||
|
|
filename: currentFileName,
|
||
|
|
filepath: root + currentFileName,
|
||
|
|
content,
|
||
|
|
extension: getExtension(currentFileName)
|
||
|
|
});
|
||
|
|
}
|
||
|
|
currentFileName = match[1].trimEnd();
|
||
|
|
index = offset;
|
||
|
|
}
|
||
|
|
if (index < code.length) {
|
||
|
|
const content = code.slice(index);
|
||
|
|
files.push({
|
||
|
|
offset: index,
|
||
|
|
filename: currentFileName,
|
||
|
|
filepath: root + currentFileName,
|
||
|
|
content,
|
||
|
|
extension: getExtension(currentFileName)
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return files;
|
||
|
|
}
|
||
|
|
function getExtension(fileName) {
|
||
|
|
return fileName.split(".").pop();
|
||
|
|
}
|
||
|
|
function parseFlag(name, value, start, end, customTags, tsOptionDeclarations) {
|
||
|
|
if (customTags.includes(name)) {
|
||
|
|
return {
|
||
|
|
type: "tag",
|
||
|
|
name,
|
||
|
|
value,
|
||
|
|
start,
|
||
|
|
end
|
||
|
|
};
|
||
|
|
}
|
||
|
|
const compilerDecl = tsOptionDeclarations.find((d) => d.name.toLocaleLowerCase() === name.toLocaleLowerCase());
|
||
|
|
if (compilerDecl) {
|
||
|
|
switch (compilerDecl.type) {
|
||
|
|
case "number":
|
||
|
|
case "string":
|
||
|
|
case "boolean":
|
||
|
|
return {
|
||
|
|
type: "compilerOptions",
|
||
|
|
name: compilerDecl.name,
|
||
|
|
value: parsePrimitive(value, compilerDecl.type),
|
||
|
|
start,
|
||
|
|
end
|
||
|
|
};
|
||
|
|
case "list": {
|
||
|
|
const elementType = compilerDecl.element.type;
|
||
|
|
const strings = value.split(",");
|
||
|
|
const resolved = typeof elementType === "string" ? strings.map((v) => parsePrimitive(v, elementType)) : strings.map((v) => getOptionValueFromMap(compilerDecl.name, v, elementType));
|
||
|
|
return {
|
||
|
|
type: "compilerOptions",
|
||
|
|
name: compilerDecl.name,
|
||
|
|
value: resolved,
|
||
|
|
start,
|
||
|
|
end
|
||
|
|
};
|
||
|
|
}
|
||
|
|
case "object":
|
||
|
|
return {
|
||
|
|
type: "compilerOptions",
|
||
|
|
name: compilerDecl.name,
|
||
|
|
value: JSON.parse(value),
|
||
|
|
start,
|
||
|
|
end
|
||
|
|
};
|
||
|
|
default: {
|
||
|
|
return {
|
||
|
|
type: "compilerOptions",
|
||
|
|
name: compilerDecl.name,
|
||
|
|
value: getOptionValueFromMap(compilerDecl.name, value, compilerDecl.type),
|
||
|
|
start,
|
||
|
|
end
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (Object.keys(defaultHandbookOptions).includes(name)) {
|
||
|
|
if (name === "errors" && typeof value === "string")
|
||
|
|
value = value.split(" ").map(Number);
|
||
|
|
if (name === "noErrors" && typeof value === "string") {
|
||
|
|
if (value === "true")
|
||
|
|
value = true;
|
||
|
|
else if (value === "false")
|
||
|
|
value = false;
|
||
|
|
else
|
||
|
|
value = value.split(" ").map(Number);
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
type: "handbookOptions",
|
||
|
|
name,
|
||
|
|
value,
|
||
|
|
start,
|
||
|
|
end
|
||
|
|
};
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
type: "unknown",
|
||
|
|
name,
|
||
|
|
value,
|
||
|
|
start,
|
||
|
|
end
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function findFlagNotations(code, customTags, tsOptionDeclarations) {
|
||
|
|
const flagNotations = [];
|
||
|
|
Array.from(code.matchAll(reConfigBoolean)).forEach((match) => {
|
||
|
|
const index = match.index;
|
||
|
|
const name = match[1];
|
||
|
|
flagNotations.push(
|
||
|
|
parseFlag(name, true, index, index + match[0].length + 1, customTags, tsOptionDeclarations)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
Array.from(code.matchAll(reConfigValue)).forEach((match) => {
|
||
|
|
const name = match[1];
|
||
|
|
if (name === "filename")
|
||
|
|
return;
|
||
|
|
const index = match.index;
|
||
|
|
const value = match[2];
|
||
|
|
flagNotations.push(
|
||
|
|
parseFlag(name, value, index, index + match[0].length + 1, customTags, tsOptionDeclarations)
|
||
|
|
);
|
||
|
|
});
|
||
|
|
return flagNotations;
|
||
|
|
}
|
||
|
|
function findCutNotations(code, meta) {
|
||
|
|
const removals = [];
|
||
|
|
const cutBefore = [...code.matchAll(reCutBefore)];
|
||
|
|
const cutAfter = [...code.matchAll(reCutAfter)];
|
||
|
|
const cutStart = [...code.matchAll(reCutStart)];
|
||
|
|
const cutEnd = [...code.matchAll(reCutEnd)];
|
||
|
|
if (cutBefore.length) {
|
||
|
|
const last = cutBefore[cutBefore.length - 1];
|
||
|
|
removals.push([0, last.index + last[0].length]);
|
||
|
|
}
|
||
|
|
if (cutAfter.length) {
|
||
|
|
const first = cutAfter[0];
|
||
|
|
removals.push([first.index, code.length]);
|
||
|
|
}
|
||
|
|
if (cutStart.length !== cutEnd.length) {
|
||
|
|
throw new TwoslashError(
|
||
|
|
`Mismatched cut markers`,
|
||
|
|
`You have ${cutStart.length} cut-starts and ${cutEnd.length} cut-ends`,
|
||
|
|
`Make sure you have a matching pair for each.`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
for (let i = 0; i < cutStart.length; i++) {
|
||
|
|
const start = cutStart[i];
|
||
|
|
const end = cutEnd[i];
|
||
|
|
if (start.index > end.index) {
|
||
|
|
throw new TwoslashError(
|
||
|
|
`Mismatched cut markers`,
|
||
|
|
`You have a cut-start at ${start.index} which is after the cut-end at ${end.index}`,
|
||
|
|
`Make sure you have a matching pair for each.`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
removals.push([start.index, end.index + end[0].length]);
|
||
|
|
}
|
||
|
|
if (meta)
|
||
|
|
meta.removals.push(...removals);
|
||
|
|
return removals;
|
||
|
|
}
|
||
|
|
function findQueryMarkers(code, meta, pc) {
|
||
|
|
if (code.includes("//")) {
|
||
|
|
const linesQuery = /* @__PURE__ */ new Set();
|
||
|
|
Array.from(code.matchAll(reAnnonateMarkers)).forEach((match) => {
|
||
|
|
const type = match[1];
|
||
|
|
const index = match.index;
|
||
|
|
meta.removals.push([index, index + match[0].length + 1]);
|
||
|
|
const markerIndex = match[0].indexOf("^");
|
||
|
|
const pos = pc.indexToPos(index + markerIndex);
|
||
|
|
let targetLine = pos.line - 1;
|
||
|
|
while (linesQuery.has(targetLine) && targetLine >= 0)
|
||
|
|
targetLine -= 1;
|
||
|
|
const targetIndex = pc.posToIndex(targetLine, pos.character);
|
||
|
|
if (type === "?") {
|
||
|
|
meta.positionQueries.push(targetIndex);
|
||
|
|
} else if (type === "|") {
|
||
|
|
meta.positionCompletions.push(targetIndex);
|
||
|
|
} else {
|
||
|
|
const markerLength = match[0].lastIndexOf("^") - markerIndex + 1;
|
||
|
|
meta.positionHighlights.push([
|
||
|
|
targetIndex,
|
||
|
|
targetIndex + markerLength,
|
||
|
|
match[2]?.trim()
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
linesQuery.add(pos.line);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
return meta;
|
||
|
|
}
|
||
|
|
function removeTsExtension(filename) {
|
||
|
|
const sansMapOrDTS = filename.replace(/\.map$/, "").replace(/\.d\.ts$/, ".ts").replace(/\.map$/, "");
|
||
|
|
return sansMapOrDTS.replace(/\.[^/.]+$/, "");
|
||
|
|
}
|
||
|
|
|
||
|
|
const flagKeys = [
|
||
|
|
"all",
|
||
|
|
"allowArbitraryExtensions",
|
||
|
|
"allowImportingTsExtensions",
|
||
|
|
"allowJs",
|
||
|
|
"allowSyntheticDefaultImports",
|
||
|
|
"allowUmdGlobalAccess",
|
||
|
|
"allowUnreachableCode",
|
||
|
|
"allowUnusedLabels",
|
||
|
|
"alwaysStrict",
|
||
|
|
"assumeChangesOnlyAffectDirectDependencies",
|
||
|
|
"baseUrl",
|
||
|
|
"build",
|
||
|
|
"charset",
|
||
|
|
"checkJs",
|
||
|
|
"composite",
|
||
|
|
"customConditions",
|
||
|
|
"declaration",
|
||
|
|
"declarationDir",
|
||
|
|
"declarationMap",
|
||
|
|
"diagnostics",
|
||
|
|
"disableReferencedProjectLoad",
|
||
|
|
"disableSizeLimit",
|
||
|
|
"disableSolutionSearching",
|
||
|
|
"disableSourceOfProjectReferenceRedirect",
|
||
|
|
"downlevelIteration",
|
||
|
|
"emitBOM",
|
||
|
|
"emitDeclarationOnly",
|
||
|
|
"emitDecoratorMetadata",
|
||
|
|
"errors",
|
||
|
|
"esModuleInterop",
|
||
|
|
"exactOptionalPropertyTypes",
|
||
|
|
"experimentalDecorators",
|
||
|
|
"explainFiles",
|
||
|
|
"extendedDiagnostics",
|
||
|
|
"forceConsistentCasingInFileNames",
|
||
|
|
"generateCpuProfile",
|
||
|
|
"generateTrace",
|
||
|
|
"help",
|
||
|
|
"help",
|
||
|
|
"ignoreDeprecations",
|
||
|
|
"importHelpers",
|
||
|
|
"importsNotUsedAsValues",
|
||
|
|
"incremental",
|
||
|
|
"init",
|
||
|
|
"inlineSourceMap",
|
||
|
|
"inlineSources",
|
||
|
|
"isolatedModules",
|
||
|
|
"jsx",
|
||
|
|
"jsxFactory",
|
||
|
|
"jsxFragmentFactory",
|
||
|
|
"jsxImportSource",
|
||
|
|
"keepNotations",
|
||
|
|
"keyofStringsOnly",
|
||
|
|
"lib",
|
||
|
|
"listEmittedFiles",
|
||
|
|
"listFiles",
|
||
|
|
"listFilesOnly",
|
||
|
|
"locale",
|
||
|
|
"mapRoot",
|
||
|
|
"maxNodeModuleJsDepth",
|
||
|
|
"module",
|
||
|
|
"moduleDetection",
|
||
|
|
"moduleResolution",
|
||
|
|
"moduleSuffixes",
|
||
|
|
"newLine",
|
||
|
|
"noEmit",
|
||
|
|
"noEmitHelpers",
|
||
|
|
"noEmitOnError",
|
||
|
|
"noErrorTruncation",
|
||
|
|
"noErrorValidation",
|
||
|
|
"noErrors",
|
||
|
|
"noErrorsCutted",
|
||
|
|
"noFallthroughCasesInSwitch",
|
||
|
|
"noImplicitAny",
|
||
|
|
"noImplicitOverride",
|
||
|
|
"noImplicitReturns",
|
||
|
|
"noImplicitThis",
|
||
|
|
"noImplicitUseStrict",
|
||
|
|
"noLib",
|
||
|
|
"noPropertyAccessFromIndexSignature",
|
||
|
|
"noResolve",
|
||
|
|
"noStaticSemanticInfo",
|
||
|
|
"noStrictGenericChecks",
|
||
|
|
"noUncheckedIndexedAccess",
|
||
|
|
"noUnusedLocals",
|
||
|
|
"noUnusedParameters",
|
||
|
|
"out",
|
||
|
|
"outDir",
|
||
|
|
"outFile",
|
||
|
|
"paths",
|
||
|
|
"plugins",
|
||
|
|
"preserveConstEnums",
|
||
|
|
"preserveSymlinks",
|
||
|
|
"preserveValueImports",
|
||
|
|
"preserveWatchOutput",
|
||
|
|
"pretty",
|
||
|
|
"project",
|
||
|
|
"reactNamespace",
|
||
|
|
"removeComments",
|
||
|
|
"resolveJsonModule",
|
||
|
|
"resolvePackageJsonExports",
|
||
|
|
"resolvePackageJsonImports",
|
||
|
|
"rootDir",
|
||
|
|
"rootDirs",
|
||
|
|
"showConfig",
|
||
|
|
"showEmit",
|
||
|
|
"showEmittedFile",
|
||
|
|
"skipDefaultLibCheck",
|
||
|
|
"skipLibCheck",
|
||
|
|
"sourceMap",
|
||
|
|
"sourceRoot",
|
||
|
|
"strict",
|
||
|
|
"strictBindCallApply",
|
||
|
|
"strictFunctionTypes",
|
||
|
|
"strictNullChecks",
|
||
|
|
"strictPropertyInitialization",
|
||
|
|
"stripInternal",
|
||
|
|
"suppressExcessPropertyErrors",
|
||
|
|
"suppressImplicitAnyIndexErrors",
|
||
|
|
"target",
|
||
|
|
"traceResolution",
|
||
|
|
"tsBuildInfoFile",
|
||
|
|
"typeRoots",
|
||
|
|
"types",
|
||
|
|
"useDefineForClassFields",
|
||
|
|
"useUnknownInCatchVariables",
|
||
|
|
"verbatimModuleSyntax",
|
||
|
|
"version",
|
||
|
|
"watch"
|
||
|
|
];
|
||
|
|
|
||
|
|
function removeTwoslashNotations(code, customTags) {
|
||
|
|
const meta = {
|
||
|
|
removals: []
|
||
|
|
};
|
||
|
|
const tags = [
|
||
|
|
...customTags ?? [],
|
||
|
|
...flagKeys
|
||
|
|
];
|
||
|
|
Array.from(code.matchAll(reConfigBoolean)).forEach((match) => {
|
||
|
|
if (!tags.includes(match[1]))
|
||
|
|
return;
|
||
|
|
meta.removals.push([match.index, match.index + match[0].length + 1]);
|
||
|
|
});
|
||
|
|
Array.from(code.matchAll(reConfigValue)).forEach((match) => {
|
||
|
|
if (!tags.includes(match[1]))
|
||
|
|
return;
|
||
|
|
meta.removals.push([match.index, match.index + match[0].length + 1]);
|
||
|
|
});
|
||
|
|
findCutNotations(code, meta);
|
||
|
|
Array.from(code.matchAll(reAnnonateMarkers)).forEach((match) => {
|
||
|
|
const index = match.index;
|
||
|
|
meta.removals.push([index, index + match[0].length + 1]);
|
||
|
|
});
|
||
|
|
return twoslashProtocol.removeCodeRanges(code, meta.removals).code;
|
||
|
|
}
|
||
|
|
|
||
|
|
exports.TwoslashError = TwoslashError;
|
||
|
|
exports.defaultCompilerOptions = defaultCompilerOptions;
|
||
|
|
exports.defaultHandbookOptions = defaultHandbookOptions;
|
||
|
|
exports.findCutNotations = findCutNotations;
|
||
|
|
exports.findFlagNotations = findFlagNotations;
|
||
|
|
exports.findQueryMarkers = findQueryMarkers;
|
||
|
|
exports.getExtension = getExtension;
|
||
|
|
exports.getIdentifierTextSpans = getIdentifierTextSpans;
|
||
|
|
exports.getObjectHash = getObjectHash;
|
||
|
|
exports.removeTsExtension = removeTsExtension;
|
||
|
|
exports.removeTwoslashNotations = removeTwoslashNotations;
|
||
|
|
exports.splitFiles = splitFiles;
|
||
|
|
exports.typesToExtension = typesToExtension;
|