Merge branch 'master' into FixAbsoluteTripleSlashCompletions

This commit is contained in:
Arthur Ozga 2016-10-03 11:07:41 -07:00
commit 728252fd4d
19 changed files with 323 additions and 41 deletions

View File

@ -17,7 +17,6 @@ declare module "gulp-typescript" {
stripInternal?: boolean;
types?: string[];
}
interface CompileStream extends NodeJS.ReadWriteStream { } // Either gulp or gulp-typescript has some odd typings which don't reflect reality, making this required
}
import * as insert from "gulp-insert";
import * as sourcemaps from "gulp-sourcemaps";
@ -169,7 +168,7 @@ for (const i in libraryTargets) {
gulp.task(target, false, [], function() {
return gulp.src(sources)
.pipe(newer(target))
.pipe(concat(target, { newLine: "" }))
.pipe(concat(target, { newLine: "\n\n" }))
.pipe(gulp.dest("."));
});
}
@ -380,10 +379,10 @@ gulp.task(builtLocalCompiler, false, [servicesFile], () => {
return localCompilerProject.src()
.pipe(newer(builtLocalCompiler))
.pipe(sourcemaps.init())
.pipe(tsc(localCompilerProject))
.pipe(localCompilerProject())
.pipe(prependCopyright())
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(builtLocalDirectory));
.pipe(gulp.dest("."));
});
gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => {
@ -391,7 +390,7 @@ gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => {
const {js, dts} = servicesProject.src()
.pipe(newer(servicesFile))
.pipe(sourcemaps.init())
.pipe(tsc(servicesProject));
.pipe(servicesProject());
const completedJs = js.pipe(prependCopyright())
.pipe(sourcemaps.write("."));
const completedDts = dts.pipe(prependCopyright(/*outputCopyright*/true))
@ -409,13 +408,13 @@ gulp.task(servicesFile, false, ["lib", "generate-diagnostics"], () => {
file.path = nodeDefinitionsFile;
return content + "\r\nexport = ts;";
}))
.pipe(gulp.dest(builtLocalDirectory)),
.pipe(gulp.dest(".")),
completedDts.pipe(clone())
.pipe(insert.transform((content, file) => {
file.path = nodeStandaloneDefinitionsFile;
return content.replace(/declare (namespace|module) ts/g, 'declare module "typescript"');
}))
]).pipe(gulp.dest(builtLocalDirectory));
]).pipe(gulp.dest("."));
});
// cancellationToken.js
@ -425,7 +424,7 @@ gulp.task(cancellationTokenJs, false, [servicesFile], () => {
return cancellationTokenProject.src()
.pipe(newer(cancellationTokenJs))
.pipe(sourcemaps.init())
.pipe(tsc(cancellationTokenProject))
.pipe(cancellationTokenProject())
.pipe(prependCopyright())
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(builtLocalDirectory));
@ -438,10 +437,10 @@ gulp.task(typingsInstallerJs, false, [servicesFile], () => {
return cancellationTokenProject.src()
.pipe(newer(typingsInstallerJs))
.pipe(sourcemaps.init())
.pipe(tsc(cancellationTokenProject))
.pipe(cancellationTokenProject())
.pipe(prependCopyright())
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(builtLocalDirectory));
.pipe(gulp.dest("."));
});
const serverFile = path.join(builtLocalDirectory, "tsserver.js");
@ -451,10 +450,10 @@ gulp.task(serverFile, false, [servicesFile, typingsInstallerJs, cancellationToke
return serverProject.src()
.pipe(newer(serverFile))
.pipe(sourcemaps.init())
.pipe(tsc(serverProject))
.pipe(serverProject())
.pipe(prependCopyright())
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(builtLocalDirectory));
.pipe(gulp.dest("."));
});
const tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js");
@ -465,14 +464,14 @@ gulp.task(tsserverLibraryFile, false, [servicesFile], (done) => {
const {js, dts}: { js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream } = serverLibraryProject.src()
.pipe(sourcemaps.init())
.pipe(newer(tsserverLibraryFile))
.pipe(tsc(serverLibraryProject));
.pipe(serverLibraryProject());
return merge2([
js.pipe(prependCopyright())
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(builtLocalDirectory)),
.pipe(gulp.dest(".")),
dts.pipe(prependCopyright())
.pipe(gulp.dest(builtLocalDirectory))
.pipe(gulp.dest("."))
]);
});
@ -544,9 +543,9 @@ gulp.task(run, false, [servicesFile], () => {
return testProject.src()
.pipe(newer(run))
.pipe(sourcemaps.init())
.pipe(tsc(testProject))
.pipe(testProject())
.pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "../../" }))
.pipe(gulp.dest(builtLocalDirectory));
.pipe(gulp.dest("."));
});
const internalTests = "internal/";
@ -730,7 +729,7 @@ gulp.task("browserify", "Runs browserify on run.js to produce a file suitable fo
return testProject.src()
.pipe(newer("built/local/bundle.js"))
.pipe(sourcemaps.init())
.pipe(tsc(testProject))
.pipe(testProject)
.pipe(through2.obj((file, enc, next) => {
const originalMap = file.sourceMap;
const prebundledContent = file.contents.toString();

View File

@ -964,7 +964,11 @@ namespace ts {
currentFlow = preTryFlow;
bind(node.finallyBlock);
}
currentFlow = finishFlowLabel(postFinallyLabel);
// if try statement has finally block and flow after finally block is unreachable - keep it
// otherwise use whatever flow was accumulated at postFinallyLabel
if (!node.finallyBlock || !(currentFlow.flags & FlowFlags.Unreachable)) {
currentFlow = finishFlowLabel(postFinallyLabel);
}
}
function bindSwitchStatement(node: SwitchStatement): void {

View File

@ -1689,7 +1689,7 @@ namespace ts {
assignment = flattenVariableDestructuringToExpression(context, decl, hoistVariableDeclaration, /*nameSubstitution*/ undefined, visitor);
}
else {
assignment = createBinary(<Identifier>decl.name, SyntaxKind.EqualsToken, decl.initializer);
assignment = createBinary(<Identifier>decl.name, SyntaxKind.EqualsToken, visitNode(decl.initializer, visitor, isExpression));
}
(assignments || (assignments = [])).push(assignment);
}

View File

@ -51,8 +51,8 @@ namespace ts.projectSystem {
export class TestTypingsInstaller extends TI.TypingsInstaller implements server.ITypingsInstaller {
protected projectService: server.ProjectService;
constructor(readonly globalTypingsCacheLocation: string, throttleLimit: number, readonly installTypingHost: server.ServerHost) {
super(globalTypingsCacheLocation, "npm", safeList.path, throttleLimit);
constructor(readonly globalTypingsCacheLocation: string, throttleLimit: number, readonly installTypingHost: server.ServerHost, log?: TI.Log) {
super(globalTypingsCacheLocation, "npm", safeList.path, throttleLimit, log);
this.init();
}

View File

@ -11,11 +11,12 @@ namespace ts.projectSystem {
}
class Installer extends TestTypingsInstaller {
constructor(host: server.ServerHost, p?: InstallerParams) {
constructor(host: server.ServerHost, p?: InstallerParams, log?: TI.Log) {
super(
(p && p.globalTypingsCacheLocation) || "/a/data",
(p && p.throttleLimit) || 5,
host);
host,
log);
}
installAll(expectedView: typeof TI.NpmViewRequest[], expectedInstall: typeof TI.NpmInstallRequest[]) {
@ -685,10 +686,10 @@ namespace ts.projectSystem {
};
const bowerJson = {
path: "/bower.json",
content: JSON.stringify({
"dependencies": {
"jquery": "^3.1.0"
}
content: JSON.stringify({
"dependencies": {
"jquery": "^3.1.0"
}
})
};
const jqueryDTS = {
@ -720,4 +721,60 @@ namespace ts.projectSystem {
checkProjectActualFiles(p, [app.path, jqueryDTS.path]);
});
});
describe("Validate package name:", () => {
it ("name cannot be too long", () => {
let packageName = "a";
for (let i = 0; i < 8; i++) {
packageName += packageName;
}
assert.equal(TI.validatePackageName(packageName), TI.PackageNameValidationResult.NameTooLong);
});
it ("name cannot start with dot", () => {
assert.equal(TI.validatePackageName(".foo"), TI.PackageNameValidationResult.NameStartsWithDot);
});
it ("name cannot start with underscore", () => {
assert.equal(TI.validatePackageName("_foo"), TI.PackageNameValidationResult.NameStartsWithUnderscore);
});
it ("scoped packages not supported", () => {
assert.equal(TI.validatePackageName("@scope/bar"), TI.PackageNameValidationResult.ScopedPackagesNotSupported);
});
it ("non URI safe characters are not supported", () => {
assert.equal(TI.validatePackageName(" scope "), TI.PackageNameValidationResult.NameContainsNonURISafeCharacters);
assert.equal(TI.validatePackageName("; say Hello from TypeScript! #"), TI.PackageNameValidationResult.NameContainsNonURISafeCharacters);
assert.equal(TI.validatePackageName("a/b/c"), TI.PackageNameValidationResult.NameContainsNonURISafeCharacters);
});
});
describe("Invalid package names", () => {
it ("should not be installed", () => {
const f1 = {
path: "/a/b/app.js",
content: "let x = 1"
};
const packageJson = {
path: "/a/b/package.json",
content: JSON.stringify({
"dependencies": {
"; say Hello from TypeScript! #": "0.0.x"
}
})
};
const messages: string[] = [];
const host = createServerHost([f1, packageJson]);
const installer = new (class extends Installer {
constructor() {
super(host, { globalTypingsCacheLocation: "/tmp" }, { isEnabled: () => true, writeLine: msg => messages.push(msg) });
}
runCommand(requestKind: TI.RequestKind, requestId: number, command: string, cwd: string, cb: server.typingsInstaller.RequestCompletedAction) {
assert(false, "runCommand should not be invoked");
}
})();
const projectService = createProjectService(host, { typingsInstaller: installer });
projectService.openClientFile(f1.path);
installer.checkPendingCommands([]);
assert.isTrue(messages.indexOf("Package name '; say Hello from TypeScript! #' contains non URI safe characters") > 0, "should find package with invalid name");
});
});
}

View File

@ -5,7 +5,6 @@
"removeComments": true,
"preserveConstEnums": true,
"pretty": true,
"outDir": "../../../built/local",
"module": "commonjs",
"sourceMap": true,
"stripInternal": true,

View File

@ -93,6 +93,7 @@ namespace ts.server {
export const Geterr = "geterr";
export const GeterrForProject = "geterrForProject";
export const Implementation = "implementation";
export const ImplementationFull = "implementation-full";
export const SemanticDiagnosticsSync = "semanticDiagnosticsSync";
export const SyntacticDiagnosticsSync = "syntacticDiagnosticsSync";
export const NavBar = "navbar";
@ -421,7 +422,7 @@ namespace ts.server {
});
}
private getImplementation(args: protocol.FileLocationRequestArgs): protocol.FileSpan[] {
private getImplementation(args: protocol.FileLocationRequestArgs, simplifiedResult: boolean): protocol.FileSpan[] | ImplementationLocation[] {
const { file, project } = this.getFileAndProject(args);
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
const position = this.getPosition(args, scriptInfo);
@ -429,11 +430,16 @@ namespace ts.server {
if (!implementations) {
return [];
}
return implementations.map(impl => ({
file: impl.fileName,
start: scriptInfo.positionToLineOffset(impl.textSpan.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(impl.textSpan))
}));
if (simplifiedResult) {
return implementations.map(impl => ({
file: impl.fileName,
start: scriptInfo.positionToLineOffset(impl.textSpan.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(impl.textSpan))
}));
}
else {
return implementations;
}
}
private getOccurrences(args: protocol.FileLocationRequestArgs): protocol.OccurrencesResponseItem[] {
@ -1329,7 +1335,10 @@ namespace ts.server {
return this.requiredResponse(this.getTypeDefinition(request.arguments));
},
[CommandNames.Implementation]: (request: protocol.Request) => {
return this.requiredResponse(this.getImplementation(request.arguments));
return this.requiredResponse(this.getImplementation(request.arguments, /*simplifiedResult*/ true));
},
[CommandNames.ImplementationFull]: (request: protocol.Request) => {
return this.requiredResponse(this.getImplementation(request.arguments, /*simplifiedResult*/ false));
},
[CommandNames.References]: (request: protocol.FileLocationRequest) => {
return this.requiredResponse(this.getReferences(request.arguments, /*simplifiedResult*/ true));

View File

@ -5,7 +5,7 @@
"removeComments": true,
"preserveConstEnums": true,
"pretty": true,
"out": "../../built/local/tsserver.js",
"outFile": "../../built/local/tsserver.js",
"sourceMap": true,
"stripInternal": true,
"types": [

View File

@ -3,7 +3,7 @@
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"out": "../../built/local/tsserverlibrary.js",
"outFile": "../../built/local/tsserverlibrary.js",
"sourceMap": true,
"stripInternal": true,
"declaration": true,

View File

@ -5,7 +5,7 @@
"removeComments": true,
"preserveConstEnums": true,
"pretty": true,
"out": "../../built/local/typingsInstaller.js",
"outFile": "../../../built/local/typingsInstaller.js",
"sourceMap": true,
"stripInternal": true,
"types": [

View File

@ -23,6 +23,43 @@ namespace ts.server.typingsInstaller {
return result.resolvedModule && result.resolvedModule.resolvedFileName;
}
export enum PackageNameValidationResult {
Ok,
ScopedPackagesNotSupported,
NameTooLong,
NameStartsWithDot,
NameStartsWithUnderscore,
NameContainsNonURISafeCharacters
}
export const MaxPackageNameLength = 214;
/**
* Validates package name using rules defined at https://docs.npmjs.com/files/package.json
*/
export function validatePackageName(packageName: string): PackageNameValidationResult {
Debug.assert(!!packageName, "Package name is not specified");
if (packageName.length > MaxPackageNameLength) {
return PackageNameValidationResult.NameTooLong;
}
if (packageName.charCodeAt(0) === CharacterCodes.dot) {
return PackageNameValidationResult.NameStartsWithDot;
}
if (packageName.charCodeAt(0) === CharacterCodes._) {
return PackageNameValidationResult.NameStartsWithUnderscore;
}
// check if name is scope package like: starts with @ and has one '/' in the middle
// scoped packages are not currently supported
// TODO: when support will be added we'll need to split and check both scope and package name
if (/^@[^/]+\/[^/]+$/.test(packageName)) {
return PackageNameValidationResult.ScopedPackagesNotSupported;
}
if (encodeURIComponent(packageName) !== packageName) {
return PackageNameValidationResult.NameContainsNonURISafeCharacters;
}
return PackageNameValidationResult.Ok;
}
export const NpmViewRequest: "npm view" = "npm view";
export const NpmInstallRequest: "npm install" = "npm install";
@ -185,14 +222,54 @@ namespace ts.server.typingsInstaller {
this.knownCachesSet[cacheLocation] = true;
}
private filterTypings(typingsToInstall: string[]) {
if (typingsToInstall.length === 0) {
return typingsToInstall;
}
const result: string[] = [];
for (const typing of typingsToInstall) {
if (this.missingTypingsSet[typing]) {
continue;
}
const validationResult = validatePackageName(typing);
if (validationResult === PackageNameValidationResult.Ok) {
result.push(typing);
}
else {
// add typing name to missing set so we won't process it again
this.missingTypingsSet[typing] = true;
if (this.log.isEnabled()) {
switch (validationResult) {
case PackageNameValidationResult.NameTooLong:
this.log.writeLine(`Package name '${typing}' should be less than ${MaxPackageNameLength} characters`);
break;
case PackageNameValidationResult.NameStartsWithDot:
this.log.writeLine(`Package name '${typing}' cannot start with '.'`);
break;
case PackageNameValidationResult.NameStartsWithUnderscore:
this.log.writeLine(`Package name '${typing}' cannot start with '_'`);
break;
case PackageNameValidationResult.ScopedPackagesNotSupported:
this.log.writeLine(`Package '${typing}' is scoped and currently is not supported`);
break;
case PackageNameValidationResult.NameContainsNonURISafeCharacters:
this.log.writeLine(`Package name '${typing}' contains non URI safe characters`);
break;
}
}
}
}
return result;
}
private installTypings(req: DiscoverTypings, cachePath: string, currentlyCachedTypings: string[], typingsToInstall: string[]) {
if (this.log.isEnabled()) {
this.log.writeLine(`Installing typings ${JSON.stringify(typingsToInstall)}`);
}
typingsToInstall = filter(typingsToInstall, x => !this.missingTypingsSet[x]);
typingsToInstall = this.filterTypings(typingsToInstall);
if (typingsToInstall.length === 0) {
if (this.log.isEnabled()) {
this.log.writeLine(`All typings are known to be missing - no need to go any further`);
this.log.writeLine(`All typings are known to be missing or invalid - no need to go any further`);
}
return;
}

View File

@ -0,0 +1,19 @@
//// [transformArrowInBlockScopedLoopVarInitializer.ts]
// https://github.com/Microsoft/TypeScript/issues/11236
while (true)
{
let local = null;
var a = () => local; // <-- Lambda should be converted to function()
}
//// [transformArrowInBlockScopedLoopVarInitializer.js]
var _loop_1 = function () {
var local = null;
a = function () { return local; }; // <-- Lambda should be converted to function()
};
var a;
// https://github.com/Microsoft/TypeScript/issues/11236
while (true) {
_loop_1();
}

View File

@ -0,0 +1,12 @@
=== tests/cases/compiler/transformArrowInBlockScopedLoopVarInitializer.ts ===
// https://github.com/Microsoft/TypeScript/issues/11236
while (true)
{
let local = null;
>local : Symbol(local, Decl(transformArrowInBlockScopedLoopVarInitializer.ts, 4, 7))
var a = () => local; // <-- Lambda should be converted to function()
>a : Symbol(a, Decl(transformArrowInBlockScopedLoopVarInitializer.ts, 5, 7))
>local : Symbol(local, Decl(transformArrowInBlockScopedLoopVarInitializer.ts, 4, 7))
}

View File

@ -0,0 +1,15 @@
=== tests/cases/compiler/transformArrowInBlockScopedLoopVarInitializer.ts ===
// https://github.com/Microsoft/TypeScript/issues/11236
while (true)
>true : true
{
let local = null;
>local : any
>null : null
var a = () => local; // <-- Lambda should be converted to function()
>a : () => any
>() => local : () => any
>local : any
}

View File

@ -0,0 +1,27 @@
//// [unreachableFlowAfterFinally.ts]
function f() {
let x = 100;
try {
throw "WAT"
}
catch (e) {
}
finally {
return x;
}
}
//// [unreachableFlowAfterFinally.js]
function f() {
var x = 100;
try {
throw "WAT";
}
catch (e) {
}
finally {
return x;
}
}

View File

@ -0,0 +1,20 @@
=== tests/cases/compiler/unreachableFlowAfterFinally.ts ===
function f() {
>f : Symbol(f, Decl(unreachableFlowAfterFinally.ts, 0, 0))
let x = 100;
>x : Symbol(x, Decl(unreachableFlowAfterFinally.ts, 2, 7))
try {
throw "WAT"
}
catch (e) {
>e : Symbol(e, Decl(unreachableFlowAfterFinally.ts, 6, 11))
}
finally {
return x;
>x : Symbol(x, Decl(unreachableFlowAfterFinally.ts, 2, 7))
}
}

View File

@ -0,0 +1,22 @@
=== tests/cases/compiler/unreachableFlowAfterFinally.ts ===
function f() {
>f : () => number
let x = 100;
>x : number
>100 : 100
try {
throw "WAT"
>"WAT" : "WAT"
}
catch (e) {
>e : any
}
finally {
return x;
>x : number
}
}

View File

@ -0,0 +1,8 @@
// @target: es5
// https://github.com/Microsoft/TypeScript/issues/11236
while (true)
{
let local = null;
var a = () => local; // <-- Lambda should be converted to function()
}

View File

@ -0,0 +1,14 @@
// @noImplicitReturns: true
function f() {
let x = 100;
try {
throw "WAT"
}
catch (e) {
}
finally {
return x;
}
}