-
Notifications
You must be signed in to change notification settings - Fork 12.8k
/
Copy pathbuildProtocol.js
135 lines (135 loc) · 6.23 KB
/
buildProtocol.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/// <reference types="node"/>
"use strict";
var ts = require("../lib/typescript");
var path = require("path");
function endsWith(s, suffix) {
return s.lastIndexOf(suffix, s.length - suffix.length) !== -1;
}
var DeclarationsWalker = (function () {
function DeclarationsWalker(typeChecker, protocolFile) {
this.typeChecker = typeChecker;
this.protocolFile = protocolFile;
this.visitedTypes = [];
this.text = "";
}
DeclarationsWalker.getExtraDeclarations = function (typeChecker, protocolFile) {
var text = "declare namespace ts.server.protocol {\n";
var walker = new DeclarationsWalker(typeChecker, protocolFile);
walker.visitTypeNodes(protocolFile);
return walker.text
? "declare namespace ts.server.protocol {\n" + walker.text + "}"
: "";
};
DeclarationsWalker.prototype.processType = function (type) {
if (this.visitedTypes.indexOf(type) >= 0) {
return;
}
this.visitedTypes.push(type);
var s = type.aliasSymbol || type.getSymbol();
if (!s) {
return;
}
if (s.name === "Array") {
// we should process type argument instead
return this.processType(type.typeArguments[0]);
}
else {
for (var _i = 0, _a = s.getDeclarations(); _i < _a.length; _i++) {
var decl = _a[_i];
var sourceFile = decl.getSourceFile();
if (sourceFile === this.protocolFile || path.basename(sourceFile.fileName) === "lib.d.ts") {
return;
}
// splice declaration in final d.ts file
var text = decl.getFullText();
this.text += text + "\n";
// recursively pull all dependencies into result dts file
this.visitTypeNodes(decl);
}
}
};
DeclarationsWalker.prototype.visitTypeNodes = function (node) {
var _this = this;
if (node.parent) {
switch (node.parent.kind) {
case ts.SyntaxKind.VariableDeclaration:
case ts.SyntaxKind.MethodDeclaration:
case ts.SyntaxKind.MethodSignature:
case ts.SyntaxKind.PropertyDeclaration:
case ts.SyntaxKind.PropertySignature:
case ts.SyntaxKind.Parameter:
case ts.SyntaxKind.IndexSignature:
if ((node.parent.type) === node) {
var type = this.typeChecker.getTypeAtLocation(node);
if (type && !(type.flags & ts.TypeFlags.TypeParameter)) {
this.processType(type);
}
}
break;
}
}
ts.forEachChild(node, function (n) { return _this.visitTypeNodes(n); });
};
return DeclarationsWalker;
}());
function generateProtocolFile(protocolTs, typeScriptServicesDts) {
var options = { target: ts.ScriptTarget.ES5, declaration: true, noResolve: true, types: [], stripInternal: true };
/**
* 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
* @return text of protocol.d.t.s
*/
function getInitialDtsFileForProtocol() {
var program = ts.createProgram([protocolTs, typeScriptServicesDts], options);
var protocolDts;
program.emit(program.getSourceFile(protocolTs), function (file, content) {
if (endsWith(file, ".d.ts")) {
protocolDts = content;
}
});
if (protocolDts === undefined) {
throw new Error("Declaration file for protocol.ts is not generated");
}
return protocolDts;
}
var protocolFileName = "protocol.d.ts";
/**
* 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
*/
function getProgramWithProtocolText(protocolDts, includeTypeScriptServices) {
var host = ts.createCompilerHost(options);
var originalGetSourceFile = host.getSourceFile;
host.getSourceFile = function (fileName) {
if (fileName === protocolFileName) {
return ts.createSourceFile(fileName, protocolDts, options.target);
}
return originalGetSourceFile.apply(host, [fileName]);
};
var rootFiles = includeTypeScriptServices ? [protocolFileName, typeScriptServicesDts] : [protocolFileName];
return ts.createProgram(rootFiles, options, host);
}
var protocolDts = getInitialDtsFileForProtocol();
var program = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ true);
var protocolFile = program.getSourceFile("protocol.d.ts");
var extraDeclarations = DeclarationsWalker.getExtraDeclarations(program.getTypeChecker(), protocolFile);
if (extraDeclarations) {
protocolDts += extraDeclarations;
}
// do sanity check and try to compile generated text as standalone program
var sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false);
var diagnostics = program.getSyntacticDiagnostics().concat(program.getSemanticDiagnostics(), program.getGlobalDiagnostics());
if (diagnostics.length) {
var flattenedDiagnostics = diagnostics.map(function (d) { return ts.flattenDiagnosticMessageText(d.messageText, "\n"); }).join("\n");
throw new Error("Unexpected errors during sanity check: " + flattenedDiagnostics);
}
return protocolDts;
}
if (process.argv.length < 5) {
console.log("Expected 3 arguments: path to 'protocol.ts', path to 'typescriptservices.d.ts' and path to output file");
process.exit(1);
}
var protocolTs = process.argv[2];
var typeScriptServicesDts = process.argv[3];
var outputFile = process.argv[4];
var generatedProtocolDts = generateProtocolFile(protocolTs, typeScriptServicesDts);
ts.sys.writeFile(outputFile, generatedProtocolDts);
//# sourceMappingURL=file:///C:/repo/TypeScript/scripts/buildProtocol.js.map