Merge branch 'master' of https://github.com/microsoft/TypeScript
This commit is contained in:
commit
4685646281
|
@ -2,6 +2,8 @@
|
|||
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
const ambientModuleSymbolRegex = /^".+"$/;
|
||||
|
||||
let nextSymbolId = 1;
|
||||
let nextNodeId = 1;
|
||||
let nextMergeId = 1;
|
||||
|
@ -100,6 +102,7 @@ namespace ts {
|
|||
getAliasedSymbol: resolveAlias,
|
||||
getEmitResolver,
|
||||
getExportsOfModule: getExportsOfModuleAsArray,
|
||||
getAmbientModules,
|
||||
|
||||
getJsxElementAttributesType,
|
||||
getJsxIntrinsicTagNames,
|
||||
|
@ -20195,5 +20198,15 @@ namespace ts {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function getAmbientModules(): Symbol[] {
|
||||
const result: Symbol[] = [];
|
||||
for (const sym in globals) {
|
||||
if (ambientModuleSymbolRegex.test(sym)) {
|
||||
result.push(globals[sym]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ namespace ts {
|
|||
|
||||
const emptyArray: any[] = [];
|
||||
|
||||
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean): string {
|
||||
export function findConfigFile(searchPath: string, fileExists: (fileName: string) => boolean, configName = "tsconfig.json"): string {
|
||||
while (true) {
|
||||
const fileName = combinePaths(searchPath, "tsconfig.json");
|
||||
const fileName = combinePaths(searchPath, configName);
|
||||
if (fileExists(fileName)) {
|
||||
return fileName;
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ namespace ts {
|
|||
|
||||
const typeReferenceExtensions = [".d.ts"];
|
||||
|
||||
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost): string[] | undefined {
|
||||
export function getEffectiveTypeRoots(options: CompilerOptions, host: { directoryExists?: (directoryName: string) => boolean, getCurrentDirectory?: () => string }): string[] | undefined {
|
||||
if (options.typeRoots) {
|
||||
return options.typeRoots;
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ namespace ts {
|
|||
* Returns the path to every node_modules/@types directory from some ancestor directory.
|
||||
* Returns undefined if there are none.
|
||||
*/
|
||||
function getDefaultTypeRoots(currentDirectory: string, host: ModuleResolutionHost): string[] | undefined {
|
||||
function getDefaultTypeRoots(currentDirectory: string, host: { directoryExists?: (directoryName: string) => boolean }): string[] | undefined {
|
||||
if (!host.directoryExists) {
|
||||
return [combinePaths(currentDirectory, nodeModulesAtTypes)];
|
||||
// And if it doesn't exist, tough.
|
||||
|
|
|
@ -1965,6 +1965,7 @@ namespace ts {
|
|||
getJsxElementAttributesType(elementNode: JsxOpeningLikeElement): Type;
|
||||
getJsxIntrinsicTagNames(): Symbol[];
|
||||
isOptionalParameter(node: ParameterDeclaration): boolean;
|
||||
getAmbientModules(): Symbol[];
|
||||
|
||||
// Should not be called directly. Should only be accessed through the Program instance.
|
||||
/* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
|
||||
|
|
|
@ -263,22 +263,31 @@ namespace FourSlash {
|
|||
constructor(private basePath: string, private testType: FourSlashTestType, public testData: FourSlashData) {
|
||||
// Create a new Services Adapter
|
||||
this.cancellationToken = new TestCancellationToken();
|
||||
const compilationOptions = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions);
|
||||
if (compilationOptions.typeRoots) {
|
||||
compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => ts.getNormalizedAbsolutePath(p, this.basePath));
|
||||
}
|
||||
let compilationOptions = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions);
|
||||
compilationOptions.skipDefaultLibCheck = true;
|
||||
|
||||
const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions);
|
||||
this.languageServiceAdapterHost = languageServiceAdapter.getHost();
|
||||
this.languageService = languageServiceAdapter.getLanguageService();
|
||||
|
||||
// Initialize the language service with all the scripts
|
||||
let startResolveFileRef: FourSlashFile;
|
||||
|
||||
ts.forEach(testData.files, file => {
|
||||
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
|
||||
this.inputFiles[file.fileName] = file.content;
|
||||
|
||||
if (ts.getBaseFileName(file.fileName).toLowerCase() === "tsconfig.json") {
|
||||
const configJson = ts.parseConfigFileTextToJson(file.fileName, file.content);
|
||||
assert.isTrue(configJson.config !== undefined);
|
||||
|
||||
// Extend our existing compiler options so that we can also support tsconfig only options
|
||||
if (configJson.config.compilerOptions) {
|
||||
const baseDirectory = ts.normalizePath(ts.getDirectoryPath(file.fileName));
|
||||
const tsConfig = ts.convertCompilerOptionsFromJson(configJson.config.compilerOptions, baseDirectory, file.fileName);
|
||||
|
||||
if (!tsConfig.errors || !tsConfig.errors.length) {
|
||||
compilationOptions = ts.extend(compilationOptions, tsConfig.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!startResolveFileRef && file.fileOptions[metadataOptionNames.resolveReference] === "true") {
|
||||
startResolveFileRef = file;
|
||||
}
|
||||
|
@ -288,6 +297,15 @@ namespace FourSlash {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
if (compilationOptions.typeRoots) {
|
||||
compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => ts.getNormalizedAbsolutePath(p, this.basePath));
|
||||
}
|
||||
|
||||
const languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions);
|
||||
this.languageServiceAdapterHost = languageServiceAdapter.getHost();
|
||||
this.languageService = languageServiceAdapter.getLanguageService();
|
||||
|
||||
if (startResolveFileRef) {
|
||||
// Add the entry-point file itself into the languageServiceShimHost
|
||||
this.languageServiceAdapterHost.addScript(startResolveFileRef.fileName, startResolveFileRef.content, /*isRootFile*/ true);
|
||||
|
@ -342,6 +360,7 @@ namespace FourSlash {
|
|||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
PlaceOpenBraceOnNewLineForFunctions: false,
|
||||
|
@ -730,10 +749,10 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string) {
|
||||
public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) {
|
||||
const completions = this.getCompletionListAtCaret();
|
||||
if (completions) {
|
||||
this.assertItemInCompletionList(completions.entries, symbol, text, documentation, kind);
|
||||
this.assertItemInCompletionList(completions.entries, symbol, text, documentation, kind, spanIndex);
|
||||
}
|
||||
else {
|
||||
this.raiseError(`No completions at position '${this.currentCaretPosition}' when looking for '${symbol}'.`);
|
||||
|
@ -749,25 +768,32 @@ namespace FourSlash {
|
|||
* @param expectedText the text associated with the symbol
|
||||
* @param expectedDocumentation the documentation text associated with the symbol
|
||||
* @param expectedKind the kind of symbol (see ScriptElementKind)
|
||||
* @param spanIndex the index of the range that the completion item's replacement text span should match
|
||||
*/
|
||||
public verifyCompletionListDoesNotContain(symbol: string, expectedText?: string, expectedDocumentation?: string, expectedKind?: string) {
|
||||
public verifyCompletionListDoesNotContain(symbol: string, expectedText?: string, expectedDocumentation?: string, expectedKind?: string, spanIndex?: number) {
|
||||
const that = this;
|
||||
let replacementSpan: ts.TextSpan;
|
||||
if (spanIndex !== undefined) {
|
||||
replacementSpan = this.getTextSpanForRangeAtIndex(spanIndex);
|
||||
}
|
||||
|
||||
function filterByTextOrDocumentation(entry: ts.CompletionEntry) {
|
||||
const details = that.getCompletionEntryDetails(entry.name);
|
||||
const documentation = ts.displayPartsToString(details.documentation);
|
||||
const text = ts.displayPartsToString(details.displayParts);
|
||||
if (expectedText && expectedDocumentation) {
|
||||
return (documentation === expectedDocumentation && text === expectedText) ? true : false;
|
||||
|
||||
// If any of the expected values are undefined, assume that users don't
|
||||
// care about them.
|
||||
if (replacementSpan && !TestState.textSpansEqual(replacementSpan, entry.replacementSpan)) {
|
||||
return false;
|
||||
}
|
||||
else if (expectedText && !expectedDocumentation) {
|
||||
return text === expectedText ? true : false;
|
||||
else if (expectedText && text !== expectedText) {
|
||||
return false;
|
||||
}
|
||||
else if (expectedDocumentation && !expectedText) {
|
||||
return documentation === expectedDocumentation ? true : false;
|
||||
else if (expectedDocumentation && documentation !== expectedDocumentation) {
|
||||
return false;
|
||||
}
|
||||
// Because expectedText and expectedDocumentation are undefined, we assume that
|
||||
// users don"t care to compare them so we will treat that entry as if the entry has matching text and documentation
|
||||
// and keep it in the list of filtered entry.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -791,6 +817,10 @@ namespace FourSlash {
|
|||
if (expectedKind) {
|
||||
error += "Expected kind: " + expectedKind + " to equal: " + filterCompletions[0].kind + ".";
|
||||
}
|
||||
if (replacementSpan) {
|
||||
const spanText = filterCompletions[0].replacementSpan ? stringify(filterCompletions[0].replacementSpan) : undefined;
|
||||
error += "Expected replacement span: " + stringify(replacementSpan) + " to equal: " + spanText + ".";
|
||||
}
|
||||
this.raiseError(error);
|
||||
}
|
||||
}
|
||||
|
@ -2188,7 +2218,7 @@ namespace FourSlash {
|
|||
return text.substring(startPos, endPos);
|
||||
}
|
||||
|
||||
private assertItemInCompletionList(items: ts.CompletionEntry[], name: string, text?: string, documentation?: string, kind?: string) {
|
||||
private assertItemInCompletionList(items: ts.CompletionEntry[], name: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
if (item.name === name) {
|
||||
|
@ -2207,6 +2237,11 @@ namespace FourSlash {
|
|||
assert.equal(item.kind, kind, this.assertionMessageAtLastKnownMarker("completion item kind for " + name));
|
||||
}
|
||||
|
||||
if (spanIndex !== undefined) {
|
||||
const span = this.getTextSpanForRangeAtIndex(spanIndex);
|
||||
assert.isTrue(TestState.textSpansEqual(span, item.replacementSpan), this.assertionMessageAtLastKnownMarker(stringify(span) + " does not equal " + stringify(item.replacementSpan) + " replacement span for " + name));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -2263,6 +2298,17 @@ namespace FourSlash {
|
|||
return `line ${(pos.line + 1)}, col ${pos.character}`;
|
||||
}
|
||||
|
||||
private getTextSpanForRangeAtIndex(index: number): ts.TextSpan {
|
||||
const ranges = this.getRanges();
|
||||
if (ranges && ranges.length > index) {
|
||||
const range = ranges[index];
|
||||
return { start: range.start, length: range.end - range.start };
|
||||
}
|
||||
else {
|
||||
this.raiseError("Supplied span index: " + index + " does not exist in range list of size: " + (ranges ? 0 : ranges.length));
|
||||
}
|
||||
}
|
||||
|
||||
public getMarkerByName(markerName: string) {
|
||||
const markerPos = this.testData.markerPositions[markerName];
|
||||
if (markerPos === undefined) {
|
||||
|
@ -2286,6 +2332,10 @@ namespace FourSlash {
|
|||
public resetCancelled(): void {
|
||||
this.cancellationToken.resetCancelled();
|
||||
}
|
||||
|
||||
private static textSpansEqual(a: ts.TextSpan, b: ts.TextSpan) {
|
||||
return a && b && a.start === b.start && a.length === b.length;
|
||||
}
|
||||
}
|
||||
|
||||
export function runFourSlashTest(basePath: string, testType: FourSlashTestType, fileName: string) {
|
||||
|
@ -2294,12 +2344,16 @@ namespace FourSlash {
|
|||
}
|
||||
|
||||
export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): void {
|
||||
// Give file paths an absolute path for the virtual file system
|
||||
const absoluteBasePath = ts.combinePaths(Harness.virtualFileSystemRoot, basePath);
|
||||
const absoluteFileName = ts.combinePaths(Harness.virtualFileSystemRoot, fileName);
|
||||
|
||||
// Parse out the files and their metadata
|
||||
const testData = parseTestData(basePath, content, fileName);
|
||||
const state = new TestState(basePath, testType, testData);
|
||||
const testData = parseTestData(absoluteBasePath, content, absoluteFileName);
|
||||
const state = new TestState(absoluteBasePath, testType, testData);
|
||||
const output = ts.transpileModule(content, { reportDiagnostics: true });
|
||||
if (output.diagnostics.length > 0) {
|
||||
throw new Error(`Syntax error in ${basePath}: ${output.diagnostics[0].messageText}`);
|
||||
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics[0].messageText}`);
|
||||
}
|
||||
runCode(output.outputText, state);
|
||||
}
|
||||
|
@ -2852,12 +2906,12 @@ namespace FourSlashInterface {
|
|||
|
||||
// Verifies the completion list contains the specified symbol. The
|
||||
// completion list is brought up if necessary
|
||||
public completionListContains(symbol: string, text?: string, documentation?: string, kind?: string) {
|
||||
public completionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) {
|
||||
if (this.negative) {
|
||||
this.state.verifyCompletionListDoesNotContain(symbol, text, documentation, kind);
|
||||
this.state.verifyCompletionListDoesNotContain(symbol, text, documentation, kind, spanIndex);
|
||||
}
|
||||
else {
|
||||
this.state.verifyCompletionListContains(symbol, text, documentation, kind);
|
||||
this.state.verifyCompletionListContains(symbol, text, documentation, kind, spanIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -514,6 +514,9 @@ namespace Harness {
|
|||
// harness always uses one kind of new line
|
||||
const harnessNewLine = "\r\n";
|
||||
|
||||
// Root for file paths that are stored in a virtual file system
|
||||
export const virtualFileSystemRoot = "/";
|
||||
|
||||
namespace IOImpl {
|
||||
declare class Enumerator {
|
||||
public atEnd(): boolean;
|
||||
|
|
|
@ -123,7 +123,7 @@ namespace Harness.LanguageService {
|
|||
}
|
||||
|
||||
export class LanguageServiceAdapterHost {
|
||||
protected fileNameToScript = ts.createMap<ScriptInfo>();
|
||||
protected virtualFileSystem: Utils.VirtualFileSystem = new Utils.VirtualFileSystem(virtualFileSystemRoot, /*useCaseSensitiveFilenames*/false);
|
||||
|
||||
constructor(protected cancellationToken = DefaultHostCancellationToken.Instance,
|
||||
protected settings = ts.getDefaultCompilerOptions()) {
|
||||
|
@ -135,22 +135,24 @@ namespace Harness.LanguageService {
|
|||
|
||||
public getFilenames(): string[] {
|
||||
const fileNames: string[] = [];
|
||||
ts.forEachProperty(this.fileNameToScript, (scriptInfo) => {
|
||||
for (const virtualEntry of this.virtualFileSystem.getAllFileEntries()){
|
||||
const scriptInfo = virtualEntry.content;
|
||||
if (scriptInfo.isRootFile) {
|
||||
// only include root files here
|
||||
// usually it means that we won't include lib.d.ts in the list of root files so it won't mess the computation of compilation root dir.
|
||||
fileNames.push(scriptInfo.fileName);
|
||||
}
|
||||
});
|
||||
}
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
public getScriptInfo(fileName: string): ScriptInfo {
|
||||
return this.fileNameToScript[fileName];
|
||||
const fileEntry = this.virtualFileSystem.traversePath(fileName);
|
||||
return fileEntry && fileEntry.isFile() ? (<Utils.VirtualFile>fileEntry).content : undefined;
|
||||
}
|
||||
|
||||
public addScript(fileName: string, content: string, isRootFile: boolean): void {
|
||||
this.fileNameToScript[fileName] = new ScriptInfo(fileName, content, isRootFile);
|
||||
this.virtualFileSystem.addFile(fileName, new ScriptInfo(fileName, content, isRootFile));
|
||||
}
|
||||
|
||||
public editScript(fileName: string, start: number, end: number, newText: string) {
|
||||
|
@ -171,7 +173,7 @@ namespace Harness.LanguageService {
|
|||
* @param col 0 based index
|
||||
*/
|
||||
public positionToLineAndCharacter(fileName: string, position: number): ts.LineAndCharacter {
|
||||
const script: ScriptInfo = this.fileNameToScript[fileName];
|
||||
const script: ScriptInfo = this.getScriptInfo(fileName);
|
||||
assert.isOk(script);
|
||||
|
||||
return ts.computeLineAndCharacterOfPosition(script.getLineMap(), position);
|
||||
|
@ -182,8 +184,14 @@ namespace Harness.LanguageService {
|
|||
class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost {
|
||||
getCompilationSettings() { return this.settings; }
|
||||
getCancellationToken() { return this.cancellationToken; }
|
||||
getDirectories(path: string): string[] { return []; }
|
||||
getCurrentDirectory(): string { return ""; }
|
||||
getDirectories(path: string): string[] {
|
||||
const dir = this.virtualFileSystem.traversePath(path);
|
||||
if (dir && dir.isDirectory()) {
|
||||
return ts.map((<Utils.VirtualDirectory>dir).getDirectories(), (d) => ts.combinePaths(path, d.name));
|
||||
}
|
||||
return [];
|
||||
}
|
||||
getCurrentDirectory(): string { return virtualFileSystemRoot; }
|
||||
getDefaultLibFileName(): string { return Harness.Compiler.defaultLibFileName; }
|
||||
getScriptFileNames(): string[] { return this.getFilenames(); }
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
|
||||
|
@ -196,6 +204,22 @@ namespace Harness.LanguageService {
|
|||
return script ? script.version.toString() : undefined;
|
||||
}
|
||||
|
||||
fileExists(fileName: string): boolean {
|
||||
const script = this.getScriptSnapshot(fileName);
|
||||
return script !== undefined;
|
||||
}
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
|
||||
return ts.matchFiles(path, extensions, exclude, include,
|
||||
/*useCaseSensitiveFileNames*/false,
|
||||
this.getCurrentDirectory(),
|
||||
(p) => this.virtualFileSystem.getAccessibleFileSystemEntries(p));
|
||||
}
|
||||
readFile(path: string, encoding?: string): string {
|
||||
const snapshot = this.getScriptSnapshot(path);
|
||||
return snapshot.getText(0, snapshot.getLength());
|
||||
}
|
||||
|
||||
|
||||
log(s: string): void { }
|
||||
trace(s: string): void { }
|
||||
error(s: string): void { }
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Utils {
|
|||
}
|
||||
|
||||
export class VirtualFile extends VirtualFileSystemEntry {
|
||||
content: string;
|
||||
content?: Harness.LanguageService.ScriptInfo;
|
||||
isFile() { return true; }
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ namespace Utils {
|
|||
}
|
||||
}
|
||||
|
||||
addFile(name: string, content?: string): VirtualFile {
|
||||
addFile(name: string, content?: Harness.LanguageService.ScriptInfo): VirtualFile {
|
||||
const entry = this.getFileSystemEntry(name);
|
||||
if (entry === undefined) {
|
||||
const file = new VirtualFile(this.fileSystem, name);
|
||||
|
@ -111,6 +111,7 @@ namespace Utils {
|
|||
getFileSystemEntries() { return this.root.getFileSystemEntries(); }
|
||||
|
||||
addDirectory(path: string) {
|
||||
path = ts.normalizePath(path);
|
||||
const components = ts.getNormalizedPathComponents(path, this.currentDirectory);
|
||||
let directory: VirtualDirectory = this.root;
|
||||
for (const component of components) {
|
||||
|
@ -123,8 +124,8 @@ namespace Utils {
|
|||
return directory;
|
||||
}
|
||||
|
||||
addFile(path: string, content?: string) {
|
||||
const absolutePath = ts.getNormalizedAbsolutePath(path, this.currentDirectory);
|
||||
addFile(path: string, content?: Harness.LanguageService.ScriptInfo) {
|
||||
const absolutePath = ts.normalizePath(ts.getNormalizedAbsolutePath(path, this.currentDirectory));
|
||||
const fileName = ts.getBaseFileName(path);
|
||||
const directoryPath = ts.getDirectoryPath(absolutePath);
|
||||
const directory = this.addDirectory(directoryPath);
|
||||
|
@ -141,6 +142,7 @@ namespace Utils {
|
|||
}
|
||||
|
||||
traversePath(path: string) {
|
||||
path = ts.normalizePath(path);
|
||||
let directory: VirtualDirectory = this.root;
|
||||
for (const component of ts.getNormalizedPathComponents(path, this.currentDirectory)) {
|
||||
const entry = directory.getFileSystemEntry(component);
|
||||
|
@ -157,6 +159,40 @@ namespace Utils {
|
|||
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the directory at the given path and retrieves a list of file names and a list
|
||||
* of directory names within it. Suitable for use with ts.matchFiles()
|
||||
* @param path The path to the directory to be read
|
||||
*/
|
||||
getAccessibleFileSystemEntries(path: string) {
|
||||
const entry = this.traversePath(path);
|
||||
if (entry && entry.isDirectory()) {
|
||||
const directory = <VirtualDirectory>entry;
|
||||
return {
|
||||
files: ts.map(directory.getFiles(), f => f.name),
|
||||
directories: ts.map(directory.getDirectories(), d => d.name)
|
||||
};
|
||||
}
|
||||
return { files: [], directories: [] };
|
||||
}
|
||||
|
||||
getAllFileEntries() {
|
||||
const fileEntries: VirtualFile[] = [];
|
||||
getFilesRecursive(this.root, fileEntries);
|
||||
return fileEntries;
|
||||
|
||||
function getFilesRecursive(dir: VirtualDirectory, result: VirtualFile[]) {
|
||||
const files = dir.getFiles();
|
||||
const dirs = dir.getDirectories();
|
||||
for (const file of files) {
|
||||
result.push(file);
|
||||
}
|
||||
for (const subDir of dirs) {
|
||||
getFilesRecursive(subDir, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class MockParseConfigHost extends VirtualFileSystem implements ts.ParseConfigHost {
|
||||
|
@ -170,17 +206,5 @@ namespace Utils {
|
|||
readDirectory(path: string, extensions: string[], excludes: string[], includes: string[]) {
|
||||
return ts.matchFiles(path, extensions, excludes, includes, this.useCaseSensitiveFileNames, this.currentDirectory, (path: string) => this.getAccessibleFileSystemEntries(path));
|
||||
}
|
||||
|
||||
getAccessibleFileSystemEntries(path: string) {
|
||||
const entry = this.traversePath(path);
|
||||
if (entry && entry.isDirectory()) {
|
||||
const directory = <VirtualDirectory>entry;
|
||||
return {
|
||||
files: ts.map(directory.getFiles(), f => f.name),
|
||||
directories: ts.map(directory.getDirectories(), d => d.name)
|
||||
};
|
||||
}
|
||||
return { files: [], directories: [] };
|
||||
}
|
||||
}
|
||||
}
|
6
src/lib/es5.d.ts
vendored
6
src/lib/es5.d.ts
vendored
|
@ -1060,6 +1060,12 @@ interface ReadonlyArray<T> {
|
|||
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
map<U>(callbackfn: (value: T, index: number, array: ReadonlyArray<T>) => U, thisArg?: any): U[];
|
||||
/**
|
||||
* Returns the elements of an array that meet the condition specified in a callback function.
|
||||
* @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
filter<S extends T>(callbackfn: (value: T, index: number, array: ReadonlyArray<T>) => value is S, thisArg?: any): S[];
|
||||
/**
|
||||
* Returns the elements of an array that meet the condition specified in a callback function.
|
||||
* @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array.
|
||||
|
|
|
@ -216,7 +216,18 @@ namespace ts.server {
|
|||
return {
|
||||
isMemberCompletion: false,
|
||||
isNewIdentifierLocation: false,
|
||||
entries: response.body
|
||||
entries: response.body.map(entry => {
|
||||
|
||||
if (entry.replacementSpan !== undefined) {
|
||||
const { name, kind, kindModifiers, sortText, replacementSpan} = entry;
|
||||
|
||||
const convertedSpan = createTextSpanFromBounds(this.lineOffsetToPosition(fileName, replacementSpan.start),
|
||||
this.lineOffsetToPosition(fileName, replacementSpan.end));
|
||||
return { name, kind, kindModifiers, sortText, replacementSpan: convertedSpan };
|
||||
}
|
||||
|
||||
return entry as { name: string, kind: string, kindModifiers: string, sortText: string };
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -306,11 +306,6 @@ namespace ts.server {
|
|||
throw new Error("No script with name '" + filename + "'");
|
||||
}
|
||||
|
||||
resolvePath(path: string): string {
|
||||
const result = this.host.resolvePath(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
fileExists(path: string): boolean {
|
||||
const result = this.host.fileExists(path);
|
||||
return result;
|
||||
|
@ -324,6 +319,14 @@ namespace ts.server {
|
|||
return this.host.getDirectories(path);
|
||||
}
|
||||
|
||||
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[] {
|
||||
return this.host.readDirectory(path, extensions, exclude, include);
|
||||
}
|
||||
|
||||
readFile(path: string, encoding?: string): string {
|
||||
return this.host.readFile(path, encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line 1 based index
|
||||
*/
|
||||
|
@ -1591,6 +1594,7 @@ namespace ts.server {
|
|||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
|
||||
InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
|
||||
PlaceOpenBraceOnNewLineForFunctions: false,
|
||||
|
|
5
src/server/protocol.d.ts
vendored
5
src/server/protocol.d.ts
vendored
|
@ -773,6 +773,11 @@ declare namespace ts.server.protocol {
|
|||
* is often the same as the name but may be different in certain circumstances.
|
||||
*/
|
||||
sortText: string;
|
||||
/**
|
||||
* An optional span that indicates the text to be replaced by this completion item. If present,
|
||||
* this span should be used instead of the default one.
|
||||
*/
|
||||
replacementSpan?: TextSpan;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -778,7 +778,17 @@ namespace ts.server {
|
|||
|
||||
return completions.entries.reduce((result: protocol.CompletionEntry[], entry: ts.CompletionEntry) => {
|
||||
if (completions.isMemberCompletion || (entry.name.toLowerCase().indexOf(prefix.toLowerCase()) === 0)) {
|
||||
result.push(entry);
|
||||
const { name, kind, kindModifiers, sortText, replacementSpan } = entry;
|
||||
|
||||
let convertedSpan: protocol.TextSpan = undefined;
|
||||
if (replacementSpan) {
|
||||
convertedSpan = {
|
||||
start: compilerService.host.positionToLineOffset(fileName, replacementSpan.start),
|
||||
end: compilerService.host.positionToLineOffset(fileName, replacementSpan.start + replacementSpan.length)
|
||||
};
|
||||
}
|
||||
|
||||
result.push({ name, kind, kindModifiers, sortText, replacementSpan: convertedSpan });
|
||||
}
|
||||
return result;
|
||||
}, []).sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
|
|
@ -50,6 +50,8 @@ namespace ts.formatting {
|
|||
// Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}.
|
||||
public SpaceAfterOpenBrace: Rule;
|
||||
public SpaceBeforeCloseBrace: Rule;
|
||||
public NoSpaceAfterOpenBrace: Rule;
|
||||
public NoSpaceBeforeCloseBrace: Rule;
|
||||
public NoSpaceBetweenEmptyBraceBrackets: Rule;
|
||||
|
||||
// Insert new line after { and before } in multi-line contexts.
|
||||
|
@ -287,6 +289,8 @@ namespace ts.formatting {
|
|||
// Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}.
|
||||
this.SpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Space));
|
||||
this.SpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Space));
|
||||
this.NoSpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Delete));
|
||||
this.NoSpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Delete));
|
||||
this.NoSpaceBetweenEmptyBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsObjectContext), RuleAction.Delete));
|
||||
|
||||
// Insert new line after { and before } in multi-line contexts.
|
||||
|
@ -414,7 +418,7 @@ namespace ts.formatting {
|
|||
this.SpaceAfterPostdecrementWhenFollowedBySubtract,
|
||||
this.SpaceAfterSubtractWhenFollowedByUnaryMinus, this.SpaceAfterSubtractWhenFollowedByPredecrement,
|
||||
this.NoSpaceAfterCloseBrace,
|
||||
this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NewLineBeforeCloseBraceInBlockContext,
|
||||
this.NewLineBeforeCloseBraceInBlockContext,
|
||||
this.SpaceAfterCloseBrace, this.SpaceBetweenCloseBraceAndElse, this.SpaceBetweenCloseBraceAndWhile, this.NoSpaceBetweenEmptyBraceBrackets,
|
||||
this.NoSpaceBetweenFunctionKeywordAndStar, this.SpaceAfterStarInGeneratorDeclaration,
|
||||
this.SpaceAfterFunctionInFuncDecl, this.NewLineAfterOpenBraceInBlockContext, this.SpaceAfterGetSetInMember,
|
||||
|
|
|
@ -81,6 +81,19 @@ namespace ts.formatting {
|
|||
rules.push(this.globalRules.NoSpaceBetweenBrackets);
|
||||
}
|
||||
|
||||
// The default value of InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces is true
|
||||
// so if the option is undefined, we should treat it as true as well
|
||||
if (options.InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces !== false) {
|
||||
rules.push(this.globalRules.SpaceAfterOpenBrace);
|
||||
rules.push(this.globalRules.SpaceBeforeCloseBrace);
|
||||
rules.push(this.globalRules.NoSpaceBetweenEmptyBraceBrackets);
|
||||
}
|
||||
else {
|
||||
rules.push(this.globalRules.NoSpaceAfterOpenBrace);
|
||||
rules.push(this.globalRules.NoSpaceBeforeCloseBrace);
|
||||
rules.push(this.globalRules.NoSpaceBetweenEmptyBraceBrackets);
|
||||
}
|
||||
|
||||
if (options.InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces) {
|
||||
rules.push(this.globalRules.SpaceAfterTemplateHeadAndMiddle);
|
||||
rules.push(this.globalRules.SpaceBeforeTemplateMiddleAndTail);
|
||||
|
|
|
@ -1049,6 +1049,11 @@ namespace ts {
|
|||
owners: string[];
|
||||
}
|
||||
|
||||
interface VisibleModuleInfo {
|
||||
moduleName: string;
|
||||
moduleDir: string;
|
||||
}
|
||||
|
||||
export interface DisplayPartsSymbolWriter extends SymbolWriter {
|
||||
displayParts(): SymbolDisplayPart[];
|
||||
}
|
||||
|
@ -1245,7 +1250,15 @@ namespace ts {
|
|||
sourceMapText?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a triple slash reference directive with an incomplete string literal for its path. Used
|
||||
* to determine if the caret is currently within the string literal and capture the literal fragment
|
||||
* for completions.
|
||||
* For example, this matches /// <reference path="fragment
|
||||
*/
|
||||
const tripleSlashDirectiveFragmentRegex = /^(\/\/\/\s*<reference\s+(path|types)\s*=\s*(?:'|"))([^\3]*)$/;
|
||||
|
||||
const nodeModulesDependencyKeys = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
||||
|
||||
let commandLineOptionsStringToEnum: CommandLineOptionOfCustomType[];
|
||||
|
||||
|
@ -2097,13 +2110,17 @@ namespace ts {
|
|||
|
||||
function isNameOfExternalModuleImportOrDeclaration(node: Node): boolean {
|
||||
if (node.kind === SyntaxKind.StringLiteral) {
|
||||
return isNameOfModuleDeclaration(node) ||
|
||||
(isExternalModuleImportEqualsDeclaration(node.parent.parent) && getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node);
|
||||
return isNameOfModuleDeclaration(node) || isExpressionOfExternalModuleImportEqualsDeclaration(node);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function isExpressionOfExternalModuleImportEqualsDeclaration(node: Node) {
|
||||
return isExternalModuleImportEqualsDeclaration(node.parent.parent) &&
|
||||
getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node;
|
||||
}
|
||||
|
||||
/** Returns true if the position is within a comment */
|
||||
function isInsideComment(sourceFile: SourceFile, token: Node, position: number): boolean {
|
||||
// The position has to be: 1. in the leading trivia (before token.getStart()), and 2. within a comment
|
||||
|
@ -3436,6 +3453,10 @@ namespace ts {
|
|||
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
|
||||
if (isInReferenceComment(sourceFile, position)) {
|
||||
return getTripleSlashReferenceCompletion(sourceFile, position);
|
||||
}
|
||||
|
||||
if (isInString(sourceFile, position)) {
|
||||
return getStringLiteralCompletionEntries(sourceFile, position);
|
||||
}
|
||||
|
@ -3605,6 +3626,13 @@ namespace ts {
|
|||
// a['/*completion position*/']
|
||||
return getStringLiteralCompletionEntriesFromElementAccess(node.parent);
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ImportDeclaration || isExpressionOfExternalModuleImportEqualsDeclaration(node) || isRequireCall(node.parent, false)) {
|
||||
// Get all known external module names or complete a path to a module
|
||||
// i.e. import * as ns from "/*completion position*/";
|
||||
// import x = require("/*completion position*/");
|
||||
// var y = require("/*completion position*/");
|
||||
return getStringLiteralCompletionEntriesFromModuleNames(<StringLiteral>node);
|
||||
}
|
||||
else {
|
||||
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
|
||||
if (argumentInfo) {
|
||||
|
@ -3697,6 +3725,446 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntriesFromModuleNames(node: StringLiteral): CompletionInfo {
|
||||
const literalValue = normalizeSlashes(node.text);
|
||||
|
||||
const scriptPath = node.getSourceFile().path;
|
||||
const scriptDirectory = getDirectoryPath(scriptPath);
|
||||
|
||||
const span = getDirectoryFragmentTextSpan((<StringLiteral>node).text, node.getStart() + 1);
|
||||
let entries: CompletionEntry[];
|
||||
if (isPathRelativeToScript(literalValue) || isRootedDiskPath(literalValue)) {
|
||||
const compilerOptions = program.getCompilerOptions();
|
||||
if (compilerOptions.rootDirs) {
|
||||
entries = getCompletionEntriesForDirectoryFragmentWithRootDirs(
|
||||
compilerOptions.rootDirs, literalValue, scriptDirectory, getSupportedExtensions(program.getCompilerOptions()), /*includeExtensions*/false, span, scriptPath);
|
||||
}
|
||||
else {
|
||||
entries = getCompletionEntriesForDirectoryFragment(
|
||||
literalValue, scriptDirectory, getSupportedExtensions(program.getCompilerOptions()), /*includeExtensions*/false, span, scriptPath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Check for node modules
|
||||
entries = getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, span);
|
||||
}
|
||||
return {
|
||||
isMemberCompletion: false,
|
||||
isNewIdentifierLocation: true,
|
||||
entries
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a script path and returns paths for all potential folders that could be merged with its
|
||||
* containing folder via the "rootDirs" compiler option
|
||||
*/
|
||||
function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, scriptPath: string, ignoreCase: boolean): string[] {
|
||||
// Make all paths absolute/normalized if they are not already
|
||||
rootDirs = map(rootDirs, rootDirectory => normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory)));
|
||||
|
||||
// Determine the path to the directory containing the script relative to the root directory it is contained within
|
||||
let relativeDirectory: string;
|
||||
for (const rootDirectory of rootDirs) {
|
||||
if (containsPath(rootDirectory, scriptPath, basePath, ignoreCase)) {
|
||||
relativeDirectory = scriptPath.substr(rootDirectory.length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now find a path for each potential directory that is to be merged with the one containing the script
|
||||
return deduplicate(map(rootDirs, rootDirectory => combinePaths(rootDirectory, relativeDirectory)));
|
||||
}
|
||||
|
||||
function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptPath: string, extensions: string[], includeExtensions: boolean, span: TextSpan, exclude?: string): CompletionEntry[] {
|
||||
const basePath = program.getCompilerOptions().project || host.getCurrentDirectory();
|
||||
const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
|
||||
const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptPath, ignoreCase);
|
||||
|
||||
const result: CompletionEntry[] = [];
|
||||
|
||||
for (const baseDirectory of baseDirectories) {
|
||||
getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensions, includeExtensions, span, exclude, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getCompletionEntriesForDirectoryFragment(fragment: string, scriptPath: string, extensions: string[], includeExtensions: boolean, span: TextSpan, exclude?: string, result: CompletionEntry[] = []): CompletionEntry[] {
|
||||
fragment = getDirectoryPath(fragment);
|
||||
if (!fragment) {
|
||||
fragment = "./";
|
||||
}
|
||||
else {
|
||||
fragment = ensureTrailingDirectorySeparator(fragment);
|
||||
}
|
||||
|
||||
const absolutePath = normalizeAndPreserveTrailingSlash(isRootedDiskPath(fragment) ? fragment : combinePaths(scriptPath, fragment));
|
||||
const baseDirectory = getDirectoryPath(absolutePath);
|
||||
const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
|
||||
|
||||
if (directoryProbablyExists(baseDirectory, host)) {
|
||||
if (host.readDirectory) {
|
||||
// Enumerate the available files if possible
|
||||
const files = host.readDirectory(baseDirectory, extensions, /*exclude*/undefined, /*include*/["./*"]);
|
||||
const foundFiles = createMap<boolean>();
|
||||
for (let filePath of files) {
|
||||
filePath = normalizePath(filePath);
|
||||
if (exclude && comparePaths(filePath, exclude, scriptPath, ignoreCase) === Comparison.EqualTo) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const foundFileName = includeExtensions ? getBaseFileName(filePath) : removeFileExtension(getBaseFileName(filePath));
|
||||
|
||||
if (!foundFiles[foundFileName]) {
|
||||
foundFiles[foundFileName] = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const foundFile in foundFiles) {
|
||||
result.push(createCompletionEntryForModule(foundFile, ScriptElementKind.scriptElement, span));
|
||||
}
|
||||
}
|
||||
|
||||
// If possible, get folder completion as well
|
||||
if (host.getDirectories) {
|
||||
const directories = host.getDirectories(baseDirectory);
|
||||
for (const directory of directories) {
|
||||
const directoryName = getBaseFileName(normalizePath(directory));
|
||||
|
||||
result.push(createCompletionEntryForModule(directoryName, ScriptElementKind.directory, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all of the declared modules and those in node modules. Possible sources of modules:
|
||||
* Modules that are found by the type checker
|
||||
* Modules found relative to "baseUrl" compliler options (including patterns from "paths" compiler option)
|
||||
* Modules from node_modules (i.e. those listed in package.json)
|
||||
* This includes all files that are found in node_modules/moduleName/ with acceptable file extensions
|
||||
*/
|
||||
function getCompletionEntriesForNonRelativeModules(fragment: string, scriptPath: string, span: TextSpan): CompletionEntry[] {
|
||||
const options = program.getCompilerOptions();
|
||||
const { baseUrl, paths } = options;
|
||||
|
||||
let result: CompletionEntry[];
|
||||
|
||||
if (baseUrl) {
|
||||
const fileExtensions = getSupportedExtensions(options);
|
||||
const projectDir = options.project || host.getCurrentDirectory();
|
||||
const absolute = isRootedDiskPath(baseUrl) ? baseUrl : combinePaths(projectDir, baseUrl);
|
||||
result = getCompletionEntriesForDirectoryFragment(fragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/false, span);
|
||||
|
||||
if (paths) {
|
||||
for (const path in paths) {
|
||||
if (paths.hasOwnProperty(path)) {
|
||||
if (path === "*") {
|
||||
if (paths[path]) {
|
||||
for (const pattern of paths[path]) {
|
||||
for (const match of getModulesForPathsPattern(fragment, baseUrl, pattern, fileExtensions)) {
|
||||
result.push(createCompletionEntryForModule(match, ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (startsWith(path, fragment)) {
|
||||
const entry = paths[path] && paths[path].length === 1 && paths[path][0];
|
||||
if (entry) {
|
||||
result.push(createCompletionEntryForModule(path, ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = [];
|
||||
}
|
||||
|
||||
getCompletionEntriesFromTypings(host, options, scriptPath, span, result);
|
||||
|
||||
for (const moduleName of enumeratePotentialNonRelativeModules(fragment, scriptPath, options)) {
|
||||
result.push(createCompletionEntryForModule(moduleName, ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: string[]): string[] {
|
||||
if (host.readDirectory) {
|
||||
const parsed = hasZeroOrOneAsteriskCharacter(pattern) ? tryParsePattern(pattern) : undefined;
|
||||
if (parsed) {
|
||||
// The prefix has two effective parts: the directory path and the base component after the filepath that is not a
|
||||
// full directory component. For example: directory/path/of/prefix/base*
|
||||
const normalizedPrefix = normalizeAndPreserveTrailingSlash(parsed.prefix);
|
||||
const normalizedPrefixDirectory = getDirectoryPath(normalizedPrefix);
|
||||
const normalizedPrefixBase = getBaseFileName(normalizedPrefix);
|
||||
|
||||
const fragmentHasPath = fragment.indexOf(directorySeparator) !== -1;
|
||||
|
||||
// Try and expand the prefix to include any path from the fragment so that we can limit the readDirectory call
|
||||
const expandedPrefixDirectory = fragmentHasPath ? combinePaths(normalizedPrefixDirectory, normalizedPrefixBase + getDirectoryPath(fragment)) : normalizedPrefixDirectory;
|
||||
|
||||
const normalizedSuffix = normalizePath(parsed.suffix);
|
||||
const baseDirectory = combinePaths(baseUrl, expandedPrefixDirectory);
|
||||
const completePrefix = fragmentHasPath ? baseDirectory : ensureTrailingDirectorySeparator(baseDirectory) + normalizedPrefixBase;
|
||||
|
||||
// If we have a suffix, then we need to read the directory all the way down. We could create a glob
|
||||
// that encodes the suffix, but we would have to escape the character "?" which readDirectory
|
||||
// doesn't support. For now, this is safer but slower
|
||||
const includeGlob = normalizedSuffix ? "**/*" : "./*";
|
||||
|
||||
const matches = host.readDirectory(baseDirectory, fileExtensions, undefined, [includeGlob]);
|
||||
const result: string[] = [];
|
||||
|
||||
// Trim away prefix and suffix
|
||||
for (const match of matches) {
|
||||
const normalizedMatch = normalizePath(match);
|
||||
if (!endsWith(normalizedMatch, normalizedSuffix) || !startsWith(normalizedMatch, completePrefix)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const start = completePrefix.length;
|
||||
const length = normalizedMatch.length - start - normalizedSuffix.length;
|
||||
|
||||
result.push(removeFileExtension(normalizedMatch.substr(start, length)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function enumeratePotentialNonRelativeModules(fragment: string, scriptPath: string, options: CompilerOptions): string[] {
|
||||
// Check If this is a nested module
|
||||
const isNestedModule = fragment.indexOf(directorySeparator) !== -1;
|
||||
const moduleNameFragment = isNestedModule ? fragment.substr(0, fragment.lastIndexOf(directorySeparator)) : undefined;
|
||||
|
||||
// Get modules that the type checker picked up
|
||||
const ambientModules = map(program.getTypeChecker().getAmbientModules(), sym => stripQuotes(sym.name));
|
||||
let nonRelativeModules = filter(ambientModules, moduleName => startsWith(moduleName, fragment));
|
||||
|
||||
// Nested modules of the form "module-name/sub" need to be adjusted to only return the string
|
||||
// after the last '/' that appears in the fragment because that's where the replacement span
|
||||
// starts
|
||||
if (isNestedModule) {
|
||||
const moduleNameWithSeperator = ensureTrailingDirectorySeparator(moduleNameFragment);
|
||||
nonRelativeModules = map(nonRelativeModules, moduleName => {
|
||||
if (startsWith(fragment, moduleNameWithSeperator)) {
|
||||
return moduleName.substr(moduleNameWithSeperator.length);
|
||||
}
|
||||
return moduleName;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (!options.moduleResolution || options.moduleResolution === ModuleResolutionKind.NodeJs) {
|
||||
for (const visibleModule of enumerateNodeModulesVisibleToScript(host, scriptPath)) {
|
||||
if (!isNestedModule) {
|
||||
nonRelativeModules.push(visibleModule.moduleName);
|
||||
}
|
||||
else if (host.readDirectory && startsWith(visibleModule.moduleName, moduleNameFragment)) {
|
||||
const nestedFiles = host.readDirectory(visibleModule.moduleDir, supportedTypeScriptExtensions, /*exclude*/undefined, /*include*/["./*"]);
|
||||
|
||||
for (let f of nestedFiles) {
|
||||
f = normalizePath(f);
|
||||
const nestedModule = removeFileExtension(getBaseFileName(f));
|
||||
nonRelativeModules.push(nestedModule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deduplicate(nonRelativeModules);
|
||||
}
|
||||
|
||||
function getTripleSlashReferenceCompletion(sourceFile: SourceFile, position: number): CompletionInfo {
|
||||
const token = getTokenAtPosition(sourceFile, position);
|
||||
if (!token) {
|
||||
return undefined;
|
||||
}
|
||||
const commentRanges: CommentRange[] = getLeadingCommentRanges(sourceFile.text, token.pos);
|
||||
|
||||
if (!commentRanges || !commentRanges.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const range = forEach(commentRanges, commentRange => position >= commentRange.pos && position <= commentRange.end && commentRange);
|
||||
|
||||
if (!range) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const text = sourceFile.text.substr(range.pos, position - range.pos);
|
||||
|
||||
const match = tripleSlashDirectiveFragmentRegex.exec(text);
|
||||
if (match) {
|
||||
const prefix = match[1];
|
||||
const kind = match[2];
|
||||
const toComplete = match[3];
|
||||
|
||||
const scriptPath = getDirectoryPath(sourceFile.path);
|
||||
let entries: CompletionEntry[];
|
||||
if (kind === "path") {
|
||||
// Give completions for a relative path
|
||||
const span: TextSpan = getDirectoryFragmentTextSpan(toComplete, range.pos + prefix.length);
|
||||
entries = getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getSupportedExtensions(program.getCompilerOptions()), /*includeExtensions*/true, span, sourceFile.path);
|
||||
}
|
||||
else {
|
||||
// Give completions based on the typings available
|
||||
const span: TextSpan = { start: range.pos + prefix.length, length: match[0].length - prefix.length };
|
||||
entries = getCompletionEntriesFromTypings(host, program.getCompilerOptions(), scriptPath, span);
|
||||
}
|
||||
|
||||
return {
|
||||
isMemberCompletion: false,
|
||||
isNewIdentifierLocation: true,
|
||||
entries
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getCompletionEntriesFromTypings(host: LanguageServiceHost, options: CompilerOptions, scriptPath: string, span: TextSpan, result: CompletionEntry[] = []): CompletionEntry[] {
|
||||
// Check for typings specified in compiler options
|
||||
if (options.types) {
|
||||
for (const moduleName of options.types) {
|
||||
result.push(createCompletionEntryForModule(moduleName, ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
}
|
||||
else if (host.getDirectories) {
|
||||
const typeRoots = getEffectiveTypeRoots(options, host);
|
||||
for (const root of typeRoots) {
|
||||
getCompletionEntriesFromDirectories(host, options, root, span, result);
|
||||
}
|
||||
}
|
||||
|
||||
if (host.getDirectories) {
|
||||
// Also get all @types typings installed in visible node_modules directories
|
||||
for (const package of findPackageJsons(scriptPath)) {
|
||||
const typesDir = combinePaths(getDirectoryPath(package), "node_modules/@types");
|
||||
getCompletionEntriesFromDirectories(host, options, typesDir, span, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getCompletionEntriesFromDirectories(host: LanguageServiceHost, options: CompilerOptions, directory: string, span: TextSpan, result: CompletionEntry[]) {
|
||||
if (host.getDirectories && directoryProbablyExists(directory, host)) {
|
||||
for (let typeDirectory of host.getDirectories(directory)) {
|
||||
typeDirectory = normalizePath(typeDirectory);
|
||||
result.push(createCompletionEntryForModule(getBaseFileName(typeDirectory), ScriptElementKind.externalModuleName, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findPackageJsons(currentDir: string): string[] {
|
||||
const paths: string[] = [];
|
||||
let currentConfigPath: string;
|
||||
while (true) {
|
||||
currentConfigPath = findConfigFile(currentDir, (f) => host.fileExists(f), "package.json");
|
||||
if (currentConfigPath) {
|
||||
paths.push(currentConfigPath);
|
||||
|
||||
currentDir = getDirectoryPath(currentConfigPath);
|
||||
const parent = getDirectoryPath(currentDir);
|
||||
if (currentDir === parent) {
|
||||
break;
|
||||
}
|
||||
currentDir = parent;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
|
||||
function enumerateNodeModulesVisibleToScript(host: LanguageServiceHost, scriptPath: string) {
|
||||
const result: VisibleModuleInfo[] = [];
|
||||
|
||||
if (host.readFile && host.fileExists) {
|
||||
for (const packageJson of findPackageJsons(scriptPath)) {
|
||||
const package = tryReadingPackageJson(packageJson);
|
||||
if (!package) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nodeModulesDir = combinePaths(getDirectoryPath(packageJson), "node_modules");
|
||||
const foundModuleNames: string[] = [];
|
||||
|
||||
// Provide completions for all non @types dependencies
|
||||
for (const key of nodeModulesDependencyKeys) {
|
||||
addPotentialPackageNames(package[key], foundModuleNames);
|
||||
}
|
||||
|
||||
for (const moduleName of foundModuleNames) {
|
||||
const moduleDir = combinePaths(nodeModulesDir, moduleName);
|
||||
result.push({
|
||||
moduleName,
|
||||
moduleDir
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
function tryReadingPackageJson(filePath: string) {
|
||||
try {
|
||||
const fileText = host.readFile(filePath);
|
||||
return JSON.parse(fileText);
|
||||
}
|
||||
catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function addPotentialPackageNames(dependencies: any, result: string[]) {
|
||||
if (dependencies) {
|
||||
for (const dep in dependencies) {
|
||||
if (dependencies.hasOwnProperty(dep) && !startsWith(dep, "@types/")) {
|
||||
result.push(dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createCompletionEntryForModule(name: string, kind: string, replacementSpan: TextSpan): CompletionEntry {
|
||||
return { name, kind, kindModifiers: ScriptElementKindModifier.none, sortText: name, replacementSpan };
|
||||
}
|
||||
|
||||
// Replace everything after the last directory seperator that appears
|
||||
function getDirectoryFragmentTextSpan(text: string, textStart: number): TextSpan {
|
||||
const index = text.lastIndexOf(directorySeparator);
|
||||
const offset = index !== -1 ? index + 1 : 0;
|
||||
return { start: textStart + offset, length: text.length - offset };
|
||||
}
|
||||
|
||||
// Returns true if the path is explicitly relative to the script (i.e. relative to . or ..)
|
||||
function isPathRelativeToScript(path: string) {
|
||||
if (path && path.length >= 2 && path.charCodeAt(0) === CharacterCodes.dot) {
|
||||
const slashIndex = path.length >= 3 && path.charCodeAt(1) === CharacterCodes.dot ? 2 : 1;
|
||||
const slashCharCode = path.charCodeAt(slashIndex);
|
||||
return slashCharCode === CharacterCodes.slash || slashCharCode === CharacterCodes.backslash;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function normalizeAndPreserveTrailingSlash(path: string) {
|
||||
return hasTrailingDirectorySeparator(path) ? ensureTrailingDirectorySeparator(normalizePath(path)) : normalizePath(path);
|
||||
}
|
||||
}
|
||||
|
||||
function getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails {
|
||||
|
@ -5627,7 +6095,6 @@ namespace ts {
|
|||
symbolToIndex: number[]): void {
|
||||
|
||||
const sourceFile = container.getSourceFile();
|
||||
const tripleSlashDirectivePrefixRegex = /^\/\/\/\s*</;
|
||||
|
||||
const start = findInComments ? container.getFullStart() : container.getStart();
|
||||
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, start, container.getEnd());
|
||||
|
@ -5792,15 +6259,6 @@ namespace ts {
|
|||
|
||||
return result[index];
|
||||
}
|
||||
|
||||
function isInNonReferenceComment(sourceFile: SourceFile, position: number): boolean {
|
||||
return isInCommentHelper(sourceFile, position, isNonReferenceComment);
|
||||
|
||||
function isNonReferenceComment(c: CommentRange): boolean {
|
||||
const commentText = sourceFile.text.substring(c.pos, c.end);
|
||||
return !tripleSlashDirectivePrefixRegex.test(commentText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getReferencesForSuperKeyword(superKeyword: Node): ReferencedSymbol[] {
|
||||
|
|
|
@ -67,6 +67,10 @@ namespace ts {
|
|||
getProjectVersion?(): string;
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
|
||||
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
|
||||
readFile(path: string, encoding?: string): string;
|
||||
fileExists(path: string): boolean;
|
||||
|
||||
getModuleResolutionsForFile?(fileName: string): string;
|
||||
getTypeReferenceDirectiveResolutionsForFile?(fileName: string): string;
|
||||
directoryExists(directoryName: string): boolean;
|
||||
|
@ -421,6 +425,28 @@ namespace ts {
|
|||
public getDefaultLibFileName(options: CompilerOptions): string {
|
||||
return this.shimHost.getDefaultLibFileName(JSON.stringify(options));
|
||||
}
|
||||
|
||||
public readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[], depth?: number): string[] {
|
||||
const pattern = getFileMatcherPatterns(path, extensions, exclude, include,
|
||||
this.shimHost.useCaseSensitiveFileNames(), this.shimHost.getCurrentDirectory());
|
||||
return JSON.parse(this.shimHost.readDirectory(
|
||||
path,
|
||||
JSON.stringify(extensions),
|
||||
JSON.stringify(pattern.basePaths),
|
||||
pattern.excludePattern,
|
||||
pattern.includeFilePattern,
|
||||
pattern.includeDirectoryPattern,
|
||||
depth
|
||||
));
|
||||
}
|
||||
|
||||
public readFile(path: string, encoding?: string): string {
|
||||
return this.shimHost.readFile(path, encoding);
|
||||
}
|
||||
|
||||
public fileExists(path: string): boolean {
|
||||
return this.shimHost.fileExists(path);
|
||||
}
|
||||
}
|
||||
|
||||
/** A cancellation that throttles calls to the host */
|
||||
|
|
|
@ -140,6 +140,14 @@ namespace ts {
|
|||
error?(s: string): void;
|
||||
useCaseSensitiveFileNames?(): boolean;
|
||||
|
||||
/*
|
||||
* LS host can optionally implement these methods to support completions for module specifiers.
|
||||
* Without these methods, only completions for ambient modules will be provided.
|
||||
*/
|
||||
readDirectory?(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
|
||||
readFile?(path: string, encoding?: string): string;
|
||||
fileExists?(path: string): boolean;
|
||||
|
||||
/*
|
||||
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
|
||||
* if implementation is omitted then language service will use built-in module resolution logic and get answers to
|
||||
|
@ -148,6 +156,11 @@ namespace ts {
|
|||
resolveModuleNames?(moduleNames: string[], containingFile: string): ResolvedModule[];
|
||||
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
|
||||
directoryExists?(directoryName: string): boolean;
|
||||
|
||||
/*
|
||||
* getDirectories is also required for full import and type reference completions. Without it defined, certain
|
||||
* completions will not be provided
|
||||
*/
|
||||
getDirectories?(directoryName: string): string[];
|
||||
}
|
||||
|
||||
|
@ -336,6 +349,7 @@ namespace ts {
|
|||
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean;
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean;
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean;
|
||||
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean;
|
||||
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean;
|
||||
InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean;
|
||||
PlaceOpenBraceOnNewLineForFunctions: boolean;
|
||||
|
@ -454,6 +468,12 @@ namespace ts {
|
|||
kind: string; // see ScriptElementKind
|
||||
kindModifiers: string; // see ScriptElementKindModifier, comma separated
|
||||
sortText: string;
|
||||
/**
|
||||
* An optional span that indicates the text to be replaced by this completion item. It will be
|
||||
* set if the required span differs from the one generated by the default replacement behavior and should
|
||||
* be used in that case
|
||||
*/
|
||||
replacementSpan?: TextSpan;
|
||||
}
|
||||
|
||||
export interface CompletionEntryDetails {
|
||||
|
@ -736,6 +756,10 @@ namespace ts {
|
|||
export const constElement = "const";
|
||||
|
||||
export const letElement = "let";
|
||||
|
||||
export const directory = "directory";
|
||||
|
||||
export const externalModuleName = "external module name";
|
||||
}
|
||||
|
||||
export namespace ScriptElementKindModifier {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// These utilities are common to multiple language service features.
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
// Matches the beginning of a triple slash directive
|
||||
const tripleSlashDirectivePrefixRegex = /^\/\/\/\s*</;
|
||||
|
||||
export interface ListItemInfo {
|
||||
listItemIndex: number;
|
||||
list: Node;
|
||||
|
@ -704,6 +707,29 @@ namespace ts {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasTrailingDirectorySeparator(path: string) {
|
||||
const lastCharacter = path.charAt(path.length - 1);
|
||||
return lastCharacter === "/" || lastCharacter === "\\";
|
||||
}
|
||||
|
||||
export function isInReferenceComment(sourceFile: SourceFile, position: number): boolean {
|
||||
return isInCommentHelper(sourceFile, position, isReferenceComment);
|
||||
|
||||
function isReferenceComment(c: CommentRange): boolean {
|
||||
const commentText = sourceFile.text.substring(c.pos, c.end);
|
||||
return tripleSlashDirectivePrefixRegex.test(commentText);
|
||||
}
|
||||
}
|
||||
|
||||
export function isInNonReferenceComment(sourceFile: SourceFile, position: number): boolean {
|
||||
return isInCommentHelper(sourceFile, position, isNonReferenceComment);
|
||||
|
||||
function isNonReferenceComment(c: CommentRange): boolean {
|
||||
const commentText = sourceFile.text.substring(c.pos, c.end);
|
||||
return !tripleSlashDirectivePrefixRegex.test(commentText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display-part writer helpers
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
EmitSkipped: true
|
||||
Diagnostics:
|
||||
Cannot write file 'tests/cases/fourslash/b.js' because it would overwrite input file.
|
||||
Cannot write file '/tests/cases/fourslash/b.js' because it would overwrite input file.
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/a.js
|
||||
FileName : /tests/cases/fourslash/a.js
|
||||
function foo2() { return 30; } // no error - should emit a.js
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/shims-pp/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/shims-pp/inputFile1.js
|
||||
var x = 5;
|
||||
var Bar = (function () {
|
||||
function Bar() {
|
||||
}
|
||||
return Bar;
|
||||
}());
|
||||
FileName : tests/cases/fourslash/shims-pp/inputFile1.d.ts
|
||||
FileName : /tests/cases/fourslash/shims-pp/inputFile1.d.ts
|
||||
declare var x: number;
|
||||
declare class Bar {
|
||||
x: string;
|
||||
|
@ -14,14 +14,14 @@ declare class Bar {
|
|||
}
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/shims-pp/inputFile2.js
|
||||
FileName : /tests/cases/fourslash/shims-pp/inputFile2.js
|
||||
var x1 = "hello world";
|
||||
var Foo = (function () {
|
||||
function Foo() {
|
||||
}
|
||||
return Foo;
|
||||
}());
|
||||
FileName : tests/cases/fourslash/shims-pp/inputFile2.d.ts
|
||||
FileName : /tests/cases/fourslash/shims-pp/inputFile2.d.ts
|
||||
declare var x1: string;
|
||||
declare class Foo {
|
||||
x: string;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/shims/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/shims/inputFile1.js
|
||||
var x = 5;
|
||||
var Bar = (function () {
|
||||
function Bar() {
|
||||
}
|
||||
return Bar;
|
||||
}());
|
||||
FileName : tests/cases/fourslash/shims/inputFile1.d.ts
|
||||
FileName : /tests/cases/fourslash/shims/inputFile1.d.ts
|
||||
declare var x: number;
|
||||
declare class Bar {
|
||||
x: string;
|
||||
|
@ -14,14 +14,14 @@ declare class Bar {
|
|||
}
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/shims/inputFile2.js
|
||||
FileName : /tests/cases/fourslash/shims/inputFile2.js
|
||||
var x1 = "hello world";
|
||||
var Foo = (function () {
|
||||
function Foo() {
|
||||
}
|
||||
return Foo;
|
||||
}());
|
||||
FileName : tests/cases/fourslash/shims/inputFile2.d.ts
|
||||
FileName : /tests/cases/fourslash/shims/inputFile2.d.ts
|
||||
declare var x1: string;
|
||||
declare class Foo {
|
||||
x: string;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/inputFile1.js
|
||||
var x = 5;
|
||||
var Bar = (function () {
|
||||
function Bar() {
|
||||
}
|
||||
return Bar;
|
||||
}());
|
||||
FileName : tests/cases/fourslash/inputFile1.d.ts
|
||||
FileName : /tests/cases/fourslash/inputFile1.d.ts
|
||||
declare var x: number;
|
||||
declare class Bar {
|
||||
x: string;
|
||||
|
@ -14,14 +14,14 @@ declare class Bar {
|
|||
}
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile2.js
|
||||
FileName : /tests/cases/fourslash/inputFile2.js
|
||||
var x1 = "hello world";
|
||||
var Foo = (function () {
|
||||
function Foo() {
|
||||
}
|
||||
return Foo;
|
||||
}());
|
||||
FileName : tests/cases/fourslash/inputFile2.d.ts
|
||||
FileName : /tests/cases/fourslash/inputFile2.d.ts
|
||||
declare var x1: string;
|
||||
declare class Foo {
|
||||
x: string;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile.js
|
||||
FileName : /tests/cases/fourslash/inputFile.js
|
||||
var x;
|
||||
var M = (function () {
|
||||
function M() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile2.js
|
||||
FileName : /tests/cases/fourslash/inputFile2.js
|
||||
var x;
|
||||
var Foo = (function () {
|
||||
function Foo() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile.js.map
|
||||
{"version":3,"file":"inputFile.js","sourceRoot":"","sources":["inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : tests/cases/fourslash/inputFile.js
|
||||
FileName : /tests/cases/fourslash/inputFile.js.map
|
||||
{"version":3,"file":"inputFile.js","sourceRoot":"","sources":["inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile.js
|
||||
var x = 109;
|
||||
var foo = "hello world";
|
||||
var M = (function () {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile.js.map
|
||||
{"version":3,"file":"inputFile.js","sourceRoot":"sourceRootDir/","sources":["inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : tests/cases/fourslash/inputFile.js
|
||||
FileName : /tests/cases/fourslash/inputFile.js.map
|
||||
{"version":3,"file":"inputFile.js","sourceRoot":"sourceRootDir/","sources":["inputFile.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile.js
|
||||
var x = 109;
|
||||
var foo = "hello world";
|
||||
var M = (function () {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile1.js.map
|
||||
{"version":3,"file":"inputFile1.js","sourceRoot":"sourceRootDir/","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : tests/cases/fourslash/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/inputFile1.js.map
|
||||
{"version":3,"file":"inputFile1.js","sourceRoot":"sourceRootDir/","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile1.js
|
||||
var x = 109;
|
||||
var foo = "hello world";
|
||||
var M = (function () {
|
||||
|
@ -10,8 +10,8 @@ var M = (function () {
|
|||
}());
|
||||
//# sourceMappingURL=inputFile1.js.map
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile2.js.map
|
||||
{"version":3,"file":"inputFile2.js","sourceRoot":"sourceRootDir/","sources":["inputFile2.ts"],"names":[],"mappings":"AAAA,IAAI,GAAG,GAAG,wBAAwB,CAAC;AACnC;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : tests/cases/fourslash/inputFile2.js
|
||||
FileName : /tests/cases/fourslash/inputFile2.js.map
|
||||
{"version":3,"file":"inputFile2.js","sourceRoot":"sourceRootDir/","sources":["inputFile2.ts"],"names":[],"mappings":"AAAA,IAAI,GAAG,GAAG,wBAAwB,CAAC;AACnC;IAAA;IAGA,CAAC;IAAD,QAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile2.js
|
||||
var bar = "hello world Typescript";
|
||||
var C = (function () {
|
||||
function C() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile1.js.map
|
||||
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}FileName : tests/cases/fourslash/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/inputFile1.js.map
|
||||
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile1.js
|
||||
// regular ts file
|
||||
var t = 5;
|
||||
var Bar = (function () {
|
||||
|
@ -8,7 +8,7 @@ var Bar = (function () {
|
|||
}
|
||||
return Bar;
|
||||
}());
|
||||
//# sourceMappingURL=inputFile1.js.mapFileName : tests/cases/fourslash/inputFile1.d.ts
|
||||
//# sourceMappingURL=inputFile1.js.mapFileName : /tests/cases/fourslash/inputFile1.d.ts
|
||||
declare var t: number;
|
||||
declare class Bar {
|
||||
x: string;
|
||||
|
@ -16,11 +16,11 @@ declare class Bar {
|
|||
}
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile2.jsx.map
|
||||
{"version":3,"file":"inputFile2.jsx","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,EAAG,CAAA"}FileName : tests/cases/fourslash/inputFile2.jsx
|
||||
FileName : /tests/cases/fourslash/inputFile2.jsx.map
|
||||
{"version":3,"file":"inputFile2.jsx","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AAAA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,EAAG,CAAA"}FileName : /tests/cases/fourslash/inputFile2.jsx
|
||||
var y = "my div";
|
||||
var x = <div name={y}/>;
|
||||
//# sourceMappingURL=inputFile2.jsx.mapFileName : tests/cases/fourslash/inputFile2.d.ts
|
||||
//# sourceMappingURL=inputFile2.jsx.mapFileName : /tests/cases/fourslash/inputFile2.d.ts
|
||||
declare var y: string;
|
||||
declare var x: any;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile1.js.map
|
||||
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}FileName : tests/cases/fourslash/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/inputFile1.js.map
|
||||
{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["inputFile1.ts"],"names":[],"mappings":"AAAA,kBAAkB;AACjB,IAAI,CAAC,GAAW,CAAC,CAAC;AAClB;IAAA;IAGA,CAAC;IAAD,UAAC;AAAD,CAAC,AAHD,IAGC"}FileName : /tests/cases/fourslash/inputFile1.js
|
||||
// regular ts file
|
||||
var t = 5;
|
||||
var Bar = (function () {
|
||||
|
@ -8,7 +8,7 @@ var Bar = (function () {
|
|||
}
|
||||
return Bar;
|
||||
}());
|
||||
//# sourceMappingURL=inputFile1.js.mapFileName : tests/cases/fourslash/inputFile1.d.ts
|
||||
//# sourceMappingURL=inputFile1.js.mapFileName : /tests/cases/fourslash/inputFile1.d.ts
|
||||
declare var t: number;
|
||||
declare class Bar {
|
||||
x: string;
|
||||
|
@ -16,11 +16,11 @@ declare class Bar {
|
|||
}
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile2.js.map
|
||||
{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AACA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,6BAAK,IAAI,EAAG,CAAC,GAAI,CAAA"}FileName : tests/cases/fourslash/inputFile2.js
|
||||
FileName : /tests/cases/fourslash/inputFile2.js.map
|
||||
{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["inputFile2.tsx"],"names":[],"mappings":"AACA,IAAI,CAAC,GAAG,QAAQ,CAAC;AACjB,IAAI,CAAC,GAAG,6BAAK,IAAI,EAAG,CAAC,GAAI,CAAA"}FileName : /tests/cases/fourslash/inputFile2.js
|
||||
var y = "my div";
|
||||
var x = React.createElement("div", { name: y });
|
||||
//# sourceMappingURL=inputFile2.js.mapFileName : tests/cases/fourslash/inputFile2.d.ts
|
||||
//# sourceMappingURL=inputFile2.js.mapFileName : /tests/cases/fourslash/inputFile2.d.ts
|
||||
declare var React: any;
|
||||
declare var y: string;
|
||||
declare var x: any;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
EmitSkipped: false
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile2.js
|
||||
FileName : /tests/cases/fourslash/inputFile2.js
|
||||
var x1 = "hello world";
|
||||
var Foo = (function () {
|
||||
function Foo() {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
EmitSkipped: false
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile2.js
|
||||
FileName : /tests/cases/fourslash/inputFile2.js
|
||||
"use strict";
|
||||
var Foo = (function () {
|
||||
function Foo() {
|
||||
|
@ -11,6 +11,6 @@ var Foo = (function () {
|
|||
exports.Foo = Foo;
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile3.js
|
||||
FileName : /tests/cases/fourslash/inputFile3.js
|
||||
var x = "hello";
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/inputFile1.js
|
||||
// File contains early errors. All outputs should be skipped.
|
||||
var uninitialized_const_error;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
EmitSkipped: true
|
||||
Diagnostics:
|
||||
Exported variable 'foo' has or is using private name 'C'.
|
||||
FileName : tests/cases/fourslash/inputFile.js
|
||||
FileName : /tests/cases/fourslash/inputFile.js
|
||||
var M;
|
||||
(function (M) {
|
||||
var C = (function () {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
EmitSkipped: true
|
||||
Diagnostics:
|
||||
Exported variable 'foo' has or is using private name 'C'.
|
||||
FileName : tests/cases/fourslash/inputFile.js
|
||||
FileName : /tests/cases/fourslash/inputFile.js
|
||||
define(["require", "exports"], function (require, exports) {
|
||||
"use strict";
|
||||
var C = (function () {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile.js
|
||||
FileName : /tests/cases/fourslash/inputFile.js
|
||||
var x = "hello world";
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile.js
|
||||
FileName : /tests/cases/fourslash/inputFile.js
|
||||
var x = "hello world";
|
||||
FileName : tests/cases/fourslash/inputFile.d.ts
|
||||
FileName : /tests/cases/fourslash/inputFile.d.ts
|
||||
declare var x: number;
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/inputFile1.js
|
||||
// File to emit, does not contain semantic errors
|
||||
// expected to be emitted correctelly regardless of the semantic errors in the other file
|
||||
var noErrors = true;
|
||||
FileName : tests/cases/fourslash/inputFile1.d.ts
|
||||
FileName : /tests/cases/fourslash/inputFile1.d.ts
|
||||
declare var noErrors: boolean;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile1.js
|
||||
FileName : /tests/cases/fourslash/inputFile1.js
|
||||
// File to emit, does not contain syntactic errors
|
||||
// expected to be emitted correctelly regardless of the syntactic errors in the other file
|
||||
var noErrors = true;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/inputFile.js
|
||||
FileName : /tests/cases/fourslash/inputFile.js
|
||||
var x;
|
||||
|
||||
|
|
33
tests/cases/fourslash/completionForStringLiteralImport1.ts
Normal file
33
tests/cases/fourslash/completionForStringLiteralImport1.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should define spans for replacement that appear after the last directory seperator in import statements
|
||||
|
||||
// @typeRoots: my_typings
|
||||
|
||||
// @Filename: test.ts
|
||||
//// import * as foo0 from "./[|some|]/*0*/
|
||||
//// import * as foo1 from "./sub/[|some|]/*1*/
|
||||
//// import * as foo2 from "[|some-|]/*2*/"
|
||||
//// import * as foo3 from "../[||]/*3*/";
|
||||
|
||||
|
||||
// @Filename: someFile1.ts
|
||||
//// /*someFile1*/
|
||||
|
||||
// @Filename: sub/someFile2.ts
|
||||
//// /*someFile2*/
|
||||
|
||||
// @Filename: my_typings/some-module/index.d.ts
|
||||
//// export var x = 9;
|
||||
|
||||
goTo.marker("0");
|
||||
verify.completionListContains("someFile1", undefined, undefined, undefined, 0);
|
||||
|
||||
goTo.marker("1");
|
||||
verify.completionListContains("someFile2", undefined, undefined, undefined, 1);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.completionListContains("some-module", undefined, undefined, undefined, 2);
|
||||
|
||||
goTo.marker("3");
|
||||
verify.completionListContains("fourslash", undefined, undefined, undefined, 3);
|
33
tests/cases/fourslash/completionForStringLiteralImport2.ts
Normal file
33
tests/cases/fourslash/completionForStringLiteralImport2.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should define spans for replacement that appear after the last directory seperator in triple slash references
|
||||
|
||||
// @typeRoots: my_typings
|
||||
|
||||
// @Filename: test.ts
|
||||
//// /// <reference path="./[|some|]/*0*/
|
||||
//// /// <reference types="[|some|]/*1*/
|
||||
|
||||
//// /// <reference path="./sub/[|some|]/*2*/" />
|
||||
//// /// <reference types="[|some|]/*3*/" />
|
||||
|
||||
// @Filename: someFile.ts
|
||||
//// /*someFile*/
|
||||
|
||||
// @Filename: sub/someOtherFile.ts
|
||||
//// /*someOtherFile*/
|
||||
|
||||
// @Filename: my_typings/some-module/index.d.ts
|
||||
//// export var x = 9;
|
||||
|
||||
goTo.marker("0");
|
||||
verify.completionListContains("someFile.ts", undefined, undefined, undefined, 0);
|
||||
|
||||
goTo.marker("1");
|
||||
verify.completionListContains("some-module", undefined, undefined, undefined, 1);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.completionListContains("someOtherFile.ts", undefined, undefined, undefined, 2);
|
||||
|
||||
goTo.marker("3");
|
||||
verify.completionListContains("some-module", undefined, undefined, undefined, 3);
|
|
@ -0,0 +1,63 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for node modules and files within those modules with ts file extensions
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "f/*import_as0*/
|
||||
//// import * as foo2 from "fake-module//*import_as1*/
|
||||
//// import * as foo3 from "fake-module/*import_as2*/
|
||||
|
||||
//// import foo4 = require("f/*import_equals0*/
|
||||
//// import foo5 = require("fake-module//*import_equals1*/
|
||||
//// import foo6 = require("fake-module/*import_equals2*/
|
||||
|
||||
//// var foo7 = require("f/*require0*/
|
||||
//// var foo8 = require("fake-module//*require1*/
|
||||
//// var foo9 = require("fake-module/*require2*/
|
||||
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "fake-module": "latest" }, "devDependencies": { "fake-module-dev": "latest" } }
|
||||
|
||||
// @Filename: node_modules/fake-module/index.js
|
||||
//// /*fake-module*/
|
||||
// @Filename: node_modules/fake-module/index.d.ts
|
||||
//// /*fakemodule-d-ts*/
|
||||
// @Filename: node_modules/fake-module/ts.ts
|
||||
//// /*ts*/
|
||||
// @Filename: node_modules/fake-module/dts.d.ts
|
||||
//// /*dts*/
|
||||
// @Filename: node_modules/fake-module/tsx.tsx
|
||||
//// /*tsx*/
|
||||
// @Filename: node_modules/fake-module/js.js
|
||||
//// /*js*/
|
||||
// @Filename: node_modules/fake-module/jsx.jsx
|
||||
//// /*jsx*/
|
||||
|
||||
// @Filename: node_modules/fake-module-dev/index.js
|
||||
//// /*fakemodule-dev*/
|
||||
// @Filename: node_modules/fake-module-dev/index.d.ts
|
||||
//// /*fakemodule-dev-d-ts*/
|
||||
|
||||
// @Filename: node_modules/unlisted-module/index.ts
|
||||
//// /*unlisted-module*/
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("fake-module");
|
||||
verify.completionListContains("fake-module-dev");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
|
||||
goTo.marker(kind + "1");
|
||||
verify.completionListContains("index");
|
||||
verify.completionListContains("ts");
|
||||
verify.completionListContains("dts");
|
||||
verify.completionListContains("tsx");
|
||||
verify.not.completionListItemsCountIsGreaterThan(4);
|
||||
|
||||
goTo.marker(kind + "2");
|
||||
verify.completionListContains("fake-module");
|
||||
verify.completionListContains("fake-module-dev");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should not give node module completions if classic module resolution is enabled
|
||||
|
||||
// @moduleResolution: classic
|
||||
|
||||
// @Filename: dir1/dir2/dir3/dir4/test0.ts
|
||||
//// import * as foo1 from "f/*import_as0*/
|
||||
//// import * as foo3 from "fake-module/*import_as1*/
|
||||
|
||||
//// import foo4 = require("f/*import_equals0*/
|
||||
//// import foo6 = require("fake-module/*import_equals1*/
|
||||
|
||||
//// var foo7 = require("f/*require0*/
|
||||
//// var foo9 = require("fake-module/*require1*/
|
||||
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "fake-module": "latest" } }
|
||||
// @Filename: node_modules/fake-module/ts.ts
|
||||
//// /*module1*/
|
||||
|
||||
// @Filename: dir1/dir2/dir3/package.json
|
||||
//// { "dependencies": { "fake-module3": "latest" } }
|
||||
// @Filename: dir1/dir2/dir3/node_modules/fake-module3/ts.ts
|
||||
//// /*module3*/
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListIsEmpty();
|
||||
|
||||
goTo.marker(kind + "1");
|
||||
verify.completionListIsEmpty();
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should handle nested files in folders discovered via the baseUrl compiler option
|
||||
|
||||
// @baseUrl: tests/cases/fourslash/modules
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "subfolder//*import_as0*/
|
||||
//// import foo2 = require("subfolder//*import_equals0*/
|
||||
//// var foo3 = require("subfolder//*require0*/
|
||||
|
||||
//// import * as foo1 from "module-from-node//*import_as1*/
|
||||
//// import foo2 = require("module-from-node//*import_equals1*/
|
||||
//// var foo3 = require("module-from-node//*require1*/
|
||||
|
||||
// @Filename: modules/subfolder/module.ts
|
||||
//// export var x = 5;
|
||||
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "module-from-node": "latest" } }
|
||||
// @Filename: node_modules/module-from-node/index.ts
|
||||
//// /*module1*/
|
||||
|
||||
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
|
||||
verify.completionListContains("module");
|
||||
verify.not.completionListItemsCountIsGreaterThan(1);
|
||||
|
||||
goTo.marker(kind + "1");
|
||||
|
||||
verify.completionListContains("index");
|
||||
verify.not.completionListItemsCountIsGreaterThan(1);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for all dependencies in package.json
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "m/*import_as0*/
|
||||
//// import foo2 = require("m/*import_equals0*/
|
||||
//// var foo3 = require("m/*require0*/
|
||||
|
||||
// @Filename: package.json
|
||||
//// {
|
||||
//// "dependencies": { "module": "latest" },
|
||||
//// "devDependencies": { "dev-module": "latest" },
|
||||
//// "optionalDependencies": { "optional-module": "latest" },
|
||||
//// "peerDependencies": { "peer-module": "latest" }
|
||||
//// }
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
|
||||
verify.completionListContains("module");
|
||||
verify.completionListContains("dev-module");
|
||||
verify.completionListContains("optional-module");
|
||||
verify.completionListContains("peer-module");
|
||||
verify.not.completionListItemsCountIsGreaterThan(4);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should not give duplicate entries for similarly named files with different extensions
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "fake-module//*import_as0*/
|
||||
//// import foo2 = require("fake-module//*import_equals0*/
|
||||
//// var foo3 = require("fake-module//*require0*/
|
||||
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "fake-module": "latest" }, "devDependencies": { "fake-module-dev": "latest" } }
|
||||
|
||||
// @Filename: node_modules/fake-module/repeated.ts
|
||||
//// /*repeatedts*/
|
||||
// @Filename: node_modules/fake-module/repeated.tsx
|
||||
//// /*repeatedtsx*/
|
||||
// @Filename: node_modules/fake-module/repeated.d.ts
|
||||
//// /*repeateddts*/
|
||||
// @Filename: node_modules/fake-module/other.js
|
||||
//// /*other*/
|
||||
// @Filename: node_modules/fake-module/other2.js
|
||||
//// /*other2*/
|
||||
|
||||
// @Filename: node_modules/unlisted-module/index.js
|
||||
//// /*unlisted-module*/
|
||||
|
||||
// @Filename: ambient.ts
|
||||
//// declare module "fake-module/other"
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("repeated");
|
||||
verify.completionListContains("other");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for js files in node modules when allowJs is set to true
|
||||
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "fake-module//*import_as0*/
|
||||
//// import foo2 = require("fake-module//*import_equals0*/
|
||||
//// var foo3 = require("fake-module//*require0*/
|
||||
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "fake-module": "latest" } }
|
||||
|
||||
// @Filename: node_modules/fake-module/ts.ts
|
||||
//// /*ts*/
|
||||
// @Filename: node_modules/fake-module/tsx.tsx
|
||||
//// /*tsx*/
|
||||
// @Filename: node_modules/fake-module/dts.d.ts
|
||||
//// /*dts*/
|
||||
// @Filename: node_modules/fake-module/js.js
|
||||
//// /*js*/
|
||||
// @Filename: node_modules/fake-module/jsx.jsx
|
||||
//// /*jsx*/
|
||||
// @Filename: node_modules/fake-module/repeated.js
|
||||
//// /*repeatedjs*/
|
||||
// @Filename: node_modules/fake-module/repeated.jsx
|
||||
//// /*repeatedjsx*/
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("ts");
|
||||
verify.completionListContains("tsx");
|
||||
verify.completionListContains("dts");
|
||||
verify.not.completionListItemsCountIsGreaterThan(3);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for all node modules visible to the script
|
||||
|
||||
// @Filename: dir1/dir2/dir3/dir4/test0.ts
|
||||
//// import * as foo1 from "f/*import_as0*/
|
||||
//// import foo4 = require("f/*import_equals0*/
|
||||
//// var foo7 = require("f/*require0*/
|
||||
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "fake-module": "latest" } }
|
||||
// @Filename: node_modules/fake-module/ts.ts
|
||||
//// /*module1*/
|
||||
|
||||
// @Filename: dir1/package.json
|
||||
//// { "dependencies": { "fake-module2": "latest" } }
|
||||
// @Filename: dir1/node_modules/fake-module2/index.ts
|
||||
//// /*module2*/
|
||||
|
||||
// @Filename: dir1/dir2/dir3/package.json
|
||||
//// { "dependencies": { "fake-module3": "latest" } }
|
||||
// @Filename: dir1/dir2/dir3/node_modules/fake-module3/ts.ts
|
||||
//// /*module3*/
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
|
||||
verify.completionListContains("fake-module");
|
||||
verify.completionListContains("fake-module2");
|
||||
verify.completionListContains("fake-module3");
|
||||
verify.not.completionListItemsCountIsGreaterThan(3);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for ambiently declared modules
|
||||
|
||||
// @Filename: test0.ts
|
||||
//// /// <reference path="./ambientModules.d.ts" />
|
||||
//// /// <reference path="./ambientModules2.d.ts" />
|
||||
//// import * as foo1 from "/*import_as0*/
|
||||
//// import * as foo2 from "a/*import_as1*/
|
||||
|
||||
//// import foo3 = require("/*import_equals0*/
|
||||
//// import foo4 = require("a/*import_equals1*/
|
||||
|
||||
//// var foo5 = require("/*require0*/
|
||||
//// var foo6 = require("a/*require1*/
|
||||
|
||||
// @Filename: ambientModules.d.ts
|
||||
//// declare module "ambientModule" {}
|
||||
//// declare module "otherAmbientModule" {} /*dummy0*/
|
||||
|
||||
// @Filename: ambientModules2.d.ts
|
||||
//// declare module "otherOtherAmbientModule" {} /*dummy1*/
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
|
||||
verify.completionListContains("ambientModule");
|
||||
verify.completionListContains("otherAmbientModule");
|
||||
verify.completionListContains("otherOtherAmbientModule");
|
||||
verify.not.completionListItemsCountIsGreaterThan(3);
|
||||
|
||||
goTo.marker(kind + "1");
|
||||
|
||||
verify.completionListContains("ambientModule");
|
||||
verify.not.completionListItemsCountIsGreaterThan(1);
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for files that are discovered via the baseUrl compiler option
|
||||
|
||||
// @baseUrl: tests/cases/fourslash/modules
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "mod/*import_as0*/
|
||||
//// import foo2 = require("mod/*import_equals0*/
|
||||
//// var foo3 = require("mod/*require0*/
|
||||
|
||||
// @Filename: modules/module.ts
|
||||
//// export var x = 5;
|
||||
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "module-from-node": "latest" } }
|
||||
// @Filename: node_modules/module-from-node/index.ts
|
||||
//// /*module1*/
|
||||
|
||||
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
|
||||
verify.completionListContains("module");
|
||||
verify.completionListContains("module-from-node");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for modules referenced via baseUrl and paths compiler options with wildcards
|
||||
|
||||
// @Filename: tsconfig.json
|
||||
//// {
|
||||
//// "compilerOptions": {
|
||||
//// "baseUrl": "./modules",
|
||||
//// "paths": {
|
||||
//// "*": [
|
||||
//// "prefix/0*/suffix.ts",
|
||||
//// "prefix-only/*",
|
||||
//// "*/suffix-only.ts"
|
||||
//// ]
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "0/*import_as0*/
|
||||
//// import foo2 = require("0/*import_equals0*/
|
||||
//// var foo3 = require("0/*require0*/
|
||||
|
||||
//// import * as foo1 from "1/*import_as1*/
|
||||
//// import foo2 = require("1/*import_equals1*/
|
||||
//// var foo3 = require("1/*require1*/
|
||||
|
||||
//// import * as foo1 from "2/*import_as2*/
|
||||
//// import foo2 = require("2/*import_equals2*/
|
||||
//// var foo3 = require("2/*require2*/
|
||||
|
||||
|
||||
// @Filename: modules/prefix/00test/suffix.ts
|
||||
//// export var x = 5;
|
||||
|
||||
// @Filename: modules/prefix-only/1test.ts
|
||||
//// export var y = 5;
|
||||
|
||||
// @Filename: modules/2test/suffix-only.ts
|
||||
//// export var z = 5;
|
||||
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("0test");
|
||||
|
||||
goTo.marker(kind + "1");
|
||||
verify.completionListContains("1test");
|
||||
|
||||
goTo.marker(kind + "2");
|
||||
verify.completionListContains("2test");
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for modules referenced via baseUrl and paths compiler options with explicit name mappings
|
||||
|
||||
// @Filename: tsconfig.json
|
||||
//// {
|
||||
//// "compilerOptions": {
|
||||
//// "baseUrl": "./modules",
|
||||
//// "paths": {
|
||||
//// "module1": ["some/path/whatever.ts"],
|
||||
//// "module2": ["some/other/path.ts"]
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "m/*import_as0*/
|
||||
//// import foo2 = require("m/*import_equals0*/
|
||||
//// var foo3 = require("m/*require0*/
|
||||
|
||||
// @Filename: some/path/whatever.ts
|
||||
//// export var x = 9;
|
||||
|
||||
// @Filename: some/other/path.ts
|
||||
//// export var y = 10;
|
||||
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("module1");
|
||||
verify.completionListContains("module2");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for typings discovered via the typeRoots compiler option
|
||||
|
||||
// @typeRoots: my_typings,my_other_typings
|
||||
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// /// <reference types="m/*types_ref0*/" />
|
||||
//// import * as foo1 from "m/*import_as0*/
|
||||
//// import foo2 = require("m/*import_equals0*/
|
||||
//// var foo3 = require("m/*require0*/
|
||||
|
||||
// @Filename: my_typings/module-x/index.d.ts
|
||||
//// export var x = 9;
|
||||
|
||||
// @Filename: my_typings/module-x/whatever.d.ts
|
||||
//// export var w = 9;
|
||||
|
||||
// @Filename: my_typings/module-y/index.d.ts
|
||||
//// export var y = 9;
|
||||
|
||||
// @Filename: my_other_typings/module-z/index.d.ts
|
||||
//// export var z = 9;
|
||||
|
||||
|
||||
const kinds = ["types_ref", "import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("module-x");
|
||||
verify.completionListContains("module-y");
|
||||
verify.completionListContains("module-z");
|
||||
verify.not.completionListItemsCountIsGreaterThan(3);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should respect the types compiler option when giving completions
|
||||
|
||||
// @typeRoots: my_typings,my_other_typings
|
||||
// @types: module-x,module-z
|
||||
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// /// <reference types="m/*types_ref0*/" />
|
||||
//// import * as foo1 from "m/*import_as0*/
|
||||
//// import foo2 = require("m/*import_equals0*/
|
||||
//// var foo3 = require("m/*require0*/
|
||||
|
||||
// @Filename: my_typings/module-x/index.d.ts
|
||||
//// export var x = 9;
|
||||
|
||||
// @Filename: my_typings/module-y/index.d.ts
|
||||
//// export var y = 9;
|
||||
|
||||
// @Filename: my_other_typings/module-z/index.d.ts
|
||||
//// export var z = 9;
|
||||
|
||||
|
||||
const kinds = ["types_ref", "import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("module-x");
|
||||
verify.completionListContains("module-z");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for typings discovered in all visible @types directories
|
||||
|
||||
// @Filename: subdirectory/test0.ts
|
||||
//// /// <reference types="m/*types_ref0*/" />
|
||||
//// import * as foo1 from "m/*import_as0*/
|
||||
//// import foo2 = require("m/*import_equals0*/
|
||||
//// var foo3 = require("m/*require0*/
|
||||
|
||||
// @Filename: subdirectory/node_modules/@types/module-x/index.d.ts
|
||||
//// export var x = 9;
|
||||
// @Filename: subdirectory/package.json
|
||||
//// { "dependencies": { "@types/module-x": "latest" } }
|
||||
|
||||
// @Filename: node_modules/@types/module-y/index.d.ts
|
||||
//// export var y = 9;
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "@types/module-y": "latest" } }
|
||||
|
||||
const kinds = ["types_ref", "import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("module-x");
|
||||
verify.completionListContains("module-y");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for ts files when allowJs is false
|
||||
|
||||
// @Filename: test0.ts
|
||||
//// import * as foo1 from "./*import_as0*/
|
||||
//// import * as foo2 from ".//*import_as1*/
|
||||
//// import * as foo4 from "./folder//*import_as2*/
|
||||
|
||||
//// import foo6 = require("./*import_equals0*/
|
||||
//// import foo7 = require(".//*import_equals1*/
|
||||
//// import foo9 = require("./folder//*import_equals2*/
|
||||
|
||||
//// var foo11 = require("./*require0*/
|
||||
//// var foo12 = require(".//*require1*/
|
||||
//// var foo14 = require("./folder//*require2*/
|
||||
|
||||
// @Filename: parentTest/sub/test5.ts
|
||||
//// import * as foo16 from "../g/*import_as3*/
|
||||
//// import foo17 = require("../g/*import_equals3*/
|
||||
//// var foo18 = require("../g/*require3*/
|
||||
|
||||
|
||||
// @Filename: f1.ts
|
||||
//// /*f1*/
|
||||
// @Filename: f1.js
|
||||
//// /*f1j*/
|
||||
// @Filename: f1.d.ts
|
||||
//// /*f1d*/
|
||||
// @Filename: f2.tsx
|
||||
//// /f2*/
|
||||
// @Filename: f3.js
|
||||
//// /*f3*/
|
||||
// @Filename: f4.jsx
|
||||
//// /*f4*/
|
||||
// @Filename: e1.ts
|
||||
//// /*e1*/
|
||||
// @Filename: folder/f3.ts
|
||||
//// /*subf1*/
|
||||
// @Filename: folder/h1.ts
|
||||
//// /*subh1*/
|
||||
// @Filename: parentTest/f4.ts
|
||||
//// /*parentf1*/
|
||||
// @Filename: parentTest/g1.ts
|
||||
//// /*parentg1*/
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListIsEmpty();
|
||||
|
||||
goTo.marker(kind + "1");
|
||||
verify.completionListContains("f1");
|
||||
verify.completionListContains("f2");
|
||||
verify.completionListContains("e1");
|
||||
verify.completionListContains("folder");
|
||||
verify.completionListContains("parentTest");
|
||||
verify.not.completionListItemsCountIsGreaterThan(5);
|
||||
|
||||
goTo.marker(kind + "2");
|
||||
verify.completionListContains("f3");
|
||||
verify.completionListContains("h1");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
|
||||
goTo.marker(kind + "3");
|
||||
verify.completionListContains("f4");
|
||||
verify.completionListContains("g1");
|
||||
verify.completionListContains("sub");
|
||||
verify.not.completionListItemsCountIsGreaterThan(3);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for ts and js files when allowJs is true
|
||||
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: test0.ts
|
||||
//// import * as foo1 from ".//*import_as0*/
|
||||
//// import * as foo2 from "./f/*import_as1*/
|
||||
|
||||
//// import foo3 = require(".//*import_equals0*/
|
||||
//// import foo4 = require("./f/*import_equals1*/
|
||||
|
||||
//// var foo5 = require(".//*require0*/
|
||||
//// var foo6 = require("./f/*require1*/
|
||||
|
||||
// @Filename: f1.ts
|
||||
//// /f1*/
|
||||
// @Filename: f1.js
|
||||
//// /*f1j*/
|
||||
// @Filename: f1.d.ts
|
||||
//// /*f1d*/
|
||||
// @Filename: f2.tsx
|
||||
//// /*f2*/
|
||||
// @Filename: f3.js
|
||||
//// /*f3*/
|
||||
// @Filename: f4.jsx
|
||||
//// /*f4*/
|
||||
// @Filename: e1.ts
|
||||
//// /*e1*/
|
||||
// @Filename: e2.js
|
||||
//// /*e2*/
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("f1");
|
||||
verify.completionListContains("f2");
|
||||
verify.completionListContains("f3");
|
||||
verify.completionListContains("f4");
|
||||
verify.completionListContains("e1");
|
||||
verify.completionListContains("e2");
|
||||
verify.not.completionListItemsCountIsGreaterThan(6);
|
||||
|
||||
goTo.marker(kind + "1");
|
||||
verify.completionListContains("f1");
|
||||
verify.completionListContains("f2");
|
||||
verify.completionListContains("f3");
|
||||
verify.completionListContains("f4");
|
||||
verify.completionListContains("e1");
|
||||
verify.completionListContains("e2");
|
||||
verify.not.completionListItemsCountIsGreaterThan(6);
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for absolute paths
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// import * as foo1 from "/tests/cases/f/*import_as0*/
|
||||
//// import * as foo2 from "/tests/cases/fourslash/*import_as1*/
|
||||
//// import * as foo3 from "/tests/cases/fourslash//*import_as2*/
|
||||
|
||||
//// import foo4 = require("/tests/cases/f/*import_equals0*/
|
||||
//// import foo5 = require("/tests/cases/fourslash/*import_equals1*/
|
||||
//// import foo6 = require("/tests/cases/fourslash//*import_equals2*/
|
||||
|
||||
//// var foo7 = require("/tests/cases/f/*require0*/
|
||||
//// var foo8 = require("/tests/cases/fourslash/*require1*/
|
||||
//// var foo9 = require("/tests/cases/fourslash//*require2*/
|
||||
|
||||
// @Filename: f1.ts
|
||||
//// /*f1*/
|
||||
// @Filename: f2.tsx
|
||||
//// /*f2*/
|
||||
// @Filename: folder/f1.ts
|
||||
//// /*subf1*/
|
||||
// @Filename: f3.js
|
||||
//// /*f3*/
|
||||
// @Filename: f4.jsx
|
||||
//// /*f4*/
|
||||
// @Filename: e1.ts
|
||||
//// /*e1*/
|
||||
// @Filename: e2.js
|
||||
//// /*e2*/
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
verify.completionListContains("fourslash");
|
||||
verify.not.completionListItemsCountIsGreaterThan(1);
|
||||
|
||||
goTo.marker(kind + "1");
|
||||
verify.completionListContains("fourslash");
|
||||
verify.not.completionListItemsCountIsGreaterThan(1);
|
||||
|
||||
goTo.marker(kind + "2");
|
||||
verify.completionListContains("f1");
|
||||
verify.completionListContains("f2");
|
||||
verify.completionListContains("e1");
|
||||
verify.completionListContains("folder");
|
||||
verify.completionListContains("tests");
|
||||
verify.not.completionListItemsCountIsGreaterThan(5);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for directories that are merged via the rootDirs compiler option
|
||||
|
||||
// @rootDirs: tests/cases/fourslash/sub/src1,tests/cases/fourslash/src2
|
||||
|
||||
// @Filename: src2/test0.ts
|
||||
//// import * as foo1 from "./mo/*import_as0*/
|
||||
//// import foo2 = require("./mo/*import_equals0*/
|
||||
//// var foo3 = require("./mo/*require0*/
|
||||
|
||||
// @Filename: src2/module0.ts
|
||||
//// export var w = 0;
|
||||
|
||||
// @Filename: sub/src1/module1.ts
|
||||
//// export var x = 0;
|
||||
|
||||
// @Filename: sub/src1/module2.ts
|
||||
//// export var y = 0;
|
||||
|
||||
// @Filename: sub/src1/more/module3.ts
|
||||
//// export var z = 0;
|
||||
|
||||
|
||||
// @Filename: f1.ts
|
||||
//// /*f1*/
|
||||
// @Filename: f2.tsx
|
||||
//// /*f2*/
|
||||
// @Filename: folder/f1.ts
|
||||
//// /*subf1*/
|
||||
// @Filename: f3.js
|
||||
//// /*f3*/
|
||||
// @Filename: f4.jsx
|
||||
//// /*f4*/
|
||||
// @Filename: e1.ts
|
||||
//// /*e1*/
|
||||
// @Filename: e2.js
|
||||
//// /*e2*/
|
||||
|
||||
const kinds = ["import_as", "import_equals", "require"];
|
||||
|
||||
for (const kind of kinds) {
|
||||
goTo.marker(kind + "0");
|
||||
|
||||
verify.completionListContains("module0");
|
||||
verify.completionListContains("module1");
|
||||
verify.completionListContains("module2");
|
||||
verify.completionListContains("more");
|
||||
|
||||
// Should not contain itself
|
||||
verify.not.completionListItemsCountIsGreaterThan(4);
|
||||
}
|
51
tests/cases/fourslash/completionForTripleSlashReference1.ts
Normal file
51
tests/cases/fourslash/completionForTripleSlashReference1.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for relative references to ts files when allowJs is false
|
||||
|
||||
// @Filename: test0.ts
|
||||
//// /// <reference path="/*0*/
|
||||
//// /// <reference path="./*1*/
|
||||
//// /// <reference path="../*2*/
|
||||
//// /// <reference path=".//*3*/
|
||||
//// /// <reference path="./f/*4*/" />
|
||||
//// /// <reference path="./parentTest//*5*/
|
||||
|
||||
// @Filename: parentTest/sub/test1.ts
|
||||
//// /// <reference path="../g/*6*/
|
||||
|
||||
// @Filename: f1.ts
|
||||
//// /*f1*/
|
||||
// @Filename: f1.js
|
||||
//// /*f1j*/
|
||||
// @Filename: f1.d.ts
|
||||
//// /*f1d*/
|
||||
// @Filename: f2.tsx
|
||||
//// /f2*/
|
||||
// @Filename: f3.js
|
||||
//// /*f3*/
|
||||
// @Filename: f4.jsx
|
||||
//// /*f4*/
|
||||
// @Filename: e1.ts
|
||||
//// /*e1*/
|
||||
// @Filename: parentTest/g1.ts
|
||||
//// /*parentg1*/
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
goTo.marker("" + i);
|
||||
verify.completionListContains("f1.ts");
|
||||
verify.completionListContains("f1.d.ts");
|
||||
verify.completionListContains("f2.tsx");
|
||||
verify.completionListContains("e1.ts");
|
||||
verify.completionListContains("parentTest");
|
||||
verify.not.completionListItemsCountIsGreaterThan(5);
|
||||
}
|
||||
|
||||
goTo.marker("5");
|
||||
verify.completionListContains("g1.ts");
|
||||
verify.completionListContains("sub");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
||||
|
||||
goTo.marker("6");
|
||||
verify.completionListContains("g1.ts");
|
||||
verify.completionListContains("sub");
|
||||
verify.not.completionListItemsCountIsGreaterThan(2);
|
33
tests/cases/fourslash/completionForTripleSlashReference2.ts
Normal file
33
tests/cases/fourslash/completionForTripleSlashReference2.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for relative references to js and ts files when allowJs is true
|
||||
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: test0.ts
|
||||
//// /// <reference path="/*0*/
|
||||
//// /// <reference path="./*1*/
|
||||
//// /// <reference path="../*2*/
|
||||
//// /// <reference path=".//*3*/
|
||||
//// /// <reference path="./f/*4*/" />
|
||||
|
||||
// @Filename: f1.ts
|
||||
//// /*f1*/
|
||||
// @Filename: f1.js
|
||||
//// /*f1j*/
|
||||
// @Filename: f1.d.ts
|
||||
//// /*f1d*/
|
||||
// @Filename: f2.tsx
|
||||
//// /f2*/
|
||||
// @Filename: f4.jsx
|
||||
//// /*f4*/
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
goTo.marker("" + i);
|
||||
verify.completionListContains("f1.ts");
|
||||
verify.completionListContains("f1.js");
|
||||
verify.completionListContains("f1.d.ts");
|
||||
verify.completionListContains("f2.tsx");
|
||||
verify.completionListContains("f4.jsx");
|
||||
verify.not.completionListItemsCountIsGreaterThan(5);
|
||||
}
|
43
tests/cases/fourslash/completionForTripleSlashReference3.ts
Normal file
43
tests/cases/fourslash/completionForTripleSlashReference3.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should give completions for absolute paths
|
||||
|
||||
// @Filename: tests/test0.ts
|
||||
//// /// <reference path="/tests/cases/f/*0*/
|
||||
|
||||
// @Filename: tests/test1.ts
|
||||
//// /// <reference path="/tests/cases/fourslash/*1*/
|
||||
|
||||
// @Filename: tests/test2.ts
|
||||
//// /// <reference path="/tests/cases/fourslash//*2*/
|
||||
|
||||
// @Filename: f1.ts
|
||||
//// /*f1*/
|
||||
// @Filename: f2.tsx
|
||||
//// /*f2*/
|
||||
// @Filename: folder/f1.ts
|
||||
//// /*subf1*/
|
||||
// @Filename: f3.js
|
||||
//// /*f3*/
|
||||
// @Filename: f4.jsx
|
||||
//// /*f4*/
|
||||
// @Filename: e1.ts
|
||||
//// /*e1*/
|
||||
// @Filename: e2.js
|
||||
//// /*e2*/
|
||||
|
||||
goTo.marker("0");
|
||||
verify.completionListContains("fourslash");
|
||||
verify.not.completionListItemsCountIsGreaterThan(1);
|
||||
|
||||
goTo.marker("1");
|
||||
verify.completionListContains("fourslash");
|
||||
verify.not.completionListItemsCountIsGreaterThan(1);
|
||||
|
||||
goTo.marker("2");
|
||||
verify.completionListContains("f1.ts");
|
||||
verify.completionListContains("f2.tsx");
|
||||
verify.completionListContains("e1.ts");
|
||||
verify.completionListContains("folder");
|
||||
verify.completionListContains("tests");
|
||||
verify.not.completionListItemsCountIsGreaterThan(5);
|
43
tests/cases/fourslash/completionForTripleSlashReference4.ts
Normal file
43
tests/cases/fourslash/completionForTripleSlashReference4.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// Should NOT give completions for directories that are merged via the rootDirs compiler option
|
||||
|
||||
// @rootDirs: sub/src1,src2
|
||||
|
||||
// @Filename: src2/test0.ts
|
||||
//// /// <reference path="./mo/*0*/
|
||||
|
||||
// @Filename: src2/module0.ts
|
||||
//// export var w = 0;
|
||||
|
||||
// @Filename: sub/src1/module1.ts
|
||||
//// export var x = 0;
|
||||
|
||||
// @Filename: sub/src1/module2.ts
|
||||
//// export var y = 0;
|
||||
|
||||
// @Filename: sub/src1/more/module3.ts
|
||||
//// export var z = 0;
|
||||
|
||||
|
||||
// @Filename: f1.ts
|
||||
//// /*f1*/
|
||||
// @Filename: f2.tsx
|
||||
//// /*f2*/
|
||||
// @Filename: folder/f1.ts
|
||||
//// /*subf1*/
|
||||
// @Filename: f3.js
|
||||
//// /*f3*/
|
||||
// @Filename: f4.jsx
|
||||
//// /*f4*/
|
||||
// @Filename: e1.ts
|
||||
//// /*e1*/
|
||||
// @Filename: e2.js
|
||||
//// /*e2*/
|
||||
|
||||
|
||||
goTo.marker("0");
|
||||
|
||||
verify.completionListContains("module0.ts");
|
||||
|
||||
verify.not.completionListItemsCountIsGreaterThan(1);
|
|
@ -12,6 +12,7 @@
|
|||
////}
|
||||
/////*PlaceOpenBraceOnNewLineForControlBlocks*/if (true) {
|
||||
////}
|
||||
/////*InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces*/{ var t = 1};
|
||||
|
||||
runTest("InsertSpaceAfterCommaDelimiter", "[1, 2, 3];[72,];", "[1,2,3];[72,];");
|
||||
runTest("InsertSpaceAfterSemicolonInForStatements", "for (i = 0; i; i++);", "for (i = 0;i;i++);");
|
||||
|
@ -23,6 +24,7 @@ runTest("InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets", "[ 1 ];[];[];
|
|||
runTest("InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces", "`${ 1 }`; `${ 1 }`", "`${1}`; `${1}`");
|
||||
runTest("PlaceOpenBraceOnNewLineForFunctions", "class foo", "class foo {");
|
||||
runTest("PlaceOpenBraceOnNewLineForControlBlocks", "if ( true )", "if ( true ) {");
|
||||
runTest("InsertSpaceAfterOpeningAndBeforeClosingNonemptyBraces", "{ var t = 1 };", "{var t = 1};");
|
||||
|
||||
|
||||
function runTest(propertyName: string, expectedStringWhenTrue: string, expectedStringWhenFalse: string) {
|
||||
|
|
|
@ -121,7 +121,7 @@ declare namespace FourSlashInterface {
|
|||
constructor(negative?: boolean);
|
||||
memberListContains(symbol: string, text?: string, documenation?: string, kind?: string): void;
|
||||
memberListCount(expectedCount: number): void;
|
||||
completionListContains(symbol: string, text?: string, documentation?: string, kind?: string): void;
|
||||
completionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number): void;
|
||||
completionListItemsCountIsGreaterThan(count: number): void;
|
||||
completionListIsEmpty(): void;
|
||||
completionListAllowsNewIdentifier(): void;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// @module: CommonJS
|
||||
// @declaration: true
|
||||
// @out: declSingleFile.js
|
||||
// @outDir: tests/cases/fourslash/
|
||||
// @outDir: /tests/cases/fourslash/
|
||||
|
||||
// @Filename: inputFile1.ts
|
||||
//// var x: number = 5;
|
||||
|
|
|
@ -12,4 +12,4 @@
|
|||
////var y = new DefaultExportedClass;
|
||||
|
||||
goTo.marker();
|
||||
verify.renameInfoSucceeded("DefaultExportedClass", '"tests/cases/fourslash/foo".DefaultExportedClass');
|
||||
verify.renameInfoSucceeded("DefaultExportedClass", '"/tests/cases/fourslash/foo".DefaultExportedClass');
|
|
@ -12,4 +12,4 @@
|
|||
////var y = new DefaultExportedClass;
|
||||
|
||||
goTo.marker();
|
||||
verify.renameInfoSucceeded("DefaultExportedClass", '"tests/cases/fourslash/foo".DefaultExportedClass');
|
||||
verify.renameInfoSucceeded("DefaultExportedClass", '"/tests/cases/fourslash/foo".DefaultExportedClass');
|
|
@ -12,4 +12,4 @@
|
|||
////var y = new /**/[|DefaultExportedClass|];
|
||||
|
||||
goTo.marker();
|
||||
verify.renameInfoSucceeded("DefaultExportedClass", '"tests/cases/fourslash/foo".DefaultExportedClass');
|
||||
verify.renameInfoSucceeded("DefaultExportedClass", '"/tests/cases/fourslash/foo".DefaultExportedClass');
|
|
@ -13,4 +13,4 @@
|
|||
////var y = DefaultExportedFunction();
|
||||
|
||||
goTo.marker();
|
||||
verify.renameInfoSucceeded("DefaultExportedFunction", '"tests/cases/fourslash/foo".DefaultExportedFunction');
|
||||
verify.renameInfoSucceeded("DefaultExportedFunction", '"/tests/cases/fourslash/foo".DefaultExportedFunction');
|
|
@ -13,4 +13,4 @@
|
|||
////var y = DefaultExportedFunction();
|
||||
|
||||
goTo.marker();
|
||||
verify.renameInfoSucceeded("DefaultExportedFunction", '"tests/cases/fourslash/foo".DefaultExportedFunction');
|
||||
verify.renameInfoSucceeded("DefaultExportedFunction", '"/tests/cases/fourslash/foo".DefaultExportedFunction');
|
Loading…
Reference in a new issue