Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/build/lib/monaco-api.ts
3520 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import fs from 'fs';
7
import type * as ts from 'typescript';
8
import path from 'path';
9
import fancyLog from 'fancy-log';
10
import ansiColors from 'ansi-colors';
11
12
const dtsv = '3';
13
14
const tsfmt = require('../../tsfmt.json');
15
16
const SRC = path.join(__dirname, '../../src');
17
export const RECIPE_PATH = path.join(__dirname, '../monaco/monaco.d.ts.recipe');
18
const DECLARATION_PATH = path.join(__dirname, '../../src/vs/monaco.d.ts');
19
20
function logErr(message: any, ...rest: any[]): void {
21
fancyLog(ansiColors.yellow(`[monaco.d.ts]`), message, ...rest);
22
}
23
24
type SourceFileGetter = (moduleId: string) => ts.SourceFile | null;
25
26
type TSTopLevelDeclaration = ts.InterfaceDeclaration | ts.EnumDeclaration | ts.ClassDeclaration | ts.TypeAliasDeclaration | ts.FunctionDeclaration | ts.ModuleDeclaration;
27
type TSTopLevelDeclare = TSTopLevelDeclaration | ts.VariableStatement;
28
29
function isDeclaration(ts: typeof import('typescript'), a: TSTopLevelDeclare): a is TSTopLevelDeclaration {
30
return (
31
a.kind === ts.SyntaxKind.InterfaceDeclaration
32
|| a.kind === ts.SyntaxKind.EnumDeclaration
33
|| a.kind === ts.SyntaxKind.ClassDeclaration
34
|| a.kind === ts.SyntaxKind.TypeAliasDeclaration
35
|| a.kind === ts.SyntaxKind.FunctionDeclaration
36
|| a.kind === ts.SyntaxKind.ModuleDeclaration
37
);
38
}
39
40
function visitTopLevelDeclarations(ts: typeof import('typescript'), sourceFile: ts.SourceFile, visitor: (node: TSTopLevelDeclare) => boolean): void {
41
let stop = false;
42
43
const visit = (node: ts.Node): void => {
44
if (stop) {
45
return;
46
}
47
48
switch (node.kind) {
49
case ts.SyntaxKind.InterfaceDeclaration:
50
case ts.SyntaxKind.EnumDeclaration:
51
case ts.SyntaxKind.ClassDeclaration:
52
case ts.SyntaxKind.VariableStatement:
53
case ts.SyntaxKind.TypeAliasDeclaration:
54
case ts.SyntaxKind.FunctionDeclaration:
55
case ts.SyntaxKind.ModuleDeclaration:
56
stop = visitor(<TSTopLevelDeclare>node);
57
}
58
59
if (stop) {
60
return;
61
}
62
ts.forEachChild(node, visit);
63
};
64
65
visit(sourceFile);
66
}
67
68
69
function getAllTopLevelDeclarations(ts: typeof import('typescript'), sourceFile: ts.SourceFile): TSTopLevelDeclare[] {
70
const all: TSTopLevelDeclare[] = [];
71
visitTopLevelDeclarations(ts, sourceFile, (node) => {
72
if (node.kind === ts.SyntaxKind.InterfaceDeclaration || node.kind === ts.SyntaxKind.ClassDeclaration || node.kind === ts.SyntaxKind.ModuleDeclaration) {
73
const interfaceDeclaration = <ts.InterfaceDeclaration>node;
74
const triviaStart = interfaceDeclaration.pos;
75
const triviaEnd = interfaceDeclaration.name.pos;
76
const triviaText = getNodeText(sourceFile, { pos: triviaStart, end: triviaEnd });
77
78
if (triviaText.indexOf('@internal') === -1) {
79
all.push(node);
80
}
81
} else {
82
const nodeText = getNodeText(sourceFile, node);
83
if (nodeText.indexOf('@internal') === -1) {
84
all.push(node);
85
}
86
}
87
return false /*continue*/;
88
});
89
return all;
90
}
91
92
93
function getTopLevelDeclaration(ts: typeof import('typescript'), sourceFile: ts.SourceFile, typeName: string): TSTopLevelDeclare | null {
94
let result: TSTopLevelDeclare | null = null;
95
visitTopLevelDeclarations(ts, sourceFile, (node) => {
96
if (isDeclaration(ts, node) && node.name) {
97
if (node.name.text === typeName) {
98
result = node;
99
return true /*stop*/;
100
}
101
return false /*continue*/;
102
}
103
// node is ts.VariableStatement
104
if (getNodeText(sourceFile, node).indexOf(typeName) >= 0) {
105
result = node;
106
return true /*stop*/;
107
}
108
return false /*continue*/;
109
});
110
return result;
111
}
112
113
114
function getNodeText(sourceFile: ts.SourceFile, node: { pos: number; end: number }): string {
115
return sourceFile.getFullText().substring(node.pos, node.end);
116
}
117
118
function hasModifier(modifiers: readonly ts.ModifierLike[] | undefined, kind: ts.SyntaxKind): boolean {
119
if (modifiers) {
120
for (let i = 0; i < modifiers.length; i++) {
121
const mod = modifiers[i];
122
if (mod.kind === kind) {
123
return true;
124
}
125
}
126
}
127
return false;
128
}
129
130
function isStatic(ts: typeof import('typescript'), member: ts.ClassElement | ts.TypeElement): boolean {
131
if (ts.canHaveModifiers(member)) {
132
return hasModifier(ts.getModifiers(member), ts.SyntaxKind.StaticKeyword);
133
}
134
return false;
135
}
136
137
function isDefaultExport(ts: typeof import('typescript'), declaration: ts.InterfaceDeclaration | ts.ClassDeclaration): boolean {
138
return (
139
hasModifier(declaration.modifiers, ts.SyntaxKind.DefaultKeyword)
140
&& hasModifier(declaration.modifiers, ts.SyntaxKind.ExportKeyword)
141
);
142
}
143
144
function getMassagedTopLevelDeclarationText(ts: typeof import('typescript'), sourceFile: ts.SourceFile, declaration: TSTopLevelDeclare, importName: string, usage: string[], enums: IEnumEntry[]): string {
145
let result = getNodeText(sourceFile, declaration);
146
if (declaration.kind === ts.SyntaxKind.InterfaceDeclaration || declaration.kind === ts.SyntaxKind.ClassDeclaration) {
147
const interfaceDeclaration = <ts.InterfaceDeclaration | ts.ClassDeclaration>declaration;
148
149
const staticTypeName = (
150
isDefaultExport(ts, interfaceDeclaration)
151
? `${importName}.default`
152
: `${importName}.${declaration.name!.text}`
153
);
154
155
let instanceTypeName = staticTypeName;
156
const typeParametersCnt = (interfaceDeclaration.typeParameters ? interfaceDeclaration.typeParameters.length : 0);
157
if (typeParametersCnt > 0) {
158
const arr: string[] = [];
159
for (let i = 0; i < typeParametersCnt; i++) {
160
arr.push('any');
161
}
162
instanceTypeName = `${instanceTypeName}<${arr.join(',')}>`;
163
}
164
165
const members: ts.NodeArray<ts.ClassElement | ts.TypeElement> = interfaceDeclaration.members;
166
members.forEach((member) => {
167
try {
168
const memberText = getNodeText(sourceFile, member);
169
if (memberText.indexOf('@internal') >= 0 || memberText.indexOf('private') >= 0) {
170
result = result.replace(memberText, '');
171
} else {
172
const memberName = (<ts.Identifier | ts.StringLiteral>member.name).text;
173
const memberAccess = (memberName.indexOf('.') >= 0 ? `['${memberName}']` : `.${memberName}`);
174
if (isStatic(ts, member)) {
175
usage.push(`a = ${staticTypeName}${memberAccess};`);
176
} else {
177
usage.push(`a = (<${instanceTypeName}>b)${memberAccess};`);
178
}
179
}
180
} catch (err) {
181
// life..
182
}
183
});
184
}
185
result = result.replace(/export default /g, 'export ');
186
result = result.replace(/export declare /g, 'export ');
187
result = result.replace(/declare /g, '');
188
const lines = result.split(/\r\n|\r|\n/);
189
for (let i = 0; i < lines.length; i++) {
190
if (/\s*\*/.test(lines[i])) {
191
// very likely a comment
192
continue;
193
}
194
lines[i] = lines[i].replace(/"/g, '\'');
195
}
196
result = lines.join('\n');
197
198
if (declaration.kind === ts.SyntaxKind.EnumDeclaration) {
199
result = result.replace(/const enum/, 'enum');
200
enums.push({
201
enumName: declaration.name.getText(sourceFile),
202
text: result
203
});
204
}
205
206
return result;
207
}
208
209
function format(ts: typeof import('typescript'), text: string, endl: string): string {
210
const REALLY_FORMAT = false;
211
212
text = preformat(text, endl);
213
if (!REALLY_FORMAT) {
214
return text;
215
}
216
217
// Parse the source text
218
const sourceFile = ts.createSourceFile('file.ts', text, ts.ScriptTarget.Latest, /*setParentPointers*/ true);
219
220
// Get the formatting edits on the input sources
221
const edits = (<any>ts).formatting.formatDocument(sourceFile, getRuleProvider(tsfmt), tsfmt);
222
223
// Apply the edits on the input code
224
return applyEdits(text, edits);
225
226
function countParensCurly(text: string): number {
227
let cnt = 0;
228
for (let i = 0; i < text.length; i++) {
229
if (text.charAt(i) === '(' || text.charAt(i) === '{') {
230
cnt++;
231
}
232
if (text.charAt(i) === ')' || text.charAt(i) === '}') {
233
cnt--;
234
}
235
}
236
return cnt;
237
}
238
239
function repeatStr(s: string, cnt: number): string {
240
let r = '';
241
for (let i = 0; i < cnt; i++) {
242
r += s;
243
}
244
return r;
245
}
246
247
function preformat(text: string, endl: string): string {
248
const lines = text.split(endl);
249
let inComment = false;
250
let inCommentDeltaIndent = 0;
251
let indent = 0;
252
for (let i = 0; i < lines.length; i++) {
253
let line = lines[i].replace(/\s$/, '');
254
let repeat = false;
255
let lineIndent = 0;
256
do {
257
repeat = false;
258
if (line.substring(0, 4) === ' ') {
259
line = line.substring(4);
260
lineIndent++;
261
repeat = true;
262
}
263
if (line.charAt(0) === '\t') {
264
line = line.substring(1);
265
lineIndent++;
266
repeat = true;
267
}
268
} while (repeat);
269
270
if (line.length === 0) {
271
continue;
272
}
273
274
if (inComment) {
275
if (/\*\//.test(line)) {
276
inComment = false;
277
}
278
lines[i] = repeatStr('\t', lineIndent + inCommentDeltaIndent) + line;
279
continue;
280
}
281
282
if (/\/\*/.test(line)) {
283
inComment = true;
284
inCommentDeltaIndent = indent - lineIndent;
285
lines[i] = repeatStr('\t', indent) + line;
286
continue;
287
}
288
289
const cnt = countParensCurly(line);
290
let shouldUnindentAfter = false;
291
let shouldUnindentBefore = false;
292
if (cnt < 0) {
293
if (/[({]/.test(line)) {
294
shouldUnindentAfter = true;
295
} else {
296
shouldUnindentBefore = true;
297
}
298
} else if (cnt === 0) {
299
shouldUnindentBefore = /^\}/.test(line);
300
}
301
let shouldIndentAfter = false;
302
if (cnt > 0) {
303
shouldIndentAfter = true;
304
} else if (cnt === 0) {
305
shouldIndentAfter = /{$/.test(line);
306
}
307
308
if (shouldUnindentBefore) {
309
indent--;
310
}
311
312
lines[i] = repeatStr('\t', indent) + line;
313
314
if (shouldUnindentAfter) {
315
indent--;
316
}
317
if (shouldIndentAfter) {
318
indent++;
319
}
320
}
321
return lines.join(endl);
322
}
323
324
function getRuleProvider(options: ts.FormatCodeSettings) {
325
// Share this between multiple formatters using the same options.
326
// This represents the bulk of the space the formatter uses.
327
return (ts as any).formatting.getFormatContext(options);
328
}
329
330
function applyEdits(text: string, edits: ts.TextChange[]): string {
331
// Apply edits in reverse on the existing text
332
let result = text;
333
for (let i = edits.length - 1; i >= 0; i--) {
334
const change = edits[i];
335
const head = result.slice(0, change.span.start);
336
const tail = result.slice(change.span.start + change.span.length);
337
result = head + change.newText + tail;
338
}
339
return result;
340
}
341
}
342
343
function createReplacerFromDirectives(directives: [RegExp, string][]): (str: string) => string {
344
return (str: string) => {
345
for (let i = 0; i < directives.length; i++) {
346
str = str.replace(directives[i][0], directives[i][1]);
347
}
348
return str;
349
};
350
}
351
352
function createReplacer(data: string): (str: string) => string {
353
data = data || '';
354
const rawDirectives = data.split(';');
355
const directives: [RegExp, string][] = [];
356
rawDirectives.forEach((rawDirective) => {
357
if (rawDirective.length === 0) {
358
return;
359
}
360
const pieces = rawDirective.split('=>');
361
let findStr = pieces[0];
362
const replaceStr = pieces[1];
363
364
findStr = findStr.replace(/[\-\\\{\}\*\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&');
365
findStr = '\\b' + findStr + '\\b';
366
directives.push([new RegExp(findStr, 'g'), replaceStr]);
367
});
368
369
return createReplacerFromDirectives(directives);
370
}
371
372
interface ITempResult {
373
result: string;
374
usageContent: string;
375
enums: string;
376
}
377
378
interface IEnumEntry {
379
enumName: string;
380
text: string;
381
}
382
383
function generateDeclarationFile(ts: typeof import('typescript'), recipe: string, sourceFileGetter: SourceFileGetter): ITempResult | null {
384
const endl = /\r\n/.test(recipe) ? '\r\n' : '\n';
385
386
const lines = recipe.split(endl);
387
const result: string[] = [];
388
389
let usageCounter = 0;
390
const usageImports: string[] = [];
391
const usage: string[] = [];
392
393
let failed = false;
394
395
usage.push(`var a: any;`);
396
usage.push(`var b: any;`);
397
398
const generateUsageImport = (moduleId: string) => {
399
const importName = 'm' + (++usageCounter);
400
usageImports.push(`import * as ${importName} from './${moduleId.replace(/\.d\.ts$/, '')}';`);
401
return importName;
402
};
403
404
const enums: IEnumEntry[] = [];
405
let version: string | null = null;
406
407
lines.forEach(line => {
408
409
if (failed) {
410
return;
411
}
412
413
const m0 = line.match(/^\/\/dtsv=(\d+)$/);
414
if (m0) {
415
version = m0[1];
416
}
417
418
const m1 = line.match(/^\s*#include\(([^;)]*)(;[^)]*)?\)\:(.*)$/);
419
if (m1) {
420
const moduleId = m1[1];
421
const sourceFile = sourceFileGetter(moduleId);
422
if (!sourceFile) {
423
logErr(`While handling ${line}`);
424
logErr(`Cannot find ${moduleId}`);
425
failed = true;
426
return;
427
}
428
429
const importName = generateUsageImport(moduleId);
430
431
const replacer = createReplacer(m1[2]);
432
433
const typeNames = m1[3].split(/,/);
434
typeNames.forEach((typeName) => {
435
typeName = typeName.trim();
436
if (typeName.length === 0) {
437
return;
438
}
439
const declaration = getTopLevelDeclaration(ts, sourceFile, typeName);
440
if (!declaration) {
441
logErr(`While handling ${line}`);
442
logErr(`Cannot find ${typeName}`);
443
failed = true;
444
return;
445
}
446
result.push(replacer(getMassagedTopLevelDeclarationText(ts, sourceFile, declaration, importName, usage, enums)));
447
});
448
return;
449
}
450
451
const m2 = line.match(/^\s*#includeAll\(([^;)]*)(;[^)]*)?\)\:(.*)$/);
452
if (m2) {
453
const moduleId = m2[1];
454
const sourceFile = sourceFileGetter(moduleId);
455
if (!sourceFile) {
456
logErr(`While handling ${line}`);
457
logErr(`Cannot find ${moduleId}`);
458
failed = true;
459
return;
460
}
461
462
const importName = generateUsageImport(moduleId);
463
464
const replacer = createReplacer(m2[2]);
465
466
const typeNames = m2[3].split(/,/);
467
const typesToExcludeMap: { [typeName: string]: boolean } = {};
468
const typesToExcludeArr: string[] = [];
469
typeNames.forEach((typeName) => {
470
typeName = typeName.trim();
471
if (typeName.length === 0) {
472
return;
473
}
474
typesToExcludeMap[typeName] = true;
475
typesToExcludeArr.push(typeName);
476
});
477
478
getAllTopLevelDeclarations(ts, sourceFile).forEach((declaration) => {
479
if (isDeclaration(ts, declaration) && declaration.name) {
480
if (typesToExcludeMap[declaration.name.text]) {
481
return;
482
}
483
} else {
484
// node is ts.VariableStatement
485
const nodeText = getNodeText(sourceFile, declaration);
486
for (let i = 0; i < typesToExcludeArr.length; i++) {
487
if (nodeText.indexOf(typesToExcludeArr[i]) >= 0) {
488
return;
489
}
490
}
491
}
492
result.push(replacer(getMassagedTopLevelDeclarationText(ts, sourceFile, declaration, importName, usage, enums)));
493
});
494
return;
495
}
496
497
result.push(line);
498
});
499
500
if (failed) {
501
return null;
502
}
503
504
if (version !== dtsv) {
505
if (!version) {
506
logErr(`gulp watch restart required. 'monaco.d.ts.recipe' is written before versioning was introduced.`);
507
} else {
508
logErr(`gulp watch restart required. 'monaco.d.ts.recipe' v${version} does not match runtime v${dtsv}.`);
509
}
510
return null;
511
}
512
513
let resultTxt = result.join(endl);
514
resultTxt = resultTxt.replace(/\bURI\b/g, 'Uri');
515
resultTxt = resultTxt.replace(/\bEvent</g, 'IEvent<');
516
resultTxt = resultTxt.split(/\r\n|\n|\r/).join(endl);
517
resultTxt = format(ts, resultTxt, endl);
518
resultTxt = resultTxt.split(/\r\n|\n|\r/).join(endl);
519
520
enums.sort((e1, e2) => {
521
if (e1.enumName < e2.enumName) {
522
return -1;
523
}
524
if (e1.enumName > e2.enumName) {
525
return 1;
526
}
527
return 0;
528
});
529
530
let resultEnums = [
531
'/*---------------------------------------------------------------------------------------------',
532
' * Copyright (c) Microsoft Corporation. All rights reserved.',
533
' * Licensed under the MIT License. See License.txt in the project root for license information.',
534
' *--------------------------------------------------------------------------------------------*/',
535
'',
536
'// THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY.',
537
''
538
].concat(enums.map(e => e.text)).join(endl);
539
resultEnums = resultEnums.split(/\r\n|\n|\r/).join(endl);
540
resultEnums = format(ts, resultEnums, endl);
541
resultEnums = resultEnums.split(/\r\n|\n|\r/).join(endl);
542
543
return {
544
result: resultTxt,
545
usageContent: `${usageImports.join('\n')}\n\n${usage.join('\n')}`,
546
enums: resultEnums
547
};
548
}
549
550
export interface IMonacoDeclarationResult {
551
content: string;
552
usageContent: string;
553
enums: string;
554
filePath: string;
555
isTheSame: boolean;
556
}
557
558
function _run(ts: typeof import('typescript'), sourceFileGetter: SourceFileGetter): IMonacoDeclarationResult | null {
559
const recipe = fs.readFileSync(RECIPE_PATH).toString();
560
const t = generateDeclarationFile(ts, recipe, sourceFileGetter);
561
if (!t) {
562
return null;
563
}
564
565
const result = t.result;
566
const usageContent = t.usageContent;
567
const enums = t.enums;
568
569
const currentContent = fs.readFileSync(DECLARATION_PATH).toString();
570
const one = currentContent.replace(/\r\n/gm, '\n');
571
const other = result.replace(/\r\n/gm, '\n');
572
const isTheSame = (one === other);
573
574
return {
575
content: result,
576
usageContent: usageContent,
577
enums: enums,
578
filePath: DECLARATION_PATH,
579
isTheSame
580
};
581
}
582
583
export class FSProvider {
584
public existsSync(filePath: string): boolean {
585
return fs.existsSync(filePath);
586
}
587
public statSync(filePath: string): fs.Stats {
588
return fs.statSync(filePath);
589
}
590
public readFileSync(_moduleId: string, filePath: string): Buffer {
591
return fs.readFileSync(filePath);
592
}
593
}
594
595
class CacheEntry {
596
constructor(
597
public readonly sourceFile: ts.SourceFile,
598
public readonly mtime: number
599
) { }
600
}
601
602
export class DeclarationResolver {
603
604
public readonly ts: typeof import('typescript');
605
private _sourceFileCache: { [moduleId: string]: CacheEntry | null };
606
607
constructor(private readonly _fsProvider: FSProvider) {
608
this.ts = require('typescript') as typeof import('typescript');
609
this._sourceFileCache = Object.create(null);
610
}
611
612
public invalidateCache(moduleId: string): void {
613
this._sourceFileCache[moduleId] = null;
614
}
615
616
public getDeclarationSourceFile(moduleId: string): ts.SourceFile | null {
617
if (this._sourceFileCache[moduleId]) {
618
// Since we cannot trust file watching to invalidate the cache, check also the mtime
619
const fileName = this._getFileName(moduleId);
620
const mtime = this._fsProvider.statSync(fileName).mtime.getTime();
621
if (this._sourceFileCache[moduleId]!.mtime !== mtime) {
622
this._sourceFileCache[moduleId] = null;
623
}
624
}
625
if (!this._sourceFileCache[moduleId]) {
626
this._sourceFileCache[moduleId] = this._getDeclarationSourceFile(moduleId);
627
}
628
return this._sourceFileCache[moduleId] ? this._sourceFileCache[moduleId]!.sourceFile : null;
629
}
630
631
private _getFileName(moduleId: string): string {
632
if (/\.d\.ts$/.test(moduleId)) {
633
return path.join(SRC, moduleId);
634
}
635
return path.join(SRC, `${moduleId}.ts`);
636
}
637
638
private _getDeclarationSourceFile(moduleId: string): CacheEntry | null {
639
const fileName = this._getFileName(moduleId);
640
if (!this._fsProvider.existsSync(fileName)) {
641
return null;
642
}
643
const mtime = this._fsProvider.statSync(fileName).mtime.getTime();
644
if (/\.d\.ts$/.test(moduleId)) {
645
// const mtime = this._fsProvider.statFileSync()
646
const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString();
647
return new CacheEntry(
648
this.ts.createSourceFile(fileName, fileContents, this.ts.ScriptTarget.ES5),
649
mtime
650
);
651
}
652
const fileContents = this._fsProvider.readFileSync(moduleId, fileName).toString();
653
const fileMap: IFileMap = {
654
'file.ts': fileContents
655
};
656
const service = this.ts.createLanguageService(new TypeScriptLanguageServiceHost(this.ts, {}, fileMap, {}));
657
const text = service.getEmitOutput('file.ts', true, true).outputFiles[0].text;
658
return new CacheEntry(
659
this.ts.createSourceFile(fileName, text, this.ts.ScriptTarget.ES5),
660
mtime
661
);
662
}
663
}
664
665
export function run3(resolver: DeclarationResolver): IMonacoDeclarationResult | null {
666
const sourceFileGetter = (moduleId: string) => resolver.getDeclarationSourceFile(moduleId);
667
return _run(resolver.ts, sourceFileGetter);
668
}
669
670
671
672
673
interface ILibMap { [libName: string]: string }
674
interface IFileMap { [fileName: string]: string }
675
676
class TypeScriptLanguageServiceHost implements ts.LanguageServiceHost {
677
678
private readonly _ts: typeof import('typescript');
679
private readonly _libs: ILibMap;
680
private readonly _files: IFileMap;
681
private readonly _compilerOptions: ts.CompilerOptions;
682
683
constructor(ts: typeof import('typescript'), libs: ILibMap, files: IFileMap, compilerOptions: ts.CompilerOptions) {
684
this._ts = ts;
685
this._libs = libs;
686
this._files = files;
687
this._compilerOptions = compilerOptions;
688
}
689
690
// --- language service host ---------------
691
692
getCompilationSettings(): ts.CompilerOptions {
693
return this._compilerOptions;
694
}
695
getScriptFileNames(): string[] {
696
return (
697
([] as string[])
698
.concat(Object.keys(this._libs))
699
.concat(Object.keys(this._files))
700
);
701
}
702
getScriptVersion(_fileName: string): string {
703
return '1';
704
}
705
getProjectVersion(): string {
706
return '1';
707
}
708
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
709
if (this._files.hasOwnProperty(fileName)) {
710
return this._ts.ScriptSnapshot.fromString(this._files[fileName]);
711
} else if (this._libs.hasOwnProperty(fileName)) {
712
return this._ts.ScriptSnapshot.fromString(this._libs[fileName]);
713
} else {
714
return this._ts.ScriptSnapshot.fromString('');
715
}
716
}
717
getScriptKind(_fileName: string): ts.ScriptKind {
718
return this._ts.ScriptKind.TS;
719
}
720
getCurrentDirectory(): string {
721
return '';
722
}
723
getDefaultLibFileName(_options: ts.CompilerOptions): string {
724
return 'defaultLib:es5';
725
}
726
isDefaultLibFileName(fileName: string): boolean {
727
return fileName === this.getDefaultLibFileName(this._compilerOptions);
728
}
729
readFile(path: string, _encoding?: string): string | undefined {
730
return this._files[path] || this._libs[path];
731
}
732
fileExists(path: string): boolean {
733
return path in this._files || path in this._libs;
734
}
735
}
736
737
export function execute(): IMonacoDeclarationResult {
738
const r = run3(new DeclarationResolver(new FSProvider()));
739
if (!r) {
740
throw new Error(`monaco.d.ts generation error - Cannot continue`);
741
}
742
return r;
743
}
744
745