Initial version

This commit is contained in:
Johannes Rieken 2016-06-09 12:39:51 +02:00 committed by Alex Dima
parent a818bfffee
commit 331acc5fef
26 changed files with 59386 additions and 2 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/node_modules/
/out/
/release/

8
.npmignore Normal file
View file

@ -0,0 +1,8 @@
/.vscode/
/lib/
/out/
/src/
/test/
/gulpfile.js
/tsconfig.json
/.npmignore

9
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,9 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.trimTrailingWhitespace": true,
"search.exclude": {
"**/node_modules": true,
"**/release": true,
"**/out": true
}
}

21
LICENSE.md Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,2 +1,12 @@
# monaco-typescript
TypeScript/JavaScript language support for the Monaco Editor
# Monaco TypeScript
TypeScript and JavaScript language support for the Monaco Editor.
![typescript](https://cloud.githubusercontent.com/assets/5047891/15926623/5262fe08-2e3d-11e6-9b90-1d43fda07178.gif)
## Installing
This npm module is bundled and distributed in the [monaco-editor](https://www.npmjs.com/package/monaco-editor) npm module.
## License
[MIT](https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md)

273
gulpfile.js Normal file
View file

@ -0,0 +1,273 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var gulp = require('gulp');
var tsb = require('gulp-tsb');
var assign = require('object-assign');
var fs = require('fs');
var path = require('path');
var merge = require('merge-stream');
var rjs = require('gulp-requirejs');
var uglify = require('gulp-uglify');
var rimraf = require('rimraf');
var es = require('event-stream');
var TYPESCRIPT_LIB_SOURCE = path.join(__dirname, 'node_modules', 'typescript', 'lib');
var TYPESCRIPT_LIB_DESTINATION = path.join(__dirname, 'lib');
gulp.task('clean-release', function(cb) { rimraf('release', { maxBusyTries: 1 }, cb); });
gulp.task('release', ['clean-release','compile'], function() {
var sha1 = getGitVersion(__dirname);
var semver = require('./package.json').version;
var headerVersion = semver + '(' + sha1 + ')';
var BUNDLED_FILE_HEADER = [
'/*!-----------------------------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' * monaco-typescript version: ' + headerVersion,
' * Released under the MIT license',
' * https://github.com/Microsoft/monaco-typescript/blob/master/LICENSE.md',
' *-----------------------------------------------------------------------------*/',
''
].join('\n');
function bundleOne(moduleId, exclude) {
return rjs({
baseUrl: '/out/',
name: 'vs/language/typescript/' + moduleId,
out: moduleId + '.js',
exclude: exclude,
paths: {
'vs/language/typescript': __dirname + '/out'
}
})
}
return merge(
bundleOne('src/monaco.contribution'),
bundleOne('lib/typescriptServices'),
bundleOne('src/mode', ['vs/language/typescript/lib/typescriptServices']),
bundleOne('src/worker', ['vs/language/typescript/lib/typescriptServices'])
)
.pipe(uglify({
preserveComments: 'some'
}))
.pipe(es.through(function(data) {
data.contents = new Buffer(
BUNDLED_FILE_HEADER
+ data.contents.toString()
);
this.emit('data', data);
}))
.pipe(gulp.dest('./release/'));
});
var compilation = tsb.create(assign({ verbose: true }, require('./tsconfig.json').compilerOptions));
var tsSources = require('./tsconfig.json').filesGlob;
function compileTask() {
return merge(
gulp.src('lib/*.js', { base: '.' }),
gulp.src(tsSources).pipe(compilation())
)
.pipe(gulp.dest('out'));
}
gulp.task('clean-out', function(cb) { rimraf('out', { maxBusyTries: 1 }, cb); });
gulp.task('compile', ['clean-out'], compileTask);
gulp.task('compile-without-clean', compileTask);
gulp.task('watch', ['compile'], function() {
gulp.watch(tsSources, ['compile-without-clean']);
});
/**
* Import files from TypeScript's dist
*/
gulp.task('import-typescript', function() {
try {
fs.statSync(TYPESCRIPT_LIB_DESTINATION);
} catch (err) {
fs.mkdirSync(TYPESCRIPT_LIB_DESTINATION);
}
importLibDeclarationFile('lib.d.ts');
importLibDeclarationFile('lib.es6.d.ts');
var tsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescriptServices.js')).toString();
tsServices +=
`
// MONACOCHANGE
define([], function() { return ts; });
// END MONACOCHANGE
`;
fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.js'), tsServices);
var dtsServices = fs.readFileSync(path.join(TYPESCRIPT_LIB_SOURCE, 'typescriptServices.d.ts')).toString();
dtsServices +=
`
// MONACOCHANGE
export = ts;
// END MONACOCHANGE
`;
fs.writeFileSync(path.join(TYPESCRIPT_LIB_DESTINATION, 'typescriptServices.d.ts'), dtsServices);
});
/**
* Import a lib*.d.ts file from TypeScript's dist
*/
function importLibDeclarationFile(name) {
var dstName = name.replace(/\.d\.ts$/, '').replace(/\./g, '-') + '-ts';
var srcPath = path.join(TYPESCRIPT_LIB_SOURCE, name);
var contents = fs.readFileSync(srcPath).toString();
var dstPath1 = path.join(TYPESCRIPT_LIB_DESTINATION, dstName + '.js');
fs.writeFileSync(dstPath1,
`/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// This is a generated file from ${name}
define([], function() { return { contents: "${escapeText(contents)}"}; });
`);
var dstPath2 = path.join(TYPESCRIPT_LIB_DESTINATION, dstName + '.d.ts');
fs.writeFileSync(dstPath2,
`/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export declare var contents: string;
`);
}
/**
* Escape text such that it can be used in a javascript string enclosed by double quotes (")
*/
function escapeText(text) {
// http://www.javascriptkit.com/jsref/escapesequence.shtml
// \b Backspace.
// \f Form feed.
// \n Newline.
// \O Nul character.
// \r Carriage return.
// \t Horizontal tab.
// \v Vertical tab.
// \' Single quote or apostrophe.
// \" Double quote.
// \\ Backslash.
// \ddd The Latin-1 character specified by the three octal digits between 0 and 377. ie, copyright symbol is \251.
// \xdd The Latin-1 character specified by the two hexadecimal digits dd between 00 and FF. ie, copyright symbol is \xA9.
// \udddd The Unicode character specified by the four hexadecimal digits dddd. ie, copyright symbol is \u00A9.
var _backspace = '\b'.charCodeAt(0);
var _formFeed = '\f'.charCodeAt(0);
var _newLine = '\n'.charCodeAt(0);
var _nullChar = 0;
var _carriageReturn = '\r'.charCodeAt(0);
var _tab = '\t'.charCodeAt(0);
var _verticalTab = '\v'.charCodeAt(0);
var _backslash = '\\'.charCodeAt(0);
var _doubleQuote = '"'.charCodeAt(0);
var startPos = 0, chrCode, replaceWith = null, resultPieces = [];
for (var i = 0, len = text.length; i < len; i++) {
chrCode = text.charCodeAt(i);
switch (chrCode) {
case _backspace:
replaceWith = '\\b';
break;
case _formFeed:
replaceWith = '\\f';
break;
case _newLine:
replaceWith = '\\n';
break;
case _nullChar:
replaceWith = '\\0';
break;
case _carriageReturn:
replaceWith = '\\r';
break;
case _tab:
replaceWith = '\\t';
break;
case _verticalTab:
replaceWith = '\\v';
break;
case _backslash:
replaceWith = '\\\\';
break;
case _doubleQuote:
replaceWith = '\\"';
break;
}
if (replaceWith !== null) {
resultPieces.push(text.substring(startPos, i));
resultPieces.push(replaceWith);
startPos = i + 1;
replaceWith = null;
}
}
resultPieces.push(text.substring(startPos, len));
return resultPieces.join('');
}
function getGitVersion(repo) {
var git = path.join(repo, '.git');
var headPath = path.join(git, 'HEAD');
var head;
try {
head = fs.readFileSync(headPath, 'utf8').trim();
} catch (e) {
return void 0;
}
if (/^[0-9a-f]{40}$/i.test(head)) {
return head;
}
var refMatch = /^ref: (.*)$/.exec(head);
if (!refMatch) {
return void 0;
}
var ref = refMatch[1];
var refPath = path.join(git, ref);
try {
return fs.readFileSync(refPath, 'utf8').trim();
} catch (e) {
// noop
}
var packedRefsPath = path.join(git, 'packed-refs');
var refsRaw;
try {
refsRaw = fs.readFileSync(packedRefsPath, 'utf8').trim();
} catch (e) {
return void 0;
}
var refsRegex = /^([0-9a-f]{40})\s+(.+)$/gm;
var refsMatch;
var refs = {};
while (refsMatch = refsRegex.exec(refsRaw)) {
refs[refsMatch[2]] = refsMatch[1];
}
return refs[ref];
}

6
lib/lib-es6-ts.d.ts vendored Normal file
View file

@ -0,0 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export declare var contents: string;

9
lib/lib-es6-ts.js Normal file

File diff suppressed because one or more lines are too long

6
lib/lib-ts.d.ts vendored Normal file
View file

@ -0,0 +1,6 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export declare var contents: string;

9
lib/lib-ts.js Normal file

File diff suppressed because one or more lines are too long

2348
lib/typescriptServices.d.ts vendored Normal file

File diff suppressed because it is too large Load diff

54817
lib/typescriptServices.js Normal file

File diff suppressed because one or more lines are too long

33
package.json Normal file
View file

@ -0,0 +1,33 @@
{
"name": "monaco-typescript",
"version": "0.1.0",
"description": "TypeScript and JavaScript language support for Monaco Editor",
"scripts": {
"test": "node_modules/.bin/mocha",
"watch": "node_modules/.bin/gulp watch",
"prepublish": "node_modules/.bin/gulp release"
},
"author": "Microsoft Corporation",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/Microsoft/monaco-typescript"
},
"bugs": {
"url": "https://github.com/Microsoft/monaco-typescript/issues"
},
"devDependencies": {
"event-stream": "^3.3.2",
"gulp": "^3.9.1",
"gulp-requirejs": "^0.1.3",
"gulp-tsb": "^1.10.4",
"gulp-uglify": "^1.5.3",
"merge-stream": "^1.0.0",
"mocha": "^2.5.3",
"monaco-editor-core": "^0.3.1",
"object-assign": "^4.1.0",
"rimraf": "^2.5.2",
"typescript": "1.8.10",
"typescript-with-globs": "^0.1.4"
}
}

540
src/languageFeatures.ts Normal file
View file

@ -0,0 +1,540 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {LanguageServiceDefaults} from './typescript';
import * as ts from '../lib/typescriptServices';
import {TypeScriptWorker} from './worker';
import Uri = monaco.Uri;
import Position = monaco.Position;
import Range = monaco.Range;
import Thenable = monaco.Thenable;
import Promise = monaco.Promise;
import CancellationToken = monaco.CancellationToken;
import IDisposable = monaco.IDisposable;
export abstract class Adapter {
constructor(protected _worker: (first:Uri, ...more:Uri[]) => Promise<TypeScriptWorker>) {
}
protected _positionToOffset(uri: Uri, position: monaco.IPosition): number {
let model = monaco.editor.getModel(uri);
return model.getOffsetAt(position);
}
protected _offsetToPosition(uri: Uri, offset: number): monaco.IPosition {
let model = monaco.editor.getModel(uri);
return model.getPositionAt(offset);
}
protected _textSpanToRange(uri: Uri, span: ts.TextSpan): monaco.IRange {
let p1 = this._offsetToPosition(uri, span.start);
let p2 = this._offsetToPosition(uri, span.start + span.length);
let {lineNumber: startLineNumber, column: startColumn} = p1;
let {lineNumber: endLineNumber, column: endColumn} = p2;
return { startLineNumber, startColumn, endLineNumber, endColumn };
}
}
// --- diagnostics --- ---
export class DiagnostcsAdapter extends Adapter {
private _disposables: IDisposable[] = [];
private _listener: { [uri: string]: IDisposable } = Object.create(null);
constructor(private _defaults: LanguageServiceDefaults, private _selector: string,
worker: (first: Uri, ...more: Uri[]) => Promise<TypeScriptWorker>
) {
super(worker);
const onModelAdd = (model: monaco.editor.IModel): void => {
if (model.getModeId() !== _selector) {
return;
}
let handle: number;
this._listener[model.uri.toString()] = model.onDidChangeContent(() => {
clearTimeout(handle);
handle = setTimeout(() => this._doValidate(model.uri), 500);
});
this._doValidate(model.uri);
};
const onModelRemoved = (model: monaco.editor.IModel): void => {
delete this._listener[model.uri.toString()];
};
this._disposables.push(monaco.editor.onDidCreateModel(onModelAdd));
this._disposables.push(monaco.editor.onWillDisposeModel(onModelRemoved));
this._disposables.push(monaco.editor.onDidChangeModelLanguage(event => {
onModelRemoved(event.model);
onModelAdd(event.model);
}));
this._disposables.push({
dispose: () => {
for (let key in this._listener) {
this._listener[key].dispose();
}
}
});
monaco.editor.getModels().forEach(onModelAdd);
}
public dispose(): void {
this._disposables.forEach(d => d && d.dispose());
this._disposables = [];
}
private _doValidate(resource: Uri): void {
this._worker(resource).then(worker => {
let promises: Promise<ts.Diagnostic[]>[] = [];
if (!this._defaults.diagnosticsOptions.noSyntaxValidation) {
promises.push(worker.getSyntacticDiagnostics(resource.toString()));
}
if (!this._defaults.diagnosticsOptions.noSemanticValidation) {
promises.push(worker.getSemanticDiagnostics(resource.toString()));
}
return Promise.join(promises);
}).then(diagnostics => {
const markers = diagnostics
.reduce((p, c) => c.concat(p), [])
.map(d => this._convertDiagnostics(resource, d));
monaco.editor.setModelMarkers(monaco.editor.getModel(resource), this._selector, markers);
}).done(undefined, err => {
console.error(err);
});
}
private _convertDiagnostics(resource: Uri, diag: ts.Diagnostic): monaco.editor.IMarkerData {
const {lineNumber: startLineNumber, column: startColumn} = this._offsetToPosition(resource, diag.start);
const {lineNumber: endLineNumber, column: endColumn} = this._offsetToPosition(resource, diag.start + diag.length);
return {
severity: monaco.Severity.Error,
startLineNumber,
startColumn,
endLineNumber,
endColumn,
message: ts.flattenDiagnosticMessageText(diag.messageText, '\n')
};
}
}
// --- suggest ------
interface MyCompletionItem extends monaco.languages.CompletionItem {
uri: Uri;
position: Position;
}
export class SuggestAdapter extends Adapter implements monaco.languages.CompletionItemProvider {
public get triggerCharacters(): string[] {
return ['.'];
}
provideCompletionItems(model:monaco.editor.IReadOnlyModel, position:Position, token:CancellationToken): Thenable<monaco.languages.CompletionItem[]> {
const wordInfo = model.getWordUntilPosition(position);
const resource = model.uri;
const offset = this._positionToOffset(resource, position);
return wireCancellationToken(token, this._worker(resource).then(worker => {
return worker.getCompletionsAtPosition(resource.toString(), offset);
}).then(info => {
if (!info) {
return;
}
let suggestions: MyCompletionItem[] = info.entries.map(entry => {
return {
uri: resource,
position: position,
label: entry.name,
sortText: entry.sortText,
kind: SuggestAdapter.convertKind(entry.kind)
};
});
return suggestions;
}));
}
resolveCompletionItem(item: monaco.languages.CompletionItem, token: CancellationToken): Thenable<monaco.languages.CompletionItem> {
let myItem = <MyCompletionItem>item;
const resource = myItem.uri;
const position = myItem.position;
return wireCancellationToken(token, this._worker(resource).then(worker => {
return worker.getCompletionEntryDetails(resource.toString(),
this._positionToOffset(resource, position),
myItem.label);
}).then(details => {
if (!details) {
return myItem;
}
return <MyCompletionItem>{
uri: resource,
position: position,
label: details.name,
kind: SuggestAdapter.convertKind(details.kind),
detail: ts.displayPartsToString(details.displayParts),
documentation: ts.displayPartsToString(details.documentation)
};
}));
}
private static convertKind(kind: string): monaco.languages.CompletionItemKind {
switch (kind) {
case Kind.primitiveType:
case Kind.keyword:
return monaco.languages.CompletionItemKind.Keyword;
case Kind.variable:
case Kind.localVariable:
return monaco.languages.CompletionItemKind.Variable;
case Kind.memberVariable:
case Kind.memberGetAccessor:
case Kind.memberSetAccessor:
return monaco.languages.CompletionItemKind.Field;
case Kind.function:
case Kind.memberFunction:
case Kind.constructSignature:
case Kind.callSignature:
case Kind.indexSignature:
return monaco.languages.CompletionItemKind.Function;
case Kind.enum:
return monaco.languages.CompletionItemKind.Enum;
case Kind.module:
return monaco.languages.CompletionItemKind.Module;
case Kind.class:
return monaco.languages.CompletionItemKind.Class;
case Kind.interface:
return monaco.languages.CompletionItemKind.Interface;
case Kind.warning:
return monaco.languages.CompletionItemKind.File;
}
return monaco.languages.CompletionItemKind.Property;
}
}
export class SignatureHelpAdapter extends Adapter implements monaco.languages.SignatureHelpProvider {
public signatureHelpTriggerCharacters = ['(', ','];
provideSignatureHelp(model: monaco.editor.IReadOnlyModel, position: Position, token: CancellationToken): Thenable<monaco.languages.SignatureHelp> {
let resource = model.uri;
return wireCancellationToken(token, this._worker(resource).then(worker => worker.getSignatureHelpItems(resource.toString(), this._positionToOffset(resource, position))).then(info => {
if (!info) {
return;
}
let ret:monaco.languages.SignatureHelp = {
activeSignature: info.selectedItemIndex,
activeParameter: info.argumentIndex,
signatures: []
};
info.items.forEach(item => {
let signature:monaco.languages.SignatureInformation = {
label: '',
documentation: null,
parameters: []
};
signature.label += ts.displayPartsToString(item.prefixDisplayParts);
item.parameters.forEach((p, i, a) => {
let label = ts.displayPartsToString(p.displayParts);
let parameter:monaco.languages.ParameterInformation = {
label: label,
documentation: ts.displayPartsToString(p.documentation)
};
signature.label += label;
signature.parameters.push(parameter);
if (i < a.length - 1) {
signature.label += ts.displayPartsToString(item.separatorDisplayParts);
}
});
signature.label += ts.displayPartsToString(item.suffixDisplayParts);
ret.signatures.push(signature);
});
return ret;
}));
}
}
// --- hover ------
export class QuickInfoAdapter extends Adapter implements monaco.languages.HoverProvider {
provideHover(model:monaco.editor.IReadOnlyModel, position:Position, token:CancellationToken): Thenable<monaco.languages.Hover> {
let resource = model.uri;
return wireCancellationToken(token, this._worker(resource).then(worker => {
return worker.getQuickInfoAtPosition(resource.toString(), this._positionToOffset(resource, position));
}).then(info => {
if (!info) {
return;
}
return <monaco.languages.Hover>{
range: this._textSpanToRange(resource, info.textSpan),
htmlContent: [{ text: ts.displayPartsToString(info.displayParts) }]
};
}));
}
}
// --- occurrences ------
export class OccurrencesAdapter extends Adapter implements monaco.languages.DocumentHighlightProvider {
public provideDocumentHighlights(model: monaco.editor.IReadOnlyModel, position: Position, token: CancellationToken): Thenable<monaco.languages.DocumentHighlight[]> {
const resource = model.uri;
return wireCancellationToken(token, this._worker(resource).then(worker => {
return worker.getOccurrencesAtPosition(resource.toString(), this._positionToOffset(resource, position));
}).then(entries => {
if (!entries) {
return;
}
return entries.map(entry => {
return <monaco.languages.DocumentHighlight>{
range: this._textSpanToRange(resource, entry.textSpan),
kind: entry.isWriteAccess ? monaco.languages.DocumentHighlightKind.Write : monaco.languages.DocumentHighlightKind.Text
};
});
}));
}
}
// --- definition ------
export class DefinitionAdapter extends Adapter {
public provideDefinition(model:monaco.editor.IReadOnlyModel, position:Position, token:CancellationToken): Thenable<monaco.languages.Definition> {
const resource = model.uri;
return wireCancellationToken(token, this._worker(resource).then(worker => {
return worker.getDefinitionAtPosition(resource.toString(), this._positionToOffset(resource, position));
}).then(entries => {
if (!entries) {
return;
}
const result: monaco.languages.Location[] = [];
for (let entry of entries) {
const uri = Uri.parse(entry.fileName);
if (monaco.editor.getModel(uri)) {
result.push({
uri: uri,
range: this._textSpanToRange(uri, entry.textSpan)
});
}
}
return result;
}));
}
}
// --- references ------
export class ReferenceAdapter extends Adapter implements monaco.languages.ReferenceProvider {
provideReferences(model:monaco.editor.IReadOnlyModel, position:Position, context: monaco.languages.ReferenceContext, token: CancellationToken): Thenable<monaco.languages.Location[]> {
const resource = model.uri;
return wireCancellationToken(token, this._worker(resource).then(worker => {
return worker.getReferencesAtPosition(resource.toString(), this._positionToOffset(resource, position));
}).then(entries => {
if (!entries) {
return;
}
const result: monaco.languages.Location[] = [];
for (let entry of entries) {
const uri = Uri.parse(entry.fileName);
if (monaco.editor.getModel(uri)) {
result.push({
uri: uri,
range: this._textSpanToRange(uri, entry.textSpan)
});
}
}
return result;
}));
}
}
// --- outline ------
export class OutlineAdapter extends Adapter implements monaco.languages.DocumentSymbolProvider {
public provideDocumentSymbols(model:monaco.editor.IReadOnlyModel, token: CancellationToken): Thenable<monaco.languages.SymbolInformation[]> {
const resource = model.uri;
return wireCancellationToken(token, this._worker(resource).then(worker => worker.getNavigationBarItems(resource.toString())).then(items => {
if (!items) {
return;
}
function convert(bucket: monaco.languages.SymbolInformation[], item: ts.NavigationBarItem, containerLabel?: string): void {
let result: monaco.languages.SymbolInformation = {
name: item.text,
kind: outlineTypeTable[item.kind] || monaco.languages.SymbolKind.Variable,
location: {
uri: resource,
range: this._textSpanToRange(resource, item.spans[0])
},
containerName: containerLabel
};
if (item.childItems && item.childItems.length > 0) {
for (let child of item.childItems) {
convert(bucket, child, result.name);
}
}
bucket.push(result);
}
let result: monaco.languages.SymbolInformation[] = [];
items.forEach(item => convert(result, item));
return result;
}));
}
}
export class Kind {
public static unknown:string = '';
public static keyword:string = 'keyword';
public static script:string = 'script';
public static module:string = 'module';
public static class:string = 'class';
public static interface:string = 'interface';
public static type:string = 'type';
public static enum:string = 'enum';
public static variable:string = 'var';
public static localVariable:string = 'local var';
public static function:string = 'function';
public static localFunction:string = 'local function';
public static memberFunction:string = 'method';
public static memberGetAccessor:string = 'getter';
public static memberSetAccessor:string = 'setter';
public static memberVariable:string = 'property';
public static constructorImplementation:string = 'constructor';
public static callSignature:string = 'call';
public static indexSignature:string = 'index';
public static constructSignature:string = 'construct';
public static parameter:string = 'parameter';
public static typeParameter:string = 'type parameter';
public static primitiveType:string = 'primitive type';
public static label:string = 'label';
public static alias:string = 'alias';
public static const:string = 'const';
public static let:string = 'let';
public static warning:string = 'warning';
}
let outlineTypeTable: { [kind: string]: monaco.languages.SymbolKind } = Object.create(null);
outlineTypeTable[Kind.module] = monaco.languages.SymbolKind.Module;
outlineTypeTable[Kind.class] = monaco.languages.SymbolKind.Class;
outlineTypeTable[Kind.enum] = monaco.languages.SymbolKind.Enum;
outlineTypeTable[Kind.interface] = monaco.languages.SymbolKind.Interface;
outlineTypeTable[Kind.memberFunction] = monaco.languages.SymbolKind.Method;
outlineTypeTable[Kind.memberVariable] = monaco.languages.SymbolKind.Property;
outlineTypeTable[Kind.memberGetAccessor] = monaco.languages.SymbolKind.Property;
outlineTypeTable[Kind.memberSetAccessor] = monaco.languages.SymbolKind.Property;
outlineTypeTable[Kind.variable] = monaco.languages.SymbolKind.Variable;
outlineTypeTable[Kind.const] = monaco.languages.SymbolKind.Variable;
outlineTypeTable[Kind.localVariable] = monaco.languages.SymbolKind.Variable;
outlineTypeTable[Kind.variable] = monaco.languages.SymbolKind.Variable;
outlineTypeTable[Kind.function] = monaco.languages.SymbolKind.Function;
outlineTypeTable[Kind.localFunction] = monaco.languages.SymbolKind.Function;
// --- formatting ----
export abstract class FormatHelper extends Adapter {
protected static _convertOptions(options: monaco.languages.IFormattingOptions): ts.FormatCodeOptions {
return {
ConvertTabsToSpaces: options.insertSpaces,
TabSize: options.tabSize,
IndentSize: options.tabSize,
IndentStyle: ts.IndentStyle.Smart,
NewLineCharacter: '\n',
InsertSpaceAfterCommaDelimiter: true,
InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
InsertSpaceAfterKeywordsInControlFlowStatements: false,
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: true,
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: true,
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: true,
InsertSpaceAfterSemicolonInForStatements: false,
InsertSpaceBeforeAndAfterBinaryOperators: true,
PlaceOpenBraceOnNewLineForControlBlocks: false,
PlaceOpenBraceOnNewLineForFunctions: false
};
}
protected _convertTextChanges(uri: Uri, change: ts.TextChange): monaco.editor.ISingleEditOperation {
return <monaco.editor.ISingleEditOperation>{
text: change.newText,
range: this._textSpanToRange(uri, change.span)
};
}
}
export class FormatAdapter extends FormatHelper implements monaco.languages.DocumentRangeFormattingEditProvider {
provideDocumentRangeFormattingEdits(model: monaco.editor.IReadOnlyModel, range: Range, options: monaco.languages.IFormattingOptions, token: CancellationToken): Thenable<monaco.editor.ISingleEditOperation[]> {
const resource = model.uri;
return wireCancellationToken(token, this._worker(resource).then(worker => {
return worker.getFormattingEditsForRange(resource.toString(),
this._positionToOffset(resource, { lineNumber: range.startLineNumber, column: range.startColumn }),
this._positionToOffset(resource, { lineNumber: range.endLineNumber, column: range.endColumn }),
FormatHelper._convertOptions(options));
}).then(edits => {
if (edits) {
return edits.map(edit => this._convertTextChanges(resource, edit));
}
}));
}
}
export class FormatOnTypeAdapter extends FormatHelper implements monaco.languages.OnTypeFormattingEditProvider {
get autoFormatTriggerCharacters() {
return [';', '}', '\n'];
}
provideOnTypeFormattingEdits(model: monaco.editor.IReadOnlyModel, position: Position, ch: string, options: monaco.languages.IFormattingOptions, token: CancellationToken): Thenable<monaco.editor.ISingleEditOperation[]> {
const resource = model.uri;
return wireCancellationToken(token, this._worker(resource).then(worker => {
return worker.getFormattingEditsAfterKeystroke(resource.toString(),
this._positionToOffset(resource, position),
ch, FormatHelper._convertOptions(options));
}).then(edits => {
if (edits) {
return edits.map(edit => this._convertTextChanges(resource, edit));
}
}));
}
}
/**
* Hook a cancellation token to a WinJS Promise
*/
function wireCancellationToken<T>(token: CancellationToken, promise: Promise<T>): Thenable<T> {
token.onCancellationRequested(() => promise.cancel());
return promise;
}

110
src/mode.ts Normal file
View file

@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {Language, createTokenizationSupport} from './tokenization';
import {LanguageServiceDefaults, typeScriptDefaults, javaScriptDefaults, LanguageServiceMode} from './typescript';
import {WorkerManager} from './workerManager';
import {TypeScriptWorker} from './worker';
import * as languageFeatures from './languageFeatures';
import Promise = monaco.Promise;
import Uri = monaco.Uri;
import IDisposable = monaco.IDisposable;
export function setupTypeScript(): void {
setupMode(
typeScriptDefaults,
'typescript',
Language.TypeScript
);
}
export function setupJavaScript(): void {
setupMode(
javaScriptDefaults,
'javascript',
Language.EcmaScript5
);
}
function setupMode(defaults:LanguageServiceDefaults, modeId:string, language:Language): void {
let disposables: IDisposable[] = [];
const client = new WorkerManager(defaults);
disposables.push(client);
const worker = (first: Uri, ...more: Uri[]): Promise<TypeScriptWorker> => {
return client.getLanguageServiceWorker(...[first].concat(more));
};
disposables.push(monaco.languages.registerCompletionItemProvider(modeId, new languageFeatures.SuggestAdapter(worker)));
disposables.push(monaco.languages.registerSignatureHelpProvider(modeId, new languageFeatures.SignatureHelpAdapter(worker)));
disposables.push(monaco.languages.registerHoverProvider(modeId, new languageFeatures.QuickInfoAdapter(worker)));
disposables.push(monaco.languages.registerDocumentHighlightProvider(modeId, new languageFeatures.OccurrencesAdapter(worker)));
disposables.push(monaco.languages.registerDefinitionProvider(modeId, new languageFeatures.DefinitionAdapter(worker)));
disposables.push(monaco.languages.registerReferenceProvider(modeId, new languageFeatures.ReferenceAdapter(worker)));
disposables.push(monaco.languages.registerDocumentSymbolProvider(modeId, new languageFeatures.OutlineAdapter(worker)));
disposables.push(monaco.languages.registerDocumentRangeFormattingEditProvider(modeId, new languageFeatures.FormatAdapter(worker)));
disposables.push(monaco.languages.registerOnTypeFormattingEditProvider(modeId, new languageFeatures.FormatOnTypeAdapter(worker)));
disposables.push(new languageFeatures.DiagnostcsAdapter(defaults, modeId, worker));
disposables.push(monaco.languages.setLanguageConfiguration(modeId, richEditConfiguration));
disposables.push(monaco.languages.setTokensProvider(modeId, createTokenizationSupport(language)));
}
const richEditConfiguration:monaco.languages.IRichLanguageConfiguration = {
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\@\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
comments: {
lineComment: '//',
blockComment: ['/*', '*/']
},
brackets: [
['{', '}'],
['[', ']'],
['(', ')']
],
onEnterRules: [
{
// e.g. /** | */
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
afterText: /^\s*\*\/$/,
action: { indentAction: monaco.languages.IndentAction.IndentOutdent, appendText: ' * ' }
},
{
// e.g. /** ...|
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
action: { indentAction: monaco.languages.IndentAction.None, appendText: ' * ' }
},
{
// e.g. * ...|
beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
action: { indentAction: monaco.languages.IndentAction.None, appendText: '* ' }
},
{
// e.g. */|
beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
action: { indentAction: monaco.languages.IndentAction.None, removeText: 1 }
}
],
__electricCharacterSupport: {
docComment: {scope:'comment.doc', open:'/**', lineStart:' * ', close:' */'}
},
autoClosingPairs: [
{ open: '{', close: '}' },
{ open: '[', close: ']' },
{ open: '(', close: ')' },
{ open: '"', close: '"', notIn: ['string'] },
{ open: '\'', close: '\'', notIn: ['string', 'comment'] },
{ open: '`', close: '`' }
]
};

View file

@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as mode from './mode';
declare var require:<T>(moduleId:[string], callback:(module:T)=>void)=>void;
function withMode(callback:(module:typeof mode)=>void): void {
require<typeof mode>(['vs/language/typescript/src/mode'], callback);
}
monaco.languages.register({
id: 'typescript',
extensions: ['.ts'],
aliases: ['TypeScript', 'ts', 'typescript'],
mimetypes: ['text/typescript']
});
monaco.languages.onLanguage('typescript', () => {
withMode((mode) => mode.setupTypeScript());
});
monaco.languages.register({
id: 'javascript',
extensions: ['.js', '.es6'],
firstLine: '^#!.*\\bnode',
filenames: ['jakefile'],
aliases: ['JavaScript', 'javascript', 'js'],
mimetypes: ['text/javascript'],
});
monaco.languages.onLanguage('javascript', () => {
withMode((mode) => mode.setupJavaScript());
});

163
src/tokenization.ts Normal file
View file

@ -0,0 +1,163 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import ts = require('../lib/typescriptServices');
export enum Language {
TypeScript,
EcmaScript5
}
export function createTokenizationSupport(language:Language): monaco.languages.TokensProvider {
var classifier = ts.createClassifier(),
bracketTypeTable = language === Language.TypeScript ? tsBracketTypeTable : jsBracketTypeTable,
tokenTypeTable = language === Language.TypeScript ? tsTokenTypeTable : jsTokenTypeTable;
return {
getInitialState: () => new State(language, ts.EndOfLineState.None, false),
tokenize: (line, state) => tokenize(bracketTypeTable, tokenTypeTable, classifier, <State> state, line)
};
}
class State implements monaco.languages.IState {
public language: Language;
public eolState: ts.EndOfLineState;
public inJsDocComment: boolean;
constructor(language:Language, eolState: ts.EndOfLineState, inJsDocComment: boolean) {
this.language = language;
this.eolState = eolState;
this.inJsDocComment = inJsDocComment;
}
public clone(): State {
return new State(this.language, this.eolState, this.inJsDocComment);
}
public equals(other:monaco.languages.IState):boolean {
if(other === this) {
return true;
}
if(!other || !(other instanceof State)) {
return false;
}
if (this.eolState !== (<State> other).eolState) {
return false;
}
if(this.inJsDocComment !== (<State> other).inJsDocComment) {
return false;
}
return true;
}
}
function tokenize(bracketTypeTable: { [i: number]: string }, tokenTypeTable: { [i: number]: string },
classifier: ts.Classifier, state: State, text: string): monaco.languages.ILineTokens {
// Create result early and fill in tokens
var ret = {
tokens: <monaco.languages.IToken[]>[],
endState: new State(state.language, ts.EndOfLineState.None, false)
};
function appendFn(startIndex:number, type:string):void {
if(ret.tokens.length === 0 || ret.tokens[ret.tokens.length - 1].scopes !== type) {
ret.tokens.push({
startIndex: startIndex,
scopes: type
});
}
}
var isTypeScript = state.language === Language.TypeScript;
// shebang statement, #! /bin/node
if (!isTypeScript && checkSheBang(0, text, appendFn)) {
return ret;
}
var result = classifier.getClassificationsForLine(text, state.eolState, true),
offset = 0;
ret.endState.eolState = result.finalLexState;
ret.endState.inJsDocComment = result.finalLexState === ts.EndOfLineState.InMultiLineCommentTrivia && (state.inJsDocComment || /\/\*\*.*$/.test(text));
for (let entry of result.entries) {
var type: string;
if (entry.classification === ts.TokenClass.Punctuation) {
// punctions: check for brackets: (){}[]
var ch = text.charCodeAt(offset);
type = bracketTypeTable[ch] || tokenTypeTable[entry.classification];
appendFn(offset, type);
} else if (entry.classification === ts.TokenClass.Comment) {
// comments: check for JSDoc, block, and line comments
if (ret.endState.inJsDocComment || /\/\*\*.*\*\//.test(text.substr(offset, entry.length))) {
appendFn(offset, isTypeScript ? 'comment.doc.ts' : 'comment.doc.js');
} else {
appendFn(offset, isTypeScript ? 'comment.ts' : 'comment.js');
}
} else {
// everything else
appendFn(offset,
tokenTypeTable[entry.classification] || '');
}
offset += entry.length;
}
return ret;
}
interface INumberStringDictionary {
[idx: number]: string;
}
var tsBracketTypeTable:INumberStringDictionary = Object.create(null);
tsBracketTypeTable['('.charCodeAt(0)] = 'delimiter.parenthesis.ts';
tsBracketTypeTable[')'.charCodeAt(0)] = 'delimiter.parenthesis.ts';
tsBracketTypeTable['{'.charCodeAt(0)] = 'delimiter.bracket.ts';
tsBracketTypeTable['}'.charCodeAt(0)] = 'delimiter.bracket.ts';
tsBracketTypeTable['['.charCodeAt(0)] = 'delimiter.array.ts';
tsBracketTypeTable[']'.charCodeAt(0)] = 'delimiter.array.ts';
var tsTokenTypeTable:INumberStringDictionary = Object.create(null);
tsTokenTypeTable[ts.TokenClass.Identifier] = 'identifier.ts';
tsTokenTypeTable[ts.TokenClass.Keyword] = 'keyword.ts';
tsTokenTypeTable[ts.TokenClass.Operator] = 'delimiter.ts';
tsTokenTypeTable[ts.TokenClass.Punctuation] = 'delimiter.ts';
tsTokenTypeTable[ts.TokenClass.NumberLiteral] = 'number.ts';
tsTokenTypeTable[ts.TokenClass.RegExpLiteral] = 'regexp.ts';
tsTokenTypeTable[ts.TokenClass.StringLiteral] = 'string.ts';
var jsBracketTypeTable:INumberStringDictionary = Object.create(null);
jsBracketTypeTable['('.charCodeAt(0)] = 'delimiter.parenthesis.js';
jsBracketTypeTable[')'.charCodeAt(0)] = 'delimiter.parenthesis.js';
jsBracketTypeTable['{'.charCodeAt(0)] = 'delimiter.bracket.js';
jsBracketTypeTable['}'.charCodeAt(0)] = 'delimiter.bracket.js';
jsBracketTypeTable['['.charCodeAt(0)] = 'delimiter.array.js';
jsBracketTypeTable[']'.charCodeAt(0)] = 'delimiter.array.js';
var jsTokenTypeTable:INumberStringDictionary = Object.create(null);
jsTokenTypeTable[ts.TokenClass.Identifier] = 'identifier.js';
jsTokenTypeTable[ts.TokenClass.Keyword] = 'keyword.js';
jsTokenTypeTable[ts.TokenClass.Operator] = 'delimiter.js';
jsTokenTypeTable[ts.TokenClass.Punctuation] = 'delimiter.js';
jsTokenTypeTable[ts.TokenClass.NumberLiteral] = 'number.js';
jsTokenTypeTable[ts.TokenClass.RegExpLiteral] = 'regexp.js';
jsTokenTypeTable[ts.TokenClass.StringLiteral] = 'string.js';
function checkSheBang(deltaOffset: number, line: string, appendFn: (startIndex: number, type: string) => void): boolean {
if (line.indexOf('#!') === 0) {
appendFn(deltaOffset, 'comment.shebang');
return true;
}
}

96
src/typescript.ts Normal file
View file

@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as ts from '../lib/typescriptServices';
import {TypeScriptWorker} from './worker';
import Emitter = monaco.Emitter;
import Promise = monaco.Promise;
import Uri = monaco.Uri;
import IDisposable = monaco.IDisposable;
// --- TypeScript configuration and defaults ---------
export interface DiagnosticsOptions {
noSemanticValidation?: boolean;
noSyntaxValidation?: boolean;
}
export class LanguageServiceDefaults {
private _onDidChange = new Emitter<LanguageServiceDefaults>();
private _extraLibs: { [path: string]: string };
private _compilerOptions: ts.CompilerOptions;
private _diagnosticsOptions: DiagnosticsOptions;
constructor(compilerOptions: ts.CompilerOptions, diagnosticsOptions: DiagnosticsOptions) {
this._extraLibs = Object.create(null);
this.setCompilerOptions(compilerOptions);
this.setDiagnosticsOptions(diagnosticsOptions);
}
get onDidChange(): monaco.IEvent<LanguageServiceDefaults>{
return this._onDidChange.event;
}
get extraLibs(): { [path: string]: string } {
return Object.freeze(this._extraLibs);
}
addExtraLib(content: string, filePath?: string): IDisposable {
if (typeof filePath === 'undefined') {
filePath = `ts:extralib-${Date.now()}`;
}
if (this._extraLibs[filePath]) {
throw new Error(`${filePath} already a extra lib`);
}
this._extraLibs[filePath] = content;
this._onDidChange.fire(this);
return {
dispose: () => {
if (delete this._extraLibs[filePath]) {
this._onDidChange.fire(this);
}
}
};
}
get compilerOptions(): ts.CompilerOptions {
return this._compilerOptions;
}
setCompilerOptions(options: ts.CompilerOptions): void {
this._compilerOptions = options || Object.create(null);
this._onDidChange.fire(this);
}
get diagnosticsOptions(): DiagnosticsOptions {
return this._diagnosticsOptions;
}
setDiagnosticsOptions(options: DiagnosticsOptions): void {
this._diagnosticsOptions = options || Object.create(null);
this._onDidChange.fire(this);
}
}
export const typeScriptDefaults = new LanguageServiceDefaults(
{ allowNonTsExtensions: true, target: ts.ScriptTarget.Latest },
{ noSemanticValidation: false, noSyntaxValidation: false });
export const javaScriptDefaults = new LanguageServiceDefaults(
{ allowNonTsExtensions: true, allowJs: true, target: ts.ScriptTarget.Latest },
{ noSemanticValidation: true, noSyntaxValidation: false });
// --- TypeScript worker protocol ---------
export interface LanguageServiceMode {
getLanguageServiceWorker(...resources: Uri[]): Promise<TypeScriptWorker>;
}

181
src/worker.ts Normal file
View file

@ -0,0 +1,181 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import ts = require('../lib/typescriptServices');
import {contents as libdts} from '../lib/lib-ts';
import {contents as libes6ts} from '../lib/lib-es6-ts';
import Promise = monaco.Promise;
const DEFAULT_LIB = {
NAME: 'defaultLib:lib.d.ts',
CONTENTS: libdts
};
const ES6_LIB = {
NAME: 'defaultLib:lib.es6.d.ts',
CONTENTS: libes6ts
};
export class TypeScriptWorker implements ts.LanguageServiceHost {
// --- model sync -----------------------
// private _models: { [uri: string]: MirrorModel2 } = Object.create(null);
private _extraLibs: { [fileName: string]: string } = Object.create(null);
private _languageService = ts.createLanguageService(this);
private _compilerOptions: ts.CompilerOptions;
// --- default ---------
acceptDefaults(options:ts.CompilerOptions, extraLibs:{ [path: string]: string }): Promise<void> {
this._compilerOptions = options;
this._extraLibs = extraLibs;
return;
}
// --- language service host ---------------
getCompilationSettings(): ts.CompilerOptions {
return this._compilerOptions;
}
getScriptFileNames(): string[] {
let models = monaco.worker.mirrorModels.map(model => model.uri.toString());
return models.concat(Object.keys(this._extraLibs));
}
private _getModel(fileName:string): monaco.worker.IMirrorModel {
let models = monaco.worker.mirrorModels;
for (let i = 0; i < models.length; i++) {
if (models[i].uri.toString() === fileName) {
return models[i];
}
}
return null;
}
getScriptVersion(fileName: string): string {
let model = this._getModel(fileName);
if (model) {
return model.version.toString();
} else if (this.isDefaultLibFileName(fileName) || fileName in this._extraLibs) {
// extra lib and default lib are static
return '1';
}
}
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
let text: string;
let model = this._getModel(fileName);
if (model) {
// a true editor model
text = model.getText();
} else if (fileName in this._extraLibs) {
// static extra lib
text = this._extraLibs[fileName];
} else if (fileName === DEFAULT_LIB.NAME) {
text = DEFAULT_LIB.CONTENTS;
} else if (fileName === ES6_LIB.NAME) {
text = ES6_LIB.CONTENTS;
} else {
return;
}
return <ts.IScriptSnapshot>{
getText: (start, end) => text.substring(start, end),
getLength: () => text.length,
getChangeRange: () => undefined
};
}
getCurrentDirectory(): string {
return '';
}
getDefaultLibFileName(options: ts.CompilerOptions): string {
// TODO@joh support lib.es7.d.ts
return options.target > ts.ScriptTarget.ES5 ? DEFAULT_LIB.NAME : ES6_LIB.NAME;
}
isDefaultLibFileName(fileName: string): boolean {
return fileName === this.getDefaultLibFileName(this._compilerOptions);
}
// --- language features
getSyntacticDiagnostics(fileName: string): Promise<ts.Diagnostic[]> {
const diagnostics = this._languageService.getSyntacticDiagnostics(fileName);
diagnostics.forEach(diag => diag.file = undefined); // diag.file cannot be JSON'yfied
return Promise.as(diagnostics);
}
getSemanticDiagnostics(fileName: string): Promise<ts.Diagnostic[]> {
const diagnostics = this._languageService.getSemanticDiagnostics(fileName);
diagnostics.forEach(diag => diag.file = undefined); // diag.file cannot be JSON'yfied
return Promise.as(diagnostics);
}
getCompilerOptionsDiagnostics(fileName: string): Promise<ts.Diagnostic[]> {
const diagnostics = this._languageService.getCompilerOptionsDiagnostics();
diagnostics.forEach(diag => diag.file = undefined); // diag.file cannot be JSON'yfied
return Promise.as(diagnostics);
}
getCompletionsAtPosition(fileName: string, position:number): Promise<ts.CompletionInfo> {
return Promise.as(this._languageService.getCompletionsAtPosition(fileName, position));
}
getCompletionEntryDetails(fileName: string, position: number, entry: string): Promise<ts.CompletionEntryDetails> {
return Promise.as(this._languageService.getCompletionEntryDetails(fileName, position, entry));
}
getSignatureHelpItems(fileName: string, position:number): Promise<ts.SignatureHelpItems> {
return Promise.as(this._languageService.getSignatureHelpItems(fileName, position));
}
getQuickInfoAtPosition(fileName: string, position: number): Promise<ts.QuickInfo> {
return Promise.as(this._languageService.getQuickInfoAtPosition(fileName, position));
}
getOccurrencesAtPosition(fileName: string, position: number): Promise<ts.ReferenceEntry[]> {
return Promise.as(this._languageService.getOccurrencesAtPosition(fileName, position));
}
getDefinitionAtPosition(fileName: string, position: number): Promise<ts.DefinitionInfo[]> {
return Promise.as(this._languageService.getDefinitionAtPosition(fileName, position));
}
getReferencesAtPosition(fileName: string, position: number): Promise<ts.ReferenceEntry[]> {
return Promise.as(this._languageService.getReferencesAtPosition(fileName, position));
}
getNavigationBarItems(fileName: string): Promise<ts.NavigationBarItem[]> {
return Promise.as(this._languageService.getNavigationBarItems(fileName));
}
getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
return Promise.as(this._languageService.getFormattingEditsForDocument(fileName, options));
}
getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
return Promise.as(this._languageService.getFormattingEditsForRange(fileName, start, end, options));
}
getFormattingEditsAfterKeystroke(fileName: string, postion: number, ch: string, options: ts.FormatCodeOptions): Promise<ts.TextChange[]> {
return Promise.as(this._languageService.getFormattingEditsAfterKeystroke(fileName, postion, ch, options));
}
getEmitOutput(fileName: string): Promise<ts.EmitOutput> {
return Promise.as(this._languageService.getEmitOutput(fileName));
}
}
export function create(): TypeScriptWorker {
return new TypeScriptWorker();
}

104
src/workerManager.ts Normal file
View file

@ -0,0 +1,104 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {LanguageServiceMode, LanguageServiceDefaults} from './typescript';
import {TypeScriptWorker} from './worker';
import Promise = monaco.Promise;
import IDisposable = monaco.IDisposable;
import Uri = monaco.Uri;
const STOP_WHEN_IDLE_FOR = 2 * 60 * 1000; // 2min
export class WorkerManager {
private _defaults: LanguageServiceDefaults;
private _idleCheckInterval: number;
private _lastUsedTime: number;
private _configChangeListener: IDisposable;
private _worker: monaco.editor.MonacoWebWorker<TypeScriptWorker>;
private _client: Promise<TypeScriptWorker>;
constructor(defaults: LanguageServiceDefaults) {
this._defaults = defaults;
this._worker = null;
this._idleCheckInterval = setInterval(() => this._checkIfIdle(), 30 * 1000);
this._lastUsedTime = 0;
this._configChangeListener = this._defaults.onDidChange(() => this._stopWorker());
}
private _stopWorker(): void {
if (this._worker) {
this._worker.dispose();
this._worker = null;
}
this._client = null;
}
dispose(): void {
clearInterval(this._idleCheckInterval);
this._configChangeListener.dispose();
this._stopWorker();
}
private _checkIfIdle(): void {
if (!this._worker) {
return;
}
let timePassedSinceLastUsed = Date.now() - this._lastUsedTime;
if (timePassedSinceLastUsed > STOP_WHEN_IDLE_FOR) {
this._stopWorker();
}
}
private _getClient(): Promise<TypeScriptWorker> {
this._lastUsedTime = Date.now();
if (!this._client) {
this._worker = monaco.editor.createWebWorker<TypeScriptWorker>({
moduleId: 'vs/language/typescript/src/worker',
});
let _client:TypeScriptWorker = null;
// avoid cancellation
this._client = toShallowCancelPromise(
this._worker.getProxy().then((client) => {
_client = client;
}).then(_ => {
const {compilerOptions, extraLibs} = this._defaults;
return _client.acceptDefaults(compilerOptions, extraLibs);
}).then(_ => _client)
);
}
return this._client;
}
getLanguageServiceWorker(...resources: Uri[]): Promise<TypeScriptWorker> {
let _client:TypeScriptWorker;
return this._getClient().then((client) => {
_client = client
}).then(_ => {
return this._worker.withSyncedResources(resources)
}).then(_ => _client);
}
}
function toShallowCancelPromise<T>(p:Promise<T>): Promise<T> {
let completeCallback: (value:T)=>void;
let errorCallback: (err:any)=>void;
let r = new Promise<T>((c, e) => {
completeCallback = c;
errorCallback = e;
}, () => { });
p.then(completeCallback, errorCallback);
return r;
}

12
test/all.js Normal file
View file

@ -0,0 +1,12 @@
var requirejs = require("requirejs");
requirejs.config({
baseUrl: 'out',
nodeRequire: require
});
requirejs([
'test/tokenization.test'
], function() {
run(); // We can launch the tests!
});

44
test/assert.d.ts vendored Normal file
View file

@ -0,0 +1,44 @@
declare module "assert" {
function internal (value: any, message?: string): void;
namespace internal {
export class AssertionError implements Error {
name: string;
message: string;
actual: any;
expected: any;
operator: string;
generatedMessage: boolean;
constructor(options?: {message?: string; actual?: any; expected?: any;
operator?: string; stackStartFunction?: Function});
}
export function fail(actual?: any, expected?: any, message?: string, operator?: string): void;
export function ok(value: any, message?: string): void;
export function equal(actual: any, expected: any, message?: string): void;
export function notEqual(actual: any, expected: any, message?: string): void;
export function deepEqual(actual: any, expected: any, message?: string): void;
export function notDeepEqual(acutal: any, expected: any, message?: string): void;
export function strictEqual(actual: any, expected: any, message?: string): void;
export function notStrictEqual(actual: any, expected: any, message?: string): void;
export function deepStrictEqual(actual: any, expected: any, message?: string): void;
export function notDeepStrictEqual(actual: any, expected: any, message?: string): void;
export var throws: {
(block: Function, message?: string): void;
(block: Function, error: Function, message?: string): void;
(block: Function, error: RegExp, message?: string): void;
(block: Function, error: (err: any) => boolean, message?: string): void;
};
export var doesNotThrow: {
(block: Function, message?: string): void;
(block: Function, error: Function, message?: string): void;
(block: Function, error: RegExp, message?: string): void;
(block: Function, error: (err: any) => boolean, message?: string): void;
};
export function ifError(value: any): void;
}
export = internal;
}

13
test/mocha.d.ts vendored Normal file
View file

@ -0,0 +1,13 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
declare function run(): void;
declare function suite(name: string, fn: (err?)=>void);
declare function test(name: string, fn: (done?: (err?)=>void)=>void);
declare function suiteSetup(fn: (done?: (err?)=>void)=>void);
declare function suiteTeardown(fn: (done?: (err?)=>void)=>void);
declare function setup(fn: (done?: (err?)=>void)=>void);
declare function teardown(fn: (done?: (err?)=>void)=>void);

3
test/mocha.opts Normal file
View file

@ -0,0 +1,3 @@
--delay
--ui tdd
test/all.js

502
test/tokenization.test.ts Normal file
View file

@ -0,0 +1,502 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import {createTokenizationSupport, Language} from '../src/tokenization';
suite('tokenization', () => {
interface ITestItem {
line: string;
tokens: monaco.languages.IToken[];
}
function executeTokenizationTests(tests:ITestItem[][]): void {
let tokenizationSupport = createTokenizationSupport(Language.EcmaScript5);
for (let i = 0, len = tests.length; i < len; i++) {
assert.ok(true, 'TEST #' + i);
executeTokenizationTest(tokenizationSupport, tests[i]);
}
}
function executeTokenizationTest(tokenizationSupport: monaco.languages.TokensProvider, tests:ITestItem[]): void {
let state = tokenizationSupport.getInitialState();
for (let i = 0, len = tests.length; i < len; i++) {
assert.ok(true, tests[i].line);
let result = tokenizationSupport.tokenize(tests[i].line, state);
if (tests[i].tokens) {
assert.deepEqual(result.tokens, tests[i].tokens, 'Tokenizing line ' + tests[i].line + ': ' + JSON.stringify(tests[i].tokens, null, '\t'));
}
state = result.endState;
}
}
test('', () => {
executeTokenizationTests([
// Keywords
[{
line: 'var x = function() { };',
tokens: [
{ startIndex: 0, scopes: 'keyword.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'identifier.js' },
{ startIndex: 5, scopes: '' },
{ startIndex: 6, scopes: 'delimiter.js' },
{ startIndex: 7, scopes: '' },
{ startIndex: 8, scopes: 'keyword.js' },
{ startIndex: 16, scopes: 'delimiter.parenthesis.js' },
{ startIndex: 18, scopes: '' },
{ startIndex: 19, scopes: 'delimiter.bracket.js' },
{ startIndex: 20, scopes: '' },
{ startIndex: 21, scopes: 'delimiter.bracket.js' },
{ startIndex: 22, scopes: 'delimiter.js' }
]}],
[{
line: ' var ',
tokens: [
{ startIndex: 0, scopes: '' },
{ startIndex: 4, scopes: 'keyword.js' },
{ startIndex: 7, scopes: '' }
]}],
// Comments - single line
[{
line: '//',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: ' // a comment',
tokens: [
{ startIndex: 0, scopes: '' },
{ startIndex: 4, scopes: 'comment.js' }
]}],
[{
line: '// a comment',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: '// a comment /*',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: '// a comment /**',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: '//sticky comment',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: 'var x = 1; // my comment // is a nice one',
tokens: [
{ startIndex: 0, scopes: 'keyword.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'identifier.js' },
{ startIndex: 5, scopes: '' },
{ startIndex: 6, scopes: 'delimiter.js' },
{ startIndex: 7, scopes: '' },
{ startIndex: 8, scopes: 'number.js' },
{ startIndex: 9, scopes: 'delimiter.js' },
{ startIndex: 10, scopes: '' },
{ startIndex: 11, scopes: 'comment.js' }
]}],
// Comments - range comment, single line
[{
line: '/* a simple comment */',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: 'var x = /* a simple comment */ 1;',
tokens: [
{ startIndex: 0, scopes: 'keyword.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'identifier.js' },
{ startIndex: 5, scopes: '' },
{ startIndex: 6, scopes: 'delimiter.js' },
{ startIndex: 7, scopes: '' },
{ startIndex: 8, scopes: 'comment.js' },
{ startIndex: 30, scopes: '' },
{ startIndex: 31, scopes: 'number.js' },
{ startIndex: 32, scopes: 'delimiter.js' }
]}],
[{
line: 'x = /**/;',
tokens: [
{ startIndex: 0, scopes: 'identifier.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'comment.js' },
{ startIndex: 8, scopes: 'delimiter.js' }
]}],
[{
line: 'x = /*/;',
tokens: [
{ startIndex: 0, scopes: 'identifier.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'comment.js' }
]}],
// Comments - range comment, multi lines
[{
line: '/* a multiline comment',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}, {
line: 'can actually span',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}, {
line: 'multiple lines */',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: 'var x = /* start a comment',
tokens: [
{ startIndex: 0, scopes: 'keyword.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'identifier.js' },
{ startIndex: 5, scopes: '' },
{ startIndex: 6, scopes: 'delimiter.js' },
{ startIndex: 7, scopes: '' },
{ startIndex: 8, scopes: 'comment.js' }
]}, {
line: ' a ',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}, {
line: 'and end it */ var a = 2;',
tokens: [
{ startIndex: 0, scopes: 'comment.js' },
{ startIndex: 13, scopes: '' },
{ startIndex: 14, scopes: 'keyword.js' },
{ startIndex: 17, scopes: '' },
{ startIndex: 18, scopes: 'identifier.js' },
{ startIndex: 19, scopes: '' },
{ startIndex: 20, scopes: 'delimiter.js' },
{ startIndex: 21, scopes: '' },
{ startIndex: 22, scopes: 'number.js' },
{ startIndex: 23, scopes: 'delimiter.js' }
]}],
// Strings
[{
line: 'var a = \'a\';',
tokens: [
{ startIndex: 0, scopes: 'keyword.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'identifier.js' },
{ startIndex: 5, scopes: '' },
{ startIndex: 6, scopes: 'delimiter.js' },
{ startIndex: 7, scopes: '' },
{ startIndex: 8, scopes: 'string.js' },
{ startIndex: 11, scopes: 'delimiter.js' }
]}],
[{
line: '"use strict";',
tokens: [
{ startIndex: 0, scopes: 'string.js' },
{ startIndex: 12, scopes: 'delimiter.js' }
]}],
[{
line: 'b = a + " \'cool\' "',
tokens: [
{ startIndex: 0, scopes: 'identifier.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'identifier.js' },
{ startIndex: 5, scopes: '' },
{ startIndex: 6, scopes: 'delimiter.js' },
{ startIndex: 7, scopes: '' },
{ startIndex: 8, scopes: 'string.js' }
]}],
[{
line: '"escaping \\"quotes\\" is cool"',
tokens: [
{ startIndex: 0, scopes: 'string.js' }
]}],
[{
line: '\'\'\'',
tokens: [
{ startIndex: 0, scopes: 'string.js' }
]}],
[{
line: '\'\\\'\'',
tokens: [
{ startIndex: 0, scopes: 'string.js' }
]}],
[{
line: '\'be careful \\not to escape\'',
tokens: [
{ startIndex: 0, scopes: 'string.js' }
]}],
// Numbers
[{
line: '0',
tokens: [
{ startIndex: 0, scopes: 'number.js' }
]}],
[{
line: ' 0',
tokens: [
{ startIndex: 0, scopes: '' },
{ startIndex: 1, scopes: 'number.js' }
]}],
[{
line: ' 0 ',
tokens: [
{ startIndex: 0, scopes: '' },
{ startIndex: 1, scopes: 'number.js' },
{ startIndex: 2, scopes: '' }
]}],
[{
line: '0 ',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 1, scopes: '' }
]}],
[{
line: '0+0',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 1, scopes: 'delimiter.js' },
{ startIndex: 2, scopes: 'number.js' }
]}],
[{
line: '100+10',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 3, scopes: 'delimiter.js' },
{ startIndex: 4, scopes: 'number.js' }
]}],
[{
line: '0 + 0',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'number.js' }
]}],
[{
line: '0123',
tokens: [
{ startIndex: 0, scopes: 'number.js' }
]}],
[{
line: '01239',
tokens: [
{ startIndex: 0, scopes: 'number.js' }
]}],
[{
line: '0x',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 1, scopes: 'identifier.js' }
]}],
[{
line: '0x123',
tokens: [
{ startIndex: 0, scopes: 'number.js' }
]}],
// Regular Expressions
[{
line: '//',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: '/**/',
tokens: [
{ startIndex: 0, scopes: 'comment.js' }
]}],
[{
line: '/***/',
tokens: [
{ startIndex: 0, scopes: 'comment.doc.js' }
]}],
[{
line: '5 / 3;',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'number.js' },
{ startIndex: 5, scopes: 'delimiter.js' }
]}],
// Advanced regular expressions
[{
line: '1 / 2; /* comment',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'number.js' },
{ startIndex: 5, scopes: 'delimiter.js' },
{ startIndex: 6, scopes: '' },
{ startIndex: 7, scopes: 'comment.js' }
]}],
[{
line: '1 / 2 / x / b;',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'number.js' },
{ startIndex: 5, scopes: '' },
{ startIndex: 6, scopes: 'delimiter.js' },
{ startIndex: 7, scopes: '' },
{ startIndex: 8, scopes: 'identifier.js' },
{ startIndex: 9, scopes: '' },
{ startIndex: 10, scopes: 'delimiter.js' },
{ startIndex: 11, scopes: '' },
{ startIndex: 12, scopes: 'identifier.js' },
{ startIndex: 13, scopes: 'delimiter.js' }
]}],
[{
line: 'a /ads/ b;',
tokens: [
{ startIndex: 0, scopes: 'identifier.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: 'identifier.js' },
{ startIndex: 6, scopes: 'delimiter.js' },
{ startIndex: 7, scopes: '' },
{ startIndex: 8, scopes: 'identifier.js' },
{ startIndex: 9, scopes: 'delimiter.js' }
]}],
[{
line: '1/(2/3)/2/3;',
tokens: [
{ startIndex: 0, scopes: 'number.js' },
{ startIndex: 1, scopes: 'delimiter.js' },
{ startIndex: 2, scopes: 'delimiter.parenthesis.js' },
{ startIndex: 3, scopes: 'number.js' },
{ startIndex: 4, scopes: 'delimiter.js' },
{ startIndex: 5, scopes: 'number.js' },
{ startIndex: 6, scopes: 'delimiter.parenthesis.js' },
{ startIndex: 7, scopes: 'delimiter.js' },
{ startIndex: 8, scopes: 'number.js' },
{ startIndex: 9, scopes: 'delimiter.js' },
{ startIndex: 10, scopes: 'number.js' },
{ startIndex: 11, scopes: 'delimiter.js' }
]}],
[{
line: '{ key: 123 }',
tokens: [
{ startIndex: 0, scopes: 'delimiter.bracket.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'identifier.js' },
{ startIndex: 5, scopes: 'delimiter.js' },
{ startIndex: 6, scopes: '' },
{ startIndex: 7, scopes: 'number.js' },
{ startIndex: 10, scopes: '' },
{ startIndex: 11, scopes: 'delimiter.bracket.js' }
]}],
[{
line: '[1,2,3]',
tokens: [
{ startIndex: 0, scopes: 'delimiter.array.js' },
{ startIndex: 1, scopes: 'number.js' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: 'number.js' },
{ startIndex: 4, scopes: 'delimiter.js' },
{ startIndex: 5, scopes: 'number.js' },
{ startIndex: 6, scopes: 'delimiter.array.js' }
]}],
[{
line: 'foo(123);',
tokens: [
{ startIndex: 0, scopes: 'identifier.js' },
{ startIndex: 3, scopes: 'delimiter.parenthesis.js' },
{ startIndex: 4, scopes: 'number.js' },
{ startIndex: 7, scopes: 'delimiter.parenthesis.js' },
{ startIndex: 8, scopes: 'delimiter.js' }
]}],
[{
line: '{a:{b:[]}}',
tokens: [
{ startIndex: 0, scopes: 'delimiter.bracket.js' },
{ startIndex: 1, scopes: 'identifier.js' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: 'delimiter.bracket.js' },
{ startIndex: 4, scopes: 'identifier.js' },
{ startIndex: 5, scopes: 'delimiter.js' },
{ startIndex: 6, scopes: 'delimiter.array.js' },
{ startIndex: 8, scopes: 'delimiter.bracket.js' }
]}],
[{
line: 'x = "[{()}]"',
tokens: [
{ startIndex: 0, scopes: 'identifier.js' },
{ startIndex: 1, scopes: '' },
{ startIndex: 2, scopes: 'delimiter.js' },
{ startIndex: 3, scopes: '' },
{ startIndex: 4, scopes: 'string.js' }
]}]
]);
});
})

29
tsconfig.json Normal file
View file

@ -0,0 +1,29 @@
{
"compilerOptions": {
"module": "amd",
"outDir": "out",
"target": "es5"
},
"filesGlob": [
"src/*.ts",
"test/*.ts",
"lib/*.d.ts",
"node_modules/monaco-editor-core/monaco.d.ts"
],
"files": [
"src/languageFeatures.ts",
"src/mode.ts",
"src/monaco.contribution.ts",
"src/tokenization.ts",
"src/typescript.ts",
"src/worker.ts",
"src/workerManager.ts",
"test/assert.d.ts",
"test/mocha.d.ts",
"test/tokenization.test.ts",
"lib/lib-es6-ts.d.ts",
"lib/lib-ts.d.ts",
"lib/typescriptServices.d.ts",
"node_modules/monaco-editor-core/monaco.d.ts"
]
}