Skip to content

Commit 1b32744

Browse files
authored
Merge pull request #11569 from Microsoft/vladima/port-11550
Ports PR #11550 to master
2 parents 4ccb3bb + 92b63fa commit 1b32744

File tree

13 files changed

+570
-210
lines changed

13 files changed

+570
-210
lines changed

Jakefile.js

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ var serverCoreSources = [
174174
"lsHost.ts",
175175
"project.ts",
176176
"editorServices.ts",
177-
"protocol.d.ts",
177+
"protocol.ts",
178178
"session.ts",
179179
"server.ts"
180180
].map(function (f) {
@@ -198,14 +198,13 @@ var typingsInstallerSources = [
198198
var serverSources = serverCoreSources.concat(servicesSources);
199199

200200
var languageServiceLibrarySources = [
201-
"protocol.d.ts",
201+
"protocol.ts",
202202
"utilities.ts",
203203
"scriptVersionCache.ts",
204204
"scriptInfo.ts",
205205
"lsHost.ts",
206206
"project.ts",
207207
"editorServices.ts",
208-
"protocol.d.ts",
209208
"session.ts",
210209

211210
].map(function (f) {
@@ -259,15 +258,14 @@ var harnessSources = harnessCoreSources.concat([
259258
].map(function (f) {
260259
return path.join(unittestsDirectory, f);
261260
})).concat([
262-
"protocol.d.ts",
261+
"protocol.ts",
263262
"utilities.ts",
264263
"scriptVersionCache.ts",
265264
"scriptInfo.ts",
266265
"lsHost.ts",
267266
"project.ts",
268267
"typingsCache.ts",
269268
"editorServices.ts",
270-
"protocol.d.ts",
271269
"session.ts",
272270
].map(function (f) {
273271
return path.join(serverDirectory, f);
@@ -518,6 +516,40 @@ compileFile(processDiagnosticMessagesJs,
518516
[],
519517
/*useBuiltCompiler*/ false);
520518

519+
var buildProtocolTs = path.join(scriptsDirectory, "buildProtocol.ts");
520+
var buildProtocolJs = path.join(scriptsDirectory, "buildProtocol.js");
521+
var buildProtocolDts = path.join(builtLocalDirectory, "protocol.d.ts");
522+
var typescriptServicesDts = path.join(builtLocalDirectory, "typescriptServices.d.ts");
523+
524+
file(buildProtocolTs);
525+
526+
compileFile(buildProtocolJs,
527+
[buildProtocolTs],
528+
[buildProtocolTs],
529+
[],
530+
/*useBuiltCompiler*/ false,
531+
{noOutFile: true});
532+
533+
file(buildProtocolDts, [buildProtocolTs, buildProtocolJs, typescriptServicesDts], function() {
534+
535+
var protocolTs = path.join(serverDirectory, "protocol.ts");
536+
537+
var cmd = host + " " + buildProtocolJs + " "+ protocolTs + " " + typescriptServicesDts + " " + buildProtocolDts;
538+
console.log(cmd);
539+
var ex = jake.createExec([cmd]);
540+
// Add listeners for output and error
541+
ex.addListener("stdout", function (output) {
542+
process.stdout.write(output);
543+
});
544+
ex.addListener("stderr", function (error) {
545+
process.stderr.write(error);
546+
});
547+
ex.addListener("cmdEnd", function () {
548+
complete();
549+
});
550+
ex.run();
551+
}, { async: true })
552+
521553
// The generated diagnostics map; built for the compiler and for the 'generate-diagnostics' task
522554
file(diagnosticInfoMapTs, [processDiagnosticMessagesJs, diagnosticMessagesJson], function () {
523555
var cmd = host + " " + processDiagnosticMessagesJs + " " + diagnosticMessagesJson;
@@ -655,6 +687,8 @@ compileFile(
655687
inlineSourceMap: true
656688
});
657689

690+
file(typescriptServicesDts, [servicesFile]);
691+
658692
var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js");
659693
compileFile(cancellationTokenFile, cancellationTokenSources, [builtLocalDirectory].concat(cancellationTokenSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { outDir: builtLocalDirectory, noOutFile: true });
660694

@@ -689,7 +723,7 @@ task("build-fold-end", [], function () {
689723

690724
// Local target to build the compiler and services
691725
desc("Builds the full compiler and services");
692-
task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, builtGeneratedDiagnosticMessagesJSON, "lssl", "build-fold-end"]);
726+
task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, buildProtocolDts, builtGeneratedDiagnosticMessagesJSON, "lssl", "build-fold-end"]);
693727

694728
// Local target to build only tsc.js
695729
desc("Builds only the compiler");
@@ -745,7 +779,7 @@ task("generate-spec", [specMd]);
745779
// Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory
746780
desc("Makes a new LKG out of the built js files");
747781
task("LKG", ["clean", "release", "local"].concat(libraryTargets), function () {
748-
var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile, cancellationTokenFile, typingsInstallerFile].concat(libraryTargets);
782+
var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile, cancellationTokenFile, typingsInstallerFile, buildProtocolDts].concat(libraryTargets);
749783
var missingFiles = expectedFiles.filter(function (f) {
750784
return !fs.existsSync(f);
751785
});

scripts/buildProtocol.ts

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/// <reference types="node"/>
2+
3+
import * as ts from "../lib/typescript";
4+
import * as path from "path";
5+
6+
function endsWith(s: string, suffix: string) {
7+
return s.lastIndexOf(suffix, s.length - suffix.length) !== -1;
8+
}
9+
10+
class DeclarationsWalker {
11+
private visitedTypes: ts.Type[] = [];
12+
private text = "";
13+
private constructor(private typeChecker: ts.TypeChecker, private protocolFile: ts.SourceFile) {
14+
}
15+
16+
static getExtraDeclarations(typeChecker: ts.TypeChecker, protocolFile: ts.SourceFile): string {
17+
let text = "declare namespace ts.server.protocol {\n";
18+
var walker = new DeclarationsWalker(typeChecker, protocolFile);
19+
walker.visitTypeNodes(protocolFile);
20+
return walker.text
21+
? `declare namespace ts.server.protocol {\n${walker.text}}`
22+
: "";
23+
}
24+
25+
private processType(type: ts.Type): void {
26+
if (this.visitedTypes.indexOf(type) >= 0) {
27+
return;
28+
}
29+
this.visitedTypes.push(type);
30+
let s = type.aliasSymbol || type.getSymbol();
31+
if (!s) {
32+
return;
33+
}
34+
if (s.name === "Array") {
35+
// we should process type argument instead
36+
return this.processType((<any>type).typeArguments[0]);
37+
}
38+
else {
39+
for (const decl of s.getDeclarations()) {
40+
const sourceFile = decl.getSourceFile();
41+
if (sourceFile === this.protocolFile || path.basename(sourceFile.fileName) === "lib.d.ts") {
42+
return;
43+
}
44+
// splice declaration in final d.ts file
45+
const text = decl.getFullText();
46+
this.text += `${text}\n`;
47+
48+
// recursively pull all dependencies into result dts file
49+
this.visitTypeNodes(decl);
50+
}
51+
}
52+
}
53+
54+
private visitTypeNodes(node: ts.Node) {
55+
if (node.parent) {
56+
switch (node.parent.kind) {
57+
case ts.SyntaxKind.VariableDeclaration:
58+
case ts.SyntaxKind.MethodDeclaration:
59+
case ts.SyntaxKind.MethodSignature:
60+
case ts.SyntaxKind.PropertyDeclaration:
61+
case ts.SyntaxKind.PropertySignature:
62+
case ts.SyntaxKind.Parameter:
63+
case ts.SyntaxKind.IndexSignature:
64+
if (((<ts.VariableDeclaration | ts.MethodDeclaration | ts.PropertyDeclaration | ts.ParameterDeclaration | ts.PropertySignature | ts.MethodSignature | ts.IndexSignatureDeclaration>node.parent).type) === node) {
65+
const type = this.typeChecker.getTypeAtLocation(node);
66+
if (type && !(type.flags & ts.TypeFlags.TypeParameter)) {
67+
this.processType(type);
68+
}
69+
}
70+
break;
71+
}
72+
}
73+
ts.forEachChild(node, n => this.visitTypeNodes(n));
74+
}
75+
}
76+
77+
function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string): string {
78+
const options = { target: ts.ScriptTarget.ES5, declaration: true, noResolve: true, types: <string[]>[], stripInternal: true };
79+
80+
/**
81+
* 1st pass - generate a program from protocol.ts and typescriptservices.d.ts and emit core version of protocol.d.ts with all internal members stripped
82+
* @return text of protocol.d.t.s
83+
*/
84+
function getInitialDtsFileForProtocol() {
85+
const program = ts.createProgram([protocolTs, typeScriptServicesDts], options);
86+
87+
let protocolDts: string;
88+
program.emit(program.getSourceFile(protocolTs), (file, content) => {
89+
if (endsWith(file, ".d.ts")) {
90+
protocolDts = content;
91+
}
92+
});
93+
if (protocolDts === undefined) {
94+
throw new Error(`Declaration file for protocol.ts is not generated`)
95+
}
96+
return protocolDts;
97+
}
98+
99+
const protocolFileName = "protocol.d.ts";
100+
/**
101+
* Second pass - generate a program from protocol.d.ts and typescriptservices.d.ts, then augment core protocol.d.ts with extra types from typescriptservices.d.ts
102+
*/
103+
function getProgramWithProtocolText(protocolDts: string, includeTypeScriptServices: boolean) {
104+
const host = ts.createCompilerHost(options);
105+
const originalGetSourceFile = host.getSourceFile;
106+
host.getSourceFile = (fileName) => {
107+
if (fileName === protocolFileName) {
108+
return ts.createSourceFile(fileName, protocolDts, options.target);
109+
}
110+
return originalGetSourceFile.apply(host, [fileName]);
111+
}
112+
const rootFiles = includeTypeScriptServices ? [protocolFileName, typeScriptServicesDts] : [protocolFileName];
113+
return ts.createProgram(rootFiles, options, host);
114+
}
115+
116+
let protocolDts = getInitialDtsFileForProtocol();
117+
const program = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ true);
118+
119+
const protocolFile = program.getSourceFile("protocol.d.ts");
120+
const extraDeclarations = DeclarationsWalker.getExtraDeclarations(program.getTypeChecker(), protocolFile);
121+
if (extraDeclarations) {
122+
protocolDts += extraDeclarations;
123+
}
124+
// do sanity check and try to compile generated text as standalone program
125+
const sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false);
126+
const diagnostics = [...program.getSyntacticDiagnostics(), ...program.getSemanticDiagnostics(), ...program.getGlobalDiagnostics()];
127+
if (diagnostics.length) {
128+
const flattenedDiagnostics = diagnostics.map(d => ts.flattenDiagnosticMessageText(d.messageText, "\n")).join("\n");
129+
throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`);
130+
}
131+
return protocolDts;
132+
}
133+
134+
if (process.argv.length < 5) {
135+
console.log(`Expected 3 arguments: path to 'protocol.ts', path to 'typescriptservices.d.ts' and path to output file`);
136+
process.exit(1);
137+
}
138+
139+
const protocolTs = process.argv[2];
140+
const typeScriptServicesDts = process.argv[3];
141+
const outputFile = process.argv[4];
142+
const generatedProtocolDts = generateProtocolFile(protocolTs, typeScriptServicesDts);
143+
ts.sys.writeFile(outputFile, generatedProtocolDts);

src/compiler/types.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2917,11 +2917,7 @@ namespace ts {
29172917
NodeJs = 2
29182918
}
29192919

2920-
export type RootPaths = string[];
2921-
export type PathSubstitutions = MapLike<string[]>;
2922-
export type TsConfigOnlyOptions = RootPaths | PathSubstitutions;
2923-
2924-
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | TsConfigOnlyOptions;
2920+
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike<string[]>;
29252921

29262922
export interface CompilerOptions {
29272923
allowJs?: boolean;
@@ -2973,14 +2969,14 @@ namespace ts {
29732969
out?: string;
29742970
outDir?: string;
29752971
outFile?: string;
2976-
paths?: PathSubstitutions;
2972+
paths?: MapLike<string[]>;
29772973
preserveConstEnums?: boolean;
29782974
project?: string;
29792975
/* @internal */ pretty?: DiagnosticStyle;
29802976
reactNamespace?: string;
29812977
removeComments?: boolean;
29822978
rootDir?: string;
2983-
rootDirs?: RootPaths;
2979+
rootDirs?: string[];
29842980
skipLibCheck?: boolean;
29852981
skipDefaultLibCheck?: boolean;
29862982
sourceMap?: boolean;

0 commit comments

Comments
 (0)