@jpoly1219/context-extractor 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,542 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.TypeScriptDriver = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ const child_process_1 = require("child_process");
30
+ const typescript_type_checker_1 = require("./typescript-type-checker");
31
+ const utils_1 = require("./utils");
32
+ class TypeScriptDriver {
33
+ constructor() {
34
+ this.typeChecker = new typescript_type_checker_1.TypeScriptTypeChecker();
35
+ }
36
+ async init(lspClient, sketchPath) {
37
+ const capabilities = {
38
+ 'textDocument': {
39
+ 'codeAction': { 'dynamicRegistration': true },
40
+ 'codeLens': { 'dynamicRegistration': true },
41
+ 'colorProvider': { 'dynamicRegistration': true },
42
+ 'completion': {
43
+ 'completionItem': {
44
+ 'commitCharactersSupport': true,
45
+ 'documentationFormat': ['markdown', 'plaintext'],
46
+ 'snippetSupport': true
47
+ },
48
+ 'completionItemKind': {
49
+ 'valueSet': [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]
50
+ },
51
+ 'contextSupport': true,
52
+ 'dynamicRegistration': true
53
+ },
54
+ 'definition': { 'dynamicRegistration': true },
55
+ 'documentHighlight': { 'dynamicRegistration': true },
56
+ 'documentLink': { 'dynamicRegistration': true },
57
+ 'documentSymbol': {
58
+ 'dynamicRegistration': true,
59
+ 'symbolKind': {
60
+ 'valueSet': [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]
61
+ }
62
+ },
63
+ 'formatting': { 'dynamicRegistration': true },
64
+ 'hover': {
65
+ 'contentFormat': ['markdown', 'plaintext'],
66
+ 'dynamicRegistration': true
67
+ },
68
+ 'implementation': { 'dynamicRegistration': true },
69
+ // 'inlayhint': { 'dynamicRegistration': true },
70
+ 'onTypeFormatting': { 'dynamicRegistration': true },
71
+ 'publishDiagnostics': { 'relatedInformation': true },
72
+ 'rangeFormatting': { 'dynamicRegistration': true },
73
+ 'references': { 'dynamicRegistration': true },
74
+ 'rename': { 'dynamicRegistration': true },
75
+ 'signatureHelp': {
76
+ 'dynamicRegistration': true,
77
+ 'signatureInformation': { 'documentationFormat': ['markdown', 'plaintext'] }
78
+ },
79
+ 'synchronization': {
80
+ 'didSave': true,
81
+ 'dynamicRegistration': true,
82
+ 'willSave': true,
83
+ 'willSaveWaitUntil': true
84
+ },
85
+ 'typeDefinition': { 'dynamicRegistration': true, 'linkSupport': true },
86
+ // 'typeHierarchy': { 'dynamicRegistration': true }
87
+ },
88
+ 'workspace': {
89
+ 'applyEdit': true,
90
+ 'configuration': true,
91
+ 'didChangeConfiguration': { 'dynamicRegistration': true },
92
+ 'didChangeWatchedFiles': { 'dynamicRegistration': true },
93
+ 'executeCommand': { 'dynamicRegistration': true },
94
+ 'symbol': {
95
+ 'dynamicRegistration': true,
96
+ 'symbolKind': {
97
+ 'valueSet': [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]
98
+ }
99
+ }, 'workspaceEdit': { 'documentChanges': true },
100
+ 'workspaceFolders': true
101
+ },
102
+ 'general': {
103
+ 'positionEncodings': ['utf-8']
104
+ },
105
+ };
106
+ const rootPath = path.dirname(sketchPath);
107
+ const rootUri = `file://${rootPath}`;
108
+ const workspaceFolders = [{ 'name': 'context-extractor', 'uri': rootUri }];
109
+ await lspClient.initialize({
110
+ processId: process.pid,
111
+ capabilities: capabilities,
112
+ trace: 'off',
113
+ rootUri: null,
114
+ workspaceFolders: workspaceFolders,
115
+ initializationOptions: {
116
+ preferences: {
117
+ includeInlayVariableTypeHints: true
118
+ }
119
+ }
120
+ });
121
+ }
122
+ async getHoleContext(lspClient, sketchFilePath) {
123
+ // For TypeScript programs, we need to inject the hole function before getting its context.
124
+ // NOTE: this can be abstracted to its own method?
125
+ const sketchDir = path.dirname(sketchFilePath);
126
+ const injectedSketchFilePath = path.join(sketchDir, "injected_sketch.ts");
127
+ const sketchFileContent = fs.readFileSync(sketchFilePath, "utf8");
128
+ const injectedSketchFileContent = `declare function _<T>(): T\n${sketchFileContent}`;
129
+ fs.writeFileSync(injectedSketchFilePath, injectedSketchFileContent);
130
+ // Sync client and server by notifying that the client has opened all the files inside the target directory.
131
+ fs.readdirSync(sketchDir).map(fileName => {
132
+ if (fs.lstatSync(path.join(sketchDir, fileName)).isFile()) {
133
+ lspClient.didOpen({
134
+ textDocument: {
135
+ uri: `file://${sketchDir}/${fileName}`,
136
+ languageId: "typescript",
137
+ text: fs.readFileSync(`${sketchDir}/${fileName}`).toString("ascii"),
138
+ version: 1
139
+ }
140
+ });
141
+ }
142
+ });
143
+ // Get hole context.
144
+ const holePattern = /_\(\)/;
145
+ const firstPatternIndex = injectedSketchFileContent.search(holePattern);
146
+ const linePosition = (injectedSketchFileContent.substring(0, firstPatternIndex).match(/\n/g)).length;
147
+ const characterPosition = firstPatternIndex - injectedSketchFileContent.split("\n", linePosition).join("\n").length - 1;
148
+ const holeHoverResult = await lspClient.hover({
149
+ textDocument: {
150
+ uri: injectedSketchFilePath
151
+ },
152
+ position: {
153
+ character: characterPosition,
154
+ line: linePosition
155
+ }
156
+ });
157
+ const formattedHoverResult = holeHoverResult.contents.value.split("\n").reduce((acc, curr) => {
158
+ if (curr != "" && curr != "```typescript" && curr != "```") {
159
+ return acc + curr;
160
+ }
161
+ else {
162
+ return acc;
163
+ }
164
+ }, "");
165
+ // function _<(a: Apple, c: Cherry, b: Banana) => Cherry > (): (a: Apple, c: Cherry, b: Banana) => Cherry
166
+ const holeFunctionPattern = /(function _)(\<.+\>)(\(\): )(.+)/;
167
+ const match = formattedHoverResult.match(holeFunctionPattern);
168
+ const functionName = "_()";
169
+ const functionTypeSpan = match[4];
170
+ // Clean up and inject the true hole function without the generic type signature.
171
+ // NOTE: this can be abstracted to its own method?
172
+ const trueHoleFunction = `declare function _(): ${functionTypeSpan}`;
173
+ const trueInjectedSketchFileContent = `${trueHoleFunction}\n${sketchFileContent}`;
174
+ fs.writeFileSync(injectedSketchFilePath, trueInjectedSketchFileContent);
175
+ lspClient.didChange({
176
+ textDocument: {
177
+ uri: `file://${injectedSketchFilePath}`,
178
+ version: 2
179
+ },
180
+ contentChanges: [{
181
+ text: trueInjectedSketchFileContent
182
+ }]
183
+ });
184
+ const sketchSymbol = await lspClient.documentSymbol({
185
+ textDocument: {
186
+ uri: `file://${injectedSketchFilePath}`,
187
+ }
188
+ });
189
+ return {
190
+ fullHoverResult: formattedHoverResult,
191
+ functionName: functionName,
192
+ functionTypeSpan: functionTypeSpan,
193
+ linePosition: linePosition,
194
+ characterPosition: characterPosition,
195
+ holeTypeDefLinePos: 0,
196
+ holeTypeDefCharPos: "declare function _(): ".length,
197
+ // range: { start: { line: 0, character: 0 }, end: { line: 0, character: 52 } }
198
+ range: sketchSymbol[0].location.range,
199
+ source: `file://${injectedSketchFilePath}`
200
+ };
201
+ }
202
+ async extractRelevantTypes(lspClient, fullHoverResult, typeName, startLine, endLine, foundSoFar, // identifier -> [full hover result, source]
203
+ currentFile) {
204
+ if (!foundSoFar.has(typeName)) {
205
+ foundSoFar.set(typeName, { typeSpan: fullHoverResult, sourceFile: currentFile.slice(7) });
206
+ // outputFile.write(`${fullHoverResult};\n`);
207
+ const content = fs.readFileSync(currentFile.slice(7), "utf8");
208
+ for (let linePos = startLine; linePos <= endLine; ++linePos) {
209
+ const numOfCharsInLine = parseInt((0, child_process_1.execSync)(`wc -m <<< "${content.split("\n")[linePos]}"`, { shell: "/bin/bash" }).toString());
210
+ for (let charPos = 0; charPos < numOfCharsInLine; ++charPos) {
211
+ try {
212
+ const typeDefinitionResult = await lspClient.typeDefinition({
213
+ textDocument: {
214
+ uri: currentFile
215
+ },
216
+ position: {
217
+ character: charPos,
218
+ line: linePos
219
+ }
220
+ });
221
+ if (typeDefinitionResult && typeDefinitionResult instanceof Array && typeDefinitionResult.length != 0) {
222
+ // Use documentSymbol instead of hover.
223
+ // This prevents type alias "squashing" done by tsserver.
224
+ // This also allows for grabbing the entire definition range and not just the symbol range.
225
+ // PERF: feels like this could be memoized to improve performance.
226
+ const documentSymbolResult = await lspClient.documentSymbol({
227
+ textDocument: {
228
+ uri: typeDefinitionResult[0].uri
229
+ }
230
+ });
231
+ // grab if the line number of typeDefinitionResult and documentSymbolResult matches
232
+ const dsMap = documentSymbolResult.reduce((m, obj) => {
233
+ m.set(obj.location.range.start.line, obj.location.range);
234
+ return m;
235
+ }, new Map());
236
+ const matchingSymbolRange = dsMap.get(typeDefinitionResult[0].range.start.line);
237
+ if (matchingSymbolRange) {
238
+ const snippetInRange = (0, utils_1.extractSnippet)(fs.readFileSync(typeDefinitionResult[0].uri.slice(7)).toString("utf8"), matchingSymbolRange.start, matchingSymbolRange.end);
239
+ // TODO: this can potentially be its own method. the driver would require some way to get type context.
240
+ // potentially, this type checker can be its own class.
241
+ const identifier = this.typeChecker.getIdentifierFromDecl(snippetInRange);
242
+ await this.extractRelevantTypes(lspClient, snippetInRange, identifier, matchingSymbolRange.start.line, matchingSymbolRange.end.line, foundSoFar, typeDefinitionResult[0].uri);
243
+ }
244
+ }
245
+ }
246
+ catch (err) {
247
+ console.log(`${err}`);
248
+ }
249
+ }
250
+ }
251
+ }
252
+ return foundSoFar;
253
+ }
254
+ async extractRelevantHeaders(_, sources, relevantTypes, holeType) {
255
+ const relevantContext = new Set();
256
+ const targetTypes = this.generateTargetTypes(relevantTypes, holeType);
257
+ // only consider lines that start with let or const
258
+ for (const source of sources) {
259
+ const sourceContent = fs.readFileSync(source).toString("utf8");
260
+ const filteredLines = sourceContent.split("\n").filter((line) => {
261
+ return line.slice(0, 3) === "let" || line.slice(0, 5) === "const";
262
+ });
263
+ // check for relationship between each line and relevant types
264
+ filteredLines.forEach(line => {
265
+ // TODO: Use the compiler API to split this.
266
+ const splittedLine = line.split(" = ")[0];
267
+ const typeSpanPattern = /(^[^:]*: )(.+)/;
268
+ const regexMatch = splittedLine.match(typeSpanPattern);
269
+ if (regexMatch) {
270
+ const returnTypeSpan = regexMatch[2];
271
+ if (!this.typeChecker.isPrimitive(returnTypeSpan.split(" => ")[1])) {
272
+ this.extractRelevantHeadersHelper(returnTypeSpan, targetTypes, relevantTypes, relevantContext, splittedLine, source);
273
+ }
274
+ }
275
+ });
276
+ }
277
+ return relevantContext;
278
+ }
279
+ generateTargetTypes(relevantTypes, holeType) {
280
+ const targetTypes = new Set();
281
+ targetTypes.add(holeType);
282
+ this.generateTargetTypesHelper(relevantTypes, holeType, targetTypes);
283
+ return targetTypes;
284
+ }
285
+ // generateTargetTypesHelper(
286
+ // relevantTypes: Map<string, TypeSpanAndSourceFile>,
287
+ // currType: string,
288
+ // targetTypes: Set<string>
289
+ // ) {
290
+ // // console.log("===Helper===")
291
+ // if (this.typeChecker.isFunction(currType)) {
292
+ // const functionPattern = /(\(.+\))( => )(.+)(;*)/;
293
+ // const rettype = currType.match(functionPattern)![3];
294
+ // targetTypes.add(rettype);
295
+ // this.generateTargetTypesHelper(relevantTypes, rettype, targetTypes);
296
+ //
297
+ // } else if (this.typeChecker.isTuple(currType)) {
298
+ // const elements = this.typeChecker.parseTypeArrayString(currType)
299
+ //
300
+ // elements.forEach(element => {
301
+ // targetTypes.add(element)
302
+ // this.generateTargetTypesHelper(relevantTypes, element, targetTypes);
303
+ // });
304
+ // } else {
305
+ // if (relevantTypes.has(currType)) {
306
+ // const definition = relevantTypes.get(currType)!.typeSpan.split(" = ")[1];
307
+ // this.generateTargetTypesHelper(relevantTypes, definition, targetTypes);
308
+ // }
309
+ // }
310
+ // }
311
+ generateTargetTypesHelper(relevantTypes, currType, targetTypes) {
312
+ // Run analysis on currType.
313
+ const typeAnalysisResult = this.typeChecker.analyzeTypeString(currType);
314
+ // Match on its kind.
315
+ if (this.typeChecker.isFunction2(typeAnalysisResult)) {
316
+ const rettype = typeAnalysisResult.returnType;
317
+ targetTypes.add(rettype.text);
318
+ this.generateTargetTypesHelper(relevantTypes, rettype.text, targetTypes);
319
+ }
320
+ else if (this.typeChecker.isTuple2(typeAnalysisResult)) {
321
+ typeAnalysisResult.constituents.forEach(constituent => {
322
+ targetTypes.add(constituent.text);
323
+ this.generateTargetTypesHelper(relevantTypes, constituent.text, targetTypes);
324
+ });
325
+ }
326
+ else {
327
+ if (relevantTypes.has(currType)) {
328
+ const definition = relevantTypes.get(currType).typeSpan.split(" = ")[1];
329
+ this.generateTargetTypesHelper(relevantTypes, definition, targetTypes);
330
+ }
331
+ }
332
+ }
333
+ // resursive helper for extractRelevantContext
334
+ // checks for nested type equivalence
335
+ // extractRelevantHeadersHelper(typeSpan: string, targetTypes: Set<string>, relevantTypes: Map<string, TypeSpanAndSourceFile>, relevantContext: Set<TypeSpanAndSourceFile>, line: string, source: string) {
336
+ // // NOTE: BUGFIX
337
+ // // console.log(`typeSpan: ${typeSpan}`)
338
+ // // console.log(`targetTypes: ${targetTypes}`)
339
+ // targetTypes.forEach(typ => {
340
+ // if (this.isTypeEquivalent(typeSpan, typ, relevantTypes)) {
341
+ // relevantContext.add({ typeSpan: line, sourceFile: source });
342
+ // }
343
+ //
344
+ // if (this.typeChecker.isFunction(typeSpan)) {
345
+ // const functionPattern = /(\(.+\))( => )(.+)/;
346
+ // const rettype = typeSpan.match(functionPattern)![3];
347
+ //
348
+ // this.extractRelevantHeadersHelper(rettype, targetTypes, relevantTypes, relevantContext, line, source);
349
+ //
350
+ // } else if (this.typeChecker.isTuple(typeSpan)) {
351
+ // const elements = this.typeChecker.parseTypeArrayString(typeSpan)
352
+ // // const elements = typeSpan.slice(1, typeSpan.length - 1).split(", ");
353
+ //
354
+ // elements.forEach(element => {
355
+ // this.extractRelevantHeadersHelper(element, targetTypes, relevantTypes, relevantContext, line, source);
356
+ // });
357
+ //
358
+ // }
359
+ // });
360
+ // }
361
+ extractRelevantHeadersHelper(typeSpan, targetTypes, relevantTypes, relevantContext, line, source) {
362
+ const typeAnalysisResult = this.typeChecker.analyzeTypeString(typeSpan);
363
+ targetTypes.forEach(typ => {
364
+ if (this.isTypeEquivalent(typeSpan, typ, relevantTypes)) {
365
+ relevantContext.add({ typeSpan: line, sourceFile: source });
366
+ }
367
+ if (this.typeChecker.isFunction2(typeAnalysisResult)) {
368
+ const rettype = typeAnalysisResult.returnType;
369
+ this.extractRelevantHeadersHelper(rettype.text, targetTypes, relevantTypes, relevantContext, line, source);
370
+ }
371
+ else if (this.typeChecker.isTuple2(typeAnalysisResult)) {
372
+ typeAnalysisResult.constituents.forEach(constituent => {
373
+ this.extractRelevantHeadersHelper(constituent.text, targetTypes, relevantTypes, relevantContext, line, source);
374
+ });
375
+ }
376
+ });
377
+ }
378
+ // two types are equivalent if they have the same normal forms
379
+ isTypeEquivalent(t1, t2, relevantTypes) {
380
+ // NOTE: BUGFIX
381
+ // console.log(`isTypeEquivalent: ${t1}, ${t2}`)
382
+ // console.log(t1 == undefined)
383
+ // console.log(t2 == undefined)
384
+ const normT1 = this.normalize(t1, relevantTypes);
385
+ const normT2 = this.normalize(t2, relevantTypes);
386
+ return normT1 === normT2;
387
+ }
388
+ // return the normal form given a type span and a set of relevant types
389
+ // TODO: replace type checking with information from the AST?
390
+ normalize(typeSpan, relevantTypes) {
391
+ // NOTE: BUGFIX
392
+ // console.log(`normalize: ${typeSpan}`)
393
+ if (typeSpan.slice(typeSpan.length - 2) == " =") {
394
+ typeSpan = typeSpan.slice(typeSpan.length - 2);
395
+ }
396
+ let normalForm = "";
397
+ // pattern matching for typeSpan
398
+ if (this.typeChecker.isPrimitive(typeSpan)) {
399
+ return typeSpan;
400
+ }
401
+ else if (this.typeChecker.isObject(typeSpan)) {
402
+ // console.log(`isObject: ${typeSpan}`)
403
+ const elements = typeSpan.slice(1, typeSpan.length - 2).split(";");
404
+ normalForm += "{";
405
+ elements.forEach(element => {
406
+ if (element !== "") {
407
+ const kv = element.split(": ");
408
+ normalForm += kv[0].slice(1, kv[0].length), ": ", this.normalize(kv[1], relevantTypes);
409
+ normalForm += "; ";
410
+ }
411
+ });
412
+ normalForm += "}";
413
+ return normalForm;
414
+ }
415
+ else if (this.typeChecker.isTuple(typeSpan)) {
416
+ // console.log(`isTuple: ${typeSpan}`)
417
+ // const elements = typeSpan.slice(1, typeSpan.length - 1).split(", ");
418
+ const elements = this.typeChecker.parseTypeArrayString(typeSpan);
419
+ normalForm += "[";
420
+ elements.forEach((element, i) => {
421
+ normalForm += this.normalize(element, relevantTypes);
422
+ if (i < elements.length - 1) {
423
+ normalForm += ", ";
424
+ }
425
+ });
426
+ normalForm += "]";
427
+ return normalForm;
428
+ }
429
+ else if (this.typeChecker.isUnion(typeSpan)) {
430
+ // console.log(`isUnion: ${typeSpan}`)
431
+ const elements = typeSpan.split(" | ");
432
+ elements.forEach((element, i) => {
433
+ normalForm += "(";
434
+ normalForm += this.normalize(element, relevantTypes);
435
+ normalForm += ")";
436
+ if (i < elements.length - 1) {
437
+ normalForm += " | ";
438
+ }
439
+ });
440
+ return normalForm;
441
+ }
442
+ else if (this.typeChecker.isArray(typeSpan)) {
443
+ // console.log(`isArray: ${typeSpan}`)
444
+ const element = typeSpan.split("[]")[0];
445
+ normalForm += this.normalize(element, relevantTypes);
446
+ normalForm += "[]";
447
+ return normalForm;
448
+ }
449
+ else if (this.typeChecker.isTypeAlias(typeSpan)) {
450
+ const typ = relevantTypes.get(typeSpan).typeSpan.split(" = ")[1];
451
+ if (typ === undefined) {
452
+ return typeSpan;
453
+ }
454
+ normalForm += this.normalize(typ, relevantTypes);
455
+ return normalForm;
456
+ }
457
+ else {
458
+ // console.log(`else: ${typeSpan}`)
459
+ return typeSpan;
460
+ }
461
+ }
462
+ normalize2(typeSpan, relevantTypes) {
463
+ // NOTE: BUGFIX
464
+ // console.log(`normalize: ${typeSpan}`)
465
+ if (typeSpan.slice(typeSpan.length - 2) == " =") {
466
+ typeSpan = typeSpan.slice(typeSpan.length - 2);
467
+ }
468
+ let normalForm = "";
469
+ const analysisResult = this.typeChecker.analyzeTypeString(typeSpan);
470
+ // pattern matching for typeSpan
471
+ // if (this.typeChecker.isPrimitive(typeSpan)) {
472
+ if (this.typeChecker.isPrimitive2(analysisResult)) {
473
+ return typeSpan;
474
+ // } else if (this.typeChecker.isObject(typeSpan)) {
475
+ }
476
+ else if (this.typeChecker.isObject2(analysisResult)) {
477
+ // console.log(`isObject: ${typeSpan}`)
478
+ const elements = typeSpan.slice(1, typeSpan.length - 2).split(";");
479
+ normalForm += "{";
480
+ elements.forEach(element => {
481
+ if (element !== "") {
482
+ const kv = element.split(": ");
483
+ normalForm += kv[0].slice(1, kv[0].length), ": ", this.normalize(kv[1], relevantTypes);
484
+ normalForm += "; ";
485
+ }
486
+ });
487
+ normalForm += "}";
488
+ return normalForm;
489
+ // } else if (this.typeChecker.isTuple(typeSpan)) {
490
+ }
491
+ else if (this.typeChecker.isTuple2(analysisResult)) {
492
+ // console.log(`isTuple: ${typeSpan}`)
493
+ // const elements = typeSpan.slice(1, typeSpan.length - 1).split(", ");
494
+ const elements = this.typeChecker.parseTypeArrayString(typeSpan);
495
+ normalForm += "[";
496
+ elements.forEach((element, i) => {
497
+ normalForm += this.normalize(element, relevantTypes);
498
+ if (i < elements.length - 1) {
499
+ normalForm += ", ";
500
+ }
501
+ });
502
+ normalForm += "]";
503
+ return normalForm;
504
+ // } else if (this.typeChecker.isUnion(typeSpan)) {
505
+ }
506
+ else if (this.typeChecker.isUnion2(analysisResult)) {
507
+ // console.log(`isUnion: ${typeSpan}`)
508
+ const elements = typeSpan.split(" | ");
509
+ elements.forEach((element, i) => {
510
+ normalForm += "(";
511
+ normalForm += this.normalize(element, relevantTypes);
512
+ normalForm += ")";
513
+ if (i < elements.length - 1) {
514
+ normalForm += " | ";
515
+ }
516
+ });
517
+ return normalForm;
518
+ // } else if (this.typeChecker.isArray(typeSpan)) {
519
+ }
520
+ else if (this.typeChecker.isArray2(analysisResult)) {
521
+ // console.log(`isArray: ${typeSpan}`)
522
+ const element = typeSpan.split("[]")[0];
523
+ normalForm += this.normalize(element, relevantTypes);
524
+ normalForm += "[]";
525
+ return normalForm;
526
+ // } else if (this.typeChecker.isTypeAlias(typeSpan)) {
527
+ }
528
+ else if (this.typeChecker.isTypeAlias2(analysisResult)) {
529
+ const typ = relevantTypes.get(typeSpan).typeSpan.split(" = ")[1];
530
+ if (typ === undefined) {
531
+ return typeSpan;
532
+ }
533
+ normalForm += this.normalize(typ, relevantTypes);
534
+ return normalForm;
535
+ }
536
+ else {
537
+ // console.log(`else: ${typeSpan}`)
538
+ return typeSpan;
539
+ }
540
+ }
541
+ }
542
+ exports.TypeScriptDriver = TypeScriptDriver;
@@ -0,0 +1,64 @@
1
+ import * as ts from 'typescript';
2
+ import { TypeChecker, TypeAnalysis } from "./types";
3
+ export declare class TypeScriptTypeChecker implements TypeChecker {
4
+ getIdentifierFromDecl(typeDecl: string): string;
5
+ getTypeContextFromDecl(typeDecl: string): {
6
+ identifier: string;
7
+ span: string;
8
+ } | null;
9
+ checkPrimitive(typeDecl: string): {
10
+ identifier: string;
11
+ span: string;
12
+ interestingIndex: number;
13
+ } | null;
14
+ checkImports(typeDecl: string): {
15
+ identifier: string;
16
+ span: string;
17
+ interestingIndex: number;
18
+ } | null;
19
+ checkModule(typeDecl: string): {
20
+ identifier: string;
21
+ span: string;
22
+ interestingIndex: number;
23
+ } | null;
24
+ checkObject(typeDecl: string): {
25
+ identifier: string;
26
+ span: string;
27
+ interestingIndex: number;
28
+ } | null;
29
+ checkUnion(typeDecl: string): {
30
+ identifier: string;
31
+ span: string;
32
+ interestingIndex: number;
33
+ } | null;
34
+ checkFunction(typeDecl: string): {
35
+ identifier: string;
36
+ span: string;
37
+ interestingIndex: number;
38
+ } | null;
39
+ checkHole(typeDecl: string): {
40
+ identifier: string;
41
+ span: string;
42
+ } | null;
43
+ checkParameter(typeDecl: string): null;
44
+ isTuple(typeSpan: string): boolean;
45
+ isUnion(typeSpan: string): boolean;
46
+ isArray(typeSpan: string): boolean;
47
+ isObject(typeSpan: string): boolean;
48
+ isFunction(typeSpan: string): boolean;
49
+ isPrimitive(typeSpan: string): boolean;
50
+ isTypeAlias(typeSpan: string): boolean;
51
+ escapeQuotes(typeSpan: string): string;
52
+ parseTypeArrayString(typeStr: string): string[];
53
+ handleMembers(members: ts.NodeArray<ts.TypeElement> | ts.NodeArray<ts.ClassElement>, checker: ts.TypeChecker): TypeAnalysis[];
54
+ analyzeTypeNode(typeNode: ts.TypeNode, checker: ts.TypeChecker): TypeAnalysis;
55
+ analyzeTypeString(typeString: string, program?: ts.Program): TypeAnalysis;
56
+ createProgramFromSource(content: string): ts.Program;
57
+ isPrimitive2(typeAnalysisResult: TypeAnalysis): RegExpMatchArray | null;
58
+ isFunction2(typeAnalysisResult: TypeAnalysis): boolean;
59
+ isTuple2(typeAnalysisResult: TypeAnalysis): boolean;
60
+ isObject2(typeAnalysisResult: TypeAnalysis): boolean;
61
+ isUnion2(typeAnalysisResult: TypeAnalysis): boolean;
62
+ isArray2(typeAnalysisResult: TypeAnalysis): boolean;
63
+ isTypeAlias2(typeAnalysisResult: TypeAnalysis): boolean;
64
+ }