mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-23 10:29:01 -06:00
Merge branch 'master' into warnaserror
Conflicts: src/compiler/diagnosticInformationMap.generated.ts src/compiler/diagnosticMessages.json src/compiler/types.ts src/harness/harness.ts
This commit is contained in:
commit
e7bb2e0ba7
1
.gitignore
vendored
1
.gitignore
vendored
@ -32,6 +32,7 @@ build.json
|
||||
tests/webhost/*.d.ts
|
||||
tests/webhost/webtsc.js
|
||||
tests/*.js
|
||||
tests/*.js.map
|
||||
tests/*.d.ts
|
||||
*.config
|
||||
scripts/debug.bat
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- '0.10'
|
||||
- '0.10'
|
||||
|
||||
sudo: false
|
||||
|
||||
before_script: npm install -g codeclimate-test-reporter
|
||||
|
||||
after_script:
|
||||
- cat coverage/lcov.info | codeclimate
|
||||
- cat coverage/lcov.info | codeclimate
|
||||
|
||||
addons:
|
||||
code_climate:
|
||||
|
||||
25
Jakefile
25
Jakefile
@ -82,8 +82,9 @@ var harnessSources = [
|
||||
].map(function (f) {
|
||||
return path.join(harnessDirectory, f);
|
||||
}).concat([
|
||||
"services/colorization.ts",
|
||||
"services/documentRegistry.ts"
|
||||
"services/colorization.ts",
|
||||
"services/documentRegistry.ts",
|
||||
"services/preProcessFile.ts"
|
||||
].map(function (f) {
|
||||
return path.join(unittestsDirectory, f);
|
||||
}));
|
||||
@ -133,7 +134,7 @@ function concatenateFiles(destinationFile, sourceFiles) {
|
||||
fs.renameSync(temp, destinationFile);
|
||||
}
|
||||
|
||||
var useDebugMode = false;
|
||||
var useDebugMode = true;
|
||||
var generateDeclarations = false;
|
||||
var host = (process.env.host || process.env.TYPESCRIPT_HOST || "node");
|
||||
var compilerFilename = "tsc.js";
|
||||
@ -148,15 +149,16 @@ var compilerFilename = "tsc.js";
|
||||
function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOutFile) {
|
||||
file(outFile, prereqs, function() {
|
||||
var dir = useBuiltCompiler ? builtLocalDirectory : LKGDirectory;
|
||||
var options = "-removeComments --module commonjs -noImplicitAny "; //" -propagateEnumConstants "
|
||||
var options = "-removeComments --module commonjs -noImplicitAny ";
|
||||
if (generateDeclarations) {
|
||||
options += "--declaration ";
|
||||
}
|
||||
|
||||
if (useDebugMode) {
|
||||
options += "--preserveConstEnums ";
|
||||
}
|
||||
|
||||
var cmd = host + " " + dir + compilerFilename + " " + options + " ";
|
||||
if (useDebugMode) {
|
||||
cmd = cmd + " " + path.join(harnessDirectory, "external/es5compat.ts") + " " + path.join(harnessDirectory, "external/json2.ts") + " ";
|
||||
}
|
||||
cmd = cmd + sources.join(" ") + (!noOutFile ? " -out " + outFile : "");
|
||||
if (useDebugMode) {
|
||||
cmd = cmd + " -sourcemap -mapRoot file:///" + path.resolve(path.dirname(outFile));
|
||||
@ -258,12 +260,11 @@ task("local", ["generate-diagnostics", "lib", tscFile, servicesFile]);
|
||||
|
||||
|
||||
// Local target to build the compiler and services
|
||||
desc("Emit debug mode files with sourcemaps");
|
||||
task("debug", function() {
|
||||
useDebugMode = true;
|
||||
desc("Sets release mode flag");
|
||||
task("release", function() {
|
||||
useDebugMode = false;
|
||||
});
|
||||
|
||||
|
||||
// Set the default task to "local"
|
||||
task("default", ["local"]);
|
||||
|
||||
@ -312,7 +313,7 @@ task("generate-spec", [specMd])
|
||||
|
||||
// Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory
|
||||
desc("Makes a new LKG out of the built js files");
|
||||
task("LKG", libraryTargets, function() {
|
||||
task("LKG", ["clean", "release", "local"].concat(libraryTargets), function() {
|
||||
var expectedFiles = [tscFile, servicesFile].concat(libraryTargets);
|
||||
var missingFiles = expectedFiles.filter(function (f) {
|
||||
return !fs.existsSync(f);
|
||||
|
||||
6531
bin/tsc.js
6531
bin/tsc.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
580
doc/spec.md
580
doc/spec.md
File diff suppressed because it is too large
Load Diff
@ -5,25 +5,51 @@
|
||||
|
||||
module ts {
|
||||
|
||||
export function isInstantiated(node: Node): boolean {
|
||||
export const enum ModuleInstanceState {
|
||||
NonInstantiated = 0,
|
||||
Instantiated = 1,
|
||||
ConstEnumOnly = 2
|
||||
}
|
||||
|
||||
export function getModuleInstanceState(node: Node): ModuleInstanceState {
|
||||
// A module is uninstantiated if it contains only
|
||||
// 1. interface declarations
|
||||
if (node.kind === SyntaxKind.InterfaceDeclaration) {
|
||||
return false;
|
||||
return ModuleInstanceState.NonInstantiated;
|
||||
}
|
||||
// 2. non - exported import declarations
|
||||
// 2. const enum declarations don't make module instantiated
|
||||
else if (node.kind === SyntaxKind.EnumDeclaration && isConstEnumDeclaration(<EnumDeclaration>node)) {
|
||||
return ModuleInstanceState.ConstEnumOnly;
|
||||
}
|
||||
// 3. non - exported import declarations
|
||||
else if (node.kind === SyntaxKind.ImportDeclaration && !(node.flags & NodeFlags.Export)) {
|
||||
return false;
|
||||
return ModuleInstanceState.NonInstantiated;
|
||||
}
|
||||
// 3. other uninstantiated module declarations.
|
||||
else if (node.kind === SyntaxKind.ModuleBlock && !forEachChild(node, isInstantiated)) {
|
||||
return false;
|
||||
// 4. other uninstantiated module declarations.
|
||||
else if (node.kind === SyntaxKind.ModuleBlock) {
|
||||
var state = ModuleInstanceState.NonInstantiated;
|
||||
forEachChild(node, n => {
|
||||
switch (getModuleInstanceState(n)) {
|
||||
case ModuleInstanceState.NonInstantiated:
|
||||
// child is non-instantiated - continue searching
|
||||
return false;
|
||||
case ModuleInstanceState.ConstEnumOnly:
|
||||
// child is const enum only - record state and continue searching
|
||||
state = ModuleInstanceState.ConstEnumOnly;
|
||||
return false;
|
||||
case ModuleInstanceState.Instantiated:
|
||||
// child is instantiated - record state and stop
|
||||
state = ModuleInstanceState.Instantiated;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return state;
|
||||
}
|
||||
else if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated((<ModuleDeclaration>node).body)) {
|
||||
return false;
|
||||
else if (node.kind === SyntaxKind.ModuleDeclaration) {
|
||||
return getModuleInstanceState((<ModuleDeclaration>node).body);
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
return ModuleInstanceState.Instantiated;
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,23 +84,30 @@ module ts {
|
||||
if (symbolKind & SymbolFlags.Value && !symbol.valueDeclaration) symbol.valueDeclaration = node;
|
||||
}
|
||||
|
||||
// TODO(jfreeman): Implement getDeclarationName for property name
|
||||
function getDeclarationName(node: Declaration): string {
|
||||
if (node.name) {
|
||||
if (node.kind === SyntaxKind.ModuleDeclaration && node.name.kind === SyntaxKind.StringLiteral) {
|
||||
return '"' + node.name.text + '"';
|
||||
return '"' + (<LiteralExpression>node.name).text + '"';
|
||||
}
|
||||
return node.name.text;
|
||||
return (<Identifier>node.name).text;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor: return "__constructor";
|
||||
case SyntaxKind.CallSignature: return "__call";
|
||||
case SyntaxKind.ConstructSignature: return "__new";
|
||||
case SyntaxKind.IndexSignature: return "__index";
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.Constructor:
|
||||
return "__constructor";
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.CallSignature:
|
||||
return "__call";
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return "__new";
|
||||
case SyntaxKind.IndexSignature:
|
||||
return "__index";
|
||||
}
|
||||
}
|
||||
|
||||
function getDisplayName(node: Declaration): string {
|
||||
return node.name ? identifierToString(node.name) : getDeclarationName(node);
|
||||
return node.name ? declarationNameToString(node.name) : getDeclarationName(node);
|
||||
}
|
||||
|
||||
function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
|
||||
@ -87,8 +120,11 @@ module ts {
|
||||
}
|
||||
// Report errors every position with duplicate declaration
|
||||
// Report errors on previous encountered declarations
|
||||
var message = symbol.flags & SymbolFlags.BlockScopedVariable ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0;
|
||||
forEach(symbol.declarations, (declaration) => {
|
||||
var message = symbol.flags & SymbolFlags.BlockScopedVariable
|
||||
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
|
||||
: Diagnostics.Duplicate_identifier_0;
|
||||
|
||||
forEach(symbol.declarations, declaration => {
|
||||
file.semanticErrors.push(createDiagnosticForNode(declaration.name, message, getDisplayName(declaration)));
|
||||
});
|
||||
file.semanticErrors.push(createDiagnosticForNode(node.name, message, getDisplayName(node)));
|
||||
@ -206,6 +242,8 @@ module ts {
|
||||
declareModuleMember(node, symbolKind, symbolExcludes);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
@ -248,14 +286,44 @@ module ts {
|
||||
if (node.name.kind === SyntaxKind.StringLiteral) {
|
||||
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
|
||||
}
|
||||
else if (isInstantiated(node)) {
|
||||
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
|
||||
}
|
||||
else {
|
||||
bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes, /*isBlockScopeContainer*/ true);
|
||||
var state = getModuleInstanceState(node);
|
||||
if (state === ModuleInstanceState.NonInstantiated) {
|
||||
bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes, /*isBlockScopeContainer*/ true);
|
||||
}
|
||||
else {
|
||||
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes, /*isBlockScopeContainer*/ true);
|
||||
if (state === ModuleInstanceState.ConstEnumOnly) {
|
||||
// mark value module as module that contains only enums
|
||||
node.symbol.constEnumOnlyModule = true;
|
||||
}
|
||||
else if (node.symbol.constEnumOnlyModule) {
|
||||
// const only value module was merged with instantiated module - reset flag
|
||||
node.symbol.constEnumOnlyModule = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function bindFunctionOrConstructorType(node: SignatureDeclaration) {
|
||||
// For a given function symbol "<...>(...) => T" we want to generate a symbol identical
|
||||
// to the one we would get for: { <...>(...): T }
|
||||
//
|
||||
// We do that by making an anonymous type literal symbol, and then setting the function
|
||||
// symbol as its sole member. To the rest of the system, this symbol will be indistinguishable
|
||||
// from an actual type literal symbol you would have gotten had you used the long form.
|
||||
|
||||
var symbolKind = node.kind === SyntaxKind.FunctionType ? SymbolFlags.CallSignature : SymbolFlags.ConstructSignature;
|
||||
var symbol = createSymbol(symbolKind, getDeclarationName(node));
|
||||
addDeclarationToSymbol(symbol, node, symbolKind);
|
||||
bindChildren(node, symbolKind, /*isBlockScopeContainer:*/ false);
|
||||
|
||||
var typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
|
||||
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
|
||||
typeLiteralSymbol.members = {};
|
||||
typeLiteralSymbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = symbol
|
||||
}
|
||||
|
||||
function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string, isBlockScopeContainer: boolean) {
|
||||
var symbol = createSymbol(symbolKind, name);
|
||||
addDeclarationToSymbol(symbol, node, symbolKind);
|
||||
@ -320,12 +388,12 @@ module ts {
|
||||
case SyntaxKind.CallSignature:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.CallSignature, 0, /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
case SyntaxKind.Method:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true);
|
||||
break;
|
||||
case SyntaxKind.ConstructSignature:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.ConstructSignature, 0, /*isBlockScopeContainer*/ true);
|
||||
break;
|
||||
case SyntaxKind.Method:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true);
|
||||
break;
|
||||
case SyntaxKind.IndexSignature:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.IndexSignature, 0, /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
@ -341,6 +409,12 @@ module ts {
|
||||
case SyntaxKind.SetAccessor:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true);
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
bindFunctionOrConstructorType(<SignatureDeclaration>node);
|
||||
break;
|
||||
|
||||
case SyntaxKind.TypeLiteral:
|
||||
bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type", /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
@ -360,8 +434,16 @@ module ts {
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes, /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.Enum, SymbolFlags.EnumExcludes, /*isBlockScopeContainer*/ false);
|
||||
if (isConstEnumDeclaration(<EnumDeclaration>node)) {
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.ConstEnum, SymbolFlags.ConstEnumExcludes, /*isBlockScopeContainer*/ false);
|
||||
}
|
||||
else {
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.RegularEnum, SymbolFlags.RegularEnumExcludes, /*isBlockScopeContainer*/ false);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
bindModuleDeclaration(<ModuleDeclaration>node);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ module ts {
|
||||
type: "boolean",
|
||||
},
|
||||
{
|
||||
name: "emitBOM",
|
||||
name: "emitBOM",
|
||||
type: "boolean"
|
||||
},
|
||||
{
|
||||
@ -107,7 +107,7 @@ module ts {
|
||||
{
|
||||
name: "target",
|
||||
shortName: "t",
|
||||
type: { "es3": ScriptTarget.ES3, "es5": ScriptTarget.ES5 , "es6": ScriptTarget.ES6 },
|
||||
type: { "es3": ScriptTarget.ES3, "es5": ScriptTarget.ES5, "es6": ScriptTarget.ES6 },
|
||||
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental,
|
||||
paramType: Diagnostics.VERSION,
|
||||
error: Diagnostics.Argument_for_target_option_must_be_es3_es5_or_es6
|
||||
@ -123,6 +123,11 @@ module ts {
|
||||
shortName: "w",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Watch_input_files,
|
||||
},
|
||||
{
|
||||
name: "preserveConstEnums",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code
|
||||
}
|
||||
];
|
||||
|
||||
@ -188,9 +193,10 @@ module ts {
|
||||
break;
|
||||
// If not a primitive, the possible types are specified in what is effectively a map of options.
|
||||
default:
|
||||
var value = (args[i++] || "").toLowerCase();
|
||||
if (hasProperty(opt.type, value)) {
|
||||
options[opt.name] = opt.type[value];
|
||||
var map = <Map<number>>opt.type;
|
||||
var key = (args[i++] || "").toLowerCase();
|
||||
if (hasProperty(map, key)) {
|
||||
options[opt.name] = map[key];
|
||||
}
|
||||
else {
|
||||
errors.push(createCompilerDiagnostic(opt.error));
|
||||
|
||||
@ -1,10 +1,30 @@
|
||||
/// <reference path="types.ts"/>
|
||||
|
||||
module ts {
|
||||
|
||||
// Ternary values are defined such that
|
||||
// x & y is False if either x or y is False.
|
||||
// x & y is Maybe if either x or y is Maybe, but neither x or y is False.
|
||||
// x & y is True if both x and y are True.
|
||||
// x | y is False if both x and y are False.
|
||||
// x | y is Maybe if either x or y is Maybe, but neither x or y is True.
|
||||
// x | y is True if either x or y is True.
|
||||
export const enum Ternary {
|
||||
False = 0,
|
||||
Maybe = 1,
|
||||
True = -1
|
||||
}
|
||||
|
||||
export interface Map<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
export const enum Comparison {
|
||||
LessThan = -1,
|
||||
EqualTo = 0,
|
||||
GreaterThan = 1
|
||||
}
|
||||
|
||||
export interface StringSet extends Map<any> { }
|
||||
|
||||
export function forEach<T, U>(array: T[], callback: (element: T) => U): U {
|
||||
@ -79,6 +99,7 @@ module ts {
|
||||
export function concatenate<T>(array1: T[], array2: T[]): T[] {
|
||||
if (!array2 || !array2.length) return array1;
|
||||
if (!array1 || !array1.length) return array2;
|
||||
|
||||
return array1.concat(array2);
|
||||
}
|
||||
|
||||
@ -101,6 +122,17 @@ module ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last element of an array if non-empty, undefined otherwise.
|
||||
*/
|
||||
export function lastOrUndefined<T>(array: T[]): T {
|
||||
if (array.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return array[array.length - 1];
|
||||
}
|
||||
|
||||
export function binarySearch(array: number[], value: number): number {
|
||||
var low = 0;
|
||||
var high = array.length - 1;
|
||||
@ -274,6 +306,12 @@ module ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): DiagnosticMessageChain {
|
||||
Debug.assert(!headChain.next);
|
||||
headChain.next = tailChain;
|
||||
return headChain;
|
||||
}
|
||||
|
||||
export function flattenDiagnosticChain(file: SourceFile, start: number, length: number, diagnosticChain: DiagnosticMessageChain, newLine: string): Diagnostic {
|
||||
Debug.assert(start >= 0, "start must be non-negative, is " + start);
|
||||
Debug.assert(length >= 0, "length must be non-negative, is " + length);
|
||||
@ -306,11 +344,11 @@ module ts {
|
||||
};
|
||||
}
|
||||
|
||||
export function compareValues<T>(a: T, b: T): number {
|
||||
if (a === b) return 0;
|
||||
if (a === undefined) return -1;
|
||||
if (b === undefined) return 1;
|
||||
return a < b ? -1 : 1;
|
||||
export function compareValues<T>(a: T, b: T): Comparison {
|
||||
if (a === b) return Comparison.EqualTo;
|
||||
if (a === undefined) return Comparison.LessThan;
|
||||
if (b === undefined) return Comparison.GreaterThan;
|
||||
return a < b ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
}
|
||||
|
||||
function getDiagnosticFilename(diagnostic: Diagnostic): string {
|
||||
@ -335,7 +373,7 @@ module ts {
|
||||
var previousDiagnostic = diagnostics[0];
|
||||
for (var i = 1; i < diagnostics.length; i++) {
|
||||
var currentDiagnostic = diagnostics[i];
|
||||
var isDupe = compareDiagnostics(currentDiagnostic, previousDiagnostic) === 0;
|
||||
var isDupe = compareDiagnostics(currentDiagnostic, previousDiagnostic) === Comparison.EqualTo;
|
||||
if (!isDupe) {
|
||||
newDiagnostics.push(currentDiagnostic);
|
||||
previousDiagnostic = currentDiagnostic;
|
||||
@ -610,7 +648,7 @@ module ts {
|
||||
getSignatureConstructor: () => <any>Signature
|
||||
}
|
||||
|
||||
export enum AssertionLevel {
|
||||
export const enum AssertionLevel {
|
||||
None = 0,
|
||||
Normal = 1,
|
||||
Aggressive = 2,
|
||||
@ -624,7 +662,7 @@ module ts {
|
||||
return currentAssertionLevel >= level;
|
||||
}
|
||||
|
||||
export function assert(expression: any, message?: string, verboseDebugInfo?: () => string): void {
|
||||
export function assert(expression: boolean, message?: string, verboseDebugInfo?: () => string): void {
|
||||
if (!expression) {
|
||||
var verboseDebugString = "";
|
||||
if (verboseDebugInfo) {
|
||||
|
||||
@ -120,6 +120,8 @@ module ts {
|
||||
const_declarations_must_be_initialized: { code: 1155, category: DiagnosticCategory.Error, key: "'const' declarations must be initialized" },
|
||||
const_declarations_can_only_be_declared_inside_a_block: { code: 1156, category: DiagnosticCategory.Error, key: "'const' declarations can only be declared inside a block." },
|
||||
let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." },
|
||||
Invalid_template_literal_expected: { code: 1158, category: DiagnosticCategory.Error, key: "Invalid template literal; expected '}'" },
|
||||
Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1159, category: DiagnosticCategory.Error, key: "Tagged templates are only available when targeting ECMAScript 6 and higher." },
|
||||
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
|
||||
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
|
||||
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
|
||||
@ -140,17 +142,16 @@ module ts {
|
||||
Global_type_0_must_have_1_type_parameter_s: { code: 2317, category: DiagnosticCategory.Error, key: "Global type '{0}' must have {1} type parameter(s)." },
|
||||
Cannot_find_global_type_0: { code: 2318, category: DiagnosticCategory.Error, key: "Cannot find global type '{0}'." },
|
||||
Named_properties_0_of_types_1_and_2_are_not_identical: { code: 2319, category: DiagnosticCategory.Error, key: "Named properties '{0}' of types '{1}' and '{2}' are not identical." },
|
||||
Interface_0_cannot_simultaneously_extend_types_1_and_2_Colon: { code: 2320, category: DiagnosticCategory.Error, key: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':" },
|
||||
Interface_0_cannot_simultaneously_extend_types_1_and_2: { code: 2320, category: DiagnosticCategory.Error, key: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}'." },
|
||||
Excessive_stack_depth_comparing_types_0_and_1: { code: 2321, category: DiagnosticCategory.Error, key: "Excessive stack depth comparing types '{0}' and '{1}'." },
|
||||
Type_0_is_not_assignable_to_type_1_Colon: { code: 2322, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}':" },
|
||||
Type_0_is_not_assignable_to_type_1: { code: 2323, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}'." },
|
||||
Type_0_is_not_assignable_to_type_1: { code: 2322, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}'." },
|
||||
Property_0_is_missing_in_type_1: { code: 2324, category: DiagnosticCategory.Error, key: "Property '{0}' is missing in type '{1}'." },
|
||||
Property_0_is_private_in_type_1_but_not_in_type_2: { code: 2325, category: DiagnosticCategory.Error, key: "Property '{0}' is private in type '{1}' but not in type '{2}'." },
|
||||
Types_of_property_0_are_incompatible_Colon: { code: 2326, category: DiagnosticCategory.Error, key: "Types of property '{0}' are incompatible:" },
|
||||
Types_of_property_0_are_incompatible: { code: 2326, category: DiagnosticCategory.Error, key: "Types of property '{0}' are incompatible." },
|
||||
Property_0_is_optional_in_type_1_but_required_in_type_2: { code: 2327, category: DiagnosticCategory.Error, key: "Property '{0}' is optional in type '{1}' but required in type '{2}'." },
|
||||
Types_of_parameters_0_and_1_are_incompatible_Colon: { code: 2328, category: DiagnosticCategory.Error, key: "Types of parameters '{0}' and '{1}' are incompatible:" },
|
||||
Types_of_parameters_0_and_1_are_incompatible: { code: 2328, category: DiagnosticCategory.Error, key: "Types of parameters '{0}' and '{1}' are incompatible." },
|
||||
Index_signature_is_missing_in_type_0: { code: 2329, category: DiagnosticCategory.Error, key: "Index signature is missing in type '{0}'." },
|
||||
Index_signatures_are_incompatible_Colon: { code: 2330, category: DiagnosticCategory.Error, key: "Index signatures are incompatible:" },
|
||||
Index_signatures_are_incompatible: { code: 2330, category: DiagnosticCategory.Error, key: "Index signatures are incompatible." },
|
||||
this_cannot_be_referenced_in_a_module_body: { code: 2331, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a module body." },
|
||||
this_cannot_be_referenced_in_current_location: { code: 2332, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in current location." },
|
||||
this_cannot_be_referenced_in_constructor_arguments: { code: 2333, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in constructor arguments." },
|
||||
@ -163,7 +164,6 @@ module ts {
|
||||
Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public and protected methods of the base class are accessible via the 'super' keyword" },
|
||||
Property_0_is_private_and_only_accessible_within_class_1: { code: 2341, category: DiagnosticCategory.Error, key: "Property '{0}' is private and only accessible within class '{1}'." },
|
||||
An_index_expression_argument_must_be_of_type_string_number_or_any: { code: 2342, category: DiagnosticCategory.Error, key: "An index expression argument must be of type 'string', 'number', or 'any'." },
|
||||
Type_0_does_not_satisfy_the_constraint_1_Colon: { code: 2343, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}':" },
|
||||
Type_0_does_not_satisfy_the_constraint_1: { code: 2344, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}'." },
|
||||
Argument_of_type_0_is_not_assignable_to_parameter_of_type_1: { code: 2345, category: DiagnosticCategory.Error, key: "Argument of type '{0}' is not assignable to parameter of type '{1}'." },
|
||||
Supplied_parameters_do_not_match_any_signature_of_call_target: { code: 2346, category: DiagnosticCategory.Error, key: "Supplied parameters do not match any signature of call target." },
|
||||
@ -173,7 +173,6 @@ module ts {
|
||||
Only_a_void_function_can_be_called_with_the_new_keyword: { code: 2350, category: DiagnosticCategory.Error, key: "Only a void function can be called with the 'new' keyword." },
|
||||
Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature: { code: 2351, category: DiagnosticCategory.Error, key: "Cannot use 'new' with an expression whose type lacks a call or construct signature." },
|
||||
Neither_type_0_nor_type_1_is_assignable_to_the_other: { code: 2352, category: DiagnosticCategory.Error, key: "Neither type '{0}' nor type '{1}' is assignable to the other." },
|
||||
Neither_type_0_nor_type_1_is_assignable_to_the_other_Colon: { code: 2353, category: DiagnosticCategory.Error, key: "Neither type '{0}' nor type '{1}' is assignable to the other:" },
|
||||
No_best_common_type_exists_among_return_expressions: { code: 2354, category: DiagnosticCategory.Error, key: "No best common type exists among return expressions." },
|
||||
A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement: { code: 2355, category: DiagnosticCategory.Error, key: "A function whose declared type is neither 'void' nor 'any' must return a value or consist of a single 'throw' statement." },
|
||||
An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type: { code: 2356, category: DiagnosticCategory.Error, key: "An arithmetic operand must be of type 'any', 'number' or an enum type." },
|
||||
@ -234,12 +233,9 @@ module ts {
|
||||
Numeric_index_type_0_is_not_assignable_to_string_index_type_1: { code: 2413, category: DiagnosticCategory.Error, key: "Numeric index type '{0}' is not assignable to string index type '{1}'." },
|
||||
Class_name_cannot_be_0: { code: 2414, category: DiagnosticCategory.Error, key: "Class name cannot be '{0}'" },
|
||||
Class_0_incorrectly_extends_base_class_1: { code: 2415, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly extends base class '{1}'." },
|
||||
Class_0_incorrectly_extends_base_class_1_Colon: { code: 2416, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly extends base class '{1}':" },
|
||||
Class_static_side_0_incorrectly_extends_base_class_static_side_1: { code: 2417, category: DiagnosticCategory.Error, key: "Class static side '{0}' incorrectly extends base class static side '{1}'." },
|
||||
Class_static_side_0_incorrectly_extends_base_class_static_side_1_Colon: { code: 2418, category: DiagnosticCategory.Error, key: "Class static side '{0}' incorrectly extends base class static side '{1}':" },
|
||||
Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_0: { code: 2419, category: DiagnosticCategory.Error, key: "Type name '{0}' in extends clause does not reference constructor function for '{0}'." },
|
||||
Class_0_incorrectly_implements_interface_1: { code: 2420, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly implements interface '{1}'." },
|
||||
Class_0_incorrectly_implements_interface_1_Colon: { code: 2421, category: DiagnosticCategory.Error, key: "Class '{0}' incorrectly implements interface '{1}':" },
|
||||
A_class_may_only_implement_another_class_or_interface: { code: 2422, category: DiagnosticCategory.Error, key: "A class may only implement another class or interface." },
|
||||
Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor: { code: 2423, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor." },
|
||||
Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property: { code: 2424, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property." },
|
||||
@ -247,7 +243,6 @@ module ts {
|
||||
Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function: { code: 2426, category: DiagnosticCategory.Error, key: "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function." },
|
||||
Interface_name_cannot_be_0: { code: 2427, category: DiagnosticCategory.Error, key: "Interface name cannot be '{0}'" },
|
||||
All_declarations_of_an_interface_must_have_identical_type_parameters: { code: 2428, category: DiagnosticCategory.Error, key: "All declarations of an interface must have identical type parameters." },
|
||||
Interface_0_incorrectly_extends_interface_1_Colon: { code: 2429, category: DiagnosticCategory.Error, key: "Interface '{0}' incorrectly extends interface '{1}':" },
|
||||
Interface_0_incorrectly_extends_interface_1: { code: 2430, category: DiagnosticCategory.Error, key: "Interface '{0}' incorrectly extends interface '{1}'." },
|
||||
Enum_name_cannot_be_0: { code: 2431, category: DiagnosticCategory.Error, key: "Enum name cannot be '{0}'" },
|
||||
In_an_enum_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_its_first_enum_element: { code: 2432, category: DiagnosticCategory.Error, key: "In an enum with multiple declarations, only one declaration can omit an initializer for its first enum element." },
|
||||
@ -271,6 +266,10 @@ module ts {
|
||||
Left_hand_side_of_assignment_expression_cannot_be_a_constant: { code: 2450, category: DiagnosticCategory.Error, key: "Left-hand side of assignment expression cannot be a constant.", isEarly: true },
|
||||
Cannot_redeclare_block_scoped_variable_0: { code: 2451, category: DiagnosticCategory.Error, key: "Cannot redeclare block-scoped variable '{0}'.", isEarly: true },
|
||||
An_enum_member_cannot_have_a_numeric_name: { code: 2452, category: DiagnosticCategory.Error, key: "An enum member cannot have a numeric name." },
|
||||
The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly: { code: 2453, category: DiagnosticCategory.Error, key: "The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly." },
|
||||
Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0: { code: 2455, category: DiagnosticCategory.Error, key: "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'." },
|
||||
Type_alias_0_circularly_references_itself: { code: 2456, category: DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." },
|
||||
Type_alias_name_cannot_be_0: { code: 2457, category: DiagnosticCategory.Error, key: "Type alias name cannot be '{0}'" },
|
||||
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
|
||||
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
|
||||
@ -350,6 +349,15 @@ module ts {
|
||||
Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4076, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from external module {2} but cannot be named." },
|
||||
Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2: { code: 4077, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'." },
|
||||
Parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4078, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using private name '{1}'." },
|
||||
Exported_type_alias_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4079, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using name '{1}' from external module {2} but cannot be named." },
|
||||
Exported_type_alias_0_has_or_is_using_name_1_from_private_module_2: { code: 4080, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using name '{1}' from private module '{2}'." },
|
||||
Exported_type_alias_0_has_or_is_using_private_name_1: { code: 4081, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using private name '{1}'." },
|
||||
Enum_declarations_must_all_be_const_or_non_const: { code: 4082, category: DiagnosticCategory.Error, key: "Enum declarations must all be const or non-const." },
|
||||
In_const_enum_declarations_member_initializer_must_be_constant_expression: { code: 4083, category: DiagnosticCategory.Error, key: "In 'const' enum declarations member initializer must be constant expression.", isEarly: true },
|
||||
const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_import_declaration_or_export_assignment: { code: 4084, category: DiagnosticCategory.Error, key: "'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment." },
|
||||
Index_expression_arguments_in_const_enums_must_be_of_type_string: { code: 4085, category: DiagnosticCategory.Error, key: "Index expression arguments in 'const' enums must be of type 'string'." },
|
||||
const_enum_member_initializer_was_evaluated_to_a_non_finite_value: { code: 4086, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to a non-finite value." },
|
||||
const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN: { code: 4087, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to disallowed value 'NaN'." },
|
||||
The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." },
|
||||
Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." },
|
||||
Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" },
|
||||
@ -364,7 +372,8 @@ module ts {
|
||||
Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations: { code: 6004, category: DiagnosticCategory.Message, key: "Specifies the location where debugger should locate TypeScript files instead of source locations." },
|
||||
Watch_input_files: { code: 6005, category: DiagnosticCategory.Message, key: "Watch input files." },
|
||||
Redirect_output_structure_to_the_directory: { code: 6006, category: DiagnosticCategory.Message, key: "Redirect output structure to the directory." },
|
||||
Do_not_emit_outputs_if_any_type_checking_errors_were_reported: { code: 6007, category: DiagnosticCategory.Message, key: "Do not emit outputs if any type checking errors were reported." },
|
||||
Do_not_erase_const_enum_declarations_in_generated_code: { code: 6007, category: DiagnosticCategory.Message, key: "Do not erase const enum declarations in generated code." },
|
||||
Do_not_emit_outputs_if_any_type_checking_errors_were_reported: { code: 6008, category: DiagnosticCategory.Message, key: "Do not emit outputs if any type checking errors were reported." },
|
||||
Do_not_emit_comments_to_output: { code: 6009, category: DiagnosticCategory.Message, key: "Do not emit comments to output." },
|
||||
Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental: { code: 6015, category: DiagnosticCategory.Message, key: "Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)" },
|
||||
Specify_module_code_generation_Colon_commonjs_or_amd: { code: 6016, category: DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs' or 'amd'" },
|
||||
|
||||
@ -471,6 +471,14 @@
|
||||
"category": "Error",
|
||||
"code": 1157
|
||||
},
|
||||
"Invalid template literal; expected '}'": {
|
||||
"category": "Error",
|
||||
"code": 1158
|
||||
},
|
||||
"Tagged templates are only available when targeting ECMAScript 6 and higher.": {
|
||||
"category": "Error",
|
||||
"code": 1159
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
@ -552,7 +560,7 @@
|
||||
"category": "Error",
|
||||
"code": 2319
|
||||
},
|
||||
"Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':": {
|
||||
"Interface '{0}' cannot simultaneously extend types '{1}' and '{2}'.": {
|
||||
"category": "Error",
|
||||
"code": 2320
|
||||
},
|
||||
@ -560,13 +568,9 @@
|
||||
"category": "Error",
|
||||
"code": 2321
|
||||
},
|
||||
"Type '{0}' is not assignable to type '{1}':": {
|
||||
"category": "Error",
|
||||
"code": 2322
|
||||
},
|
||||
"Type '{0}' is not assignable to type '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 2323
|
||||
"code": 2322
|
||||
},
|
||||
"Property '{0}' is missing in type '{1}'.": {
|
||||
"category": "Error",
|
||||
@ -576,7 +580,7 @@
|
||||
"category": "Error",
|
||||
"code": 2325
|
||||
},
|
||||
"Types of property '{0}' are incompatible:": {
|
||||
"Types of property '{0}' are incompatible.": {
|
||||
"category": "Error",
|
||||
"code": 2326
|
||||
},
|
||||
@ -584,7 +588,7 @@
|
||||
"category": "Error",
|
||||
"code": 2327
|
||||
},
|
||||
"Types of parameters '{0}' and '{1}' are incompatible:": {
|
||||
"Types of parameters '{0}' and '{1}' are incompatible.": {
|
||||
"category": "Error",
|
||||
"code": 2328
|
||||
},
|
||||
@ -592,7 +596,7 @@
|
||||
"category": "Error",
|
||||
"code": 2329
|
||||
},
|
||||
"Index signatures are incompatible:": {
|
||||
"Index signatures are incompatible.": {
|
||||
"category": "Error",
|
||||
"code": 2330
|
||||
},
|
||||
@ -644,10 +648,6 @@
|
||||
"category": "Error",
|
||||
"code": 2342
|
||||
},
|
||||
"Type '{0}' does not satisfy the constraint '{1}':": {
|
||||
"category": "Error",
|
||||
"code": 2343
|
||||
},
|
||||
"Type '{0}' does not satisfy the constraint '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 2344
|
||||
@ -684,10 +684,6 @@
|
||||
"category": "Error",
|
||||
"code": 2352
|
||||
},
|
||||
"Neither type '{0}' nor type '{1}' is assignable to the other:": {
|
||||
"category": "Error",
|
||||
"code": 2353
|
||||
},
|
||||
"No best common type exists among return expressions.": {
|
||||
"category": "Error",
|
||||
"code": 2354
|
||||
@ -928,18 +924,10 @@
|
||||
"category": "Error",
|
||||
"code": 2415
|
||||
},
|
||||
"Class '{0}' incorrectly extends base class '{1}':": {
|
||||
"category": "Error",
|
||||
"code": 2416
|
||||
},
|
||||
"Class static side '{0}' incorrectly extends base class static side '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 2417
|
||||
},
|
||||
"Class static side '{0}' incorrectly extends base class static side '{1}':": {
|
||||
"category": "Error",
|
||||
"code": 2418
|
||||
},
|
||||
"Type name '{0}' in extends clause does not reference constructor function for '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2419
|
||||
@ -948,10 +936,6 @@
|
||||
"category": "Error",
|
||||
"code": 2420
|
||||
},
|
||||
"Class '{0}' incorrectly implements interface '{1}':": {
|
||||
"category": "Error",
|
||||
"code": 2421
|
||||
},
|
||||
"A class may only implement another class or interface.": {
|
||||
"category": "Error",
|
||||
"code": 2422
|
||||
@ -980,10 +964,6 @@
|
||||
"category": "Error",
|
||||
"code": 2428
|
||||
},
|
||||
"Interface '{0}' incorrectly extends interface '{1}':": {
|
||||
"category": "Error",
|
||||
"code": 2429
|
||||
},
|
||||
"Interface '{0}' incorrectly extends interface '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 2430
|
||||
@ -1080,6 +1060,22 @@
|
||||
"category": "Error",
|
||||
"code": 2452
|
||||
},
|
||||
"The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly.": {
|
||||
"category": "Error",
|
||||
"code": 2453
|
||||
},
|
||||
"Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2455
|
||||
},
|
||||
"Type alias '{0}' circularly references itself.": {
|
||||
"category": "Error",
|
||||
"code": 2456
|
||||
},
|
||||
"Type alias name cannot be '{0}'": {
|
||||
"category": "Error",
|
||||
"code": 2457
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@ -1397,13 +1393,47 @@
|
||||
"category": "Error",
|
||||
"code": 4078
|
||||
},
|
||||
|
||||
|
||||
"Exported type alias '{0}' has or is using name '{1}' from external module {2} but cannot be named.": {
|
||||
"category": "Error",
|
||||
"code": 4079
|
||||
},
|
||||
"Exported type alias '{0}' has or is using name '{1}' from private module '{2}'.": {
|
||||
"category": "Error",
|
||||
"code": 4080
|
||||
},
|
||||
"Exported type alias '{0}' has or is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 4081
|
||||
},
|
||||
"Enum declarations must all be const or non-const.": {
|
||||
"category": "Error",
|
||||
"code": 4082
|
||||
},
|
||||
"In 'const' enum declarations member initializer must be constant expression.": {
|
||||
"category": "Error",
|
||||
"code": 4083,
|
||||
"isEarly": true
|
||||
},
|
||||
"'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment.": {
|
||||
"category": "Error",
|
||||
"code": 4084
|
||||
},
|
||||
"Index expression arguments in 'const' enums must be of type 'string'.": {
|
||||
"category": "Error",
|
||||
"code": 4085
|
||||
},
|
||||
"'const' enum member initializer was evaluated to a non-finite value.": {
|
||||
"category": "Error",
|
||||
"code": 4086
|
||||
},
|
||||
"'const' enum member initializer was evaluated to disallowed value 'NaN'.": {
|
||||
"category": "Error",
|
||||
"code": 4087
|
||||
},
|
||||
"The current host does not support the '{0}' option.": {
|
||||
"category": "Error",
|
||||
"code": 5001
|
||||
},
|
||||
|
||||
"Cannot find the common subdirectory path for the input files.": {
|
||||
"category": "Error",
|
||||
"code": 5009
|
||||
@ -1456,10 +1486,14 @@
|
||||
"category": "Message",
|
||||
"code": 6006
|
||||
},
|
||||
"Do not emit outputs if any type checking errors were reported.": {
|
||||
"Do not erase const enum declarations in generated code.": {
|
||||
"category": "Message",
|
||||
"code": 6007
|
||||
},
|
||||
"Do not emit outputs if any type checking errors were reported.": {
|
||||
"category": "Message",
|
||||
"code": 6008
|
||||
},
|
||||
"Do not emit comments to output.": {
|
||||
"category": "Message",
|
||||
"code": 6009
|
||||
|
||||
@ -86,8 +86,9 @@ module ts {
|
||||
var getAccessor: AccessorDeclaration;
|
||||
var setAccessor: AccessorDeclaration;
|
||||
forEach(node.members, (member: Declaration) => {
|
||||
// TODO(jfreeman): Handle computed names for accessor matching
|
||||
if ((member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor) &&
|
||||
member.name.text === accessor.name.text &&
|
||||
(<Identifier>member.name).text === (<Identifier>accessor.name).text &&
|
||||
(member.flags & NodeFlags.Static) === (accessor.flags & NodeFlags.Static)) {
|
||||
if (!firstAccessor) {
|
||||
firstAccessor = <AccessorDeclaration>member;
|
||||
@ -138,7 +139,7 @@ module ts {
|
||||
function writeLiteral(s: string) {
|
||||
if (s && s.length) {
|
||||
write(s);
|
||||
var lineStartsOfS = getLineStarts(s);
|
||||
var lineStartsOfS = computeLineStarts(s);
|
||||
if (lineStartsOfS.length > 1) {
|
||||
lineCount = lineCount + lineStartsOfS.length - 1;
|
||||
linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1];
|
||||
@ -577,7 +578,8 @@ module ts {
|
||||
node.kind === SyntaxKind.EnumDeclaration) {
|
||||
// Declaration and has associated name use it
|
||||
if ((<Declaration>node).name) {
|
||||
scopeName = (<Declaration>node).name.text;
|
||||
// TODO(jfreeman): Ask shkamat about what this name should be for source maps
|
||||
scopeName = (<Identifier>(<Declaration>node).name).text;
|
||||
}
|
||||
recordScopeNameStart(scopeName);
|
||||
}
|
||||
@ -786,27 +788,136 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitLiteral(node: LiteralExpression) {
|
||||
var text = getSourceTextOfLocalNode(node);
|
||||
if (node.kind === SyntaxKind.StringLiteral && compilerOptions.sourceMap) {
|
||||
function emitLiteral(node: LiteralExpression): void {
|
||||
var text = getLiteralText();
|
||||
|
||||
if (compilerOptions.sourceMap && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
|
||||
writer.writeLiteral(text);
|
||||
}
|
||||
else {
|
||||
write(text);
|
||||
}
|
||||
|
||||
function getLiteralText() {
|
||||
if (compilerOptions.target < ScriptTarget.ES6 && isTemplateLiteralKind(node.kind)) {
|
||||
return getTemplateLiteralAsStringLiteral(node)
|
||||
}
|
||||
|
||||
return getSourceTextOfLocalNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
function getTemplateLiteralAsStringLiteral(node: LiteralExpression): string {
|
||||
return '"' + escapeString(node.text) + '"';
|
||||
}
|
||||
|
||||
function emitTemplateExpression(node: TemplateExpression): void {
|
||||
// In ES6 mode and above, we can simply emit each portion of a template in order, but in
|
||||
// ES3 & ES5 we must convert the template expression into a series of string concatenations.
|
||||
if (compilerOptions.target >= ScriptTarget.ES6) {
|
||||
forEachChild(node, emit);
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.assert(node.parent.kind !== SyntaxKind.TaggedTemplateExpression);
|
||||
|
||||
var templateNeedsParens = isExpression(node.parent)
|
||||
&& node.parent.kind !== SyntaxKind.ParenExpression
|
||||
&& comparePrecedenceToBinaryPlus(node.parent) !== Comparison.LessThan;
|
||||
|
||||
if (templateNeedsParens) {
|
||||
write("(");
|
||||
}
|
||||
|
||||
emitLiteral(node.head);
|
||||
|
||||
forEach(node.templateSpans, templateSpan => {
|
||||
// Check if the expression has operands and binds its operands less closely than binary '+'.
|
||||
// If it does, we need to wrap the expression in parentheses. Otherwise, something like
|
||||
// `abc${ 1 << 2}`
|
||||
// becomes
|
||||
// "abc" + 1 << 2 + ""
|
||||
// which is really
|
||||
// ("abc" + 1) << (2 + "")
|
||||
// rather than
|
||||
// "abc" + (1 << 2) + ""
|
||||
var needsParens = templateSpan.expression.kind !== SyntaxKind.ParenExpression
|
||||
&& comparePrecedenceToBinaryPlus(templateSpan.expression) !== Comparison.GreaterThan;
|
||||
|
||||
write(" + ");
|
||||
|
||||
if (needsParens) {
|
||||
write("(");
|
||||
}
|
||||
emit(templateSpan.expression);
|
||||
if (needsParens) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
// Only emit if the literal is non-empty.
|
||||
// The binary '+' operator is left-associative, so the first string concatenation will force
|
||||
// the result up to this point to be a string. Emitting a '+ ""' has no semantic effect.
|
||||
if (templateSpan.literal.text.length !== 0) {
|
||||
write(" + ")
|
||||
emitLiteral(templateSpan.literal);
|
||||
}
|
||||
});
|
||||
|
||||
if (templateNeedsParens) {
|
||||
write(")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the expression has lesser, greater,
|
||||
* or equal precedence to the binary '+' operator
|
||||
*/
|
||||
function comparePrecedenceToBinaryPlus(expression: Expression): Comparison {
|
||||
// All binary expressions have lower precedence than '+' apart from '*', '/', and '%'.
|
||||
// All unary operators have a higher precedence apart from yield.
|
||||
// Arrow functions and conditionals have a lower precedence,
|
||||
// although we convert the former into regular function expressions in ES5 mode,
|
||||
// and in ES6 mode this function won't get called anyway.
|
||||
//
|
||||
// TODO (drosen): Note that we need to account for the upcoming 'yield' and
|
||||
// spread ('...') unary operators that are anticipated for ES6.
|
||||
Debug.assert(compilerOptions.target <= ScriptTarget.ES5);
|
||||
switch (expression.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
switch ((<BinaryExpression>expression).operator) {
|
||||
case SyntaxKind.AsteriskToken:
|
||||
case SyntaxKind.SlashToken:
|
||||
case SyntaxKind.PercentToken:
|
||||
return Comparison.GreaterThan;
|
||||
case SyntaxKind.PlusToken:
|
||||
return Comparison.EqualTo;
|
||||
default:
|
||||
return Comparison.LessThan;
|
||||
}
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
return Comparison.LessThan;
|
||||
default:
|
||||
return Comparison.GreaterThan;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function emitTemplateSpan(span: TemplateSpan) {
|
||||
emit(span.expression);
|
||||
emit(span.literal);
|
||||
}
|
||||
|
||||
// This function specifically handles numeric/string literals for enum and accessor 'identifiers'.
|
||||
// In a sense, it does not actually emit identifiers as much as it declares a name for a specific property.
|
||||
function emitQuotedIdentifier(node: Identifier) {
|
||||
function emitExpressionForPropertyName(node: DeclarationName) {
|
||||
if (node.kind === SyntaxKind.StringLiteral) {
|
||||
emitLiteral(node);
|
||||
emitLiteral(<LiteralExpression>node);
|
||||
}
|
||||
else {
|
||||
write("\"");
|
||||
|
||||
if (node.kind === SyntaxKind.NumericLiteral) {
|
||||
write(node.text);
|
||||
write((<LiteralExpression>node).text);
|
||||
}
|
||||
else {
|
||||
write(getSourceTextOfLocalNode(node));
|
||||
@ -922,19 +1033,29 @@ module ts {
|
||||
emitTrailingComments(node);
|
||||
}
|
||||
|
||||
function emitPropertyAccess(node: PropertyAccess) {
|
||||
function tryEmitConstantValue(node: PropertyAccess | IndexedAccess): boolean {
|
||||
var constantValue = resolver.getConstantValue(node);
|
||||
if (constantValue !== undefined) {
|
||||
write(constantValue.toString() + " /* " + identifierToString(node.right) + " */");
|
||||
var propertyName = node.kind === SyntaxKind.PropertyAccess ? declarationNameToString((<PropertyAccess>node).right) : getTextOfNode((<IndexedAccess>node).index);
|
||||
write(constantValue.toString() + " /* " + propertyName + " */");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
emit(node.left);
|
||||
write(".");
|
||||
emit(node.right);
|
||||
return false;
|
||||
}
|
||||
|
||||
function emitPropertyAccess(node: PropertyAccess) {
|
||||
if (tryEmitConstantValue(node)) {
|
||||
return;
|
||||
}
|
||||
emit(node.left);
|
||||
write(".");
|
||||
emit(node.right);
|
||||
}
|
||||
|
||||
function emitIndexedAccess(node: IndexedAccess) {
|
||||
if (tryEmitConstantValue(node)) {
|
||||
return;
|
||||
}
|
||||
emit(node.object);
|
||||
write("[");
|
||||
emit(node.index);
|
||||
@ -977,6 +1098,13 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitTaggedTemplateExpression(node: TaggedTemplateExpression): void {
|
||||
Debug.assert(compilerOptions.target >= ScriptTarget.ES6, "Trying to emit a tagged template in pre-ES6 mode.");
|
||||
emit(node.tag);
|
||||
write(" ");
|
||||
emit(node.template);
|
||||
}
|
||||
|
||||
function emitParenExpression(node: ParenExpression) {
|
||||
if (node.expression.kind === SyntaxKind.TypeAssertion) {
|
||||
var operand = (<TypeAssertion>node.expression).operand;
|
||||
@ -1225,6 +1353,10 @@ module ts {
|
||||
emitToken(SyntaxKind.CloseBraceToken, node.clauses.end);
|
||||
}
|
||||
|
||||
function isOnSameLine(node1: Node, node2: Node) {
|
||||
return getLineOfLocalPosition(skipTrivia(currentSourceFile.text, node1.pos)) === getLineOfLocalPosition(skipTrivia(currentSourceFile.text, node2.pos));
|
||||
}
|
||||
|
||||
function emitCaseOrDefaultClause(node: CaseOrDefaultClause) {
|
||||
if (node.kind === SyntaxKind.CaseClause) {
|
||||
write("case ");
|
||||
@ -1234,9 +1366,16 @@ module ts {
|
||||
else {
|
||||
write("default:");
|
||||
}
|
||||
increaseIndent();
|
||||
emitLines(node.statements);
|
||||
decreaseIndent();
|
||||
|
||||
if (node.statements.length === 1 && isOnSameLine(node, node.statements[0])) {
|
||||
write(" ");
|
||||
emit(node.statements[0]);
|
||||
}
|
||||
else {
|
||||
increaseIndent();
|
||||
emitLines(node.statements);
|
||||
decreaseIndent();
|
||||
}
|
||||
}
|
||||
|
||||
function emitThrowStatement(node: ThrowStatement) {
|
||||
@ -1327,7 +1466,7 @@ module ts {
|
||||
emitTrailingComments(node);
|
||||
}
|
||||
|
||||
function emitDefaultValueAssignments(node: FunctionDeclaration) {
|
||||
function emitDefaultValueAssignments(node: FunctionLikeDeclaration) {
|
||||
forEach(node.parameters, param => {
|
||||
if (param.initializer) {
|
||||
writeLine();
|
||||
@ -1347,7 +1486,7 @@ module ts {
|
||||
});
|
||||
}
|
||||
|
||||
function emitRestParameter(node: FunctionDeclaration) {
|
||||
function emitRestParameter(node: FunctionLikeDeclaration) {
|
||||
if (hasRestParameters(node)) {
|
||||
var restIndex = node.parameters.length - 1;
|
||||
var restParam = node.parameters[restIndex];
|
||||
@ -1393,7 +1532,7 @@ module ts {
|
||||
emitTrailingComments(node);
|
||||
}
|
||||
|
||||
function emitFunctionDeclaration(node: FunctionDeclaration) {
|
||||
function emitFunctionDeclaration(node: FunctionLikeDeclaration) {
|
||||
if (!node.body) {
|
||||
return emitPinnedOrTripleSlashComments(node);
|
||||
}
|
||||
@ -1421,7 +1560,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitSignatureParameters(node: FunctionDeclaration) {
|
||||
function emitSignatureParameters(node: FunctionLikeDeclaration) {
|
||||
increaseIndent();
|
||||
write("(");
|
||||
if (node) {
|
||||
@ -1431,7 +1570,7 @@ module ts {
|
||||
decreaseIndent();
|
||||
}
|
||||
|
||||
function emitSignatureAndBody(node: FunctionDeclaration) {
|
||||
function emitSignatureAndBody(node: FunctionLikeDeclaration) {
|
||||
emitSignatureParameters(node);
|
||||
write(" {");
|
||||
scopeEmitStart(node);
|
||||
@ -1528,7 +1667,8 @@ module ts {
|
||||
});
|
||||
}
|
||||
|
||||
function emitMemberAccess(memberName: Identifier) {
|
||||
// TODO(jfreeman): Account for computed property name
|
||||
function emitMemberAccess(memberName: DeclarationName) {
|
||||
if (memberName.kind === SyntaxKind.StringLiteral || memberName.kind === SyntaxKind.NumericLiteral) {
|
||||
write("[");
|
||||
emitNode(memberName);
|
||||
@ -1601,7 +1741,7 @@ module ts {
|
||||
write(".prototype");
|
||||
}
|
||||
write(", ");
|
||||
emitQuotedIdentifier((<AccessorDeclaration>member).name);
|
||||
emitExpressionForPropertyName((<AccessorDeclaration>member).name);
|
||||
emitEnd((<AccessorDeclaration>member).name);
|
||||
write(", {");
|
||||
increaseIndent();
|
||||
@ -1760,6 +1900,11 @@ module ts {
|
||||
}
|
||||
|
||||
function emitEnumDeclaration(node: EnumDeclaration) {
|
||||
// const enums are completely erased during compilation.
|
||||
var isConstEnum = isConstEnumDeclaration(node);
|
||||
if (isConstEnum && !compilerOptions.preserveConstEnums) {
|
||||
return;
|
||||
}
|
||||
emitLeadingComments(node);
|
||||
if (!(node.flags & NodeFlags.Export)) {
|
||||
emitStart(node);
|
||||
@ -1777,7 +1922,7 @@ module ts {
|
||||
write(") {");
|
||||
increaseIndent();
|
||||
scopeEmitStart(node);
|
||||
emitEnumMemberDeclarations();
|
||||
emitEnumMemberDeclarations(isConstEnum);
|
||||
decreaseIndent();
|
||||
writeLine();
|
||||
emitToken(SyntaxKind.CloseBraceToken, node.members.end);
|
||||
@ -1800,7 +1945,7 @@ module ts {
|
||||
}
|
||||
emitTrailingComments(node);
|
||||
|
||||
function emitEnumMemberDeclarations() {
|
||||
function emitEnumMemberDeclarations(isConstEnum: boolean) {
|
||||
forEach(node.members, member => {
|
||||
writeLine();
|
||||
emitLeadingComments(member);
|
||||
@ -1809,16 +1954,16 @@ module ts {
|
||||
write("[");
|
||||
write(resolver.getLocalNameOfContainer(node));
|
||||
write("[");
|
||||
emitQuotedIdentifier(member.name);
|
||||
emitExpressionForPropertyName(member.name);
|
||||
write("] = ");
|
||||
if (member.initializer) {
|
||||
if (member.initializer && !isConstEnum) {
|
||||
emit(member.initializer);
|
||||
}
|
||||
else {
|
||||
write(resolver.getEnumMemberValue(member).toString());
|
||||
}
|
||||
write("] = ");
|
||||
emitQuotedIdentifier(member.name);
|
||||
emitExpressionForPropertyName(member.name);
|
||||
emitEnd(member);
|
||||
write(";");
|
||||
emitTrailingComments(member);
|
||||
@ -1834,7 +1979,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitModuleDeclaration(node: ModuleDeclaration) {
|
||||
if (!isInstantiated(node)) {
|
||||
if (getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) {
|
||||
return emitPinnedOrTripleSlashComments(node);
|
||||
}
|
||||
emitLeadingComments(node);
|
||||
@ -1886,7 +2031,7 @@ module ts {
|
||||
// preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when
|
||||
// - current file is not external module
|
||||
// - import declaration is top level and target is value imported by entity name
|
||||
emitImportDeclaration = !isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportedViaEntityName(node);
|
||||
emitImportDeclaration = !isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportWithEntityName(node);
|
||||
}
|
||||
|
||||
if (emitImportDeclaration) {
|
||||
@ -1930,7 +2075,10 @@ module ts {
|
||||
function getExternalImportDeclarations(node: SourceFile): ImportDeclaration[] {
|
||||
var result: ImportDeclaration[] = [];
|
||||
forEach(node.statements, stat => {
|
||||
if (stat.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>stat).externalModuleName && resolver.isReferencedImportDeclaration(stat)) {
|
||||
if (stat.kind === SyntaxKind.ImportDeclaration
|
||||
&& (<ImportDeclaration>stat).externalModuleName
|
||||
&& resolver.isReferencedImportDeclaration(<ImportDeclaration>stat)) {
|
||||
|
||||
result.push(<ImportDeclaration>stat);
|
||||
}
|
||||
});
|
||||
@ -2085,7 +2233,15 @@ module ts {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateHead:
|
||||
case SyntaxKind.TemplateMiddle:
|
||||
case SyntaxKind.TemplateTail:
|
||||
return emitLiteral(<LiteralExpression>node);
|
||||
case SyntaxKind.TemplateExpression:
|
||||
return emitTemplateExpression(<TemplateExpression>node);
|
||||
case SyntaxKind.TemplateSpan:
|
||||
return emitTemplateSpan(<TemplateSpan>node);
|
||||
case SyntaxKind.QualifiedName:
|
||||
return emitPropertyAccess(<QualifiedName>node);
|
||||
case SyntaxKind.ArrayLiteral:
|
||||
@ -2102,6 +2258,8 @@ module ts {
|
||||
return emitCallExpression(<CallExpression>node);
|
||||
case SyntaxKind.NewExpression:
|
||||
return emitNewExpression(<NewExpression>node);
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
return emitTaggedTemplateExpression(<TaggedTemplateExpression>node);
|
||||
case SyntaxKind.TypeAssertion:
|
||||
return emit((<TypeAssertion>node).operand);
|
||||
case SyntaxKind.ParenExpression:
|
||||
@ -2109,7 +2267,7 @@ module ts {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return emitFunctionDeclaration(<FunctionDeclaration>node);
|
||||
return emitFunctionDeclaration(<FunctionLikeDeclaration>node);
|
||||
case SyntaxKind.PrefixOperator:
|
||||
case SyntaxKind.PostfixOperator:
|
||||
return emitUnaryExpression(<UnaryExpression>node);
|
||||
@ -2352,7 +2510,7 @@ module ts {
|
||||
var getSymbolVisibilityDiagnosticMessage: (symbolAccesibilityResult: SymbolAccessiblityResult) => {
|
||||
errorNode: Node;
|
||||
diagnosticMessage: DiagnosticMessage;
|
||||
typeName?: Identifier
|
||||
typeName?: DeclarationName
|
||||
}
|
||||
|
||||
function createTextWriterWithSymbolWriter(): EmitTextWriterWithSymbolWriter {
|
||||
@ -2566,10 +2724,39 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
|
||||
if (resolver.isDeclarationVisible(node)) {
|
||||
emitJsDocComments(node);
|
||||
emitDeclarationFlags(node);
|
||||
write("type ");
|
||||
emitSourceTextOfNode(node.name);
|
||||
write(" = ");
|
||||
getSymbolVisibilityDiagnosticMessage = getTypeAliasDeclarationVisibilityError;
|
||||
resolver.writeTypeAtLocation(node.type, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
|
||||
write(";");
|
||||
writeLine();
|
||||
}
|
||||
function getTypeAliasDeclarationVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
|
||||
var diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
||||
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Exported_type_alias_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Exported_type_alias_0_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1;
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: node.name
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function emitEnumDeclaration(node: EnumDeclaration) {
|
||||
if (resolver.isDeclarationVisible(node)) {
|
||||
emitJsDocComments(node);
|
||||
emitDeclarationFlags(node);
|
||||
if (isConstEnumDeclaration(node)) {
|
||||
write("const ")
|
||||
}
|
||||
write("enum ");
|
||||
emitSourceTextOfNode(node.name);
|
||||
write(" {");
|
||||
@ -2649,7 +2836,7 @@ module ts {
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.fail("This is unknown parent for type parameter: " + SyntaxKind[node.parent.kind]);
|
||||
Debug.fail("This is unknown parent for type parameter: " + node.parent.kind);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -2785,11 +2972,12 @@ module ts {
|
||||
function emitPropertyDeclaration(node: PropertyDeclaration) {
|
||||
emitJsDocComments(node);
|
||||
emitDeclarationFlags(node);
|
||||
emitVariableDeclaration(node);
|
||||
emitVariableDeclaration(<VariableDeclaration>node);
|
||||
write(";");
|
||||
writeLine();
|
||||
}
|
||||
|
||||
// TODO(jfreeman): Factor out common part of property definition, but treat name differently
|
||||
function emitVariableDeclaration(node: VariableDeclaration) {
|
||||
// If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
|
||||
// so there is no check needed to see if declaration is visible
|
||||
@ -2817,6 +3005,7 @@ module ts {
|
||||
}
|
||||
// This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
|
||||
else if (node.kind === SyntaxKind.Property) {
|
||||
// TODO(jfreeman): Deal with computed properties in error reporting.
|
||||
if (node.flags & NodeFlags.Static) {
|
||||
diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
|
||||
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
@ -2900,6 +3089,7 @@ module ts {
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
errorNode: <Node>node.parameters[0],
|
||||
// TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name
|
||||
typeName: node.name
|
||||
};
|
||||
}
|
||||
@ -2927,7 +3117,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitFunctionDeclaration(node: FunctionDeclaration) {
|
||||
function emitFunctionDeclaration(node: FunctionLikeDeclaration) {
|
||||
// If we are emitting Method/Constructor it isn't moduleElement and hence already determined to be emitting
|
||||
// so no need to verify if the declaration is visible
|
||||
if ((node.kind !== SyntaxKind.FunctionDeclaration || resolver.isDeclarationVisible(node)) &&
|
||||
@ -3045,7 +3235,7 @@ module ts {
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.fail("This is unknown kind for signature: " + SyntaxKind[node.kind]);
|
||||
Debug.fail("This is unknown kind for signature: " + node.kind);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -3130,7 +3320,7 @@ module ts {
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.fail("This is unknown parent for parameter: " + SyntaxKind[node.parent.kind]);
|
||||
Debug.fail("This is unknown parent for parameter: " + node.parent.kind);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -3146,7 +3336,7 @@ module ts {
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.Method:
|
||||
return emitFunctionDeclaration(<FunctionDeclaration>node);
|
||||
return emitFunctionDeclaration(<FunctionLikeDeclaration>node);
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return emitConstructSignatureDeclaration(<SignatureDeclaration>node);
|
||||
case SyntaxKind.CallSignature:
|
||||
@ -3163,6 +3353,8 @@ module ts {
|
||||
return emitInterfaceDeclaration(<InterfaceDeclaration>node);
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return emitClassDeclaration(<ClassDeclaration>node);
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return emitTypeAliasDeclaration(<TypeAliasDeclaration>node);
|
||||
case SyntaxKind.EnumMember:
|
||||
return emitEnumMemberDeclaration(<EnumMember>node);
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -24,6 +24,7 @@ module ts {
|
||||
isReservedWord(): boolean;
|
||||
reScanGreaterToken(): SyntaxKind;
|
||||
reScanSlashToken(): SyntaxKind;
|
||||
reScanTemplateToken(): SyntaxKind;
|
||||
scan(): SyntaxKind;
|
||||
setText(text: string): void;
|
||||
setTextPos(textPos: number): void;
|
||||
@ -80,6 +81,7 @@ module ts {
|
||||
"throw": SyntaxKind.ThrowKeyword,
|
||||
"true": SyntaxKind.TrueKeyword,
|
||||
"try": SyntaxKind.TryKeyword,
|
||||
"type": SyntaxKind.TypeKeyword,
|
||||
"typeof": SyntaxKind.TypeOfKeyword,
|
||||
"var": SyntaxKind.VarKeyword,
|
||||
"void": SyntaxKind.VoidKeyword,
|
||||
@ -244,7 +246,7 @@ module ts {
|
||||
return tokenStrings[t];
|
||||
}
|
||||
|
||||
export function getLineStarts(text: string): number[] {
|
||||
export function computeLineStarts(text: string): number[] {
|
||||
var result: number[] = new Array();
|
||||
var pos = 0;
|
||||
var lineStart = 0;
|
||||
@ -292,7 +294,7 @@ module ts {
|
||||
}
|
||||
|
||||
export function positionToLineAndCharacter(text: string, pos: number) {
|
||||
var lineStarts = getLineStarts(text);
|
||||
var lineStarts = computeLineStarts(text);
|
||||
return getLineAndCharacterOfPosition(lineStarts, pos);
|
||||
}
|
||||
|
||||
@ -465,7 +467,7 @@ module ts {
|
||||
var len: number; // Length of text
|
||||
var startPos: number; // Start position of whitespace before current token
|
||||
var tokenPos: number; // Start position of text of current token
|
||||
var token: number;
|
||||
var token: SyntaxKind;
|
||||
var tokenValue: string;
|
||||
var precedingLineBreak: boolean;
|
||||
|
||||
@ -518,10 +520,10 @@ module ts {
|
||||
return +(text.substring(start, pos));
|
||||
}
|
||||
|
||||
function scanHexDigits(count: number, exact?: boolean): number {
|
||||
function scanHexDigits(count: number, mustMatchCount?: boolean): number {
|
||||
var digits = 0;
|
||||
var value = 0;
|
||||
while (digits < count || !exact) {
|
||||
while (digits < count || !mustMatchCount) {
|
||||
var ch = text.charCodeAt(pos);
|
||||
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) {
|
||||
value = value * 16 + ch - CharacterCodes._0;
|
||||
@ -562,60 +564,7 @@ module ts {
|
||||
}
|
||||
if (ch === CharacterCodes.backslash) {
|
||||
result += text.substring(start, pos);
|
||||
pos++;
|
||||
if (pos >= len) {
|
||||
error(Diagnostics.Unexpected_end_of_text);
|
||||
break;
|
||||
}
|
||||
ch = text.charCodeAt(pos++);
|
||||
switch (ch) {
|
||||
case CharacterCodes._0:
|
||||
result += "\0";
|
||||
break;
|
||||
case CharacterCodes.b:
|
||||
result += "\b";
|
||||
break;
|
||||
case CharacterCodes.t:
|
||||
result += "\t";
|
||||
break;
|
||||
case CharacterCodes.n:
|
||||
result += "\n";
|
||||
break;
|
||||
case CharacterCodes.v:
|
||||
result += "\v";
|
||||
break;
|
||||
case CharacterCodes.f:
|
||||
result += "\f";
|
||||
break;
|
||||
case CharacterCodes.r:
|
||||
result += "\r";
|
||||
break;
|
||||
case CharacterCodes.singleQuote:
|
||||
result += "\'";
|
||||
break;
|
||||
case CharacterCodes.doubleQuote:
|
||||
result += "\"";
|
||||
break;
|
||||
case CharacterCodes.x:
|
||||
case CharacterCodes.u:
|
||||
var ch = scanHexDigits(ch === CharacterCodes.x ? 2 : 4, true);
|
||||
if (ch >= 0) {
|
||||
result += String.fromCharCode(ch);
|
||||
}
|
||||
else {
|
||||
error(Diagnostics.Hexadecimal_digit_expected);
|
||||
}
|
||||
break;
|
||||
case CharacterCodes.carriageReturn:
|
||||
if (pos < len && text.charCodeAt(pos) === CharacterCodes.lineFeed) pos++;
|
||||
break;
|
||||
case CharacterCodes.lineFeed:
|
||||
case CharacterCodes.lineSeparator:
|
||||
case CharacterCodes.paragraphSeparator:
|
||||
break;
|
||||
default:
|
||||
result += String.fromCharCode(ch);
|
||||
}
|
||||
result += scanEscapeSequence();
|
||||
start = pos;
|
||||
continue;
|
||||
}
|
||||
@ -629,13 +578,136 @@ module ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current 'tokenValue' and returns a NoSubstitutionTemplateLiteral or
|
||||
* a literal component of a TemplateExpression.
|
||||
*/
|
||||
function scanTemplateAndSetTokenValue(): SyntaxKind {
|
||||
var startedWithBacktick = text.charCodeAt(pos) === CharacterCodes.backtick;
|
||||
|
||||
pos++;
|
||||
var start = pos;
|
||||
var contents = ""
|
||||
var resultingToken: SyntaxKind;
|
||||
|
||||
while (true) {
|
||||
if (pos >= len) {
|
||||
contents += text.substring(start, pos);
|
||||
error(Diagnostics.Unexpected_end_of_text);
|
||||
resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
|
||||
break;
|
||||
}
|
||||
|
||||
var currChar = text.charCodeAt(pos);
|
||||
|
||||
// '`'
|
||||
if (currChar === CharacterCodes.backtick) {
|
||||
contents += text.substring(start, pos);
|
||||
pos++;
|
||||
resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
|
||||
break;
|
||||
}
|
||||
|
||||
// '${'
|
||||
if (currChar === CharacterCodes.$ && pos + 1 < len && text.charCodeAt(pos + 1) === CharacterCodes.openBrace) {
|
||||
contents += text.substring(start, pos);
|
||||
pos += 2;
|
||||
resultingToken = startedWithBacktick ? SyntaxKind.TemplateHead : SyntaxKind.TemplateMiddle;
|
||||
break;
|
||||
}
|
||||
|
||||
// Escape character
|
||||
if (currChar === CharacterCodes.backslash) {
|
||||
contents += text.substring(start, pos);
|
||||
contents += scanEscapeSequence();
|
||||
start = pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Speculated ECMAScript 6 Spec 11.8.6.1:
|
||||
// <CR><LF> and <CR> LineTerminatorSequences are normalized to <LF> for Template Values
|
||||
// An explicit EscapeSequence is needed to include a <CR> or <CR><LF> sequence.
|
||||
if (currChar === CharacterCodes.carriageReturn) {
|
||||
contents += text.substring(start, pos);
|
||||
|
||||
if (pos + 1 < len && text.charCodeAt(pos + 1) === CharacterCodes.lineFeed) {
|
||||
pos++;
|
||||
}
|
||||
pos++;
|
||||
contents += "\n";
|
||||
start = pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
pos++;
|
||||
}
|
||||
|
||||
Debug.assert(resultingToken !== undefined);
|
||||
|
||||
tokenValue = contents;
|
||||
return resultingToken;
|
||||
}
|
||||
|
||||
function scanEscapeSequence(): string {
|
||||
pos++;
|
||||
if (pos >= len) {
|
||||
error(Diagnostics.Unexpected_end_of_text);
|
||||
return "";
|
||||
}
|
||||
var ch = text.charCodeAt(pos++);
|
||||
switch (ch) {
|
||||
case CharacterCodes._0:
|
||||
return "\0";
|
||||
case CharacterCodes.b:
|
||||
return "\b";
|
||||
case CharacterCodes.t:
|
||||
return "\t";
|
||||
case CharacterCodes.n:
|
||||
return "\n";
|
||||
case CharacterCodes.v:
|
||||
return "\v";
|
||||
case CharacterCodes.f:
|
||||
return "\f";
|
||||
case CharacterCodes.r:
|
||||
return "\r";
|
||||
case CharacterCodes.singleQuote:
|
||||
return "\'";
|
||||
case CharacterCodes.doubleQuote:
|
||||
return "\"";
|
||||
case CharacterCodes.x:
|
||||
case CharacterCodes.u:
|
||||
var ch = scanHexDigits(ch === CharacterCodes.x ? 2 : 4, /*mustMatchCount*/ true);
|
||||
if (ch >= 0) {
|
||||
return String.fromCharCode(ch);
|
||||
}
|
||||
else {
|
||||
error(Diagnostics.Hexadecimal_digit_expected);
|
||||
return ""
|
||||
}
|
||||
|
||||
// when encountering a LineContinuation (i.e. a backslash and a line terminator sequence),
|
||||
// the line terminator is interpreted to be "the empty code unit sequence".
|
||||
case CharacterCodes.carriageReturn:
|
||||
if (pos < len && text.charCodeAt(pos) === CharacterCodes.lineFeed) {
|
||||
pos++;
|
||||
}
|
||||
// fall through
|
||||
case CharacterCodes.lineFeed:
|
||||
case CharacterCodes.lineSeparator:
|
||||
case CharacterCodes.paragraphSeparator:
|
||||
return ""
|
||||
default:
|
||||
return String.fromCharCode(ch);
|
||||
}
|
||||
}
|
||||
|
||||
// Current character is known to be a backslash. Check for Unicode escape of the form '\uXXXX'
|
||||
// and return code point value if valid Unicode escape is found. Otherwise return -1.
|
||||
function peekUnicodeEscape(): number {
|
||||
if (pos + 5 < len && text.charCodeAt(pos + 1) === CharacterCodes.u) {
|
||||
var start = pos;
|
||||
pos += 2;
|
||||
var value = scanHexDigits(4, true);
|
||||
var value = scanHexDigits(4, /*mustMatchCount*/ true);
|
||||
pos = start;
|
||||
return value;
|
||||
}
|
||||
@ -734,6 +806,8 @@ module ts {
|
||||
case CharacterCodes.singleQuote:
|
||||
tokenValue = scanString();
|
||||
return token = SyntaxKind.StringLiteral;
|
||||
case CharacterCodes.backtick:
|
||||
return token = scanTemplateAndSetTokenValue()
|
||||
case CharacterCodes.percent:
|
||||
if (text.charCodeAt(pos + 1) === CharacterCodes.equals) {
|
||||
return pos += 2, token = SyntaxKind.PercentEqualsToken;
|
||||
@ -851,7 +925,7 @@ module ts {
|
||||
case CharacterCodes._0:
|
||||
if (pos + 2 < len && (text.charCodeAt(pos + 1) === CharacterCodes.X || text.charCodeAt(pos + 1) === CharacterCodes.x)) {
|
||||
pos += 2;
|
||||
var value = scanHexDigits(1, false);
|
||||
var value = scanHexDigits(1, /*mustMatchCount*/ false);
|
||||
if (value < 0) {
|
||||
error(Diagnostics.Hexadecimal_digit_expected);
|
||||
value = 0;
|
||||
@ -1037,6 +1111,15 @@ module ts {
|
||||
return token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unconditionally back up and scan a template expression portion.
|
||||
*/
|
||||
function reScanTemplateToken(): SyntaxKind {
|
||||
Debug.assert(token === SyntaxKind.CloseBraceToken, "'reScanTemplateToken' should only be called on a '}'");
|
||||
pos = tokenPos;
|
||||
return token = scanTemplateAndSetTokenValue();
|
||||
}
|
||||
|
||||
function tryScan<T>(callback: () => T): T {
|
||||
var savePos = pos;
|
||||
var saveStartPos = startPos;
|
||||
@ -1085,10 +1168,11 @@ module ts {
|
||||
isReservedWord: () => token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord,
|
||||
reScanGreaterToken: reScanGreaterToken,
|
||||
reScanSlashToken: reScanSlashToken,
|
||||
reScanTemplateToken: reScanTemplateToken,
|
||||
scan: scan,
|
||||
setText: setText,
|
||||
setTextPos: setTextPos,
|
||||
tryScan: tryScan
|
||||
tryScan: tryScan,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
/// <reference path="core.ts"/>
|
||||
/// <reference path="scanner.ts"/>
|
||||
|
||||
module ts {
|
||||
|
||||
@ -9,7 +8,7 @@ module ts {
|
||||
}
|
||||
|
||||
// token > SyntaxKind.Identifer => token is a keyword
|
||||
export enum SyntaxKind {
|
||||
export const enum SyntaxKind {
|
||||
Unknown,
|
||||
EndOfFileToken,
|
||||
SingleLineCommentTrivia,
|
||||
@ -20,6 +19,11 @@ module ts {
|
||||
NumericLiteral,
|
||||
StringLiteral,
|
||||
RegularExpressionLiteral,
|
||||
NoSubstitutionTemplateLiteral,
|
||||
// Pseudo-literals
|
||||
TemplateHead,
|
||||
TemplateMiddle,
|
||||
TemplateTail,
|
||||
// Punctuation
|
||||
OpenBraceToken,
|
||||
CloseBraceToken,
|
||||
@ -132,6 +136,7 @@ module ts {
|
||||
NumberKeyword,
|
||||
SetKeyword,
|
||||
StringKeyword,
|
||||
TypeKeyword,
|
||||
// Parse tree nodes
|
||||
Missing,
|
||||
// Names
|
||||
@ -150,6 +155,8 @@ module ts {
|
||||
IndexSignature,
|
||||
// Type
|
||||
TypeReference,
|
||||
FunctionType,
|
||||
ConstructorType,
|
||||
TypeQuery,
|
||||
TypeLiteral,
|
||||
ArrayType,
|
||||
@ -164,6 +171,7 @@ module ts {
|
||||
IndexedAccess,
|
||||
CallExpression,
|
||||
NewExpression,
|
||||
TaggedTemplateExpression,
|
||||
TypeAssertion,
|
||||
ParenExpression,
|
||||
FunctionExpression,
|
||||
@ -172,6 +180,8 @@ module ts {
|
||||
PostfixOperator,
|
||||
BinaryExpression,
|
||||
ConditionalExpression,
|
||||
TemplateExpression,
|
||||
TemplateSpan,
|
||||
OmittedExpression,
|
||||
// Element
|
||||
Block,
|
||||
@ -202,6 +212,7 @@ module ts {
|
||||
FunctionBlock,
|
||||
ClassDeclaration,
|
||||
InterfaceDeclaration,
|
||||
TypeAliasDeclaration,
|
||||
EnumDeclaration,
|
||||
ModuleDeclaration,
|
||||
ModuleBlock,
|
||||
@ -222,7 +233,7 @@ module ts {
|
||||
FirstReservedWord = BreakKeyword,
|
||||
LastReservedWord = WithKeyword,
|
||||
FirstKeyword = BreakKeyword,
|
||||
LastKeyword = StringKeyword,
|
||||
LastKeyword = TypeKeyword,
|
||||
FirstFutureReservedWord = ImplementsKeyword,
|
||||
LastFutureReservedWord = YieldKeyword,
|
||||
FirstTypeNode = TypeReference,
|
||||
@ -230,12 +241,20 @@ module ts {
|
||||
FirstPunctuation = OpenBraceToken,
|
||||
LastPunctuation = CaretEqualsToken,
|
||||
FirstToken = EndOfFileToken,
|
||||
LastToken = StringKeyword,
|
||||
LastToken = TypeKeyword,
|
||||
FirstTriviaToken = SingleLineCommentTrivia,
|
||||
LastTriviaToken = WhitespaceTrivia
|
||||
LastTriviaToken = WhitespaceTrivia,
|
||||
FirstLiteralToken = NumericLiteral,
|
||||
LastLiteralToken = NoSubstitutionTemplateLiteral,
|
||||
FirstTemplateToken = NoSubstitutionTemplateLiteral,
|
||||
LastTemplateToken = TemplateTail,
|
||||
FirstOperator = SemicolonToken,
|
||||
LastOperator = CaretEqualsToken,
|
||||
FirstBinaryOperator = LessThanToken,
|
||||
LastBinaryOperator = CaretEqualsToken
|
||||
}
|
||||
|
||||
export enum NodeFlags {
|
||||
export const enum NodeFlags {
|
||||
Export = 0x00000001, // Declarations
|
||||
Ambient = 0x00000002, // Declarations
|
||||
QuestionMark = 0x00000004, // Parameter/Property/Method
|
||||
@ -280,9 +299,7 @@ module ts {
|
||||
right: Identifier;
|
||||
}
|
||||
|
||||
export interface EntityName extends Node {
|
||||
// Identifier, QualifiedName, or Missing
|
||||
}
|
||||
export type EntityName = Identifier | QualifiedName;
|
||||
|
||||
export interface ParsedSignature {
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
@ -290,34 +307,66 @@ module ts {
|
||||
type?: TypeNode;
|
||||
}
|
||||
|
||||
export type DeclarationName = Identifier | LiteralExpression | ComputedPropertyName;
|
||||
|
||||
export interface Declaration extends Node {
|
||||
name?: Identifier;
|
||||
name?: DeclarationName;
|
||||
}
|
||||
|
||||
export interface ComputedPropertyName extends Node {
|
||||
expression: Expression;
|
||||
}
|
||||
|
||||
export interface TypeParameterDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
constraint?: TypeNode;
|
||||
}
|
||||
|
||||
export interface SignatureDeclaration extends Declaration, ParsedSignature { }
|
||||
|
||||
export interface VariableDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
type?: TypeNode;
|
||||
initializer?: Expression;
|
||||
}
|
||||
|
||||
export interface PropertyDeclaration extends VariableDeclaration { }
|
||||
export interface PropertyDeclaration extends Declaration {
|
||||
type?: TypeNode;
|
||||
initializer?: Expression;
|
||||
}
|
||||
|
||||
export interface ParameterDeclaration extends VariableDeclaration { }
|
||||
|
||||
export interface FunctionDeclaration extends Declaration, ParsedSignature {
|
||||
body?: Node; // Block or Expression
|
||||
/**
|
||||
* Several node kinds share function-like features such as a signature,
|
||||
* a name, and a body. These nodes should extend FunctionLikeDeclaration.
|
||||
* Examples:
|
||||
* FunctionDeclaration
|
||||
* MethodDeclaration
|
||||
* ConstructorDeclaration
|
||||
* AccessorDeclaration
|
||||
* FunctionExpression
|
||||
*/
|
||||
export interface FunctionLikeDeclaration extends Declaration, ParsedSignature {
|
||||
body?: Block | Expression;
|
||||
}
|
||||
|
||||
export interface MethodDeclaration extends FunctionDeclaration { }
|
||||
export interface FunctionDeclaration extends FunctionLikeDeclaration {
|
||||
name: Identifier;
|
||||
body?: Block;
|
||||
}
|
||||
|
||||
export interface ConstructorDeclaration extends FunctionDeclaration { }
|
||||
export interface MethodDeclaration extends FunctionLikeDeclaration {
|
||||
body?: Block;
|
||||
}
|
||||
|
||||
export interface AccessorDeclaration extends FunctionDeclaration { }
|
||||
export interface ConstructorDeclaration extends FunctionLikeDeclaration {
|
||||
body?: Block;
|
||||
}
|
||||
|
||||
export interface AccessorDeclaration extends FunctionLikeDeclaration {
|
||||
body?: Block;
|
||||
}
|
||||
|
||||
export interface TypeNode extends Node { }
|
||||
|
||||
@ -375,17 +424,30 @@ module ts {
|
||||
whenFalse: Expression;
|
||||
}
|
||||
|
||||
export interface FunctionExpression extends Expression, FunctionDeclaration {
|
||||
body: Node; // Required, whereas the member inherited from FunctionDeclaration is optional
|
||||
export interface FunctionExpression extends Expression, FunctionLikeDeclaration {
|
||||
name?: Identifier;
|
||||
body: Block | Expression; // Required, whereas the member inherited from FunctionDeclaration is optional
|
||||
}
|
||||
|
||||
// The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral
|
||||
// this means quotes have been removed and escapes have been converted to actual characters. For a NumericLiteral, the
|
||||
// stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1".
|
||||
// The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral,
|
||||
// or any literal of a template, this means quotes have been removed and escapes have been converted to actual characters.
|
||||
// For a NumericLiteral, the stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1".
|
||||
export interface LiteralExpression extends Expression {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface TemplateExpression extends Expression {
|
||||
head: LiteralExpression;
|
||||
templateSpans: NodeArray<TemplateSpan>;
|
||||
}
|
||||
|
||||
// Each of these corresponds to a substitution expression and a template literal, in that order.
|
||||
// The template literal must have kind TemplateMiddleLiteral or TemplateTailLiteral.
|
||||
export interface TemplateSpan extends Node {
|
||||
expression: Expression;
|
||||
literal: LiteralExpression;
|
||||
}
|
||||
|
||||
export interface ParenExpression extends Expression {
|
||||
expression: Expression;
|
||||
}
|
||||
@ -416,6 +478,13 @@ module ts {
|
||||
|
||||
export interface NewExpression extends CallExpression { }
|
||||
|
||||
export interface TaggedTemplateExpression extends Expression {
|
||||
tag: Expression;
|
||||
template: LiteralExpression | TemplateExpression;
|
||||
}
|
||||
|
||||
export type CallLikeExpression = CallExpression | NewExpression | TaggedTemplateExpression;
|
||||
|
||||
export interface TypeAssertion extends Expression {
|
||||
type: TypeNode;
|
||||
operand: Expression;
|
||||
@ -509,6 +578,7 @@ module ts {
|
||||
}
|
||||
|
||||
export interface ClassDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
baseType?: TypeReferenceNode;
|
||||
implementedTypes?: NodeArray<TypeReferenceNode>;
|
||||
@ -516,24 +586,34 @@ module ts {
|
||||
}
|
||||
|
||||
export interface InterfaceDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
typeParameters?: NodeArray<TypeParameterDeclaration>;
|
||||
baseTypes?: NodeArray<TypeReferenceNode>;
|
||||
members: NodeArray<Node>;
|
||||
}
|
||||
|
||||
export interface TypeAliasDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
type: TypeNode;
|
||||
}
|
||||
|
||||
export interface EnumMember extends Declaration {
|
||||
name: Identifier | LiteralExpression;
|
||||
initializer?: Expression;
|
||||
}
|
||||
|
||||
export interface EnumDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
members: NodeArray<EnumMember>;
|
||||
}
|
||||
|
||||
export interface ModuleDeclaration extends Declaration {
|
||||
body: Node; // Block or ModuleDeclaration
|
||||
name: Identifier | LiteralExpression;
|
||||
body: Block | ModuleDeclaration;
|
||||
}
|
||||
|
||||
export interface ImportDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
entityName?: EntityName;
|
||||
externalModuleName?: LiteralExpression;
|
||||
}
|
||||
@ -553,8 +633,9 @@ module ts {
|
||||
export interface SourceFile extends Block {
|
||||
filename: string;
|
||||
text: string;
|
||||
getLineAndCharacterFromPosition(position: number): { line: number; character: number };
|
||||
getLineAndCharacterFromPosition(position: number): LineAndCharacter;
|
||||
getPositionFromLineAndCharacter(line: number, character: number): number;
|
||||
getLineStarts(): number[];
|
||||
amdDependencies: string[];
|
||||
referencedFiles: FileReference[];
|
||||
syntacticErrors: Diagnostic[];
|
||||
@ -582,40 +663,24 @@ module ts {
|
||||
}
|
||||
|
||||
export interface SourceMapSpan {
|
||||
/** Line number in the js file*/
|
||||
emittedLine: number;
|
||||
/** Column number in the js file */
|
||||
emittedColumn: number;
|
||||
/** Line number in the ts file */
|
||||
sourceLine: number;
|
||||
/** Column number in the ts file */
|
||||
sourceColumn: number;
|
||||
/** Optional name (index into names array) associated with this span */
|
||||
nameIndex?: number;
|
||||
/** ts file (index into sources array) associated with this span*/
|
||||
sourceIndex: number;
|
||||
emittedLine: number; // Line number in the .js file
|
||||
emittedColumn: number; // Column number in the .js file
|
||||
sourceLine: number; // Line number in the .ts file
|
||||
sourceColumn: number; // Column number in the .ts file
|
||||
nameIndex?: number; // Optional name (index into names array) associated with this span
|
||||
sourceIndex: number; // .ts file (index into sources array) associated with this span*/
|
||||
}
|
||||
|
||||
export interface SourceMapData {
|
||||
/** Where the sourcemap file is written */
|
||||
sourceMapFilePath: string;
|
||||
/** source map URL written in the js file */
|
||||
jsSourceMappingURL: string;
|
||||
/** Source map's file field - js file name*/
|
||||
sourceMapFile: string;
|
||||
/** Source map's sourceRoot field - location where the sources will be present if not "" */
|
||||
sourceMapSourceRoot: string;
|
||||
/** Source map's sources field - list of sources that can be indexed in this source map*/
|
||||
sourceMapSources: string[];
|
||||
/** input source file (which one can use on program to get the file)
|
||||
this is one to one mapping with the sourceMapSources list*/
|
||||
inputSourceFileNames: string[];
|
||||
/** Source map's names field - list of names that can be indexed in this source map*/
|
||||
sourceMapNames?: string[];
|
||||
/** Source map's mapping field - encoded source map spans*/
|
||||
sourceMapMappings: string;
|
||||
/** Raw source map spans that were encoded into the sourceMapMappings*/
|
||||
sourceMapDecodedMappings: SourceMapSpan[];
|
||||
sourceMapFilePath: string; // Where the sourcemap file is written
|
||||
jsSourceMappingURL: string; // source map URL written in the .js file
|
||||
sourceMapFile: string; // Source map's file field - .js file name
|
||||
sourceMapSourceRoot: string; // Source map's sourceRoot field - location where the sources will be present if not ""
|
||||
sourceMapSources: string[]; // Source map's sources field - list of sources that can be indexed in this source map
|
||||
inputSourceFileNames: string[]; // Input source file (which one can use on program to get the file), 1:1 mapping with the sourceMapSources list
|
||||
sourceMapNames?: string[]; // Source map's names field - list of names that can be indexed in this source map
|
||||
sourceMapMappings: string; // Source map's mapping field - encoded source map spans
|
||||
sourceMapDecodedMappings: SourceMapSpan[]; // Raw source map spans that were encoded into the sourceMapMappings
|
||||
}
|
||||
|
||||
// Return code used by getEmitOutput function to indicate status of the function
|
||||
@ -645,7 +710,8 @@ module ts {
|
||||
checkProgram(): void;
|
||||
emitFiles(targetSourceFile?: SourceFile): EmitResult;
|
||||
getParentOfSymbol(symbol: Symbol): Symbol;
|
||||
getTypeOfSymbol(symbol: Symbol): Type;
|
||||
getNarrowedTypeOfSymbol(symbol: Symbol, node: Node): Type;
|
||||
getDeclaredTypeOfSymbol(symbol: Symbol): Type;
|
||||
getPropertiesOfType(type: Type): Symbol[];
|
||||
getPropertyOfType(type: Type, propertyName: string): Symbol;
|
||||
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[];
|
||||
@ -663,15 +729,12 @@ module ts {
|
||||
getContextualType(node: Node): Type;
|
||||
getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature;
|
||||
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature;
|
||||
isImplementationOfOverload(node: FunctionDeclaration): boolean;
|
||||
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
|
||||
isUndefinedSymbol(symbol: Symbol): boolean;
|
||||
isArgumentsSymbol(symbol: Symbol): boolean;
|
||||
isArgumentsSymbol(symbol: Symbol): boolean;
|
||||
isEmitBlocked(sourceFile?: SourceFile): boolean;
|
||||
|
||||
// Returns the constant value of this enum member, or 'undefined' if the enum member has a
|
||||
// computed value.
|
||||
// Returns the constant value of this enum member, or 'undefined' if the enum member has a computed value.
|
||||
getEnumMemberValue(node: EnumMember): number;
|
||||
|
||||
isValidPropertyAccess(node: PropertyAccess, propertyName: string): boolean;
|
||||
getAliasedSymbol(symbol: Symbol): Symbol;
|
||||
}
|
||||
@ -707,7 +770,7 @@ module ts {
|
||||
trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
|
||||
}
|
||||
|
||||
export enum TypeFormatFlags {
|
||||
export const enum TypeFormatFlags {
|
||||
None = 0x00000000,
|
||||
WriteArrayAsGenericType = 0x00000001, // Write Array<T> instead T[]
|
||||
UseTypeOfFunction = 0x00000002, // Write typeof instead of function type literal
|
||||
@ -718,7 +781,7 @@ module ts {
|
||||
InElementType = 0x00000040, // Writing an array or union element type
|
||||
}
|
||||
|
||||
export enum SymbolFormatFlags {
|
||||
export const enum SymbolFormatFlags {
|
||||
None = 0x00000000,
|
||||
WriteTypeParametersOrArguments = 0x00000001, // Write symbols's type argument if it is instantiated symbol
|
||||
// eg. class C<T> { p: T } <-- Show p as C<T>.p here
|
||||
@ -729,7 +792,7 @@ module ts {
|
||||
// When this flag is specified m.c will be used to refer to the class instead of alias symbol x
|
||||
}
|
||||
|
||||
export enum SymbolAccessibility {
|
||||
export const enum SymbolAccessibility {
|
||||
Accessible,
|
||||
NotAccessible,
|
||||
CannotBeNamed
|
||||
@ -744,78 +807,76 @@ module ts {
|
||||
|
||||
export interface EmitResolver {
|
||||
getProgram(): Program;
|
||||
getLocalNameOfContainer(container: Declaration): string;
|
||||
getLocalNameOfContainer(container: ModuleDeclaration | EnumDeclaration): string;
|
||||
getExpressionNamePrefix(node: Identifier): string;
|
||||
getExportAssignmentName(node: SourceFile): string;
|
||||
isReferencedImportDeclaration(node: ImportDeclaration): boolean;
|
||||
isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean;
|
||||
isTopLevelValueImportWithEntityName(node: ImportDeclaration): boolean;
|
||||
getNodeCheckFlags(node: Node): NodeCheckFlags;
|
||||
getEnumMemberValue(node: EnumMember): number;
|
||||
hasSemanticErrors(): boolean;
|
||||
isDeclarationVisible(node: Declaration): boolean;
|
||||
isImplementationOfOverload(node: FunctionDeclaration): boolean;
|
||||
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
|
||||
writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
|
||||
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
|
||||
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult;
|
||||
isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult;
|
||||
|
||||
// Returns the constant value this property access resolves to, or 'undefined' if it does
|
||||
// resolve to a constant.
|
||||
getConstantValue(node: PropertyAccess): number;
|
||||
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
|
||||
getConstantValue(node: PropertyAccess | IndexedAccess): number;
|
||||
isEmitBlocked(sourceFile?: SourceFile): boolean;
|
||||
}
|
||||
|
||||
export enum SymbolFlags {
|
||||
FunctionScopedVariable = 0x00000001, // Variable (var) or parameter
|
||||
Property = 0x00000002, // Property or enum member
|
||||
EnumMember = 0x00000004, // Enum member
|
||||
Function = 0x00000008, // Function
|
||||
Class = 0x00000010, // Class
|
||||
Interface = 0x00000020, // Interface
|
||||
Enum = 0x00000040, // Enum
|
||||
ValueModule = 0x00000080, // Instantiated module
|
||||
NamespaceModule = 0x00000100, // Uninstantiated module
|
||||
TypeLiteral = 0x00000200, // Type Literal
|
||||
ObjectLiteral = 0x00000400, // Object Literal
|
||||
Method = 0x00000800, // Method
|
||||
Constructor = 0x00001000, // Constructor
|
||||
GetAccessor = 0x00002000, // Get accessor
|
||||
SetAccessor = 0x00004000, // Set accessor
|
||||
CallSignature = 0x00008000, // Call signature
|
||||
ConstructSignature = 0x00010000, // Construct signature
|
||||
IndexSignature = 0x00020000, // Index signature
|
||||
TypeParameter = 0x00040000, // Type parameter
|
||||
export const enum SymbolFlags {
|
||||
FunctionScopedVariable = 0x00000001, // Variable (var) or parameter
|
||||
BlockScopedVariable = 0x00000002, // A block-scoped variable (let or const)
|
||||
Property = 0x00000004, // Property or enum member
|
||||
EnumMember = 0x00000008, // Enum member
|
||||
Function = 0x00000010, // Function
|
||||
Class = 0x00000020, // Class
|
||||
Interface = 0x00000040, // Interface
|
||||
ConstEnum = 0x00000080, // Const enum
|
||||
RegularEnum = 0x00000100, // Enum
|
||||
ValueModule = 0x00000200, // Instantiated module
|
||||
NamespaceModule = 0x00000400, // Uninstantiated module
|
||||
TypeLiteral = 0x00000800, // Type Literal
|
||||
ObjectLiteral = 0x00001000, // Object Literal
|
||||
Method = 0x00002000, // Method
|
||||
Constructor = 0x00004000, // Constructor
|
||||
GetAccessor = 0x00008000, // Get accessor
|
||||
SetAccessor = 0x00010000, // Set accessor
|
||||
CallSignature = 0x00020000, // Call signature
|
||||
ConstructSignature = 0x00040000, // Construct signature
|
||||
IndexSignature = 0x00080000, // Index signature
|
||||
TypeParameter = 0x00100000, // Type parameter
|
||||
TypeAlias = 0x00200000, // Type alias
|
||||
|
||||
// Export markers (see comment in declareModuleMember in binder)
|
||||
ExportValue = 0x00080000, // Exported value marker
|
||||
ExportType = 0x00100000, // Exported type marker
|
||||
ExportNamespace = 0x00200000, // Exported namespace marker
|
||||
|
||||
Import = 0x00400000, // Import
|
||||
Instantiated = 0x00800000, // Instantiated symbol
|
||||
Merged = 0x01000000, // Merged symbol (created during program binding)
|
||||
Transient = 0x02000000, // Transient symbol (created during type check)
|
||||
Prototype = 0x04000000, // Prototype property (no source representation)
|
||||
UnionProperty = 0x08000000, // Property in union type
|
||||
|
||||
BlockScopedVariable = 0x10000000, // A block-scoped variable (let ot const)
|
||||
ExportValue = 0x00400000, // Exported value marker
|
||||
ExportType = 0x00800000, // Exported type marker
|
||||
ExportNamespace = 0x01000000, // Exported namespace marker
|
||||
Import = 0x02000000, // Import
|
||||
Instantiated = 0x04000000, // Instantiated symbol
|
||||
Merged = 0x08000000, // Merged symbol (created during program binding)
|
||||
Transient = 0x10000000, // Transient symbol (created during type check)
|
||||
Prototype = 0x20000000, // Prototype property (no source representation)
|
||||
UnionProperty = 0x40000000, // Property in union type
|
||||
|
||||
Enum = RegularEnum | ConstEnum,
|
||||
Variable = FunctionScopedVariable | BlockScopedVariable,
|
||||
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
|
||||
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter,
|
||||
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
|
||||
Namespace = ValueModule | NamespaceModule,
|
||||
Module = ValueModule | NamespaceModule,
|
||||
Accessor = GetAccessor | SetAccessor,
|
||||
Signature = CallSignature | ConstructSignature | IndexSignature,
|
||||
|
||||
|
||||
// Variables can be redeclared, but can not redeclare a block-scoped declaration with the
|
||||
// same name, or any other value that is not a variable, e.g. ValueModule or Class
|
||||
FunctionScopedVariableExcludes = Value & ~FunctionScopedVariable,
|
||||
|
||||
// Block-scoped declarations are not allowed to be re-declared
|
||||
// they can not merge with anything in the value space
|
||||
BlockScopedVariableExcludes = Value,
|
||||
BlockScopedVariableExcludes = Value,
|
||||
|
||||
ParameterExcludes = Value,
|
||||
PropertyExcludes = Value,
|
||||
@ -823,19 +884,18 @@ module ts {
|
||||
FunctionExcludes = Value & ~(Function | ValueModule),
|
||||
ClassExcludes = (Value | Type) & ~ValueModule,
|
||||
InterfaceExcludes = Type & ~Interface,
|
||||
EnumExcludes = (Value | Type) & ~(Enum | ValueModule),
|
||||
ValueModuleExcludes = Value & ~(Function | Class | Enum | ValueModule),
|
||||
RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules
|
||||
ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums
|
||||
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule),
|
||||
NamespaceModuleExcludes = 0,
|
||||
MethodExcludes = Value & ~Method,
|
||||
GetAccessorExcludes = Value & ~SetAccessor,
|
||||
SetAccessorExcludes = Value & ~GetAccessor,
|
||||
TypeParameterExcludes = Type & ~TypeParameter,
|
||||
TypeAliasExcludes = Type,
|
||||
ImportExcludes = Import, // Imports collide with all other imports with the same name
|
||||
|
||||
|
||||
// Imports collide with all other imports with the same name.
|
||||
ImportExcludes = Import,
|
||||
|
||||
ModuleMember = Variable | Function | Class | Interface | Enum | Module | Import,
|
||||
ModuleMember = Variable | Function | Class | Interface | Enum | Module | TypeAlias | Import,
|
||||
|
||||
ExportHasLocal = Function | Class | Enum | ValueModule,
|
||||
|
||||
@ -843,9 +903,9 @@ module ts {
|
||||
HasExports = Class | Enum | Module,
|
||||
HasMembers = Class | Interface | TypeLiteral | ObjectLiteral,
|
||||
|
||||
IsContainer = HasLocals | HasExports | HasMembers,
|
||||
PropertyOrAccessor = Property | Accessor,
|
||||
Export = ExportNamespace | ExportType | ExportValue,
|
||||
IsContainer = HasLocals | HasExports | HasMembers,
|
||||
PropertyOrAccessor = Property | Accessor,
|
||||
Export = ExportNamespace | ExportType | ExportValue,
|
||||
}
|
||||
|
||||
export interface Symbol {
|
||||
@ -858,7 +918,8 @@ module ts {
|
||||
members?: SymbolTable; // Class, interface or literal instance members
|
||||
exports?: SymbolTable; // Module exports
|
||||
exportSymbol?: Symbol; // Exported symbol associated with this symbol
|
||||
valueDeclaration?: Declaration // First value declaration of the symbol
|
||||
valueDeclaration?: Declaration // First value declaration of the symbol,
|
||||
constEnumOnlyModule?: boolean // For modules - if true - module contains only const enums or other modules with only const enums.
|
||||
}
|
||||
|
||||
export interface SymbolLinks {
|
||||
@ -877,7 +938,7 @@ module ts {
|
||||
[index: string]: Symbol;
|
||||
}
|
||||
|
||||
export enum NodeCheckFlags {
|
||||
export const enum NodeCheckFlags {
|
||||
TypeChecked = 0x00000001, // Node has been type checked
|
||||
LexicalThis = 0x00000002, // Lexical 'this' reference
|
||||
CaptureThis = 0x00000004, // Lexical 'this' used in body
|
||||
@ -902,7 +963,7 @@ module ts {
|
||||
assignmentChecks?: Map<boolean>; // Cache of assignment checks
|
||||
}
|
||||
|
||||
export enum TypeFlags {
|
||||
export const enum TypeFlags {
|
||||
Any = 0x00000001,
|
||||
String = 0x00000002,
|
||||
Number = 0x00000004,
|
||||
@ -999,7 +1060,7 @@ module ts {
|
||||
mapper?: TypeMapper; // Instantiation mapper
|
||||
}
|
||||
|
||||
export enum SignatureKind {
|
||||
export const enum SignatureKind {
|
||||
Call,
|
||||
Construct,
|
||||
}
|
||||
@ -1019,7 +1080,7 @@ module ts {
|
||||
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
|
||||
}
|
||||
|
||||
export enum IndexKind {
|
||||
export const enum IndexKind {
|
||||
String,
|
||||
Number,
|
||||
}
|
||||
@ -1028,12 +1089,18 @@ module ts {
|
||||
(t: Type): Type;
|
||||
}
|
||||
|
||||
export interface TypeInferences {
|
||||
primary: Type[]; // Inferences made directly to a type parameter
|
||||
secondary: Type[]; // Inferences made to a type parameter in a union type
|
||||
}
|
||||
|
||||
export interface InferenceContext {
|
||||
typeParameters: TypeParameter[]; // Type parameters for which inferences are made
|
||||
inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType)
|
||||
inferenceCount: number; // Incremented for every inference made (whether new or not)
|
||||
inferences: Type[][]; // Inferences made for each type parameter
|
||||
inferredTypes: Type[]; // Inferred type for each type parameter
|
||||
typeParameters: TypeParameter[]; // Type parameters for which inferences are made
|
||||
inferUnionTypes: boolean; // Infer union types for disjoint candidates (otherwise undefinedType)
|
||||
inferences: TypeInferences[]; // Inferences made for each type parameter
|
||||
inferredTypes: Type[]; // Inferred type for each type parameter
|
||||
failedTypeParameterIndex?: number; // Index of type parameter for which inference failed
|
||||
// It is optional because in contextual signature instantiation, nothing fails
|
||||
}
|
||||
|
||||
export interface DiagnosticMessage {
|
||||
@ -1061,7 +1128,16 @@ module ts {
|
||||
messageText: string;
|
||||
category: DiagnosticCategory;
|
||||
code: number;
|
||||
/**
|
||||
* Early error - any error (can be produced at parsing\binding\typechecking step) that blocks emit
|
||||
*/
|
||||
isEarly?: boolean;
|
||||
/**
|
||||
* Parse error - error produced by parser when it scanner returns a token
|
||||
* that parser does not understand in its current state
|
||||
* (as opposed to grammar error when parser can interpret the token but interpretation is not legal from the grammar perespective)
|
||||
*/
|
||||
isParseError?: boolean;
|
||||
}
|
||||
|
||||
export enum DiagnosticCategory {
|
||||
@ -1094,10 +1170,11 @@ module ts {
|
||||
target?: ScriptTarget;
|
||||
version?: boolean;
|
||||
watch?: boolean;
|
||||
[option: string]: any;
|
||||
preserveConstEnums?: boolean;
|
||||
[option: string]: string | number | boolean;
|
||||
}
|
||||
|
||||
export enum ModuleKind {
|
||||
export const enum ModuleKind {
|
||||
None,
|
||||
CommonJS,
|
||||
AMD,
|
||||
@ -1112,7 +1189,7 @@ module ts {
|
||||
}
|
||||
|
||||
|
||||
export enum ScriptTarget {
|
||||
export const enum ScriptTarget {
|
||||
ES3,
|
||||
ES5,
|
||||
ES6,
|
||||
@ -1127,14 +1204,14 @@ module ts {
|
||||
|
||||
export interface CommandLineOption {
|
||||
name: string;
|
||||
type: any; // "string", "number", "boolean", or an object literal mapping named values to actual values
|
||||
type: string | Map<number>; // "string", "number", "boolean", or an object literal mapping named values to actual values
|
||||
shortName?: string; // A short pneumonic for convenience - for instance, 'h' can be used in place of 'help'.
|
||||
description?: DiagnosticMessage; // The message describing what the command line switch does
|
||||
paramName?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter.
|
||||
error?: DiagnosticMessage; // The error given when the argument does not fit a customized 'type'.
|
||||
}
|
||||
|
||||
export enum CharacterCodes {
|
||||
export const enum CharacterCodes {
|
||||
nullCharacter = 0,
|
||||
maxAsciiCharacter = 0x7F,
|
||||
|
||||
@ -1236,6 +1313,7 @@ module ts {
|
||||
asterisk = 0x2A, // *
|
||||
at = 0x40, // @
|
||||
backslash = 0x5C, // \
|
||||
backtick = 0x60, // `
|
||||
bar = 0x7C, // |
|
||||
caret = 0x5E, // ^
|
||||
closeBrace = 0x7D, // }
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
/// <reference path='typeWriter.ts' />
|
||||
/// <reference path='syntacticCleaner.ts' />
|
||||
|
||||
enum CompilerTestType {
|
||||
const enum CompilerTestType {
|
||||
Conformance,
|
||||
Regressions,
|
||||
Test262
|
||||
@ -296,12 +296,10 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
typeLines.push('=== ' + file.unitName + ' ===\r\n');
|
||||
for (var i = 0; i < codeLines.length; i++) {
|
||||
var currentCodeLine = codeLines[i];
|
||||
var lastLine = typeLines[typeLines.length];
|
||||
typeLines.push(currentCodeLine + '\r\n');
|
||||
if (typeMap[file.unitName]) {
|
||||
var typeInfo = typeMap[file.unitName][i];
|
||||
if (typeInfo) {
|
||||
var leadingSpaces = '';
|
||||
typeInfo.forEach(ty => {
|
||||
typeLines.push('>' + ty + '\r\n');
|
||||
});
|
||||
|
||||
@ -136,10 +136,11 @@ module FourSlash {
|
||||
outDir: 'outDir',
|
||||
sourceMap: 'sourceMap',
|
||||
sourceRoot: 'sourceRoot',
|
||||
resolveReference: 'ResolveReference', // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file
|
||||
};
|
||||
|
||||
// List of allowed metadata names
|
||||
var fileMetadataNames = [testOptMetadataNames.filename, testOptMetadataNames.emitThisFile];
|
||||
var fileMetadataNames = [testOptMetadataNames.filename, testOptMetadataNames.emitThisFile, testOptMetadataNames.resolveReference];
|
||||
var globalMetadataNames = [testOptMetadataNames.baselineFile, testOptMetadataNames.declaration,
|
||||
testOptMetadataNames.mapRoot, testOptMetadataNames.module, testOptMetadataNames.out,
|
||||
testOptMetadataNames.outDir, testOptMetadataNames.sourceMap, testOptMetadataNames.sourceRoot]
|
||||
@ -236,6 +237,25 @@ module FourSlash {
|
||||
throw new Error("Operation should be cancelled");
|
||||
}
|
||||
|
||||
// This function creates IScriptSnapshot object for testing getPreProcessedFileInfo
|
||||
// Return object may lack some functionalities for other purposes.
|
||||
function createScriptSnapShot(sourceText: string): TypeScript.IScriptSnapshot {
|
||||
return {
|
||||
getText: (start: number, end: number) => {
|
||||
return sourceText.substr(start, end - start);
|
||||
},
|
||||
getLength: () => {
|
||||
return sourceText.length;
|
||||
},
|
||||
getLineStartPositions: () => {
|
||||
return <number[]>[];
|
||||
},
|
||||
getChangeRange: (oldSnapshot: TypeScript.IScriptSnapshot) => {
|
||||
return <TypeScript.TextChangeRange>undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class TestState {
|
||||
// Language service instance
|
||||
public languageServiceShimHost: Harness.LanguageService.TypeScriptLS;
|
||||
@ -264,6 +284,16 @@ module FourSlash {
|
||||
private scenarioActions: string[] = [];
|
||||
private taoInvalidReason: string = null;
|
||||
|
||||
private inputFiles: ts.Map<string> = {}; // Map between inputFile's filename and its content for easily looking up when resolving references
|
||||
|
||||
// Add input file which has matched file name with the given reference-file path.
|
||||
// This is necessary when resolveReference flag is specified
|
||||
private addMatchedInputFile(referenceFilePath: string) {
|
||||
var inputFile = this.inputFiles[referenceFilePath];
|
||||
if (inputFile && !Harness.isLibraryFile(referenceFilePath)) {
|
||||
this.languageServiceShimHost.addScript(referenceFilePath, inputFile);
|
||||
}
|
||||
}
|
||||
|
||||
constructor(public testData: FourSlashData) {
|
||||
// Initialize the language service with all the scripts
|
||||
@ -273,57 +303,57 @@ module FourSlash {
|
||||
var compilationSettings = convertGlobalOptionsToCompilationSettings(this.testData.globalOptions);
|
||||
this.languageServiceShimHost.setCompilationSettings(compilationSettings);
|
||||
|
||||
var inputFiles: { unitName: string; content: string }[] = [];
|
||||
var startResolveFileRef: FourSlashFile = undefined;
|
||||
|
||||
testData.files.forEach(file => {
|
||||
var fixedPath = file.fileName.substr(file.fileName.indexOf('tests/'));
|
||||
});
|
||||
|
||||
// NEWTODO: disable resolution for now.
|
||||
// If the last unit contains require( or /// reference then consider it the only input file
|
||||
// and the rest will be added via resolution. If not, then assume we have multiple files
|
||||
// with 0 references in any of them. We could be smarter here to allow scenarios like
|
||||
// 2 files without references and 1 file with a reference but we have 0 tests like that
|
||||
// at the moment and an exhaustive search of the test files for that content could be quite slow.
|
||||
var lastFile = testData.files[testData.files.length - 1];
|
||||
//if (/require\(/.test(lastFile.content) || /reference\spath/.test(lastFile.content)) {
|
||||
// inputFiles.push({ unitName: lastFile.fileName, content: lastFile.content });
|
||||
//} else {
|
||||
inputFiles = testData.files.map(file => {
|
||||
return { unitName: file.fileName, content: file.content };
|
||||
});
|
||||
//}
|
||||
|
||||
|
||||
// NEWTODO: Re-implement commented-out section
|
||||
//harnessCompiler.addInputFiles(inputFiles);
|
||||
//try {
|
||||
// var resolvedFiles = harnessCompiler.resolve();
|
||||
|
||||
// resolvedFiles.forEach(file => {
|
||||
// if (!Harness.isLibraryFile(file.path)) {
|
||||
// var fixedPath = file.path.substr(file.path.indexOf('tests/'));
|
||||
// var content = harnessCompiler.getContentForFile(fixedPath);
|
||||
// this.languageServiceShimHost.addScript(fixedPath, content);
|
||||
// }
|
||||
// });
|
||||
|
||||
// this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal);
|
||||
//}
|
||||
//finally {
|
||||
// // harness no longer needs the results of the above work, make sure the next test operations are in a clean state
|
||||
// harnessCompiler.reset();
|
||||
//}
|
||||
|
||||
/// NEWTODO: For now do not resolve, just use the input files
|
||||
inputFiles.forEach(file => {
|
||||
if (!Harness.isLibraryFile(file.unitName)) {
|
||||
this.languageServiceShimHost.addScript(file.unitName, file.content);
|
||||
ts.forEach(testData.files, file => {
|
||||
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
|
||||
this.inputFiles[file.fileName] = file.content;
|
||||
if (!startResolveFileRef && file.fileOptions[testOptMetadataNames.resolveReference]) {
|
||||
startResolveFileRef = file;
|
||||
} else if (startResolveFileRef) {
|
||||
// If entry point for resolving file references is already specified, report duplication error
|
||||
throw new Error("There exists a Fourslash file which has resolveReference flag specified; remove duplicated resolveReference flag");
|
||||
}
|
||||
});
|
||||
|
||||
this.languageServiceShimHost.addDefaultLibrary();
|
||||
if (startResolveFileRef) {
|
||||
// Add the entry-point file itself into the languageServiceShimHost
|
||||
this.languageServiceShimHost.addScript(startResolveFileRef.fileName, startResolveFileRef.content);
|
||||
|
||||
var jsonResolvedResult = JSON.parse(this.languageServiceShimHost.getCoreService().getPreProcessedFileInfo(startResolveFileRef.fileName,
|
||||
createScriptSnapShot(startResolveFileRef.content)));
|
||||
var resolvedResult = jsonResolvedResult.result;
|
||||
var referencedFiles: ts.IFileReference[] = resolvedResult.referencedFiles;
|
||||
var importedFiles: ts.IFileReference[] = resolvedResult.importedFiles;
|
||||
|
||||
// Add triple reference files into language-service host
|
||||
ts.forEach(referencedFiles, referenceFile => {
|
||||
// Fourslash insert tests/cases/fourslash into inputFile.unitName so we will properly append the same base directory to refFile path
|
||||
var referenceFilePath = "tests/cases/fourslash/" + referenceFile.path;
|
||||
this.addMatchedInputFile(referenceFilePath);
|
||||
});
|
||||
|
||||
// Add import files into language-service host
|
||||
ts.forEach(importedFiles, importedFile => {
|
||||
// Fourslash insert tests/cases/fourslash into inputFile.unitName and import statement doesn't require ".ts"
|
||||
// so convert them before making appropriate comparison
|
||||
var importedFilePath = "tests/cases/fourslash/" + importedFile.path + ".ts";
|
||||
this.addMatchedInputFile(importedFilePath);
|
||||
});
|
||||
|
||||
// Check if no-default-lib flag is false and if so add default library
|
||||
if (!resolvedResult.isLibFile) {
|
||||
this.languageServiceShimHost.addDefaultLibrary();
|
||||
}
|
||||
} else {
|
||||
// resolveReference file-option is not specified then do not resolve any files and include all inputFiles
|
||||
ts.forEachKey(this.inputFiles, fileName => {
|
||||
if (!Harness.isLibraryFile(fileName)) {
|
||||
this.languageServiceShimHost.addScript(fileName, this.inputFiles[fileName]);
|
||||
}
|
||||
});
|
||||
this.languageServiceShimHost.addDefaultLibrary();
|
||||
}
|
||||
|
||||
// Sneak into the language service and get its compiler so we can examine the syntax trees
|
||||
this.languageService = this.languageServiceShimHost.getLanguageService().languageService;
|
||||
@ -991,7 +1021,7 @@ module FourSlash {
|
||||
var resultString = "SpanInfo: " + JSON.stringify(spanInfo);
|
||||
if (spanInfo) {
|
||||
var spanString = this.activeFile.content.substr(spanInfo.start(), spanInfo.length());
|
||||
var spanLineMap = ts.getLineStarts(spanString);
|
||||
var spanLineMap = ts.computeLineStarts(spanString);
|
||||
for (var i = 0; i < spanLineMap.length; i++) {
|
||||
if (!i) {
|
||||
resultString += "\n";
|
||||
@ -1005,7 +1035,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
private baselineCurrentFileLocations(getSpanAtPos: (pos: number) => TypeScript.TextSpan): string {
|
||||
var fileLineMap = ts.getLineStarts(this.activeFile.content);
|
||||
var fileLineMap = ts.computeLineStarts(this.activeFile.content);
|
||||
var nextLine = 0;
|
||||
var resultString = "";
|
||||
var currentLine: string;
|
||||
@ -2044,10 +2074,6 @@ module FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
private getEOF(): number {
|
||||
return this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength();
|
||||
}
|
||||
|
||||
// Get the text of the entire line the caret is currently at
|
||||
private getCurrentLineContent() {
|
||||
// The current caret position (in line/col terms)
|
||||
@ -2163,14 +2189,6 @@ module FourSlash {
|
||||
return result;
|
||||
}
|
||||
|
||||
private getCurrentLineNumberZeroBased() {
|
||||
return this.getCurrentLineNumberOneBased() - 1;
|
||||
}
|
||||
|
||||
private getCurrentLineNumberOneBased() {
|
||||
return this.languageServiceShimHost.positionToZeroBasedLineCol(this.activeFile.fileName, this.currentCaretPosition).line + 1;
|
||||
}
|
||||
|
||||
private getLineColStringAtPosition(position: number) {
|
||||
var pos = this.languageServiceShimHost.positionToZeroBasedLineCol(this.activeFile.fileName, position);
|
||||
return 'line ' + (pos.line + 1) + ', col ' + pos.character;
|
||||
@ -2368,7 +2386,7 @@ module FourSlash {
|
||||
};
|
||||
}
|
||||
|
||||
enum State {
|
||||
const enum State {
|
||||
none,
|
||||
inSlashStarMarker,
|
||||
inObjectMarker
|
||||
|
||||
@ -20,7 +20,7 @@ class FourslashRunner extends RunnerBase {
|
||||
});
|
||||
|
||||
this.tests.forEach((fn: string) => {
|
||||
fn = Harness.Path.switchToForwardSlashes(fn);
|
||||
fn = ts.normalizeSlashes(fn);
|
||||
var justName = fn.replace(/^.*[\\\/]/, '');
|
||||
|
||||
// Convert to relative path
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
|
||||
/// <reference path='..\services\services.ts' />
|
||||
/// <reference path='..\services\shims.ts' />
|
||||
/// <reference path='..\compiler\core.ts' />
|
||||
/// <reference path='..\compiler\sys.ts' />
|
||||
/// <reference path='external\mocha.d.ts'/>
|
||||
/// <reference path='external\chai.d.ts'/>
|
||||
@ -30,7 +31,7 @@ module Utils {
|
||||
var global = <any>Function("return this").call(null);
|
||||
|
||||
// Setup some globals based on the current environment
|
||||
export enum ExecutionEnvironment {
|
||||
export const enum ExecutionEnvironment {
|
||||
Node,
|
||||
Browser,
|
||||
CScript
|
||||
@ -117,15 +118,11 @@ module Harness.Path {
|
||||
}
|
||||
|
||||
export function filePath(fullPath: string) {
|
||||
fullPath = switchToForwardSlashes(fullPath);
|
||||
fullPath = ts.normalizeSlashes(fullPath);
|
||||
var components = fullPath.split("/");
|
||||
var path: string[] = components.slice(0, components.length - 1);
|
||||
return path.join("/") + "/";
|
||||
}
|
||||
|
||||
export function switchToForwardSlashes(path: string) {
|
||||
return path.replace(/\\/g, "/").replace(/\/\//g, '/');
|
||||
}
|
||||
}
|
||||
|
||||
module Harness {
|
||||
@ -564,7 +561,7 @@ module Harness {
|
||||
// Register input files
|
||||
function register(file: { unitName: string; content: string; }) {
|
||||
if (file.content !== undefined) {
|
||||
var filename = Path.switchToForwardSlashes(file.unitName);
|
||||
var filename = ts.normalizeSlashes(file.unitName);
|
||||
filemap[getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, scriptTarget, /*version:*/ "0");
|
||||
}
|
||||
};
|
||||
@ -761,7 +758,6 @@ module Harness {
|
||||
case 'codepage':
|
||||
case 'createFileLog':
|
||||
case 'filename':
|
||||
case 'propagateenumconstants':
|
||||
case 'removecomments':
|
||||
case 'watch':
|
||||
case 'allowautomaticsemicoloninsertion':
|
||||
@ -776,7 +772,9 @@ module Harness {
|
||||
case 'errortruncation':
|
||||
options.noErrorTruncation = setting.value === 'false';
|
||||
break;
|
||||
|
||||
case 'preserveconstenums':
|
||||
options.preserveConstEnums = setting.value === 'true';
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unsupported compiler setting ' + setting.flag);
|
||||
}
|
||||
@ -785,7 +783,7 @@ module Harness {
|
||||
var filemap: { [name: string]: ts.SourceFile; } = {};
|
||||
var register = (file: { unitName: string; content: string; }) => {
|
||||
if (file.content !== undefined) {
|
||||
var filename = Path.switchToForwardSlashes(file.unitName);
|
||||
var filename = ts.normalizeSlashes(file.unitName);
|
||||
filemap[getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, options.target, /*version:*/ "0");
|
||||
}
|
||||
};
|
||||
@ -962,7 +960,7 @@ module Harness {
|
||||
// Note: IE JS engine incorrectly handles consecutive delimiters here when using RegExp split, so
|
||||
// we have to string-based splitting instead and try to figure out the delimiting chars
|
||||
|
||||
var lineStarts = ts.getLineStarts(inputFile.content);
|
||||
var lineStarts = ts.computeLineStarts(inputFile.content);
|
||||
var lines = inputFile.content.split('\n');
|
||||
lines.forEach((line, lineIndex) => {
|
||||
if (line.length > 0 && line.charAt(line.length - 1) === '\r') {
|
||||
@ -1007,8 +1005,12 @@ module Harness {
|
||||
assert.equal(markedErrorCount, fileErrors.length, 'count of errors in ' + inputFile.unitName);
|
||||
});
|
||||
|
||||
var numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => {
|
||||
return diagnostic.filename && isLibraryFile(diagnostic.filename);
|
||||
});
|
||||
|
||||
// Verify we didn't miss any errors in total
|
||||
assert.equal(totalErrorsReported, diagnostics.length, 'total number of errors');
|
||||
assert.equal(totalErrorsReported + numLibraryDiagnostics, diagnostics.length, 'total number of errors');
|
||||
|
||||
return minimalDiagnosticsToString(diagnostics) +
|
||||
sys.newLine + sys.newLine + outputLines.join('\r\n');
|
||||
@ -1093,7 +1095,6 @@ module Harness {
|
||||
/** @param fileResults an array of strings for the fileName and an ITextWriter with its code */
|
||||
constructor(fileResults: GeneratedFile[], errors: HarnessDiagnostic[], public program: ts.Program,
|
||||
public currentDirectoryForProgram: string, private sourceMapData: ts.SourceMapData[]) {
|
||||
var lines: string[] = [];
|
||||
|
||||
fileResults.forEach(emittedFile => {
|
||||
if (isDTS(emittedFile.fileName)) {
|
||||
@ -1149,7 +1150,7 @@ module Harness {
|
||||
var optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*(\S*)/gm; // multiple matches on multiple lines
|
||||
|
||||
// List of allowed metadata names
|
||||
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames"];
|
||||
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror","noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums"];
|
||||
|
||||
function extractCompilerSettings(content: string): CompilerSetting[] {
|
||||
|
||||
@ -1247,7 +1248,6 @@ module Harness {
|
||||
|
||||
/** Support class for baseline files */
|
||||
export module Baseline {
|
||||
var firstRun = true;
|
||||
|
||||
export interface BaselineOptions {
|
||||
LineEndingSensitive?: boolean;
|
||||
@ -1288,8 +1288,7 @@ module Harness {
|
||||
IO.createDirectory(dirName);
|
||||
fileCache[dirName] = true;
|
||||
}
|
||||
var parentDir = IO.directoryName(actualFilename); // .../tests/baselines/local
|
||||
var parentParentDir = IO.directoryName(IO.directoryName(actualFilename)) // .../tests/baselines
|
||||
|
||||
// Create folders if needed
|
||||
createDirectoryStructure(Harness.IO.directoryName(actualFilename));
|
||||
|
||||
|
||||
@ -258,6 +258,10 @@ module Harness.LanguageService {
|
||||
return new TypeScript.Services.TypeScriptServicesFactory().createClassifierShim(this);
|
||||
}
|
||||
|
||||
public getCoreService(): ts.CoreServicesShim {
|
||||
return new TypeScript.Services.TypeScriptServicesFactory().createCoreServicesShim(this);
|
||||
}
|
||||
|
||||
/** Parse file given its source text */
|
||||
public parseSourceText(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.SourceUnitSyntax {
|
||||
return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), ts.ScriptTarget.Latest, TypeScript.isDTSFile(fileName)).sourceUnit();
|
||||
|
||||
@ -175,10 +175,10 @@ module Playback {
|
||||
}
|
||||
|
||||
function findResultByPath<T>(wrapper: { resolvePath(s: string): string }, logArray: { path: string; result?: T }[], expectedPath: string, defaultValue?: T): T {
|
||||
var normalizedName = Harness.Path.switchToForwardSlashes(expectedPath).toLowerCase();
|
||||
var normalizedName = ts.normalizeSlashes(expectedPath).toLowerCase();
|
||||
// Try to find the result through normal filename
|
||||
for (var i = 0; i < logArray.length; i++) {
|
||||
if (Harness.Path.switchToForwardSlashes(logArray[i].path).toLowerCase() === normalizedName) {
|
||||
if (ts.normalizeSlashes(logArray[i].path).toLowerCase() === normalizedName) {
|
||||
return logArray[i].result;
|
||||
}
|
||||
}
|
||||
@ -203,7 +203,7 @@ module Playback {
|
||||
function pathsAreEquivalent(left: string, right: string, wrapper: { resolvePath(s: string): string }) {
|
||||
var key = left + '-~~-' + right;
|
||||
function areSame(a: string, b: string) {
|
||||
return Harness.Path.switchToForwardSlashes(a).toLowerCase() === Harness.Path.switchToForwardSlashes(b).toLowerCase();
|
||||
return ts.normalizeSlashes(a).toLowerCase() === ts.normalizeSlashes(b).toLowerCase();
|
||||
}
|
||||
function check() {
|
||||
if (Harness.Path.getFileName(left).toLowerCase() === Harness.Path.getFileName(right).toLowerCase()) {
|
||||
|
||||
@ -23,7 +23,7 @@ module RWC {
|
||||
function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[], clean?: (s: string) => string) {
|
||||
// Collect, test, and sort the filenames
|
||||
function cleanName(fn: string) {
|
||||
var lastSlash = Harness.Path.switchToForwardSlashes(fn).lastIndexOf('/');
|
||||
var lastSlash = ts.normalizeSlashes(fn).lastIndexOf('/');
|
||||
return fn.substr(lastSlash + 1).toLowerCase();
|
||||
}
|
||||
outputFiles.sort((a, b) => cleanName(a.fileName).localeCompare(cleanName(b.fileName)));
|
||||
@ -52,7 +52,7 @@ module RWC {
|
||||
var compilerResult: Harness.Compiler.CompilerResult;
|
||||
var compilerOptions: ts.CompilerOptions;
|
||||
var baselineOpts: Harness.Baseline.BaselineOptions = { Subfolder: 'rwc' };
|
||||
var baseName = /(.*)\/(.*).json/.exec(Harness.Path.switchToForwardSlashes(jsonPath))[2];
|
||||
var baseName = /(.*)\/(.*).json/.exec(ts.normalizeSlashes(jsonPath))[2];
|
||||
// Compile .d.ts files
|
||||
var declFileCompilationResult: {
|
||||
declInputFiles: { unitName: string; content: string }[];
|
||||
@ -99,7 +99,7 @@ module RWC {
|
||||
}
|
||||
|
||||
ts.forEach(ioLog.filesRead, fileRead => {
|
||||
var resolvedPath = Harness.Path.switchToForwardSlashes(sys.resolvePath(fileRead.path));
|
||||
var resolvedPath = ts.normalizeSlashes(sys.resolvePath(fileRead.path));
|
||||
var inInputList = ts.forEach(inputFiles, inputFile=> inputFile.unitName === resolvedPath);
|
||||
if (!inInputList) {
|
||||
// Add the file to other files
|
||||
@ -117,7 +117,7 @@ module RWC {
|
||||
});
|
||||
|
||||
function getHarnessCompilerInputUnit(fileName: string) {
|
||||
var resolvedPath = Harness.Path.switchToForwardSlashes(sys.resolvePath(fileName));
|
||||
var resolvedPath = ts.normalizeSlashes(sys.resolvePath(fileName));
|
||||
try {
|
||||
var content = sys.readFile(resolvedPath);
|
||||
}
|
||||
|
||||
@ -223,7 +223,7 @@ module Harness.SourceMapRecoder {
|
||||
sourceMapNames = sourceMapData.sourceMapNames;
|
||||
|
||||
jsFile = currentJsFile;
|
||||
jsLineMap = ts.getLineStarts(jsFile.code);
|
||||
jsLineMap = ts.computeLineStarts(jsFile.code);
|
||||
|
||||
spansOnSingleLine = [];
|
||||
prevWrittenSourcePos = 0;
|
||||
@ -294,7 +294,7 @@ module Harness.SourceMapRecoder {
|
||||
sourceMapRecoder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex]);
|
||||
sourceMapRecoder.WriteLine("-------------------------------------------------------------------");
|
||||
|
||||
tsLineMap = ts.getLineStarts(newSourceFileCode);
|
||||
tsLineMap = ts.computeLineStarts(newSourceFileCode);
|
||||
tsCode = newSourceFileCode;
|
||||
prevWrittenSourcePos = 0;
|
||||
}
|
||||
@ -390,7 +390,7 @@ module Harness.SourceMapRecoder {
|
||||
}
|
||||
}
|
||||
|
||||
var tsCodeLineMap = ts.getLineStarts(sourceText);
|
||||
var tsCodeLineMap = ts.computeLineStarts(sourceText);
|
||||
for (var i = 0; i < tsCodeLineMap.length; i++) {
|
||||
writeSourceMapIndent(prevEmittedCol, i == 0 ? markerIds[index] : " >");
|
||||
sourceMapRecoder.Write(getTextOfLine(i, tsCodeLineMap, sourceText));
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
interface TypeWriterResult {
|
||||
line: number;
|
||||
column: number;
|
||||
syntaxKind: string;
|
||||
syntaxKind: number;
|
||||
sourceText: string;
|
||||
type: string;
|
||||
}
|
||||
@ -84,7 +84,7 @@ class TypeWriterWalker {
|
||||
this.results.push({
|
||||
line: lineAndCharacter.line - 1,
|
||||
column: lineAndCharacter.character,
|
||||
syntaxKind: ts.SyntaxKind[node.kind],
|
||||
syntaxKind: node.kind,
|
||||
sourceText: sourceText,
|
||||
type: this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.WriteOwnNameForAnyLike)
|
||||
});
|
||||
@ -92,7 +92,7 @@ class TypeWriterWalker {
|
||||
|
||||
private getTypeOfNode(node: ts.Node): ts.Type {
|
||||
var type = this.checker.getTypeOfNode(node);
|
||||
ts.Debug.assert(type, "type doesn't exist");
|
||||
ts.Debug.assert(type !== undefined, "type doesn't exist");
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
4
src/lib/core.d.ts
vendored
4
src/lib/core.d.ts
vendored
@ -484,6 +484,10 @@ declare var Number: {
|
||||
POSITIVE_INFINITY: number;
|
||||
}
|
||||
|
||||
interface TemplateStringsArray extends Array<string> {
|
||||
raw: string[];
|
||||
}
|
||||
|
||||
interface Math {
|
||||
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
|
||||
E: number;
|
||||
|
||||
@ -74,7 +74,7 @@ module ts.BreakpointResolver {
|
||||
return textSpan(node);
|
||||
}
|
||||
|
||||
if (node.parent.kind == SyntaxKind.ArrowFunction && (<FunctionDeclaration>node.parent).body == node) {
|
||||
if (node.parent.kind == SyntaxKind.ArrowFunction && (<FunctionLikeDeclaration>node.parent).body == node) {
|
||||
// If this is body of arrow function, it is allowed to have the breakpoint
|
||||
return textSpan(node);
|
||||
}
|
||||
@ -99,7 +99,7 @@ module ts.BreakpointResolver {
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return spanInFunctionDeclaration(<FunctionDeclaration>node);
|
||||
return spanInFunctionDeclaration(<FunctionLikeDeclaration>node);
|
||||
|
||||
case SyntaxKind.FunctionBlock:
|
||||
return spanInFunctionBlock(<Block>node);
|
||||
@ -178,7 +178,7 @@ module ts.BreakpointResolver {
|
||||
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
// span on complete module if it is instantiated
|
||||
if (!isInstantiated(node)) {
|
||||
if (getModuleInstanceState(node) !== ModuleInstanceState.Instantiated) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -194,8 +194,9 @@ module ts.BreakpointResolver {
|
||||
// span in statement
|
||||
return spanInNode((<WithStatement>node).statement);
|
||||
|
||||
// No breakpoint in interface
|
||||
// No breakpoint in interface, type alias
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
return undefined;
|
||||
|
||||
// Tokens:
|
||||
@ -246,7 +247,7 @@ module ts.BreakpointResolver {
|
||||
}
|
||||
|
||||
// return type of function go to previous token
|
||||
if (isAnyFunction(node.parent) && (<FunctionDeclaration>node.parent).type === node) {
|
||||
if (isAnyFunction(node.parent) && (<FunctionLikeDeclaration>node.parent).type === node) {
|
||||
return spanInPreviousNode(node);
|
||||
}
|
||||
|
||||
@ -305,7 +306,7 @@ module ts.BreakpointResolver {
|
||||
return textSpan(parameter);
|
||||
}
|
||||
else {
|
||||
var functionDeclaration = <FunctionDeclaration>parameter.parent;
|
||||
var functionDeclaration = <FunctionLikeDeclaration>parameter.parent;
|
||||
var indexOfParameter = indexOf(functionDeclaration.parameters, parameter);
|
||||
if (indexOfParameter) {
|
||||
// Not a first parameter, go to previous parameter
|
||||
@ -318,12 +319,12 @@ module ts.BreakpointResolver {
|
||||
}
|
||||
}
|
||||
|
||||
function canFunctionHaveSpanInWholeDeclaration(functionDeclaration: FunctionDeclaration) {
|
||||
function canFunctionHaveSpanInWholeDeclaration(functionDeclaration: FunctionLikeDeclaration) {
|
||||
return !!(functionDeclaration.flags & NodeFlags.Export) ||
|
||||
(functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration && functionDeclaration.kind !== SyntaxKind.Constructor);
|
||||
}
|
||||
|
||||
function spanInFunctionDeclaration(functionDeclaration: FunctionDeclaration): TypeScript.TextSpan {
|
||||
function spanInFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration): TypeScript.TextSpan {
|
||||
// No breakpoints in the function signature
|
||||
if (!functionDeclaration.body) {
|
||||
return undefined;
|
||||
@ -340,7 +341,7 @@ module ts.BreakpointResolver {
|
||||
|
||||
function spanInFunctionBlock(block: Block): TypeScript.TextSpan {
|
||||
var nodeForSpanInBlock = block.statements.length ? block.statements[0] : block.getLastToken();
|
||||
if (canFunctionHaveSpanInWholeDeclaration(<FunctionDeclaration>block.parent)) {
|
||||
if (canFunctionHaveSpanInWholeDeclaration(<FunctionLikeDeclaration>block.parent)) {
|
||||
return spanInNodeIfStartsOnSameLine(block.parent, nodeForSpanInBlock);
|
||||
}
|
||||
|
||||
@ -350,7 +351,7 @@ module ts.BreakpointResolver {
|
||||
function spanInBlock(block: Block): TypeScript.TextSpan {
|
||||
switch (block.parent.kind) {
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
if (!isInstantiated(block.parent)) {
|
||||
if (getModuleInstanceState(block.parent) !== ModuleInstanceState.Instantiated) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -407,7 +408,7 @@ module ts.BreakpointResolver {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.ModuleBlock:
|
||||
// If this is not instantiated module block no bp span
|
||||
if (!isInstantiated(node.parent.parent)) {
|
||||
if (getModuleInstanceState(node.parent.parent) !== ModuleInstanceState.Instantiated) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export class Comment {
|
||||
constructor(private _trivia: ISyntaxTrivia,
|
||||
public endsLine: boolean,
|
||||
public _start: number,
|
||||
public _end: number) {
|
||||
}
|
||||
|
||||
public start(): number {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
public end(): number {
|
||||
return this._end;
|
||||
}
|
||||
|
||||
public fullText(): string {
|
||||
return this._trivia.fullText();
|
||||
}
|
||||
|
||||
public kind(): SyntaxKind {
|
||||
return this._trivia.kind();
|
||||
}
|
||||
|
||||
public structuralEquals(ast: Comment, includingPosition: boolean): boolean {
|
||||
if (includingPosition) {
|
||||
if (this.start() !== ast.start() || this.end() !== ast.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return this._trivia.fullText() === ast._trivia.fullText() &&
|
||||
this.endsLine === ast.endsLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,759 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.ASTHelpers {
|
||||
|
||||
|
||||
var sentinelEmptyArray: any[] = [];
|
||||
|
||||
//export function scriptIsElided(sourceUnit: SourceUnitSyntax): boolean {
|
||||
// return isDTSFile(sourceUnit.syntaxTree.fileName()) || moduleMembersAreElided(sourceUnit.moduleElements);
|
||||
//}
|
||||
|
||||
//export function moduleIsElided(declaration: ModuleDeclarationSyntax): boolean {
|
||||
// return hasModifier(declaration.modifiers, PullElementFlags.Ambient) || moduleMembersAreElided(declaration.moduleElements);
|
||||
//}
|
||||
|
||||
//function moduleMembersAreElided(members: IModuleElementSyntax[]): boolean {
|
||||
// for (var i = 0, n = members.length; i < n; i++) {
|
||||
// var member = members[i];
|
||||
|
||||
// // We should emit *this* module if it contains any non-interface types.
|
||||
// // Caveat: if we have contain a module, then we should be emitted *if we want to
|
||||
// // emit that inner module as well.
|
||||
// if (member.kind() === SyntaxKind.ModuleDeclaration) {
|
||||
// if (!moduleIsElided(<ModuleDeclarationSyntax>member)) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// else if (member.kind() !== SyntaxKind.InterfaceDeclaration) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return true;
|
||||
//}
|
||||
|
||||
//export function enumIsElided(declaration: EnumDeclarationSyntax): boolean {
|
||||
// if (hasModifier(declaration.modifiers, PullElementFlags.Ambient)) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// return false;
|
||||
//}
|
||||
|
||||
export function isValidAstNode(ast: ISyntaxElement): boolean {
|
||||
return ast && !isShared(ast) && start(ast) !== -1 && end(ast) !== -1;
|
||||
}
|
||||
|
||||
export function isValidSpan(ast: ISpan): boolean {
|
||||
if (!ast)
|
||||
return false;
|
||||
|
||||
if (ast.start() === -1 || ast.end() === -1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///
|
||||
/// Return the ISyntaxElement containing "position"
|
||||
///
|
||||
export function getAstAtPosition(script: ISyntaxElement, pos: number, useTrailingTriviaAsLimChar: boolean = true, forceInclusive: boolean = false): ISyntaxElement {
|
||||
var top: ISyntaxElement = null;
|
||||
|
||||
var pre = function (cur: ISyntaxElement, walker: IAstWalker) {
|
||||
if (!isShared(cur) && isValidAstNode(cur)) {
|
||||
var isInvalid1 = cur.kind() === SyntaxKind.ExpressionStatement && width(cur) === 0;
|
||||
|
||||
if (isInvalid1) {
|
||||
walker.options.goChildren = false;
|
||||
}
|
||||
else {
|
||||
// Add "cur" to the stack if it contains our position
|
||||
// For "identifier" nodes, we need a special case: A position equal to "limChar" is
|
||||
// valid, since the position corresponds to a caret position (in between characters)
|
||||
// For example:
|
||||
// bar
|
||||
// 0123
|
||||
// If "position === 3", the caret is at the "right" of the "r" character, which should be considered valid
|
||||
var inclusive =
|
||||
forceInclusive ||
|
||||
cur.kind() === SyntaxKind.IdentifierName ||
|
||||
cur.kind() === SyntaxKind.MemberAccessExpression ||
|
||||
cur.kind() === SyntaxKind.QualifiedName ||
|
||||
//cur.kind() === SyntaxKind.TypeRef ||
|
||||
cur.kind() === SyntaxKind.VariableDeclaration ||
|
||||
cur.kind() === SyntaxKind.VariableDeclarator ||
|
||||
cur.kind() === SyntaxKind.InvocationExpression ||
|
||||
pos === end(script) + lastToken(script).trailingTriviaWidth(); // Special "EOF" case
|
||||
|
||||
var minChar = start(cur);
|
||||
var limChar = end(cur) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(cur) : 0) + (inclusive ? 1 : 0);
|
||||
if (pos >= minChar && pos < limChar) {
|
||||
|
||||
// Ignore empty lists
|
||||
if ((cur.kind() !== SyntaxKind.List && cur.kind() !== SyntaxKind.SeparatedList) || end(cur) > start(cur)) {
|
||||
// TODO: Since ISyntaxElement is sometimes not correct wrt to position, only add "cur" if it's better
|
||||
// than top of the stack.
|
||||
if (top === null) {
|
||||
top = cur;
|
||||
}
|
||||
else if (start(cur) >= start(top) &&
|
||||
(end(cur) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(cur) : 0)) <= (end(top) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(top) : 0))) {
|
||||
// this new node appears to be better than the one we're
|
||||
// storing. Make this the new node.
|
||||
|
||||
// However, If the current top is a missing identifier, we
|
||||
// don't want to replace it with another missing identifier.
|
||||
// We want to return the first missing identifier found in a
|
||||
// depth first walk of the tree.
|
||||
if (width(top) !== 0 || width(cur) !== 0) {
|
||||
top = cur;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't go further down the tree if pos is outside of [minChar, limChar]
|
||||
walker.options.goChildren = (minChar <= pos && pos <= limChar);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getAstWalkerFactory().walk(script, pre);
|
||||
return top;
|
||||
}
|
||||
|
||||
export function getExtendsHeritageClause(clauses: HeritageClauseSyntax[]): HeritageClauseSyntax {
|
||||
return getHeritageClause(clauses, SyntaxKind.ExtendsHeritageClause);
|
||||
}
|
||||
|
||||
export function getImplementsHeritageClause(clauses: HeritageClauseSyntax[]): HeritageClauseSyntax {
|
||||
return getHeritageClause(clauses, SyntaxKind.ImplementsHeritageClause);
|
||||
}
|
||||
|
||||
function getHeritageClause(clauses: HeritageClauseSyntax[], kind: SyntaxKind): HeritageClauseSyntax {
|
||||
if (clauses) {
|
||||
for (var i = 0, n = clauses.length; i < n; i++) {
|
||||
var child = clauses[i];
|
||||
|
||||
if (child.typeNames.length > 0 && child.kind() === kind) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function isCallExpression(ast: ISyntaxElement): boolean {
|
||||
return (ast && ast.kind() === SyntaxKind.InvocationExpression) ||
|
||||
(ast && ast.kind() === SyntaxKind.ObjectCreationExpression);
|
||||
}
|
||||
|
||||
export function isCallExpressionTarget(ast: ISyntaxElement): boolean {
|
||||
return !!getCallExpressionTarget(ast);
|
||||
}
|
||||
|
||||
export function getCallExpressionTarget(ast: ISyntaxElement): ISyntaxElement {
|
||||
if (!ast) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var current = ast;
|
||||
|
||||
while (current && current.parent) {
|
||||
if (current.parent.kind() === SyntaxKind.MemberAccessExpression &&
|
||||
(<MemberAccessExpressionSyntax>current.parent).name === current) {
|
||||
current = current.parent;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (current && current.parent) {
|
||||
if (current.parent.kind() === SyntaxKind.InvocationExpression || current.parent.kind() === SyntaxKind.ObjectCreationExpression) {
|
||||
return current === (<InvocationExpressionSyntax>current.parent).expression ? current : null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function isNameOfSomeDeclaration(ast: ISyntaxElement) {
|
||||
if (ast === null || ast.parent === null) {
|
||||
return false;
|
||||
}
|
||||
if (ast.kind() !== SyntaxKind.IdentifierName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (ast.parent.kind()) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return (<ClassDeclarationSyntax>ast.parent).identifier === ast;
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return (<InterfaceDeclarationSyntax>ast.parent).identifier === ast;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return (<EnumDeclarationSyntax>ast.parent).identifier === ast;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return (<ModuleDeclarationSyntax>ast.parent).name === ast || (<ModuleDeclarationSyntax>ast.parent).stringLiteral === ast;
|
||||
case SyntaxKind.VariableDeclarator:
|
||||
return (<VariableDeclaratorSyntax>ast.parent).propertyName === ast;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return (<FunctionDeclarationSyntax>ast.parent).identifier === ast;
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
return (<MemberFunctionDeclarationSyntax>ast.parent).propertyName === ast;
|
||||
case SyntaxKind.Parameter:
|
||||
return (<ParameterSyntax>ast.parent).identifier === ast;
|
||||
case SyntaxKind.TypeParameter:
|
||||
return (<TypeParameterSyntax>ast.parent).identifier === ast;
|
||||
case SyntaxKind.SimplePropertyAssignment:
|
||||
return (<SimplePropertyAssignmentSyntax>ast.parent).propertyName === ast;
|
||||
case SyntaxKind.FunctionPropertyAssignment:
|
||||
return (<FunctionPropertyAssignmentSyntax>ast.parent).propertyName === ast;
|
||||
case SyntaxKind.EnumElement:
|
||||
return (<EnumElementSyntax>ast.parent).propertyName === ast;
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return (<ImportDeclarationSyntax>ast.parent).identifier === ast;
|
||||
case SyntaxKind.MethodSignature:
|
||||
return (<MethodSignatureSyntax>ast.parent).propertyName === ast;
|
||||
case SyntaxKind.PropertySignature:
|
||||
return (<MethodSignatureSyntax>ast.parent).propertyName === ast;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isDeclarationASTOrDeclarationNameAST(ast: ISyntaxElement) {
|
||||
return isNameOfSomeDeclaration(ast) || ASTHelpers.isDeclarationAST(ast);
|
||||
}
|
||||
|
||||
export function getEnclosingParameterForInitializer(ast: ISyntaxElement): ParameterSyntax {
|
||||
var current = ast;
|
||||
while (current) {
|
||||
switch (current.kind()) {
|
||||
case SyntaxKind.EqualsValueClause:
|
||||
if (current.parent && current.parent.kind() === SyntaxKind.Parameter) {
|
||||
return <ParameterSyntax>current.parent;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
// exit early
|
||||
return null;
|
||||
}
|
||||
|
||||
current = current.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getEnclosingMemberDeclaration(ast: ISyntaxElement): ISyntaxElement {
|
||||
var current = ast;
|
||||
|
||||
while (current) {
|
||||
switch (current.kind()) {
|
||||
case SyntaxKind.MemberVariableDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return current;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
// exit early
|
||||
return null;
|
||||
}
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function isNameOfFunction(ast: ISyntaxElement) {
|
||||
return ast
|
||||
&& ast.parent
|
||||
&& ast.kind() === SyntaxKind.IdentifierName
|
||||
&& ast.parent.kind() === SyntaxKind.FunctionDeclaration
|
||||
&& (<FunctionDeclarationSyntax>ast.parent).identifier === ast;
|
||||
}
|
||||
|
||||
export function isNameOfMemberFunction(ast: ISyntaxElement) {
|
||||
return ast
|
||||
&& ast.parent
|
||||
&& ast.kind() === SyntaxKind.IdentifierName
|
||||
&& ast.parent.kind() === SyntaxKind.MemberFunctionDeclaration
|
||||
&& (<MemberFunctionDeclarationSyntax>ast.parent).propertyName === ast;
|
||||
}
|
||||
|
||||
export function isNameOfMemberAccessExpression(ast: ISyntaxElement) {
|
||||
if (ast &&
|
||||
ast.parent &&
|
||||
ast.parent.kind() === SyntaxKind.MemberAccessExpression &&
|
||||
(<MemberAccessExpressionSyntax>ast.parent).name === ast) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isRightSideOfQualifiedName(ast: ISyntaxElement) {
|
||||
if (ast &&
|
||||
ast.parent &&
|
||||
ast.parent.kind() === SyntaxKind.QualifiedName &&
|
||||
(<QualifiedNameSyntax>ast.parent).right === ast) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function parentIsModuleDeclaration(ast: ISyntaxElement) {
|
||||
return ast.parent && ast.parent.kind() === SyntaxKind.ModuleDeclaration;
|
||||
}
|
||||
|
||||
export function isDeclarationAST(ast: ISyntaxElement): boolean {
|
||||
switch (ast.kind()) {
|
||||
case SyntaxKind.VariableDeclarator:
|
||||
return getVariableStatement(<VariableDeclaratorSyntax>ast) !== null;
|
||||
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.SimpleArrowFunctionExpression:
|
||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ArrayType:
|
||||
case SyntaxKind.ObjectType:
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.ConstructorDeclaration:
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.MemberVariableDeclaration:
|
||||
case SyntaxKind.IndexMemberDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.EnumElement:
|
||||
case SyntaxKind.SimplePropertyAssignment:
|
||||
case SyntaxKind.FunctionPropertyAssignment:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.PropertySignature:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function preComments(element: ISyntaxElement, text: ISimpleText): Comment[]{
|
||||
if (element) {
|
||||
switch (element.kind()) {
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.SimplePropertyAssignment:
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.ConstructorDeclaration:
|
||||
case SyntaxKind.MemberVariableDeclaration:
|
||||
case SyntaxKind.EnumElement:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.FunctionPropertyAssignment:
|
||||
case SyntaxKind.Parameter:
|
||||
return convertNodeLeadingComments(element, text);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function postComments(element: ISyntaxElement, text: ISimpleText): Comment[] {
|
||||
if (element) {
|
||||
switch (element.kind()) {
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
return convertNodeTrailingComments(element, text, /*allowWithNewLine:*/ true);
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.SimplePropertyAssignment:
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.ConstructorDeclaration:
|
||||
case SyntaxKind.MemberVariableDeclaration:
|
||||
case SyntaxKind.EnumElement:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.FunctionPropertyAssignment:
|
||||
case SyntaxKind.Parameter:
|
||||
return convertNodeTrailingComments(element, text);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function convertNodeTrailingComments(node: ISyntaxElement, text: ISimpleText, allowWithNewLine = false): Comment[]{
|
||||
// Bail out quickly before doing any expensive math computation.
|
||||
var _lastToken = lastToken(node);
|
||||
if (_lastToken === null || !_lastToken.hasTrailingTrivia()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!allowWithNewLine && SyntaxUtilities.isLastTokenOnLine(_lastToken, text)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return convertComments(_lastToken.trailingTrivia(text), fullStart(node) + fullWidth(node) - _lastToken.trailingTriviaWidth(text));
|
||||
}
|
||||
|
||||
function convertNodeLeadingComments(element: ISyntaxElement, text: ISimpleText): Comment[]{
|
||||
if (element) {
|
||||
return convertTokenLeadingComments(firstToken(element), text);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function convertTokenLeadingComments(token: ISyntaxToken, text: ISimpleText): Comment[]{
|
||||
if (token === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return token.hasLeadingTrivia()
|
||||
? convertComments(token.leadingTrivia(text), token.fullStart())
|
||||
: null;
|
||||
}
|
||||
|
||||
export function convertTokenTrailingComments(token: ISyntaxToken, text: ISimpleText): Comment[] {
|
||||
if (token === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return token.hasTrailingTrivia()
|
||||
? convertComments(token.trailingTrivia(text), fullEnd(token) - token.trailingTriviaWidth(text))
|
||||
: null;
|
||||
}
|
||||
|
||||
function convertComments(triviaList: ISyntaxTriviaList, commentStartPosition: number): Comment[]{
|
||||
var result: Comment[] = null;
|
||||
|
||||
for (var i = 0, n = triviaList.count(); i < n; i++) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
|
||||
if (trivia.isComment()) {
|
||||
var hasTrailingNewLine = ((i + 1) < n) && triviaList.syntaxTriviaAt(i + 1).isNewLine();
|
||||
result = result || [];
|
||||
result.push(convertComment(trivia, commentStartPosition, hasTrailingNewLine));
|
||||
}
|
||||
|
||||
commentStartPosition += trivia.fullWidth();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertComment(trivia: ISyntaxTrivia, commentStartPosition: number, hasTrailingNewLine: boolean): Comment {
|
||||
var comment = new Comment(trivia, hasTrailingNewLine, commentStartPosition, commentStartPosition + trivia.fullWidth());
|
||||
|
||||
return comment;
|
||||
}
|
||||
|
||||
export function docComments(ast: ISyntaxElement, text: ISimpleText): Comment[] {
|
||||
if (isDeclarationAST(ast)) {
|
||||
var comments: Comment[] = null;
|
||||
|
||||
if (ast.kind() === SyntaxKind.VariableDeclarator) {
|
||||
// Get the doc comments for a variable off of the variable statement. That's what
|
||||
// they'll be attached to in the tree.
|
||||
comments = TypeScript.ASTHelpers.preComments(getVariableStatement(<VariableDeclaratorSyntax>ast), text);
|
||||
}
|
||||
else if (ast.kind() === SyntaxKind.Parameter) {
|
||||
// First check if the parameter was written like so:
|
||||
// (
|
||||
// /** blah */ a,
|
||||
// /** blah */ b);
|
||||
comments = TypeScript.ASTHelpers.preComments(ast, text);
|
||||
if (!comments) {
|
||||
// Now check if it was written like so:
|
||||
// (/** blah */ a, /** blah */ b);
|
||||
// In this case, the comment will belong to the preceding token.
|
||||
var previousToken = findToken(syntaxTree(ast).sourceUnit(), firstToken(ast).fullStart() - 1);
|
||||
if (previousToken && (previousToken.kind() === SyntaxKind.OpenParenToken || previousToken.kind() === SyntaxKind.CommaToken)) {
|
||||
comments = convertTokenTrailingComments(previousToken, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
comments = TypeScript.ASTHelpers.preComments(ast, text);
|
||||
}
|
||||
|
||||
if (comments && comments.length > 0) {
|
||||
return comments.filter(c => isDocComment(c));
|
||||
}
|
||||
}
|
||||
|
||||
return sentinelEmptyArray;
|
||||
}
|
||||
|
||||
export function isDocComment(comment: Comment) {
|
||||
if (comment.kind() === SyntaxKind.MultiLineCommentTrivia) {
|
||||
var fullText = comment.fullText();
|
||||
return fullText.charAt(2) === "*" && fullText.charAt(3) !== "/";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getParameterList(ast: ISyntaxElement): ParameterListSyntax {
|
||||
if (ast) {
|
||||
switch (ast.kind()) {
|
||||
case SyntaxKind.ConstructorDeclaration:
|
||||
return getParameterList((<ConstructorDeclarationSyntax>ast).callSignature);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return getParameterList((<FunctionDeclarationSyntax>ast).callSignature);
|
||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
return getParameterList((<ParenthesizedArrowFunctionExpressionSyntax>ast).callSignature);
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return getParameterList((<ConstructSignatureSyntax>ast).callSignature);
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
return getParameterList((<MemberFunctionDeclarationSyntax>ast).callSignature);
|
||||
case SyntaxKind.FunctionPropertyAssignment:
|
||||
return getParameterList((<FunctionPropertyAssignmentSyntax>ast).callSignature);
|
||||
case SyntaxKind.FunctionExpression:
|
||||
return getParameterList((<FunctionExpressionSyntax>ast).callSignature);
|
||||
case SyntaxKind.MethodSignature:
|
||||
return getParameterList((<MethodSignatureSyntax>ast).callSignature);
|
||||
case SyntaxKind.ConstructorType:
|
||||
return (<ConstructorTypeSyntax>ast).parameterList;
|
||||
case SyntaxKind.FunctionType:
|
||||
return (<FunctionTypeSyntax>ast).parameterList;
|
||||
case SyntaxKind.CallSignature:
|
||||
return (<CallSignatureSyntax>ast).parameterList;
|
||||
case SyntaxKind.GetAccessor:
|
||||
return getParameterList((<GetAccessorSyntax>ast).callSignature);
|
||||
case SyntaxKind.SetAccessor:
|
||||
return getParameterList((<SetAccessorSyntax>ast).callSignature);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getType(ast: ISyntaxElement): ITypeSyntax {
|
||||
if (ast) {
|
||||
switch (ast.kind()) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return getType((<FunctionDeclarationSyntax>ast).callSignature);
|
||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
return getType((<ParenthesizedArrowFunctionExpressionSyntax>ast).callSignature);
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return getType((<ConstructSignatureSyntax>ast).callSignature);
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
return getType((<MemberFunctionDeclarationSyntax>ast).callSignature);
|
||||
case SyntaxKind.FunctionPropertyAssignment:
|
||||
return getType((<FunctionPropertyAssignmentSyntax>ast).callSignature);
|
||||
case SyntaxKind.FunctionExpression:
|
||||
return getType((<FunctionExpressionSyntax>ast).callSignature);
|
||||
case SyntaxKind.MethodSignature:
|
||||
return getType((<MethodSignatureSyntax>ast).callSignature);
|
||||
case SyntaxKind.CallSignature:
|
||||
return getType((<CallSignatureSyntax>ast).typeAnnotation);
|
||||
case SyntaxKind.IndexSignature:
|
||||
return getType((<IndexSignatureSyntax>ast).typeAnnotation);
|
||||
case SyntaxKind.PropertySignature:
|
||||
return getType((<PropertySignatureSyntax>ast).typeAnnotation);
|
||||
case SyntaxKind.GetAccessor:
|
||||
return getType((<GetAccessorSyntax>ast).callSignature);
|
||||
case SyntaxKind.Parameter:
|
||||
return getType((<ParameterSyntax>ast).typeAnnotation);
|
||||
case SyntaxKind.MemberVariableDeclaration:
|
||||
return getType((<MemberVariableDeclarationSyntax>ast).variableDeclarator);
|
||||
case SyntaxKind.VariableDeclarator:
|
||||
return getType((<VariableDeclaratorSyntax>ast).typeAnnotation);
|
||||
case SyntaxKind.CatchClause:
|
||||
return getType((<CatchClauseSyntax>ast).typeAnnotation);
|
||||
case SyntaxKind.ConstructorType:
|
||||
return (<ConstructorTypeSyntax>ast).type;
|
||||
case SyntaxKind.FunctionType:
|
||||
return (<FunctionTypeSyntax>ast).type;
|
||||
case SyntaxKind.TypeAnnotation:
|
||||
return (<TypeAnnotationSyntax>ast).type;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getVariableStatement(variableDeclarator: VariableDeclaratorSyntax): VariableStatementSyntax {
|
||||
if (variableDeclarator && variableDeclarator.parent && variableDeclarator.parent.parent && variableDeclarator.parent.parent.parent &&
|
||||
variableDeclarator.parent.kind() === SyntaxKind.SeparatedList &&
|
||||
variableDeclarator.parent.parent.kind() === SyntaxKind.VariableDeclaration &&
|
||||
variableDeclarator.parent.parent.parent.kind() === SyntaxKind.VariableStatement) {
|
||||
|
||||
return <VariableStatementSyntax>variableDeclarator.parent.parent.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function getVariableDeclaratorModifiers(variableDeclarator: VariableDeclaratorSyntax): ISyntaxToken[] {
|
||||
var variableStatement = getVariableStatement(variableDeclarator);
|
||||
return variableStatement ? variableStatement.modifiers : Syntax.emptyList<ISyntaxToken>();
|
||||
}
|
||||
|
||||
export function isIntegerLiteralAST(expression: ISyntaxElement): boolean {
|
||||
if (expression) {
|
||||
switch (expression.kind()) {
|
||||
case SyntaxKind.PlusExpression:
|
||||
case SyntaxKind.NegateExpression:
|
||||
// Note: if there is a + or - sign, we can only allow a normal integer following
|
||||
// (and not a hex integer). i.e. -0xA is a legal expression, but it is not a
|
||||
// *literal*.
|
||||
expression = (<PrefixUnaryExpressionSyntax>expression).operand;
|
||||
return expression.kind() === SyntaxKind.NumericLiteral && IntegerUtilities.isInteger((<ISyntaxToken>expression).text());
|
||||
|
||||
case SyntaxKind.NumericLiteral:
|
||||
// If it doesn't have a + or -, then either an integer literal or a hex literal
|
||||
// is acceptable.
|
||||
var text = (<ISyntaxToken>expression).text();
|
||||
return IntegerUtilities.isInteger(text) || IntegerUtilities.isHexInteger(text);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getEnclosingModuleDeclaration(ast: ISyntaxElement): ModuleDeclarationSyntax {
|
||||
while (ast) {
|
||||
if (ast.kind() === SyntaxKind.ModuleDeclaration) {
|
||||
return <ModuleDeclarationSyntax>ast;
|
||||
}
|
||||
|
||||
ast = ast.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function isEntireNameOfModuleDeclaration(nameAST: ISyntaxElement) {
|
||||
return parentIsModuleDeclaration(nameAST) && (<ModuleDeclarationSyntax>nameAST.parent).name === nameAST;
|
||||
}
|
||||
|
||||
export function getModuleDeclarationFromNameAST(ast: ISyntaxElement): ModuleDeclarationSyntax {
|
||||
if (ast) {
|
||||
switch (ast.kind()) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
if (parentIsModuleDeclaration(ast) && (<ModuleDeclarationSyntax>ast.parent).stringLiteral === ast) {
|
||||
return <ModuleDeclarationSyntax>ast.parent;
|
||||
}
|
||||
return null;
|
||||
|
||||
case SyntaxKind.IdentifierName:
|
||||
case SyntaxKind.QualifiedName:
|
||||
if (isEntireNameOfModuleDeclaration(ast)) {
|
||||
return <ModuleDeclarationSyntax>ast.parent;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
// Only qualified names can be name of module declaration if they didnt satisfy above conditions
|
||||
for (ast = ast.parent; ast && ast.kind() === SyntaxKind.QualifiedName; ast = ast.parent) {
|
||||
if (isEntireNameOfModuleDeclaration(ast)) {
|
||||
return <ModuleDeclarationSyntax>ast.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function isLastNameOfModule(ast: ModuleDeclarationSyntax, astName: ISyntaxElement): boolean {
|
||||
if (ast) {
|
||||
if (ast.stringLiteral) {
|
||||
return astName === ast.stringLiteral;
|
||||
}
|
||||
else if (ast.name.kind() === SyntaxKind.QualifiedName) {
|
||||
return astName === (<QualifiedNameSyntax>ast.name).right;
|
||||
}
|
||||
else {
|
||||
return astName === ast.name;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getNameOfIdentifierOrQualifiedName(name: ISyntaxElement): string {
|
||||
if (name.kind() === SyntaxKind.IdentifierName) {
|
||||
return (<ISyntaxToken>name).text();
|
||||
}
|
||||
else {
|
||||
Debug.assert(name.kind() == SyntaxKind.QualifiedName);
|
||||
var dotExpr = <QualifiedNameSyntax>name;
|
||||
return getNameOfIdentifierOrQualifiedName(dotExpr.left) + "." + getNameOfIdentifierOrQualifiedName(dotExpr.right);
|
||||
}
|
||||
}
|
||||
|
||||
export function getModuleNames(name: ISyntaxElement, result?: ISyntaxToken[]): ISyntaxToken[] {
|
||||
result = result || [];
|
||||
|
||||
if (name.kind() === SyntaxKind.QualifiedName) {
|
||||
getModuleNames((<QualifiedNameSyntax>name).left, result);
|
||||
result.push((<QualifiedNameSyntax>name).right);
|
||||
}
|
||||
else {
|
||||
result.push(<ISyntaxToken>name);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@ -1,721 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
function walkListChildren(preAst: ISyntaxNodeOrToken[], walker: AstWalker): void {
|
||||
for (var i = 0, n = preAst.length; i < n; i++) {
|
||||
walker.walk(preAst[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function walkThrowStatementChildren(preAst: ThrowStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkPrefixUnaryExpressionChildren(preAst: PrefixUnaryExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.operand);
|
||||
}
|
||||
|
||||
function walkPostfixUnaryExpressionChildren(preAst: PostfixUnaryExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.operand);
|
||||
}
|
||||
|
||||
function walkDeleteExpressionChildren(preAst: DeleteExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkTypeArgumentListChildren(preAst: TypeArgumentListSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeArguments);
|
||||
}
|
||||
|
||||
function walkTupleTypeChildren(preAst: TupleTypeSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.types);
|
||||
}
|
||||
|
||||
function walkTypeOfExpressionChildren(preAst: TypeOfExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkVoidExpressionChildren(preAst: VoidExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkArgumentListChildren(preAst: ArgumentListSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeArgumentList);
|
||||
walker.walk(preAst.arguments);
|
||||
}
|
||||
|
||||
function walkArrayLiteralExpressionChildren(preAst: ArrayLiteralExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expressions);
|
||||
}
|
||||
|
||||
function walkSimplePropertyAssignmentChildren(preAst: SimplePropertyAssignmentSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkFunctionPropertyAssignmentChildren(preAst: FunctionPropertyAssignmentSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.callSignature);
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkGetAccessorChildren(preAst: GetAccessorSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.callSignature);
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkSeparatedListChildren(preAst: ISyntaxNodeOrToken[], walker: AstWalker): void {
|
||||
for (var i = 0, n = preAst.length; i < n; i++) {
|
||||
walker.walk(preAst[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function walkSetAccessorChildren(preAst: SetAccessorSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.callSignature);
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkObjectLiteralExpressionChildren(preAst: ObjectLiteralExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyAssignments);
|
||||
}
|
||||
|
||||
function walkCastExpressionChildren(preAst: CastExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.type);
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkParenthesizedExpressionChildren(preAst: ParenthesizedExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkElementAccessExpressionChildren(preAst: ElementAccessExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
walker.walk(preAst.argumentExpression);
|
||||
}
|
||||
|
||||
function walkMemberAccessExpressionChildren(preAst: MemberAccessExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
walker.walk(preAst.name);
|
||||
}
|
||||
|
||||
function walkQualifiedNameChildren(preAst: QualifiedNameSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.left);
|
||||
walker.walk(preAst.right);
|
||||
}
|
||||
|
||||
function walkBinaryExpressionChildren(preAst: BinaryExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.left);
|
||||
walker.walk(preAst.right);
|
||||
}
|
||||
|
||||
function walkEqualsValueClauseChildren(preAst: EqualsValueClauseSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.value);
|
||||
}
|
||||
|
||||
function walkTypeParameterChildren(preAst: TypeParameterSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.constraint);
|
||||
}
|
||||
|
||||
function walkTypeParameterListChildren(preAst: TypeParameterListSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeParameters);
|
||||
}
|
||||
|
||||
function walkGenericTypeChildren(preAst: GenericTypeSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.name);
|
||||
walker.walk(preAst.typeArgumentList);
|
||||
}
|
||||
|
||||
function walkTypeAnnotationChildren(preAst: TypeAnnotationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.type);
|
||||
}
|
||||
|
||||
function walkTypeQueryChildren(preAst: TypeQuerySyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.name);
|
||||
}
|
||||
|
||||
function walkInvocationExpressionChildren(preAst: InvocationExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
walker.walk(preAst.argumentList);
|
||||
}
|
||||
|
||||
function walkObjectCreationExpressionChildren(preAst: ObjectCreationExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
walker.walk(preAst.argumentList);
|
||||
}
|
||||
|
||||
function walkTrinaryExpressionChildren(preAst: ConditionalExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.condition);
|
||||
walker.walk(preAst.whenTrue);
|
||||
walker.walk(preAst.whenFalse);
|
||||
}
|
||||
|
||||
function walkFunctionExpressionChildren(preAst: FunctionExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.callSignature);
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkFunctionTypeChildren(preAst: FunctionTypeSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeParameterList);
|
||||
walker.walk(preAst.parameterList);
|
||||
walker.walk(preAst.type);
|
||||
}
|
||||
|
||||
function walkParenthesizedArrowFunctionExpressionChildren(preAst: ParenthesizedArrowFunctionExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.callSignature);
|
||||
walker.walk(preAst.block);
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkSimpleArrowFunctionExpressionChildren(preAst: SimpleArrowFunctionExpressionSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.parameter);
|
||||
walker.walk(preAst.block);
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkMemberFunctionDeclarationChildren(preAst: MemberFunctionDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.callSignature);
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkFuncDeclChildren(preAst: FunctionDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.callSignature);
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkIndexMemberDeclarationChildren(preAst: IndexMemberDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.indexSignature);
|
||||
}
|
||||
|
||||
function walkIndexSignatureChildren(preAst: IndexSignatureSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.parameters);
|
||||
walker.walk(preAst.typeAnnotation);
|
||||
}
|
||||
|
||||
function walkCallSignatureChildren(preAst: CallSignatureSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeParameterList);
|
||||
walker.walk(preAst.parameterList);
|
||||
walker.walk(preAst.typeAnnotation);
|
||||
}
|
||||
|
||||
function walkConstraintChildren(preAst: ConstraintSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeOrExpression);
|
||||
}
|
||||
|
||||
function walkConstructorDeclarationChildren(preAst: ConstructorDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.callSignature);
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkConstructorTypeChildren(preAst: FunctionTypeSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeParameterList);
|
||||
walker.walk(preAst.parameterList);
|
||||
walker.walk(preAst.type);
|
||||
}
|
||||
|
||||
function walkConstructSignatureChildren(preAst: ConstructSignatureSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.callSignature);
|
||||
}
|
||||
|
||||
function walkParameterChildren(preAst: ParameterSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.typeAnnotation);
|
||||
walker.walk(preAst.equalsValueClause);
|
||||
}
|
||||
|
||||
function walkParameterListChildren(preAst: ParameterListSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.parameters);
|
||||
}
|
||||
|
||||
function walkPropertySignatureChildren(preAst: PropertySignatureSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.typeAnnotation);
|
||||
}
|
||||
|
||||
function walkVariableDeclaratorChildren(preAst: VariableDeclaratorSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.typeAnnotation);
|
||||
walker.walk(preAst.equalsValueClause);
|
||||
}
|
||||
|
||||
function walkMemberVariableDeclarationChildren(preAst: MemberVariableDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.variableDeclarator);
|
||||
}
|
||||
|
||||
function walkMethodSignatureChildren(preAst: MethodSignatureSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.callSignature);
|
||||
}
|
||||
|
||||
function walkReturnStatementChildren(preAst: ReturnStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkForStatementChildren(preAst: ForStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.variableDeclaration);
|
||||
walker.walk(preAst.initializer);
|
||||
walker.walk(preAst.condition);
|
||||
walker.walk(preAst.incrementor);
|
||||
walker.walk(preAst.statement);
|
||||
}
|
||||
|
||||
function walkForInStatementChildren(preAst: ForInStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.variableDeclaration);
|
||||
walker.walk(preAst.left);
|
||||
walker.walk(preAst.expression);
|
||||
walker.walk(preAst.statement);
|
||||
}
|
||||
|
||||
function walkIfStatementChildren(preAst: IfStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.condition);
|
||||
walker.walk(preAst.statement);
|
||||
walker.walk(preAst.elseClause);
|
||||
}
|
||||
|
||||
function walkElseClauseChildren(preAst: ElseClauseSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.statement);
|
||||
}
|
||||
|
||||
function walkWhileStatementChildren(preAst: WhileStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.condition);
|
||||
walker.walk(preAst.statement);
|
||||
}
|
||||
|
||||
function walkDoStatementChildren(preAst: DoStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.condition);
|
||||
walker.walk(preAst.statement);
|
||||
}
|
||||
|
||||
function walkBlockChildren(preAst: BlockSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.statements);
|
||||
}
|
||||
|
||||
function walkVariableDeclarationChildren(preAst: VariableDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.variableDeclarators);
|
||||
}
|
||||
|
||||
function walkCaseSwitchClauseChildren(preAst: CaseSwitchClauseSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
walker.walk(preAst.statements);
|
||||
}
|
||||
|
||||
function walkDefaultSwitchClauseChildren(preAst: DefaultSwitchClauseSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.statements);
|
||||
}
|
||||
|
||||
function walkSwitchStatementChildren(preAst: SwitchStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
walker.walk(preAst.switchClauses);
|
||||
}
|
||||
|
||||
function walkTryStatementChildren(preAst: TryStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.block);
|
||||
walker.walk(preAst.catchClause);
|
||||
walker.walk(preAst.finallyClause);
|
||||
}
|
||||
|
||||
function walkCatchClauseChildren(preAst: CatchClauseSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.typeAnnotation);
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkExternalModuleReferenceChildren(preAst: ExternalModuleReferenceSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.stringLiteral);
|
||||
}
|
||||
|
||||
function walkFinallyClauseChildren(preAst: FinallyClauseSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.block);
|
||||
}
|
||||
|
||||
function walkClassDeclChildren(preAst: ClassDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.typeParameterList);
|
||||
walker.walk(preAst.heritageClauses);
|
||||
walker.walk(preAst.classElements);
|
||||
}
|
||||
|
||||
function walkScriptChildren(preAst: SourceUnitSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.moduleElements);
|
||||
}
|
||||
|
||||
function walkHeritageClauseChildren(preAst: HeritageClauseSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeNames);
|
||||
}
|
||||
|
||||
function walkInterfaceDeclerationChildren(preAst: InterfaceDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.typeParameterList);
|
||||
walker.walk(preAst.heritageClauses);
|
||||
walker.walk(preAst.body);
|
||||
}
|
||||
|
||||
function walkObjectTypeChildren(preAst: ObjectTypeSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.typeMembers);
|
||||
}
|
||||
|
||||
function walkArrayTypeChildren(preAst: ArrayTypeSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.type);
|
||||
}
|
||||
|
||||
function walkModuleDeclarationChildren(preAst: ModuleDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.name);
|
||||
walker.walk(preAst.stringLiteral);
|
||||
walker.walk(preAst.moduleElements);
|
||||
}
|
||||
|
||||
function walkModuleNameModuleReferenceChildren(preAst: ModuleNameModuleReferenceSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.moduleName);
|
||||
}
|
||||
|
||||
function walkEnumDeclarationChildren(preAst: EnumDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.enumElements);
|
||||
}
|
||||
|
||||
function walkEnumElementChildren(preAst: EnumElementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.propertyName);
|
||||
walker.walk(preAst.equalsValueClause);
|
||||
}
|
||||
|
||||
function walkImportDeclarationChildren(preAst: ImportDeclarationSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.moduleReference);
|
||||
}
|
||||
|
||||
function walkExportAssignmentChildren(preAst: ExportAssignmentSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
}
|
||||
|
||||
function walkWithStatementChildren(preAst: WithStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.condition);
|
||||
walker.walk(preAst.statement);
|
||||
}
|
||||
|
||||
function walkExpressionStatementChildren(preAst: ExpressionStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.expression);
|
||||
}
|
||||
|
||||
function walkLabeledStatementChildren(preAst: LabeledStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.identifier);
|
||||
walker.walk(preAst.statement);
|
||||
}
|
||||
|
||||
function walkVariableStatementChildren(preAst: VariableStatementSyntax, walker: AstWalker): void {
|
||||
walker.walk(preAst.variableDeclaration);
|
||||
}
|
||||
|
||||
var childrenWalkers: IAstWalkChildren[] = new Array<IAstWalkChildren>(SyntaxKind.LastNode + 1);
|
||||
|
||||
// Tokens/trivia can't ever be walked into.
|
||||
for (var i = SyntaxKind.FirstToken, n = SyntaxKind.LastToken; i <= n; i++) {
|
||||
childrenWalkers[i] = null;
|
||||
}
|
||||
for (var i = SyntaxKind.FirstTrivia, n = SyntaxKind.LastTrivia; i <= n; i++) {
|
||||
childrenWalkers[i] = null;
|
||||
}
|
||||
|
||||
childrenWalkers[SyntaxKind.AddAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.AddExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.AndAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.AnyKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.ArgumentList] = walkArgumentListChildren;
|
||||
childrenWalkers[SyntaxKind.ArrayLiteralExpression] = walkArrayLiteralExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ArrayType] = walkArrayTypeChildren;
|
||||
childrenWalkers[SyntaxKind.SimpleArrowFunctionExpression] = walkSimpleArrowFunctionExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ParenthesizedArrowFunctionExpression] = walkParenthesizedArrowFunctionExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.AssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.BitwiseAndExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.BitwiseExclusiveOrExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.BitwiseNotExpression] = walkPrefixUnaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.BitwiseOrExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.Block] = walkBlockChildren;
|
||||
childrenWalkers[SyntaxKind.BooleanKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.BreakStatement] = null;
|
||||
childrenWalkers[SyntaxKind.CallSignature] = walkCallSignatureChildren;
|
||||
childrenWalkers[SyntaxKind.CaseSwitchClause] = walkCaseSwitchClauseChildren;
|
||||
childrenWalkers[SyntaxKind.CastExpression] = walkCastExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.CatchClause] = walkCatchClauseChildren;
|
||||
childrenWalkers[SyntaxKind.ClassDeclaration] = walkClassDeclChildren;
|
||||
childrenWalkers[SyntaxKind.CommaExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ConditionalExpression] = walkTrinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.Constraint] = walkConstraintChildren;
|
||||
childrenWalkers[SyntaxKind.ConstructorDeclaration] = walkConstructorDeclarationChildren;
|
||||
childrenWalkers[SyntaxKind.ConstructSignature] = walkConstructSignatureChildren;
|
||||
childrenWalkers[SyntaxKind.ContinueStatement] = null;
|
||||
childrenWalkers[SyntaxKind.ConstructorType] = walkConstructorTypeChildren;
|
||||
childrenWalkers[SyntaxKind.DebuggerStatement] = null;
|
||||
childrenWalkers[SyntaxKind.DefaultSwitchClause] = walkDefaultSwitchClauseChildren;
|
||||
childrenWalkers[SyntaxKind.DeleteExpression] = walkDeleteExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.DivideAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.DivideExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.DoStatement] = walkDoStatementChildren;
|
||||
childrenWalkers[SyntaxKind.ElementAccessExpression] = walkElementAccessExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ElseClause] = walkElseClauseChildren;
|
||||
childrenWalkers[SyntaxKind.EmptyStatement] = null;
|
||||
childrenWalkers[SyntaxKind.EnumDeclaration] = walkEnumDeclarationChildren;
|
||||
childrenWalkers[SyntaxKind.EnumElement] = walkEnumElementChildren;
|
||||
childrenWalkers[SyntaxKind.EqualsExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.EqualsValueClause] = walkEqualsValueClauseChildren;
|
||||
childrenWalkers[SyntaxKind.EqualsWithTypeConversionExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ExclusiveOrAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ExportAssignment] = walkExportAssignmentChildren;
|
||||
childrenWalkers[SyntaxKind.ExpressionStatement] = walkExpressionStatementChildren;
|
||||
childrenWalkers[SyntaxKind.ExtendsHeritageClause] = walkHeritageClauseChildren;
|
||||
childrenWalkers[SyntaxKind.ExternalModuleReference] = walkExternalModuleReferenceChildren;
|
||||
childrenWalkers[SyntaxKind.FalseKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.FinallyClause] = walkFinallyClauseChildren;
|
||||
childrenWalkers[SyntaxKind.ForInStatement] = walkForInStatementChildren;
|
||||
childrenWalkers[SyntaxKind.ForStatement] = walkForStatementChildren;
|
||||
childrenWalkers[SyntaxKind.FunctionDeclaration] = walkFuncDeclChildren;
|
||||
childrenWalkers[SyntaxKind.FunctionExpression] = walkFunctionExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.FunctionPropertyAssignment] = walkFunctionPropertyAssignmentChildren;
|
||||
childrenWalkers[SyntaxKind.FunctionType] = walkFunctionTypeChildren;
|
||||
childrenWalkers[SyntaxKind.GenericType] = walkGenericTypeChildren;
|
||||
childrenWalkers[SyntaxKind.GetAccessor] = walkGetAccessorChildren;
|
||||
childrenWalkers[SyntaxKind.GreaterThanExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.GreaterThanOrEqualExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.IfStatement] = walkIfStatementChildren;
|
||||
childrenWalkers[SyntaxKind.ImplementsHeritageClause] = walkHeritageClauseChildren;
|
||||
childrenWalkers[SyntaxKind.ImportDeclaration] = walkImportDeclarationChildren;
|
||||
childrenWalkers[SyntaxKind.IndexMemberDeclaration] = walkIndexMemberDeclarationChildren;
|
||||
childrenWalkers[SyntaxKind.IndexSignature] = walkIndexSignatureChildren;
|
||||
childrenWalkers[SyntaxKind.InExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.InstanceOfExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.InterfaceDeclaration] = walkInterfaceDeclerationChildren;
|
||||
childrenWalkers[SyntaxKind.InvocationExpression] = walkInvocationExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.LabeledStatement] = walkLabeledStatementChildren;
|
||||
childrenWalkers[SyntaxKind.LeftShiftAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.LeftShiftExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.LessThanExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.LessThanOrEqualExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.List] = walkListChildren;
|
||||
childrenWalkers[SyntaxKind.LogicalAndExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.LogicalNotExpression] = walkPrefixUnaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.LogicalOrExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.MemberAccessExpression] = walkMemberAccessExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.MemberFunctionDeclaration] = walkMemberFunctionDeclarationChildren;
|
||||
childrenWalkers[SyntaxKind.MemberVariableDeclaration] = walkMemberVariableDeclarationChildren;
|
||||
childrenWalkers[SyntaxKind.MethodSignature] = walkMethodSignatureChildren;
|
||||
childrenWalkers[SyntaxKind.ModuleDeclaration] = walkModuleDeclarationChildren;
|
||||
childrenWalkers[SyntaxKind.ModuleNameModuleReference] = walkModuleNameModuleReferenceChildren;
|
||||
childrenWalkers[SyntaxKind.ModuloAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ModuloExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.MultiplyAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.MultiplyExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.IdentifierName] = null;
|
||||
childrenWalkers[SyntaxKind.NegateExpression] = walkPrefixUnaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.None] = null;
|
||||
childrenWalkers[SyntaxKind.NotEqualsExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.NotEqualsWithTypeConversionExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.NullKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.NumberKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.NumericLiteral] = null;
|
||||
childrenWalkers[SyntaxKind.ObjectCreationExpression] = walkObjectCreationExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ObjectLiteralExpression] = walkObjectLiteralExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.ObjectType] = walkObjectTypeChildren;
|
||||
childrenWalkers[SyntaxKind.OmittedExpression] = null;
|
||||
childrenWalkers[SyntaxKind.OrAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.Parameter] = walkParameterChildren;
|
||||
childrenWalkers[SyntaxKind.ParameterList] = walkParameterListChildren;
|
||||
childrenWalkers[SyntaxKind.ParenthesizedExpression] = walkParenthesizedExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.PlusExpression] = walkPrefixUnaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.PostDecrementExpression] = walkPostfixUnaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.PostIncrementExpression] = walkPostfixUnaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.PreDecrementExpression] = walkPrefixUnaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.PreIncrementExpression] = walkPrefixUnaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.PropertySignature] = walkPropertySignatureChildren;
|
||||
childrenWalkers[SyntaxKind.QualifiedName] = walkQualifiedNameChildren;
|
||||
childrenWalkers[SyntaxKind.RegularExpressionLiteral] = null;
|
||||
childrenWalkers[SyntaxKind.ReturnStatement] = walkReturnStatementChildren;
|
||||
childrenWalkers[SyntaxKind.SourceUnit] = walkScriptChildren;
|
||||
childrenWalkers[SyntaxKind.SeparatedList] = walkSeparatedListChildren;
|
||||
childrenWalkers[SyntaxKind.SetAccessor] = walkSetAccessorChildren;
|
||||
childrenWalkers[SyntaxKind.SignedRightShiftAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.SignedRightShiftExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.SimplePropertyAssignment] = walkSimplePropertyAssignmentChildren;
|
||||
childrenWalkers[SyntaxKind.StringLiteral] = null;
|
||||
childrenWalkers[SyntaxKind.StringKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.SubtractAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.SubtractExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.SuperKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.SwitchStatement] = walkSwitchStatementChildren;
|
||||
childrenWalkers[SyntaxKind.ThisKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.ThrowStatement] = walkThrowStatementChildren;
|
||||
childrenWalkers[SyntaxKind.TriviaList] = null;
|
||||
childrenWalkers[SyntaxKind.TrueKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.TryStatement] = walkTryStatementChildren;
|
||||
childrenWalkers[SyntaxKind.TupleType] = walkTupleTypeChildren;
|
||||
childrenWalkers[SyntaxKind.TypeAnnotation] = walkTypeAnnotationChildren;
|
||||
childrenWalkers[SyntaxKind.TypeArgumentList] = walkTypeArgumentListChildren;
|
||||
childrenWalkers[SyntaxKind.TypeOfExpression] = walkTypeOfExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.TypeParameter] = walkTypeParameterChildren;
|
||||
childrenWalkers[SyntaxKind.TypeParameterList] = walkTypeParameterListChildren;
|
||||
childrenWalkers[SyntaxKind.TypeQuery] = walkTypeQueryChildren;
|
||||
childrenWalkers[SyntaxKind.UnsignedRightShiftAssignmentExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.UnsignedRightShiftExpression] = walkBinaryExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.VariableDeclaration] = walkVariableDeclarationChildren;
|
||||
childrenWalkers[SyntaxKind.VariableDeclarator] = walkVariableDeclaratorChildren;
|
||||
childrenWalkers[SyntaxKind.VariableStatement] = walkVariableStatementChildren;
|
||||
childrenWalkers[SyntaxKind.VoidExpression] = walkVoidExpressionChildren;
|
||||
childrenWalkers[SyntaxKind.VoidKeyword] = null;
|
||||
childrenWalkers[SyntaxKind.WhileStatement] = walkWhileStatementChildren;
|
||||
childrenWalkers[SyntaxKind.WithStatement] = walkWithStatementChildren;
|
||||
|
||||
// Verify the code is up to date with the enum
|
||||
for (var e in SyntaxKind) {
|
||||
if (SyntaxKind.hasOwnProperty(e) && StringUtilities.isString(SyntaxKind[e])) {
|
||||
TypeScript.Debug.assert(childrenWalkers[e] !== undefined, "Fix initWalkers: " + SyntaxKind[e]);
|
||||
}
|
||||
}
|
||||
|
||||
export class AstWalkOptions {
|
||||
public goChildren = true;
|
||||
public stopWalking = false;
|
||||
}
|
||||
|
||||
interface IAstWalkChildren {
|
||||
(preAst: ISyntaxElement, walker: AstWalker): void;
|
||||
}
|
||||
|
||||
export interface IAstWalker {
|
||||
options: AstWalkOptions;
|
||||
state: any
|
||||
}
|
||||
|
||||
interface AstWalker {
|
||||
walk(ast: ISyntaxElement): void;
|
||||
}
|
||||
|
||||
class SimplePreAstWalker implements AstWalker {
|
||||
public options: AstWalkOptions = new AstWalkOptions();
|
||||
|
||||
constructor(
|
||||
private pre: (ast: ISyntaxElement, state: any) => void,
|
||||
public state: any) {
|
||||
}
|
||||
|
||||
public walk(ast: ISyntaxElement): void {
|
||||
if (!ast) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pre(ast, this.state);
|
||||
|
||||
var walker = childrenWalkers[ast.kind()];
|
||||
if (walker) {
|
||||
walker(ast, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SimplePrePostAstWalker implements AstWalker {
|
||||
public options: AstWalkOptions = new AstWalkOptions();
|
||||
|
||||
constructor(
|
||||
private pre: (ast: ISyntaxElement, state: any) => void,
|
||||
private post: (ast: ISyntaxElement, state: any) => void,
|
||||
public state: any) {
|
||||
}
|
||||
|
||||
public walk(ast: ISyntaxElement): void {
|
||||
if (!ast) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pre(ast, this.state);
|
||||
|
||||
var walker = childrenWalkers[ast.kind()];
|
||||
if (walker) {
|
||||
walker(ast, this);
|
||||
}
|
||||
|
||||
this.post(ast, this.state);
|
||||
}
|
||||
}
|
||||
|
||||
class NormalAstWalker implements AstWalker {
|
||||
public options: AstWalkOptions = new AstWalkOptions();
|
||||
|
||||
constructor(
|
||||
private pre: (ast: ISyntaxElement, walker: IAstWalker) => void,
|
||||
private post: (ast: ISyntaxElement, walker: IAstWalker) => void,
|
||||
public state: any) {
|
||||
}
|
||||
|
||||
public walk(ast: ISyntaxElement): void {
|
||||
if (!ast) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're stopping, then bail out immediately.
|
||||
if (this.options.stopWalking) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pre(ast, this);
|
||||
|
||||
// If we were asked to stop, then stop.
|
||||
if (this.options.stopWalking) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.options.goChildren) {
|
||||
// Call the "walkChildren" function corresponding to "nodeType".
|
||||
var walker = childrenWalkers[ast.kind()];
|
||||
if (walker) {
|
||||
walker(ast, this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no go only applies to children of node issuing it
|
||||
this.options.goChildren = true;
|
||||
}
|
||||
|
||||
if (this.post) {
|
||||
this.post(ast, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class AstWalkerFactory {
|
||||
public walk(ast: ISyntaxElement, pre: (ast: ISyntaxElement, walker: IAstWalker) => void, post?: (ast: ISyntaxElement, walker: IAstWalker) => void, state?: any): void {
|
||||
new NormalAstWalker(pre, post, state).walk(ast);
|
||||
}
|
||||
|
||||
public simpleWalk(ast: ISyntaxElement, pre: (ast: ISyntaxElement, state: any) => void, post?: (ast: ISyntaxElement, state: any) => void, state?: any): void {
|
||||
if (post) {
|
||||
new SimplePrePostAstWalker(pre, post, state).walk(ast);
|
||||
}
|
||||
else {
|
||||
new SimplePreAstWalker(pre, state).walk(ast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var globalAstWalkerFactory = new AstWalkerFactory();
|
||||
|
||||
export function getAstWalkerFactory(): AstWalkerFactory {
|
||||
return globalAstWalkerFactory;
|
||||
}
|
||||
}
|
||||
@ -16,56 +16,6 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export function stripStartAndEndQuotes(str: string) {
|
||||
var firstCharCode = str && str.charCodeAt(0);
|
||||
if (str && str.length >= 2 && firstCharCode === str.charCodeAt(str.length - 1) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
|
||||
return str.substring(1, str.length - 1);
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
export function isSingleQuoted(str: string) {
|
||||
return str && str.length >= 2 && str.charCodeAt(0) === str.charCodeAt(str.length - 1) && str.charCodeAt(0) === CharacterCodes.singleQuote;
|
||||
}
|
||||
|
||||
export function isDoubleQuoted(str: string) {
|
||||
return str && str.length >= 2 && str.charCodeAt(0) === str.charCodeAt(str.length - 1) && str.charCodeAt(0) === CharacterCodes.doubleQuote;
|
||||
}
|
||||
|
||||
export function isQuoted(str: string) {
|
||||
return isDoubleQuoted(str) || isSingleQuoted(str);
|
||||
}
|
||||
|
||||
export function quoteStr(str: string) {
|
||||
return "\"" + str + "\"";
|
||||
}
|
||||
|
||||
var switchToForwardSlashesRegEx = /\\/g;
|
||||
export function switchToForwardSlashes(path: string) {
|
||||
return path.replace(switchToForwardSlashesRegEx, "/");
|
||||
}
|
||||
|
||||
export function trimModName(modName: string) {
|
||||
// in case's it's a declare file...
|
||||
if (modName.length > 5 && modName.substring(modName.length - 5, modName.length) === ".d.ts") {
|
||||
return modName.substring(0, modName.length - 5);
|
||||
}
|
||||
if (modName.length > 3 && modName.substring(modName.length - 3, modName.length) === ".ts") {
|
||||
return modName.substring(0, modName.length - 3);
|
||||
}
|
||||
// in case's it's a .js file
|
||||
if (modName.length > 3 && modName.substring(modName.length - 3, modName.length) === ".js") {
|
||||
return modName.substring(0, modName.length - 3);
|
||||
}
|
||||
|
||||
return modName;
|
||||
}
|
||||
|
||||
export function getDeclareFilePath(fname: string) {
|
||||
return isTSFile(fname) ? changePathToDTS(fname) : changePathToDTS(fname);
|
||||
}
|
||||
|
||||
function isFileOfExtension(fname: string, ext: string) {
|
||||
var invariantFname = fname.toLocaleUpperCase();
|
||||
var invariantExt = ext.toLocaleUpperCase();
|
||||
@ -73,121 +23,7 @@ module TypeScript {
|
||||
return invariantFname.length > extLength && invariantFname.substring(invariantFname.length - extLength, invariantFname.length) === invariantExt;
|
||||
}
|
||||
|
||||
export function isTSFile(fname: string) {
|
||||
return isFileOfExtension(fname, ".ts");
|
||||
}
|
||||
|
||||
export function isDTSFile(fname: string) {
|
||||
return isFileOfExtension(fname, ".d.ts");
|
||||
}
|
||||
|
||||
export function getPrettyName(modPath: string, quote=true, treatAsFileName=false): any {
|
||||
var modName = treatAsFileName ? switchToForwardSlashes(modPath) : trimModName(stripStartAndEndQuotes(modPath));
|
||||
var components = this.getPathComponents(modName);
|
||||
return components.length ? (quote ? quoteStr(components[components.length - 1]) : components[components.length - 1]) : modPath;
|
||||
}
|
||||
|
||||
export function getPathComponents(path: string) {
|
||||
return path.split("/");
|
||||
}
|
||||
|
||||
export function getRelativePathToFixedPath(fixedModFilePath: string, absoluteModPath: string, isAbsoultePathURL = true) {
|
||||
absoluteModPath = switchToForwardSlashes(absoluteModPath);
|
||||
|
||||
var modComponents = this.getPathComponents(absoluteModPath);
|
||||
var fixedModComponents = this.getPathComponents(fixedModFilePath);
|
||||
|
||||
// Find the component that differs
|
||||
var joinStartIndex = 0;
|
||||
for (; joinStartIndex < modComponents.length && joinStartIndex < fixedModComponents.length ; joinStartIndex++) {
|
||||
if (fixedModComponents[joinStartIndex] !== modComponents[joinStartIndex]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the relative path
|
||||
if (joinStartIndex !== 0) {
|
||||
var relativePath = "";
|
||||
var relativePathComponents = modComponents.slice(joinStartIndex, modComponents.length);
|
||||
for (; joinStartIndex < fixedModComponents.length; joinStartIndex++) {
|
||||
if (fixedModComponents[joinStartIndex] !== "") {
|
||||
relativePath = relativePath + "../";
|
||||
}
|
||||
}
|
||||
|
||||
return relativePath + relativePathComponents.join("/");
|
||||
}
|
||||
|
||||
if (isAbsoultePathURL && absoluteModPath.indexOf("://") === -1) {
|
||||
absoluteModPath = "file:///" + absoluteModPath;
|
||||
}
|
||||
|
||||
return absoluteModPath;
|
||||
}
|
||||
|
||||
export function changePathToDTS(modPath: string) {
|
||||
return trimModName(stripStartAndEndQuotes(modPath)) + ".d.ts";
|
||||
}
|
||||
|
||||
export function isRelative(path: string) {
|
||||
return path.length > 0 && path.charAt(0) === ".";
|
||||
}
|
||||
export function isRooted(path: string) {
|
||||
return path.length > 0 && (path.charAt(0) === "\\" || path.charAt(0) === "/" || (path.indexOf(":\\") !== -1) || (path.indexOf(":/") !== -1));
|
||||
}
|
||||
|
||||
export function getRootFilePath(outFname: string) {
|
||||
if (outFname === "") {
|
||||
return outFname;
|
||||
}
|
||||
else {
|
||||
var isPath = outFname.indexOf("/") !== -1;
|
||||
return isPath ? filePath(outFname) : "";
|
||||
}
|
||||
}
|
||||
|
||||
export function filePathComponents(fullPath: string) {
|
||||
fullPath = switchToForwardSlashes(fullPath);
|
||||
var components = getPathComponents(fullPath);
|
||||
return components.slice(0, components.length - 1);
|
||||
}
|
||||
|
||||
export function filePath(fullPath: string) {
|
||||
var path = filePathComponents(fullPath);
|
||||
return path.join("/") + "/";
|
||||
}
|
||||
|
||||
export function convertToDirectoryPath(dirPath: string) {
|
||||
if (dirPath && dirPath.charAt(dirPath.length - 1) !== "/") {
|
||||
dirPath += "/";
|
||||
}
|
||||
|
||||
return dirPath;
|
||||
}
|
||||
|
||||
var normalizePathRegEx = /^\\\\[^\\]/;
|
||||
export function normalizePath(path: string): string {
|
||||
// If it's a UNC style path (i.e. \\server\share), convert to a URI style (i.e. file://server/share)
|
||||
if (normalizePathRegEx.test(path)) {
|
||||
path = "file:" + path;
|
||||
}
|
||||
var parts = this.getPathComponents(switchToForwardSlashes(path));
|
||||
var normalizedParts: string[] = [];
|
||||
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var part = parts[i];
|
||||
if (part === ".") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (normalizedParts.length > 0 && ArrayUtilities.last(normalizedParts) !== ".." && part === "..") {
|
||||
normalizedParts.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
normalizedParts.push(part);
|
||||
}
|
||||
|
||||
return normalizedParts.join("/");
|
||||
}
|
||||
}
|
||||
@ -1,208 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
module TypeScript {
|
||||
export interface ILineAndCharacter {
|
||||
line: number;
|
||||
character: number;
|
||||
}
|
||||
|
||||
// Note: This is being using by the host (VS) and is marshaled back and forth. When changing this make sure the changes
|
||||
// are reflected in the managed side as well.
|
||||
export interface IFileReference extends ILineAndCharacter {
|
||||
path: string;
|
||||
isResident: boolean;
|
||||
position: number;
|
||||
length: number;
|
||||
}
|
||||
|
||||
///
|
||||
/// Preprocessing
|
||||
///
|
||||
export interface IPreProcessedFileInfo {
|
||||
referencedFiles: IFileReference[];
|
||||
importedFiles: IFileReference[];
|
||||
diagnostics: Diagnostic[];
|
||||
isLibFile: boolean;
|
||||
}
|
||||
|
||||
interface ITripleSlashDirectiveProperties {
|
||||
noDefaultLib: boolean;
|
||||
diagnostics: Diagnostic[];
|
||||
referencedFiles: IFileReference[];
|
||||
}
|
||||
|
||||
function isNoDefaultLibMatch(comment: string): RegExpExecArray {
|
||||
var isNoDefaultLibRegex = /^(\/\/\/\s*<reference\s+no-default-lib=)('|")(.+?)\2\s*\/>/gim;
|
||||
return isNoDefaultLibRegex.exec(comment);
|
||||
}
|
||||
|
||||
export var tripleSlashReferenceRegExp = /^(\/\/\/\s*<reference\s+path=)('|")(.+?)\2\s*(static=('|")(.+?)\5\s*)*\/>/;
|
||||
|
||||
function getFileReferenceFromReferencePath(fileName: string, text: ISimpleText, position: number, comment: string, diagnostics: Diagnostic[]): IFileReference {
|
||||
// First, just see if they've written: /// <reference\s+
|
||||
// If so, then we'll consider this a reference directive and we'll report errors if it's
|
||||
// malformed. Otherwise, we'll completely ignore this.
|
||||
var lineMap = text.lineMap();
|
||||
|
||||
var simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
|
||||
if (simpleReferenceRegEx.exec(comment)) {
|
||||
var isNoDefaultLib = isNoDefaultLibMatch(comment);
|
||||
|
||||
if (!isNoDefaultLib) {
|
||||
var fullReferenceRegEx = tripleSlashReferenceRegExp;
|
||||
var fullReference = fullReferenceRegEx.exec(comment);
|
||||
|
||||
if (!fullReference) {
|
||||
// It matched the start of a reference directive, but wasn't well formed. Report
|
||||
// an appropriate error to the user.
|
||||
diagnostics.push(new Diagnostic(fileName, lineMap, position, comment.length, DiagnosticCode.Invalid_reference_directive_syntax));
|
||||
}
|
||||
else {
|
||||
var path: string = normalizePath(fullReference[3]);
|
||||
var adjustedPath = normalizePath(path);
|
||||
|
||||
var isResident = fullReference.length >= 7 && fullReference[6] === "true";
|
||||
return {
|
||||
line: 0,
|
||||
character: 0,
|
||||
position: 0,
|
||||
length: 0,
|
||||
path: switchToForwardSlashes(adjustedPath),
|
||||
isResident: isResident
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var reportDiagnostic = () => { };
|
||||
|
||||
function processImports(text: ISimpleText, scanner: Scanner.IScanner, token: ISyntaxToken, importedFiles: IFileReference[]): void {
|
||||
var lineChar = { line: -1, character: -1 };
|
||||
|
||||
var lineMap = text.lineMap();
|
||||
var start = new Date().getTime();
|
||||
// Look for:
|
||||
// import foo = module("foo")
|
||||
while (token.kind() !== SyntaxKind.EndOfFileToken) {
|
||||
if (token.kind() === SyntaxKind.ImportKeyword) {
|
||||
var importToken = token;
|
||||
token = scanner.scan(/*allowRegularExpression:*/ false);
|
||||
|
||||
if (SyntaxFacts.isIdentifierNameOrAnyKeyword(token)) {
|
||||
token = scanner.scan(/*allowRegularExpression:*/ false);
|
||||
|
||||
if (token.kind() === SyntaxKind.EqualsToken) {
|
||||
token = scanner.scan(/*allowRegularExpression:*/ false);
|
||||
|
||||
if (token.kind() === SyntaxKind.ModuleKeyword || token.kind() === SyntaxKind.RequireKeyword) {
|
||||
token = scanner.scan(/*allowRegularExpression:*/ false);
|
||||
|
||||
if (token.kind() === SyntaxKind.OpenParenToken) {
|
||||
token = scanner.scan(/*allowRegularExpression:*/ false);
|
||||
|
||||
lineMap.fillLineAndCharacterFromPosition(TypeScript.start(importToken, text), lineChar);
|
||||
|
||||
if (token.kind() === SyntaxKind.StringLiteral) {
|
||||
var ref = {
|
||||
line: lineChar.line,
|
||||
character: lineChar.character,
|
||||
position: TypeScript.start(token, text),
|
||||
length: width(token),
|
||||
path: stripStartAndEndQuotes(switchToForwardSlashes(token.text())),
|
||||
isResident: false
|
||||
};
|
||||
importedFiles.push(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
token = scanner.scan(/*allowRegularExpression:*/ false);
|
||||
}
|
||||
|
||||
var totalTime = new Date().getTime() - start;
|
||||
//TypeScript.fileResolutionScanImportsTime += totalTime;
|
||||
}
|
||||
|
||||
function processTripleSlashDirectives(fileName: string, text: ISimpleText, firstToken: ISyntaxToken): ITripleSlashDirectiveProperties {
|
||||
var leadingTrivia = firstToken.leadingTrivia(text);
|
||||
|
||||
var position = 0;
|
||||
var lineChar = { line: -1, character: -1 };
|
||||
var noDefaultLib = false;
|
||||
var diagnostics: Diagnostic[] = [];
|
||||
var referencedFiles: IFileReference[] = [];
|
||||
var lineMap = text.lineMap();
|
||||
|
||||
for (var i = 0, n = leadingTrivia.count(); i < n; i++) {
|
||||
var trivia = leadingTrivia.syntaxTriviaAt(i);
|
||||
|
||||
if (trivia.kind() === SyntaxKind.SingleLineCommentTrivia) {
|
||||
var triviaText = trivia.fullText();
|
||||
var referencedCode = getFileReferenceFromReferencePath(fileName, text, position, triviaText, diagnostics);
|
||||
|
||||
if (referencedCode) {
|
||||
lineMap.fillLineAndCharacterFromPosition(position, lineChar);
|
||||
referencedCode.position = position;
|
||||
referencedCode.length = trivia.fullWidth();
|
||||
referencedCode.line = lineChar.line;
|
||||
referencedCode.character = lineChar.character;
|
||||
|
||||
referencedFiles.push(referencedCode);
|
||||
}
|
||||
|
||||
// is it a lib file?
|
||||
var isNoDefaultLib = isNoDefaultLibMatch(triviaText);
|
||||
if (isNoDefaultLib) {
|
||||
noDefaultLib = isNoDefaultLib[3] === "true";
|
||||
}
|
||||
}
|
||||
|
||||
position += trivia.fullWidth();
|
||||
}
|
||||
|
||||
return { noDefaultLib: noDefaultLib, diagnostics: diagnostics, referencedFiles: referencedFiles };
|
||||
}
|
||||
|
||||
export function preProcessFile(fileName: string, sourceText: IScriptSnapshot, readImportFiles = true): IPreProcessedFileInfo {
|
||||
var text = SimpleText.fromScriptSnapshot(sourceText);
|
||||
var scanner = Scanner.createScanner(ts.ScriptTarget.Latest, text, reportDiagnostic);
|
||||
|
||||
var firstToken = scanner.scan(/*allowRegularExpression:*/ false);
|
||||
|
||||
// only search out dynamic mods
|
||||
// if you find a dynamic mod, ignore every other mod inside, until you balance rcurlies
|
||||
// var position
|
||||
|
||||
var importedFiles: IFileReference[] = [];
|
||||
if (readImportFiles) {
|
||||
processImports(text, scanner, firstToken, importedFiles);
|
||||
}
|
||||
|
||||
var properties = processTripleSlashDirectives(fileName, text, firstToken);
|
||||
|
||||
return { referencedFiles: properties.referencedFiles, importedFiles: importedFiles, isLibFile: properties.noDefaultLib, diagnostics: properties.diagnostics };
|
||||
}
|
||||
|
||||
export function getReferencedFiles(fileName: string, sourceText: IScriptSnapshot): IFileReference[] {
|
||||
return preProcessFile(fileName, sourceText, false).referencedFiles;
|
||||
}
|
||||
} // Tools
|
||||
@ -7,7 +7,7 @@ module TypeScript {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (array1 === null || array2 === null) {
|
||||
if (!array1 || !array2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public static firstOrDefault<T>(array: T[], func: (v: T, index: number) => boolean): T {
|
||||
@ -82,7 +82,7 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public static first<T>(array: T[], func?: (v: T, index: number) => boolean): T {
|
||||
|
||||
@ -14,13 +14,14 @@ module TypeScript {
|
||||
return this.currentAssertionLevel >= level;
|
||||
}
|
||||
|
||||
public static assert(expression: any, message: string = "", verboseDebugInfo: () => string = null): void {
|
||||
public static assert(expression: any, message?: string, verboseDebugInfo?: () => string): void {
|
||||
if (!expression) {
|
||||
var verboseDebugString = "";
|
||||
if (verboseDebugInfo) {
|
||||
verboseDebugString = "\r\nVerbose Debug Information:" + verboseDebugInfo();
|
||||
}
|
||||
|
||||
message = message || "";
|
||||
throw new Error("Debug Failure. False expression: " + message + verboseDebugString);
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,11 +50,11 @@ module TypeScript {
|
||||
private _arguments: any[];
|
||||
private _additionalLocations: Location[];
|
||||
|
||||
constructor(fileName: string, lineMap: LineMap, start: number, length: number, diagnosticKey: string, _arguments: any[]= null, additionalLocations: Location[] = null) {
|
||||
constructor(fileName: string, lineMap: LineMap, start: number, length: number, diagnosticKey: string, _arguments?: any[], additionalLocations?: Location[]) {
|
||||
super(fileName, lineMap, start, length);
|
||||
this._diagnosticKey = diagnosticKey;
|
||||
this._arguments = (_arguments && _arguments.length > 0) ? _arguments : null;
|
||||
this._additionalLocations = (additionalLocations && additionalLocations.length > 0) ? additionalLocations : null;
|
||||
this._arguments = (_arguments && _arguments.length > 0) ? _arguments : undefined;
|
||||
this._additionalLocations = (additionalLocations && additionalLocations.length > 0) ? additionalLocations : undefined;
|
||||
}
|
||||
|
||||
public toJSON(key: any): any {
|
||||
|
||||
@ -1,9 +1,14 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export interface ILineAndCharacter {
|
||||
line: number;
|
||||
character: number;
|
||||
}
|
||||
|
||||
export class LineMap {
|
||||
public static empty = new LineMap(() => [0], 0);
|
||||
private _lineStarts: number[] = null;
|
||||
private _lineStarts: number[] = undefined;
|
||||
|
||||
constructor(private _computeLineStarts: () => number[], private length: number) {
|
||||
}
|
||||
@ -18,7 +23,7 @@ module TypeScript {
|
||||
}
|
||||
|
||||
public lineStarts(): number[] {
|
||||
if (this._lineStarts === null) {
|
||||
if (!this._lineStarts) {
|
||||
this._lineStarts = this._computeLineStarts();
|
||||
}
|
||||
|
||||
|
||||
953
src/services/formatting.ts
Normal file
953
src/services/formatting.ts
Normal file
@ -0,0 +1,953 @@
|
||||
///<reference path='services.ts' />
|
||||
///<reference path='formatting\indentation.ts' />
|
||||
///<reference path='formatting\formattingScanner.ts' />
|
||||
///<reference path='formatting\rulesProvider.ts' />
|
||||
|
||||
module ts.formatting {
|
||||
|
||||
export interface TextRangeWithKind extends TextRange {
|
||||
kind: SyntaxKind;
|
||||
}
|
||||
|
||||
export interface TokenInfo {
|
||||
leadingTrivia: TextRangeWithKind[];
|
||||
token: TextRangeWithKind;
|
||||
trailingTrivia: TextRangeWithKind[];
|
||||
}
|
||||
|
||||
const enum Constants {
|
||||
Unknown = -1
|
||||
}
|
||||
|
||||
/*
|
||||
* Indentation for the scope that can be dynamically recomputed.
|
||||
* i.e
|
||||
* while(true)
|
||||
* { var x;
|
||||
* }
|
||||
* Normally indentation is applied only to the first token in line so at glance 'var' should not be touched.
|
||||
* However if some format rule adds new line between '}' and 'var' 'var' will become
|
||||
* the first token in line so it should be indented
|
||||
*/
|
||||
interface DynamicIndentation {
|
||||
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind): number;
|
||||
getIndentationForComment(owningToken: SyntaxKind): number;
|
||||
/**
|
||||
* Indentation for open and close tokens of the node if it is block or another node that needs special indentation
|
||||
* ... {
|
||||
* .........<child>
|
||||
* ....}
|
||||
* ____ - indentation
|
||||
* ____ - delta
|
||||
**/
|
||||
getIndentation(): number;
|
||||
/**
|
||||
* Prefered relative indentation for child nodes.
|
||||
* Delta is used to carry the indentation info
|
||||
* foo(bar({
|
||||
* $
|
||||
* }))
|
||||
* Both 'foo', 'bar' introduce new indentation with delta = 4, but total indentation in $ is not 8.
|
||||
* foo: { indentation: 0, delta: 4 }
|
||||
* bar: { indentation: foo.indentation + foo.delta = 4, delta: 4} however 'foo' and 'bar' are on the same line
|
||||
* so bar inherits indentation from foo and bar.delta will be 4
|
||||
*
|
||||
*/
|
||||
getDelta(): number;
|
||||
/**
|
||||
* Formatter calls this function when rule adds or deletes new lines from the text
|
||||
* so indentation scope can adjust values of indentation and delta.
|
||||
*/
|
||||
recomputeIndentation(lineAddedByFormatting: boolean): void;
|
||||
}
|
||||
|
||||
interface Indentation {
|
||||
indentation: number;
|
||||
delta: number
|
||||
}
|
||||
|
||||
export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
var line = sourceFile.getLineAndCharacterFromPosition(position).line;
|
||||
Debug.assert(line >= 2);
|
||||
// get the span for the previous\current line
|
||||
var span = {
|
||||
// get start position for the previous line
|
||||
pos: getStartPositionOfLine(line - 1, sourceFile),
|
||||
// get end position for the current line (end value is exclusive so add 1 to the result)
|
||||
end: getEndLinePosition(line, sourceFile) + 1
|
||||
}
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter);
|
||||
}
|
||||
|
||||
export function formatOnSemicolon(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
return formatOutermostParent(position, SyntaxKind.SemicolonToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnSemicolon);
|
||||
}
|
||||
|
||||
export function formatOnClosingCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
return formatOutermostParent(position, SyntaxKind.CloseBraceToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnClosingCurlyBrace);
|
||||
}
|
||||
|
||||
export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
var span = {
|
||||
pos: 0,
|
||||
end: sourceFile.text.length
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatDocument);
|
||||
}
|
||||
|
||||
export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
// format from the beginning of the line
|
||||
var span = {
|
||||
pos: getStartLinePositionForPosition(start, sourceFile),
|
||||
end: end
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection);
|
||||
}
|
||||
|
||||
function formatOutermostParent(position: number, expectedLastToken: SyntaxKind, sourceFile: SourceFile, options: FormatCodeOptions, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] {
|
||||
var parent = findOutermostParent(position, expectedLastToken, sourceFile);
|
||||
if (!parent) {
|
||||
return [];
|
||||
}
|
||||
var span = {
|
||||
pos: getStartLinePositionForPosition(parent.getStart(sourceFile), sourceFile),
|
||||
end: parent.end
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, requestKind);
|
||||
}
|
||||
|
||||
function findOutermostParent(position: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node {
|
||||
var precedingToken = findPrecedingToken(position, sourceFile);
|
||||
if (!precedingToken || precedingToken.kind !== expectedTokenKind) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// walk up and search for the parent node that ends at the same position with precedingToken.
|
||||
// for cases like this
|
||||
//
|
||||
// var x = 1;
|
||||
// while (true) {
|
||||
// }
|
||||
// after typing close curly in while statement we want to reformat just the while statement.
|
||||
// However if we just walk upwards searching for the parent that has the same end value -
|
||||
// we'll end up with the whole source file. isListElement allows to stop on the list element level
|
||||
var current = precedingToken;
|
||||
while (current &&
|
||||
current.parent &&
|
||||
current.parent.end === precedingToken.end &&
|
||||
!isListElement(current.parent, current)) {
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
// Returns true if node is a element in some list in parent
|
||||
// i.e. parent is class declaration with the list of members and node is one of members.
|
||||
function isListElement(parent: Node, node: Node): boolean {
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return rangeContainsRange((<InterfaceDeclaration>parent).members, node);
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
var body = (<ModuleDeclaration>parent).body;
|
||||
return body && body.kind === SyntaxKind.Block && rangeContainsRange((<Block>body).statements, node);
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return rangeContainsRange((<Block>parent).statements, node)
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** find node that fully contains given text range */
|
||||
function findEnclosingNode(range: TextRange, sourceFile: SourceFile): Node {
|
||||
return find(sourceFile);
|
||||
|
||||
function find(n: Node): Node {
|
||||
var candidate = forEachChild(n, c => startEndContainsRange(c.getStart(sourceFile), c.end, range) && c);
|
||||
if (candidate) {
|
||||
var result = find(candidate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
/** formatting is not applied to ranges that contain parse errors.
|
||||
* This function will return a predicate that for a given text range will tell
|
||||
* if there are any parse errors that overlap with the range.
|
||||
*/
|
||||
function prepareRangeContainsErrorFunction(errors: Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean {
|
||||
if (!errors.length) {
|
||||
return rangeHasNoErrors;
|
||||
}
|
||||
|
||||
// pick only errors that fall in range
|
||||
var sorted = errors
|
||||
.filter(d => d.isParseError && rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length))
|
||||
.sort((e1, e2) => e1.start - e2.start);
|
||||
|
||||
if (!sorted.length) {
|
||||
return rangeHasNoErrors;
|
||||
}
|
||||
|
||||
var index = 0;
|
||||
|
||||
return r => {
|
||||
// in current implementation sequence of arguments [r1, r2...] is monotonically increasing.
|
||||
// 'index' tracks the index of the most recent error that was checked.
|
||||
while (true) {
|
||||
if (index >= sorted.length) {
|
||||
// all errors in the range were already checked -> no error in specified range
|
||||
return false;
|
||||
}
|
||||
|
||||
var error = sorted[index];
|
||||
if (r.end <= error.start) {
|
||||
// specified range ends before the error refered by 'index' - no error in range
|
||||
return false;
|
||||
}
|
||||
|
||||
if (startEndOverlapsWithStartEnd(r.pos, r.end, error.start, error.start + error.length)) {
|
||||
// specified range overlaps with error range
|
||||
return true;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
};
|
||||
|
||||
function rangeHasNoErrors(r: TextRange): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start of the original range might fall inside the comment - scanner will not yield appropriate results
|
||||
* This function will look for token that is located before the start of target range
|
||||
* and return its end as start position for the scanner.
|
||||
*/
|
||||
function getScanStartPosition(enclosingNode: Node, originalRange: TextRange, sourceFile: SourceFile): number {
|
||||
var start = enclosingNode.getStart(sourceFile);
|
||||
if (start === originalRange.pos && enclosingNode.end === originalRange.end) {
|
||||
return start;
|
||||
}
|
||||
|
||||
var precedingToken = findPrecedingToken(originalRange.pos, sourceFile);
|
||||
// no preceding token found - start from the beginning of enclosing node
|
||||
return precedingToken ? precedingToken.end : enclosingNode.pos;
|
||||
}
|
||||
|
||||
function formatSpan(originalRange: TextRange,
|
||||
sourceFile: SourceFile,
|
||||
options: FormatCodeOptions,
|
||||
rulesProvider: RulesProvider,
|
||||
requestKind: FormattingRequestKind): TextChange[] {
|
||||
|
||||
var rangeContainsError = prepareRangeContainsErrorFunction(sourceFile.syntacticErrors, originalRange);
|
||||
|
||||
// formatting context is used by rules provider
|
||||
var formattingContext = new FormattingContext(sourceFile, requestKind);
|
||||
|
||||
// find the smallest node that fully wraps the range and compute the initial indentation for the node
|
||||
var enclosingNode = findEnclosingNode(originalRange, sourceFile);
|
||||
|
||||
var formattingScanner = getFormattingScanner(sourceFile, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end);
|
||||
|
||||
var initialIndentation = SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options);
|
||||
|
||||
var previousRangeHasError: boolean;
|
||||
var previousRange: TextRangeWithKind;
|
||||
var previousParent: Node;
|
||||
var previousRangeStartLine: number;
|
||||
|
||||
var edits: TextChange[] = [];
|
||||
|
||||
formattingScanner.advance();
|
||||
|
||||
if (formattingScanner.isOnToken()) {
|
||||
var startLine = sourceFile.getLineAndCharacterFromPosition(enclosingNode.getStart(sourceFile)).line;
|
||||
var delta = SmartIndenter.shouldIndentChildNode(enclosingNode.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
|
||||
processNode(enclosingNode, enclosingNode, startLine, initialIndentation, delta);
|
||||
}
|
||||
|
||||
formattingScanner.close();
|
||||
|
||||
return edits;
|
||||
|
||||
// local functions
|
||||
|
||||
/** Tries to compute the indentation for a list element.
|
||||
* If list element is not in range then
|
||||
* function will pick its actual indentation
|
||||
* so it can be pushed downstream as inherited indentation.
|
||||
* If list element is in the range - its indentation will be equal
|
||||
* to inherited indentation from its predecessors.
|
||||
*/
|
||||
function tryComputeIndentationForListItem(startPos: number,
|
||||
endPos: number,
|
||||
parentStartLine: number,
|
||||
range: TextRange,
|
||||
inheritedIndentation: number): number {
|
||||
|
||||
if (rangeOverlapsWithStartEnd(range, startPos, endPos)) {
|
||||
if (inheritedIndentation !== Constants.Unknown) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var startLine = sourceFile.getLineAndCharacterFromPosition(startPos).line;
|
||||
var startLinePosition = getStartLinePositionForPosition(startPos, sourceFile);
|
||||
var column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options);
|
||||
if (startLine !== parentStartLine || startPos === column) {
|
||||
return column
|
||||
}
|
||||
}
|
||||
|
||||
return Constants.Unknown;
|
||||
}
|
||||
|
||||
function computeIndentation(
|
||||
node: TextRangeWithKind,
|
||||
startLine: number,
|
||||
inheritedIndentation: number,
|
||||
parent: Node,
|
||||
parentDynamicIndentation: DynamicIndentation,
|
||||
effectiveParentStartLine: number): Indentation {
|
||||
|
||||
var indentation = inheritedIndentation;
|
||||
if (indentation === Constants.Unknown) {
|
||||
if (isSomeBlock(node.kind)) {
|
||||
// blocks should be indented in
|
||||
// - other blocks
|
||||
// - source file
|
||||
// - switch\default clauses
|
||||
if (isSomeBlock(parent.kind) ||
|
||||
parent.kind === SyntaxKind.SourceFile ||
|
||||
parent.kind === SyntaxKind.CaseClause ||
|
||||
parent.kind === SyntaxKind.DefaultClause) {
|
||||
|
||||
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
|
||||
}
|
||||
else {
|
||||
indentation = parentDynamicIndentation.getIndentation();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile)) {
|
||||
indentation = parentDynamicIndentation.getIndentation();
|
||||
}
|
||||
else {
|
||||
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var delta = SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
|
||||
|
||||
if (effectiveParentStartLine === startLine) {
|
||||
// if node is located on the same line with the parent
|
||||
// - inherit indentation from the parent
|
||||
// - push children if either parent of node itself has non-zero delta
|
||||
indentation = parentDynamicIndentation.getIndentation();
|
||||
delta = Math.min(options.IndentSize, parentDynamicIndentation.getDelta() + delta);
|
||||
}
|
||||
return {
|
||||
indentation: indentation,
|
||||
delta: delta
|
||||
}
|
||||
}
|
||||
|
||||
function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, delta: number): DynamicIndentation {
|
||||
return {
|
||||
getIndentationForComment: kind => {
|
||||
switch (kind) {
|
||||
// preceding comment to the token that closes the indentation scope inherits the indentation from the scope
|
||||
// .. {
|
||||
// // comment
|
||||
// }
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
case SyntaxKind.CloseBracketToken:
|
||||
return indentation + delta;
|
||||
}
|
||||
return indentation;
|
||||
},
|
||||
getIndentationForToken: (line, kind) => {
|
||||
switch (kind) {
|
||||
// open and close brace, 'else' and 'while' (in do statement) tokens has indentation of the parent
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
case SyntaxKind.OpenBracketToken:
|
||||
case SyntaxKind.CloseBracketToken:
|
||||
case SyntaxKind.ElseKeyword:
|
||||
case SyntaxKind.WhileKeyword:
|
||||
return indentation;
|
||||
default:
|
||||
// if token line equals to the line of containing node (this is a first token in the node) - use node indentation
|
||||
return nodeStartLine !== line ? indentation + delta : indentation;
|
||||
}
|
||||
},
|
||||
getIndentation: () => indentation,
|
||||
getDelta: () => delta,
|
||||
recomputeIndentation: lineAdded => {
|
||||
if (node.parent && SmartIndenter.shouldIndentChildNode(node.parent.kind, node.kind)) {
|
||||
if (lineAdded) {
|
||||
indentation += options.IndentSize;
|
||||
}
|
||||
else {
|
||||
indentation -= options.IndentSize;
|
||||
}
|
||||
|
||||
if (SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown)) {
|
||||
delta = options.IndentSize;
|
||||
}
|
||||
else {
|
||||
delta = 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function processNode(node: Node, contextNode: Node, nodeStartLine: number, indentation: number, delta: number) {
|
||||
if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nodeDynamicIndentation = getDynamicIndentation(node, nodeStartLine, indentation, delta);
|
||||
|
||||
// a useful observations when tracking context node
|
||||
// /
|
||||
// [a]
|
||||
// / | \
|
||||
// [b] [c] [d]
|
||||
// node 'a' is a context node for nodes 'b', 'c', 'd'
|
||||
// except for the leftmost leaf token in [b] - in this case context node ('e') is located somewhere above 'a'
|
||||
// this rule can be applied recursively to child nodes of 'a'.
|
||||
//
|
||||
// context node is set to parent node value after processing every child node
|
||||
// context node is set to parent of the token after processing every token
|
||||
|
||||
var childContextNode = contextNode;
|
||||
|
||||
// if there are any tokens that logically belong to node and interleave child nodes
|
||||
// such tokens will be consumed in processChildNode for for the child that follows them
|
||||
forEachChild(
|
||||
node,
|
||||
child => {
|
||||
processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, /*isListElement*/ false)
|
||||
},
|
||||
(nodes: NodeArray<Node>) => {
|
||||
processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation);
|
||||
});
|
||||
|
||||
// proceed any tokens in the node that are located after child nodes
|
||||
while (formattingScanner.isOnToken()) {
|
||||
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
if (tokenInfo.token.end > node.end) {
|
||||
break;
|
||||
}
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation);
|
||||
}
|
||||
|
||||
function processChildNode(
|
||||
child: Node,
|
||||
inheritedIndentation: number,
|
||||
parent: Node,
|
||||
parentDynamicIndentation: DynamicIndentation,
|
||||
parentStartLine: number,
|
||||
isListItem: boolean): number {
|
||||
|
||||
var childStartPos = child.getStart(sourceFile);
|
||||
|
||||
var childStart = sourceFile.getLineAndCharacterFromPosition(childStartPos);
|
||||
|
||||
// if child is a list item - try to get its indentation
|
||||
var childIndentationAmount = Constants.Unknown;
|
||||
if (isListItem) {
|
||||
childIndentationAmount = tryComputeIndentationForListItem(childStartPos, child.end, parentStartLine, originalRange, inheritedIndentation);
|
||||
if (childIndentationAmount !== Constants.Unknown) {
|
||||
inheritedIndentation = childIndentationAmount;
|
||||
}
|
||||
}
|
||||
|
||||
// child node is outside the target range - do not dive inside
|
||||
if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
if (child.kind === SyntaxKind.Missing) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
while (formattingScanner.isOnToken()) {
|
||||
// proceed any parent tokens that are located prior to child.getStart()
|
||||
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
if (tokenInfo.token.end > childStartPos) {
|
||||
// stop when formatting scanner advances past the beginning of the child
|
||||
break;
|
||||
}
|
||||
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
|
||||
}
|
||||
|
||||
if (!formattingScanner.isOnToken()) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
if (isToken(child)) {
|
||||
// if child node is a token, it does not impact indentation, proceed it using parent indentation scope rules
|
||||
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
Debug.assert(tokenInfo.token.end === child.end);
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
var childIndentation = computeIndentation(child, childStart.line, childIndentationAmount, node, parentDynamicIndentation, parentStartLine);
|
||||
|
||||
processNode(child, childContextNode, childStart.line, childIndentation.indentation, childIndentation.delta);
|
||||
|
||||
childContextNode = node;
|
||||
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
function processChildNodes(nodes: NodeArray<Node>,
|
||||
parent: Node,
|
||||
parentStartLine: number,
|
||||
parentDynamicIndentation: DynamicIndentation): void {
|
||||
|
||||
var listStartToken = getOpenTokenForList(parent, nodes);
|
||||
var listEndToken = getCloseTokenForOpenToken(listStartToken);
|
||||
|
||||
var listDynamicIndentation = parentDynamicIndentation;
|
||||
var startLine = parentStartLine;
|
||||
|
||||
if (listStartToken !== SyntaxKind.Unknown) {
|
||||
// introduce a new indentation scope for lists (including list start and end tokens)
|
||||
while (formattingScanner.isOnToken()) {
|
||||
var tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||
if (tokenInfo.token.end > nodes.pos) {
|
||||
// stop when formatting scanner moves past the beginning of node list
|
||||
break;
|
||||
}
|
||||
else if (tokenInfo.token.kind === listStartToken) {
|
||||
// consume list start token
|
||||
startLine = sourceFile.getLineAndCharacterFromPosition(tokenInfo.token.pos).line;
|
||||
var indentation =
|
||||
computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, startLine);
|
||||
|
||||
listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta);
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
|
||||
}
|
||||
else {
|
||||
// consume any tokens that precede the list as child elements of 'node' using its indentation scope
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var inheritedIndentation = Constants.Unknown;
|
||||
for (var i = 0, len = nodes.length; i < len; ++i) {
|
||||
inheritedIndentation = processChildNode(nodes[i], inheritedIndentation, node, listDynamicIndentation, startLine, /*isListElement*/ true)
|
||||
}
|
||||
|
||||
if (listEndToken !== SyntaxKind.Unknown) {
|
||||
if (formattingScanner.isOnToken()) {
|
||||
var tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||
if (tokenInfo.token.kind === listEndToken) {
|
||||
// consume list end token
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation): void {
|
||||
Debug.assert(rangeContainsRange(parent, currentTokenInfo.token));
|
||||
|
||||
var lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
|
||||
var indentToken = false;
|
||||
|
||||
if (currentTokenInfo.leadingTrivia) {
|
||||
processTrivia(currentTokenInfo.leadingTrivia, parent, childContextNode, dynamicIndentation);
|
||||
}
|
||||
|
||||
var lineAdded: boolean;
|
||||
var isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token);
|
||||
|
||||
var tokenStart = sourceFile.getLineAndCharacterFromPosition(currentTokenInfo.token.pos);
|
||||
if (isTokenInRange) {
|
||||
// save prevStartLine since processRange will overwrite this value with current ones
|
||||
var prevStartLine = previousRangeStartLine;
|
||||
lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation);
|
||||
if (lineAdded !== undefined) {
|
||||
indentToken = lineAdded;
|
||||
}
|
||||
else {
|
||||
indentToken = lastTriviaWasNewLine && tokenStart.line !== prevStartLine;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTokenInfo.trailingTrivia) {
|
||||
processTrivia(currentTokenInfo.trailingTrivia, parent, childContextNode, dynamicIndentation);
|
||||
}
|
||||
|
||||
if (indentToken) {
|
||||
var indentNextTokenOrTrivia = true;
|
||||
if (currentTokenInfo.leadingTrivia) {
|
||||
for (var i = 0, len = currentTokenInfo.leadingTrivia.length; i < len; ++i) {
|
||||
var triviaItem = currentTokenInfo.leadingTrivia[i];
|
||||
if (!rangeContainsRange(originalRange, triviaItem)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var triviaStartLine = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos).line;
|
||||
switch (triviaItem.kind) {
|
||||
case SyntaxKind.MultiLineCommentTrivia:
|
||||
var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind);
|
||||
indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia);
|
||||
indentNextTokenOrTrivia = false;
|
||||
break;
|
||||
case SyntaxKind.SingleLineCommentTrivia:
|
||||
if (indentNextTokenOrTrivia) {
|
||||
var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind);
|
||||
insertIndentation(triviaItem.pos, commentIndentation, /*lineAdded*/ false);
|
||||
indentNextTokenOrTrivia = false;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
indentNextTokenOrTrivia = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// indent token only if is it is in target range and does not overlap with any error ranges
|
||||
if (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) {
|
||||
var tokenIndentation = dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind);
|
||||
insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAdded);
|
||||
}
|
||||
}
|
||||
|
||||
formattingScanner.advance();
|
||||
|
||||
childContextNode = parent;
|
||||
}
|
||||
}
|
||||
|
||||
function processTrivia(trivia: TextRangeWithKind[], parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): void {
|
||||
for (var i = 0, len = trivia.length; i < len; ++i) {
|
||||
var triviaItem = trivia[i];
|
||||
if (isComment(triviaItem.kind) && rangeContainsRange(originalRange, triviaItem)) {
|
||||
var triviaItemStart = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos);
|
||||
processRange(triviaItem, triviaItemStart, parent, contextNode, dynamicIndentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processRange(range: TextRangeWithKind,
|
||||
rangeStart: LineAndCharacter,
|
||||
parent: Node,
|
||||
contextNode: Node,
|
||||
dynamicIndentation: DynamicIndentation): boolean {
|
||||
|
||||
var rangeHasError = rangeContainsError(range);
|
||||
var lineAdded: boolean;
|
||||
if (!rangeHasError && !previousRangeHasError) {
|
||||
if (!previousRange) {
|
||||
// trim whitespaces starting from the beginning of the span up to the current line
|
||||
var originalStart = sourceFile.getLineAndCharacterFromPosition(originalRange.pos);
|
||||
trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line);
|
||||
}
|
||||
else {
|
||||
lineAdded =
|
||||
processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation)
|
||||
}
|
||||
}
|
||||
|
||||
previousRange = range;
|
||||
previousParent = parent;
|
||||
previousRangeStartLine = rangeStart.line;
|
||||
previousRangeHasError = rangeHasError;
|
||||
|
||||
return lineAdded;
|
||||
}
|
||||
|
||||
function processPair(currentItem: TextRangeWithKind,
|
||||
currentStartLine: number,
|
||||
currentParent: Node,
|
||||
previousItem: TextRangeWithKind,
|
||||
previousStartLine: number,
|
||||
previousParent: Node,
|
||||
contextNode: Node,
|
||||
dynamicIndentation: DynamicIndentation): boolean {
|
||||
|
||||
formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode);
|
||||
|
||||
var rule = rulesProvider.getRulesMap().GetRule(formattingContext);
|
||||
|
||||
var trimTrailingWhitespaces: boolean;
|
||||
var lineAdded: boolean;
|
||||
if (rule) {
|
||||
applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine);
|
||||
|
||||
if (rule.Operation.Action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
|
||||
// Handle the case where the next line is moved to be the end of this line.
|
||||
// In this case we don't indent the next line in the next pass.
|
||||
if (currentParent.getStart(sourceFile) === currentItem.pos) {
|
||||
lineAdded = false;
|
||||
}
|
||||
}
|
||||
else if (rule.Operation.Action & RuleAction.NewLine && currentStartLine === previousStartLine) {
|
||||
// Handle the case where token2 is moved to the new line.
|
||||
// In this case we indent token2 in the next pass but we set
|
||||
// sameLineIndent flag to notify the indenter that the indentation is within the line.
|
||||
if (currentParent.getStart(sourceFile) === currentItem.pos) {
|
||||
lineAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (lineAdded !== undefined) {
|
||||
dynamicIndentation.recomputeIndentation(lineAdded);
|
||||
}
|
||||
|
||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||
trimTrailingWhitespaces =
|
||||
(rule.Operation.Action & (RuleAction.NewLine | RuleAction.Space)) &&
|
||||
rule.Flag !== RuleFlags.CanDeleteNewLines;
|
||||
}
|
||||
else {
|
||||
trimTrailingWhitespaces = true;
|
||||
}
|
||||
|
||||
if (currentStartLine !== previousStartLine && trimTrailingWhitespaces) {
|
||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||
trimTrailingWhitespacesForLines(previousStartLine, currentStartLine, previousItem);
|
||||
}
|
||||
|
||||
return lineAdded;
|
||||
}
|
||||
|
||||
function insertIndentation(pos: number, indentation: number, lineAdded: boolean): void {
|
||||
var indentationString = getIndentationString(indentation, options);
|
||||
if (lineAdded) {
|
||||
// new line is added before the token by the formatting rules
|
||||
// insert indentation string at the very beginning of the token
|
||||
recordReplace(pos, 0, indentationString);
|
||||
}
|
||||
else {
|
||||
var tokenStart = sourceFile.getLineAndCharacterFromPosition(pos);
|
||||
if (indentation !== tokenStart.character - 1) {
|
||||
var startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile);
|
||||
recordReplace(startLinePosition, tokenStart.character - 1, indentationString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean) {
|
||||
// split comment in lines
|
||||
var startLine = sourceFile.getLineAndCharacterFromPosition(commentRange.pos).line;
|
||||
var endLine = sourceFile.getLineAndCharacterFromPosition(commentRange.end).line;
|
||||
|
||||
if (startLine === endLine) {
|
||||
if (!firstLineIsIndented) {
|
||||
// treat as single line comment
|
||||
insertIndentation(commentRange.pos, indentation, /*lineAdded*/ false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
var parts: TextRange[] = [];
|
||||
var startPos = commentRange.pos;
|
||||
for (var line = startLine; line < endLine; ++line) {
|
||||
var endOfLine = getEndLinePosition(line, sourceFile);
|
||||
parts.push({ pos: startPos, end: endOfLine });
|
||||
startPos = getStartPositionOfLine(line + 1, sourceFile);
|
||||
}
|
||||
|
||||
parts.push({ pos: startPos, end: commentRange.end });
|
||||
}
|
||||
|
||||
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||
|
||||
var nonWhitespaceColumnInFirstPart =
|
||||
SmartIndenter.findFirstNonWhitespaceColumn(startLinePos, parts[0].pos, sourceFile, options);
|
||||
|
||||
if (indentation === nonWhitespaceColumnInFirstPart) {
|
||||
return;
|
||||
}
|
||||
|
||||
var startIndex = 0;
|
||||
if (firstLineIsIndented) {
|
||||
startIndex = 1;
|
||||
startLine++;
|
||||
}
|
||||
|
||||
// shift all parts on the delta size
|
||||
var delta = indentation - nonWhitespaceColumnInFirstPart;
|
||||
for (var i = startIndex, len = parts.length; i < len; ++i, ++startLine) {
|
||||
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||
var nonWhitespaceColumn =
|
||||
i === 0
|
||||
? nonWhitespaceColumnInFirstPart
|
||||
: SmartIndenter.findFirstNonWhitespaceColumn(parts[i].pos, parts[i].end, sourceFile, options);
|
||||
|
||||
var newIndentation = nonWhitespaceColumn + delta;
|
||||
if (newIndentation > 0) {
|
||||
var indentationString = getIndentationString(newIndentation, options);
|
||||
recordReplace(startLinePos, nonWhitespaceColumn, indentationString);
|
||||
}
|
||||
else {
|
||||
recordDelete(startLinePos, nonWhitespaceColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function trimTrailingWhitespacesForLines(line1: number, line2: number, range?: TextRangeWithKind) {
|
||||
for (var line = line1; line < line2; ++line) {
|
||||
var lineStartPosition = getStartPositionOfLine(line, sourceFile);
|
||||
var lineEndPosition = getEndLinePosition(line, sourceFile);
|
||||
|
||||
// do not trim whitespaces in comments
|
||||
if (range && isComment(range.kind) && range.pos <= lineEndPosition && range.end > lineEndPosition) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var pos = lineEndPosition;
|
||||
while (pos >= lineStartPosition && isWhiteSpace(sourceFile.text.charCodeAt(pos))) {
|
||||
pos--;
|
||||
}
|
||||
if (pos !== lineEndPosition) {
|
||||
Debug.assert(pos === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(pos)));
|
||||
recordDelete(pos + 1, lineEndPosition - pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function newTextChange(start: number, len: number, newText: string): TextChange {
|
||||
return { span: new TypeScript.TextSpan(start, len), newText: newText }
|
||||
}
|
||||
|
||||
function recordDelete(start: number, len: number) {
|
||||
if (len) {
|
||||
edits.push(newTextChange(start, len, ""));
|
||||
}
|
||||
}
|
||||
|
||||
function recordReplace(start: number, len: number, newText: string) {
|
||||
if (len || newText) {
|
||||
edits.push(newTextChange(start, len, newText));
|
||||
}
|
||||
}
|
||||
|
||||
function applyRuleEdits(rule: Rule,
|
||||
previousRange: TextRangeWithKind,
|
||||
previousStartLine: number,
|
||||
currentRange: TextRangeWithKind,
|
||||
currentStartLine: number): void {
|
||||
|
||||
var between: TextRange;
|
||||
switch (rule.Operation.Action) {
|
||||
case RuleAction.Ignore:
|
||||
// no action required
|
||||
return;
|
||||
case RuleAction.Delete:
|
||||
if (previousRange.end !== currentRange.pos) {
|
||||
// delete characters starting from t1.end up to t2.pos exclusive
|
||||
recordDelete(previousRange.end, currentRange.pos - previousRange.end);
|
||||
}
|
||||
break;
|
||||
case RuleAction.NewLine:
|
||||
// exit early if we on different lines and rule cannot change number of newlines
|
||||
// if line1 and line2 are on subsequent lines then no edits are required - ok to exit
|
||||
// if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines
|
||||
if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
// edit should not be applied only if we have one line feed between elements
|
||||
var lineDelta = currentStartLine - previousStartLine;
|
||||
if (lineDelta !== 1) {
|
||||
recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.NewLineCharacter);
|
||||
}
|
||||
break;
|
||||
case RuleAction.Space:
|
||||
// exit early if we on different lines and rule cannot change number of newlines
|
||||
if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
var posDelta = currentRange.pos - previousRange.end;
|
||||
if (posDelta !== 1 || sourceFile.text.charCodeAt(previousRange.end) !== CharacterCodes.space) {
|
||||
recordReplace(previousRange.end, currentRange.pos - previousRange.end, " ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isSomeBlock(kind: SyntaxKind): boolean {
|
||||
switch (kind) {
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.FunctionBlock:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getOpenTokenForList(node: Node, list: Node[]) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if ((<FunctionDeclaration>node).typeParameters === list) {
|
||||
return SyntaxKind.LessThanToken;
|
||||
}
|
||||
else if ((<FunctionDeclaration>node).parameters === list) {
|
||||
return SyntaxKind.OpenParenToken;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
if ((<CallExpression>node).typeArguments === list) {
|
||||
return SyntaxKind.LessThanToken;
|
||||
}
|
||||
else if ((<CallExpression>node).arguments === list) {
|
||||
return SyntaxKind.OpenParenToken;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.TypeReference:
|
||||
if ((<TypeReferenceNode>node).typeArguments === list) {
|
||||
return SyntaxKind.LessThanToken;
|
||||
}
|
||||
}
|
||||
|
||||
return SyntaxKind.Unknown;
|
||||
}
|
||||
|
||||
function getCloseTokenForOpenToken(kind: SyntaxKind) {
|
||||
switch (kind) {
|
||||
case SyntaxKind.OpenParenToken:
|
||||
return SyntaxKind.CloseParenToken;
|
||||
case SyntaxKind.LessThanToken:
|
||||
return SyntaxKind.GreaterThanToken;
|
||||
}
|
||||
|
||||
return SyntaxKind.Unknown;
|
||||
}
|
||||
}
|
||||
@ -1,320 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class Formatter extends MultipleTokenIndenter {
|
||||
private previousTokenSpan: TokenSpan = null;
|
||||
private previousTokenParent: IndentationNodeContext = null;
|
||||
|
||||
// TODO: implement it with skipped tokens in Fidelity
|
||||
private scriptHasErrors: boolean = false;
|
||||
|
||||
private rulesProvider: RulesProvider;
|
||||
private formattingRequestKind: FormattingRequestKind;
|
||||
private formattingContext: FormattingContext;
|
||||
|
||||
constructor(textSpan: TextSpan,
|
||||
sourceUnit: SourceUnitSyntax,
|
||||
indentFirstToken: boolean,
|
||||
options: FormattingOptions,
|
||||
snapshot: ITextSnapshot,
|
||||
rulesProvider: RulesProvider,
|
||||
formattingRequestKind: FormattingRequestKind) {
|
||||
|
||||
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
|
||||
|
||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
||||
|
||||
this.rulesProvider = rulesProvider;
|
||||
this.formattingRequestKind = formattingRequestKind;
|
||||
this.formattingContext = new FormattingContext(this.snapshot(), this.formattingRequestKind);
|
||||
}
|
||||
|
||||
public static getEdits(textSpan: TextSpan,
|
||||
sourceUnit: SourceUnitSyntax,
|
||||
options: FormattingOptions,
|
||||
indentFirstToken: boolean,
|
||||
snapshot: ITextSnapshot,
|
||||
rulesProvider: RulesProvider,
|
||||
formattingRequestKind: FormattingRequestKind): TextEditInfo[] {
|
||||
var walker = new Formatter(textSpan, sourceUnit, indentFirstToken, options, snapshot, rulesProvider, formattingRequestKind);
|
||||
visitNodeOrToken(walker, sourceUnit);
|
||||
return walker.edits();
|
||||
}
|
||||
|
||||
public visitTokenInSpan(token: ISyntaxToken): void {
|
||||
if (token.fullWidth() !== 0) {
|
||||
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
|
||||
if (this.textSpan().containsTextSpan(tokenSpan)) {
|
||||
this.processToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
// Call the base class to process the token and indent it if needed
|
||||
super.visitTokenInSpan(token);
|
||||
}
|
||||
|
||||
private processToken(token: ISyntaxToken): void {
|
||||
var position = this.position();
|
||||
|
||||
// Extract any leading comments
|
||||
if (token.leadingTriviaWidth() !== 0) {
|
||||
this.processTrivia(token.leadingTrivia(), position);
|
||||
position += token.leadingTriviaWidth();
|
||||
}
|
||||
|
||||
// Push the token
|
||||
var currentTokenSpan = new TokenSpan(token.kind(), position, width(token));
|
||||
if (!this.parent().hasSkippedOrMissingTokenChild()) {
|
||||
if (this.previousTokenSpan) {
|
||||
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
|
||||
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
|
||||
}
|
||||
else {
|
||||
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
|
||||
this.trimWhitespaceInLineRange(this.getLineNumber(this.textSpan()), this.getLineNumber(currentTokenSpan));
|
||||
}
|
||||
}
|
||||
this.previousTokenSpan = currentTokenSpan;
|
||||
if (this.previousTokenParent) {
|
||||
// Make sure to clear the previous parent before assigning a new value to it
|
||||
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
|
||||
}
|
||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
||||
position += width(token);
|
||||
|
||||
// Extract any trailing comments
|
||||
if (token.trailingTriviaWidth() !== 0) {
|
||||
this.processTrivia(token.trailingTrivia(), position);
|
||||
}
|
||||
}
|
||||
|
||||
private processTrivia(triviaList: ISyntaxTriviaList, fullStart: number) {
|
||||
var position = fullStart;
|
||||
|
||||
for (var i = 0, n = triviaList.count(); i < n ; i++) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
// For a comment, format it like it is a token. For skipped text, eat it up as a token, but skip the formatting
|
||||
if (trivia.isComment() || trivia.isSkippedToken()) {
|
||||
var currentTokenSpan = new TokenSpan(trivia.kind(), position, trivia.fullWidth());
|
||||
if (this.textSpan().containsTextSpan(currentTokenSpan)) {
|
||||
if (trivia.isComment() && this.previousTokenSpan) {
|
||||
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
|
||||
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
|
||||
}
|
||||
else {
|
||||
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
|
||||
var startLine = this.getLineNumber(this.previousTokenSpan || this.textSpan());
|
||||
this.trimWhitespaceInLineRange(startLine, this.getLineNumber(currentTokenSpan));
|
||||
}
|
||||
this.previousTokenSpan = currentTokenSpan;
|
||||
if (this.previousTokenParent) {
|
||||
// Make sure to clear the previous parent before assigning a new value to it
|
||||
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
|
||||
}
|
||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
||||
}
|
||||
}
|
||||
|
||||
position += trivia.fullWidth();
|
||||
}
|
||||
}
|
||||
|
||||
private findCommonParents(parent1: IndentationNodeContext, parent2: IndentationNodeContext): IndentationNodeContext {
|
||||
// TODO: disable debug assert message
|
||||
|
||||
var shallowParent: IndentationNodeContext;
|
||||
var shallowParentDepth: number;
|
||||
var deepParent: IndentationNodeContext;
|
||||
var deepParentDepth: number;
|
||||
|
||||
if (parent1.depth() < parent2.depth()) {
|
||||
shallowParent = parent1;
|
||||
shallowParentDepth = parent1.depth();
|
||||
deepParent = parent2;
|
||||
deepParentDepth = parent2.depth();
|
||||
}
|
||||
else {
|
||||
shallowParent = parent2;
|
||||
shallowParentDepth = parent2.depth();
|
||||
deepParent = parent1;
|
||||
deepParentDepth = parent1.depth();
|
||||
}
|
||||
|
||||
Debug.assert(shallowParentDepth >= 0, "Expected shallowParentDepth >= 0");
|
||||
Debug.assert(deepParentDepth >= 0, "Expected deepParentDepth >= 0");
|
||||
Debug.assert(deepParentDepth >= shallowParentDepth, "Expected deepParentDepth >= shallowParentDepth");
|
||||
|
||||
while (deepParentDepth > shallowParentDepth) {
|
||||
deepParent = <IndentationNodeContext>deepParent.parent();
|
||||
deepParentDepth--;
|
||||
}
|
||||
|
||||
Debug.assert(deepParentDepth === shallowParentDepth, "Expected deepParentDepth === shallowParentDepth");
|
||||
|
||||
while (deepParent.node() && shallowParent.node()) {
|
||||
if (deepParent.node() === shallowParent.node()) {
|
||||
return deepParent;
|
||||
}
|
||||
deepParent = <IndentationNodeContext>deepParent.parent();
|
||||
shallowParent = <IndentationNodeContext>shallowParent.parent();
|
||||
}
|
||||
|
||||
// The root should be the first element in the parent chain, we can not be here unless something wrong
|
||||
// happened along the way
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
|
||||
private formatPair(t1: TokenSpan, t1Parent: IndentationNodeContext, t2: TokenSpan, t2Parent: IndentationNodeContext): void {
|
||||
var token1Line = this.getLineNumber(t1);
|
||||
var token2Line = this.getLineNumber(t2);
|
||||
|
||||
// Find common parent
|
||||
var commonParent= this.findCommonParents(t1Parent, t2Parent);
|
||||
|
||||
// Update the context
|
||||
this.formattingContext.updateContext(t1, t1Parent, t2, t2Parent, commonParent);
|
||||
|
||||
// Find rules matching the current context
|
||||
var rule = this.rulesProvider.getRulesMap().GetRule(this.formattingContext);
|
||||
|
||||
if (rule != null) {
|
||||
// Record edits from the rule
|
||||
this.RecordRuleEdits(rule, t1, t2);
|
||||
|
||||
// Handle the case where the next line is moved to be the end of this line.
|
||||
// In this case we don't indent the next line in the next pass.
|
||||
if ((rule.Operation.Action == RuleAction.Space || rule.Operation.Action == RuleAction.Delete) &&
|
||||
token1Line != token2Line) {
|
||||
this.forceSkipIndentingNextToken(t2.start());
|
||||
}
|
||||
|
||||
// Handle the case where token2 is moved to the new line.
|
||||
// In this case we indent token2 in the next pass but we set
|
||||
// sameLineIndent flag to notify the indenter that the indentation is within the line.
|
||||
if (rule.Operation.Action == RuleAction.NewLine && token1Line == token2Line) {
|
||||
this.forceIndentNextToken(t2.start());
|
||||
}
|
||||
}
|
||||
|
||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||
if (token1Line != token2Line && (!rule || (rule.Operation.Action != RuleAction.Delete && rule.Flag != RuleFlags.CanDeleteNewLines))) {
|
||||
this.trimWhitespaceInLineRange(token1Line, token2Line, t1);
|
||||
}
|
||||
}
|
||||
|
||||
private getLineNumber(span: TextSpan): number {
|
||||
return this.snapshot().getLineNumberFromPosition(span.start());
|
||||
}
|
||||
|
||||
private trimWhitespaceInLineRange(startLine: number, endLine: number, token?: TokenSpan): void {
|
||||
for (var lineNumber = startLine; lineNumber < endLine; ++lineNumber) {
|
||||
var line = this.snapshot().getLineFromLineNumber(lineNumber);
|
||||
|
||||
this.trimWhitespace(line, token);
|
||||
}
|
||||
}
|
||||
|
||||
private trimWhitespace(line: ITextSnapshotLine, token?: TokenSpan): void {
|
||||
// Don't remove the trailing spaces inside comments (this includes line comments and block comments)
|
||||
if (token && (token.kind == SyntaxKind.MultiLineCommentTrivia || token.kind == SyntaxKind.SingleLineCommentTrivia) && token.start() <= line.endPosition() && token.end() >= line.endPosition())
|
||||
return;
|
||||
|
||||
var text = line.getText();
|
||||
var index = 0;
|
||||
|
||||
for (index = text.length - 1; index >= 0; --index) {
|
||||
if (!CharacterInfo.isWhitespace(text.charCodeAt(index))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
if (index < text.length) {
|
||||
this.recordEdit(line.startPosition() + index, line.length() - index, "");
|
||||
}
|
||||
}
|
||||
|
||||
private RecordRuleEdits(rule: Rule, t1: TokenSpan, t2: TokenSpan): void {
|
||||
if (rule.Operation.Action == RuleAction.Ignore) {
|
||||
return;
|
||||
}
|
||||
|
||||
var betweenSpan: TextSpan;
|
||||
|
||||
switch (rule.Operation.Action) {
|
||||
case RuleAction.Delete:
|
||||
{
|
||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
||||
|
||||
if (betweenSpan.length() > 0) {
|
||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), "");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RuleAction.NewLine:
|
||||
{
|
||||
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
|
||||
return;
|
||||
}
|
||||
|
||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
||||
|
||||
var doEdit = false;
|
||||
var betweenText = this.snapshot().getText(betweenSpan);
|
||||
|
||||
var lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter);
|
||||
if (lineFeedLoc < 0) {
|
||||
// no linefeeds, do the edit
|
||||
doEdit = true;
|
||||
}
|
||||
else {
|
||||
// We only require one line feed. If there is another one, do the edit
|
||||
lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter, lineFeedLoc + 1);
|
||||
if (lineFeedLoc >= 0) {
|
||||
doEdit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doEdit) {
|
||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), this.options.newLineCharacter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RuleAction.Space:
|
||||
{
|
||||
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
|
||||
return;
|
||||
}
|
||||
|
||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
||||
|
||||
if (betweenSpan.length() > 1 || this.snapshot().getText(betweenSpan) != " ") {
|
||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), " ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,48 +13,48 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/// <reference path="formatting.ts"/>
|
||||
/// <reference path="references.ts"/>
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class FormattingContext {
|
||||
public currentTokenSpan: TokenSpan = null;
|
||||
public nextTokenSpan: TokenSpan = null;
|
||||
public contextNode: IndentationNodeContext = null;
|
||||
public currentTokenParent: IndentationNodeContext = null;
|
||||
public nextTokenParent: IndentationNodeContext = null;
|
||||
public currentTokenSpan: TextRangeWithKind;
|
||||
public nextTokenSpan: TextRangeWithKind;
|
||||
public contextNode: Node;
|
||||
public currentTokenParent: Node;
|
||||
public nextTokenParent: Node;
|
||||
|
||||
private contextNodeAllOnSameLine: boolean = null;
|
||||
private nextNodeAllOnSameLine: boolean = null;
|
||||
private tokensAreOnSameLine: boolean = null;
|
||||
private contextNodeBlockIsOnOneLine: boolean = null;
|
||||
private nextNodeBlockIsOnOneLine: boolean = null;
|
||||
private contextNodeAllOnSameLine: boolean;
|
||||
private nextNodeAllOnSameLine: boolean;
|
||||
private tokensAreOnSameLine: boolean;
|
||||
private contextNodeBlockIsOnOneLine: boolean;
|
||||
private nextNodeBlockIsOnOneLine: boolean;
|
||||
|
||||
constructor(private snapshot: ITextSnapshot, public formattingRequestKind: FormattingRequestKind) {
|
||||
Debug.assert(this.snapshot != null, "snapshot is null");
|
||||
constructor(private sourceFile: SourceFile, public formattingRequestKind: FormattingRequestKind) {
|
||||
}
|
||||
|
||||
public updateContext(currentTokenSpan: TokenSpan, currentTokenParent: IndentationNodeContext, nextTokenSpan: TokenSpan, nextTokenParent: IndentationNodeContext, commonParent: IndentationNodeContext) {
|
||||
Debug.assert(currentTokenSpan != null, "currentTokenSpan is null");
|
||||
Debug.assert(currentTokenParent != null, "currentTokenParent is null");
|
||||
Debug.assert(nextTokenSpan != null, "nextTokenSpan is null");
|
||||
Debug.assert(nextTokenParent != null, "nextTokenParent is null");
|
||||
Debug.assert(commonParent != null, "commonParent is null");
|
||||
public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) {
|
||||
Debug.assert(currentRange !== undefined, "currentTokenSpan is null");
|
||||
Debug.assert(currentTokenParent !== undefined, "currentTokenParent is null");
|
||||
Debug.assert(nextRange !== undefined, "nextTokenSpan is null");
|
||||
Debug.assert(nextTokenParent !== undefined, "nextTokenParent is null");
|
||||
Debug.assert(commonParent !== undefined, "commonParent is null");
|
||||
|
||||
this.currentTokenSpan = currentTokenSpan;
|
||||
this.currentTokenSpan = currentRange;
|
||||
this.currentTokenParent = currentTokenParent;
|
||||
this.nextTokenSpan = nextTokenSpan;
|
||||
this.nextTokenSpan = nextRange;
|
||||
this.nextTokenParent = nextTokenParent;
|
||||
this.contextNode = commonParent;
|
||||
|
||||
this.contextNodeAllOnSameLine = null;
|
||||
this.nextNodeAllOnSameLine = null;
|
||||
this.tokensAreOnSameLine = null;
|
||||
this.contextNodeBlockIsOnOneLine = null;
|
||||
this.nextNodeBlockIsOnOneLine = null;
|
||||
// drop cached results
|
||||
this.contextNodeAllOnSameLine = undefined;
|
||||
this.nextNodeAllOnSameLine = undefined;
|
||||
this.tokensAreOnSameLine = undefined;
|
||||
this.contextNodeBlockIsOnOneLine = undefined;
|
||||
this.nextNodeBlockIsOnOneLine = undefined;
|
||||
}
|
||||
|
||||
public ContextNodeAllOnSameLine(): boolean {
|
||||
if (this.contextNodeAllOnSameLine === null) {
|
||||
if (this.contextNodeAllOnSameLine === undefined) {
|
||||
this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode);
|
||||
}
|
||||
|
||||
@ -62,7 +62,7 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
public NextNodeAllOnSameLine(): boolean {
|
||||
if (this.nextNodeAllOnSameLine === null) {
|
||||
if (this.nextNodeAllOnSameLine === undefined) {
|
||||
this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent);
|
||||
}
|
||||
|
||||
@ -70,10 +70,9 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
public TokensAreOnSameLine(): boolean {
|
||||
if (this.tokensAreOnSameLine === null) {
|
||||
var startLine = this.snapshot.getLineNumberFromPosition(this.currentTokenSpan.start());
|
||||
var endLine = this.snapshot.getLineNumberFromPosition(this.nextTokenSpan.start());
|
||||
|
||||
if (this.tokensAreOnSameLine === undefined) {
|
||||
var startLine = this.sourceFile.getLineAndCharacterFromPosition(this.currentTokenSpan.pos).line;
|
||||
var endLine = this.sourceFile.getLineAndCharacterFromPosition(this.nextTokenSpan.pos).line;
|
||||
this.tokensAreOnSameLine = (startLine == endLine);
|
||||
}
|
||||
|
||||
@ -81,7 +80,7 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
public ContextNodeBlockIsOnOneLine() {
|
||||
if (this.contextNodeBlockIsOnOneLine === null) {
|
||||
if (this.contextNodeBlockIsOnOneLine === undefined) {
|
||||
this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode);
|
||||
}
|
||||
|
||||
@ -89,28 +88,28 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
public NextNodeBlockIsOnOneLine() {
|
||||
if (this.nextNodeBlockIsOnOneLine === null) {
|
||||
if (this.nextNodeBlockIsOnOneLine === undefined) {
|
||||
this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent);
|
||||
}
|
||||
|
||||
return this.nextNodeBlockIsOnOneLine;
|
||||
}
|
||||
|
||||
public NodeIsOnOneLine(node: IndentationNodeContext): boolean {
|
||||
var startLine = this.snapshot.getLineNumberFromPosition(node.start());
|
||||
var endLine = this.snapshot.getLineNumberFromPosition(node.end());
|
||||
|
||||
private NodeIsOnOneLine(node: Node): boolean {
|
||||
var startLine = this.sourceFile.getLineAndCharacterFromPosition(node.getStart(this.sourceFile)).line;
|
||||
var endLine = this.sourceFile.getLineAndCharacterFromPosition(node.getEnd()).line;
|
||||
return startLine == endLine;
|
||||
}
|
||||
|
||||
// Now we know we have a block (or a fake block represented by some other kind of node with an open and close brace as children).
|
||||
// IMPORTANT!!! This relies on the invariant that IsBlockContext must return true ONLY for nodes with open and close braces as immediate children
|
||||
public BlockIsOnOneLine(node: IndentationNodeContext): boolean {
|
||||
var block = <BlockSyntax>node.node();
|
||||
|
||||
// Now check if they are on the same line
|
||||
return this.snapshot.getLineNumberFromPosition(end(block.openBraceToken)) ===
|
||||
this.snapshot.getLineNumberFromPosition(start(block.closeBraceToken));
|
||||
private BlockIsOnOneLine(node: Node): boolean {
|
||||
var openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile);
|
||||
var closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile);
|
||||
if (openBrace && closeBrace) {
|
||||
var startLine = this.sourceFile.getLineAndCharacterFromPosition(openBrace.getEnd()).line;
|
||||
var endLine = this.sourceFile.getLineAndCharacterFromPosition(closeBrace.getStart(this.sourceFile)).line;
|
||||
return startLine === endLine;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,125 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/// <reference path="formatting.ts"/>
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class FormattingManager {
|
||||
private options: FormattingOptions;
|
||||
|
||||
constructor(private syntaxTree: SyntaxTree,
|
||||
private snapshot: ITextSnapshot,
|
||||
private rulesProvider: RulesProvider,
|
||||
editorOptions: ts.EditorOptions) {
|
||||
//
|
||||
// TODO: convert to use FormattingOptions instead of EditorOptions
|
||||
this.options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter)
|
||||
}
|
||||
|
||||
public formatSelection(minChar: number, limChar: number): ts.TextChange[] {
|
||||
var span = TextSpan.fromBounds(minChar, limChar);
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatSelection);
|
||||
}
|
||||
|
||||
public formatDocument(): ts.TextChange[] {
|
||||
var span = TextSpan.fromBounds(0, this.snapshot.getLength());
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatDocument);
|
||||
}
|
||||
|
||||
public formatOnSemicolon(caretPosition: number): ts.TextChange[] {
|
||||
var sourceUnit = this.syntaxTree.sourceUnit();
|
||||
var semicolonPositionedToken = findToken(sourceUnit, caretPosition - 1);
|
||||
|
||||
if (semicolonPositionedToken.kind() === SyntaxKind.SemicolonToken) {
|
||||
// Find the outer most parent that this semicolon terminates
|
||||
var current: ISyntaxElement = semicolonPositionedToken;
|
||||
while (current.parent !== null &&
|
||||
end(current.parent) === end(semicolonPositionedToken) &&
|
||||
current.parent.kind() !== SyntaxKind.List) {
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
// Compute the span
|
||||
var span = new TextSpan(fullStart(current), fullWidth(current));
|
||||
|
||||
// Format the span
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatOnSemicolon);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public formatOnClosingCurlyBrace(caretPosition: number): ts.TextChange[] {
|
||||
var sourceUnit = this.syntaxTree.sourceUnit();
|
||||
var closeBracePositionedToken = findToken(sourceUnit, caretPosition - 1);
|
||||
|
||||
if (closeBracePositionedToken.kind() === SyntaxKind.CloseBraceToken) {
|
||||
// Find the outer most parent that this closing brace terminates
|
||||
var current: ISyntaxElement = closeBracePositionedToken;
|
||||
while (current.parent !== null &&
|
||||
end(current.parent) === end(closeBracePositionedToken) &&
|
||||
current.parent.kind() !== SyntaxKind.List) {
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
// Compute the span
|
||||
var span = new TextSpan(fullStart(current), fullWidth(current));
|
||||
|
||||
// Format the span
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatOnClosingCurlyBrace);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public formatOnEnter(caretPosition: number): ts.TextChange[] {
|
||||
var lineNumber = this.snapshot.getLineNumberFromPosition(caretPosition);
|
||||
|
||||
if (lineNumber > 0) {
|
||||
// Format both lines
|
||||
var prevLine = this.snapshot.getLineFromLineNumber(lineNumber - 1);
|
||||
var currentLine = this.snapshot.getLineFromLineNumber(lineNumber);
|
||||
var span = TextSpan.fromBounds(prevLine.startPosition(), currentLine.endPosition());
|
||||
|
||||
// Format the span
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatOnEnter);
|
||||
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): ts.TextChange[] {
|
||||
// Always format from the beginning of the line
|
||||
var startLine = this.snapshot.getLineFromPosition(span.start());
|
||||
span = TextSpan.fromBounds(startLine.startPosition(), span.end());
|
||||
|
||||
var result: ts.TextChange[] = [];
|
||||
|
||||
var formattingEdits = Formatter.getEdits(span, this.syntaxTree.sourceUnit(), this.options, true, this.snapshot, this.rulesProvider, formattingRequestKind);
|
||||
|
||||
//
|
||||
// TODO: Change the ILanguageService interface to return TextEditInfo (with start, and length) instead of TextEdit (with minChar and limChar)
|
||||
formattingEdits.forEach(item => {
|
||||
result.push({
|
||||
span: new TextSpan(item.position, item.length),
|
||||
newText: item.replaceWith
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,15 +13,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/// <reference path="formatting.ts"/>
|
||||
/// <reference path="references.ts"/>
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export enum FormattingRequestKind {
|
||||
module ts.formatting {
|
||||
export const enum FormattingRequestKind {
|
||||
FormatDocument,
|
||||
FormatSelection,
|
||||
FormatOnEnter,
|
||||
FormatOnSemicolon,
|
||||
FormatOnClosingCurlyBrace,
|
||||
FormatOnPaste
|
||||
FormatOnClosingCurlyBrace
|
||||
}
|
||||
}
|
||||
222
src/services/formatting/formattingScanner.ts
Normal file
222
src/services/formatting/formattingScanner.ts
Normal file
@ -0,0 +1,222 @@
|
||||
/// <reference path="..\formatting.ts"/>
|
||||
/// <reference path="..\..\compiler\scanner.ts"/>
|
||||
|
||||
module ts.formatting {
|
||||
var scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false);
|
||||
|
||||
export interface FormattingScanner {
|
||||
advance(): void;
|
||||
isOnToken(): boolean;
|
||||
readTokenInfo(n: Node): TokenInfo;
|
||||
lastTrailingTriviaWasNewLine(): boolean;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
const enum ScanAction{
|
||||
Scan,
|
||||
RescanGreaterThanToken,
|
||||
RescanSlashToken,
|
||||
RescanTemplateToken
|
||||
}
|
||||
|
||||
export function getFormattingScanner(sourceFile: SourceFile, startPos: number, endPos: number): FormattingScanner {
|
||||
|
||||
scanner.setText(sourceFile.text);
|
||||
scanner.setTextPos(startPos);
|
||||
|
||||
var wasNewLine: boolean = true;
|
||||
var leadingTrivia: TextRangeWithKind[];
|
||||
var trailingTrivia: TextRangeWithKind[];
|
||||
|
||||
var savedPos: number;
|
||||
var lastScanAction: ScanAction;
|
||||
var lastTokenInfo: TokenInfo;
|
||||
|
||||
return {
|
||||
advance: advance,
|
||||
readTokenInfo: readTokenInfo,
|
||||
isOnToken: isOnToken,
|
||||
lastTrailingTriviaWasNewLine: () => wasNewLine,
|
||||
close: () => {
|
||||
lastTokenInfo = undefined;
|
||||
scanner.setText(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function advance(): void {
|
||||
lastTokenInfo = undefined;
|
||||
var isStarted = scanner.getStartPos() !== startPos;
|
||||
|
||||
if (isStarted) {
|
||||
if (trailingTrivia) {
|
||||
Debug.assert(trailingTrivia.length !== 0);
|
||||
wasNewLine = trailingTrivia[trailingTrivia.length - 1].kind === SyntaxKind.NewLineTrivia;
|
||||
}
|
||||
else {
|
||||
wasNewLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
leadingTrivia = undefined;
|
||||
trailingTrivia = undefined;
|
||||
|
||||
if (!isStarted) {
|
||||
scanner.scan();
|
||||
}
|
||||
|
||||
var t: SyntaxKind;
|
||||
var pos = scanner.getStartPos();
|
||||
|
||||
// Read leading trivia and token
|
||||
while (pos < endPos) {
|
||||
var t = scanner.getToken();
|
||||
if (!isTrivia(t)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// consume leading trivia
|
||||
scanner.scan();
|
||||
var item = {
|
||||
pos: pos,
|
||||
end: scanner.getStartPos(),
|
||||
kind: t
|
||||
}
|
||||
|
||||
pos = scanner.getStartPos();
|
||||
|
||||
if (!leadingTrivia) {
|
||||
leadingTrivia = [];
|
||||
}
|
||||
leadingTrivia.push(item);
|
||||
}
|
||||
|
||||
savedPos = scanner.getStartPos();
|
||||
}
|
||||
|
||||
function shouldRescanGreaterThanToken(container: Node): boolean {
|
||||
if (container.kind !== SyntaxKind.BinaryExpression) {
|
||||
return false;
|
||||
}
|
||||
switch ((<BinaryExpression>container).operator) {
|
||||
case SyntaxKind.GreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanToken:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function shouldRescanSlashToken(container: Node): boolean {
|
||||
return container.kind === SyntaxKind.RegularExpressionLiteral;
|
||||
}
|
||||
|
||||
function shouldRescanTemplateToken(container: Node): boolean {
|
||||
return container.kind === SyntaxKind.TemplateSpan;
|
||||
}
|
||||
|
||||
function startsWithSlashToken(t: SyntaxKind): boolean {
|
||||
return t === SyntaxKind.SlashToken || t === SyntaxKind.SlashEqualsToken;
|
||||
}
|
||||
|
||||
function readTokenInfo(n: Node): TokenInfo {
|
||||
if (!isOnToken()) {
|
||||
// scanner is not on the token (either advance was not called yet or scanner is already past the end position)
|
||||
return {
|
||||
leadingTrivia: leadingTrivia,
|
||||
trailingTrivia: undefined,
|
||||
token: undefined
|
||||
};
|
||||
}
|
||||
|
||||
// normally scanner returns the smallest available token
|
||||
// check the kind of context node to determine if scanner should have more greedy behavior and consume more text.
|
||||
var expectedScanAction =
|
||||
shouldRescanGreaterThanToken(n)
|
||||
? ScanAction.RescanGreaterThanToken
|
||||
: shouldRescanSlashToken(n)
|
||||
? ScanAction.RescanSlashToken
|
||||
: shouldRescanTemplateToken(n)
|
||||
? ScanAction.RescanTemplateToken
|
||||
: ScanAction.Scan
|
||||
|
||||
if (lastTokenInfo && expectedScanAction === lastScanAction) {
|
||||
// readTokenInfo was called before with the same expected scan action.
|
||||
// No need to re-scan text, return existing 'lastTokenInfo'
|
||||
return lastTokenInfo;
|
||||
}
|
||||
|
||||
if (scanner.getStartPos() !== savedPos) {
|
||||
Debug.assert(lastTokenInfo !== undefined);
|
||||
// readTokenInfo was called before but scan action differs - rescan text
|
||||
scanner.setTextPos(savedPos);
|
||||
scanner.scan();
|
||||
}
|
||||
|
||||
var currentToken = scanner.getToken();
|
||||
|
||||
if (expectedScanAction === ScanAction.RescanGreaterThanToken && currentToken === SyntaxKind.GreaterThanToken) {
|
||||
currentToken = scanner.reScanGreaterToken();
|
||||
Debug.assert((<BinaryExpression>n).operator === currentToken);
|
||||
lastScanAction = ScanAction.RescanGreaterThanToken;
|
||||
}
|
||||
else if (expectedScanAction === ScanAction.RescanSlashToken && startsWithSlashToken(currentToken)) {
|
||||
currentToken = scanner.reScanSlashToken();
|
||||
Debug.assert(n.kind === currentToken);
|
||||
lastScanAction = ScanAction.RescanSlashToken;
|
||||
}
|
||||
else if (expectedScanAction === ScanAction.RescanTemplateToken && currentToken === SyntaxKind.CloseBraceToken) {
|
||||
currentToken = scanner.reScanTemplateToken();
|
||||
lastScanAction = ScanAction.RescanTemplateToken;
|
||||
}
|
||||
else {
|
||||
lastScanAction = ScanAction.Scan;
|
||||
}
|
||||
|
||||
var token: TextRangeWithKind = {
|
||||
pos: scanner.getStartPos(),
|
||||
end: scanner.getTextPos(),
|
||||
kind: currentToken
|
||||
}
|
||||
|
||||
// consume trailing trivia
|
||||
while(scanner.getStartPos() < endPos) {
|
||||
currentToken = scanner.scan();
|
||||
if (!isTrivia(currentToken)) {
|
||||
break;
|
||||
}
|
||||
var trivia = {
|
||||
pos: scanner.getStartPos(),
|
||||
end: scanner.getTextPos(),
|
||||
kind: currentToken
|
||||
};
|
||||
|
||||
if (!trailingTrivia) {
|
||||
trailingTrivia = [];
|
||||
}
|
||||
|
||||
trailingTrivia.push(trivia);
|
||||
|
||||
if (currentToken === SyntaxKind.NewLineTrivia) {
|
||||
// move past new line
|
||||
scanner.scan();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return lastTokenInfo = {
|
||||
leadingTrivia: leadingTrivia,
|
||||
trailingTrivia: trailingTrivia,
|
||||
token: token
|
||||
}
|
||||
}
|
||||
|
||||
function isOnToken(): boolean {
|
||||
var current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken();
|
||||
var startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos();
|
||||
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/services/formatting/indentation.ts
Normal file
54
src/services/formatting/indentation.ts
Normal file
@ -0,0 +1,54 @@
|
||||
module ts.formatting {
|
||||
|
||||
var internedTabsIndentation: string[];
|
||||
var internedSpacesIndentation: string[];
|
||||
|
||||
export function getIndentationString(indentation: number, options: FormatCodeOptions): string {
|
||||
if (!options.ConvertTabsToSpaces) {
|
||||
var tabs = Math.floor(indentation / options.TabSize);
|
||||
var spaces = indentation - tabs * options.TabSize;
|
||||
|
||||
var tabString: string;
|
||||
if (!internedTabsIndentation) {
|
||||
internedTabsIndentation = [];
|
||||
}
|
||||
|
||||
if (internedTabsIndentation[tabs] === undefined) {
|
||||
internedTabsIndentation[tabs] = tabString = repeat('\t', tabs);
|
||||
}
|
||||
else {
|
||||
tabString = internedTabsIndentation[tabs];
|
||||
}
|
||||
|
||||
return spaces ? tabString + repeat(" ", spaces) : tabString;
|
||||
}
|
||||
else {
|
||||
var spacesString: string;
|
||||
var quotient = Math.floor(indentation / options.IndentSize);
|
||||
var remainder = indentation % options.IndentSize;
|
||||
if (!internedSpacesIndentation) {
|
||||
internedSpacesIndentation = [];
|
||||
}
|
||||
|
||||
if (internedSpacesIndentation[quotient] === undefined) {
|
||||
spacesString = repeat(" ", options.IndentSize * quotient);
|
||||
internedSpacesIndentation[quotient] = spacesString;
|
||||
}
|
||||
else {
|
||||
spacesString = internedSpacesIndentation[quotient];
|
||||
}
|
||||
|
||||
|
||||
return remainder ? spacesString + repeat(" ", remainder) : spacesString;
|
||||
}
|
||||
|
||||
function repeat(value: string, count: number): string {
|
||||
var s = "";
|
||||
for (var i = 0; i < count; ++i) {
|
||||
s += value;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,103 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class IndentationNodeContext {
|
||||
private _node: ISyntaxNode;
|
||||
private _parent: IndentationNodeContext;
|
||||
private _fullStart: number;
|
||||
private _indentationAmount: number;
|
||||
private _childIndentationAmountDelta: number;
|
||||
private _depth: number;
|
||||
private _hasSkippedOrMissingTokenChild: boolean;
|
||||
|
||||
constructor(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
|
||||
this.update(parent, node, fullStart, indentationAmount, childIndentationAmountDelta);
|
||||
}
|
||||
|
||||
public parent(): IndentationNodeContext {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
public node(): ISyntaxNode {
|
||||
return this._node;
|
||||
}
|
||||
|
||||
public fullStart(): number {
|
||||
return this._fullStart;
|
||||
}
|
||||
|
||||
public fullWidth(): number {
|
||||
return fullWidth(this._node);
|
||||
}
|
||||
|
||||
public start(): number {
|
||||
return this._fullStart + leadingTriviaWidth(this._node);
|
||||
}
|
||||
|
||||
public end(): number {
|
||||
return this._fullStart + leadingTriviaWidth(this._node) + width(this._node);
|
||||
}
|
||||
|
||||
public indentationAmount(): number {
|
||||
return this._indentationAmount;
|
||||
}
|
||||
|
||||
public childIndentationAmountDelta(): number {
|
||||
return this._childIndentationAmountDelta;
|
||||
}
|
||||
|
||||
public depth(): number {
|
||||
return this._depth;
|
||||
}
|
||||
|
||||
public kind(): SyntaxKind {
|
||||
return this._node.kind();
|
||||
}
|
||||
|
||||
public hasSkippedOrMissingTokenChild(): boolean {
|
||||
if (this._hasSkippedOrMissingTokenChild === null) {
|
||||
this._hasSkippedOrMissingTokenChild = Syntax.nodeHasSkippedOrMissingTokens(this._node);
|
||||
}
|
||||
return this._hasSkippedOrMissingTokenChild;
|
||||
}
|
||||
|
||||
public clone(pool: IndentationNodeContextPool): IndentationNodeContext {
|
||||
var parent: IndentationNodeContext = null;
|
||||
if (this._parent) {
|
||||
parent = this._parent.clone(pool);
|
||||
}
|
||||
return pool.getNode(parent, this._node, this._fullStart, this._indentationAmount, this._childIndentationAmountDelta);
|
||||
}
|
||||
|
||||
public update(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
|
||||
this._parent = parent;
|
||||
this._node = node;
|
||||
this._fullStart = fullStart;
|
||||
this._indentationAmount = indentationAmount;
|
||||
this._childIndentationAmountDelta = childIndentationAmountDelta;
|
||||
this._hasSkippedOrMissingTokenChild = null;
|
||||
|
||||
if (parent) {
|
||||
this._depth = parent.depth() + 1;
|
||||
}
|
||||
else {
|
||||
this._depth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class IndentationNodeContextPool {
|
||||
private nodes: IndentationNodeContext[] = [];
|
||||
|
||||
public getNode(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationLevel: number, childIndentationLevelDelta: number): IndentationNodeContext {
|
||||
if (this.nodes.length > 0) {
|
||||
var cachedNode = this.nodes.pop();
|
||||
cachedNode.update(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
|
||||
return cachedNode;
|
||||
}
|
||||
|
||||
return new IndentationNodeContext(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
|
||||
}
|
||||
|
||||
public releaseNode(node: IndentationNodeContext, recursive: boolean = false): void {
|
||||
this.nodes.push(node);
|
||||
|
||||
if (recursive) {
|
||||
var parent = node.parent();
|
||||
if (parent) {
|
||||
this.releaseNode(parent, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,349 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class IndentationTrackingWalker extends SyntaxWalker {
|
||||
private _position: number = 0;
|
||||
private _parent: IndentationNodeContext = null;
|
||||
private _textSpan: TextSpan;
|
||||
private _snapshot: ITextSnapshot;
|
||||
private _lastTriviaWasNewLine: boolean;
|
||||
private _indentationNodeContextPool: IndentationNodeContextPool;
|
||||
private _text: ISimpleText;
|
||||
|
||||
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, public options: FormattingOptions) {
|
||||
super();
|
||||
|
||||
// Create a pool object to manage context nodes while walking the tree
|
||||
this._indentationNodeContextPool = new IndentationNodeContextPool();
|
||||
|
||||
this._textSpan = textSpan;
|
||||
this._text = sourceUnit.syntaxTree.text;
|
||||
this._snapshot = snapshot;
|
||||
this._parent = this._indentationNodeContextPool.getNode(null, sourceUnit, 0, 0, 0);
|
||||
|
||||
// Is the first token in the span at the start of a new line.
|
||||
this._lastTriviaWasNewLine = indentFirstToken;
|
||||
}
|
||||
|
||||
public position(): number {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
public parent(): IndentationNodeContext {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
public textSpan(): TextSpan {
|
||||
return this._textSpan;
|
||||
}
|
||||
|
||||
public snapshot(): ITextSnapshot {
|
||||
return this._snapshot;
|
||||
}
|
||||
|
||||
public indentationNodeContextPool(): IndentationNodeContextPool {
|
||||
return this._indentationNodeContextPool;
|
||||
}
|
||||
|
||||
public forceIndentNextToken(tokenStart: number): void {
|
||||
this._lastTriviaWasNewLine = true;
|
||||
this.forceRecomputeIndentationOfParent(tokenStart, true);
|
||||
}
|
||||
|
||||
public forceSkipIndentingNextToken(tokenStart: number): void {
|
||||
this._lastTriviaWasNewLine = false;
|
||||
this.forceRecomputeIndentationOfParent(tokenStart, false);
|
||||
}
|
||||
|
||||
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
|
||||
throw Errors.abstract();
|
||||
}
|
||||
|
||||
public visitTokenInSpan(token: ISyntaxToken): void {
|
||||
if (this._lastTriviaWasNewLine) {
|
||||
// Compute the indentation level at the current token
|
||||
var indentationAmount = this.getTokenIndentationAmount(token);
|
||||
var commentIndentationAmount = this.getCommentIndentationAmount(token);
|
||||
|
||||
// Process the token
|
||||
this.indentToken(token, indentationAmount, commentIndentationAmount);
|
||||
}
|
||||
}
|
||||
|
||||
public visitToken(token: ISyntaxToken): void {
|
||||
var tokenSpan = new TextSpan(this._position, token.fullWidth());
|
||||
|
||||
if (tokenSpan.intersectsWithTextSpan(this._textSpan)) {
|
||||
this.visitTokenInSpan(token);
|
||||
|
||||
// Only track new lines on tokens within the range. Make sure to check that the last trivia is a newline, and not just one of the trivia
|
||||
var trivia = token.trailingTrivia();
|
||||
this._lastTriviaWasNewLine = trivia.hasNewLine() && trivia.syntaxTriviaAt(trivia.count() - 1).kind() == SyntaxKind.NewLineTrivia;
|
||||
}
|
||||
|
||||
// Update the position
|
||||
this._position += token.fullWidth();
|
||||
}
|
||||
|
||||
public visitNode(node: ISyntaxNode): void {
|
||||
var nodeSpan = new TextSpan(this._position, fullWidth(node));
|
||||
|
||||
if (nodeSpan.intersectsWithTextSpan(this._textSpan)) {
|
||||
// Update indentation level
|
||||
var indentation = this.getNodeIndentation(node);
|
||||
|
||||
// Update the parent
|
||||
var currentParent = this._parent;
|
||||
this._parent = this._indentationNodeContextPool.getNode(currentParent, node, this._position, indentation.indentationAmount, indentation.indentationAmountDelta);
|
||||
|
||||
// Visit node
|
||||
visitNodeOrToken(this, node);
|
||||
|
||||
// Reset state
|
||||
this._indentationNodeContextPool.releaseNode(this._parent);
|
||||
this._parent = currentParent;
|
||||
}
|
||||
else {
|
||||
// We're skipping the node, so update our position accordingly.
|
||||
this._position += fullWidth(node);
|
||||
}
|
||||
}
|
||||
|
||||
private getTokenIndentationAmount(token: ISyntaxToken): number {
|
||||
// If this is the first token of a node, it should follow the node indentation and not the child indentation;
|
||||
// (e.g.class in a class declaration or module in module declariotion).
|
||||
// Open and close braces should follow the indentation of thier parent as well(e.g.
|
||||
// class {
|
||||
// }
|
||||
// Also in a do-while statement, the while should be indented like the parent.
|
||||
if (firstToken(this._parent.node()) === token ||
|
||||
token.kind() === SyntaxKind.OpenBraceToken || token.kind() === SyntaxKind.CloseBraceToken ||
|
||||
token.kind() === SyntaxKind.OpenBracketToken || token.kind() === SyntaxKind.CloseBracketToken ||
|
||||
(token.kind() === SyntaxKind.WhileKeyword && this._parent.node().kind() == SyntaxKind.DoStatement)) {
|
||||
return this._parent.indentationAmount();
|
||||
}
|
||||
|
||||
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
|
||||
}
|
||||
|
||||
private getCommentIndentationAmount(token: ISyntaxToken): number {
|
||||
// If this is token terminating an indentation scope, leading comments should be indented to follow the children
|
||||
// indentation level and not the node
|
||||
|
||||
if (token.kind() === SyntaxKind.CloseBraceToken || token.kind() === SyntaxKind.CloseBracketToken) {
|
||||
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
|
||||
}
|
||||
return this._parent.indentationAmount();
|
||||
}
|
||||
|
||||
private getNodeIndentation(node: ISyntaxNode, newLineInsertedByFormatting?: boolean): { indentationAmount: number; indentationAmountDelta: number; } {
|
||||
var parent = this._parent;
|
||||
|
||||
// We need to get the parent's indentation, which could be one of 2 things. If first token of the parent is in the span, use the parent's computed indentation.
|
||||
// If the parent was outside the span, use the actual indentation of the parent.
|
||||
var parentIndentationAmount: number;
|
||||
if (this._textSpan.containsPosition(parent.start())) {
|
||||
parentIndentationAmount = parent.indentationAmount();
|
||||
}
|
||||
else {
|
||||
if (parent.kind() === SyntaxKind.Block && !this.shouldIndentBlockInParent(this._parent.parent())) {
|
||||
// Blocks preserve the indentation of their containing node (unless they're a
|
||||
// standalone block in a list). i.e. if you have:
|
||||
//
|
||||
// function foo(
|
||||
// a: number) {
|
||||
//
|
||||
// Then we expect the indentation of the block to be tied to the function, not to
|
||||
// the line that the block is defined on. If we were to do the latter, then the
|
||||
// indentation would be here:
|
||||
//
|
||||
// function foo(
|
||||
// a: number) {
|
||||
// |
|
||||
//
|
||||
// Instead of:
|
||||
//
|
||||
// function foo(
|
||||
// a: number) {
|
||||
// |
|
||||
parent = this._parent.parent();
|
||||
}
|
||||
|
||||
var line = this._snapshot.getLineFromPosition(parent.start()).getText();
|
||||
var firstNonWhiteSpacePosition = Indentation.firstNonWhitespacePosition(line);
|
||||
parentIndentationAmount = Indentation.columnForPositionInString(line, firstNonWhiteSpacePosition, this.options);
|
||||
}
|
||||
var parentIndentationAmountDelta = parent.childIndentationAmountDelta();
|
||||
|
||||
// The indentation level of the node
|
||||
var indentationAmount: number;
|
||||
|
||||
// The delta it adds to its children.
|
||||
var indentationAmountDelta: number;
|
||||
var parentNode = parent.node();
|
||||
|
||||
switch (node.kind()) {
|
||||
default:
|
||||
// General case
|
||||
// This node should follow the child indentation set by its parent
|
||||
// This node does not introduce any new indentation scope, indent any decendants of this node (tokens or child nodes)
|
||||
// using the same indentation level
|
||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
||||
indentationAmountDelta = 0;
|
||||
break;
|
||||
|
||||
// Statements introducing {}
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ObjectType:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.ConstructorDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.IndexMemberDeclaration:
|
||||
case SyntaxKind.CatchClause:
|
||||
// Statements introducing []
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.ArrayType:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
case SyntaxKind.IndexSignature:
|
||||
// Other statements
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.CaseSwitchClause:
|
||||
case SyntaxKind.DefaultSwitchClause:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.ThrowStatement:
|
||||
case SyntaxKind.SimpleArrowFunctionExpression:
|
||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.ExportAssignment:
|
||||
|
||||
// Expressions which have argument lists or parameter lists
|
||||
case SyntaxKind.InvocationExpression:
|
||||
case SyntaxKind.ObjectCreationExpression:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
|
||||
// These nodes should follow the child indentation set by its parent;
|
||||
// they introduce a new indenation scope; children should be indented at one level deeper
|
||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
||||
indentationAmountDelta = this.options.indentSpaces;
|
||||
break;
|
||||
|
||||
case SyntaxKind.IfStatement:
|
||||
if (parent.kind() === SyntaxKind.ElseClause &&
|
||||
!SyntaxUtilities.isLastTokenOnLine((<ElseClauseSyntax>parentNode).elseKeyword, this._text)) {
|
||||
// This is an else if statement with the if on the same line as the else, do not indent the if statmement.
|
||||
// Note: Children indentation has already been set by the parent if statement, so no need to increment
|
||||
indentationAmount = parentIndentationAmount;
|
||||
}
|
||||
else {
|
||||
// Otherwise introduce a new indenation scope; children should be indented at one level deeper
|
||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
||||
}
|
||||
indentationAmountDelta = this.options.indentSpaces;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ElseClause:
|
||||
// Else should always follow its parent if statement indentation.
|
||||
// Note: Children indentation has already been set by the parent if statement, so no need to increment
|
||||
indentationAmount = parentIndentationAmount;
|
||||
indentationAmountDelta = this.options.indentSpaces;
|
||||
break;
|
||||
|
||||
|
||||
case SyntaxKind.Block:
|
||||
// Check if the block is a member in a list of statements (if the parent is a source unit, module, or block, or switch clause)
|
||||
if (this.shouldIndentBlockInParent(parent)) {
|
||||
indentationAmount = parentIndentationAmount + parentIndentationAmountDelta;
|
||||
}
|
||||
else {
|
||||
indentationAmount = parentIndentationAmount;
|
||||
}
|
||||
|
||||
indentationAmountDelta = this.options.indentSpaces;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the parent happens to start on the same line as this node, then override the current node indenation with that
|
||||
// of the parent. This avoid having to add an extra level of indentation for the children. e.g.:
|
||||
// return {
|
||||
// a:1
|
||||
// };
|
||||
// instead of:
|
||||
// return {
|
||||
// a:1
|
||||
// };
|
||||
// We also need to pass the delta (if it is nonzero) to the children, so that subsequent lines get indented. Essentially, if any node starting on the given line
|
||||
// has a nonzero delta , the resulting delta should be inherited from this node. This is to indent cases like the following:
|
||||
// return a
|
||||
// || b;
|
||||
// Lastly, it is possible the node indentation needs to be recomputed because the formatter inserted a newline before its first token.
|
||||
// If this is the case, we know the node no longer starts on the same line as its parent (or at least we shouldn't treat it as such).
|
||||
if (parentNode) {
|
||||
if (!newLineInsertedByFormatting /*This could be false or undefined here*/) {
|
||||
var parentStartLine = this._snapshot.getLineNumberFromPosition(parent.start());
|
||||
var currentNodeStartLine = this._snapshot.getLineNumberFromPosition(this._position + leadingTriviaWidth(node));
|
||||
if (parentStartLine === currentNodeStartLine || newLineInsertedByFormatting === false /*meaning a new line was removed and we are force recomputing*/) {
|
||||
indentationAmount = parentIndentationAmount;
|
||||
indentationAmountDelta = Math.min(this.options.indentSpaces, parentIndentationAmountDelta + indentationAmountDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
indentationAmount: indentationAmount,
|
||||
indentationAmountDelta: indentationAmountDelta
|
||||
};
|
||||
}
|
||||
|
||||
private shouldIndentBlockInParent(parent: IndentationNodeContext): boolean {
|
||||
switch (parent.kind()) {
|
||||
case SyntaxKind.SourceUnit:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.CaseSwitchClause:
|
||||
case SyntaxKind.DefaultSwitchClause:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private forceRecomputeIndentationOfParent(tokenStart: number, newLineAdded: boolean /*as opposed to removed*/): void {
|
||||
var parent = this._parent;
|
||||
if (parent.fullStart() === tokenStart) {
|
||||
// Temporarily pop the parent before recomputing
|
||||
this._parent = parent.parent();
|
||||
var indentation = this.getNodeIndentation(parent.node(), /* newLineInsertedByFormatting */ newLineAdded);
|
||||
parent.update(parent.parent(), parent.node(), parent.fullStart(), indentation.indentationAmount, indentation.indentationAmountDelta);
|
||||
this._parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,206 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class MultipleTokenIndenter extends IndentationTrackingWalker {
|
||||
private _edits: TextEditInfo[] = [];
|
||||
|
||||
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) {
|
||||
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
|
||||
}
|
||||
|
||||
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
|
||||
// Ignore generated tokens
|
||||
if (token.fullWidth() === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have any skipped tokens as children, do not process this node for indentation or formatting
|
||||
if (this.parent().hasSkippedOrMissingTokenChild()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Be strict, and only consider nodes that fall inside the span. This avoids indenting a multiline string
|
||||
// on enter at the end of, as the whole token was not included in the span
|
||||
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
|
||||
if (!this.textSpan().containsTextSpan(tokenSpan)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute an indentation string for this token
|
||||
var indentationString = Indentation.indentationString(indentationAmount, this.options);
|
||||
|
||||
var commentIndentationString = Indentation.indentationString(commentIndentationAmount, this.options);
|
||||
|
||||
// Record any needed indentation edits
|
||||
this.recordIndentationEditsForToken(token, indentationString, commentIndentationString);
|
||||
}
|
||||
|
||||
public edits(): TextEditInfo[]{
|
||||
return this._edits;
|
||||
}
|
||||
|
||||
public recordEdit(position: number, length: number, replaceWith: string): void {
|
||||
this._edits.push(new TextEditInfo(position, length, replaceWith));
|
||||
}
|
||||
|
||||
private recordIndentationEditsForToken(token: ISyntaxToken, indentationString: string, commentIndentationString: string) {
|
||||
var position = this.position();
|
||||
var indentNextTokenOrTrivia = true;
|
||||
var leadingWhiteSpace = ""; // We need to track the whitespace before a multiline comment
|
||||
|
||||
// Process any leading trivia if any
|
||||
var triviaList = token.leadingTrivia();
|
||||
if (triviaList) {
|
||||
for (var i = 0, length = triviaList.count(); i < length; i++, position += trivia.fullWidth()) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
// Skip this trivia if it is not in the span
|
||||
if (!this.textSpan().containsTextSpan(new TextSpan(position, trivia.fullWidth()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (trivia.kind()) {
|
||||
case SyntaxKind.MultiLineCommentTrivia:
|
||||
// We will only indent the first line of the multiline comment if we were planning to indent the next trivia. However,
|
||||
// subsequent lines will always be indented
|
||||
this.recordIndentationEditsForMultiLineComment(trivia, position, commentIndentationString, leadingWhiteSpace, !indentNextTokenOrTrivia /* already indented first line */);
|
||||
indentNextTokenOrTrivia = false;
|
||||
leadingWhiteSpace = "";
|
||||
break;
|
||||
|
||||
case SyntaxKind.SingleLineCommentTrivia:
|
||||
case SyntaxKind.SkippedTokenTrivia:
|
||||
if (indentNextTokenOrTrivia) {
|
||||
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, position, commentIndentationString);
|
||||
indentNextTokenOrTrivia = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.WhitespaceTrivia:
|
||||
// If the next trivia is a comment, use the comment indentation level instead of the regular indentation level
|
||||
// If the next trivia is a newline, this whole line is just whitespace, so don't do anything (trimming will take care of it)
|
||||
var nextTrivia = length > i + 1 && triviaList.syntaxTriviaAt(i + 1);
|
||||
var whiteSpaceIndentationString = nextTrivia && nextTrivia.isComment() ? commentIndentationString : indentationString;
|
||||
if (indentNextTokenOrTrivia) {
|
||||
if (!(nextTrivia && nextTrivia.isNewLine())) {
|
||||
this.recordIndentationEditsForWhitespace(trivia, position, whiteSpaceIndentationString);
|
||||
}
|
||||
indentNextTokenOrTrivia = false;
|
||||
}
|
||||
leadingWhiteSpace += trivia.fullText();
|
||||
break;
|
||||
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
// We hit a newline processing the trivia. We need to add the indentation to the
|
||||
// next line as well. Note: don't bother indenting the newline itself. This will
|
||||
// just insert ugly whitespace that most users probably will not want.
|
||||
indentNextTokenOrTrivia = true;
|
||||
leadingWhiteSpace = "";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (token.kind() !== SyntaxKind.EndOfFileToken && indentNextTokenOrTrivia) {
|
||||
// If the last trivia item was a new line, or no trivia items were encounterd record the
|
||||
// indentation edit at the token position
|
||||
if (indentationString.length > 0) {
|
||||
this.recordEdit(position, 0, indentationString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private recordIndentationEditsForSingleLineOrSkippedText(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
|
||||
// Record the edit
|
||||
if (indentationString.length > 0) {
|
||||
this.recordEdit(fullStart, 0, indentationString);
|
||||
}
|
||||
}
|
||||
|
||||
private recordIndentationEditsForWhitespace(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
|
||||
var text = trivia.fullText();
|
||||
|
||||
// Check if the current indentation matches the desired indentation or not
|
||||
if (indentationString === text) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the edit
|
||||
this.recordEdit(fullStart, text.length, indentationString);
|
||||
}
|
||||
|
||||
private recordIndentationEditsForMultiLineComment(trivia: ISyntaxTrivia, fullStart: number, indentationString: string, leadingWhiteSpace: string, firstLineAlreadyIndented: boolean): void {
|
||||
// If the multiline comment spans multiple lines, we need to add the right indent amount to
|
||||
// each successive line segment as well.
|
||||
var position = fullStart;
|
||||
var segments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia);
|
||||
|
||||
if (segments.length <= 1) {
|
||||
if (!firstLineAlreadyIndented) {
|
||||
// Process the one-line multiline comment just like a single line comment
|
||||
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, fullStart, indentationString);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Find number of columns in first segment
|
||||
var whiteSpaceColumnsInFirstSegment = Indentation.columnForPositionInString(leadingWhiteSpace, leadingWhiteSpace.length, this.options);
|
||||
|
||||
var indentationColumns = Indentation.columnForPositionInString(indentationString, indentationString.length, this.options);
|
||||
var startIndex = 0;
|
||||
if (firstLineAlreadyIndented) {
|
||||
startIndex = 1;
|
||||
position += segments[0].length;
|
||||
}
|
||||
for (var i = startIndex; i < segments.length; i++) {
|
||||
var segment = segments[i];
|
||||
this.recordIndentationEditsForSegment(segment, position, indentationColumns, whiteSpaceColumnsInFirstSegment);
|
||||
position += segment.length;
|
||||
}
|
||||
}
|
||||
|
||||
private recordIndentationEditsForSegment(segment: string, fullStart: number, indentationColumns: number, whiteSpaceColumnsInFirstSegment: number): void {
|
||||
// Indent subsequent lines using a column delta of the actual indentation relative to the first line
|
||||
var firstNonWhitespacePosition = Indentation.firstNonWhitespacePosition(segment);
|
||||
var leadingWhiteSpaceColumns = Indentation.columnForPositionInString(segment, firstNonWhitespacePosition, this.options);
|
||||
var deltaFromFirstSegment = leadingWhiteSpaceColumns - whiteSpaceColumnsInFirstSegment;
|
||||
var finalColumns = indentationColumns + deltaFromFirstSegment;
|
||||
if (finalColumns < 0) {
|
||||
finalColumns = 0;
|
||||
}
|
||||
var indentationString = Indentation.indentationString(finalColumns, this.options);
|
||||
|
||||
if (firstNonWhitespacePosition < segment.length &&
|
||||
CharacterInfo.isLineTerminator(segment.charCodeAt(firstNonWhitespacePosition))) {
|
||||
// If this segment was just a newline, then don't bother indenting it. That will just
|
||||
// leave the user with an ugly indent in their output that they probably do not want.
|
||||
return;
|
||||
}
|
||||
|
||||
if (indentationString === segment.substring(0, firstNonWhitespacePosition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the edit
|
||||
this.recordEdit(fullStart, firstNonWhitespacePosition, indentationString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,11 +14,7 @@
|
||||
//
|
||||
|
||||
///<reference path='..\services.ts' />
|
||||
///<reference path='textSnapshot.ts' />
|
||||
///<reference path='textSnapshotLine.ts' />
|
||||
///<reference path='snapshotPoint.ts' />
|
||||
///<reference path='formattingContext.ts' />
|
||||
///<reference path='formattingManager.ts' />
|
||||
///<reference path='formattingRequestKind.ts' />
|
||||
///<reference path='rule.ts' />
|
||||
///<reference path='ruleAction.ts' />
|
||||
@ -28,12 +24,5 @@
|
||||
///<reference path='ruleOperationContext.ts' />
|
||||
///<reference path='rules.ts' />
|
||||
///<reference path='rulesMap.ts' />
|
||||
///<reference path='rulesProvider.ts' />
|
||||
///<reference path='textEditInfo.ts' />
|
||||
///<reference path='tokenRange.ts' />
|
||||
///<reference path='tokenSpan.ts' />
|
||||
///<reference path='indentationNodeContext.ts' />
|
||||
///<reference path='indentationNodeContextPool.ts' />
|
||||
///<reference path='indentationTrackingWalker.ts' />
|
||||
///<reference path='multipleTokenIndenter.ts' />
|
||||
///<reference path='formatter.ts' />
|
||||
///<reference path='tokenSpan.ts' />
|
||||
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class Rule {
|
||||
constructor(
|
||||
public Descriptor: RuleDescriptor,
|
||||
|
||||
@ -13,13 +13,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export enum RuleAction {
|
||||
Ignore,
|
||||
Space,
|
||||
NewLine,
|
||||
Delete
|
||||
module ts.formatting {
|
||||
export const enum RuleAction {
|
||||
Ignore = 0x00000001,
|
||||
Space = 0x00000002,
|
||||
NewLine = 0x00000004,
|
||||
Delete = 0x00000008
|
||||
}
|
||||
}
|
||||
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class RuleDescriptor {
|
||||
constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) {
|
||||
}
|
||||
@ -34,7 +34,6 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor
|
||||
//: this(TokenRange.FromToken(left), right)
|
||||
{
|
||||
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right);
|
||||
}
|
||||
|
||||
@ -13,10 +13,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export enum RuleFlags {
|
||||
module ts.formatting {
|
||||
export const enum RuleFlags {
|
||||
None,
|
||||
CanDeleteNewLines
|
||||
}
|
||||
|
||||
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class RuleOperation {
|
||||
public Context: RuleOperationContext;
|
||||
public Action: RuleAction;
|
||||
|
||||
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
|
||||
export class RuleOperationContext {
|
||||
private customContextChecks: { (context: FormattingContext): boolean; }[];
|
||||
|
||||
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class Rules {
|
||||
public getRuleName(rule: Rule) {
|
||||
var o: ts.Map<any> = <any>this;
|
||||
@ -241,7 +241,7 @@ module TypeScript.Services.Formatting {
|
||||
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
|
||||
|
||||
// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
|
||||
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.MultiLineCommentTrivia]);
|
||||
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia]);
|
||||
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
|
||||
|
||||
// Place a space before open brace in a control flow construct
|
||||
@ -299,7 +299,7 @@ module TypeScript.Services.Formatting {
|
||||
|
||||
// get x() {}
|
||||
// set x(val) {}
|
||||
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
|
||||
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
|
||||
|
||||
// Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
|
||||
this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
|
||||
@ -324,7 +324,7 @@ module TypeScript.Services.Formatting {
|
||||
this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
||||
|
||||
// Optional parameters and var args
|
||||
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
|
||||
|
||||
// generics
|
||||
@ -437,7 +437,7 @@ module TypeScript.Services.Formatting {
|
||||
///
|
||||
|
||||
static IsForContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ForStatement;
|
||||
return context.contextNode.kind === SyntaxKind.ForStatement;
|
||||
}
|
||||
|
||||
static IsNotForContext(context: FormattingContext): boolean {
|
||||
@ -446,51 +446,19 @@ module TypeScript.Services.Formatting {
|
||||
|
||||
static IsBinaryOpContext(context: FormattingContext): boolean {
|
||||
|
||||
switch (context.contextNode.kind()) {
|
||||
// binary expressions
|
||||
case SyntaxKind.AssignmentExpression:
|
||||
case SyntaxKind.AddAssignmentExpression:
|
||||
case SyntaxKind.SubtractAssignmentExpression:
|
||||
case SyntaxKind.MultiplyAssignmentExpression:
|
||||
case SyntaxKind.DivideAssignmentExpression:
|
||||
case SyntaxKind.ModuloAssignmentExpression:
|
||||
case SyntaxKind.AndAssignmentExpression:
|
||||
case SyntaxKind.ExclusiveOrAssignmentExpression:
|
||||
case SyntaxKind.OrAssignmentExpression:
|
||||
case SyntaxKind.LeftShiftAssignmentExpression:
|
||||
case SyntaxKind.SignedRightShiftAssignmentExpression:
|
||||
case SyntaxKind.UnsignedRightShiftAssignmentExpression:
|
||||
switch (context.contextNode.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
case SyntaxKind.LogicalOrExpression:
|
||||
case SyntaxKind.LogicalAndExpression:
|
||||
case SyntaxKind.BitwiseOrExpression:
|
||||
case SyntaxKind.BitwiseExclusiveOrExpression:
|
||||
case SyntaxKind.BitwiseAndExpression:
|
||||
case SyntaxKind.EqualsWithTypeConversionExpression:
|
||||
case SyntaxKind.NotEqualsWithTypeConversionExpression:
|
||||
case SyntaxKind.EqualsExpression:
|
||||
case SyntaxKind.NotEqualsExpression:
|
||||
case SyntaxKind.LessThanExpression:
|
||||
case SyntaxKind.GreaterThanExpression:
|
||||
case SyntaxKind.LessThanOrEqualExpression:
|
||||
case SyntaxKind.GreaterThanOrEqualExpression:
|
||||
case SyntaxKind.InstanceOfExpression:
|
||||
case SyntaxKind.InExpression:
|
||||
case SyntaxKind.LeftShiftExpression:
|
||||
case SyntaxKind.SignedRightShiftExpression:
|
||||
case SyntaxKind.UnsignedRightShiftExpression:
|
||||
case SyntaxKind.MultiplyExpression:
|
||||
case SyntaxKind.DivideExpression:
|
||||
case SyntaxKind.ModuloExpression:
|
||||
case SyntaxKind.AddExpression:
|
||||
case SyntaxKind.SubtractExpression:
|
||||
return true;
|
||||
|
||||
// equal in import a = module('a');
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
// equal in var a = 0;
|
||||
case SyntaxKind.VariableDeclarator:
|
||||
case SyntaxKind.EqualsValueClause:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
// equal in p = 0;
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.Property:
|
||||
return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
|
||||
// "in" keyword in for (var x in []) { }
|
||||
case SyntaxKind.ForInStatement:
|
||||
@ -546,16 +514,21 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
// IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children
|
||||
static NodeIsBlockContext(node: IndentationNodeContext): boolean {
|
||||
static NodeIsBlockContext(node: Node): boolean {
|
||||
if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) {
|
||||
// This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc).
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (node.kind()) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.ObjectLiteral:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
case SyntaxKind.FunctionBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -563,17 +536,20 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsFunctionDeclContext(context: FormattingContext): boolean {
|
||||
switch (context.contextNode.kind()) {
|
||||
switch (context.contextNode.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.Method:
|
||||
//case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.MethodSignature:
|
||||
///case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ConstructorDeclaration:
|
||||
case SyntaxKind.SimpleArrowFunctionExpression:
|
||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
//case SyntaxKind.ConstructorDeclaration:
|
||||
//case SyntaxKind.SimpleArrowFunctionExpression:
|
||||
//case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one
|
||||
return true;
|
||||
}
|
||||
@ -585,11 +561,12 @@ module TypeScript.Services.Formatting {
|
||||
return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode);
|
||||
}
|
||||
|
||||
static NodeIsTypeScriptDeclWithBlockContext(node: IndentationNodeContext): boolean {
|
||||
switch (node.kind()) {
|
||||
static NodeIsTypeScriptDeclWithBlockContext(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ObjectType:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return true;
|
||||
}
|
||||
@ -598,11 +575,16 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsAfterCodeBlockContext(context: FormattingContext): boolean {
|
||||
switch (context.currentTokenParent.kind()) {
|
||||
switch (context.currentTokenParent.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
case SyntaxKind.FunctionBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
return true;
|
||||
}
|
||||
@ -610,7 +592,7 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsControlDeclContext(context: FormattingContext): boolean {
|
||||
switch (context.contextNode.kind()) {
|
||||
switch (context.contextNode.kind) {
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
@ -619,9 +601,10 @@ module TypeScript.Services.Formatting {
|
||||
case SyntaxKind.TryStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.ElseClause:
|
||||
case SyntaxKind.CatchClause:
|
||||
case SyntaxKind.FinallyClause:
|
||||
// TODO
|
||||
// case SyntaxKind.ElseClause:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@ -630,15 +613,15 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsObjectContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ObjectLiteralExpression;
|
||||
return context.contextNode.kind === SyntaxKind.ObjectLiteral;
|
||||
}
|
||||
|
||||
static IsFunctionCallContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.InvocationExpression;
|
||||
return context.contextNode.kind === SyntaxKind.CallExpression;
|
||||
}
|
||||
|
||||
static IsNewContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ObjectCreationExpression;
|
||||
return context.contextNode.kind === SyntaxKind.NewExpression;
|
||||
}
|
||||
|
||||
static IsFunctionCallOrNewContext(context: FormattingContext): boolean {
|
||||
@ -654,25 +637,43 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsModuleDeclContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ModuleDeclaration;
|
||||
return context.contextNode.kind === SyntaxKind.ModuleDeclaration;
|
||||
}
|
||||
|
||||
static IsObjectTypeContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ObjectType && context.contextNode.parent().kind() !== SyntaxKind.InterfaceDeclaration;
|
||||
return context.contextNode.kind === SyntaxKind.TypeLiteral;// && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration;
|
||||
}
|
||||
|
||||
static IsTypeArgumentOrParameter(tokenKind: SyntaxKind, parentKind: SyntaxKind): boolean {
|
||||
return ((tokenKind === SyntaxKind.LessThanToken || tokenKind === SyntaxKind.GreaterThanToken) &&
|
||||
(parentKind === SyntaxKind.TypeParameterList || parentKind === SyntaxKind.TypeArgumentList));
|
||||
static IsTypeArgumentOrParameter(token: TextRangeWithKind, parent: Node): boolean {
|
||||
if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) {
|
||||
return false;
|
||||
}
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static IsTypeArgumentOrParameterContext(context: FormattingContext): boolean {
|
||||
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan.kind, context.currentTokenParent.kind()) ||
|
||||
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan.kind, context.nextTokenParent.kind());
|
||||
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan, context.currentTokenParent) ||
|
||||
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan, context.nextTokenParent);
|
||||
}
|
||||
|
||||
static IsVoidOpContext(context: FormattingContext): boolean {
|
||||
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind() === SyntaxKind.VoidExpression;
|
||||
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.PrefixOperator;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class RulesMap {
|
||||
public map: RulesBucket[];
|
||||
public mapRowLength: number;
|
||||
|
||||
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/// <reference path="formatting.ts"/>
|
||||
/// <reference path="references.ts"/>
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class RulesProvider {
|
||||
private globalRules: Rules;
|
||||
private options: ts.FormatCodeOptions;
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
|
||||
export class SnapshotPoint {
|
||||
constructor(public snapshot: ITextSnapshot, public position: number) {
|
||||
}
|
||||
public getContainingLine(): ITextSnapshotLine {
|
||||
return this.snapshot.getLineFromPosition(this.position);
|
||||
}
|
||||
public add(offset: number): SnapshotPoint {
|
||||
return new SnapshotPoint(this.snapshot, this.position + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class TextEditInfo {
|
||||
|
||||
constructor(public position: number, public length: number, public replaceWith: string) {
|
||||
}
|
||||
|
||||
public toString() {
|
||||
return "[ position: " + this.position + ", length: " + this.length + ", replaceWith: '" + this.replaceWith + "' ]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,89 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export interface ITextSnapshot {
|
||||
getLength(): number;
|
||||
getText(span: TextSpan): string;
|
||||
getLineNumberFromPosition(position: number): number;
|
||||
getLineFromPosition(position: number): ITextSnapshotLine;
|
||||
getLineFromLineNumber(lineNumber: number): ITextSnapshotLine;
|
||||
}
|
||||
|
||||
export class TextSnapshot implements ITextSnapshot {
|
||||
private lines: TextSnapshotLine[];
|
||||
|
||||
constructor(private snapshot: ISimpleText) {
|
||||
this.lines = [];
|
||||
}
|
||||
|
||||
public getLength(): number {
|
||||
return this.snapshot.length();
|
||||
}
|
||||
|
||||
public getText(span: TextSpan): string {
|
||||
return this.snapshot.substr(span.start(), span.length());
|
||||
}
|
||||
|
||||
public getLineNumberFromPosition(position: number): number {
|
||||
return this.snapshot.lineMap().getLineNumberFromPosition(position);
|
||||
}
|
||||
|
||||
public getLineFromPosition(position: number): ITextSnapshotLine {
|
||||
var lineNumber = this.getLineNumberFromPosition(position);
|
||||
return this.getLineFromLineNumber(lineNumber);
|
||||
}
|
||||
|
||||
public getLineFromLineNumber(lineNumber: number): ITextSnapshotLine {
|
||||
var line = this.lines[lineNumber];
|
||||
if (line === undefined) {
|
||||
line = <TextSnapshotLine>this.getLineFromLineNumberWorker(lineNumber);
|
||||
this.lines[lineNumber] = line;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private getLineFromLineNumberWorker(lineNumber: number): ITextSnapshotLine {
|
||||
var lineMap = this.snapshot.lineMap().lineStarts();
|
||||
var lineMapIndex = lineNumber; //Note: lineMap is 0-based
|
||||
if (lineMapIndex < 0 || lineMapIndex >= lineMap.length)
|
||||
throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Invalid_line_number_0, [lineMapIndex]));
|
||||
var start = lineMap[lineMapIndex];
|
||||
|
||||
var end: number;
|
||||
var endIncludingLineBreak: number;
|
||||
var lineBreak = "";
|
||||
if (lineMapIndex == lineMap.length) {
|
||||
end = endIncludingLineBreak = this.snapshot.length();
|
||||
}
|
||||
else {
|
||||
endIncludingLineBreak = (lineMapIndex >= lineMap.length - 1 ? this.snapshot.length() : lineMap[lineMapIndex + 1]);
|
||||
for (var p = endIncludingLineBreak - 1; p >= start; p--) {
|
||||
var c = this.snapshot.substr(p, 1);
|
||||
//TODO: Other ones?
|
||||
if (c != "\r" && c != "\n") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
end = p + 1;
|
||||
lineBreak = this.snapshot.substr(end, endIncludingLineBreak - end);
|
||||
}
|
||||
var result = new TextSnapshotLine(this, lineNumber, start, end, lineBreak);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export interface ITextSnapshotLine {
|
||||
snapshot(): ITextSnapshot;
|
||||
|
||||
start(): SnapshotPoint;
|
||||
startPosition(): number;
|
||||
|
||||
end(): SnapshotPoint;
|
||||
endPosition(): number;
|
||||
|
||||
endIncludingLineBreak(): SnapshotPoint;
|
||||
endIncludingLineBreakPosition(): number;
|
||||
|
||||
length(): number;
|
||||
lineNumber(): number;
|
||||
getText(): string;
|
||||
}
|
||||
|
||||
export class TextSnapshotLine implements ITextSnapshotLine {
|
||||
constructor(private _snapshot: ITextSnapshot, private _lineNumber: number, private _start: number, private _end: number, private _lineBreak: string) {
|
||||
}
|
||||
|
||||
public snapshot() {
|
||||
return this._snapshot;
|
||||
}
|
||||
|
||||
public start() {
|
||||
return new SnapshotPoint(this._snapshot, this._start);
|
||||
}
|
||||
|
||||
public startPosition() {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
public end() {
|
||||
return new SnapshotPoint(this._snapshot, this._end);
|
||||
}
|
||||
|
||||
public endPosition() {
|
||||
return this._end;
|
||||
}
|
||||
|
||||
public endIncludingLineBreak() {
|
||||
return new SnapshotPoint(this._snapshot, this._end + this._lineBreak.length);
|
||||
}
|
||||
|
||||
public endIncludingLineBreakPosition() {
|
||||
return this._end + this._lineBreak.length;
|
||||
}
|
||||
|
||||
public length() {
|
||||
return this._end - this._start;
|
||||
}
|
||||
|
||||
public lineNumber() {
|
||||
return this._lineNumber;
|
||||
}
|
||||
|
||||
public getText(): string {
|
||||
return this._snapshot.getText(TextSpan.fromBounds(this._start, this._end));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export module Shared {
|
||||
export interface ITokenAccess {
|
||||
GetTokens(): SyntaxKind[];
|
||||
@ -41,12 +41,6 @@ module TypeScript.Services.Formatting {
|
||||
public Contains(token: SyntaxKind): boolean {
|
||||
return this.tokens.indexOf(token) >= 0;
|
||||
}
|
||||
|
||||
|
||||
public toString(): string {
|
||||
return "[tokenRangeStart=" + SyntaxKind[this.tokens[0]] + "," +
|
||||
"tokenRangeEnd=" + SyntaxKind[this.tokens[this.tokens.length - 1]] + "]";
|
||||
}
|
||||
}
|
||||
|
||||
export class TokenValuesAccess implements ITokenAccess {
|
||||
@ -76,10 +70,6 @@ module TypeScript.Services.Formatting {
|
||||
public Contains(tokenValue: SyntaxKind): boolean {
|
||||
return tokenValue == this.token;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return "[singleTokenKind=" + SyntaxKind[this.token] + "]";
|
||||
}
|
||||
}
|
||||
|
||||
export class TokenAllAccess implements ITokenAccess {
|
||||
@ -135,18 +125,18 @@ module TypeScript.Services.Formatting {
|
||||
static Any: TokenRange = TokenRange.AllTokens();
|
||||
static AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([SyntaxKind.MultiLineCommentTrivia]));
|
||||
static Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword);
|
||||
static Operators = TokenRange.FromRange(SyntaxKind.SemicolonToken, SyntaxKind.SlashEqualsToken);
|
||||
static BinaryOperators = TokenRange.FromRange(SyntaxKind.LessThanToken, SyntaxKind.SlashEqualsToken);
|
||||
static Operators = TokenRange.FromRange(SyntaxKind.FirstOperator, SyntaxKind.LastOperator);
|
||||
static BinaryOperators = TokenRange.FromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator);
|
||||
static BinaryKeywordOperators = TokenRange.FromTokens([SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword]);
|
||||
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedStrictKeyword, SyntaxKind.LastFutureReservedStrictKeyword);
|
||||
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedWord, SyntaxKind.LastFutureReservedWord);
|
||||
static UnaryPrefixOperators = TokenRange.FromTokens([SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]);
|
||||
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
static Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]);
|
||||
static TypeNames = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
|
||||
static TypeNames = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13,11 +13,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class TokenSpan extends TextSpan {
|
||||
module ts.formatting {
|
||||
export class TokenSpan extends TypeScript.TextSpan {
|
||||
constructor(public kind: SyntaxKind, start: number, length: number) {
|
||||
super(start, length);
|
||||
}
|
||||
|
||||
@ -1,154 +0,0 @@
|
||||
|
||||
module TypeScript.Indentation {
|
||||
export function columnForEndOfTokenAtPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
|
||||
var token = findToken(syntaxTree.sourceUnit(), position);
|
||||
return columnForStartOfTokenAtPosition(syntaxTree, position, options) + width(token);
|
||||
}
|
||||
|
||||
export function columnForStartOfTokenAtPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
|
||||
var token = findToken(syntaxTree.sourceUnit(), position);
|
||||
|
||||
// Walk backward from this token until we find the first token in the line. For each token
|
||||
// we see (that is not the first tokem in line), push the entirety of the text into the text
|
||||
// array. Then, for the first token, add its text (without its leading trivia) to the text
|
||||
// array. i.e. if we have:
|
||||
//
|
||||
// var foo = a => bar();
|
||||
//
|
||||
// And we want the column for the start of 'bar', then we'll add the underlinded portions to
|
||||
// the text array:
|
||||
//
|
||||
// var foo = a => bar();
|
||||
// _
|
||||
// __
|
||||
// __
|
||||
// ____
|
||||
// ____
|
||||
var firstTokenInLine = Syntax.firstTokenInLineContainingPosition(syntaxTree, token.fullStart());
|
||||
var leadingTextInReverse: string[] = [];
|
||||
|
||||
var current = token;
|
||||
while (current !== firstTokenInLine) {
|
||||
current = previousToken(current);
|
||||
|
||||
if (current === firstTokenInLine) {
|
||||
// We're at the first token in teh line.
|
||||
// We don't want the leading trivia for this token. That will be taken care of in
|
||||
// columnForFirstNonWhitespaceCharacterInLine. So just push the trailing trivia
|
||||
// and then the token text.
|
||||
leadingTextInReverse.push(current.trailingTrivia().fullText());
|
||||
leadingTextInReverse.push(current.text());
|
||||
}
|
||||
else {
|
||||
// We're at an intermediate token on the line. Just push all its text into the array.
|
||||
leadingTextInReverse.push(current.fullText());
|
||||
}
|
||||
}
|
||||
|
||||
// Now, add all trivia to the start of the line on the first token in the list.
|
||||
collectLeadingTriviaTextToStartOfLine(firstTokenInLine, leadingTextInReverse);
|
||||
|
||||
return columnForLeadingTextInReverse(leadingTextInReverse, options);
|
||||
}
|
||||
|
||||
export function columnForStartOfFirstTokenInLineContainingPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
|
||||
// Walk backward through the tokens until we find the first one on the line.
|
||||
var firstTokenInLine = Syntax.firstTokenInLineContainingPosition(syntaxTree, position);
|
||||
var leadingTextInReverse: string[] = [];
|
||||
|
||||
// Now, add all trivia to the start of the line on the first token in the list.
|
||||
collectLeadingTriviaTextToStartOfLine(firstTokenInLine, leadingTextInReverse);
|
||||
|
||||
return columnForLeadingTextInReverse(leadingTextInReverse, options);
|
||||
}
|
||||
|
||||
// Collect all the trivia that precedes this token. Stopping when we hit a newline trivia
|
||||
// or a multiline comment that spans multiple lines. This is meant to be called on the first
|
||||
// token in a line.
|
||||
function collectLeadingTriviaTextToStartOfLine(firstTokenInLine: ISyntaxToken,
|
||||
leadingTextInReverse: string[]) {
|
||||
var leadingTrivia = firstTokenInLine.leadingTrivia();
|
||||
|
||||
for (var i = leadingTrivia.count() - 1; i >= 0; i--) {
|
||||
var trivia = leadingTrivia.syntaxTriviaAt(i);
|
||||
if (trivia.kind() === SyntaxKind.NewLineTrivia) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (trivia.kind() === SyntaxKind.MultiLineCommentTrivia) {
|
||||
var lineSegments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia);
|
||||
leadingTextInReverse.push(ArrayUtilities.last(lineSegments));
|
||||
|
||||
if (lineSegments.length > 0) {
|
||||
// This multiline comment actually spanned multiple lines. So we're done.
|
||||
break;
|
||||
}
|
||||
|
||||
// It was only on a single line, so keep on going.
|
||||
}
|
||||
|
||||
leadingTextInReverse.push(trivia.fullText());
|
||||
}
|
||||
}
|
||||
|
||||
function columnForLeadingTextInReverse(leadingTextInReverse: string[],
|
||||
options: FormattingOptions): number {
|
||||
var column = 0;
|
||||
|
||||
// walk backwards. This means we're actually walking forward from column 0 to the start of
|
||||
// the token.
|
||||
for (var i = leadingTextInReverse.length - 1; i >= 0; i--) {
|
||||
var text = leadingTextInReverse[i];
|
||||
column = columnForPositionInStringWorker(text, text.length, column, options);
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
|
||||
// Returns the column that this input string ends at (assuming it starts at column 0).
|
||||
export function columnForPositionInString(input: string, position: number, options: FormattingOptions): number {
|
||||
return columnForPositionInStringWorker(input, position, 0, options);
|
||||
}
|
||||
|
||||
function columnForPositionInStringWorker(input: string, position: number, startColumn: number, options: FormattingOptions): number {
|
||||
var column = startColumn;
|
||||
var spacesPerTab = options.spacesPerTab;
|
||||
|
||||
for (var j = 0; j < position; j++) {
|
||||
var ch = input.charCodeAt(j);
|
||||
|
||||
if (ch === CharacterCodes.tab) {
|
||||
column += spacesPerTab - column % spacesPerTab;
|
||||
}
|
||||
else {
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
|
||||
export function indentationString(column: number, options: FormattingOptions): string {
|
||||
var numberOfTabs = 0;
|
||||
var numberOfSpaces = Math.max(0, column);
|
||||
|
||||
if (options.useTabs) {
|
||||
numberOfTabs = Math.floor(column / options.spacesPerTab);
|
||||
numberOfSpaces -= numberOfTabs * options.spacesPerTab;
|
||||
}
|
||||
|
||||
return StringUtilities.repeat('\t', numberOfTabs) +
|
||||
StringUtilities.repeat(' ', numberOfSpaces);
|
||||
}
|
||||
|
||||
export function firstNonWhitespacePosition(value: string): number {
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
var ch = value.charCodeAt(i);
|
||||
if (!CharacterInfo.isWhitespace(ch)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return value.length;
|
||||
}
|
||||
}
|
||||
@ -73,13 +73,14 @@ module ts.NavigationBar {
|
||||
function sortNodes(nodes: Node[]): Node[] {
|
||||
return nodes.slice(0).sort((n1: Declaration, n2: Declaration) => {
|
||||
if (n1.name && n2.name) {
|
||||
return n1.name.text.localeCompare(n2.name.text);
|
||||
// TODO(jfreeman): How do we sort declarations with computed names?
|
||||
return (<Identifier>n1.name).text.localeCompare((<Identifier>n2.name).text);
|
||||
}
|
||||
else if (n1.name) {
|
||||
return 1;
|
||||
}
|
||||
else if (n2.name) {
|
||||
-1;
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
return n1.kind - n2.kind;
|
||||
@ -106,7 +107,7 @@ module ts.NavigationBar {
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
var functionDeclaration = <FunctionDeclaration>node;
|
||||
var functionDeclaration = <FunctionLikeDeclaration>node;
|
||||
if (isTopLevelFunctionDeclaration(functionDeclaration)) {
|
||||
topLevelNodes.push(node);
|
||||
addTopLevelNodes((<Block>functionDeclaration.body).statements, topLevelNodes);
|
||||
@ -116,11 +117,12 @@ module ts.NavigationBar {
|
||||
}
|
||||
}
|
||||
|
||||
function isTopLevelFunctionDeclaration(functionDeclaration: FunctionDeclaration) {
|
||||
function isTopLevelFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration) {
|
||||
if (functionDeclaration.kind === SyntaxKind.FunctionDeclaration) {
|
||||
// A function declaration is 'top level' if it contains any function declarations
|
||||
// within it.
|
||||
if (functionDeclaration.body && functionDeclaration.body.kind === SyntaxKind.FunctionBlock) {
|
||||
// Proper function declarations can only have identifier names
|
||||
if (forEach((<Block>functionDeclaration.body).statements,
|
||||
s => s.kind === SyntaxKind.FunctionDeclaration && !isEmpty((<FunctionDeclaration>s).name.text))) {
|
||||
|
||||
@ -230,7 +232,7 @@ module ts.NavigationBar {
|
||||
return createItem(node, getTextOfNode((<PropertyDeclaration>node).name), ts.ScriptElementKind.memberVariableElement);
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return createItem(node, getTextOfNode((<FunctionDeclaration>node).name), ts.ScriptElementKind.functionElement);
|
||||
return createItem(node, getTextOfNode((<FunctionLikeDeclaration>node).name), ts.ScriptElementKind.functionElement);
|
||||
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
if (node.flags & NodeFlags.Const) {
|
||||
@ -371,8 +373,10 @@ module ts.NavigationBar {
|
||||
});
|
||||
|
||||
// Add the constructor parameters in as children of the class (for property parameters).
|
||||
// Note that *all* parameters will be added to the nodes array, but parameters that
|
||||
// are not properties will be filtered out later by createChildItem.
|
||||
var nodes: Node[] = constructor
|
||||
? constructor.parameters.concat(node.members)
|
||||
? node.members.concat(constructor.parameters)
|
||||
: node.members;
|
||||
|
||||
var childItems = getItemsWorker(sortNodes(nodes), createChildItem);
|
||||
|
||||
@ -13,7 +13,6 @@ module TypeScript {
|
||||
Automatic_semicolon_insertion_not_allowed: "Automatic semicolon insertion not allowed.",
|
||||
Unexpected_token_0_expected: "Unexpected token; '{0}' expected.",
|
||||
Trailing_comma_not_allowed: "Trailing comma not allowed.",
|
||||
AsteriskSlash_expected: "'*/' expected.",
|
||||
public_or_private_modifier_must_precede_static: "'public' or 'private' modifier must precede 'static'.",
|
||||
Unexpected_token: "Unexpected token.",
|
||||
Catch_clause_parameter_cannot_have_a_type_annotation: "Catch clause parameter cannot have a type annotation.",
|
||||
@ -95,6 +94,9 @@ module TypeScript {
|
||||
return_statement_must_be_contained_within_a_function_body: "'return' statement must be contained within a function body.",
|
||||
Expression_expected: "Expression expected.",
|
||||
Type_expected: "Type expected.",
|
||||
Template_literal_cannot_be_used_as_an_element_name: "Template literal cannot be used as an element name.",
|
||||
Computed_property_names_cannot_be_used_here: "Computed property names cannot be used here.",
|
||||
yield_expression_must_be_contained_within_a_generator_declaration: "'yield' expression must be contained within a generator declaration.",
|
||||
Duplicate_identifier_0: "Duplicate identifier '{0}'.",
|
||||
The_name_0_does_not_exist_in_the_current_scope: "The name '{0}' does not exist in the current scope.",
|
||||
The_name_0_does_not_refer_to_a_value: "The name '{0}' does not refer to a value.",
|
||||
|
||||
@ -96,6 +96,9 @@ module TypeScript {
|
||||
"'return' statement must be contained within a function body.": { "code": 1108, "category": DiagnosticCategory.Error },
|
||||
"Expression expected.": { "code": 1109, "category": DiagnosticCategory.Error },
|
||||
"Type expected.": { "code": 1110, "category": DiagnosticCategory.Error },
|
||||
"Template literal cannot be used as an element name.": { "code": 1111, "category": DiagnosticCategory.Error },
|
||||
"Computed property names cannot be used here.": { "code": 1112, "category": DiagnosticCategory.Error },
|
||||
"'yield' expression must be contained within a generator declaration.": { "code": 1113, "category": DiagnosticCategory.Error },
|
||||
"Duplicate identifier '{0}'.": { "code": 2000, "category": DiagnosticCategory.Error },
|
||||
"The name '{0}' does not exist in the current scope.": { "code": 2001, "category": DiagnosticCategory.Error },
|
||||
"The name '{0}' does not refer to a value.": { "code": 2002, "category": DiagnosticCategory.Error },
|
||||
|
||||
@ -47,10 +47,6 @@
|
||||
"category": "Error",
|
||||
"code": 1009
|
||||
},
|
||||
"'*/' expected.": {
|
||||
"category": "Error",
|
||||
"code": 1010
|
||||
},
|
||||
"'public' or 'private' modifier must precede 'static'.": {
|
||||
"category": "Error",
|
||||
"code": 1011
|
||||
@ -375,6 +371,18 @@
|
||||
"category": "Error",
|
||||
"code": 1110
|
||||
},
|
||||
"Template literal cannot be used as an element name.": {
|
||||
"category": "Error",
|
||||
"code": 1111
|
||||
},
|
||||
"Computed property names cannot be used here.": {
|
||||
"category": "Error",
|
||||
"code": 1112
|
||||
},
|
||||
"'yield' expression must be contained within a generator declaration.": {
|
||||
"category": "Error",
|
||||
"code": 1113
|
||||
},
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2000
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,6 @@
|
||||
/// <reference path='services.ts' />
|
||||
|
||||
/// <reference path='compiler\pathUtils.ts' />
|
||||
/// <reference path='compiler\precompile.ts' />
|
||||
|
||||
var debugObjectHost = (<any>this);
|
||||
|
||||
@ -55,6 +54,17 @@ module ts {
|
||||
getDefaultLibFilename(): string;
|
||||
}
|
||||
|
||||
///
|
||||
/// Pre-processing
|
||||
///
|
||||
// Note: This is being using by the host (VS) and is marshaled back and forth.
|
||||
// When changing this make sure the changes are reflected in the managed side as well
|
||||
export interface IFileReference {
|
||||
path: string;
|
||||
position: number;
|
||||
length: number;
|
||||
}
|
||||
|
||||
/** Public interface of a language service instance shim. */
|
||||
export interface ShimFactory {
|
||||
registerShim(shim: Shim): void;
|
||||
@ -171,13 +181,13 @@ module ts {
|
||||
}
|
||||
|
||||
/// TODO: delete this, it is only needed until the VS interface is updated
|
||||
export enum LanguageVersion {
|
||||
export const enum LanguageVersion {
|
||||
EcmaScript3 = 0,
|
||||
EcmaScript5 = 1,
|
||||
EcmaScript6 = 2,
|
||||
}
|
||||
|
||||
export enum ModuleGenTarget {
|
||||
export const enum ModuleGenTarget {
|
||||
Unspecified = 0,
|
||||
Synchronous = 1,
|
||||
Asynchronous = 2,
|
||||
@ -507,17 +517,6 @@ module ts {
|
||||
};
|
||||
}
|
||||
|
||||
private realizeDiagnosticWithFileName(diagnostic: Diagnostic): { fileName: string; message: string; start: number; length: number; category: string; } {
|
||||
return {
|
||||
fileName: diagnostic.file.filename,
|
||||
message: diagnostic.messageText,
|
||||
start: diagnostic.start,
|
||||
length: diagnostic.length,
|
||||
/// TODO: no need for the tolowerCase call
|
||||
category: DiagnosticCategory[diagnostic.category].toLowerCase()
|
||||
};
|
||||
}
|
||||
|
||||
public getSyntacticClassifications(fileName: string, start: number, length: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
@ -559,7 +558,7 @@ module ts {
|
||||
"getCompilerOptionsDiagnostics()",
|
||||
() => {
|
||||
var errors = this.languageService.getCompilerOptionsDiagnostics();
|
||||
return errors.map(d => this.realizeDiagnosticWithFileName(d))
|
||||
return errors.map(LanguageServiceShimObject.realizeDiagnostic)
|
||||
});
|
||||
}
|
||||
|
||||
@ -846,12 +845,33 @@ module ts {
|
||||
return forwardJSONCall(this.logger, actionDescription, action);
|
||||
}
|
||||
|
||||
public getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string {
|
||||
public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: TypeScript.IScriptSnapshot): string {
|
||||
return this.forwardJSONCall(
|
||||
"getPreProcessedFileInfo('" + fileName + "')",
|
||||
() => {
|
||||
var result = TypeScript.preProcessFile(fileName, sourceText);
|
||||
return result;
|
||||
var result = preProcessFile(sourceTextSnapshot.getText(0, sourceTextSnapshot.getLength()));
|
||||
var convertResult = {
|
||||
referencedFiles: <IFileReference[]>[],
|
||||
importedFiles: <IFileReference[]>[],
|
||||
isLibFile: result.isLibFile
|
||||
};
|
||||
|
||||
forEach(result.referencedFiles, refFile => {
|
||||
convertResult.referencedFiles.push({
|
||||
path: normalizePath(refFile.filename),
|
||||
position: refFile.pos,
|
||||
length: refFile.end - refFile.pos
|
||||
});
|
||||
});
|
||||
|
||||
forEach(result.importedFiles, importedFile => {
|
||||
convertResult.importedFiles.push({
|
||||
path: normalizeSlashes(importedFile.filename),
|
||||
position: importedFile.pos,
|
||||
length: importedFile.end - importedFile.pos
|
||||
});
|
||||
});
|
||||
return convertResult;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -219,19 +219,19 @@ module ts.SignatureHelp {
|
||||
// Find the list that starts right *after* the < or ( token.
|
||||
// If the user has just opened a list, consider this item 0.
|
||||
var list = getChildListThatStartsWithOpenerToken(parent, node, sourceFile);
|
||||
Debug.assert(list);
|
||||
Debug.assert(list !== undefined);
|
||||
return {
|
||||
list: list,
|
||||
listItemIndex: 0
|
||||
};
|
||||
}
|
||||
|
||||
if (node.kind === SyntaxKind.GreaterThanToken
|
||||
|| node.kind === SyntaxKind.CloseParenToken
|
||||
|| node === parent.func) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// findListItemInfo can return undefined if we are not in parent's argument list
|
||||
// or type argument list. This includes cases where the cursor is:
|
||||
// - To the right of the closing paren
|
||||
// - Between the type arguments and the arguments (greater than token)
|
||||
// - On the target of the call (parent.func)
|
||||
// - On the 'new' keyword in a 'new' expression
|
||||
return findListItemInfo(node);
|
||||
}
|
||||
|
||||
@ -244,7 +244,7 @@ module ts.SignatureHelp {
|
||||
// If the node is not a subspan of its parent, this is a big problem.
|
||||
// There have been crashes that might be caused by this violation.
|
||||
if (n.pos < n.parent.pos || n.end > n.parent.end) {
|
||||
Debug.fail("Node of kind " + SyntaxKind[n.kind] + " is not a subspan of its parent of kind " + SyntaxKind[n.parent.kind]);
|
||||
Debug.fail("Node of kind " + n.kind + " is not a subspan of its parent of kind " + n.parent.kind);
|
||||
}
|
||||
|
||||
var argumentInfo = getImmediatelyContainingArgumentInfo(n);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
///<reference path='..\services.ts' />
|
||||
///<reference path='services.ts' />
|
||||
|
||||
module ts.formatting {
|
||||
export module SmartIndenter {
|
||||
export function getIndentation(position: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
export function getIndentation(position: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
if (position > sourceFile.text.length) {
|
||||
return 0; // past EOF
|
||||
}
|
||||
@ -13,8 +13,8 @@ module ts.formatting {
|
||||
}
|
||||
|
||||
// no indentation in string \regex literals
|
||||
if ((precedingToken.kind === SyntaxKind.StringLiteral || precedingToken.kind === SyntaxKind.RegularExpressionLiteral) &&
|
||||
precedingToken.getStart(sourceFile) <= position &&
|
||||
if ((precedingToken.kind === SyntaxKind.StringLiteral || precedingToken.kind === SyntaxKind.RegularExpressionLiteral) &&
|
||||
precedingToken.getStart(sourceFile) <= position &&
|
||||
precedingToken.end > position) {
|
||||
return 0;
|
||||
}
|
||||
@ -37,14 +37,14 @@ module ts.formatting {
|
||||
var indentationDelta: number;
|
||||
|
||||
while (current) {
|
||||
if (positionBelongsToNode(current, position, sourceFile) && nodeContentIsIndented(current, previous)) {
|
||||
if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(current.kind, previous ? previous.kind : SyntaxKind.Unknown)) {
|
||||
currentStart = getStartLineAndCharacterForNode(current, sourceFile);
|
||||
|
||||
if (nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile)) {
|
||||
indentationDelta = 0;
|
||||
}
|
||||
else {
|
||||
indentationDelta = lineAtPosition !== currentStart.line ? options.indentSpaces : 0;
|
||||
indentationDelta = lineAtPosition !== currentStart.line ? options.IndentSize : 0;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -59,12 +59,27 @@ module ts.formatting {
|
||||
previous = current;
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
|
||||
if (!current) {
|
||||
// no parent was found - return 0 to be indented on the level of SourceFile
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getIndentationForNodeWorker(current, currentStart, /*ignoreActualIndentationRange*/ undefined, indentationDelta, sourceFile, options);
|
||||
}
|
||||
|
||||
export function getIndentationForNode(n: Node, ignoreActualIndentationRange: TextRange, sourceFile: SourceFile, options: FormatCodeOptions): number {
|
||||
var start = sourceFile.getLineAndCharacterFromPosition(n.getStart(sourceFile));
|
||||
return getIndentationForNodeWorker(n, start, ignoreActualIndentationRange, /*indentationDelta*/ 0, sourceFile, options);
|
||||
}
|
||||
|
||||
function getIndentationForNodeWorker(
|
||||
current: Node,
|
||||
currentStart: LineAndCharacter,
|
||||
ignoreActualIndentationRange: TextRange,
|
||||
indentationDelta: number,
|
||||
sourceFile: SourceFile,
|
||||
options: EditorOptions): number {
|
||||
|
||||
var parent: Node = current.parent;
|
||||
var parentStart: LineAndCharacter;
|
||||
@ -72,26 +87,35 @@ module ts.formatting {
|
||||
// walk upwards and collect indentations for pairs of parent-child nodes
|
||||
// indentation is not added if parent and child nodes start on the same line or if parent is IfStatement and child starts on the same line with 'else clause'
|
||||
while (parent) {
|
||||
// check if current node is a list item - if yes, take indentation from it
|
||||
var actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
|
||||
if (actualIndentation !== -1) {
|
||||
return actualIndentation + indentationDelta;
|
||||
var useActualIndentation = true;
|
||||
if (ignoreActualIndentationRange) {
|
||||
var start = current.getStart(sourceFile);
|
||||
useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end;
|
||||
}
|
||||
|
||||
parentStart = sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile));
|
||||
var parentAndChildShareLine =
|
||||
parentStart.line === currentStart.line ||
|
||||
if (useActualIndentation) {
|
||||
// check if current node is a list item - if yes, take indentation from it
|
||||
var actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
|
||||
if (actualIndentation !== -1) {
|
||||
return actualIndentation + indentationDelta;
|
||||
}
|
||||
}
|
||||
parentStart = getParentStart(parent, current, sourceFile);
|
||||
var parentAndChildShareLine =
|
||||
parentStart.line === currentStart.line ||
|
||||
childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile);
|
||||
|
||||
// try to fetch actual indentation for current node from source text
|
||||
var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
|
||||
if (actualIndentation !== -1) {
|
||||
return actualIndentation + indentationDelta;
|
||||
if (useActualIndentation) {
|
||||
// try to fetch actual indentation for current node from source text
|
||||
var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
|
||||
if (actualIndentation !== -1) {
|
||||
return actualIndentation + indentationDelta;
|
||||
}
|
||||
}
|
||||
|
||||
// increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line
|
||||
if (nodeContentIsIndented(parent, current) && !parentAndChildShareLine) {
|
||||
indentationDelta += options.indentSpaces;
|
||||
if (shouldIndentChildNode(parent.kind, current.kind) && !parentAndChildShareLine) {
|
||||
indentationDelta += options.IndentSize;
|
||||
}
|
||||
|
||||
current = parent;
|
||||
@ -102,13 +126,23 @@ module ts.formatting {
|
||||
return indentationDelta;
|
||||
}
|
||||
|
||||
|
||||
function getParentStart(parent: Node, child: Node, sourceFile: SourceFile): LineAndCharacter {
|
||||
var containingList = getContainingList(child, sourceFile);
|
||||
if (containingList) {
|
||||
return sourceFile.getLineAndCharacterFromPosition(containingList.pos);
|
||||
}
|
||||
|
||||
return sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile));
|
||||
}
|
||||
|
||||
/*
|
||||
* Function returns -1 if indentation cannot be determined
|
||||
*/
|
||||
function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
*/
|
||||
function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
// previous token is comma that separates items in list - find the previous item and try to derive indentation from it
|
||||
var commaItemInfo = findListItemInfo(commaToken);
|
||||
Debug.assert(commaItemInfo.listItemIndex > 0);
|
||||
Debug.assert(commaItemInfo && commaItemInfo.listItemIndex > 0);
|
||||
// The item we're interested in is right before the comma
|
||||
return deriveActualIndentationFromList(commaItemInfo.list.getChildren(), commaItemInfo.listItemIndex - 1, sourceFile, options);
|
||||
}
|
||||
@ -116,20 +150,20 @@ module ts.formatting {
|
||||
/*
|
||||
* Function returns -1 if actual indentation for node should not be used (i.e because node is nested expression)
|
||||
*/
|
||||
function getActualIndentationForNode(current: Node,
|
||||
parent: Node,
|
||||
currentLineAndChar: LineAndCharacter,
|
||||
parentAndChildShareLine: boolean,
|
||||
sourceFile: SourceFile,
|
||||
options: TypeScript.FormattingOptions): number {
|
||||
function getActualIndentationForNode(current: Node,
|
||||
parent: Node,
|
||||
currentLineAndChar: LineAndCharacter,
|
||||
parentAndChildShareLine: boolean,
|
||||
sourceFile: SourceFile,
|
||||
options: EditorOptions): number {
|
||||
|
||||
// actual indentation is used for statements\declarations if one of cases below is true:
|
||||
// - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually
|
||||
// - parent and child are not on the same line
|
||||
var useActualIndentation =
|
||||
var useActualIndentation =
|
||||
(isDeclaration(current) || isStatement(current)) &&
|
||||
(parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine);
|
||||
|
||||
|
||||
if (!useActualIndentation) {
|
||||
return -1;
|
||||
}
|
||||
@ -142,7 +176,7 @@ module ts.formatting {
|
||||
if (!nextToken) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (nextToken.kind === SyntaxKind.OpenBraceToken) {
|
||||
// open braces are always indented at the parent level
|
||||
return true;
|
||||
@ -172,30 +206,30 @@ module ts.formatting {
|
||||
return candidate.end > position || !isCompletedNode(candidate, sourceFile);
|
||||
}
|
||||
|
||||
function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: Node, childStartLine: number, sourceFile: SourceFile): boolean {
|
||||
export function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFile): boolean {
|
||||
if (parent.kind === SyntaxKind.IfStatement && (<IfStatement>parent).elseStatement === child) {
|
||||
var elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile);
|
||||
Debug.assert(elseKeyword);
|
||||
Debug.assert(elseKeyword !== undefined);
|
||||
|
||||
var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line;
|
||||
var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line;
|
||||
return elseKeywordStartLine === childStartLine;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
function getContainingList(node: Node, sourceFile: SourceFile): NodeArray<Node> {
|
||||
if (node.parent) {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
if ((<TypeReferenceNode>node.parent).typeArguments) {
|
||||
return getActualIndentationFromList((<TypeReferenceNode>node.parent).typeArguments);
|
||||
return (<TypeReferenceNode>node.parent).typeArguments;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ObjectLiteral:
|
||||
return getActualIndentationFromList((<ObjectLiteral>node.parent).properties);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return getActualIndentationFromList((<TypeLiteralNode>node.parent).members);
|
||||
return (<ObjectLiteral>node.parent).properties;
|
||||
case SyntaxKind.ArrayLiteral:
|
||||
return getActualIndentationFromList((<ArrayLiteral>node.parent).elements);
|
||||
return (<ArrayLiteral>node.parent).elements;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
@ -203,21 +237,26 @@ module ts.formatting {
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
if ((<SignatureDeclaration>node.parent).typeParameters && node.end < (<SignatureDeclaration>node.parent).typeParameters.end) {
|
||||
return getActualIndentationFromList((<SignatureDeclaration>node.parent).typeParameters);
|
||||
return (<SignatureDeclaration>node.parent).typeParameters;
|
||||
}
|
||||
|
||||
return getActualIndentationFromList((<SignatureDeclaration>node.parent).parameters);
|
||||
|
||||
return (<SignatureDeclaration>node.parent).parameters;
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.CallExpression:
|
||||
if ((<CallExpression>node.parent).typeArguments && node.end < (<CallExpression>node.parent).typeArguments.end) {
|
||||
return getActualIndentationFromList((<CallExpression>node.parent).typeArguments);
|
||||
return (<CallExpression>node.parent).typeArguments;
|
||||
}
|
||||
|
||||
return getActualIndentationFromList((<CallExpression>node.parent).arguments);
|
||||
|
||||
return (<CallExpression>node.parent).arguments;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
var containingList = getContainingList(node, sourceFile);
|
||||
return containingList ? getActualIndentationFromList(containingList) : -1;
|
||||
|
||||
function getActualIndentationFromList(list: Node[]): number {
|
||||
var index = indexOf(list, node);
|
||||
@ -226,13 +265,13 @@ module ts.formatting {
|
||||
}
|
||||
|
||||
|
||||
function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
Debug.assert(index >= 0 && index < list.length);
|
||||
var node = list[index];
|
||||
|
||||
// walk toward the start of the list starting from current node and check if the line is the same for all items.
|
||||
// if end line for item [i - 1] differs from the start line for item [i] - find column of the first non-whitespace character on the line of item [i]
|
||||
var lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile);
|
||||
var lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile);
|
||||
for (var i = index - 1; i >= 0; --i) {
|
||||
if (list[i].kind === SyntaxKind.CommaToken) {
|
||||
continue;
|
||||
@ -248,53 +287,34 @@ module ts.formatting {
|
||||
return -1;
|
||||
}
|
||||
|
||||
function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
var lineStart = sourceFile.getPositionFromLineAndCharacter(lineAndCharacter.line, 1);
|
||||
return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options);
|
||||
}
|
||||
|
||||
export function findFirstNonWhitespaceColumn(startPos: number, endPos: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
var column = 0;
|
||||
for (var i = 0; i < lineAndCharacter.character; ++i) {
|
||||
var charCode = sourceFile.text.charCodeAt(lineStart + i);
|
||||
if (!isWhiteSpace(charCode)) {
|
||||
for (var pos = startPos; pos < endPos; ++pos) {
|
||||
var ch = sourceFile.text.charCodeAt(pos);
|
||||
if (!isWhiteSpace(ch)) {
|
||||
return column;
|
||||
}
|
||||
|
||||
if (charCode === CharacterCodes.tab) {
|
||||
column += options.spacesPerTab;
|
||||
if (ch === CharacterCodes.tab) {
|
||||
column += options.TabSize + (column % options.TabSize);
|
||||
}
|
||||
else {
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
|
||||
function nodeContentIsIndented(parent: Node, child: Node): boolean {
|
||||
switch (parent.kind) {
|
||||
function nodeContentIsAlwaysIndented(kind: SyntaxKind): boolean {
|
||||
switch (kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return true;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
// ModuleBlock should take care of indentation
|
||||
return false;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
// FunctionBlock should take care of indentation
|
||||
return false;
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
return child && child.kind !== SyntaxKind.Block;
|
||||
case SyntaxKind.IfStatement:
|
||||
return child && child.kind !== SyntaxKind.Block;
|
||||
case SyntaxKind.TryStatement:
|
||||
// TryBlock\CatchBlock\FinallyBlock should take care of indentation
|
||||
return false;
|
||||
case SyntaxKind.ArrayLiteral:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.FunctionBlock:
|
||||
@ -312,7 +332,32 @@ module ts.formatting {
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.ExportAssignment:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function shouldIndentChildNode(parent: SyntaxKind, child: SyntaxKind): boolean {
|
||||
if (nodeContentIsAlwaysIndented(parent)) {
|
||||
return true;
|
||||
}
|
||||
switch (parent) {
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
return child !== SyntaxKind.Block;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return child !== SyntaxKind.FunctionBlock;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -361,14 +406,14 @@ module ts.formatting {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return !(<FunctionDeclaration>n).body || isCompletedNode((<FunctionDeclaration>n).body, sourceFile);
|
||||
return !(<FunctionLikeDeclaration>n).body || isCompletedNode((<FunctionLikeDeclaration>n).body, sourceFile);
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return (<ModuleDeclaration>n).body && isCompletedNode((<ModuleDeclaration>n).body, sourceFile);
|
||||
case SyntaxKind.IfStatement:
|
||||
if ((<IfStatement>n).elseStatement) {
|
||||
return isCompletedNode((<IfStatement>n).elseStatement, sourceFile);
|
||||
}
|
||||
return isCompletedNode((<IfStatement>n).thenStatement, sourceFile);
|
||||
return isCompletedNode((<IfStatement>n).thenStatement, sourceFile);
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
return isCompletedNode((<ExpressionStatement>n).expression, sourceFile);
|
||||
case SyntaxKind.ArrayLiteral:
|
||||
@ -384,10 +429,10 @@ module ts.formatting {
|
||||
case SyntaxKind.DoStatement:
|
||||
// rough approximation: if DoStatement has While keyword - then if node is completed is checking the presence of ')';
|
||||
var hasWhileKeyword = findChildOfKind(n, SyntaxKind.WhileKeyword, sourceFile);
|
||||
if(hasWhileKeyword) {
|
||||
if (hasWhileKeyword) {
|
||||
return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile);
|
||||
}
|
||||
return isCompletedNode((<DoStatement>n).statement, sourceFile);
|
||||
return isCompletedNode((<DoStatement>n).statement, sourceFile);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
2242
src/services/syntax/SyntaxGenerator.js
Normal file
2242
src/services/syntax/SyntaxGenerator.js
Normal file
File diff suppressed because it is too large
Load Diff
37
src/services/syntax/SyntaxGenerator.js.map
Normal file
37
src/services/syntax/SyntaxGenerator.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -1,7 +1,7 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export enum SyntaxConstants {
|
||||
export enum SyntaxNodeConstants {
|
||||
None = 0,
|
||||
|
||||
// Masks that we use to place information about a node into a single int. The first bit tells
|
||||
@ -15,12 +15,15 @@ module TypeScript {
|
||||
// only be used by the incremental parser if it is parsed in the same strict context as before.
|
||||
// last masks off the part of the int
|
||||
//
|
||||
// The width of the node is stored in the remainder of the int. This allows us up to 512MB
|
||||
// for a node by using all 29 bits. However, in the common case, we'll use less than 29 bits
|
||||
// The width of the node is stored in the remainder of the int. This allows us up to 128MB
|
||||
// for a node by using all 27 bits. However, in the common case, we'll use less than 27 bits
|
||||
// for the width. Thus, the info will be stored in a single int in chakra.
|
||||
NodeDataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
|
||||
NodeIncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
|
||||
NodeParsedInStrictModeMask = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
|
||||
NodeFullWidthShift = 3, // 1111 1111 1111 1111 1111 1111 1111 1000
|
||||
DataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
|
||||
IncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
|
||||
ParsedInStrictModeContext = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
|
||||
ParsedInDisallowInContext = 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000
|
||||
ParsedInYieldContext = 0x00000010, // 0000 0000 0000 0000 0000 0000 0001 0000
|
||||
ParsedInGeneratorParameterContext = 0x00000020, // 0000 0000 0000 0000 0000 0000 0010 0000
|
||||
FullWidthShift = 1 << 6, // 1111 1111 1111 1111 1111 1111 1100 0000
|
||||
}
|
||||
}
|
||||
@ -1,357 +0,0 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export class SyntaxVisitor implements ISyntaxVisitor {
|
||||
public defaultVisit(node: ISyntaxNodeOrToken): any {
|
||||
return null;
|
||||
}
|
||||
|
||||
public visitToken(token: ISyntaxToken): any {
|
||||
return this.defaultVisit(token);
|
||||
}
|
||||
|
||||
public visitSourceUnit(node: SourceUnitSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitQualifiedName(node: QualifiedNameSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitObjectType(node: ObjectTypeSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitFunctionType(node: FunctionTypeSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitArrayType(node: ArrayTypeSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitConstructorType(node: ConstructorTypeSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitGenericType(node: GenericTypeSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitTypeQuery(node: TypeQuerySyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitTupleType(node: TupleTypeSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitFunctionDeclaration(node: FunctionDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitModuleDeclaration(node: ModuleDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitClassDeclaration(node: ClassDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitEnumDeclaration(node: EnumDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitImportDeclaration(node: ImportDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitExportAssignment(node: ExportAssignmentSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitGetAccessor(node: GetAccessorSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitSetAccessor(node: SetAccessorSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitPropertySignature(node: PropertySignatureSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitCallSignature(node: CallSignatureSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitConstructSignature(node: ConstructSignatureSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitIndexSignature(node: IndexSignatureSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitMethodSignature(node: MethodSignatureSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitBlock(node: BlockSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitIfStatement(node: IfStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitVariableStatement(node: VariableStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitExpressionStatement(node: ExpressionStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitReturnStatement(node: ReturnStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitSwitchStatement(node: SwitchStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitBreakStatement(node: BreakStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitContinueStatement(node: ContinueStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitForStatement(node: ForStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitForInStatement(node: ForInStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitEmptyStatement(node: EmptyStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitThrowStatement(node: ThrowStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitWhileStatement(node: WhileStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitTryStatement(node: TryStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitLabeledStatement(node: LabeledStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitDoStatement(node: DoStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitDebuggerStatement(node: DebuggerStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitWithStatement(node: WithStatementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitDeleteExpression(node: DeleteExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitTypeOfExpression(node: TypeOfExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitVoidExpression(node: VoidExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitConditionalExpression(node: ConditionalExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitBinaryExpression(node: BinaryExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitMemberAccessExpression(node: MemberAccessExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitInvocationExpression(node: InvocationExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitArrayLiteralExpression(node: ArrayLiteralExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitObjectCreationExpression(node: ObjectCreationExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitParenthesizedExpression(node: ParenthesizedExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitCastExpression(node: CastExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitElementAccessExpression(node: ElementAccessExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitFunctionExpression(node: FunctionExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitOmittedExpression(node: OmittedExpressionSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitVariableDeclaration(node: VariableDeclarationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitVariableDeclarator(node: VariableDeclaratorSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitArgumentList(node: ArgumentListSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitParameterList(node: ParameterListSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitTypeArgumentList(node: TypeArgumentListSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitTypeParameterList(node: TypeParameterListSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitHeritageClause(node: HeritageClauseSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitEqualsValueClause(node: EqualsValueClauseSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitCaseSwitchClause(node: CaseSwitchClauseSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitDefaultSwitchClause(node: DefaultSwitchClauseSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitElseClause(node: ElseClauseSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitCatchClause(node: CatchClauseSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitFinallyClause(node: FinallyClauseSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitTypeParameter(node: TypeParameterSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitConstraint(node: ConstraintSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitParameter(node: ParameterSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitEnumElement(node: EnumElementSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitTypeAnnotation(node: TypeAnnotationSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitExternalModuleReference(node: ExternalModuleReferenceSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
|
||||
public visitModuleNameModuleReference(node: ModuleNameModuleReferenceSyntax): any {
|
||||
return this.defaultVisit(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,21 +0,0 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export class DepthLimitedWalker extends SyntaxWalker {
|
||||
private _depth: number = 0;
|
||||
private _maximumDepth: number = 0;
|
||||
|
||||
constructor(maximumDepth: number) {
|
||||
super();
|
||||
this._maximumDepth = maximumDepth;
|
||||
}
|
||||
|
||||
public visitNode(node: ISyntaxNode): void {
|
||||
if (this._depth < this._maximumDepth) {
|
||||
this._depth++;
|
||||
super.visitNode(node);
|
||||
this._depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,8 +88,8 @@ module TypeScript.IncrementalParser {
|
||||
|
||||
function release() {
|
||||
_scannerParserSource.release();
|
||||
_scannerParserSource = null;
|
||||
_oldSourceUnitCursor = null;
|
||||
_scannerParserSource = undefined;
|
||||
_oldSourceUnitCursor = undefined;
|
||||
_outstandingRewindPointCount = 0;
|
||||
}
|
||||
|
||||
@ -177,13 +177,13 @@ module TypeScript.IncrementalParser {
|
||||
|
||||
// Null out the cursor that the rewind point points to. This way we don't try
|
||||
// to return it in 'releaseRewindPoint'.
|
||||
rewindPoint.oldSourceUnitCursor = null;
|
||||
rewindPoint.oldSourceUnitCursor = undefined;
|
||||
|
||||
_scannerParserSource.rewind(rewindPoint);
|
||||
}
|
||||
|
||||
function releaseRewindPoint(rewindPoint: IParserRewindPoint): void {
|
||||
if (rewindPoint.oldSourceUnitCursor !== null) {
|
||||
if (rewindPoint.oldSourceUnitCursor) {
|
||||
returnSyntaxCursor(rewindPoint.oldSourceUnitCursor);
|
||||
}
|
||||
|
||||
@ -220,7 +220,7 @@ module TypeScript.IncrementalParser {
|
||||
|
||||
// If our current absolute position is in the middle of the changed range in the new text
|
||||
// then we definitely can't read from the old source unit right now.
|
||||
if (_changeRange !== null && _changeRangeNewSpan.intersectsWithPosition(absolutePosition())) {
|
||||
if (_changeRange && _changeRangeNewSpan.intersectsWithPosition(absolutePosition())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -235,7 +235,7 @@ module TypeScript.IncrementalParser {
|
||||
!_oldSourceUnitCursor.isFinished();
|
||||
}
|
||||
|
||||
function updateTokens(nodeOrToken: ISyntaxNodeOrToken): void {
|
||||
function updateTokenPosition(token: ISyntaxToken): void {
|
||||
// If we got a node or token, and we're past the range of edited text, then walk its
|
||||
// constituent tokens, making sure all their positions are correct. We don't need to
|
||||
// do this for the tokens before the edited range (since their positions couldn't have
|
||||
@ -243,38 +243,70 @@ module TypeScript.IncrementalParser {
|
||||
// edited range, as their positions will be correct when the underlying parser source
|
||||
// creates them.
|
||||
|
||||
var position = absolutePosition();
|
||||
var tokenWasMoved = isPastChangeRange() && fullStart(nodeOrToken) !== position;
|
||||
|
||||
if (tokenWasMoved) {
|
||||
setTokenFullStartWalker.position = position;
|
||||
|
||||
visitNodeOrToken(setTokenFullStartWalker, nodeOrToken);
|
||||
if (isPastChangeRange()) {
|
||||
token.setFullStart(absolutePosition());
|
||||
}
|
||||
}
|
||||
|
||||
function updateNodePosition(node: ISyntaxNode): void {
|
||||
// If we got a node or token, and we're past the range of edited text, then walk its
|
||||
// constituent tokens, making sure all their positions are correct. We don't need to
|
||||
// do this for the tokens before the edited range (since their positions couldn't have
|
||||
// been affected by the edit), and we don't need to do this for the tokens in the
|
||||
// edited range, as their positions will be correct when the underlying parser source
|
||||
// creates them.
|
||||
|
||||
if (isPastChangeRange()) {
|
||||
var position = absolutePosition();
|
||||
|
||||
var tokens = getTokens(node);
|
||||
|
||||
for (var i = 0, n = tokens.length; i < n; i++) {
|
||||
var token = tokens[i];
|
||||
token.setFullStart(position);
|
||||
|
||||
position += token.fullWidth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTokens(node: ISyntaxNode): ISyntaxToken[] {
|
||||
var tokens = node.__cachedTokens;
|
||||
if (!tokens) {
|
||||
tokens = [];
|
||||
tokenCollectorWalker.tokens = tokens;
|
||||
|
||||
visitNodeOrToken(tokenCollectorWalker, node);
|
||||
|
||||
node.__cachedTokens = tokens;
|
||||
tokenCollectorWalker.tokens = undefined;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function currentNode(): ISyntaxNode {
|
||||
if (canReadFromOldSourceUnit()) {
|
||||
// Try to read a node. If we can't then our caller will call back in and just try
|
||||
// to get a token.
|
||||
var node = tryGetNodeFromOldSourceUnit();
|
||||
if (node !== null) {
|
||||
if (node) {
|
||||
// Make sure the positions for the tokens in this node are correct.
|
||||
updateTokens(node);
|
||||
updateNodePosition(node);
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
// Either we were ahead of the old text, or we were pinned. No node can be read here.
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function currentToken(): ISyntaxToken {
|
||||
if (canReadFromOldSourceUnit()) {
|
||||
var token = tryGetTokenFromOldSourceUnit();
|
||||
if (token !== null) {
|
||||
if (token) {
|
||||
// Make sure the token's position/text is correct.
|
||||
updateTokens(token);
|
||||
updateTokenPosition(token);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
@ -354,9 +386,9 @@ module TypeScript.IncrementalParser {
|
||||
// e) we are still in the same strict or non-strict state that the node was originally parsed in.
|
||||
while (true) {
|
||||
var node = _oldSourceUnitCursor.currentNode();
|
||||
if (node === null) {
|
||||
if (node === undefined) {
|
||||
// Couldn't even read a node, nothing to return.
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!intersectsWithChangeRangeSpanInOriginalText(absolutePosition(), fullWidth(node))) {
|
||||
@ -395,7 +427,7 @@ module TypeScript.IncrementalParser {
|
||||
// need to make sure that if that the parser asks for a *token* we don't return it.
|
||||
// Converted identifiers can't ever be created by the scanner, and as such, should not
|
||||
// be returned by this source.
|
||||
if (token !== null) {
|
||||
if (token) {
|
||||
if (!intersectsWithChangeRangeSpanInOriginalText(position, token.fullWidth())) {
|
||||
// Didn't intersect with the change range.
|
||||
if (!token.isIncrementallyUnusable() && !Scanner.isContextualToken(token)) {
|
||||
@ -417,13 +449,13 @@ module TypeScript.IncrementalParser {
|
||||
var token = _oldSourceUnitCursor.currentToken();
|
||||
|
||||
return canReuseTokenFromOldSourceUnit(absolutePosition(), token)
|
||||
? token : null;
|
||||
? token : undefined;
|
||||
}
|
||||
|
||||
function peekToken(n: number): ISyntaxToken {
|
||||
if (canReadFromOldSourceUnit()) {
|
||||
var token = tryPeekTokenFromOldSourceUnit(n);
|
||||
if (token !== null) {
|
||||
if (token) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
@ -462,7 +494,7 @@ module TypeScript.IncrementalParser {
|
||||
var interimToken = _oldSourceUnitCursor.currentToken();
|
||||
|
||||
if (!canReuseTokenFromOldSourceUnit(currentPosition, interimToken)) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
currentPosition += interimToken.fullWidth();
|
||||
@ -471,7 +503,7 @@ module TypeScript.IncrementalParser {
|
||||
|
||||
var token = _oldSourceUnitCursor.currentToken();
|
||||
return canReuseTokenFromOldSourceUnit(currentPosition, token)
|
||||
? token : null;
|
||||
? token : undefined;
|
||||
}
|
||||
|
||||
function consumeNode(node: ISyntaxNode): void {
|
||||
@ -486,7 +518,7 @@ module TypeScript.IncrementalParser {
|
||||
var _absolutePosition = absolutePosition() + fullWidth(node);
|
||||
_scannerParserSource.resetToPosition(_absolutePosition);
|
||||
|
||||
// Debug.assert(previousToken !== null);
|
||||
// Debug.assert(previousToken !== undefined);
|
||||
// Debug.assert(previousToken.width() > 0);
|
||||
|
||||
//if (!isPastChangeRange()) {
|
||||
@ -497,6 +529,8 @@ module TypeScript.IncrementalParser {
|
||||
}
|
||||
|
||||
function consumeToken(currentToken: ISyntaxToken): void {
|
||||
// Debug.assert(currentToken.fullWidth() > 0 || currentToken.kind === SyntaxKind.EndOfFileToken);
|
||||
|
||||
// This token may have come from the old source unit, or from the new text. Handle
|
||||
// both accordingly.
|
||||
|
||||
@ -515,7 +549,7 @@ module TypeScript.IncrementalParser {
|
||||
var _absolutePosition = absolutePosition() + currentToken.fullWidth();
|
||||
_scannerParserSource.resetToPosition(_absolutePosition);
|
||||
|
||||
// Debug.assert(previousToken !== null);
|
||||
// Debug.assert(previousToken !== undefined);
|
||||
// Debug.assert(previousToken.width() > 0);
|
||||
|
||||
//if (!isPastChangeRange()) {
|
||||
@ -543,15 +577,15 @@ module TypeScript.IncrementalParser {
|
||||
|
||||
// Once we're past the change range, we no longer need it. Null it out.
|
||||
// From now on we can check if we're past the change range just by seeing
|
||||
// if this is null.
|
||||
_changeRange = null;
|
||||
// if this is undefined.
|
||||
_changeRange = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isPastChangeRange(): boolean {
|
||||
return _changeRange === null;
|
||||
return _changeRange === undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -605,7 +639,7 @@ module TypeScript.IncrementalParser {
|
||||
if (syntaxCursorPoolCount > 0) {
|
||||
// If we reused an existing cursor, take it out of the pool so no one else uses it.
|
||||
syntaxCursorPoolCount--;
|
||||
syntaxCursorPool[syntaxCursorPoolCount] = null;
|
||||
syntaxCursorPool[syntaxCursorPoolCount] = undefined;
|
||||
}
|
||||
|
||||
return cursor;
|
||||
@ -652,11 +686,11 @@ module TypeScript.IncrementalParser {
|
||||
for (var i = 0, n = pieces.length; i < n; i++) {
|
||||
var piece = pieces[i];
|
||||
|
||||
if (piece.element === null) {
|
||||
if (piece.element === undefined) {
|
||||
break;
|
||||
}
|
||||
|
||||
piece.element = null;
|
||||
piece.element = undefined;
|
||||
piece.indexInParent = -1;
|
||||
}
|
||||
|
||||
@ -669,7 +703,7 @@ module TypeScript.IncrementalParser {
|
||||
for (var i = 0, n = other.pieces.length; i < n; i++) {
|
||||
var piece = other.pieces[i];
|
||||
|
||||
if (piece.element === null) {
|
||||
if (piece.element === undefined) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -685,13 +719,13 @@ module TypeScript.IncrementalParser {
|
||||
|
||||
function currentNodeOrToken(): ISyntaxNodeOrToken {
|
||||
if (isFinished()) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var result = pieces[currentPieceIndex].element;
|
||||
|
||||
// The current element must always be a node or a token.
|
||||
// Debug.assert(result !== null);
|
||||
// Debug.assert(result !== undefined);
|
||||
// Debug.assert(result.isNode() || result.isToken());
|
||||
|
||||
return <ISyntaxNodeOrToken>result;
|
||||
@ -699,12 +733,16 @@ module TypeScript.IncrementalParser {
|
||||
|
||||
function currentNode(): ISyntaxNode {
|
||||
var element = currentNodeOrToken();
|
||||
return isNode(element) ? <ISyntaxNode>element : null;
|
||||
return isNode(element) ? <ISyntaxNode>element : undefined;
|
||||
}
|
||||
|
||||
function isEmptyList(element: ISyntaxElement) {
|
||||
return isList(element) && (<ISyntaxNodeOrToken[]>element).length === 0;
|
||||
}
|
||||
|
||||
function moveToFirstChild() {
|
||||
var nodeOrToken = currentNodeOrToken();
|
||||
if (nodeOrToken === null) {
|
||||
if (nodeOrToken === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -721,7 +759,7 @@ module TypeScript.IncrementalParser {
|
||||
// next sibling of the empty node.
|
||||
for (var i = 0, n = childCount(nodeOrToken); i < n; i++) {
|
||||
var child = childAt(nodeOrToken, i);
|
||||
if (child !== null && !isShared(child)) {
|
||||
if (child && !isEmptyList(child)) {
|
||||
// Great, we found a real child. Push that.
|
||||
pushElement(child, /*indexInParent:*/ i);
|
||||
|
||||
@ -749,14 +787,13 @@ module TypeScript.IncrementalParser {
|
||||
for (var i = currentPiece.indexInParent + 1, n = childCount(parent); i < n; i++) {
|
||||
var sibling = childAt(parent, i);
|
||||
|
||||
if (sibling !== null && !isShared(sibling)) {
|
||||
if (sibling && !isEmptyList(sibling)) {
|
||||
// We found a good sibling that we can move to. Just reuse our existing piece
|
||||
// so we don't have to push/pop.
|
||||
currentPiece.element = sibling;
|
||||
currentPiece.indexInParent = i;
|
||||
|
||||
// The sibling might have been a list. Move to it's first child. it must have
|
||||
// one since this was a non-shared element.
|
||||
// The sibling might have been a list. Move to it's first child.
|
||||
moveToFirstChildIfList();
|
||||
return;
|
||||
}
|
||||
@ -766,7 +803,7 @@ module TypeScript.IncrementalParser {
|
||||
|
||||
// Clear the data from the old piece. We don't want to keep any elements around
|
||||
// unintentionally.
|
||||
currentPiece.element = null;
|
||||
currentPiece.element = undefined;
|
||||
currentPiece.indexInParent = -1;
|
||||
|
||||
// Point at the parent. if we move past the top of the path, then we're finished.
|
||||
@ -777,7 +814,7 @@ module TypeScript.IncrementalParser {
|
||||
function moveToFirstChildIfList(): void {
|
||||
var element = pieces[currentPieceIndex].element;
|
||||
|
||||
if (isList(element) || isSeparatedList(element)) {
|
||||
if (isList(element)) {
|
||||
// We cannot ever get an empty list in our piece path. Empty lists are 'shared' and
|
||||
// we make sure to filter that out before pushing any children.
|
||||
// Debug.assert(childCount(element) > 0);
|
||||
@ -787,7 +824,7 @@ module TypeScript.IncrementalParser {
|
||||
}
|
||||
|
||||
function pushElement(element: ISyntaxElement, indexInParent: number): void {
|
||||
// Debug.assert(element !== null);
|
||||
// Debug.assert(element !== undefined);
|
||||
// Debug.assert(indexInParent >= 0);
|
||||
currentPieceIndex++;
|
||||
|
||||
@ -819,8 +856,8 @@ module TypeScript.IncrementalParser {
|
||||
moveToFirstToken();
|
||||
|
||||
var element = currentNodeOrToken();
|
||||
// Debug.assert(element === null || element.isToken());
|
||||
return element === null ? null : <ISyntaxToken>element;
|
||||
// Debug.assert(element === undefined || element.isToken());
|
||||
return <ISyntaxToken>element;
|
||||
}
|
||||
|
||||
return {
|
||||
@ -841,21 +878,17 @@ module TypeScript.IncrementalParser {
|
||||
// A simple walker we use to hit all the tokens of a node and update their positions when they
|
||||
// are reused in a different location because of an incremental parse.
|
||||
|
||||
class SetTokenFullStartWalker extends SyntaxWalker {
|
||||
public position: number;
|
||||
class TokenCollectorWalker extends SyntaxWalker {
|
||||
public tokens: ISyntaxToken[] = [];
|
||||
|
||||
public visitToken(token: ISyntaxToken): void {
|
||||
var position = this.position;
|
||||
token.setFullStart(position);
|
||||
|
||||
this.position = position + token.fullWidth();
|
||||
this.tokens.push(token);
|
||||
}
|
||||
}
|
||||
|
||||
var setTokenFullStartWalker = new SetTokenFullStartWalker();
|
||||
var tokenCollectorWalker = new TokenCollectorWalker();
|
||||
|
||||
export function parse(oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree {
|
||||
Debug.assert(oldSyntaxTree.isConcrete(), "Can only incrementally parse a concrete syntax tree.");
|
||||
if (textChangeRange.isUnchanged()) {
|
||||
return oldSyntaxTree;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -16,11 +16,11 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
private newLineCountBetweenModuleElements(element1: IModuleElementSyntax, element2: IModuleElementSyntax): number {
|
||||
if (element1 === null || element2 === null) {
|
||||
if (!element1 || !element2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastToken(element1).kind() === SyntaxKind.CloseBraceToken) {
|
||||
if (lastToken(element1).kind === SyntaxKind.CloseBraceToken) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -28,19 +28,19 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
private newLineCountBetweenClassElements(element1: IClassElementSyntax, element2: IClassElementSyntax): number {
|
||||
if (element1 === null || element2 === null) {
|
||||
if (!element1 || !element2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private newLineCountBetweenStatements(element1: IClassElementSyntax, element2: IClassElementSyntax): number {
|
||||
if (element1 === null || element2 === null) {
|
||||
private newLineCountBetweenStatements(element1: IStatementSyntax, element2: IStatementSyntax): number {
|
||||
if (!element1 || !element2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastToken(element1).kind() === SyntaxKind.CloseBraceToken) {
|
||||
if (lastToken(element1).kind === SyntaxKind.CloseBraceToken) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
private newLineCountBetweenSwitchClauses(element1: ISwitchClauseSyntax, element2: ISwitchClauseSyntax): number {
|
||||
if (element1 === null || element2 === null) {
|
||||
if (!element1 || !element2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
private appendToken(token: ISyntaxToken): void {
|
||||
if (token !== null && token.fullWidth() > 0) {
|
||||
if (token && token.fullWidth() > 0) {
|
||||
this.appendIndentationIfAfterNewLine();
|
||||
this.appendText(token.text());
|
||||
}
|
||||
@ -150,7 +150,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureSpace();
|
||||
}
|
||||
|
||||
visitNodeOrToken(this, childAt(list, i));
|
||||
visitNodeOrToken(this, list[i]);
|
||||
}
|
||||
else {
|
||||
this.appendToken(<ISyntaxToken>childAt(list, i));
|
||||
@ -165,7 +165,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureNewLine();
|
||||
}
|
||||
|
||||
visitNodeOrToken(this, childAt(list, i));
|
||||
visitNodeOrToken(this, list[i]);
|
||||
}
|
||||
else {
|
||||
this.appendToken(<ISyntaxToken>childAt(list, i));
|
||||
@ -174,7 +174,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
private appendModuleElements(list: IModuleElementSyntax[]): void {
|
||||
var lastModuleElement: IModuleElementSyntax = null;
|
||||
var lastModuleElement: IModuleElementSyntax = undefined;
|
||||
for (var i = 0, n = list.length; i < n; i++) {
|
||||
var moduleElement = list[i];
|
||||
var newLineCount = this.newLineCountBetweenModuleElements(lastModuleElement, moduleElement);
|
||||
@ -236,7 +236,7 @@ module TypeScript.PrettyPrinter {
|
||||
|
||||
this.indentation++;
|
||||
|
||||
var lastClassElement: IClassElementSyntax = null;
|
||||
var lastClassElement: IClassElementSyntax = undefined;
|
||||
for (var i = 0, n = node.classElements.length; i < n; i++) {
|
||||
var classElement = node.classElements[i];
|
||||
var newLineCount = this.newLineCountBetweenClassElements(lastClassElement, classElement);
|
||||
@ -278,7 +278,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
for (var i = 0, n = childCount(node.typeMembers); i < n; i++) {
|
||||
visitNodeOrToken(this, childAt(node.typeMembers, i));
|
||||
visitNodeOrToken(this, node.typeMembers[i]);
|
||||
|
||||
if (appendNewLines) {
|
||||
this.ensureNewLine();
|
||||
@ -305,9 +305,6 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureSpace();
|
||||
this.appendElement(node.name);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.stringLiteral);
|
||||
this.ensureSpace();
|
||||
|
||||
this.appendToken(node.openBraceToken);
|
||||
this.ensureNewLine();
|
||||
|
||||
@ -319,13 +316,13 @@ module TypeScript.PrettyPrinter {
|
||||
this.appendToken(node.closeBraceToken);
|
||||
}
|
||||
|
||||
private appendBlockOrSemicolon(block: BlockSyntax, semicolonToken: ISyntaxToken) {
|
||||
if (block) {
|
||||
private appendBlockOrSemicolon(body: BlockSyntax | ISyntaxToken) {
|
||||
if (body.kind === SyntaxKind.Block) {
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, block);
|
||||
visitNodeOrToken(this, body);
|
||||
}
|
||||
else {
|
||||
this.appendToken(semicolonToken);
|
||||
this.appendToken(<ISyntaxToken>body);
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,7 +333,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.identifier);
|
||||
this.appendNode(node.callSignature);
|
||||
this.appendBlockOrSemicolon(node.block, node.semicolonToken);
|
||||
this.appendBlockOrSemicolon(node.body);
|
||||
}
|
||||
|
||||
public visitVariableStatement(node: VariableStatementSyntax): void {
|
||||
@ -353,7 +350,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
public visitVariableDeclarator(node: VariableDeclaratorSyntax): void {
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
this.appendNode(node.equalsValueClause);
|
||||
}
|
||||
|
||||
@ -390,8 +387,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.equalsGreaterThanToken);
|
||||
this.ensureSpace();
|
||||
this.appendNode(node.block);
|
||||
this.appendElement(node.expression);
|
||||
visitNodeOrToken(this, node.body);
|
||||
}
|
||||
|
||||
public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): void {
|
||||
@ -399,8 +395,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.equalsGreaterThanToken);
|
||||
this.ensureSpace();
|
||||
this.appendNode(node.block);
|
||||
this.appendElement(node.expression);
|
||||
visitNodeOrToken(this, node.body);
|
||||
}
|
||||
|
||||
public visitQualifiedName(node: QualifiedNameSyntax): void {
|
||||
@ -427,6 +422,20 @@ module TypeScript.PrettyPrinter {
|
||||
this.appendToken(node.closeBracketToken);
|
||||
}
|
||||
|
||||
public visitParenthesizedType(node: ParenthesizedTypeSyntax): void {
|
||||
this.appendToken(node.openParenToken);
|
||||
this.appendElement(node.type);
|
||||
this.appendToken(node.closeParenToken);
|
||||
}
|
||||
|
||||
public visitUnionType(node: UnionTypeSyntax): void {
|
||||
this.appendElement(node.left);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.barToken);
|
||||
this.ensureSpace();
|
||||
this.appendElement(node.right);
|
||||
}
|
||||
|
||||
public visitConstructorType(node: ConstructorTypeSyntax): void {
|
||||
this.appendToken(node.newKeyword);
|
||||
this.ensureSpace();
|
||||
@ -472,7 +481,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
private appendStatements(statements: IStatementSyntax[]): void {
|
||||
var lastStatement: IStatementSyntax = null;
|
||||
var lastStatement: IStatementSyntax = undefined;
|
||||
for (var i = 0, n = statements.length; i < n; i++) {
|
||||
var statement = statements[i];
|
||||
|
||||
@ -538,7 +547,7 @@ module TypeScript.PrettyPrinter {
|
||||
public visitBinaryExpression(node: BinaryExpressionSyntax): void {
|
||||
visitNodeOrToken(this, node.left);
|
||||
|
||||
if (node.kind() !== SyntaxKind.CommaExpression) {
|
||||
if (node.operatorToken.kind !== SyntaxKind.CommaToken) {
|
||||
this.ensureSpace();
|
||||
}
|
||||
|
||||
@ -565,7 +574,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
public visitMethodSignature(node: MethodSignatureSyntax): void {
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
this.appendToken(node.questionToken);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
}
|
||||
@ -578,7 +587,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
public visitPropertySignature(node: PropertySignatureSyntax): void {
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
this.appendToken(node.questionToken);
|
||||
this.appendNode(node.typeAnnotation);
|
||||
}
|
||||
@ -614,7 +623,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
private appendBlockOrStatement(node: IStatementSyntax): void {
|
||||
if (node.kind() === SyntaxKind.Block) {
|
||||
if (node.kind === SyntaxKind.Block) {
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node);
|
||||
}
|
||||
@ -640,7 +649,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureNewLine();
|
||||
this.appendToken(node.elseKeyword);
|
||||
|
||||
if (node.statement.kind() === SyntaxKind.IfStatement) {
|
||||
if (node.statement.kind === SyntaxKind.IfStatement) {
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node.statement);
|
||||
}
|
||||
@ -657,7 +666,7 @@ module TypeScript.PrettyPrinter {
|
||||
public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): void {
|
||||
this.appendToken(node.constructorKeyword);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
this.appendBlockOrSemicolon(node.block, node.semicolonToken);
|
||||
this.appendBlockOrSemicolon(node.body);
|
||||
}
|
||||
|
||||
public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): void {
|
||||
@ -670,9 +679,9 @@ module TypeScript.PrettyPrinter {
|
||||
public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): void {
|
||||
this.appendSpaceList(node.modifiers);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
this.appendBlockOrSemicolon(node.block, node.semicolonToken);
|
||||
this.appendBlockOrSemicolon(node.body);
|
||||
}
|
||||
|
||||
public visitGetAccessor(node: GetAccessorSyntax): void {
|
||||
@ -680,7 +689,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.getKeyword);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node.block);
|
||||
@ -691,7 +700,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.setKeyword);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
visitNodeOrToken(this, node.callSignature)
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node.block);
|
||||
@ -743,7 +752,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.appendToken(node.openBraceToken);
|
||||
this.ensureNewLine();
|
||||
|
||||
var lastSwitchClause: ISwitchClauseSyntax = null;
|
||||
var lastSwitchClause: ISwitchClauseSyntax = undefined;
|
||||
for (var i = 0, n = node.switchClauses.length; i < n; i++) {
|
||||
var switchClause = node.switchClauses[i];
|
||||
|
||||
@ -760,9 +769,9 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
private appendSwitchClauseStatements(node: ISwitchClauseSyntax): void {
|
||||
if (childCount(node.statements) === 1 && childAt(node.statements, 0).kind() === SyntaxKind.Block) {
|
||||
if (childCount(node.statements) === 1 && childAt(node.statements, 0).kind === SyntaxKind.Block) {
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, childAt(node.statements, 0));
|
||||
visitNodeOrToken(this, node.statements[0]);
|
||||
}
|
||||
else if (childCount(node.statements) > 0) {
|
||||
this.ensureNewLine();
|
||||
@ -811,8 +820,7 @@ module TypeScript.PrettyPrinter {
|
||||
this.appendToken(node.forKeyword);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.openParenToken);
|
||||
this.appendNode(node.variableDeclaration);
|
||||
this.appendElement(node.initializer);
|
||||
visitNodeOrToken(this, node.initializer);
|
||||
this.appendToken(node.firstSemicolonToken);
|
||||
|
||||
if (node.condition) {
|
||||
@ -835,12 +843,11 @@ module TypeScript.PrettyPrinter {
|
||||
this.appendToken(node.forKeyword);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.openParenToken);
|
||||
this.appendNode(node.variableDeclaration);
|
||||
this.appendElement(node.left);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.inKeyword);
|
||||
this.ensureSpace();
|
||||
this.appendElement(node.expression);
|
||||
this.appendElement(node.right);
|
||||
this.appendToken(node.closeParenToken);
|
||||
this.appendBlockOrStatement(node.statement);
|
||||
}
|
||||
@ -881,7 +888,7 @@ module TypeScript.PrettyPrinter {
|
||||
}
|
||||
|
||||
public visitEnumElement(node: EnumElementSyntax): void {
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
this.ensureSpace();
|
||||
this.appendNode(node.equalsValueClause);
|
||||
}
|
||||
@ -912,15 +919,21 @@ module TypeScript.PrettyPrinter {
|
||||
this.appendToken(node.closeBraceToken);
|
||||
}
|
||||
|
||||
public visitComputedPropertyName(node: ComputedPropertyNameSyntax): void {
|
||||
this.appendToken(node.openBracketToken);
|
||||
visitNodeOrToken(this, node.expression);
|
||||
this.appendToken(node.closeBracketToken);
|
||||
}
|
||||
|
||||
public visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): void {
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
this.appendToken(node.colonToken);
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node.expression);
|
||||
}
|
||||
|
||||
public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): void {
|
||||
this.appendToken(node.propertyName);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node.block);
|
||||
@ -1005,9 +1018,33 @@ module TypeScript.PrettyPrinter {
|
||||
visitNodeOrToken(this, node.expression);
|
||||
}
|
||||
|
||||
public visitYieldExpression(node: YieldExpressionSyntax): void {
|
||||
this.appendToken(node.yieldKeyword);
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node.expression);
|
||||
}
|
||||
|
||||
public visitDebuggerStatement(node: DebuggerStatementSyntax): void {
|
||||
this.appendToken(node.debuggerKeyword);
|
||||
this.appendToken(node.semicolonToken);
|
||||
}
|
||||
|
||||
public visitTemplateExpression(node: TemplateExpressionSyntax): void {
|
||||
this.appendToken(node.templateStartToken);
|
||||
this.ensureSpace();
|
||||
this.appendSpaceList(node.templateClauses);
|
||||
}
|
||||
|
||||
public visitTemplateClause(node: TemplateClauseSyntax): void {
|
||||
visitNodeOrToken(this, node.expression);
|
||||
this.ensureSpace();
|
||||
this.appendToken(node.templateMiddleOrEndToken);
|
||||
}
|
||||
|
||||
public visitTemplateAccessExpression(node: TemplateAccessExpressionSyntax): void {
|
||||
visitNodeOrToken(this, node.expression);
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node.templateExpression);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17,9 +17,7 @@
|
||||
///<reference path='syntaxElement.ts' />
|
||||
///<reference path='syntaxFacts2.ts' />
|
||||
///<reference path='syntaxList.ts' />
|
||||
///<reference path='syntaxNode.ts' />
|
||||
///<reference path='syntaxNodeOrToken.ts' />
|
||||
///<reference path='syntaxNodes.interfaces.generated.ts' />
|
||||
|
||||
// SyntaxDedenter depends on SyntaxRewriter
|
||||
// ///<reference path='syntaxDedenter.ts' />
|
||||
@ -41,6 +39,7 @@
|
||||
///<reference path='parser.ts' />
|
||||
|
||||
// Concrete nodes depend on the parser.
|
||||
///<reference path='syntaxInterfaces.generated.ts' />
|
||||
///<reference path='syntaxNodes.concrete.generated.ts' />
|
||||
|
||||
// SyntaxTree depends on PositionTrackingWalker
|
||||
|
||||
@ -60,84 +60,47 @@ module TypeScript.Scanner {
|
||||
// This gives us 23bit for width (or 8MB of width which should be enough for any codebase).
|
||||
|
||||
enum ScannerConstants {
|
||||
LargeTokenFullStartShift = 4,
|
||||
LargeTokenFullWidthShift = 7,
|
||||
LargeTokenLeadingTriviaBitMask = 0x01, // 00000001
|
||||
LargeTokenLeadingCommentBitMask = 0x02, // 00000010
|
||||
LargeTokenTrailingTriviaBitMask = 0x04, // 00000100
|
||||
LargeTokenTrailingCommentBitMask = 0x08, // 00001000
|
||||
LargeTokenTriviaBitMask = 0x0F, // 00001111
|
||||
LargeTokenFullWidthShift = 3,
|
||||
|
||||
FixedWidthTokenFullStartShift = 7,
|
||||
FixedWidthTokenMaxFullStart = 0x7FFFFF, // 23 ones.
|
||||
WhitespaceTrivia = 0x01, // 00000001
|
||||
NewlineTrivia = 0x02, // 00000010
|
||||
CommentTrivia = 0x04, // 00000100
|
||||
TriviaMask = 0x07, // 00000111
|
||||
|
||||
SmallTokenFullWidthShift = 7,
|
||||
SmallTokenFullStartShift = 12,
|
||||
SmallTokenMaxFullStart = 0x3FFFF, // 18 ones.
|
||||
SmallTokenMaxFullWidth = 0x1F, // 5 ones
|
||||
SmallTokenFullWidthMask = 0x1F, // 00011111
|
||||
|
||||
KindMask = 0x7F, // 01111111
|
||||
IsVariableWidthMask = 0x80, // 10000000
|
||||
KindMask = 0x7F, // 01111111
|
||||
IsVariableWidthMask = 0x80, // 10000000
|
||||
}
|
||||
|
||||
// Make sure our math works for packing/unpacking large fullStarts.
|
||||
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(1 << 26, 3)) === (1 << 26));
|
||||
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(3 << 25, 1)) === (3 << 25));
|
||||
Debug.assert(largeTokenUnpackFullStart(largeTokenPackFullStartAndInfo(10 << 23, 2)) === (10 << 23));
|
||||
|
||||
function fixedWidthTokenPackData(fullStart: number, kind: SyntaxKind) {
|
||||
return (fullStart << ScannerConstants.FixedWidthTokenFullStartShift) | kind;
|
||||
function largeTokenPackData(fullWidth: number, leadingTriviaInfo: number) {
|
||||
return (fullWidth << ScannerConstants.LargeTokenFullWidthShift) | leadingTriviaInfo;
|
||||
}
|
||||
|
||||
function fixedWidthTokenUnpackFullStart(packedData: number) {
|
||||
return packedData >> ScannerConstants.FixedWidthTokenFullStartShift;
|
||||
function largeTokenUnpackFullWidth(packedFullWidthAndInfo: number): number {
|
||||
return packedFullWidthAndInfo >> ScannerConstants.LargeTokenFullWidthShift;
|
||||
}
|
||||
|
||||
function smallTokenPackData(fullStart: number, fullWidth: number, kind: SyntaxKind) {
|
||||
return (fullStart << ScannerConstants.SmallTokenFullStartShift) |
|
||||
(fullWidth << ScannerConstants.SmallTokenFullWidthShift) |
|
||||
kind;
|
||||
}
|
||||
|
||||
function smallTokenUnpackFullWidth(packedData: number): SyntaxKind {
|
||||
return (packedData >> ScannerConstants.SmallTokenFullWidthShift) & ScannerConstants.SmallTokenFullWidthMask;
|
||||
}
|
||||
|
||||
function smallTokenUnpackFullStart(packedData: number): number {
|
||||
return packedData >> ScannerConstants.SmallTokenFullStartShift;
|
||||
}
|
||||
|
||||
function largeTokenPackFullStartAndInfo(fullStart: number, triviaInfo: number): number {
|
||||
return (fullStart << ScannerConstants.LargeTokenFullStartShift) | triviaInfo;
|
||||
}
|
||||
|
||||
function largeTokenUnpackFullWidth(packedFullWidthAndKind: number) {
|
||||
return packedFullWidthAndKind >> ScannerConstants.LargeTokenFullWidthShift;
|
||||
}
|
||||
|
||||
function largeTokenUnpackFullStart(packedFullStartAndInfo: number): number {
|
||||
return packedFullStartAndInfo >> ScannerConstants.LargeTokenFullStartShift;
|
||||
function largeTokenUnpackLeadingTriviaInfo(packedFullWidthAndInfo: number): number {
|
||||
return packedFullWidthAndInfo & ScannerConstants.TriviaMask;
|
||||
}
|
||||
|
||||
function largeTokenUnpackHasLeadingTrivia(packed: number): boolean {
|
||||
return (packed & ScannerConstants.LargeTokenLeadingTriviaBitMask) !== 0;
|
||||
return largeTokenUnpackLeadingTriviaInfo(packed) !== 0;
|
||||
}
|
||||
|
||||
function largeTokenUnpackHasTrailingTrivia(packed: number): boolean {
|
||||
return (packed & ScannerConstants.LargeTokenTrailingTriviaBitMask) !== 0;
|
||||
function hasComment(info: number) {
|
||||
return (info & ScannerConstants.CommentTrivia) !== 0;
|
||||
}
|
||||
|
||||
function hasNewLine(info: number) {
|
||||
return (info & ScannerConstants.NewlineTrivia) !== 0;
|
||||
}
|
||||
|
||||
function largeTokenUnpackHasLeadingNewLine(packed: number): boolean {
|
||||
return hasNewLine(largeTokenUnpackLeadingTriviaInfo(packed));
|
||||
}
|
||||
|
||||
function largeTokenUnpackHasLeadingComment(packed: number): boolean {
|
||||
return (packed & ScannerConstants.LargeTokenLeadingCommentBitMask) !== 0;
|
||||
}
|
||||
|
||||
function largeTokenUnpackHasTrailingComment(packed: number): boolean {
|
||||
return (packed & ScannerConstants.LargeTokenTrailingCommentBitMask) !== 0;
|
||||
}
|
||||
|
||||
function largeTokenUnpackTriviaInfo(packed: number): number {
|
||||
return packed & ScannerConstants.LargeTokenTriviaBitMask;
|
||||
return hasComment(largeTokenUnpackLeadingTriviaInfo(packed));
|
||||
}
|
||||
|
||||
var isKeywordStartCharacter: number[] = ArrayUtilities.createArray<number>(CharacterCodes.maxAsciiCharacter, 0);
|
||||
@ -166,7 +129,7 @@ module TypeScript.Scanner {
|
||||
// These tokens are contextually created based on parsing decisions. We can't reuse
|
||||
// them in incremental scenarios as we may be in a context where the parser would not
|
||||
// create them.
|
||||
switch (token.kind()) {
|
||||
switch (token.kind) {
|
||||
// Created by the parser when it sees / or /= in a location where it needs an expression.
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
|
||||
@ -178,12 +141,17 @@ module TypeScript.Scanner {
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
|
||||
return true;
|
||||
|
||||
// Created by the parser when it sees } while parsing a template expression.
|
||||
case SyntaxKind.TemplateMiddleToken:
|
||||
case SyntaxKind.TemplateEndToken:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return token.isKeywordConvertedToIdentifier();
|
||||
}
|
||||
}
|
||||
|
||||
var lastTokenInfo = { leadingTriviaWidth: -1, width: -1 };
|
||||
var lastTokenInfo = { leadingTriviaWidth: -1 };
|
||||
var lastTokenInfoTokenID: number = -1;
|
||||
|
||||
var triviaScanner = createScannerInternal(ts.ScriptTarget.Latest, SimpleText.fromString(""), () => { });
|
||||
@ -207,15 +175,7 @@ module TypeScript.Scanner {
|
||||
return Syntax.emptyTriviaList;
|
||||
}
|
||||
|
||||
return triviaScanner.scanTrivia(token, text, /*isTrailing:*/ false);
|
||||
}
|
||||
|
||||
function trailingTrivia(token: IScannerToken, text: ISimpleText): ISyntaxTriviaList {
|
||||
if (!token.hasTrailingTrivia()) {
|
||||
return Syntax.emptyTriviaList;
|
||||
}
|
||||
|
||||
return triviaScanner.scanTrivia(token, text, /*isTrailing:*/ true);
|
||||
return triviaScanner.scanTrivia(token, text);
|
||||
}
|
||||
|
||||
function leadingTriviaWidth(token: IScannerToken, text: ISimpleText): number {
|
||||
@ -227,15 +187,6 @@ module TypeScript.Scanner {
|
||||
return lastTokenInfo.leadingTriviaWidth;
|
||||
}
|
||||
|
||||
function trailingTriviaWidth(token: IScannerToken, text: ISimpleText): number {
|
||||
if (!token.hasTrailingTrivia()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fillSizeInfo(token, text);
|
||||
return token.fullWidth() - lastTokenInfo.leadingTriviaWidth - lastTokenInfo.width;
|
||||
}
|
||||
|
||||
function tokenIsIncrementallyUnusable(token: IScannerToken): boolean {
|
||||
// No scanner tokens make their *containing node* incrementally unusable.
|
||||
// Note: several scanner tokens may themselves be unusable. i.e. if the parser asks
|
||||
@ -246,50 +197,56 @@ module TypeScript.Scanner {
|
||||
}
|
||||
|
||||
class FixedWidthTokenWithNoTrivia implements ISyntaxToken {
|
||||
public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any;
|
||||
public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; public _propertyAssignmentBrand: any; public _propertyNameBrand: any;
|
||||
public parent: ISyntaxElement;
|
||||
public childCount: number;
|
||||
|
||||
constructor(private _packedData: number) {
|
||||
constructor(private _fullStart: number, public kind: SyntaxKind) {
|
||||
}
|
||||
|
||||
public setFullStart(fullStart: number): void {
|
||||
this._packedData = fixedWidthTokenPackData(fullStart, this.kind());
|
||||
this._fullStart = fullStart;
|
||||
}
|
||||
|
||||
public childAt(index: number): ISyntaxElement { throw Errors.invalidOperation() }
|
||||
|
||||
public isIncrementallyUnusable(): boolean { return false; }
|
||||
public isKeywordConvertedToIdentifier(): boolean { return false; }
|
||||
public hasSkippedToken(): boolean { return false; }
|
||||
public fullText(): string { return SyntaxFacts.getText(this.kind()); }
|
||||
public fullText(): string { return SyntaxFacts.getText(this.kind); }
|
||||
public text(): string { return this.fullText(); }
|
||||
public leadingTrivia(): ISyntaxTriviaList { return Syntax.emptyTriviaList; }
|
||||
public trailingTrivia(): ISyntaxTriviaList { return Syntax.emptyTriviaList; }
|
||||
public leadingTriviaWidth(): number { return 0; }
|
||||
public trailingTriviaWidth(): number { return 0; }
|
||||
|
||||
public kind(): SyntaxKind { return this._packedData & ScannerConstants.KindMask; }
|
||||
public fullWidth(): number { return this.fullText().length; }
|
||||
public fullStart(): number { return fixedWidthTokenUnpackFullStart(this._packedData); }
|
||||
public fullWidth(): number { return fixedWidthTokenLength(this.kind); }
|
||||
public fullStart(): number { return this._fullStart; }
|
||||
public hasLeadingTrivia(): boolean { return false; }
|
||||
public hasTrailingTrivia(): boolean { return false; }
|
||||
public hasLeadingNewLine(): boolean { return false; }
|
||||
public hasLeadingSkippedToken(): boolean { return false; }
|
||||
public hasLeadingComment(): boolean { return false; }
|
||||
public hasTrailingComment(): boolean { return false; }
|
||||
public clone(): ISyntaxToken { return new FixedWidthTokenWithNoTrivia(this._packedData); }
|
||||
|
||||
public clone(): ISyntaxToken { return new FixedWidthTokenWithNoTrivia(this._fullStart, this.kind); }
|
||||
}
|
||||
FixedWidthTokenWithNoTrivia.prototype.childCount = 0;
|
||||
|
||||
class LargeScannerToken implements ISyntaxToken {
|
||||
public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any;
|
||||
public _primaryExpressionBrand: any; public _memberExpressionBrand: any; public _leftHandSideExpressionBrand: any; public _postfixExpressionBrand: any; public _unaryExpressionBrand: any; public _expressionBrand: any; public _typeBrand: any; public _nameBrand: any; public _propertyAssignmentBrand: any; public _propertyNameBrand: any;
|
||||
public parent: ISyntaxElement;
|
||||
public childCount: number;
|
||||
|
||||
private cachedText: string;
|
||||
constructor(private _packedFullStartAndInfo: number, private _packedFullWidthAndKind: number, cachedText: string) {
|
||||
|
||||
constructor(private _fullStart: number, public kind: SyntaxKind, private _packedFullWidthAndInfo: number, cachedText: string) {
|
||||
if (cachedText !== undefined) {
|
||||
this.cachedText = cachedText;
|
||||
}
|
||||
}
|
||||
|
||||
public setFullStart(fullStart: number): void {
|
||||
this._packedFullStartAndInfo = largeTokenPackFullStartAndInfo(fullStart,
|
||||
largeTokenUnpackTriviaInfo(this._packedFullStartAndInfo));
|
||||
this._fullStart = fullStart;
|
||||
}
|
||||
|
||||
public childAt(index: number): ISyntaxElement { throw Errors.invalidOperation() }
|
||||
|
||||
private syntaxTreeText(text: ISimpleText) {
|
||||
var result = text || syntaxTree(this).text;
|
||||
Debug.assert(result);
|
||||
@ -298,7 +255,6 @@ module TypeScript.Scanner {
|
||||
|
||||
public isIncrementallyUnusable(): boolean { return tokenIsIncrementallyUnusable(this); }
|
||||
public isKeywordConvertedToIdentifier(): boolean { return false; }
|
||||
public hasSkippedToken(): boolean { return false; }
|
||||
|
||||
public fullText(text?: ISimpleText): string {
|
||||
return fullText(this, this.syntaxTreeText(text));
|
||||
@ -306,29 +262,23 @@ module TypeScript.Scanner {
|
||||
|
||||
public text(): string {
|
||||
var cachedText = this.cachedText;
|
||||
return cachedText !== undefined ? cachedText : SyntaxFacts.getText(this.kind());
|
||||
return cachedText !== undefined ? cachedText : SyntaxFacts.getText(this.kind);
|
||||
}
|
||||
|
||||
public leadingTrivia(text?: ISimpleText): ISyntaxTriviaList { return leadingTrivia(this, this.syntaxTreeText(text)); }
|
||||
public trailingTrivia(text?: ISimpleText): ISyntaxTriviaList { return trailingTrivia(this, this.syntaxTreeText(text)); }
|
||||
public leadingTriviaWidth(text?: ISimpleText): number { return leadingTriviaWidth(this, this.syntaxTreeText(text)); }
|
||||
|
||||
public leadingTriviaWidth(text?: ISimpleText): number {
|
||||
return leadingTriviaWidth(this, this.syntaxTreeText(text));
|
||||
}
|
||||
public fullWidth(): number { return largeTokenUnpackFullWidth(this._packedFullWidthAndInfo); }
|
||||
public fullStart(): number { return this._fullStart; }
|
||||
|
||||
public trailingTriviaWidth(text?: ISimpleText): number {
|
||||
return trailingTriviaWidth(this, this.syntaxTreeText(text));
|
||||
}
|
||||
public hasLeadingTrivia(): boolean { return largeTokenUnpackHasLeadingTrivia(this._packedFullWidthAndInfo); }
|
||||
public hasLeadingNewLine(): boolean { return largeTokenUnpackHasLeadingNewLine(this._packedFullWidthAndInfo); }
|
||||
public hasLeadingComment(): boolean { return largeTokenUnpackHasLeadingComment(this._packedFullWidthAndInfo); }
|
||||
public hasLeadingSkippedToken(): boolean { return false; }
|
||||
|
||||
public kind(): SyntaxKind { return this._packedFullWidthAndKind & ScannerConstants.KindMask; }
|
||||
public fullWidth(): number { return largeTokenUnpackFullWidth(this._packedFullWidthAndKind); }
|
||||
public fullStart(): number { return largeTokenUnpackFullStart(this._packedFullStartAndInfo); }
|
||||
public hasLeadingTrivia(): boolean { return largeTokenUnpackHasLeadingTrivia(this._packedFullStartAndInfo); }
|
||||
public hasTrailingTrivia(): boolean { return largeTokenUnpackHasTrailingTrivia(this._packedFullStartAndInfo); }
|
||||
public hasLeadingComment(): boolean { return largeTokenUnpackHasLeadingComment(this._packedFullStartAndInfo); }
|
||||
public hasTrailingComment(): boolean { return largeTokenUnpackHasTrailingComment(this._packedFullStartAndInfo); }
|
||||
public clone(): ISyntaxToken { return new LargeScannerToken(this._packedFullStartAndInfo, this._packedFullWidthAndKind, this.cachedText); }
|
||||
public clone(): ISyntaxToken { return new LargeScannerToken(this._fullStart, this.kind, this._packedFullWidthAndInfo, this.cachedText); }
|
||||
}
|
||||
LargeScannerToken.prototype.childCount = 0;
|
||||
|
||||
export interface DiagnosticCallback {
|
||||
(position: number, width: number, key: string, arguments: any[]): void;
|
||||
@ -336,12 +286,11 @@ module TypeScript.Scanner {
|
||||
|
||||
interface TokenInfo {
|
||||
leadingTriviaWidth: number;
|
||||
width: number;
|
||||
}
|
||||
|
||||
interface IScannerInternal extends IScanner {
|
||||
fillTokenInfo(token: IScannerToken, text: ISimpleText, tokenInfo: TokenInfo): void;
|
||||
scanTrivia(token: IScannerToken, text: ISimpleText, isTrailing: boolean): ISyntaxTriviaList;
|
||||
scanTrivia(token: IScannerToken, text: ISimpleText): ISyntaxTriviaList;
|
||||
}
|
||||
|
||||
export interface IScanner {
|
||||
@ -368,12 +317,13 @@ module TypeScript.Scanner {
|
||||
}
|
||||
|
||||
function reset(_text: ISimpleText, _start: number, _end: number) {
|
||||
Debug.assert(_start <= _text.length(), "Token's start was not within the bounds of text: " + _start + " - [0, " + _text.length() + ")");
|
||||
Debug.assert(_end <= _text.length(), "Token's end was not within the bounds of text: " + _end + " - [0, " + _text.length() + ")");
|
||||
var textLength = _text.length();
|
||||
Debug.assert(_start <= textLength, "Token's start was not within the bounds of text.");
|
||||
Debug.assert(_end <= textLength, "Token's end was not within the bounds of text:");
|
||||
|
||||
if (!str || text !== _text) {
|
||||
text = _text;
|
||||
str = _text.substr(0, _text.length());
|
||||
str = _text.substr(0, textLength);
|
||||
}
|
||||
|
||||
start = _start;
|
||||
@ -383,15 +333,13 @@ module TypeScript.Scanner {
|
||||
|
||||
function scan(allowContextualToken: boolean): ISyntaxToken {
|
||||
var fullStart = index;
|
||||
var leadingTriviaInfo = scanTriviaInfo(/*isTrailing: */ false);
|
||||
var leadingTriviaInfo = scanTriviaInfo();
|
||||
|
||||
var start = index;
|
||||
var kindAndIsVariableWidth = scanSyntaxKind(allowContextualToken);
|
||||
|
||||
var end = index;
|
||||
var trailingTriviaInfo = scanTriviaInfo(/*isTrailing: */true);
|
||||
|
||||
var fullWidth = index - fullStart;
|
||||
var fullEnd = index;
|
||||
var fullWidth = fullEnd - fullStart;
|
||||
|
||||
// If we have no trivia, and we are a fixed width token kind, and our size isn't too
|
||||
// large, and we're a real fixed width token (and not something like "\u0076ar").
|
||||
@ -399,34 +347,21 @@ module TypeScript.Scanner {
|
||||
var isFixedWidth = kind >= SyntaxKind.FirstFixedWidth && kind <= SyntaxKind.LastFixedWidth &&
|
||||
((kindAndIsVariableWidth & ScannerConstants.IsVariableWidthMask) === 0);
|
||||
|
||||
if (isFixedWidth &&
|
||||
leadingTriviaInfo === 0 && trailingTriviaInfo === 0 &&
|
||||
fullStart <= ScannerConstants.FixedWidthTokenMaxFullStart &&
|
||||
(kindAndIsVariableWidth & ScannerConstants.IsVariableWidthMask) === 0) {
|
||||
|
||||
return new FixedWidthTokenWithNoTrivia((fullStart << ScannerConstants.FixedWidthTokenFullStartShift) | kind);
|
||||
if (isFixedWidth && leadingTriviaInfo === 0) {
|
||||
return new FixedWidthTokenWithNoTrivia(fullStart, kind);
|
||||
}
|
||||
else {
|
||||
// inline the packing logic for perf.
|
||||
var packedFullStartAndTriviaInfo = (fullStart << ScannerConstants.LargeTokenFullStartShift) |
|
||||
leadingTriviaInfo | (trailingTriviaInfo << 2);
|
||||
|
||||
var packedFullWidthAndKind = (fullWidth << ScannerConstants.LargeTokenFullWidthShift) | kind;
|
||||
var cachedText = isFixedWidth ? undefined : text.substr(start, end - start);
|
||||
return new LargeScannerToken(packedFullStartAndTriviaInfo, packedFullWidthAndKind, cachedText);
|
||||
var packedFullWidthAndInfo = largeTokenPackData(fullWidth, leadingTriviaInfo);
|
||||
var cachedText = isFixedWidth ? undefined : text.substr(start, fullEnd - start);
|
||||
return new LargeScannerToken(fullStart, kind, packedFullWidthAndInfo, cachedText);
|
||||
}
|
||||
}
|
||||
|
||||
function scanTrivia(parent: IScannerToken, text: ISimpleText, isTrailing: boolean): ISyntaxTriviaList {
|
||||
function scanTrivia(parent: IScannerToken, text: ISimpleText): ISyntaxTriviaList {
|
||||
var tokenFullStart = parent.fullStart();
|
||||
var tokenStart = tokenFullStart + leadingTriviaWidth(parent, text)
|
||||
|
||||
if (isTrailing) {
|
||||
reset(text, tokenStart + parent.text().length, tokenFullStart + parent.fullWidth());
|
||||
}
|
||||
else {
|
||||
reset(text, tokenFullStart, tokenStart);
|
||||
}
|
||||
reset(text, tokenFullStart, tokenStart);
|
||||
// Debug.assert(length > 0);
|
||||
|
||||
// Keep this exactly in sync with scanTriviaInfo
|
||||
@ -483,15 +418,7 @@ module TypeScript.Scanner {
|
||||
case CharacterCodes.paragraphSeparator:
|
||||
case CharacterCodes.lineSeparator:
|
||||
trivia.push(scanLineTerminatorSequenceTrivia(ch));
|
||||
|
||||
// If we're consuming leading trivia, then we will continue consuming more
|
||||
// trivia (including newlines) up to the first token we see. If we're
|
||||
// consuming trailing trivia, then we break after the first newline we see.
|
||||
if (!isTrailing) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
continue;
|
||||
|
||||
default:
|
||||
throw Errors.invalidOperation();
|
||||
@ -508,7 +435,7 @@ module TypeScript.Scanner {
|
||||
|
||||
// Returns 0 if there was no trivia, or 1 if there was trivia. Returned as an int instead
|
||||
// of a boolean because we'll need a numerical value later on to store in our tokens.
|
||||
function scanTriviaInfo(isTrailing: boolean): number {
|
||||
function scanTriviaInfo(): number {
|
||||
// Keep this exactly in sync with scanTrivia
|
||||
var result = 0;
|
||||
var _end = end;
|
||||
@ -523,7 +450,7 @@ module TypeScript.Scanner {
|
||||
case CharacterCodes.formFeed:
|
||||
index++;
|
||||
// we have trivia
|
||||
result |= 1;
|
||||
result |= ScannerConstants.WhitespaceTrivia;
|
||||
continue;
|
||||
|
||||
case CharacterCodes.carriageReturn:
|
||||
@ -532,18 +459,12 @@ module TypeScript.Scanner {
|
||||
}
|
||||
// fall through.
|
||||
case CharacterCodes.lineFeed:
|
||||
case CharacterCodes.paragraphSeparator:
|
||||
case CharacterCodes.lineSeparator:
|
||||
index++;
|
||||
|
||||
// we have trivia
|
||||
result |= 1;
|
||||
|
||||
// If we're consuming leading trivia, then we will continue consuming more
|
||||
// trivia (including newlines) up to the first token we see. If we're
|
||||
// consuming trailing trivia, then we break after the first newline we see.
|
||||
if (isTrailing) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result |= ScannerConstants.NewlineTrivia;
|
||||
continue;
|
||||
|
||||
case CharacterCodes.slash:
|
||||
@ -551,14 +472,14 @@ module TypeScript.Scanner {
|
||||
var ch2 = str.charCodeAt(index + 1);
|
||||
if (ch2 === CharacterCodes.slash) {
|
||||
// we have a comment, and we have trivia
|
||||
result |= 3;
|
||||
result |= ScannerConstants.CommentTrivia;
|
||||
skipSingleLineCommentTrivia();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch2 === CharacterCodes.asterisk) {
|
||||
// we have a comment, and we have trivia
|
||||
result |= 3;
|
||||
result |= ScannerConstants.CommentTrivia;
|
||||
skipMultiLineCommentTrivia();
|
||||
continue;
|
||||
}
|
||||
@ -568,8 +489,8 @@ module TypeScript.Scanner {
|
||||
return result;
|
||||
|
||||
default:
|
||||
if (ch > CharacterCodes.maxAsciiCharacter && slowScanTriviaInfo(ch)) {
|
||||
result |= 1;
|
||||
if (ch > CharacterCodes.maxAsciiCharacter && slowScanWhitespaceTriviaInfo(ch)) {
|
||||
result |= ScannerConstants.WhitespaceTrivia;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -580,7 +501,7 @@ module TypeScript.Scanner {
|
||||
return result;
|
||||
}
|
||||
|
||||
function slowScanTriviaInfo(ch: number): boolean {
|
||||
function slowScanWhitespaceTriviaInfo(ch: number): boolean {
|
||||
switch (ch) {
|
||||
case CharacterCodes.nonBreakingSpace:
|
||||
case CharacterCodes.enQuad:
|
||||
@ -598,8 +519,6 @@ module TypeScript.Scanner {
|
||||
case CharacterCodes.narrowNoBreakSpace:
|
||||
case CharacterCodes.ideographicSpace:
|
||||
case CharacterCodes.byteOrderMark:
|
||||
case CharacterCodes.paragraphSeparator:
|
||||
case CharacterCodes.lineSeparator:
|
||||
index++;
|
||||
return true;
|
||||
|
||||
@ -694,26 +613,31 @@ module TypeScript.Scanner {
|
||||
return createTrivia(SyntaxKind.MultiLineCommentTrivia, absoluteStartIndex);
|
||||
}
|
||||
|
||||
function skipMultiLineCommentTrivia(): number {
|
||||
function skipMultiLineCommentTrivia(): void {
|
||||
// The '2' is for the "/*" we consumed.
|
||||
var _index = index + 2;
|
||||
var _end = end;
|
||||
|
||||
index += 2;
|
||||
|
||||
while (true) {
|
||||
if (index === end) {
|
||||
reportDiagnostic(end, 0, DiagnosticCode.AsteriskSlash_expected, null);
|
||||
return;
|
||||
if (_index === _end) {
|
||||
reportDiagnostic(end, 0, DiagnosticCode._0_expected, ["*/"]);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((index + 1) < end &&
|
||||
str.charCodeAt(index) === CharacterCodes.asterisk &&
|
||||
str.charCodeAt(index + 1) === CharacterCodes.slash) {
|
||||
if ((_index + 1) < _end &&
|
||||
str.charCodeAt(_index) === CharacterCodes.asterisk &&
|
||||
str.charCodeAt(_index + 1) === CharacterCodes.slash) {
|
||||
|
||||
index += 2;
|
||||
return;
|
||||
_index += 2;
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
_index++;
|
||||
}
|
||||
|
||||
index = _index;
|
||||
}
|
||||
|
||||
function scanLineTerminatorSequenceTrivia(ch: number): ISyntaxTrivia {
|
||||
@ -742,10 +666,10 @@ module TypeScript.Scanner {
|
||||
index++;
|
||||
|
||||
switch (character) {
|
||||
case CharacterCodes.exclamation /*33*/: return scanExclamationToken();
|
||||
case CharacterCodes.exclamation/*33*/: return scanExclamationToken();
|
||||
case CharacterCodes.doubleQuote/*34*/: return scanStringLiteral(character);
|
||||
case CharacterCodes.percent /*37*/: return scanPercentToken();
|
||||
case CharacterCodes.ampersand /*38*/: return scanAmpersandToken();
|
||||
case CharacterCodes.percent/*37*/: return scanPercentToken();
|
||||
case CharacterCodes.ampersand/*38*/: return scanAmpersandToken();
|
||||
case CharacterCodes.singleQuote/*39*/: return scanStringLiteral(character);
|
||||
case CharacterCodes.openParen/*40*/: return SyntaxKind.OpenParenToken;
|
||||
case CharacterCodes.closeParen/*41*/: return SyntaxKind.CloseParenToken;
|
||||
@ -771,10 +695,11 @@ module TypeScript.Scanner {
|
||||
case CharacterCodes.openBracket/*91*/: return SyntaxKind.OpenBracketToken;
|
||||
case CharacterCodes.closeBracket/*93*/: return SyntaxKind.CloseBracketToken;
|
||||
case CharacterCodes.caret/*94*/: return scanCaretToken();
|
||||
case CharacterCodes.backtick/*96*/: return scanTemplateToken(character);
|
||||
|
||||
case CharacterCodes.openBrace/*123*/: return SyntaxKind.OpenBraceToken;
|
||||
case CharacterCodes.bar/*124*/: return scanBarToken();
|
||||
case CharacterCodes.closeBrace/*125*/: return SyntaxKind.CloseBraceToken;
|
||||
case CharacterCodes.closeBrace/*125*/: return scanCloseBraceToken(allowContextualToken, character);
|
||||
case CharacterCodes.tilde/*126*/: return SyntaxKind.TildeToken;
|
||||
}
|
||||
|
||||
@ -916,7 +841,7 @@ module TypeScript.Scanner {
|
||||
|
||||
if (languageVersion >= ts.ScriptTarget.ES5) {
|
||||
reportDiagnostic(
|
||||
start, index - start, DiagnosticCode.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher, null);
|
||||
start, index - start, DiagnosticCode.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1073,6 +998,39 @@ module TypeScript.Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
function scanCloseBraceToken(allowContextualToken: boolean, startChar: number): SyntaxKind {
|
||||
return allowContextualToken ? scanTemplateToken(startChar) : SyntaxKind.CloseBraceToken;
|
||||
}
|
||||
|
||||
function scanTemplateToken(startChar: number): SyntaxKind {
|
||||
var startedWithBacktick = startChar === CharacterCodes.backtick;
|
||||
|
||||
while (true) {
|
||||
if (index === end) {
|
||||
// Hit the end of the file.
|
||||
reportDiagnostic(end, 0, DiagnosticCode._0_expected, ["`"]);
|
||||
break;
|
||||
}
|
||||
|
||||
var ch = str.charCodeAt(index);
|
||||
index++;
|
||||
|
||||
if (ch === CharacterCodes.backtick) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ch === CharacterCodes.$ &&
|
||||
index < end &&
|
||||
str.charCodeAt(index) === CharacterCodes.openBrace) {
|
||||
|
||||
index++;
|
||||
return startedWithBacktick ? SyntaxKind.TemplateStartToken : SyntaxKind.TemplateMiddleToken;
|
||||
}
|
||||
}
|
||||
|
||||
return startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateToken : SyntaxKind.TemplateEndToken;
|
||||
}
|
||||
|
||||
function scanAmpersandToken(): SyntaxKind {
|
||||
var character = str.charCodeAt(index);
|
||||
if (character === CharacterCodes.equals) {
|
||||
@ -1223,7 +1181,7 @@ module TypeScript.Scanner {
|
||||
switch (ch) {
|
||||
case CharacterCodes.backslash:
|
||||
// We're now in an escape. Consume the next character we see (unless it's
|
||||
// a newline or null.
|
||||
// a newline or undefined.
|
||||
inEscape = true;
|
||||
continue;
|
||||
|
||||
@ -1364,7 +1322,7 @@ module TypeScript.Scanner {
|
||||
break;
|
||||
}
|
||||
else if (isNaN(ch) || isNewLineCharacter(ch)) {
|
||||
reportDiagnostic(Math.min(index, end), 1, DiagnosticCode.Missing_close_quote_character, null);
|
||||
reportDiagnostic(Math.min(index, end), 1, DiagnosticCode.Missing_close_quote_character, undefined);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
@ -1431,7 +1389,7 @@ module TypeScript.Scanner {
|
||||
var ch2 = str.charCodeAt(index);
|
||||
if (!CharacterInfo.isHexDigit(ch2)) {
|
||||
if (report) {
|
||||
reportDiagnostic(start, index - start, DiagnosticCode.Unrecognized_escape_sequence, null)
|
||||
reportDiagnostic(start, index - start, DiagnosticCode.Unrecognized_escape_sequence, undefined)
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1449,14 +1407,10 @@ module TypeScript.Scanner {
|
||||
var fullEnd = fullStart + token.fullWidth();
|
||||
reset(text, fullStart, fullEnd);
|
||||
|
||||
scanTriviaInfo(/*isTrailing: */ false);
|
||||
scanTriviaInfo();
|
||||
|
||||
var start = index;
|
||||
scanSyntaxKind(isContextualToken(token));
|
||||
var end = index;
|
||||
|
||||
tokenInfo.leadingTriviaWidth = start - fullStart;
|
||||
tokenInfo.width = end - start;
|
||||
}
|
||||
|
||||
reset(text, 0, text.length());
|
||||
@ -1511,30 +1465,30 @@ module TypeScript.Scanner {
|
||||
var rewindPointPool: IScannerRewindPoint[] = [];
|
||||
var rewindPointPoolCount = 0;
|
||||
|
||||
var lastDiagnostic: Diagnostic = null;
|
||||
var lastDiagnostic: Diagnostic = undefined;
|
||||
var reportDiagnostic = (position: number, fullWidth: number, diagnosticKey: string, args: any[]) => {
|
||||
lastDiagnostic = new Diagnostic(fileName, text.lineMap(), position, fullWidth, diagnosticKey, args);
|
||||
};
|
||||
|
||||
// The sliding window that we store tokens in.
|
||||
var slidingWindow = new SlidingWindow(fetchNextItem, ArrayUtilities.createArray(/*defaultWindowSize:*/ 1024, null), null);
|
||||
var slidingWindow = new SlidingWindow(fetchNextItem, ArrayUtilities.createArray(/*defaultWindowSize:*/ 1024, undefined), undefined);
|
||||
|
||||
// The scanner we're pulling tokens from.
|
||||
var scanner = createScanner(languageVersion, text, reportDiagnostic);
|
||||
|
||||
function release() {
|
||||
slidingWindow = null;
|
||||
scanner = null;
|
||||
slidingWindow = undefined;
|
||||
scanner = undefined;
|
||||
_tokenDiagnostics = [];
|
||||
rewindPointPool = [];
|
||||
lastDiagnostic = null;
|
||||
reportDiagnostic = null;
|
||||
lastDiagnostic = undefined;
|
||||
reportDiagnostic = undefined;
|
||||
}
|
||||
|
||||
function currentNode(): ISyntaxNode {
|
||||
// The normal parser source never returns nodes. They're only returned by the
|
||||
// incremental parser source.
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function consumeNode(node: ISyntaxNode): void {
|
||||
@ -1557,7 +1511,7 @@ module TypeScript.Scanner {
|
||||
|
||||
rewindPointPoolCount--;
|
||||
var result = rewindPointPool[rewindPointPoolCount];
|
||||
rewindPointPool[rewindPointPoolCount] = null;
|
||||
rewindPointPool[rewindPointPoolCount] = undefined;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1593,7 +1547,7 @@ module TypeScript.Scanner {
|
||||
// Debug.assert(spaceAvailable > 0);
|
||||
var token = scanner.scan(allowContextualToken);
|
||||
|
||||
if (lastDiagnostic === null) {
|
||||
if (lastDiagnostic === undefined) {
|
||||
return token;
|
||||
}
|
||||
|
||||
@ -1601,7 +1555,7 @@ module TypeScript.Scanner {
|
||||
// it won't be reused in incremental scenarios.
|
||||
|
||||
_tokenDiagnostics.push(lastDiagnostic);
|
||||
lastDiagnostic = null;
|
||||
lastDiagnostic = undefined;
|
||||
return Syntax.realizeToken(token, text);
|
||||
}
|
||||
|
||||
@ -1610,6 +1564,8 @@ module TypeScript.Scanner {
|
||||
}
|
||||
|
||||
function consumeToken(token: ISyntaxToken): void {
|
||||
// Debug.assert(token.fullWidth() > 0 || token.kind === SyntaxKind.EndOfFileToken);
|
||||
|
||||
// Debug.assert(currentToken() === token);
|
||||
_absolutePosition += token.fullWidth();
|
||||
|
||||
@ -1628,22 +1584,24 @@ module TypeScript.Scanner {
|
||||
var diagnostic = _tokenDiagnostics[tokenDiagnosticsLength - 1];
|
||||
if (diagnostic.start() >= position) {
|
||||
tokenDiagnosticsLength--;
|
||||
_tokenDiagnostics.pop();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_tokenDiagnostics.length = tokenDiagnosticsLength;
|
||||
}
|
||||
|
||||
function resetToPosition(absolutePosition: number): void {
|
||||
Debug.assert(absolutePosition <= text.length(), "Trying to set the position outside the bounds of the text!");
|
||||
var resetBackward = absolutePosition <= _absolutePosition;
|
||||
|
||||
_absolutePosition = absolutePosition;
|
||||
|
||||
// First, remove any diagnostics that came after this position.
|
||||
removeDiagnosticsOnOrAfterPosition(absolutePosition);
|
||||
if (resetBackward) {
|
||||
// First, remove any diagnostics that came after this position.
|
||||
removeDiagnosticsOnOrAfterPosition(absolutePosition);
|
||||
}
|
||||
|
||||
// Now, tell our sliding window to throw away all tokens after this position as well.
|
||||
slidingWindow.disgardAllItemsFromCurrentIndexOnwards();
|
||||
@ -1655,7 +1613,7 @@ module TypeScript.Scanner {
|
||||
|
||||
function currentContextualToken(): ISyntaxToken {
|
||||
// We better be on a / or > token right now.
|
||||
// Debug.assert(SyntaxFacts.isAnyDivideToken(currentToken().kind()));
|
||||
// Debug.assert(SyntaxFacts.isAnyDivideToken(currentToken().kind));
|
||||
|
||||
// First, we're going to rewind all our data to the point where this / or /= token started.
|
||||
// That's because if it does turn out to be a regular expression, then any tokens or token
|
||||
@ -1675,7 +1633,7 @@ module TypeScript.Scanner {
|
||||
|
||||
// We have better gotten some sort of regex token. Otherwise, something *very* wrong has
|
||||
// occurred.
|
||||
// Debug.assert(SyntaxFacts.isAnyDivideOrRegularExpressionToken(token.kind()));
|
||||
// Debug.assert(SyntaxFacts.isAnyDivideOrRegularExpressionToken(token.kind));
|
||||
|
||||
return token;
|
||||
}
|
||||
@ -1699,4 +1657,9 @@ module TypeScript.Scanner {
|
||||
resetToPosition: resetToPosition,
|
||||
};
|
||||
}
|
||||
|
||||
var fixedWidthArray = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 4, 5, 8, 8, 7, 6, 2, 4, 5, 7, 3, 8, 2, 2, 10, 3, 4, 6, 6, 4, 5, 4, 3, 6, 3, 4, 5, 4, 5, 5, 4, 6, 7, 6, 5, 10, 9, 3, 7, 7, 9, 6, 6, 5, 3, 7, 11, 7, 3, 6, 7, 6, 3, 6, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 1, 1, 1, 1, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 2, 2, 2, 1, 2];
|
||||
function fixedWidthTokenLength(kind: SyntaxKind) {
|
||||
return fixedWidthArray[kind];
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,8 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export class ScannerUtilities {
|
||||
public static identifierKind(str: string, start: number, length: number): SyntaxKind {
|
||||
export module ScannerUtilities {
|
||||
export function identifierKind(str: string, start: number, length: number): SyntaxKind {
|
||||
switch (length) {
|
||||
case 2: // do, if, in
|
||||
switch(str.charCodeAt(start)) {
|
||||
|
||||
@ -167,7 +167,7 @@ module TypeScript {
|
||||
// Assert disabled because it is actually expensive enugh to affect perf.
|
||||
// Debug.assert(n >= 0);
|
||||
while (this.currentRelativeItemIndex + n >= this.windowCount) {
|
||||
if (!this.addMoreItemsToWindow(/*argument:*/ null)) {
|
||||
if (!this.addMoreItemsToWindow(/*argument:*/ undefined)) {
|
||||
return this.defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,24 +3,13 @@
|
||||
module TypeScript.Syntax {
|
||||
export var _nextSyntaxID: number = 1;
|
||||
|
||||
export function childIndex(parent: ISyntaxElement, child: ISyntaxElement) {
|
||||
for (var i = 0, n = childCount(parent); i < n; i++) {
|
||||
var current = childAt(parent, i);
|
||||
if (current === child) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
|
||||
export function nodeHasSkippedOrMissingTokens(node: ISyntaxNode): boolean {
|
||||
for (var i = 0; i < childCount(node); i++) {
|
||||
var child = childAt(node, i);
|
||||
if (isToken(child)) {
|
||||
var token = <ISyntaxToken>child;
|
||||
// If a token is skipped, return true. Or if it is a missing token. The only empty token that is not missing is EOF
|
||||
if (token.hasSkippedToken() || (width(token) === 0 && token.kind() !== SyntaxKind.EndOfFileToken)) {
|
||||
if (token.hasLeadingSkippedToken() || (fullWidth(token) === 0 && token.kind !== SyntaxKind.EndOfFileToken)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -30,7 +19,7 @@ module TypeScript.Syntax {
|
||||
}
|
||||
|
||||
export function isUnterminatedStringLiteral(token: ISyntaxToken): boolean {
|
||||
if (token && token.kind() === SyntaxKind.StringLiteral) {
|
||||
if (token && token.kind === SyntaxKind.StringLiteral) {
|
||||
var text = token.text();
|
||||
return text.length < 2 || text.charCodeAt(text.length - 1) !== text.charCodeAt(0);
|
||||
}
|
||||
@ -39,7 +28,7 @@ module TypeScript.Syntax {
|
||||
}
|
||||
|
||||
export function isUnterminatedMultilineCommentTrivia(trivia: ISyntaxTrivia): boolean {
|
||||
if (trivia && trivia.kind() === SyntaxKind.MultiLineCommentTrivia) {
|
||||
if (trivia && trivia.kind === SyntaxKind.MultiLineCommentTrivia) {
|
||||
var text = trivia.fullText();
|
||||
return text.length < 4 || text.substring(text.length - 2) !== "*/";
|
||||
}
|
||||
@ -53,145 +42,43 @@ module TypeScript.Syntax {
|
||||
return true;
|
||||
}
|
||||
else if (position === end) {
|
||||
return trivia.kind() === SyntaxKind.SingleLineCommentTrivia || isUnterminatedMultilineCommentTrivia(trivia);
|
||||
return trivia.kind === SyntaxKind.SingleLineCommentTrivia || isUnterminatedMultilineCommentTrivia(trivia);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isEntirelyInsideComment(sourceUnit: SourceUnitSyntax, position: number): boolean {
|
||||
var positionedToken = findToken(sourceUnit, position);
|
||||
var fullStart = positionedToken.fullStart();
|
||||
var triviaList: ISyntaxTriviaList = null;
|
||||
var lastTriviaBeforeToken: ISyntaxTrivia = null;
|
||||
|
||||
if (positionedToken.kind() === SyntaxKind.EndOfFileToken) {
|
||||
// Check if the trivia is leading on the EndOfFile token
|
||||
if (positionedToken.hasLeadingTrivia()) {
|
||||
triviaList = positionedToken.leadingTrivia();
|
||||
}
|
||||
// Or trailing on the previous token
|
||||
else {
|
||||
positionedToken = previousToken(positionedToken);
|
||||
if (positionedToken) {
|
||||
if (positionedToken && positionedToken.hasTrailingTrivia()) {
|
||||
triviaList = positionedToken.trailingTrivia();
|
||||
fullStart = end(positionedToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (position <= (fullStart + positionedToken.leadingTriviaWidth())) {
|
||||
triviaList = positionedToken.leadingTrivia();
|
||||
}
|
||||
else if (position >= (fullStart + width(positionedToken))) {
|
||||
triviaList = positionedToken.trailingTrivia();
|
||||
fullStart = end(positionedToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (triviaList) {
|
||||
// Try to find the trivia matching the position
|
||||
for (var i = 0, n = triviaList.count(); i < n; i++) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
if (position <= fullStart) {
|
||||
// Moved passed the trivia we need
|
||||
break;
|
||||
}
|
||||
else if (position <= fullStart + trivia.fullWidth() && trivia.isComment()) {
|
||||
// Found the comment trivia we were looking for
|
||||
lastTriviaBeforeToken = trivia;
|
||||
break;
|
||||
}
|
||||
|
||||
fullStart += trivia.fullWidth();
|
||||
}
|
||||
}
|
||||
|
||||
return lastTriviaBeforeToken && isEntirelyInsideCommentTrivia(lastTriviaBeforeToken, fullStart, position);
|
||||
}
|
||||
|
||||
export function isEntirelyInStringOrRegularExpressionLiteral(sourceUnit: SourceUnitSyntax, position: number): boolean {
|
||||
var positionedToken = findToken(sourceUnit, position);
|
||||
|
||||
if (positionedToken) {
|
||||
if (positionedToken.kind() === SyntaxKind.EndOfFileToken) {
|
||||
// EndOfFile token, enusre it did not follow an unterminated string literal
|
||||
positionedToken = previousToken(positionedToken);
|
||||
return positionedToken && positionedToken.trailingTriviaWidth() === 0 && isUnterminatedStringLiteral(positionedToken);
|
||||
}
|
||||
else if (position > start(positionedToken)) {
|
||||
// Ensure position falls enterily within the literal if it is terminated, or the line if it is not
|
||||
return (position < end(positionedToken) && (positionedToken.kind() === TypeScript.SyntaxKind.StringLiteral || positionedToken.kind() === TypeScript.SyntaxKind.RegularExpressionLiteral)) ||
|
||||
(position <= end(positionedToken) && isUnterminatedStringLiteral(positionedToken));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function findSkippedTokenOnLeftInTriviaList(positionedToken: ISyntaxToken, position: number, lookInLeadingTriviaList: boolean): ISyntaxToken {
|
||||
var triviaList: TypeScript.ISyntaxTriviaList = null;
|
||||
var fullEnd: number;
|
||||
|
||||
if (lookInLeadingTriviaList) {
|
||||
triviaList = positionedToken.leadingTrivia();
|
||||
fullEnd = positionedToken.fullStart() + triviaList.fullWidth();
|
||||
}
|
||||
else {
|
||||
triviaList = positionedToken.trailingTrivia();
|
||||
fullEnd = TypeScript.fullEnd(positionedToken);
|
||||
}
|
||||
|
||||
if (triviaList && triviaList.hasSkippedToken()) {
|
||||
for (var i = triviaList.count() - 1; i >= 0; i--) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
var triviaWidth = trivia.fullWidth();
|
||||
|
||||
if (trivia.isSkippedToken() && position >= fullEnd) {
|
||||
return trivia.skippedToken();
|
||||
}
|
||||
|
||||
fullEnd -= triviaWidth;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function findSkippedTokenOnLeft(positionedToken: ISyntaxToken, position: number): ISyntaxToken {
|
||||
var positionInLeadingTriviaList = (position < start(positionedToken));
|
||||
return findSkippedTokenOnLeftInTriviaList(positionedToken, position, /*lookInLeadingTriviaList*/ positionInLeadingTriviaList);
|
||||
}
|
||||
|
||||
export function getAncestorOfKind(positionedToken: ISyntaxElement, kind: SyntaxKind): ISyntaxElement {
|
||||
while (positionedToken && positionedToken.parent) {
|
||||
if (positionedToken.parent.kind() === kind) {
|
||||
if (positionedToken.parent.kind === kind) {
|
||||
return positionedToken.parent;
|
||||
}
|
||||
|
||||
positionedToken = positionedToken.parent;
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function hasAncestorOfKind(positionedToken: ISyntaxElement, kind: SyntaxKind): boolean {
|
||||
return getAncestorOfKind(positionedToken, kind) !== null;
|
||||
return !!getAncestorOfKind(positionedToken, kind);
|
||||
}
|
||||
|
||||
export function isIntegerLiteral(expression: IExpressionSyntax): boolean {
|
||||
if (expression) {
|
||||
switch (expression.kind()) {
|
||||
case SyntaxKind.PlusExpression:
|
||||
case SyntaxKind.NegateExpression:
|
||||
// Note: if there is a + or - sign, we can only allow a normal integer following
|
||||
// (and not a hex integer). i.e. -0xA is a legal expression, but it is not a
|
||||
// *literal*.
|
||||
expression = (<PrefixUnaryExpressionSyntax>expression).operand;
|
||||
return isToken(expression) && IntegerUtilities.isInteger((<ISyntaxToken>expression).text());
|
||||
switch (expression.kind) {
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
var prefixExpr = <PrefixUnaryExpressionSyntax>expression;
|
||||
if (prefixExpr.operatorToken.kind == SyntaxKind.PlusToken || prefixExpr.operatorToken.kind === SyntaxKind.MinusToken) {
|
||||
// Note: if there is a + or - sign, we can only allow a normal integer following
|
||||
// (and not a hex integer). i.e. -0xA is a legal expression, but it is not a
|
||||
// *literal*.
|
||||
expression = prefixExpr.operand;
|
||||
return isToken(expression) && IntegerUtilities.isInteger((<ISyntaxToken>expression).text());
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
case SyntaxKind.NumericLiteral:
|
||||
// If it doesn't have a + or -, then either an integer literal or a hex literal
|
||||
@ -207,25 +94,21 @@ module TypeScript.Syntax {
|
||||
export function containingNode(element: ISyntaxElement): ISyntaxNode {
|
||||
var current = element.parent;
|
||||
|
||||
while (current !== null && !isNode(current)) {
|
||||
while (current && !isNode(current)) {
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return <ISyntaxNode>current;
|
||||
}
|
||||
|
||||
export function findTokenOnLeft(element: ISyntaxElement, position: number, includeSkippedTokens: boolean = false): ISyntaxToken {
|
||||
var positionedToken = findToken(element, position, /*includeSkippedTokens*/ false);
|
||||
export function findTokenOnLeft(sourceUnit: SourceUnitSyntax, position: number): ISyntaxToken {
|
||||
var positionedToken = findToken(sourceUnit, position);
|
||||
var _start = start(positionedToken);
|
||||
|
||||
// Position better fall within this token.
|
||||
// Debug.assert(position >= positionedToken.fullStart());
|
||||
// Debug.assert(position < positionedToken.fullEnd() || positionedToken.token().tokenKind === SyntaxKind.EndOfFileToken);
|
||||
|
||||
if (includeSkippedTokens) {
|
||||
positionedToken = findSkippedTokenOnLeft(positionedToken, position) || positionedToken;
|
||||
}
|
||||
|
||||
// if position is after the start of the token, then this token is the token on the left.
|
||||
if (position > _start) {
|
||||
return positionedToken;
|
||||
@ -234,50 +117,24 @@ module TypeScript.Syntax {
|
||||
// we're in the trivia before the start of the token. Need to return the previous token.
|
||||
if (positionedToken.fullStart() === 0) {
|
||||
// Already on the first token. Nothing before us.
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return previousToken(positionedToken, includeSkippedTokens);
|
||||
return previousToken(positionedToken);
|
||||
}
|
||||
|
||||
export function findCompleteTokenOnLeft(element: ISyntaxElement, position: number, includeSkippedTokens: boolean = false): ISyntaxToken {
|
||||
var positionedToken = findToken(element, position, /*includeSkippedTokens*/ false);
|
||||
export function findCompleteTokenOnLeft(sourceUnit: SourceUnitSyntax, position: number): ISyntaxToken {
|
||||
var positionedToken = findToken(sourceUnit, position);
|
||||
|
||||
// Position better fall within this token.
|
||||
// Debug.assert(position >= positionedToken.fullStart());
|
||||
// Debug.assert(position < positionedToken.fullEnd() || positionedToken.token().tokenKind === SyntaxKind.EndOfFileToken);
|
||||
|
||||
if (includeSkippedTokens) {
|
||||
positionedToken = findSkippedTokenOnLeft(positionedToken, position) || positionedToken;
|
||||
}
|
||||
|
||||
// if position is after the end of the token, then this token is the token on the left.
|
||||
if (width(positionedToken) > 0 && position >= end(positionedToken)) {
|
||||
if (width(positionedToken) > 0 && position >= fullEnd(positionedToken)) {
|
||||
return positionedToken;
|
||||
}
|
||||
|
||||
return previousToken(positionedToken, includeSkippedTokens);
|
||||
}
|
||||
|
||||
export function firstTokenInLineContainingPosition(syntaxTree: SyntaxTree, position: number): ISyntaxToken {
|
||||
var current = findToken(syntaxTree.sourceUnit(), position);
|
||||
while (true) {
|
||||
if (isFirstTokenInLine(current, syntaxTree.lineMap())) {
|
||||
break;
|
||||
}
|
||||
|
||||
current = previousToken(current);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
function isFirstTokenInLine(token: ISyntaxToken, lineMap: LineMap): boolean {
|
||||
var _previousToken = previousToken(token);
|
||||
if (_previousToken === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return lineMap.getLineNumberFromPosition(end(_previousToken)) !== lineMap.getLineNumberFromPosition(start(token));
|
||||
return previousToken(positionedToken);
|
||||
}
|
||||
}
|
||||
@ -1,52 +1,12 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
// True if there is only a single instance of this element (and thus can be reused in many
|
||||
// places in a syntax tree). Examples of this include our empty lists. Because empty
|
||||
// lists can be found all over the tree, we want to save on memory by using this single
|
||||
// instance instead of creating new objects for each case. Note: because of this, shared
|
||||
// nodes don't have positions or parents.
|
||||
export function isShared(element: ISyntaxElement): boolean {
|
||||
var kind = element.kind();
|
||||
return (kind === SyntaxKind.List || kind === SyntaxKind.SeparatedList) && (<ISyntaxNodeOrToken[]>element).length === 0;
|
||||
}
|
||||
|
||||
export function childCount(element: ISyntaxElement): number {
|
||||
var kind = element.kind();
|
||||
if (kind === SyntaxKind.List) {
|
||||
return (<ISyntaxNodeOrToken[]>element).length;
|
||||
}
|
||||
else if (kind === SyntaxKind.SeparatedList) {
|
||||
return (<ISyntaxNodeOrToken[]>element).length + (<ISyntaxNodeOrToken[]>element).separators.length;
|
||||
}
|
||||
else if (kind >= SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return nodeMetadata[kind].length;
|
||||
}
|
||||
}
|
||||
|
||||
export function childAt(element: ISyntaxElement, index: number): ISyntaxElement {
|
||||
var kind = element.kind();
|
||||
if (kind === SyntaxKind.List) {
|
||||
return (<ISyntaxNodeOrToken[]>element)[index];
|
||||
}
|
||||
else if (kind === SyntaxKind.SeparatedList) {
|
||||
return (index % 2 === 0) ? (<ISyntaxNodeOrToken[]>element)[index / 2] : (<ISyntaxNodeOrToken[]>element).separators[(index - 1) / 2];
|
||||
}
|
||||
else {
|
||||
// Debug.assert(isNode(element));
|
||||
return (<any>element)[nodeMetadata[element.kind()][index]];
|
||||
}
|
||||
}
|
||||
|
||||
export function syntaxTree(element: ISyntaxElement): SyntaxTree {
|
||||
if (element) {
|
||||
Debug.assert(!isShared(element));
|
||||
// Debug.assert(!isShared(element));
|
||||
|
||||
while (element) {
|
||||
if (element.kind() === SyntaxKind.SourceUnit) {
|
||||
if (element.kind === SyntaxKind.SourceUnit) {
|
||||
return (<SourceUnitSyntax>element).syntaxTree;
|
||||
}
|
||||
|
||||
@ -54,40 +14,52 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function parsedInStrictMode(node: ISyntaxNode): boolean {
|
||||
var info = node.data;
|
||||
export function parsedInStrictModeContext(node: ISyntaxNode): boolean {
|
||||
var info = node.__data;
|
||||
if (info === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info & SyntaxConstants.NodeParsedInStrictModeMask) !== 0;
|
||||
return (info & SyntaxNodeConstants.ParsedInStrictModeContext) !== 0;
|
||||
}
|
||||
|
||||
export function previousToken(token: ISyntaxToken, includeSkippedTokens: boolean = false): ISyntaxToken {
|
||||
if (includeSkippedTokens) {
|
||||
var triviaList = token.leadingTrivia();
|
||||
if (triviaList && triviaList.hasSkippedToken()) {
|
||||
var currentTriviaEndPosition = TypeScript.start(token);
|
||||
for (var i = triviaList.count() - 1; i >= 0; i--) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
if (trivia.isSkippedToken()) {
|
||||
return trivia.skippedToken();
|
||||
}
|
||||
|
||||
currentTriviaEndPosition -= trivia.fullWidth();
|
||||
}
|
||||
}
|
||||
export function parsedInDisallowInContext(node: ISyntaxNode): boolean {
|
||||
var info = node.__data;
|
||||
if (info === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info & SyntaxNodeConstants.ParsedInDisallowInContext) !== 0;
|
||||
}
|
||||
|
||||
export function parsedInYieldContext(node: ISyntaxNode): boolean {
|
||||
var info = node.__data;
|
||||
if (info === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info & SyntaxNodeConstants.ParsedInYieldContext) !== 0;
|
||||
}
|
||||
|
||||
export function parsedInGeneratorParameterContext(node: ISyntaxNode): boolean {
|
||||
var info = node.__data;
|
||||
if (info === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info & SyntaxNodeConstants.ParsedInGeneratorParameterContext) !== 0;
|
||||
}
|
||||
|
||||
export function previousToken(token: ISyntaxToken): ISyntaxToken {
|
||||
var start = token.fullStart();
|
||||
if (start === 0) {
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return findToken(syntaxTree(token).sourceUnit(), start - 1, includeSkippedTokens);
|
||||
return findToken(syntaxTree(token).sourceUnit(), start - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,136 +75,98 @@ module TypeScript {
|
||||
* Note: findToken will always return a non-missing token with width greater than or equal to
|
||||
* 1 (except for EOF). Empty tokens synthesized by the parser are never returned.
|
||||
*/
|
||||
export function findToken(element: ISyntaxElement, position: number, includeSkippedTokens: boolean = false): ISyntaxToken {
|
||||
var endOfFileToken = tryGetEndOfFileAt(element, position);
|
||||
if (endOfFileToken !== null) {
|
||||
return endOfFileToken;
|
||||
}
|
||||
|
||||
if (position < 0 || position >= fullWidth(element)) {
|
||||
export function findToken(sourceUnit: SourceUnitSyntax, position: number): ISyntaxToken {
|
||||
if (position < 0) {
|
||||
throw Errors.argumentOutOfRange("position");
|
||||
}
|
||||
|
||||
var positionedToken = findTokenWorker(element, position);
|
||||
|
||||
if (includeSkippedTokens) {
|
||||
return findSkippedTokenInPositionedToken(positionedToken, position) || positionedToken;
|
||||
var token = findTokenInNodeOrToken(sourceUnit, 0, position);
|
||||
if (token) {
|
||||
Debug.assert(token.fullWidth() > 0);
|
||||
return token;
|
||||
}
|
||||
|
||||
// Could not find a better match
|
||||
return positionedToken;
|
||||
}
|
||||
|
||||
export function findSkippedTokenInPositionedToken(positionedToken: ISyntaxToken, position: number): ISyntaxToken {
|
||||
var positionInLeadingTriviaList = (position < start(positionedToken));
|
||||
return findSkippedTokenInTriviaList(positionedToken, position, /*lookInLeadingTriviaList*/ positionInLeadingTriviaList);
|
||||
}
|
||||
|
||||
export function findSkippedTokenInLeadingTriviaList(positionedToken: ISyntaxToken, position: number): ISyntaxToken {
|
||||
return findSkippedTokenInTriviaList(positionedToken, position, /*lookInLeadingTriviaList*/ true);
|
||||
}
|
||||
|
||||
export function findSkippedTokenInTrailingTriviaList(positionedToken: ISyntaxToken, position: number): ISyntaxToken {
|
||||
return findSkippedTokenInTriviaList(positionedToken, position, /*lookInLeadingTriviaList*/ false);
|
||||
}
|
||||
|
||||
function findSkippedTokenInTriviaList(positionedToken: ISyntaxToken, position: number, lookInLeadingTriviaList: boolean): ISyntaxToken {
|
||||
var triviaList: TypeScript.ISyntaxTriviaList = null;
|
||||
var fullStart: number;
|
||||
|
||||
if (lookInLeadingTriviaList) {
|
||||
triviaList = positionedToken.leadingTrivia();
|
||||
fullStart = positionedToken.fullStart();
|
||||
}
|
||||
else {
|
||||
triviaList = positionedToken.trailingTrivia();
|
||||
fullStart = end(positionedToken);
|
||||
if (position === fullWidth(sourceUnit)) {
|
||||
return sourceUnit.endOfFileToken;
|
||||
}
|
||||
|
||||
if (triviaList && triviaList.hasSkippedToken()) {
|
||||
for (var i = 0, n = triviaList.count(); i < n; i++) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
var triviaWidth = trivia.fullWidth();
|
||||
|
||||
if (trivia.isSkippedToken() && position >= fullStart && position <= fullStart + triviaWidth) {
|
||||
return trivia.skippedToken();
|
||||
}
|
||||
|
||||
fullStart += triviaWidth;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function findTokenWorker(element: ISyntaxElement, position: number): ISyntaxToken {
|
||||
// Debug.assert(position >= 0 && position < this.fullWidth());
|
||||
if (isToken(element)) {
|
||||
Debug.assert(fullWidth(element) > 0);
|
||||
return <ISyntaxToken>element;
|
||||
}
|
||||
|
||||
if (isShared(element)) {
|
||||
// This should never have been called on this element. It has a 0 width, so the client
|
||||
// should have skipped over this.
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
|
||||
// Consider: we could use a binary search here to find the child more quickly.
|
||||
for (var i = 0, n = childCount(element); i < n; i++) {
|
||||
var child = childAt(element, i);
|
||||
|
||||
if (child !== null) {
|
||||
var childFullWidth = fullWidth(child);
|
||||
if (childFullWidth > 0) {
|
||||
var childFullStart = fullStart(child);
|
||||
|
||||
if (position >= childFullStart) {
|
||||
var childFullEnd = childFullStart + childFullWidth;
|
||||
|
||||
if (position < childFullEnd) {
|
||||
return findTokenWorker(child, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (position > fullWidth(sourceUnit)) {
|
||||
throw Errors.argumentOutOfRange("position");
|
||||
}
|
||||
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
|
||||
function findTokenWorker(element: ISyntaxElement, elementPosition: number, position: number): ISyntaxToken {
|
||||
if (isList(element)) {
|
||||
return findTokenInList(<ISyntaxNodeOrToken[]>element, elementPosition, position);
|
||||
}
|
||||
else {
|
||||
return findTokenInNodeOrToken(<ISyntaxNodeOrToken>element, elementPosition, position);
|
||||
}
|
||||
}
|
||||
|
||||
function findTokenInList(list: ISyntaxNodeOrToken[], elementPosition: number, position: number): ISyntaxToken {
|
||||
for (var i = 0, n = list.length; i < n; i++) {
|
||||
var child = list[i];
|
||||
|
||||
var childFullWidth = fullWidth(child);
|
||||
var elementEndPosition = elementPosition + childFullWidth;
|
||||
|
||||
if (position < elementEndPosition) {
|
||||
return findTokenWorker(child, elementPosition, position);
|
||||
}
|
||||
|
||||
elementPosition = elementEndPosition;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
function findTokenInNodeOrToken(nodeOrToken: ISyntaxNodeOrToken, elementPosition: number, position: number): ISyntaxToken {
|
||||
if (isToken(nodeOrToken)) {
|
||||
return <ISyntaxToken>nodeOrToken;
|
||||
}
|
||||
|
||||
for (var i = 0, n = childCount(nodeOrToken); i < n; i++) {
|
||||
var child = nodeOrToken.childAt(i);
|
||||
|
||||
if (child) {
|
||||
var childFullWidth = fullWidth(child);
|
||||
var elementEndPosition = elementPosition + childFullWidth;
|
||||
|
||||
if (position < elementEndPosition) {
|
||||
return findTokenWorker(child, elementPosition, position);
|
||||
}
|
||||
|
||||
elementPosition = elementEndPosition;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function tryGetEndOfFileAt(element: ISyntaxElement, position: number): ISyntaxToken {
|
||||
if (element.kind() === SyntaxKind.SourceUnit && position === fullWidth(element)) {
|
||||
if (element.kind === SyntaxKind.SourceUnit && position === fullWidth(element)) {
|
||||
var sourceUnit = <SourceUnitSyntax>element;
|
||||
return sourceUnit.endOfFileToken;
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function nextToken(token: ISyntaxToken, text?: ISimpleText, includeSkippedTokens: boolean = false): ISyntaxToken {
|
||||
if (token.kind() === SyntaxKind.EndOfFileToken) {
|
||||
return null;
|
||||
export function nextToken(token: ISyntaxToken, text?: ISimpleText): ISyntaxToken {
|
||||
if (token.kind === SyntaxKind.EndOfFileToken) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (includeSkippedTokens) {
|
||||
var triviaList = token.trailingTrivia(text);
|
||||
if (triviaList && triviaList.hasSkippedToken()) {
|
||||
for (var i = 0, n = triviaList.count(); i < n; i++) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
if (trivia.isSkippedToken()) {
|
||||
return trivia.skippedToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return findToken(syntaxTree(token).sourceUnit(), fullEnd(token), includeSkippedTokens);
|
||||
return findToken(syntaxTree(token).sourceUnit(), fullEnd(token));
|
||||
}
|
||||
|
||||
export function isNode(element: ISyntaxElement): boolean {
|
||||
if (element !== null) {
|
||||
var kind = element.kind();
|
||||
if (element) {
|
||||
var kind = element.kind;
|
||||
return kind >= SyntaxKind.FirstNode && kind <= SyntaxKind.LastNode;
|
||||
}
|
||||
|
||||
@ -244,25 +178,21 @@ module TypeScript {
|
||||
}
|
||||
|
||||
export function isToken(element: ISyntaxElement): boolean {
|
||||
if (element !== null) {
|
||||
return isTokenKind(element.kind());
|
||||
if (element) {
|
||||
return isTokenKind(element.kind);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isList(element: ISyntaxElement): boolean {
|
||||
return element !== null && element.kind() === SyntaxKind.List;
|
||||
}
|
||||
|
||||
export function isSeparatedList(element: ISyntaxElement): boolean {
|
||||
return element !== null && element.kind() === SyntaxKind.SeparatedList;
|
||||
return element instanceof Array;
|
||||
}
|
||||
|
||||
export function syntaxID(element: ISyntaxElement): number {
|
||||
if (isShared(element)) {
|
||||
throw Errors.invalidOperation("Should not use shared syntax element as a key.");
|
||||
}
|
||||
//if (isShared(element)) {
|
||||
// throw Errors.invalidOperation("Should not use shared syntax element as a key.");
|
||||
//}
|
||||
|
||||
var obj = <any>element;
|
||||
if (obj._syntaxID === undefined) {
|
||||
@ -301,69 +231,37 @@ module TypeScript {
|
||||
return token ? token.leadingTriviaWidth(text) : 0;
|
||||
}
|
||||
|
||||
export function trailingTriviaWidth(element: ISyntaxElement, text?: ISimpleText): number {
|
||||
var token = lastToken(element);
|
||||
return token ? token.trailingTriviaWidth(text) : 0;
|
||||
}
|
||||
|
||||
export function firstToken(element: ISyntaxElement): ISyntaxToken {
|
||||
if (element) {
|
||||
var kind = element.kind();
|
||||
var kind = element.kind;
|
||||
|
||||
if (isTokenKind(kind)) {
|
||||
return fullWidth(element) > 0 || element.kind() === SyntaxKind.EndOfFileToken ? <ISyntaxToken>element : null;
|
||||
return (<ISyntaxToken>element).fullWidth() > 0 || kind === SyntaxKind.EndOfFileToken ? <ISyntaxToken>element : undefined;
|
||||
}
|
||||
|
||||
if (kind === SyntaxKind.List) {
|
||||
var array = <ISyntaxNodeOrToken[]>element;
|
||||
for (var i = 0, n = array.length; i < n; i++) {
|
||||
var token = firstToken(array[i]);
|
||||
if (token) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (kind === SyntaxKind.SeparatedList) {
|
||||
var array = <ISyntaxNodeOrToken[]>element;
|
||||
var separators = array.separators;
|
||||
for (var i = 0, n = array.length + separators.length; i < n; i++) {
|
||||
var token = firstToken(i % 2 === 0 ? array[i / 2] : separators[(i - 1) / 2]);
|
||||
if (token) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var metadata = nodeMetadata[kind];
|
||||
for (var i = 0, n = metadata.length; i < n; i++) {
|
||||
var child = (<any>element)[metadata[i]];
|
||||
var token = firstToken(child);
|
||||
if (token) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
if (element.kind() === SyntaxKind.SourceUnit) {
|
||||
return (<SourceUnitSyntax>element).endOfFileToken;
|
||||
for (var i = 0, n = childCount(element); i < n; i++) {
|
||||
var token = firstToken(childAt(element, i));
|
||||
if (token) {
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function lastToken(element: ISyntaxElement): ISyntaxToken {
|
||||
if (isToken(element)) {
|
||||
return fullWidth(element) > 0 || element.kind() === SyntaxKind.EndOfFileToken ? <ISyntaxToken>element : null;
|
||||
return fullWidth(element) > 0 || element.kind === SyntaxKind.EndOfFileToken ? <ISyntaxToken>element : undefined;
|
||||
}
|
||||
|
||||
if (element.kind() === SyntaxKind.SourceUnit) {
|
||||
if (element.kind === SyntaxKind.SourceUnit) {
|
||||
return (<SourceUnitSyntax>element).endOfFileToken;
|
||||
}
|
||||
|
||||
for (var i = childCount(element) - 1; i >= 0; i--) {
|
||||
var child = childAt(element, i);
|
||||
if (child !== null) {
|
||||
if (child) {
|
||||
var token = lastToken(child);
|
||||
if (token) {
|
||||
return token;
|
||||
@ -371,11 +269,11 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function fullStart(element: ISyntaxElement): number {
|
||||
Debug.assert(!isShared(element));
|
||||
// Debug.assert(!isShared(element));
|
||||
var token = isToken(element) ? <ISyntaxToken>element : firstToken(element);
|
||||
return token ? token.fullStart() : -1;
|
||||
}
|
||||
@ -385,12 +283,8 @@ module TypeScript {
|
||||
return (<ISyntaxToken>element).fullWidth();
|
||||
}
|
||||
|
||||
if (isShared(element)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var info = data(element);
|
||||
return info >>> SyntaxConstants.NodeFullWidthShift;
|
||||
return (info / SyntaxNodeConstants.FullWidthShift) | 0;
|
||||
}
|
||||
|
||||
export function isIncrementallyUnusable(element: ISyntaxElement): boolean {
|
||||
@ -398,54 +292,74 @@ module TypeScript {
|
||||
return (<ISyntaxToken>element).isIncrementallyUnusable();
|
||||
}
|
||||
|
||||
if (isShared(element)) {
|
||||
// All shared lists are reusable.
|
||||
return false;
|
||||
}
|
||||
|
||||
return (data(element) & SyntaxConstants.NodeIncrementallyUnusableMask) !== 0;
|
||||
return (data(element) & SyntaxNodeConstants.IncrementallyUnusableMask) !== 0;
|
||||
}
|
||||
|
||||
function data(element: ISyntaxElement): number {
|
||||
Debug.assert(isNode(element) || isList(element) || isSeparatedList(element));
|
||||
// Debug.assert(isNode(element) || isList(element));
|
||||
|
||||
// Lists and nodes all have a 'data' element.
|
||||
var dataElement = <{ data: number }><any>element;
|
||||
var dataElement = <ISyntaxNode>element;
|
||||
|
||||
var info = dataElement.data;
|
||||
var info = dataElement.__data;
|
||||
if (info === undefined) {
|
||||
info = 0;
|
||||
}
|
||||
|
||||
if ((info & SyntaxConstants.NodeDataComputed) === 0) {
|
||||
if ((info & SyntaxNodeConstants.DataComputed) === 0) {
|
||||
info |= computeData(element);
|
||||
dataElement.data = info;
|
||||
dataElement.__data = info;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
function computeData(element: ISyntaxElement): number {
|
||||
var slotCount = childCount(element);
|
||||
function combineData(fullWidth: number, isIncrementallyUnusable: boolean) {
|
||||
return (fullWidth * SyntaxNodeConstants.FullWidthShift) +
|
||||
(isIncrementallyUnusable ? SyntaxNodeConstants.IncrementallyUnusableMask : 0) +
|
||||
SyntaxNodeConstants.DataComputed;
|
||||
}
|
||||
|
||||
function listComputeData(list: ISyntaxNodeOrToken[]): number {
|
||||
var fullWidth = 0;
|
||||
var isIncrementallyUnusable = false;
|
||||
|
||||
for (var i = 0, n = list.length; i < n; i++) {
|
||||
var child: ISyntaxElement = list[i];
|
||||
|
||||
fullWidth += TypeScript.fullWidth(child);
|
||||
isIncrementallyUnusable = isIncrementallyUnusable || TypeScript.isIncrementallyUnusable(child);
|
||||
}
|
||||
|
||||
return combineData(fullWidth, isIncrementallyUnusable);
|
||||
}
|
||||
|
||||
function computeData(element: ISyntaxElement): number {
|
||||
if (isList(element)) {
|
||||
return listComputeData(<ISyntaxNodeOrToken[]>element);
|
||||
}
|
||||
else {
|
||||
return nodeOrTokenComputeData(<ISyntaxNodeOrToken>element);
|
||||
}
|
||||
}
|
||||
|
||||
function nodeOrTokenComputeData(nodeOrToken: ISyntaxNodeOrToken) {
|
||||
var fullWidth = 0;
|
||||
var slotCount = nodeOrToken.childCount;
|
||||
|
||||
// If we have no children (like an OmmittedExpressionSyntax), we're automatically not reusable.
|
||||
var isIncrementallyUnusable = slotCount === 0;
|
||||
|
||||
for (var i = 0, n = slotCount; i < n; i++) {
|
||||
var child = childAt(element, i);
|
||||
var child = nodeOrToken.childAt(i);
|
||||
|
||||
if (child) {
|
||||
fullWidth += TypeScript.fullWidth(child);
|
||||
|
||||
isIncrementallyUnusable = isIncrementallyUnusable || TypeScript.isIncrementallyUnusable(child);
|
||||
}
|
||||
}
|
||||
|
||||
return (fullWidth << SyntaxConstants.NodeFullWidthShift)
|
||||
| (isIncrementallyUnusable ? SyntaxConstants.NodeIncrementallyUnusableMask : 0)
|
||||
| SyntaxConstants.NodeDataComputed;
|
||||
return combineData(fullWidth, isIncrementallyUnusable);
|
||||
}
|
||||
|
||||
export function start(element: ISyntaxElement, text?: ISimpleText): number {
|
||||
@ -453,16 +367,11 @@ module TypeScript {
|
||||
return token ? token.fullStart() + token.leadingTriviaWidth(text) : -1;
|
||||
}
|
||||
|
||||
export function end(element: ISyntaxElement, text?: ISimpleText): number {
|
||||
var token = isToken(element) ? <ISyntaxToken>element : lastToken(element);
|
||||
return token ? fullEnd(token) - token.trailingTriviaWidth(text) : -1;
|
||||
}
|
||||
|
||||
export function width(element: ISyntaxElement, text?: ISimpleText): number {
|
||||
if (isToken(element)) {
|
||||
return (<ISyntaxToken>element).text().length;
|
||||
}
|
||||
return fullWidth(element) - leadingTriviaWidth(element, text) - trailingTriviaWidth(element, text);
|
||||
return fullWidth(element) - leadingTriviaWidth(element, text);
|
||||
}
|
||||
|
||||
export function fullEnd(element: ISyntaxElement): number {
|
||||
@ -474,21 +383,22 @@ module TypeScript {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (token1 === null || token2 === null) {
|
||||
if (!token1 || !token2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
var lineMap = text.lineMap();
|
||||
return lineMap.getLineNumberFromPosition(end(token1, text)) !== lineMap.getLineNumberFromPosition(start(token2, text));
|
||||
return lineMap.getLineNumberFromPosition(fullEnd(token1)) !== lineMap.getLineNumberFromPosition(start(token2, text));
|
||||
}
|
||||
|
||||
export interface ISyntaxElement {
|
||||
kind(): SyntaxKind;
|
||||
parent?: ISyntaxElement;
|
||||
kind: SyntaxKind;
|
||||
parent: ISyntaxElement;
|
||||
}
|
||||
|
||||
export interface ISyntaxNode extends ISyntaxNodeOrToken {
|
||||
data: number;
|
||||
__data: number;
|
||||
__cachedTokens: ISyntaxToken[];
|
||||
}
|
||||
|
||||
export interface IModuleReferenceSyntax extends ISyntaxNode {
|
||||
@ -496,6 +406,7 @@ module TypeScript {
|
||||
}
|
||||
|
||||
export interface IModuleElementSyntax extends ISyntaxNode {
|
||||
_moduleElementBrand: any;
|
||||
}
|
||||
|
||||
export interface IStatementSyntax extends IModuleElementSyntax {
|
||||
@ -503,15 +414,28 @@ module TypeScript {
|
||||
}
|
||||
|
||||
export interface ITypeMemberSyntax extends ISyntaxNode {
|
||||
_typeMemberBrand: any;
|
||||
}
|
||||
|
||||
export interface IClassElementSyntax extends ISyntaxNode {
|
||||
_classElementBrand: any;
|
||||
}
|
||||
|
||||
export interface IMemberDeclarationSyntax extends IClassElementSyntax {
|
||||
_memberDeclarationBrand: any;
|
||||
}
|
||||
|
||||
export interface IPropertyAssignmentSyntax extends IClassElementSyntax {
|
||||
export interface IPropertyAssignmentSyntax extends ISyntaxNodeOrToken {
|
||||
_propertyAssignmentBrand: any;
|
||||
}
|
||||
|
||||
export interface IAccessorSyntax extends IPropertyAssignmentSyntax, IMemberDeclarationSyntax {
|
||||
_accessorBrand: any;
|
||||
|
||||
modifiers: ISyntaxToken[];
|
||||
propertyName: IPropertyNameSyntax;
|
||||
callSignature: CallSignatureSyntax;
|
||||
block: BlockSyntax;
|
||||
}
|
||||
|
||||
export interface ISwitchClauseSyntax extends ISyntaxNode {
|
||||
@ -553,5 +477,10 @@ module TypeScript {
|
||||
}
|
||||
|
||||
export interface INameSyntax extends ITypeSyntax {
|
||||
_nameBrand: any;
|
||||
}
|
||||
|
||||
export interface IPropertyNameSyntax extends ISyntaxNodeOrToken {
|
||||
_propertyNameBrand: any;
|
||||
}
|
||||
}
|
||||
@ -134,7 +134,7 @@ module TypeScript.SyntaxFacts {
|
||||
|
||||
export function getText(kind: SyntaxKind): string {
|
||||
var result = kindToText[kind];
|
||||
return result !== undefined ? result : null;
|
||||
return result;// !== undefined ? result : undefined;
|
||||
}
|
||||
|
||||
export function isAnyKeyword(kind: SyntaxKind): boolean {
|
||||
@ -146,114 +146,60 @@ module TypeScript.SyntaxFacts {
|
||||
}
|
||||
|
||||
export function isPrefixUnaryExpressionOperatorToken(tokenKind: SyntaxKind): boolean {
|
||||
return getPrefixUnaryExpressionFromOperatorToken(tokenKind) !== SyntaxKind.None;
|
||||
switch (tokenKind) {
|
||||
case SyntaxKind.PlusToken:
|
||||
case SyntaxKind.MinusToken:
|
||||
case SyntaxKind.TildeToken:
|
||||
case SyntaxKind.ExclamationToken:
|
||||
case SyntaxKind.PlusPlusToken:
|
||||
case SyntaxKind.MinusMinusToken:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function isBinaryExpressionOperatorToken(tokenKind: SyntaxKind): boolean {
|
||||
return getBinaryExpressionFromOperatorToken(tokenKind) !== SyntaxKind.None;
|
||||
}
|
||||
|
||||
export function getPrefixUnaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind {
|
||||
switch (tokenKind) {
|
||||
case SyntaxKind.PlusToken: return SyntaxKind.PlusExpression;
|
||||
case SyntaxKind.MinusToken: return SyntaxKind.NegateExpression;
|
||||
case SyntaxKind.TildeToken: return SyntaxKind.BitwiseNotExpression;
|
||||
case SyntaxKind.ExclamationToken: return SyntaxKind.LogicalNotExpression;
|
||||
case SyntaxKind.PlusPlusToken: return SyntaxKind.PreIncrementExpression;
|
||||
case SyntaxKind.MinusMinusToken: return SyntaxKind.PreDecrementExpression;
|
||||
default: return SyntaxKind.None;
|
||||
}
|
||||
}
|
||||
|
||||
export function getPostfixUnaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind {
|
||||
switch (tokenKind) {
|
||||
case SyntaxKind.PlusPlusToken: return SyntaxKind.PostIncrementExpression;
|
||||
case SyntaxKind.MinusMinusToken: return SyntaxKind.PostDecrementExpression;
|
||||
default: return SyntaxKind.None;
|
||||
}
|
||||
}
|
||||
|
||||
export function getBinaryExpressionFromOperatorToken(tokenKind: SyntaxKind): SyntaxKind {
|
||||
switch (tokenKind) {
|
||||
case SyntaxKind.AsteriskToken: return SyntaxKind.MultiplyExpression;
|
||||
case SyntaxKind.SlashToken: return SyntaxKind.DivideExpression;
|
||||
case SyntaxKind.PercentToken: return SyntaxKind.ModuloExpression;
|
||||
case SyntaxKind.PlusToken: return SyntaxKind.AddExpression;
|
||||
case SyntaxKind.MinusToken: return SyntaxKind.SubtractExpression;
|
||||
case SyntaxKind.LessThanLessThanToken: return SyntaxKind.LeftShiftExpression;
|
||||
case SyntaxKind.GreaterThanGreaterThanToken: return SyntaxKind.SignedRightShiftExpression;
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return SyntaxKind.UnsignedRightShiftExpression;
|
||||
case SyntaxKind.LessThanToken: return SyntaxKind.LessThanExpression;
|
||||
case SyntaxKind.GreaterThanToken: return SyntaxKind.GreaterThanExpression;
|
||||
case SyntaxKind.LessThanEqualsToken: return SyntaxKind.LessThanOrEqualExpression;
|
||||
case SyntaxKind.GreaterThanEqualsToken: return SyntaxKind.GreaterThanOrEqualExpression;
|
||||
case SyntaxKind.InstanceOfKeyword: return SyntaxKind.InstanceOfExpression;
|
||||
case SyntaxKind.InKeyword: return SyntaxKind.InExpression;
|
||||
case SyntaxKind.EqualsEqualsToken: return SyntaxKind.EqualsWithTypeConversionExpression;
|
||||
case SyntaxKind.ExclamationEqualsToken: return SyntaxKind.NotEqualsWithTypeConversionExpression;
|
||||
case SyntaxKind.EqualsEqualsEqualsToken: return SyntaxKind.EqualsExpression;
|
||||
case SyntaxKind.ExclamationEqualsEqualsToken: return SyntaxKind.NotEqualsExpression;
|
||||
case SyntaxKind.AmpersandToken: return SyntaxKind.BitwiseAndExpression;
|
||||
case SyntaxKind.CaretToken: return SyntaxKind.BitwiseExclusiveOrExpression;
|
||||
case SyntaxKind.BarToken: return SyntaxKind.BitwiseOrExpression;
|
||||
case SyntaxKind.AmpersandAmpersandToken: return SyntaxKind.LogicalAndExpression;
|
||||
case SyntaxKind.BarBarToken: return SyntaxKind.LogicalOrExpression;
|
||||
case SyntaxKind.BarEqualsToken: return SyntaxKind.OrAssignmentExpression;
|
||||
case SyntaxKind.AmpersandEqualsToken: return SyntaxKind.AndAssignmentExpression;
|
||||
case SyntaxKind.CaretEqualsToken: return SyntaxKind.ExclusiveOrAssignmentExpression;
|
||||
case SyntaxKind.LessThanLessThanEqualsToken: return SyntaxKind.LeftShiftAssignmentExpression;
|
||||
case SyntaxKind.GreaterThanGreaterThanEqualsToken: return SyntaxKind.SignedRightShiftAssignmentExpression;
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: return SyntaxKind.UnsignedRightShiftAssignmentExpression;
|
||||
case SyntaxKind.PlusEqualsToken: return SyntaxKind.AddAssignmentExpression;
|
||||
case SyntaxKind.MinusEqualsToken: return SyntaxKind.SubtractAssignmentExpression;
|
||||
case SyntaxKind.AsteriskEqualsToken: return SyntaxKind.MultiplyAssignmentExpression;
|
||||
case SyntaxKind.SlashEqualsToken: return SyntaxKind.DivideAssignmentExpression;
|
||||
case SyntaxKind.PercentEqualsToken: return SyntaxKind.ModuloAssignmentExpression;
|
||||
case SyntaxKind.EqualsToken: return SyntaxKind.AssignmentExpression;
|
||||
case SyntaxKind.CommaToken: return SyntaxKind.CommaExpression;
|
||||
default: return SyntaxKind.None;
|
||||
}
|
||||
}
|
||||
|
||||
export function getOperatorTokenFromBinaryExpression(tokenKind: SyntaxKind): SyntaxKind {
|
||||
switch (tokenKind) {
|
||||
case SyntaxKind.MultiplyExpression: return SyntaxKind.AsteriskToken;
|
||||
case SyntaxKind.DivideExpression: return SyntaxKind.SlashToken;
|
||||
case SyntaxKind.ModuloExpression: return SyntaxKind.PercentToken;
|
||||
case SyntaxKind.AddExpression: return SyntaxKind.PlusToken;
|
||||
case SyntaxKind.SubtractExpression: return SyntaxKind.MinusToken;
|
||||
case SyntaxKind.LeftShiftExpression: return SyntaxKind.LessThanLessThanToken;
|
||||
case SyntaxKind.SignedRightShiftExpression: return SyntaxKind.GreaterThanGreaterThanToken;
|
||||
case SyntaxKind.UnsignedRightShiftExpression: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken;
|
||||
case SyntaxKind.LessThanExpression: return SyntaxKind.LessThanToken;
|
||||
case SyntaxKind.GreaterThanExpression: return SyntaxKind.GreaterThanToken;
|
||||
case SyntaxKind.LessThanOrEqualExpression: return SyntaxKind.LessThanEqualsToken;
|
||||
case SyntaxKind.GreaterThanOrEqualExpression: return SyntaxKind.GreaterThanEqualsToken;
|
||||
case SyntaxKind.InstanceOfExpression: return SyntaxKind.InstanceOfKeyword;
|
||||
case SyntaxKind.InExpression: return SyntaxKind.InKeyword;
|
||||
case SyntaxKind.EqualsWithTypeConversionExpression: return SyntaxKind.EqualsEqualsToken;
|
||||
case SyntaxKind.NotEqualsWithTypeConversionExpression: return SyntaxKind.ExclamationEqualsToken;
|
||||
case SyntaxKind.EqualsExpression: return SyntaxKind.EqualsEqualsEqualsToken;
|
||||
case SyntaxKind.NotEqualsExpression: return SyntaxKind.ExclamationEqualsEqualsToken;
|
||||
case SyntaxKind.BitwiseAndExpression: return SyntaxKind.AmpersandToken;
|
||||
case SyntaxKind.BitwiseExclusiveOrExpression: return SyntaxKind.CaretToken;
|
||||
case SyntaxKind.BitwiseOrExpression: return SyntaxKind.BarToken;
|
||||
case SyntaxKind.LogicalAndExpression: return SyntaxKind.AmpersandAmpersandToken;
|
||||
case SyntaxKind.LogicalOrExpression: return SyntaxKind.BarBarToken;
|
||||
case SyntaxKind.OrAssignmentExpression: return SyntaxKind.BarEqualsToken;
|
||||
case SyntaxKind.AndAssignmentExpression: return SyntaxKind.AmpersandEqualsToken;
|
||||
case SyntaxKind.ExclusiveOrAssignmentExpression: return SyntaxKind.CaretEqualsToken;
|
||||
case SyntaxKind.LeftShiftAssignmentExpression: return SyntaxKind.LessThanLessThanEqualsToken;
|
||||
case SyntaxKind.SignedRightShiftAssignmentExpression: return SyntaxKind.GreaterThanGreaterThanEqualsToken;
|
||||
case SyntaxKind.UnsignedRightShiftAssignmentExpression: return SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken;
|
||||
case SyntaxKind.AddAssignmentExpression: return SyntaxKind.PlusEqualsToken;
|
||||
case SyntaxKind.SubtractAssignmentExpression: return SyntaxKind.MinusEqualsToken;
|
||||
case SyntaxKind.MultiplyAssignmentExpression: return SyntaxKind.AsteriskEqualsToken;
|
||||
case SyntaxKind.DivideAssignmentExpression: return SyntaxKind.SlashEqualsToken;
|
||||
case SyntaxKind.ModuloAssignmentExpression: return SyntaxKind.PercentEqualsToken;
|
||||
case SyntaxKind.AssignmentExpression: return SyntaxKind.EqualsToken;
|
||||
case SyntaxKind.CommaExpression: return SyntaxKind.CommaToken;
|
||||
default: return SyntaxKind.None;
|
||||
case SyntaxKind.AsteriskToken:
|
||||
case SyntaxKind.SlashToken:
|
||||
case SyntaxKind.PercentToken:
|
||||
case SyntaxKind.PlusToken:
|
||||
case SyntaxKind.MinusToken:
|
||||
case SyntaxKind.LessThanLessThanToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
||||
case SyntaxKind.LessThanToken:
|
||||
case SyntaxKind.GreaterThanToken:
|
||||
case SyntaxKind.LessThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanEqualsToken:
|
||||
case SyntaxKind.InstanceOfKeyword:
|
||||
case SyntaxKind.InKeyword:
|
||||
case SyntaxKind.EqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsToken:
|
||||
case SyntaxKind.EqualsEqualsEqualsToken:
|
||||
case SyntaxKind.ExclamationEqualsEqualsToken:
|
||||
case SyntaxKind.AmpersandToken:
|
||||
case SyntaxKind.CaretToken:
|
||||
case SyntaxKind.BarToken:
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
case SyntaxKind.BarBarToken:
|
||||
case SyntaxKind.BarEqualsToken:
|
||||
case SyntaxKind.AmpersandEqualsToken:
|
||||
case SyntaxKind.CaretEqualsToken:
|
||||
case SyntaxKind.LessThanLessThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.PlusEqualsToken:
|
||||
case SyntaxKind.MinusEqualsToken:
|
||||
case SyntaxKind.AsteriskEqualsToken:
|
||||
case SyntaxKind.SlashEqualsToken:
|
||||
case SyntaxKind.PercentEqualsToken:
|
||||
case SyntaxKind.EqualsToken:
|
||||
case SyntaxKind.CommaToken:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,16 +2,8 @@
|
||||
|
||||
module TypeScript.SyntaxFacts {
|
||||
export function isDirectivePrologueElement(node: ISyntaxNodeOrToken): boolean {
|
||||
if (node.kind() === SyntaxKind.ExpressionStatement) {
|
||||
var expressionStatement = <ExpressionStatementSyntax>node;
|
||||
var expression = expressionStatement.expression;
|
||||
|
||||
if (expression.kind() === SyntaxKind.StringLiteral) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return node.kind === SyntaxKind.ExpressionStatement &&
|
||||
(<ExpressionStatementSyntax>node).expression.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
export function isUseStrictDirective(node: ISyntaxNodeOrToken): boolean {
|
||||
@ -23,7 +15,7 @@ module TypeScript.SyntaxFacts {
|
||||
}
|
||||
|
||||
export function isIdentifierNameOrAnyKeyword(token: ISyntaxToken): boolean {
|
||||
var tokenKind = token.kind();
|
||||
var tokenKind = token.kind;
|
||||
return tokenKind === SyntaxKind.IdentifierName || SyntaxFacts.isAnyKeyword(tokenKind);
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -5,8 +5,6 @@ module TypeScript {
|
||||
// Variable width tokens, trivia and lists.
|
||||
None,
|
||||
List,
|
||||
SeparatedList,
|
||||
TriviaList,
|
||||
|
||||
// Trivia
|
||||
WhitespaceTrivia,
|
||||
@ -28,6 +26,12 @@ module TypeScript {
|
||||
NumericLiteral,
|
||||
StringLiteral,
|
||||
|
||||
// Template tokens
|
||||
NoSubstitutionTemplateToken,
|
||||
TemplateStartToken,
|
||||
TemplateMiddleToken,
|
||||
TemplateEndToken,
|
||||
|
||||
// All fixed width tokens follow.
|
||||
|
||||
// Keywords
|
||||
@ -159,6 +163,8 @@ module TypeScript {
|
||||
GenericType,
|
||||
TypeQuery,
|
||||
TupleType,
|
||||
UnionType,
|
||||
ParenthesizedType,
|
||||
|
||||
// Module elements.
|
||||
InterfaceDeclaration,
|
||||
@ -207,54 +213,13 @@ module TypeScript {
|
||||
WithStatement,
|
||||
|
||||
// Expressions
|
||||
PlusExpression,
|
||||
NegateExpression,
|
||||
BitwiseNotExpression,
|
||||
LogicalNotExpression,
|
||||
PreIncrementExpression,
|
||||
PreDecrementExpression,
|
||||
PrefixUnaryExpression,
|
||||
DeleteExpression,
|
||||
TypeOfExpression,
|
||||
VoidExpression,
|
||||
CommaExpression,
|
||||
AssignmentExpression,
|
||||
AddAssignmentExpression,
|
||||
SubtractAssignmentExpression,
|
||||
MultiplyAssignmentExpression,
|
||||
DivideAssignmentExpression,
|
||||
ModuloAssignmentExpression,
|
||||
AndAssignmentExpression,
|
||||
ExclusiveOrAssignmentExpression,
|
||||
OrAssignmentExpression,
|
||||
LeftShiftAssignmentExpression,
|
||||
SignedRightShiftAssignmentExpression,
|
||||
UnsignedRightShiftAssignmentExpression,
|
||||
ConditionalExpression,
|
||||
LogicalOrExpression,
|
||||
LogicalAndExpression,
|
||||
BitwiseOrExpression,
|
||||
BitwiseExclusiveOrExpression,
|
||||
BitwiseAndExpression,
|
||||
EqualsWithTypeConversionExpression,
|
||||
NotEqualsWithTypeConversionExpression,
|
||||
EqualsExpression,
|
||||
NotEqualsExpression,
|
||||
LessThanExpression,
|
||||
GreaterThanExpression,
|
||||
LessThanOrEqualExpression,
|
||||
GreaterThanOrEqualExpression,
|
||||
InstanceOfExpression,
|
||||
InExpression,
|
||||
LeftShiftExpression,
|
||||
SignedRightShiftExpression,
|
||||
UnsignedRightShiftExpression,
|
||||
MultiplyExpression,
|
||||
DivideExpression,
|
||||
ModuloExpression,
|
||||
AddExpression,
|
||||
SubtractExpression,
|
||||
PostIncrementExpression,
|
||||
PostDecrementExpression,
|
||||
BinaryExpression,
|
||||
PostfixUnaryExpression,
|
||||
MemberAccessExpression,
|
||||
InvocationExpression,
|
||||
ArrayLiteralExpression,
|
||||
@ -267,6 +232,9 @@ module TypeScript {
|
||||
ElementAccessExpression,
|
||||
FunctionExpression,
|
||||
OmittedExpression,
|
||||
TemplateExpression,
|
||||
TemplateAccessExpression,
|
||||
YieldExpression,
|
||||
|
||||
// Variable declarations
|
||||
VariableDeclaration,
|
||||
@ -279,14 +247,14 @@ module TypeScript {
|
||||
TypeParameterList,
|
||||
|
||||
// Clauses
|
||||
ExtendsHeritageClause,
|
||||
ImplementsHeritageClause,
|
||||
HeritageClause,
|
||||
EqualsValueClause,
|
||||
CaseSwitchClause,
|
||||
DefaultSwitchClause,
|
||||
ElseClause,
|
||||
CatchClause,
|
||||
FinallyClause,
|
||||
TemplateClause,
|
||||
|
||||
// Generics
|
||||
TypeParameter,
|
||||
@ -294,14 +262,13 @@ module TypeScript {
|
||||
|
||||
// Property Assignment
|
||||
SimplePropertyAssignment,
|
||||
// GetAccessorPropertyAssignment,
|
||||
// SetAccessorPropertyAssignment,
|
||||
FunctionPropertyAssignment,
|
||||
|
||||
// Misc.
|
||||
Parameter,
|
||||
EnumElement,
|
||||
TypeAnnotation,
|
||||
ComputedPropertyName,
|
||||
ExternalModuleReference,
|
||||
ModuleNameModuleReference,
|
||||
|
||||
|
||||
@ -1,95 +1,69 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
interface Array<T> {
|
||||
data: number;
|
||||
separators?: TypeScript.ISyntaxToken[];
|
||||
__data: number;
|
||||
|
||||
kind(): TypeScript.SyntaxKind;
|
||||
kind: TypeScript.SyntaxKind;
|
||||
parent: TypeScript.ISyntaxElement;
|
||||
}
|
||||
|
||||
separatorCount(): number;
|
||||
separatorAt(index: number): TypeScript.ISyntaxToken;
|
||||
module TypeScript {
|
||||
export interface ISeparatedSyntaxList<T extends ISyntaxNodeOrToken> extends Array<ISyntaxNodeOrToken> {
|
||||
//separatorCount(): number;
|
||||
//separatorAt(index: number): TypeScript.ISyntaxToken;
|
||||
|
||||
//nonSeparatorCount(): number;
|
||||
//nonSeparatorAt(index: number): T;
|
||||
}
|
||||
}
|
||||
|
||||
module TypeScript {
|
||||
export function separatorCount(list: ISeparatedSyntaxList<ISyntaxNodeOrToken>) {
|
||||
return list === undefined ? 0 : list.length >> 1;
|
||||
}
|
||||
|
||||
export function nonSeparatorCount(list: ISeparatedSyntaxList<ISyntaxNodeOrToken>) {
|
||||
return list === undefined ? 0 : (list.length + 1) >> 1;
|
||||
}
|
||||
|
||||
export function separatorAt(list: ISeparatedSyntaxList<ISyntaxNodeOrToken>, index: number): ISyntaxToken {
|
||||
return <ISyntaxToken>list[(index << 1) + 1];
|
||||
}
|
||||
|
||||
export function nonSeparatorAt<T extends ISyntaxNodeOrToken>(list: ISeparatedSyntaxList<T>, index: number): T {
|
||||
return <T>list[index << 1];
|
||||
}
|
||||
}
|
||||
|
||||
module TypeScript.Syntax {
|
||||
var _emptyList: ISyntaxNodeOrToken[] = [];
|
||||
|
||||
var _emptySeparatedList: ISyntaxNodeOrToken[] = [];
|
||||
var _emptySeparators: ISyntaxToken[] = [];
|
||||
|
||||
_emptySeparatedList.separators = _emptySeparators;
|
||||
|
||||
function assertEmptyLists() {
|
||||
// Debug.assert(_emptyList.length === 0);
|
||||
// var separators = _emptySeparatedList.separators;
|
||||
// Debug.assert(!separators || separators.length === 0);
|
||||
function addArrayPrototypeValue(name: string, val: any) {
|
||||
if (Object.defineProperty && (<any>Array.prototype)[name] === undefined) {
|
||||
Object.defineProperty(Array.prototype, name, { value: val, writable: false });
|
||||
}
|
||||
else {
|
||||
(<any>Array.prototype)[name] = val;
|
||||
}
|
||||
}
|
||||
|
||||
Array.prototype.kind = function () {
|
||||
return this.separators === undefined ? SyntaxKind.List : SyntaxKind.SeparatedList;
|
||||
}
|
||||
|
||||
Array.prototype.separatorCount = function (): number {
|
||||
assertEmptyLists();
|
||||
// Debug.assert(this.kind === SyntaxKind.SeparatedList);
|
||||
return this.separators.length;
|
||||
}
|
||||
|
||||
Array.prototype.separatorAt = function (index: number): ISyntaxToken {
|
||||
assertEmptyLists();
|
||||
// Debug.assert(this.kind === SyntaxKind.SeparatedList);
|
||||
// Debug.assert(index >= 0 && index < this.separators.length);
|
||||
return this.separators[index];
|
||||
}
|
||||
|
||||
export function emptyList<T extends ISyntaxNodeOrToken>(): T[] {
|
||||
return <T[]><any>_emptyList;
|
||||
}
|
||||
|
||||
export function emptySeparatedList<T extends ISyntaxNodeOrToken>(): T[] {
|
||||
return <T[]><any>_emptySeparatedList;
|
||||
}
|
||||
addArrayPrototypeValue("kind", SyntaxKind.List);
|
||||
|
||||
export function list<T extends ISyntaxNodeOrToken>(nodes: T[]): T[] {
|
||||
if (nodes === undefined || nodes === null || nodes.length === 0) {
|
||||
return emptyList<T>();
|
||||
}
|
||||
|
||||
for (var i = 0, n = nodes.length; i < n; i++) {
|
||||
nodes[i].parent = nodes;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function separatedList<T extends ISyntaxNodeOrToken>(nodes: T[], separators: ISyntaxToken[]): T[] {
|
||||
if (nodes === undefined || nodes === null || nodes.length === 0) {
|
||||
return emptySeparatedList<T>();
|
||||
}
|
||||
|
||||
// Debug.assert(separators.length === nodes.length || separators.length == (nodes.length - 1));
|
||||
|
||||
for (var i = 0, n = nodes.length; i < n; i++) {
|
||||
nodes[i].parent = nodes;
|
||||
}
|
||||
|
||||
for (var i = 0, n = separators.length; i < n; i++) {
|
||||
separators[i].parent = nodes;
|
||||
}
|
||||
|
||||
|
||||
nodes.separators = separators.length === 0 ? _emptySeparators : separators;
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function nonSeparatorIndexOf<T extends ISyntaxNodeOrToken>(list: T[], ast: ISyntaxNodeOrToken): number {
|
||||
for (var i = 0, n = list.length; i < n; i++) {
|
||||
if (list[i] === ast) {
|
||||
return i;
|
||||
if (nodes !== undefined) {
|
||||
for (var i = 0, n = nodes.length; i < n; i++) {
|
||||
nodes[i].parent = nodes;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function separatedList<T extends ISyntaxNodeOrToken>(nodesAndTokens: ISyntaxNodeOrToken[]): ISeparatedSyntaxList<T> {
|
||||
if (nodesAndTokens !== undefined) {
|
||||
for (var i = 0, n = nodesAndTokens.length; i < n; i++) {
|
||||
nodesAndTokens[i].parent = nodesAndTokens;
|
||||
}
|
||||
}
|
||||
|
||||
return <ISeparatedSyntaxList<T>>nodesAndTokens;
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export class SyntaxNode implements ISyntaxNodeOrToken {
|
||||
private __kind: SyntaxKind;
|
||||
public data: number;
|
||||
public parent: ISyntaxElement;
|
||||
|
||||
constructor(data: number) {
|
||||
if (data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
public kind(): SyntaxKind {
|
||||
return this.__kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,5 +2,7 @@
|
||||
|
||||
module TypeScript {
|
||||
export interface ISyntaxNodeOrToken extends ISyntaxElement {
|
||||
childCount: number;
|
||||
childAt(index: number): ISyntaxElement;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user