Mid edits

This commit is contained in:
Arthur Ozga 2016-11-22 16:46:09 -08:00
parent 2131d5727e
commit 7a67cf1796
11 changed files with 190 additions and 49 deletions

View file

@ -400,49 +400,64 @@ namespace ts.Completions {
/**
* 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
* * 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)
*
* We include all files that are found in node_modules/moduleName/ with acceptable file extensions.
* Note that we do not traverse the path through all of its ancestors and node_modules subdirectories as that is too
* slow and the above should include all intended packages.
*/
function getCompletionEntriesForNonRelativeModules(fragment: string, scriptPath: string, span: TextSpan): CompletionEntry[] {
const { baseUrl, paths } = compilerOptions;
let result: CompletionEntry[];
// TODO: (arozga) do completions by path fragment
const dirPathFragment = getDirectoryPath(normalizeSlashes(fragment));
if (baseUrl) {
const fileExtensions = getSupportedExtensions(compilerOptions);
const projectDir = compilerOptions.project || host.getCurrentDirectory();
const absolute = isRootedDiskPath(baseUrl) ? baseUrl : combinePaths(projectDir, baseUrl);
result = getCompletionEntriesForDirectoryFragment(fragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/false, span);
if (paths) {
if (!paths) {
result = getCompletionEntriesForDirectoryFragment(dirPathFragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/false, span);
}
else {
result = [];
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));
}
if (!paths.hasOwnProperty(path)) {
continue;
}
const patterns = paths[path];
if (!patterns) {
continue;
}
const pathPattern = hasZeroOrOneAsteriskCharacter(path) ? tryParsePattern(path) : undefined;
if (pathPattern) {
for (const pattern of patterns) {
// TODO: (arozga) Need to match fragment against path-pattern to see if we have already partially-completed the path.
const matches = getModulesForPathsPattern(fragment, baseUrl, pattern, fileExtensions);
// TODO: (arozga)
if (matches) {
for (const match of matches) {
// TODO: (arozga) need to figure out which fragment to add based on
result.push(createCompletionEntryForModule(pathPattern.prefix + match + pathPattern.suffix, 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 {
// TODO: (arozga) Check if target of pattern exists.
result.push(createCompletionEntryForModule(path, ScriptElementKind.externalModuleName, span));
}
}
}
}
else {
result = [];
}
getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, span, result);
result = getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, span, result);
for (const moduleName of enumeratePotentialNonRelativeModules(fragment, scriptPath, compilerOptions)) {
result.push(createCompletionEntryForModule(moduleName, ScriptElementKind.externalModuleName, span));
@ -451,7 +466,14 @@ namespace ts.Completions {
return result;
}
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: string[]): string[] {
/**
* ???
*
* TODO: (arozga) Make the fragment a path (as an argument)
* TODO: (arozga) Make the result returned be the only the last bit of the path (like in getDirFragment).
* TODO: (arozga) Draw pictures of what we think the various components look like.
*/
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: string[]): string[] | undefined {
if (host.readDirectory) {
const parsed = hasZeroOrOneAsteriskCharacter(pattern) ? tryParsePattern(pattern) : undefined;
if (parsed) {
@ -486,6 +508,7 @@ namespace ts.Completions {
continue;
}
// TODO: (arozga) simplify.
const start = completePrefix.length;
const length = normalizedMatch.length - start - normalizedSuffix.length;

View file

@ -1,7 +1,6 @@
/// <reference path='fourslash.ts' />
// Should give completions for node modules and files within those modules with ts file extensions/
// When baseURL isn't specified, _________________??????????????????
// We don't walk the filesystem to search for modules. Instead we use cheap heuristics.
// @moduleResolution: node
@ -9,8 +8,8 @@
//// import {I as I0} from "/*0*/
//// import * as IModule0 from "/*1*/
//// import IRequireModule0 from "/*2*/
//// // TODO:(arozga) require syntax?
//// import foo2 = require("/*3*/
//// var foo3 = require("/*4*/
// @Filename: src/not_present.ts
// @Filename: src/node_modules/1.ts
@ -28,26 +27,8 @@
// @Filename: src/node_modules/@types/13/index.tsx
// @Filename: src/node_modules/@types/14/index.d.ts
// @Filename: not_present.ts
// @Filename: node_modules/15.ts
// @Filename: node_modules/16.tsx
// @Filename: node_modules/17.d.ts
// @Filename: node_modules/18/package.json
// @Filename: node_modules/19/index.ts
// @Filename: node_modules/20/index.tsx
// @Filename: node_modules/21/index.d.ts
// @Filename: node_modules/@types/22.ts
// @Filename: node_modules/@types/23.tsx
// @Filename: node_modules/@types/24.d.ts
// @Filename: node_modules/@types/25/package.json
// @Filename: node_modules/@types/26/index.ts
// @Filename: node_modules/@types/27/index.tsx
// @Filename: node_modules/@types/28/index.d.ts
for (let marker = 0; marker < 3; marker++) {
for (let marker = 0; marker < 5; marker++) {
goTo.marker(marker.toString());
for (let i = 1; i < 29; i++) {
verify.completionListContains(i.toString());
verify.not.completionListItemsCountIsGreaterThan(28);
}
verify.completionListIsEmpty();
}

View file

@ -0,0 +1,35 @@
/// <reference path='fourslash.ts' />
// if baseURL is specified but paths is not, then we offer completions for non-relative imports
// relative to the baseURL.
// @Filename: tsconfig.json
//// {
//// "compilerOptions": {
//// "baseUrl": "./modules"
//// }
//// }
// @Filename: test.ts
//// import * as a from "/*0*/
//// import * as b from "dir//*1*/"
// @Filename: node_modules/bad.ts
// @Filename: modules/a.ts
//// /*marker_a*/
// @Filename: modules/a.d.ts
//// /*marker_a_d*/
// @Filename: modules/dir/b.ts
//// /*marker_b*/
goTo.marker("0");
verify.completionListContains("a");
verify.completionListContains("dir");
verify.not.completionListItemsCountIsGreaterThan(2);
goTo.marker("1");
verify.completionListContains("b");
verify.not.completionListItemsCountIsGreaterThan(1);

View file

@ -0,0 +1 @@
/// <reference path='fourslash.ts' />

View file

@ -0,0 +1 @@
/// <reference path='fourslash.ts' />

View file

@ -0,0 +1,95 @@
/// <reference path='fourslash.ts' />
// If baseURL and paths is specified, we compare against the baseUrl/paths rule.
// We do NOT do a raw comparison against baseUrl unless we specified such a paths rule.
// @Filename: tsconfig.json
//// {
//// "compilerOptions": {
//// "baseUrl": "./modules"
//// }
//// }
// @Filename: tsconfig.json
//// {
//// "compilerOptions": {
//// "baseUrl": "./modules",
//// "paths": {
//// "a": ["a.ts"],
//// "b": ["b.ts"],
//// "c": ["c.ts", "c.d.ts"],
//// "d": ["dir/d.ts"],
//// "e/e": ["dir/e.ts"],
//// "*": ["dir_star/*"],
//// "prefix_*_suffix": ["dir_star/*"],
//// "i": ["i.ts"], // Target does not exist.
//// "j/j": ["dir/j.ts"] // Target does not exist.
//// }
//// }
//// }
// @Filename: test.ts
//// import * as a from "/*0*/
//// import * as b from "e//*1*/
//// import * as c from "g//*2*/
//// import * as d from "prefix_dir2//*3*/_suffix
// @Filename: node_modules/bad.ts
//// /*marker_bad*/
// @Filename: modules/also_bad.ts
//// /*marker_also_bad*/
// @Filename: modules/a.ts
//// /*marker_a*/
// @Filename: modules/b.ts
//// /*marker_b*/
// @Filename: modules/c.ts
//// /*marker_c*/
// @Filename: modules/c.d.ts
//// /*marker_c_d*/
// @Filename: modules/dir/d.ts
//// /*marker_d*/
// @Filename: modules/dir/e.ts
//// /*marker_e*/
// @Filename: modules/dir_star/f.ts
//// /*marker_f*/
// @Filename: modules/dir_star/g.ts
//// /*marker_g*/
// @Filename: modules/dir_star/dir2/h.ts
//// /*marker_h*/
goTo.marker("0");
verify.completionListContains("a");
verify.completionListContains("b");
verify.completionListContains("c");
verify.completionListContains("d");
verify.completionListContains("e");
verify.completionListContains("f");
verify.completionListContains("g");
verify.completionListContains("dir2");
verify.completionListContains("prefix_f_suffix");
verify.completionListContains("prefix_g_suffix");
verify.completionListContains("prefix_dir2_suffix");
verify.completionListContains("h");
verify.completionListContains("i");
verify.not.completionListItemsCountIsGreaterThan(5);
/*
goTo.marker("1");
verify.completionListContains("d");
verify.not.completionListItemsCountIsGreaterThan(1);
goTo.marker("2");
verify.completionListIsEmpty();
goTo.marker("2");
verify.completionListContains("h");
*/

View file

@ -0,0 +1 @@
/// <reference path='fourslash.ts' />

View file

@ -0,0 +1 @@
/// <reference path='fourslash.ts' />

View file

@ -0,0 +1 @@
/// <reference path='fourslash.ts' />

View file

@ -0,0 +1 @@
/// <reference path='fourslash.ts' />

View file

@ -0,0 +1 @@
/// <reference path='fourslash.ts' />