@typescript/twoslash
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -1,7 +0,7 @@ | ||
declare type LZ = typeof import('lz-string'); | ||
declare type TS = typeof import('typescript'); | ||
declare module 'typescript' { | ||
declare type LZ = typeof import("lz-string"); | ||
declare type TS = typeof import("typescript"); | ||
declare module "typescript" { | ||
type Option = { | ||
name: string; | ||
type: 'list' | 'boolean' | 'number' | 'string' | import('typescript').Map<number>; | ||
type: "list" | "boolean" | "number" | "string" | import("typescript").Map<number>; | ||
element?: Option; | ||
@@ -24,4 +24,8 @@ }; | ||
showEmittedFile: string; | ||
/** Whether to disable the pre-cache of LSP calls for interesting identifiers */ | ||
noStaticSemanticInfo: false; | ||
/** Whether to disable the pre-cache of LSP calls for interesting identifiers, defaults to false */ | ||
noStaticSemanticInfo: boolean; | ||
/** Declare that the TypeScript program should edit the fsMap which is passed in, this is only useful for tool-makers, defaults to false */ | ||
emit: boolean; | ||
/** Declare that you don't need to validate that errors have corresponding annotations, defaults to false */ | ||
noErrorValidation: boolean; | ||
} | ||
@@ -35,3 +39,3 @@ export interface TwoSlashReturn { | ||
highlights: { | ||
kind: 'highlight'; | ||
kind: "highlight"; | ||
position: number; | ||
@@ -61,10 +65,15 @@ length: number; | ||
queries: { | ||
kind: 'query'; | ||
/** The index of the text in the file */ | ||
start: number; | ||
/** how long the identifier */ | ||
length: number; | ||
kind: "query"; | ||
/** What line is the highlighted identifier on? */ | ||
line: number; | ||
/** At what index in the line does the caret represent */ | ||
offset: number; | ||
/** The text of the token which is highlighted */ | ||
text: string; | ||
/** Any attached JSDocs */ | ||
docs: string | undefined; | ||
/** The token start which the query indicates */ | ||
start: number; | ||
/** The length of the token */ | ||
length: number; | ||
}[]; | ||
@@ -91,2 +100,3 @@ /** Diagnostic error messages which came up when creating the program */ | ||
* @param extension For example: "ts", "tsx", "typescript", "javascript" or "js". | ||
* @param defaultOptions Allows setting any of the handbook options from outside the function, useful if you don't want LSP identifiers | ||
* @param tsModule An optional copy of the TypeScript import, if missing it will be require'd. | ||
@@ -97,3 +107,3 @@ * @param lzstringModule An optional copy of the lz-string import, if missing it will be require'd. | ||
*/ | ||
export declare function twoslasher(code: string, extension: string, tsModule?: TS, lzstringModule?: LZ, fsMap?: Map<string, string>): TwoSlashReturn; | ||
export declare function twoslasher(code: string, extension: string, defaultOptions?: Partial<ExampleOptions>, tsModule?: TS, lzstringModule?: LZ, fsMap?: Map<string, string>): TwoSlashReturn; | ||
export {}; |
@@ -133,3 +133,3 @@ 'use strict'; | ||
/*#__PURE__*/ | ||
debug('twoslasher'); | ||
debug("twoslasher"); | ||
@@ -141,2 +141,3 @@ function filterHighlightLines(codeLines) { | ||
var contentOffset = 0; | ||
var removedLines = 0; | ||
@@ -149,26 +150,23 @@ for (var i = 0; i < codeLines.length; i++) { | ||
if (queryMatch !== null) { | ||
var start = line.indexOf('^'); | ||
var position = contentOffset + start; | ||
var start = line.indexOf("^"); | ||
queries.push({ | ||
kind: 'query', | ||
kind: "query", | ||
offset: start, | ||
position: position, | ||
text: undefined, | ||
docs: undefined, | ||
line: i | ||
line: i + removedLines - 1 | ||
}); | ||
log("Removing line " + i + " for having a query"); | ||
removedLines++; | ||
codeLines.splice(i, 1); | ||
i--; | ||
} else if (highlightMatch !== null) { | ||
var _start = line.indexOf('^'); | ||
var _start = line.indexOf("^"); | ||
var length = line.lastIndexOf('^') - _start + 1; | ||
var _position = contentOffset + _start; | ||
var description = highlightMatch[1] ? highlightMatch[1].trim() : ''; | ||
var length = line.lastIndexOf("^") - _start + 1; | ||
var position = contentOffset + _start; | ||
var description = highlightMatch[1] ? highlightMatch[1].trim() : ""; | ||
highlights.push({ | ||
kind: 'highlight', | ||
position: _position, | ||
kind: "highlight", | ||
position: position, | ||
length: length, | ||
@@ -180,2 +178,3 @@ description: description, | ||
codeLines.splice(i, 1); | ||
removedLines++; | ||
i--; | ||
@@ -211,10 +210,10 @@ } else { | ||
switch (opt.type) { | ||
case 'number': | ||
case 'string': | ||
case 'boolean': | ||
case "number": | ||
case "string": | ||
case "boolean": | ||
opts[opt.name] = parsePrimitive(value, opt.type); | ||
break; | ||
case 'list': | ||
opts[opt.name] = value.split(',').map(function (v) { | ||
case "list": | ||
opts[opt.name] = value.split(",").map(function (v) { | ||
return parsePrimitive(v, opt.element.type); | ||
@@ -230,3 +229,3 @@ }); | ||
var keys = Array.from(opt.type.keys()); | ||
throw new Error("Invalid value " + value + " for " + opt.name + ". Allowed values: " + keys.join(',')); | ||
throw new Error("Invalid value " + value + " for " + opt.name + ". Allowed values: " + keys.join(",")); | ||
} | ||
@@ -272,6 +271,6 @@ | ||
options[match[1]] = true; | ||
setOption(match[1], 'true', options, ts); | ||
setOption(match[1], "true", options, ts); | ||
} else if (match = valuedConfigRegexp.exec(codeLines[i])) { | ||
// Skip a filename tag, which should propagate through this stage | ||
if (match[1] === 'filename') { | ||
if (match[1] === "filename") { | ||
i++; | ||
@@ -297,4 +296,6 @@ continue; | ||
showEmit: false, | ||
showEmittedFile: 'index.js', | ||
noStaticSemanticInfo: false | ||
showEmittedFile: "index.js", | ||
noStaticSemanticInfo: false, | ||
emit: false, | ||
noErrorValidation: false | ||
}; | ||
@@ -326,5 +327,5 @@ | ||
if ('errors' in options && typeof options.errors === 'string') { | ||
options.errors = options.errors.split(' ').map(Number); | ||
log('Setting options.error to ', options.errors); | ||
if ("errors" in options && typeof options.errors === "string") { | ||
options.errors = options.errors.split(" ").map(Number); | ||
log("Setting options.error to ", options.errors); | ||
} | ||
@@ -340,2 +341,3 @@ | ||
* @param extension For example: "ts", "tsx", "typescript", "javascript" or "js". | ||
* @param defaultOptions Allows setting any of the handbook options from outside the function, useful if you don't want LSP identifiers | ||
* @param tsModule An optional copy of the TypeScript import, if missing it will be require'd. | ||
@@ -348,8 +350,8 @@ * @param lzstringModule An optional copy of the lz-string import, if missing it will be require'd. | ||
function twoslasher(code, extension, tsModule, lzstringModule, fsMap) { | ||
var ts = tsModule !== null && tsModule !== void 0 ? tsModule : require('typescript'); | ||
var lzstring = lzstringModule !== null && lzstringModule !== void 0 ? lzstringModule : require('lz-string'); | ||
function twoslasher(code, extension, defaultOptions, tsModule, lzstringModule, fsMap) { | ||
var ts = tsModule !== null && tsModule !== void 0 ? tsModule : require("typescript"); | ||
var lzstring = lzstringModule !== null && lzstringModule !== void 0 ? lzstringModule : require("lz-string"); | ||
var originalCode = code; | ||
var safeExtension = typesToExtension(extension); | ||
var defaultFileName = 'index.' + safeExtension; | ||
var defaultFileName = "index." + safeExtension; | ||
log("\n\nLooking at code: \n```" + safeExtension + "\n" + code + "\n```\n"); | ||
@@ -365,3 +367,5 @@ var defaultCompilerOptions = { | ||
var codeLines = code.split(/\r\n?|\n/g); | ||
var handbookOptions = filterHandbookOptions(codeLines); | ||
var handbookOptions = _extends({}, filterHandbookOptions(codeLines), {}, defaultOptions); | ||
var compilerOptions = filterCompilerOptions(codeLines, defaultCompilerOptions, ts); | ||
@@ -372,7 +376,8 @@ var vfs$1 = fsMap !== null && fsMap !== void 0 ? fsMap : createLocallyPoweredVFS(compilerOptions); | ||
var ls = env.languageService; | ||
code = codeLines.join('\n'); | ||
code = codeLines.join("\n"); | ||
var partialQueries = []; | ||
var queries = []; | ||
var highlights = []; // TODO: This doesn't handle a single file with a name | ||
var fileContent = code.split('// @filename: '); | ||
var fileContent = code.split("// @filename: "); | ||
var noFilepaths = fileContent.length === 1; | ||
@@ -386,3 +391,3 @@ var makeDefault = [defaultFileName, code.split(/\r\n?|\n/g)]; | ||
var firstLine = '// @filename: ' + filename; | ||
var firstLine = "// @filename: " + filename; | ||
return [filename, [firstLine].concat(content)]; | ||
@@ -408,3 +413,3 @@ }; | ||
var _loop3 = function _loop3() { | ||
var _highlights, _queries; | ||
var _highlights, _partialQueries; | ||
@@ -424,3 +429,3 @@ if (_isArray2) { | ||
var newFileCode = codeLines.join('\n'); | ||
var newFileCode = codeLines.join("\n"); | ||
env.createFile(filename, newFileCode); | ||
@@ -430,41 +435,37 @@ var updates = filterHighlightLines(codeLines); | ||
(_highlights = highlights).push.apply(_highlights, updates.highlights); // ------ Do the LSP lookup for the queries | ||
// TODO: this is not perfect, it seems to have issues when there are multiple queries | ||
// in the same sourcefile. Looks like it's about removing the query comments before them. | ||
var removedChars = 0; | ||
var lspedQueries = updates.queries.map(function (q) { | ||
var quickInfo = ls.getQuickInfoAtPosition(filename, q.position - removedChars); | ||
var token = ls.getDefinitionAtPosition(filename, q.position - removedChars); | ||
removedChars += ('//' + q.offset + '?^\n').length; | ||
var text = "Could not get LSP result: " + stringAroundIndex(env.getSourceFile(filename).text, q.position); | ||
var docs, | ||
start = 0, | ||
length = 0; | ||
var lspedQueries = updates.queries.map(function (q, i) { | ||
var sourceFile = env.getSourceFile(filename); | ||
var position = ts.getPositionOfLineAndCharacter(sourceFile, q.line, q.offset); | ||
var quickInfo = ls.getQuickInfoAtPosition(filename, position); | ||
var token = ls.getDefinitionAtPosition(filename, position); // prettier-ignore | ||
var text = "Could not get LSP result: " + stringAroundIndex(env.getSourceFile(filename).text, position); | ||
var docs = undefined; | ||
if (quickInfo && token && quickInfo.displayParts) { | ||
text = quickInfo.displayParts.map(function (dp) { | ||
return dp.text; | ||
}).join(''); | ||
}).join(""); | ||
docs = quickInfo.documentation ? quickInfo.documentation.map(function (d) { | ||
return d.text; | ||
}).join('<br/>') : undefined; | ||
length = token[0].textSpan.start; | ||
start = token[0].textSpan.length; | ||
}).join("<br/>") : undefined; | ||
} | ||
var queryResult = _extends({}, q, { | ||
var queryResult = { | ||
kind: "query", | ||
text: text, | ||
docs: docs, | ||
start: start, | ||
length: length | ||
}); | ||
line: q.line - i, | ||
offset: q.offset, | ||
file: filename | ||
}; | ||
return queryResult; | ||
}); | ||
(_queries = queries).push.apply(_queries, lspedQueries); // Sets the file in the compiler as being without the comments | ||
(_partialQueries = partialQueries).push.apply(_partialQueries, lspedQueries); // Sets the file in the compiler as being without the comments | ||
var newEditedFileCode = codeLines.join('\n'); | ||
var newEditedFileCode = codeLines.join("\n"); | ||
env.updateFile(filename, newEditedFileCode); | ||
@@ -484,4 +485,11 @@ }; | ||
filterHighlightLines(allCodeLines); | ||
code = allCodeLines.join('\n'); // Code should now be safe to compile, so we're going to split it into different files | ||
code = allCodeLines.join("\n"); // Lets fs changes propagate back up to the fsMap | ||
if (handbookOptions.emit) { | ||
var _env$languageService$; | ||
(_env$languageService$ = env.languageService.getProgram()) === null || _env$languageService$ === void 0 ? void 0 : _env$languageService$.emit(); | ||
} // Code should now be safe to compile, so we're going to split it into different files | ||
var errs = []; // Let because of a filter when cutting | ||
@@ -496,60 +504,76 @@ | ||
errs.push.apply(errs, ls.getSyntacticDiagnostics(file)); | ||
} // Get all of the interesting quick info popover | ||
} | ||
var source = env.sys.readFile(file); | ||
var sourceFile = env.getSourceFile(file); | ||
if (!sourceFile) throw new Error("No sourcefile found for " + file + " in twoslash"); // Get all of the interesting quick info popover | ||
if (!handbookOptions.noStaticSemanticInfo && !handbookOptions.showEmit) { | ||
// const fileRep = fileMap[file] | ||
var source = env.sys.readFile(file); | ||
var fileContentStartIndexInModifiedFile = code.indexOf(source) == -1 ? 0 : code.indexOf(source); | ||
var sourceFile = env.getSourceFile(file); | ||
var linesAbove = code.slice(0, fileContentStartIndexInModifiedFile).split("\n").length - 1; // Get all interesting identifiers in the file, so we can show hover info for it | ||
if (sourceFile) { | ||
// Get all interesting identifiers in the file, so we can show hover info for it | ||
var identifiers = getIdentifierTextSpans(ts, sourceFile); | ||
var identifiers = getIdentifierTextSpans(ts, sourceFile); | ||
for (var _iterator3 = identifiers, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { | ||
var _ref3; | ||
for (var _iterator3 = identifiers, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { | ||
var _ref3; | ||
if (_isArray3) { | ||
if (_i3 >= _iterator3.length) break; | ||
_ref3 = _iterator3[_i3++]; | ||
} else { | ||
_i3 = _iterator3.next(); | ||
if (_i3.done) break; | ||
_ref3 = _i3.value; | ||
} | ||
if (_isArray3) { | ||
if (_i3 >= _iterator3.length) break; | ||
_ref3 = _iterator3[_i3++]; | ||
} else { | ||
_i3 = _iterator3.next(); | ||
if (_i3.done) break; | ||
_ref3 = _i3.value; | ||
} | ||
var identifier = _ref3; | ||
var span = identifier.span; | ||
var quickInfo = ls.getQuickInfoAtPosition(file, span.start); | ||
var identifier = _ref3; | ||
var span = identifier.span; | ||
var quickInfo = ls.getQuickInfoAtPosition(file, span.start); | ||
if (quickInfo && quickInfo.displayParts) { | ||
var text = quickInfo.displayParts.map(function (dp) { | ||
return dp.text; | ||
}).join(''); | ||
var targetString = identifier.text; | ||
var docs = quickInfo.documentation ? quickInfo.documentation.map(function (d) { | ||
return d.text; | ||
}).join('\n') : undefined; // Get the position of the | ||
if (quickInfo && quickInfo.displayParts) { | ||
var text = quickInfo.displayParts.map(function (dp) { | ||
return dp.text; | ||
}).join(""); | ||
var targetString = identifier.text; | ||
var docs = quickInfo.documentation ? quickInfo.documentation.map(function (d) { | ||
return d.text; | ||
}).join("\n") : undefined; // Get the position of the | ||
var position = span.start + fileContentStartIndexInModifiedFile; // Use TypeScript to pull out line/char from the original code at the position + any previous offset | ||
var position = span.start + fileContentStartIndexInModifiedFile; // Use TypeScript to pull out line/char from the original code at the position + any previous offset | ||
var burnerSourceFile = ts.createSourceFile('_.ts', code, ts.ScriptTarget.ES2015); | ||
var burnerSourceFile = ts.createSourceFile("_.ts", code, ts.ScriptTarget.ES2015); | ||
var _ts$getLineAndCharact = ts.getLineAndCharacterOfPosition(burnerSourceFile, position), | ||
line = _ts$getLineAndCharact.line, | ||
character = _ts$getLineAndCharact.character; | ||
var _ts$getLineAndCharact = ts.getLineAndCharacterOfPosition(burnerSourceFile, position), | ||
line = _ts$getLineAndCharact.line, | ||
character = _ts$getLineAndCharact.character; | ||
staticQuickInfos.push({ | ||
text: text, | ||
docs: docs, | ||
start: position, | ||
length: span.length, | ||
line: line, | ||
character: character, | ||
targetString: targetString | ||
}); | ||
} | ||
staticQuickInfos.push({ | ||
text: text, | ||
docs: docs, | ||
start: position, | ||
length: span.length, | ||
line: line, | ||
character: character, | ||
targetString: targetString | ||
}); | ||
} | ||
} | ||
} // Offset the queries for this file because they are based on the line for that one | ||
// specific file, and not the global twoslash document. This has to be done here because | ||
// in the above loops, the code for queries/highlights hasn't been stripped yet. | ||
partialQueries.filter(function (q) { | ||
return q.file === file; | ||
}).forEach(function (q) { | ||
var pos = ts.getPositionOfLineAndCharacter(sourceFile, q.line, q.offset) + fileContentStartIndexInModifiedFile; | ||
queries.push({ | ||
docs: q.docs, | ||
kind: "query", | ||
start: pos, | ||
length: q.text.length, | ||
text: q.text, | ||
offset: q.offset, | ||
line: q.line + linesAbove | ||
}); | ||
}); | ||
} | ||
@@ -561,3 +585,3 @@ }); | ||
if (relevantErrors.length) { | ||
if (!handbookOptions.noErrorValidation && relevantErrors.length) { | ||
validateCodeForErrors(relevantErrors, handbookOptions, extension, originalCode); | ||
@@ -583,3 +607,3 @@ } | ||
var fileContentStartIndexInModifiedFile = code.indexOf(codeWhereErrorLives); | ||
var renderedMessage = escapeHtml(ts.flattenDiagnosticMessageText(err.messageText, '\n')); | ||
var renderedMessage = escapeHtml(ts.flattenDiagnosticMessageText(err.messageText, "\n")); | ||
var id = "err-" + err.code + "-" + err.start + "-" + err.length; | ||
@@ -613,3 +637,3 @@ | ||
return o.name; | ||
}).join(', '); | ||
}).join(", "); | ||
throw new Error("Cannot find the file " + handbookOptions.showEmittedFile + " - in " + allFiles); | ||
@@ -619,7 +643,7 @@ } | ||
code = file.text; | ||
extension = file.name.split('.').pop(); // Remove highlights and queries, because it won't work across transpiles, | ||
extension = file.name.split(".").pop(); // Remove highlights and queries, because it won't work across transpiles, | ||
// though I guess source-mapping could handle the transition | ||
highlights = []; | ||
queries = []; | ||
partialQueries = []; | ||
staticQuickInfos = []; | ||
@@ -632,3 +656,3 @@ } | ||
var cutString = '// ---cut---\n'; | ||
var cutString = "// ---cut---\n"; | ||
@@ -638,3 +662,3 @@ if (code.includes(cutString)) { | ||
var cutIndex = code.indexOf(cutString) + cutString.length; | ||
var lineOffset = code.substr(0, cutIndex).split('\n').length - 1; // Kills the code shown | ||
var lineOffset = code.substr(0, cutIndex).split("\n").length - 1; // Kills the code shown | ||
@@ -666,6 +690,6 @@ code = code.split(cutString).pop(); // For any type of metadata shipped, it will need to be shifted to | ||
queries.forEach(function (q) { | ||
return q.start -= cutIndex; | ||
return q.line -= lineOffset; | ||
}); | ||
queries = queries.filter(function (q) { | ||
return q.start > -1; | ||
return q.line > -1; | ||
}); | ||
@@ -672,0 +696,0 @@ } |
@@ -1,2 +0,2 @@ | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=(e=require("debug"))&&"object"==typeof e&&"default"in e?e.default:e,r=require("@typescript/vfs");function n(){return(n=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e}).apply(this,arguments)}function i(e,t){switch(t){case"number":return+e;case"string":return e;case"boolean":return"true"===e.toLowerCase()||0===e.length}throw new Error("Unknown primitive type "+t+" with - "+e)}var o=t("twoslasher");function a(e){for(var t=[],r=[],n=0,i=0,a=0;a<e.length;a++){var s=e[a],l=/^\/\/\s*\^+( .+)?$/.exec(s);if(null!==/^\/\/\s*\^\?\s*$/.exec(s)){var c=s.indexOf("^");r.push({kind:"query",offset:c,position:i+c,text:void 0,docs:void 0,line:a}),o("Removing line "+a+" for having a query"),e.splice(a,1),a--}else if(null!==l){var u=s.indexOf("^"),f=s.lastIndexOf("^")-u+1,p=i+u,g=l[1]?l[1].trim():"";t.push({kind:"highlight",position:p,length:f,description:g,line:a}),o("Removing line "+a+" for having a highlight"),e.splice(a,1),a--}else i=n,n+=s.length+1}return{highlights:t,queries:r}}function s(e,t,r,n){o("Setting "+e+" to "+t);var a=function(){if(l){if(c>=s.length)return"break";u=s[c++]}else{if((c=s.next()).done)return"break";u=c.value}var n=u;if(n.name.toLowerCase()===e.toLowerCase()){switch(n.type){case"number":case"string":case"boolean":r[n.name]=i(t,n.type);break;case"list":r[n.name]=t.split(",").map((function(e){return i(e,n.element.type)}));break;default:if(r[n.name]=n.type.get(t.toLowerCase()),o("Set "+n.name+" to "+r[n.name]),void 0===r[n.name]){var a=Array.from(n.type.keys());throw new Error("Invalid value "+t+" for "+n.name+". Allowed values: "+a.join(","))}}return{v:void 0}}},s=n.optionDeclarations,l=Array.isArray(s),c=0;e:for(s=l?s:s[Symbol.iterator]();;){var u,f=a();switch(f){case"break":break e;default:if("object"==typeof f)return f.v}}throw new Error("No compiler setting named '"+e+"' exists!")}var l=/^\/\/\s?@(\w+)$/,c=/^\/\/\s?@(\w+):\s?(.+)$/,u={errors:[],noErrors:!1,showEmit:!1,showEmittedFile:"index.js",noStaticSemanticInfo:!1};exports.twoslasher=function(e,t,i,f,p){var g=null!=i?i:require("typescript"),h=null!=f?f:require("lz-string"),d=e,v=function(e){switch(e){case"js":case"javascript":return"js";case"ts":case"typescript":return"ts";case"tsx":return"tsx";case"jsn":return"json"}throw new Error("Cannot handle the file extension:"+e)}(t),m="index."+v;o("\n\nLooking at code: \n```"+v+"\n"+e+"\n```\n");var y={strict:!0,target:g.ScriptTarget.ES2016,allowJs:!0};!function(e){if(e.includes("// @errors "))throw new Error("You have '@errors ' - you're missing the colon after errors");if(e.includes("// @filename "))throw new Error("You have '@filename ' - you're missing the colon after filename")}(e);var x=(e=function(e){return(e=e.replace(/¨D/g,"$")).replace(/¨T/g,"~")}(e)).split(/\r\n?|\n/g),w=function(e){for(var t=n({},u),r=0;r<e.length;r++){var i=void 0;(i=l.exec(e[r]))?i[1]in t&&(t[i[1]]=!0,o("Setting options."+i[1]+" to true"),e.splice(r,1),r--):(i=c.exec(e[r]))&&i[1]in t&&(t[i[1]]=i[2],o("Setting options."+i[1]+" to "+i[2]),e.splice(r,1),r--)}return"errors"in t&&"string"==typeof t.errors&&(t.errors=t.errors.split(" ").map(Number),o("Setting options.error to ",t.errors)),t}(x),b=function(e,t,r){for(var i=n({},t),o=0;o<e.length;){var a=void 0;if(a=l.exec(e[o]))i[a[1]]=!0,s(a[1],"true",i,r);else{if(!(a=c.exec(e[o]))){o++;continue}if("filename"===a[1]){o++;continue}s(a[1],a[2],i,r)}e.splice(o,1)}return i}(x,y,g),S=null!=p?p:function(e){return r.createDefaultMapFromNodeModules(e)}(b),E=r.createSystem(S),j=r.createVirtualTypeScriptEnvironment(E,[],g,b),k=j.languageService;e=x.join("\n");var A=[],O=[],F=e.split("// @filename: "),T=1===F.length,C=[m,e.split(/\r\n?|\n/g)],P=(T?[C]:F.map((function(e){var t=e.split(/\r\n?|\n/g),r=t[0],n=t.slice(1);return[r,["// @filename: "+r].concat(n)]}))).filter((function(e){return e[0].length})),q=P.map((function(e){return e[0]})),I=function(){var e,t;if(D){if(M>=L.length)return"break";N=L[M++]}else{if((M=L.next()).done)return"break";N=M.value}var r=N[0],i=N[1],o=i.join("\n");j.createFile(r,o);var s=a(i);(e=O).push.apply(e,s.highlights);var l=0,c=s.queries.map((function(e){var t=k.getQuickInfoAtPosition(r,e.position-l),i=k.getDefinitionAtPosition(r,e.position-l);l+=("//"+e.offset+"?^\n").length;var o,a,s,c="Could not get LSP result: "+[(o=j.getSourceFile(r).text)[(a=e.position)-3],o[a-2],o[a-1],">",o[a],"<",o[a+1],o[a+2],o[a+3]].filter(Boolean).join(""),u=0,f=0;return t&&i&&t.displayParts&&(c=t.displayParts.map((function(e){return e.text})).join(""),s=t.documentation?t.documentation.map((function(e){return e.text})).join("<br/>"):void 0,f=i[0].textSpan.start,u=i[0].textSpan.length),n({},e,{text:c,docs:s,start:u,length:f})}));(t=A).push.apply(t,c);var u=i.join("\n");j.updateFile(r,u)},L=P,D=Array.isArray(L),M=0;for(L=D?L:L[Symbol.iterator]();;){var N;if("break"===I())break}var $=e.split(/\r\n?|\n/g);a($),e=$.join("\n");var R=[],Q=[];q.forEach((function(t){if(w.noErrors||(R.push.apply(R,k.getSemanticDiagnostics(t)),R.push.apply(R,k.getSyntacticDiagnostics(t))),!w.noStaticSemanticInfo&&!w.showEmit){var r=j.sys.readFile(t),n=-1==e.indexOf(r)?0:e.indexOf(r),i=j.getSourceFile(t);if(i){var o=function(e,t){var r=[];return function n(i){e.forEachChild(i,(function(i){if(e.isIdentifier(i)){var o=i.getStart(t,!1);r.push({span:e.createTextSpan(o,i.end-o),text:i.getText(t)})}n(i)}))}(t),r}(g,i),a=Array.isArray(o),s=0;for(o=a?o:o[Symbol.iterator]();;){var l;if(a){if(s>=o.length)break;l=o[s++]}else{if((s=o.next()).done)break;l=s.value}var c=l,u=c.span,f=k.getQuickInfoAtPosition(t,u.start);if(f&&f.displayParts){var p=f.displayParts.map((function(e){return e.text})).join(""),h=c.text,d=f.documentation?f.documentation.map((function(e){return e.text})).join("\n"):void 0,v=u.start+n,m=g.createSourceFile("_.ts",e,g.ScriptTarget.ES2015),y=g.getLineAndCharacterOfPosition(m,v);Q.push({text:p,docs:d,start:v,length:u.length,line:y.line,character:y.character,targetString:h})}}}}}));var U=R.filter((function(e){return e.file&&q.includes(e.file.fileName)}));U.length&&function(e,t,r,n){var i=e.filter((function(e){return!t.errors.includes(e.code)})),o=i.map((function(e){return e.code})).join(" ");if(i.length){var a="// @errors: "+e.map((function(e){return e.code})).join(" "),s=t.errors.length?" - the annotation specified "+t.errors:"\n\nExpected:\n"+a,l=i.map((function(e){return"["+e.code+"] - "+("string"==typeof e.messageText?e.messageText:e.messageText.messageText)})).join("\n ");throw new Error("Errors were thrown in the sample, but not included in an errors tag: "+o+s+"\n\n "+l+"\n\n## Code\n\n'''"+r+"\n"+n+"\n'''")}}(U,w,t,d);var _=[],Y=U,z=Array.isArray(Y),B=0;for(Y=z?Y:Y[Symbol.iterator]();;){var J;if(z){if(B>=Y.length)break;J=Y[B++]}else{if((B=Y.next()).done)break;J=B.value}var V=J,G=j.sys.readFile(V.file.fileName),H=e.indexOf(G),K=g.flattenDiagnosticMessageText(V.messageText,"\n").replace(/</g,"<"),W="err-"+V.code+"-"+V.start+"-"+V.length,X=g.getLineAndCharacterOfPosition(V.file,V.start);_.push({category:V.category,code:V.code,length:V.length,start:V.start?V.start+H:void 0,line:X.line,character:X.character,renderedMessage:K,id:W})}if(w.showEmit){var Z=k.getEmitOutput(m),ee=Z.outputFiles.find((function(e){return e.name===w.showEmittedFile}));if(!ee){var te=Z.outputFiles.map((function(e){return e.name})).join(", ");throw new Error("Cannot find the file "+w.showEmittedFile+" - in "+te)}e=ee.text,t=ee.name.split(".").pop(),O=[],A=[],Q=[]}var re="https://www.typescriptlang.org/play/#code/"+h.compressToEncodedURIComponent(d),ne="// ---cut---\n";if(e.includes(ne)){var ie=e.indexOf(ne)+ne.length,oe=e.substr(0,ie).split("\n").length-1;e=e.split(ne).pop(),Q.forEach((function(e){e.start-=ie,e.line-=oe})),Q=Q.filter((function(e){return e.start>-1})),_.forEach((function(e){e.start&&(e.start-=ie),e.line&&(e.line-=oe)})),_=_.filter((function(e){return e.start&&e.start>-1})),O.forEach((function(e){e.position-=ie,e.line-=oe})),O=O.filter((function(e){return e.position>-1})),A.forEach((function(e){return e.start-=ie})),A=A.filter((function(e){return e.start>-1}))}return{code:e,extension:t,highlights:O,queries:A,staticQuickInfos:Q,errors:_,playgroundURL:re}}; | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,t=(e=require("debug"))&&"object"==typeof e&&"default"in e?e.default:e,r=require("@typescript/vfs");function n(){return(n=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var n in r)Object.prototype.hasOwnProperty.call(r,n)&&(e[n]=r[n])}return e}).apply(this,arguments)}function i(e,t){switch(t){case"number":return+e;case"string":return e;case"boolean":return"true"===e.toLowerCase()||0===e.length}throw new Error("Unknown primitive type "+t+" with - "+e)}var o=t("twoslasher");function a(e){for(var t=[],r=[],n=0,i=0,a=0,s=0;s<e.length;s++){var l=e[s],c=/^\/\/\s*\^+( .+)?$/.exec(l);if(null!==/^\/\/\s*\^\?\s*$/.exec(l)){var u=l.indexOf("^");r.push({kind:"query",offset:u,text:void 0,docs:void 0,line:s+a-1}),o("Removing line "+s+" for having a query"),a++,e.splice(s,1),s--}else if(null!==c){var f=l.indexOf("^"),p=l.lastIndexOf("^")-f+1,g=i+f,h=c[1]?c[1].trim():"";t.push({kind:"highlight",position:g,length:p,description:h,line:s}),o("Removing line "+s+" for having a highlight"),e.splice(s,1),a++,s--}else i=n,n+=l.length+1}return{highlights:t,queries:r}}function s(e,t,r,n){o("Setting "+e+" to "+t);var a=function(){if(l){if(c>=s.length)return"break";u=s[c++]}else{if((c=s.next()).done)return"break";u=c.value}var n=u;if(n.name.toLowerCase()===e.toLowerCase()){switch(n.type){case"number":case"string":case"boolean":r[n.name]=i(t,n.type);break;case"list":r[n.name]=t.split(",").map((function(e){return i(e,n.element.type)}));break;default:if(r[n.name]=n.type.get(t.toLowerCase()),o("Set "+n.name+" to "+r[n.name]),void 0===r[n.name]){var a=Array.from(n.type.keys());throw new Error("Invalid value "+t+" for "+n.name+". Allowed values: "+a.join(","))}}return{v:void 0}}},s=n.optionDeclarations,l=Array.isArray(s),c=0;e:for(s=l?s:s[Symbol.iterator]();;){var u,f=a();switch(f){case"break":break e;default:if("object"==typeof f)return f.v}}throw new Error("No compiler setting named '"+e+"' exists!")}var l=/^\/\/\s?@(\w+)$/,c=/^\/\/\s?@(\w+):\s?(.+)$/,u={errors:[],noErrors:!1,showEmit:!1,showEmittedFile:"index.js",noStaticSemanticInfo:!1,emit:!1,noErrorValidation:!1};exports.twoslasher=function(e,t,i,f,p,g){var h=null!=f?f:require("typescript"),d=null!=p?p:require("lz-string"),v=e,m=function(e){switch(e){case"js":case"javascript":return"js";case"ts":case"typescript":return"ts";case"tsx":return"tsx";case"jsn":return"json"}throw new Error("Cannot handle the file extension:"+e)}(t),y="index."+m;o("\n\nLooking at code: \n```"+m+"\n"+e+"\n```\n");var x={strict:!0,target:h.ScriptTarget.ES2016,allowJs:!0};!function(e){if(e.includes("// @errors "))throw new Error("You have '@errors ' - you're missing the colon after errors");if(e.includes("// @filename "))throw new Error("You have '@filename ' - you're missing the colon after filename")}(e);var w=(e=function(e){return(e=e.replace(/¨D/g,"$")).replace(/¨T/g,"~")}(e)).split(/\r\n?|\n/g),E=n({},function(e){for(var t=n({},u),r=0;r<e.length;r++){var i=void 0;(i=l.exec(e[r]))?i[1]in t&&(t[i[1]]=!0,o("Setting options."+i[1]+" to true"),e.splice(r,1),r--):(i=c.exec(e[r]))&&i[1]in t&&(t[i[1]]=i[2],o("Setting options."+i[1]+" to "+i[2]),e.splice(r,1),r--)}return"errors"in t&&"string"==typeof t.errors&&(t.errors=t.errors.split(" ").map(Number),o("Setting options.error to ",t.errors)),t}(w),{},i),b=function(e,t,r){for(var i=n({},t),o=0;o<e.length;){var a=void 0;if(a=l.exec(e[o]))i[a[1]]=!0,s(a[1],"true",i,r);else{if(!(a=c.exec(e[o]))){o++;continue}if("filename"===a[1]){o++;continue}s(a[1],a[2],i,r)}e.splice(o,1)}return i}(w,x,h),S=null!=g?g:function(e){return r.createDefaultMapFromNodeModules(e)}(b),j=r.createSystem(S),k=r.createVirtualTypeScriptEnvironment(j,[],h,b),A=k.languageService;e=w.join("\n");var O=[],P=[],C=[],F=e.split("// @filename: "),T=1===F.length,q=[y,e.split(/\r\n?|\n/g)],L=(T?[q]:F.map((function(e){var t=e.split(/\r\n?|\n/g),r=t[0],n=t.slice(1);return[r,["// @filename: "+r].concat(n)]}))).filter((function(e){return e[0].length})),I=L.map((function(e){return e[0]})),D=function(){var e,t;if(M){if($>=N.length)return"break";R=N[$++]}else{if(($=N.next()).done)return"break";R=$.value}var r=R[0],n=R[1],i=n.join("\n");k.createFile(r,i);var o=a(n);(e=C).push.apply(e,o.highlights);var s=o.queries.map((function(e,t){var n,i,o=k.getSourceFile(r),a=h.getPositionOfLineAndCharacter(o,e.line,e.offset),s=A.getQuickInfoAtPosition(r,a),l=A.getDefinitionAtPosition(r,a),c="Could not get LSP result: "+[(n=k.getSourceFile(r).text)[(i=a)-3],n[i-2],n[i-1],">",n[i],"<",n[i+1],n[i+2],n[i+3]].filter(Boolean).join(""),u=void 0;return s&&l&&s.displayParts&&(c=s.displayParts.map((function(e){return e.text})).join(""),u=s.documentation?s.documentation.map((function(e){return e.text})).join("<br/>"):void 0),{kind:"query",text:c,docs:u,line:e.line-t,offset:e.offset,file:r}}));(t=O).push.apply(t,s);var l=n.join("\n");k.updateFile(r,l)},N=L,M=Array.isArray(N),$=0;for(N=M?N:N[Symbol.iterator]();;){var R;if("break"===D())break}var Q,U=e.split(/\r\n?|\n/g);a(U),e=U.join("\n"),E.emit&&(null===(Q=k.languageService.getProgram())||void 0===Q||Q.emit());var V=[],_=[];I.forEach((function(t){E.noErrors||(V.push.apply(V,A.getSemanticDiagnostics(t)),V.push.apply(V,A.getSyntacticDiagnostics(t)));var r=k.sys.readFile(t),n=k.getSourceFile(t);if(!n)throw new Error("No sourcefile found for "+t+" in twoslash");if(!E.noStaticSemanticInfo&&!E.showEmit){var i=-1==e.indexOf(r)?0:e.indexOf(r),o=e.slice(0,i).split("\n").length-1,a=function(e,t){var r=[];return function n(i){e.forEachChild(i,(function(i){if(e.isIdentifier(i)){var o=i.getStart(t,!1);r.push({span:e.createTextSpan(o,i.end-o),text:i.getText(t)})}n(i)}))}(t),r}(h,n),s=Array.isArray(a),l=0;for(a=s?a:a[Symbol.iterator]();;){var c;if(s){if(l>=a.length)break;c=a[l++]}else{if((l=a.next()).done)break;c=l.value}var u=c,f=u.span,p=A.getQuickInfoAtPosition(t,f.start);if(p&&p.displayParts){var g=p.displayParts.map((function(e){return e.text})).join(""),d=u.text,v=p.documentation?p.documentation.map((function(e){return e.text})).join("\n"):void 0,m=f.start+i,y=h.createSourceFile("_.ts",e,h.ScriptTarget.ES2015),x=h.getLineAndCharacterOfPosition(y,m);_.push({text:g,docs:v,start:m,length:f.length,line:x.line,character:x.character,targetString:d})}}O.filter((function(e){return e.file===t})).forEach((function(e){var t=h.getPositionOfLineAndCharacter(n,e.line,e.offset)+i;P.push({docs:e.docs,kind:"query",start:t,length:e.text.length,text:e.text,offset:e.offset,line:e.line+o})}))}}));var Y=V.filter((function(e){return e.file&&I.includes(e.file.fileName)}));!E.noErrorValidation&&Y.length&&function(e,t,r,n){var i=e.filter((function(e){return!t.errors.includes(e.code)})),o=i.map((function(e){return e.code})).join(" ");if(i.length){var a="// @errors: "+e.map((function(e){return e.code})).join(" "),s=t.errors.length?" - the annotation specified "+t.errors:"\n\nExpected:\n"+a,l=i.map((function(e){return"["+e.code+"] - "+("string"==typeof e.messageText?e.messageText:e.messageText.messageText)})).join("\n ");throw new Error("Errors were thrown in the sample, but not included in an errors tag: "+o+s+"\n\n "+l+"\n\n## Code\n\n'''"+r+"\n"+n+"\n'''")}}(Y,E,t,v);var z=[],B=Y,J=Array.isArray(B),G=0;for(B=J?B:B[Symbol.iterator]();;){var H;if(J){if(G>=B.length)break;H=B[G++]}else{if((G=B.next()).done)break;H=G.value}var K=H,W=k.sys.readFile(K.file.fileName),X=e.indexOf(W),Z=h.flattenDiagnosticMessageText(K.messageText,"\n").replace(/</g,"<"),ee="err-"+K.code+"-"+K.start+"-"+K.length,te=h.getLineAndCharacterOfPosition(K.file,K.start);z.push({category:K.category,code:K.code,length:K.length,start:K.start?K.start+X:void 0,line:te.line,character:te.character,renderedMessage:Z,id:ee})}if(E.showEmit){var re=A.getEmitOutput(y),ne=re.outputFiles.find((function(e){return e.name===E.showEmittedFile}));if(!ne){var ie=re.outputFiles.map((function(e){return e.name})).join(", ");throw new Error("Cannot find the file "+E.showEmittedFile+" - in "+ie)}e=ne.text,t=ne.name.split(".").pop(),C=[],O=[],_=[]}var oe="https://www.typescriptlang.org/play/#code/"+d.compressToEncodedURIComponent(v),ae="// ---cut---\n";if(e.includes(ae)){var se=e.indexOf(ae)+ae.length,le=e.substr(0,se).split("\n").length-1;e=e.split(ae).pop(),_.forEach((function(e){e.start-=se,e.line-=le})),_=_.filter((function(e){return e.start>-1})),z.forEach((function(e){e.start&&(e.start-=se),e.line&&(e.line-=le)})),z=z.filter((function(e){return e.start&&e.start>-1})),C.forEach((function(e){e.position-=se,e.line-=le})),C=C.filter((function(e){return e.position>-1})),P.forEach((function(e){return e.line-=le})),P=P.filter((function(e){return e.line>-1}))}return{code:e,extension:t,highlights:C,queries:P,staticQuickInfos:_,errors:z,playgroundURL:oe}}; | ||
//# sourceMappingURL=twoslash.cjs.production.min.js.map |
@@ -127,3 +127,3 @@ import debug from 'debug'; | ||
/*#__PURE__*/ | ||
debug('twoslasher'); | ||
debug("twoslasher"); | ||
@@ -135,2 +135,3 @@ function filterHighlightLines(codeLines) { | ||
var contentOffset = 0; | ||
var removedLines = 0; | ||
@@ -143,26 +144,23 @@ for (var i = 0; i < codeLines.length; i++) { | ||
if (queryMatch !== null) { | ||
var start = line.indexOf('^'); | ||
var position = contentOffset + start; | ||
var start = line.indexOf("^"); | ||
queries.push({ | ||
kind: 'query', | ||
kind: "query", | ||
offset: start, | ||
position: position, | ||
text: undefined, | ||
docs: undefined, | ||
line: i | ||
line: i + removedLines - 1 | ||
}); | ||
log("Removing line " + i + " for having a query"); | ||
removedLines++; | ||
codeLines.splice(i, 1); | ||
i--; | ||
} else if (highlightMatch !== null) { | ||
var _start = line.indexOf('^'); | ||
var _start = line.indexOf("^"); | ||
var length = line.lastIndexOf('^') - _start + 1; | ||
var _position = contentOffset + _start; | ||
var description = highlightMatch[1] ? highlightMatch[1].trim() : ''; | ||
var length = line.lastIndexOf("^") - _start + 1; | ||
var position = contentOffset + _start; | ||
var description = highlightMatch[1] ? highlightMatch[1].trim() : ""; | ||
highlights.push({ | ||
kind: 'highlight', | ||
position: _position, | ||
kind: "highlight", | ||
position: position, | ||
length: length, | ||
@@ -174,2 +172,3 @@ description: description, | ||
codeLines.splice(i, 1); | ||
removedLines++; | ||
i--; | ||
@@ -205,10 +204,10 @@ } else { | ||
switch (opt.type) { | ||
case 'number': | ||
case 'string': | ||
case 'boolean': | ||
case "number": | ||
case "string": | ||
case "boolean": | ||
opts[opt.name] = parsePrimitive(value, opt.type); | ||
break; | ||
case 'list': | ||
opts[opt.name] = value.split(',').map(function (v) { | ||
case "list": | ||
opts[opt.name] = value.split(",").map(function (v) { | ||
return parsePrimitive(v, opt.element.type); | ||
@@ -224,3 +223,3 @@ }); | ||
var keys = Array.from(opt.type.keys()); | ||
throw new Error("Invalid value " + value + " for " + opt.name + ". Allowed values: " + keys.join(',')); | ||
throw new Error("Invalid value " + value + " for " + opt.name + ". Allowed values: " + keys.join(",")); | ||
} | ||
@@ -266,6 +265,6 @@ | ||
options[match[1]] = true; | ||
setOption(match[1], 'true', options, ts); | ||
setOption(match[1], "true", options, ts); | ||
} else if (match = valuedConfigRegexp.exec(codeLines[i])) { | ||
// Skip a filename tag, which should propagate through this stage | ||
if (match[1] === 'filename') { | ||
if (match[1] === "filename") { | ||
i++; | ||
@@ -291,4 +290,6 @@ continue; | ||
showEmit: false, | ||
showEmittedFile: 'index.js', | ||
noStaticSemanticInfo: false | ||
showEmittedFile: "index.js", | ||
noStaticSemanticInfo: false, | ||
emit: false, | ||
noErrorValidation: false | ||
}; | ||
@@ -320,5 +321,5 @@ | ||
if ('errors' in options && typeof options.errors === 'string') { | ||
options.errors = options.errors.split(' ').map(Number); | ||
log('Setting options.error to ', options.errors); | ||
if ("errors" in options && typeof options.errors === "string") { | ||
options.errors = options.errors.split(" ").map(Number); | ||
log("Setting options.error to ", options.errors); | ||
} | ||
@@ -334,2 +335,3 @@ | ||
* @param extension For example: "ts", "tsx", "typescript", "javascript" or "js". | ||
* @param defaultOptions Allows setting any of the handbook options from outside the function, useful if you don't want LSP identifiers | ||
* @param tsModule An optional copy of the TypeScript import, if missing it will be require'd. | ||
@@ -342,8 +344,8 @@ * @param lzstringModule An optional copy of the lz-string import, if missing it will be require'd. | ||
function twoslasher(code, extension, tsModule, lzstringModule, fsMap) { | ||
var ts = tsModule !== null && tsModule !== void 0 ? tsModule : require('typescript'); | ||
var lzstring = lzstringModule !== null && lzstringModule !== void 0 ? lzstringModule : require('lz-string'); | ||
function twoslasher(code, extension, defaultOptions, tsModule, lzstringModule, fsMap) { | ||
var ts = tsModule !== null && tsModule !== void 0 ? tsModule : require("typescript"); | ||
var lzstring = lzstringModule !== null && lzstringModule !== void 0 ? lzstringModule : require("lz-string"); | ||
var originalCode = code; | ||
var safeExtension = typesToExtension(extension); | ||
var defaultFileName = 'index.' + safeExtension; | ||
var defaultFileName = "index." + safeExtension; | ||
log("\n\nLooking at code: \n```" + safeExtension + "\n" + code + "\n```\n"); | ||
@@ -359,3 +361,5 @@ var defaultCompilerOptions = { | ||
var codeLines = code.split(/\r\n?|\n/g); | ||
var handbookOptions = filterHandbookOptions(codeLines); | ||
var handbookOptions = _extends({}, filterHandbookOptions(codeLines), {}, defaultOptions); | ||
var compilerOptions = filterCompilerOptions(codeLines, defaultCompilerOptions, ts); | ||
@@ -366,7 +370,8 @@ var vfs = fsMap !== null && fsMap !== void 0 ? fsMap : createLocallyPoweredVFS(compilerOptions); | ||
var ls = env.languageService; | ||
code = codeLines.join('\n'); | ||
code = codeLines.join("\n"); | ||
var partialQueries = []; | ||
var queries = []; | ||
var highlights = []; // TODO: This doesn't handle a single file with a name | ||
var fileContent = code.split('// @filename: '); | ||
var fileContent = code.split("// @filename: "); | ||
var noFilepaths = fileContent.length === 1; | ||
@@ -380,3 +385,3 @@ var makeDefault = [defaultFileName, code.split(/\r\n?|\n/g)]; | ||
var firstLine = '// @filename: ' + filename; | ||
var firstLine = "// @filename: " + filename; | ||
return [filename, [firstLine].concat(content)]; | ||
@@ -402,3 +407,3 @@ }; | ||
var _loop3 = function _loop3() { | ||
var _highlights, _queries; | ||
var _highlights, _partialQueries; | ||
@@ -418,3 +423,3 @@ if (_isArray2) { | ||
var newFileCode = codeLines.join('\n'); | ||
var newFileCode = codeLines.join("\n"); | ||
env.createFile(filename, newFileCode); | ||
@@ -424,41 +429,37 @@ var updates = filterHighlightLines(codeLines); | ||
(_highlights = highlights).push.apply(_highlights, updates.highlights); // ------ Do the LSP lookup for the queries | ||
// TODO: this is not perfect, it seems to have issues when there are multiple queries | ||
// in the same sourcefile. Looks like it's about removing the query comments before them. | ||
var removedChars = 0; | ||
var lspedQueries = updates.queries.map(function (q) { | ||
var quickInfo = ls.getQuickInfoAtPosition(filename, q.position - removedChars); | ||
var token = ls.getDefinitionAtPosition(filename, q.position - removedChars); | ||
removedChars += ('//' + q.offset + '?^\n').length; | ||
var text = "Could not get LSP result: " + stringAroundIndex(env.getSourceFile(filename).text, q.position); | ||
var docs, | ||
start = 0, | ||
length = 0; | ||
var lspedQueries = updates.queries.map(function (q, i) { | ||
var sourceFile = env.getSourceFile(filename); | ||
var position = ts.getPositionOfLineAndCharacter(sourceFile, q.line, q.offset); | ||
var quickInfo = ls.getQuickInfoAtPosition(filename, position); | ||
var token = ls.getDefinitionAtPosition(filename, position); // prettier-ignore | ||
var text = "Could not get LSP result: " + stringAroundIndex(env.getSourceFile(filename).text, position); | ||
var docs = undefined; | ||
if (quickInfo && token && quickInfo.displayParts) { | ||
text = quickInfo.displayParts.map(function (dp) { | ||
return dp.text; | ||
}).join(''); | ||
}).join(""); | ||
docs = quickInfo.documentation ? quickInfo.documentation.map(function (d) { | ||
return d.text; | ||
}).join('<br/>') : undefined; | ||
length = token[0].textSpan.start; | ||
start = token[0].textSpan.length; | ||
}).join("<br/>") : undefined; | ||
} | ||
var queryResult = _extends({}, q, { | ||
var queryResult = { | ||
kind: "query", | ||
text: text, | ||
docs: docs, | ||
start: start, | ||
length: length | ||
}); | ||
line: q.line - i, | ||
offset: q.offset, | ||
file: filename | ||
}; | ||
return queryResult; | ||
}); | ||
(_queries = queries).push.apply(_queries, lspedQueries); // Sets the file in the compiler as being without the comments | ||
(_partialQueries = partialQueries).push.apply(_partialQueries, lspedQueries); // Sets the file in the compiler as being without the comments | ||
var newEditedFileCode = codeLines.join('\n'); | ||
var newEditedFileCode = codeLines.join("\n"); | ||
env.updateFile(filename, newEditedFileCode); | ||
@@ -478,4 +479,11 @@ }; | ||
filterHighlightLines(allCodeLines); | ||
code = allCodeLines.join('\n'); // Code should now be safe to compile, so we're going to split it into different files | ||
code = allCodeLines.join("\n"); // Lets fs changes propagate back up to the fsMap | ||
if (handbookOptions.emit) { | ||
var _env$languageService$; | ||
(_env$languageService$ = env.languageService.getProgram()) === null || _env$languageService$ === void 0 ? void 0 : _env$languageService$.emit(); | ||
} // Code should now be safe to compile, so we're going to split it into different files | ||
var errs = []; // Let because of a filter when cutting | ||
@@ -490,60 +498,76 @@ | ||
errs.push.apply(errs, ls.getSyntacticDiagnostics(file)); | ||
} // Get all of the interesting quick info popover | ||
} | ||
var source = env.sys.readFile(file); | ||
var sourceFile = env.getSourceFile(file); | ||
if (!sourceFile) throw new Error("No sourcefile found for " + file + " in twoslash"); // Get all of the interesting quick info popover | ||
if (!handbookOptions.noStaticSemanticInfo && !handbookOptions.showEmit) { | ||
// const fileRep = fileMap[file] | ||
var source = env.sys.readFile(file); | ||
var fileContentStartIndexInModifiedFile = code.indexOf(source) == -1 ? 0 : code.indexOf(source); | ||
var sourceFile = env.getSourceFile(file); | ||
var linesAbove = code.slice(0, fileContentStartIndexInModifiedFile).split("\n").length - 1; // Get all interesting identifiers in the file, so we can show hover info for it | ||
if (sourceFile) { | ||
// Get all interesting identifiers in the file, so we can show hover info for it | ||
var identifiers = getIdentifierTextSpans(ts, sourceFile); | ||
var identifiers = getIdentifierTextSpans(ts, sourceFile); | ||
for (var _iterator3 = identifiers, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { | ||
var _ref3; | ||
for (var _iterator3 = identifiers, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { | ||
var _ref3; | ||
if (_isArray3) { | ||
if (_i3 >= _iterator3.length) break; | ||
_ref3 = _iterator3[_i3++]; | ||
} else { | ||
_i3 = _iterator3.next(); | ||
if (_i3.done) break; | ||
_ref3 = _i3.value; | ||
} | ||
if (_isArray3) { | ||
if (_i3 >= _iterator3.length) break; | ||
_ref3 = _iterator3[_i3++]; | ||
} else { | ||
_i3 = _iterator3.next(); | ||
if (_i3.done) break; | ||
_ref3 = _i3.value; | ||
} | ||
var identifier = _ref3; | ||
var span = identifier.span; | ||
var quickInfo = ls.getQuickInfoAtPosition(file, span.start); | ||
var identifier = _ref3; | ||
var span = identifier.span; | ||
var quickInfo = ls.getQuickInfoAtPosition(file, span.start); | ||
if (quickInfo && quickInfo.displayParts) { | ||
var text = quickInfo.displayParts.map(function (dp) { | ||
return dp.text; | ||
}).join(''); | ||
var targetString = identifier.text; | ||
var docs = quickInfo.documentation ? quickInfo.documentation.map(function (d) { | ||
return d.text; | ||
}).join('\n') : undefined; // Get the position of the | ||
if (quickInfo && quickInfo.displayParts) { | ||
var text = quickInfo.displayParts.map(function (dp) { | ||
return dp.text; | ||
}).join(""); | ||
var targetString = identifier.text; | ||
var docs = quickInfo.documentation ? quickInfo.documentation.map(function (d) { | ||
return d.text; | ||
}).join("\n") : undefined; // Get the position of the | ||
var position = span.start + fileContentStartIndexInModifiedFile; // Use TypeScript to pull out line/char from the original code at the position + any previous offset | ||
var position = span.start + fileContentStartIndexInModifiedFile; // Use TypeScript to pull out line/char from the original code at the position + any previous offset | ||
var burnerSourceFile = ts.createSourceFile('_.ts', code, ts.ScriptTarget.ES2015); | ||
var burnerSourceFile = ts.createSourceFile("_.ts", code, ts.ScriptTarget.ES2015); | ||
var _ts$getLineAndCharact = ts.getLineAndCharacterOfPosition(burnerSourceFile, position), | ||
line = _ts$getLineAndCharact.line, | ||
character = _ts$getLineAndCharact.character; | ||
var _ts$getLineAndCharact = ts.getLineAndCharacterOfPosition(burnerSourceFile, position), | ||
line = _ts$getLineAndCharact.line, | ||
character = _ts$getLineAndCharact.character; | ||
staticQuickInfos.push({ | ||
text: text, | ||
docs: docs, | ||
start: position, | ||
length: span.length, | ||
line: line, | ||
character: character, | ||
targetString: targetString | ||
}); | ||
} | ||
staticQuickInfos.push({ | ||
text: text, | ||
docs: docs, | ||
start: position, | ||
length: span.length, | ||
line: line, | ||
character: character, | ||
targetString: targetString | ||
}); | ||
} | ||
} | ||
} // Offset the queries for this file because they are based on the line for that one | ||
// specific file, and not the global twoslash document. This has to be done here because | ||
// in the above loops, the code for queries/highlights hasn't been stripped yet. | ||
partialQueries.filter(function (q) { | ||
return q.file === file; | ||
}).forEach(function (q) { | ||
var pos = ts.getPositionOfLineAndCharacter(sourceFile, q.line, q.offset) + fileContentStartIndexInModifiedFile; | ||
queries.push({ | ||
docs: q.docs, | ||
kind: "query", | ||
start: pos, | ||
length: q.text.length, | ||
text: q.text, | ||
offset: q.offset, | ||
line: q.line + linesAbove | ||
}); | ||
}); | ||
} | ||
@@ -555,3 +579,3 @@ }); | ||
if (relevantErrors.length) { | ||
if (!handbookOptions.noErrorValidation && relevantErrors.length) { | ||
validateCodeForErrors(relevantErrors, handbookOptions, extension, originalCode); | ||
@@ -577,3 +601,3 @@ } | ||
var fileContentStartIndexInModifiedFile = code.indexOf(codeWhereErrorLives); | ||
var renderedMessage = escapeHtml(ts.flattenDiagnosticMessageText(err.messageText, '\n')); | ||
var renderedMessage = escapeHtml(ts.flattenDiagnosticMessageText(err.messageText, "\n")); | ||
var id = "err-" + err.code + "-" + err.start + "-" + err.length; | ||
@@ -607,3 +631,3 @@ | ||
return o.name; | ||
}).join(', '); | ||
}).join(", "); | ||
throw new Error("Cannot find the file " + handbookOptions.showEmittedFile + " - in " + allFiles); | ||
@@ -613,7 +637,7 @@ } | ||
code = file.text; | ||
extension = file.name.split('.').pop(); // Remove highlights and queries, because it won't work across transpiles, | ||
extension = file.name.split(".").pop(); // Remove highlights and queries, because it won't work across transpiles, | ||
// though I guess source-mapping could handle the transition | ||
highlights = []; | ||
queries = []; | ||
partialQueries = []; | ||
staticQuickInfos = []; | ||
@@ -626,3 +650,3 @@ } | ||
var cutString = '// ---cut---\n'; | ||
var cutString = "// ---cut---\n"; | ||
@@ -632,3 +656,3 @@ if (code.includes(cutString)) { | ||
var cutIndex = code.indexOf(cutString) + cutString.length; | ||
var lineOffset = code.substr(0, cutIndex).split('\n').length - 1; // Kills the code shown | ||
var lineOffset = code.substr(0, cutIndex).split("\n").length - 1; // Kills the code shown | ||
@@ -660,6 +684,6 @@ code = code.split(cutString).pop(); // For any type of metadata shipped, it will need to be shifted to | ||
queries.forEach(function (q) { | ||
return q.start -= cutIndex; | ||
return q.line -= lineOffset; | ||
}); | ||
queries = queries.filter(function (q) { | ||
return q.start > -1; | ||
return q.line > -1; | ||
}); | ||
@@ -666,0 +690,0 @@ } |
{ | ||
"name": "@typescript/twoslash", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "author": "TypeScript team", |
101
README.md
@@ -106,4 +106,8 @@ # TypeScript TwoSlash | ||
showEmittedFile: string | ||
/** Whether to disable the pre-cache of LSP calls for interesting identifiers */ | ||
noStaticSemanticInfo: false | ||
/** Whether to disable the pre-cache of LSP calls for interesting identifiers, defaults to false */ | ||
noStaticSemanticInfo: boolean | ||
/** Declare that the TypeScript program should edit the fsMap which is passed in, this is only useful for tool-makers, defaults to false */ | ||
emit: boolean | ||
/** Declare that you don't need to validate that errors have corresponding annotations, defaults to false */ | ||
noErrorValidation: boolean | ||
} | ||
@@ -219,6 +223,6 @@ ``` | ||
function createLabel<T extends number | string>(idOrName: T): NameOrId<T> { | ||
throw 'unimplemented' | ||
throw "unimplemented" | ||
} | ||
let a = createLabel('typescript') | ||
let a = createLabel("typescript") | ||
// ^? | ||
@@ -229,3 +233,3 @@ | ||
let c = createLabel(Math.random() ? 'hello' : 42) | ||
let c = createLabel(Math.random() ? "hello" : 42) | ||
// ^? | ||
@@ -238,10 +242,10 @@ ``` | ||
> function createLabel<T extends number | string>(idOrName: T): NameOrId<T> { | ||
> throw 'unimplemented' | ||
> throw "unimplemented" | ||
> } | ||
> | ||
> let a = createLabel('typescript') | ||
> let a = createLabel("typescript") | ||
> | ||
> let b = createLabel(2.8) | ||
> | ||
> let c = createLabel(Math.random() ? 'hello' : 42) | ||
> let c = createLabel(Math.random() ? "hello" : 42) | ||
> ``` | ||
@@ -256,3 +260,31 @@ | ||
> "highlights": [], | ||
> "queries": [], | ||
> "queries": [ | ||
> { | ||
> "docs": "", | ||
> "kind": "query", | ||
> "start": 354, | ||
> "length": 16, | ||
> "text": "let a: NameLabel", | ||
> "offset": 4, | ||
> "line": 4 | ||
> }, | ||
> { | ||
> "docs": "", | ||
> "kind": "query", | ||
> "start": 390, | ||
> "length": 14, | ||
> "text": "let b: IdLabel", | ||
> "offset": 4, | ||
> "line": 6 | ||
> }, | ||
> { | ||
> "docs": "", | ||
> "kind": "query", | ||
> "start": 417, | ||
> "length": 26, | ||
> "text": "let c: IdLabel | NameLabel", | ||
> "offset": 4, | ||
> "line": 8 | ||
> } | ||
> ], | ||
> "staticQuickInfos": "[ 14 items ]", | ||
@@ -311,3 +343,3 @@ > "errors": [], | ||
greet('Maddison', new Date()) | ||
greet("Maddison", new Date()) | ||
// ^^^^^^^^^^ | ||
@@ -323,3 +355,3 @@ ``` | ||
> | ||
> greet('Maddison', new Date()) | ||
> greet("Maddison", new Date()) | ||
> ``` | ||
@@ -353,6 +385,6 @@ | ||
// @filename: file-with-export.ts | ||
export const helloWorld = 'Example string' | ||
export const helloWorld = "Example string" | ||
// @filename: index.ts | ||
import { helloWorld } from './file-with-export' | ||
import { helloWorld } from "./file-with-export" | ||
console.log(helloWorld) | ||
@@ -365,6 +397,6 @@ ``` | ||
> // @filename: file-with-export.ts | ||
> export const helloWorld = 'Example string' | ||
> export const helloWorld = "Example string" | ||
> | ||
> // @filename: index.ts | ||
> import { helloWorld } from './file-with-export' | ||
> import { helloWorld } from "./file-with-export" | ||
> console.log(helloWorld) | ||
@@ -390,3 +422,3 @@ > ``` | ||
```ts | ||
let foo = 'hello there!' | ||
let foo = "hello there!" | ||
// ^? | ||
@@ -398,3 +430,3 @@ ``` | ||
> ```ts | ||
> let foo = 'hello there!' | ||
> let foo = "hello there!" | ||
> ``` | ||
@@ -411,10 +443,9 @@ | ||
> { | ||
> "docs": "", | ||
> "kind": "query", | ||
> "start": 4, | ||
> "length": 15, | ||
> "text": "let foo: string", | ||
> "offset": 4, | ||
> "position": 4, | ||
> "text": "let foo: string", | ||
> "docs": "", | ||
> "line": 1, | ||
> "start": 3, | ||
> "length": 4 | ||
> "line": 0 | ||
> } | ||
@@ -449,3 +480,3 @@ > ], | ||
> function (o, n) { | ||
> var m = typeof Symbol === 'function' && o[Symbol.iterator] | ||
> var m = typeof Symbol === "function" && o[Symbol.iterator] | ||
> if (!m) return o | ||
@@ -462,3 +493,3 @@ > var i = m.call(o), | ||
> try { | ||
> if (r && !r.done && (m = i['return'])) m.call(i) | ||
> if (r && !r.done && (m = i["return"])) m.call(i) | ||
> } finally { | ||
@@ -506,2 +537,3 @@ > if (e) throw e.error | ||
* @param extension For example: "ts", "tsx", "typescript", "javascript" or "js". | ||
* @param defaultOptions Allows setting any of the handbook options from outside the function, useful if you don't want LSP identifiers | ||
* @param tsModule An optional copy of the TypeScript import, if missing it will be require'd. | ||
@@ -515,2 +547,3 @@ * @param lzstringModule An optional copy of the lz-string import, if missing it will be require'd. | ||
extension: string, | ||
defaultOptions?: Partial<ExampleOptions>, | ||
tsModule?: TS, | ||
@@ -532,3 +565,3 @@ lzstringModule?: LZ, | ||
highlights: { | ||
kind: 'highlight' | ||
kind: "highlight" | ||
position: number | ||
@@ -558,11 +591,15 @@ length: number | ||
queries: { | ||
kind: 'query' | ||
/** The index of the text in the file */ | ||
start: number | ||
/** how long the identifier */ | ||
length: number | ||
kind: "query" | ||
/** What line is the highlighted identifier on? */ | ||
line: number | ||
/** At what index in the line does the caret represent */ | ||
offset: number | ||
// TODO: Add these so we can present something | ||
/** The text of the token which is highlighted */ | ||
text: string | ||
/** Any attached JSDocs */ | ||
docs: string | undefined | ||
/** The token start which the query indicates */ | ||
start: number | ||
/** The length of the token */ | ||
length: number | ||
}[] | ||
@@ -569,0 +606,0 @@ /** Diagnostic error messages which came up when creating the program */ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
203870
18
1289
621