Merge branch 'release-1.4' into compilationSettingsCleanup
This commit is contained in:
commit
2f6bb57137
42 changed files with 17329 additions and 1789 deletions
111
Jakefile
111
Jakefile
|
@ -35,6 +35,7 @@ var compilerSources = [
|
|||
"types.ts",
|
||||
"scanner.ts",
|
||||
"parser.ts",
|
||||
"utilities.ts",
|
||||
"binder.ts",
|
||||
"checker.ts",
|
||||
"emitter.ts",
|
||||
|
@ -47,26 +48,53 @@ var compilerSources = [
|
|||
|
||||
var servicesSources = [
|
||||
"core.ts",
|
||||
"sys.ts",
|
||||
"types.ts",
|
||||
"scanner.ts",
|
||||
"parser.ts",
|
||||
"utilities.ts",
|
||||
"binder.ts",
|
||||
"checker.ts",
|
||||
"emitter.ts"
|
||||
"emitter.ts",
|
||||
"diagnosticInformationMap.generated.ts"
|
||||
].map(function (f) {
|
||||
return path.join(compilerDirectory, f);
|
||||
}).concat([
|
||||
"breakpoints.ts",
|
||||
"navigationBar.ts",
|
||||
"outliningElementsCollector.ts",
|
||||
"services.ts",
|
||||
"shims.ts",
|
||||
"signatureHelp.ts",
|
||||
"utilities.ts",
|
||||
"navigationBar.ts",
|
||||
"outliningElementsCollector.ts"
|
||||
"formatting/formatting.ts",
|
||||
"formatting/formattingContext.ts",
|
||||
"formatting/formattingRequestKind.ts",
|
||||
"formatting/formattingScanner.ts",
|
||||
"formatting/references.ts",
|
||||
"formatting/rule.ts",
|
||||
"formatting/ruleAction.ts",
|
||||
"formatting/ruleDescriptor.ts",
|
||||
"formatting/ruleFlag.ts",
|
||||
"formatting/ruleOperation.ts",
|
||||
"formatting/ruleOperationContext.ts",
|
||||
"formatting/rules.ts",
|
||||
"formatting/rulesMap.ts",
|
||||
"formatting/rulesProvider.ts",
|
||||
"formatting/smartIndenter.ts",
|
||||
"formatting/tokenRange.ts"
|
||||
].map(function (f) {
|
||||
return path.join(servicesDirectory, f);
|
||||
}));
|
||||
|
||||
var definitionsRoots = [
|
||||
"compiler/types.d.ts",
|
||||
"compiler/scanner.d.ts",
|
||||
"compiler/parser.d.ts",
|
||||
"compiler/checker.d.ts",
|
||||
"services/services.d.ts",
|
||||
];
|
||||
|
||||
var harnessSources = [
|
||||
"harness.ts",
|
||||
"sourceMapRecorder.ts",
|
||||
|
@ -148,25 +176,48 @@ var compilerFilename = "tsc.js";
|
|||
* @param prefixes: a list of files to prepend to the target file
|
||||
* @param useBuiltCompiler: true to use the built compiler, false to use the LKG
|
||||
* @param noOutFile: true to compile without using --out
|
||||
* @param generateDeclarations: true to compile using --declaration
|
||||
* @param outDir: true to compile using --outDir
|
||||
* @param keepComments: false to compile using --removeComments
|
||||
* @param callback: a function to execute after the compilation process ends
|
||||
*/
|
||||
function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOutFile, generateDeclarations, callback) {
|
||||
function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOutFile, generateDeclarations, outDir, keepComments, noResolve, callback) {
|
||||
file(outFile, prereqs, function() {
|
||||
var dir = useBuiltCompiler ? builtLocalDirectory : LKGDirectory;
|
||||
var options = "-removeComments --module commonjs -noImplicitAny ";
|
||||
var options = "--module commonjs -noImplicitAny";
|
||||
|
||||
if (!keepComments) {
|
||||
options += " -removeComments";
|
||||
}
|
||||
|
||||
if (generateDeclarations) {
|
||||
options += "--declaration ";
|
||||
options += " --declaration";
|
||||
}
|
||||
|
||||
if (useDebugMode) {
|
||||
options += "--preserveConstEnums ";
|
||||
options += " --preserveConstEnums";
|
||||
}
|
||||
|
||||
if (outDir) {
|
||||
options += " --outDir " + outDir;
|
||||
}
|
||||
|
||||
if (!noOutFile) {
|
||||
options += " --out " + outFile;
|
||||
}
|
||||
|
||||
if(noResolve) {
|
||||
options += " --noResolve";
|
||||
}
|
||||
|
||||
if (useDebugMode) {
|
||||
options += " -sourcemap -mapRoot file:///" + path.resolve(path.dirname(outFile));
|
||||
}
|
||||
|
||||
var cmd = host + " " + dir + compilerFilename + " " + options + " ";
|
||||
cmd = cmd + sources.join(" ") + (!noOutFile ? " -out " + outFile : "");
|
||||
if (useDebugMode) {
|
||||
cmd = cmd + " -sourcemap -mapRoot file:///" + path.resolve(path.dirname(outFile));
|
||||
}
|
||||
cmd = cmd + sources.join(" ");
|
||||
console.log(cmd + "\n");
|
||||
|
||||
var ex = jake.createExec([cmd]);
|
||||
// Add listeners for output and error
|
||||
ex.addListener("stdout", function(output) {
|
||||
|
@ -259,24 +310,38 @@ var tscFile = path.join(builtLocalDirectory, compilerFilename);
|
|||
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
|
||||
|
||||
var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
|
||||
var servicesDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
|
||||
compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources), [copyright], /*useBuiltCompiler*/ true);
|
||||
|
||||
compileFile(servicesFile,
|
||||
servicesSources,
|
||||
[builtLocalDirectory, copyright].concat(servicesSources),
|
||||
[copyright],
|
||||
var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts");
|
||||
var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
|
||||
var tempDirPath = path.join(builtLocalDirectory, "temptempdir");
|
||||
compileFile(nodeDefinitionsFile, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources),
|
||||
/*prefixes*/ undefined,
|
||||
/*useBuiltCompiler*/ true,
|
||||
/*noOutFile*/ false,
|
||||
/*noOutFile*/ true,
|
||||
/*generateDeclarations*/ true,
|
||||
/*callback*/ fixDeclarationFile);
|
||||
/*outDir*/ tempDirPath,
|
||||
/*keepComments*/ true,
|
||||
/*noResolve*/ true,
|
||||
/*callback*/ function () {
|
||||
concatenateFiles(standaloneDefinitionsFile, definitionsRoots.map(function (f) {
|
||||
return path.join(tempDirPath, f);
|
||||
}));
|
||||
prependFile(copyright, standaloneDefinitionsFile);
|
||||
|
||||
function fixDeclarationFile() {
|
||||
fs.appendFileSync(servicesDefinitionsFile, os.EOL + "export = ts;")
|
||||
}
|
||||
// Create the node definition file by replacing 'ts' module with '"typescript"' as a module.
|
||||
jake.cpR(standaloneDefinitionsFile, nodeDefinitionsFile, {silent: true});
|
||||
var definitionFileContents = fs.readFileSync(nodeDefinitionsFile).toString();
|
||||
definitionFileContents = definitionFileContents.replace(/declare module ts/g, 'declare module "typescript"');
|
||||
fs.writeFileSync(nodeDefinitionsFile, definitionFileContents);
|
||||
|
||||
// Delete the temp dir
|
||||
jake.rmRf(tempDirPath, {silent: true});
|
||||
});
|
||||
|
||||
// Local target to build the compiler and services
|
||||
desc("Builds the full compiler and services");
|
||||
task("local", ["generate-diagnostics", "lib", tscFile, servicesFile]);
|
||||
task("local", ["generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile]);
|
||||
|
||||
// Local target to build the compiler and services
|
||||
desc("Sets release mode flag");
|
||||
|
@ -327,7 +392,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", ["clean", "release", "local"].concat(libraryTargets), function() {
|
||||
var expectedFiles = [tscFile, servicesFile, servicesDefinitionsFile].concat(libraryTargets);
|
||||
var expectedFiles = [tscFile, servicesFile, nodeDefinitionsFile, standaloneDefinitionsFile].concat(libraryTargets);
|
||||
var missingFiles = expectedFiles.filter(function (f) {
|
||||
return !fs.existsSync(f);
|
||||
});
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
"url" : "https://github.com/Microsoft/TypeScript.git"
|
||||
},
|
||||
"preferGlobal" : true,
|
||||
"main" : "./bin/tsc.js",
|
||||
"main" : "./bin/typescriptServices.js",
|
||||
"bin" : {
|
||||
"tsc" : "./bin/tsc"
|
||||
},
|
||||
|
|
|
@ -4,57 +4,12 @@
|
|||
/// <reference path="parser.ts"/>
|
||||
/// <reference path="binder.ts"/>
|
||||
/// <reference path="emitter.ts"/>
|
||||
/// <reference path="utilities.ts"/>
|
||||
|
||||
module ts {
|
||||
var nextSymbolId = 1;
|
||||
var nextNodeId = 1;
|
||||
var nextMergeId = 1;
|
||||
|
||||
export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
|
||||
var declarations = symbol.declarations;
|
||||
for (var i = 0; i < declarations.length; i++) {
|
||||
var declaration = declarations[i];
|
||||
if (declaration.kind === kind) {
|
||||
return declaration;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface StringSymbolWriter extends SymbolWriter {
|
||||
string(): string;
|
||||
}
|
||||
|
||||
// Pool writers to avoid needing to allocate them for every symbol we write.
|
||||
var stringWriters: StringSymbolWriter[] = [];
|
||||
export function getSingleLineStringWriter(): StringSymbolWriter {
|
||||
if (stringWriters.length == 0) {
|
||||
var str = "";
|
||||
|
||||
var writeText: (text: string) => void = text => str += text;
|
||||
return {
|
||||
string: () => str,
|
||||
writeKeyword: writeText,
|
||||
writeOperator: writeText,
|
||||
writePunctuation: writeText,
|
||||
writeSpace: writeText,
|
||||
writeStringLiteral: writeText,
|
||||
writeParameter: writeText,
|
||||
writeSymbol: writeText,
|
||||
|
||||
// Completely ignore indentation for string writers. And map newlines to
|
||||
// a single space.
|
||||
writeLine: () => str += " ",
|
||||
increaseIndent: () => { },
|
||||
decreaseIndent: () => { },
|
||||
clear: () => str = "",
|
||||
trackSymbol: () => { }
|
||||
};
|
||||
}
|
||||
|
||||
return stringWriters.pop();
|
||||
}
|
||||
var nextMergeId = 1;
|
||||
|
||||
/// fullTypeCheck denotes if this instance of the typechecker will be used to get semantic diagnostics.
|
||||
/// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors
|
||||
|
@ -1019,11 +974,6 @@ module ts {
|
|||
};
|
||||
}
|
||||
|
||||
function releaseStringWriter(writer: StringSymbolWriter) {
|
||||
writer.clear()
|
||||
stringWriters.push(writer);
|
||||
}
|
||||
|
||||
function writeKeyword(writer: SymbolWriter, kind: SyntaxKind) {
|
||||
writer.writeKeyword(tokenToString(kind));
|
||||
}
|
||||
|
@ -4445,8 +4395,8 @@ module ts {
|
|||
// Get the narrowed type of a given symbol at a given location
|
||||
function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) {
|
||||
var type = getTypeOfSymbol(symbol);
|
||||
// Only narrow when symbol is variable of a structured type
|
||||
if (node && (symbol.flags & SymbolFlags.Variable && type.flags & TypeFlags.Structured)) {
|
||||
// Only narrow when symbol is variable of an object, union, or type parameter type
|
||||
if (node && symbol.flags & SymbolFlags.Variable && type.flags & (TypeFlags.ObjectType | TypeFlags.Union | TypeFlags.TypeParameter)) {
|
||||
loop: while (node.parent) {
|
||||
var child = node;
|
||||
node = node.parent;
|
||||
|
@ -5385,7 +5335,7 @@ module ts {
|
|||
}
|
||||
|
||||
// Fall back to any.
|
||||
if (compilerOptions.noImplicitAny && objectType !== anyType) {
|
||||
if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && objectType !== anyType) {
|
||||
error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type);
|
||||
}
|
||||
|
||||
|
@ -6400,12 +6350,12 @@ module ts {
|
|||
return numberType;
|
||||
}
|
||||
|
||||
// Return true if type is any, an object type, a type parameter, or a union type composed of only those kinds of types
|
||||
// Return true if type an object type, a type parameter, or a union type composed of only those kinds of types
|
||||
function isStructuredType(type: Type): boolean {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
return !forEach((<UnionType>type).types, t => !isStructuredType(t));
|
||||
}
|
||||
return (type.flags & TypeFlags.Structured) !== 0;
|
||||
return (type.flags & (TypeFlags.ObjectType | TypeFlags.TypeParameter)) !== 0;
|
||||
}
|
||||
|
||||
function isConstEnumObjectType(type: Type) : boolean {
|
||||
|
@ -6422,11 +6372,11 @@ module ts {
|
|||
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
|
||||
// The result is always of the Boolean primitive type.
|
||||
// NOTE: do not raise error if leftType is unknown as related error was already reported
|
||||
if (leftType !== unknownType && !isStructuredType(leftType)) {
|
||||
if (!(leftType.flags & TypeFlags.Any || isStructuredType(leftType))) {
|
||||
error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
// NOTE: do not raise error if right is unknown as related error was already reported
|
||||
if (rightType !== unknownType && rightType !== anyType && !isTypeSubtypeOf(rightType, globalFunctionType)) {
|
||||
if (!(rightType.flags & TypeFlags.Any || isTypeSubtypeOf(rightType, globalFunctionType))) {
|
||||
error(node.right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type);
|
||||
}
|
||||
return booleanType;
|
||||
|
@ -6440,7 +6390,7 @@ module ts {
|
|||
if (leftType !== anyType && leftType !== stringType && leftType !== numberType) {
|
||||
error(node.left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_types_any_string_or_number);
|
||||
}
|
||||
if (!isStructuredType(rightType)) {
|
||||
if (!(rightType.flags & TypeFlags.Any || isStructuredType(rightType))) {
|
||||
error(node.right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
return booleanType;
|
||||
|
@ -7796,7 +7746,7 @@ module ts {
|
|||
var exprType = checkExpression(node.expression);
|
||||
// unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved
|
||||
// in this case error about missing name is already reported - do not report extra one
|
||||
if (!isStructuredType(exprType) && exprType !== unknownType) {
|
||||
if (!(exprType.flags & TypeFlags.Any || isStructuredType(exprType))) {
|
||||
error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,11 @@ module ts {
|
|||
description: Diagnostics.Redirect_output_structure_to_the_directory,
|
||||
paramType: Diagnostics.DIRECTORY,
|
||||
},
|
||||
{
|
||||
name: "preserveConstEnums",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code
|
||||
},
|
||||
{
|
||||
name: "removeComments",
|
||||
type: "boolean",
|
||||
|
@ -104,6 +109,11 @@ module ts {
|
|||
description: Diagnostics.Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations,
|
||||
paramType: Diagnostics.LOCATION,
|
||||
},
|
||||
{
|
||||
name: "suppressImplicitAnyIndexErrors",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures,
|
||||
},
|
||||
{
|
||||
name: "target",
|
||||
shortName: "t",
|
||||
|
@ -124,13 +134,8 @@ module ts {
|
|||
type: "boolean",
|
||||
description: Diagnostics.Watch_input_files,
|
||||
},
|
||||
{
|
||||
name: "preserveConstEnums",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
var shortOptionNames: Map<string> = {};
|
||||
var optionNameMap: Map<CommandLineOption> = {};
|
||||
|
||||
|
|
|
@ -15,10 +15,6 @@ module ts {
|
|||
True = -1
|
||||
}
|
||||
|
||||
export interface Map<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
export const enum Comparison {
|
||||
LessThan = -1,
|
||||
EqualTo = 0,
|
||||
|
|
|
@ -411,6 +411,7 @@ module ts {
|
|||
Warn_on_expressions_and_declarations_with_an_implied_any_type: { code: 6052, category: DiagnosticCategory.Message, key: "Warn on expressions and declarations with an implied 'any' type." },
|
||||
File_0_not_found: { code: 6053, category: DiagnosticCategory.Error, key: "File '{0}' not found." },
|
||||
File_0_must_have_extension_ts_or_d_ts: { code: 6054, category: DiagnosticCategory.Error, key: "File '{0}' must have extension '.ts' or '.d.ts'." },
|
||||
Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures: { code: 6055, category: DiagnosticCategory.Message, key: "Suppress noImplicitAny errors for indexing objects lacking index signatures." },
|
||||
Variable_0_implicitly_has_an_1_type: { code: 7005, category: DiagnosticCategory.Error, key: "Variable '{0}' implicitly has an '{1}' type." },
|
||||
Parameter_0_implicitly_has_an_1_type: { code: 7006, category: DiagnosticCategory.Error, key: "Parameter '{0}' implicitly has an '{1}' type." },
|
||||
Member_0_implicitly_has_an_1_type: { code: 7008, category: DiagnosticCategory.Error, key: "Member '{0}' implicitly has an '{1}' type." },
|
||||
|
|
|
@ -1643,6 +1643,10 @@
|
|||
"category": "Error",
|
||||
"code": 6054
|
||||
},
|
||||
"Suppress noImplicitAny errors for indexing objects lacking index signatures.": {
|
||||
"category": "Message",
|
||||
"code": 6055
|
||||
},
|
||||
|
||||
"Variable '{0}' implicitly has an '{1}' type.": {
|
||||
"category": "Error",
|
||||
|
|
|
@ -1,41 +1,11 @@
|
|||
/// <reference path="types.ts"/>
|
||||
/// <reference path="core.ts"/>
|
||||
/// <reference path="scanner.ts"/>
|
||||
/// <reference path="utilities.ts"/>
|
||||
|
||||
module ts {
|
||||
var nodeConstructors = new Array<new () => Node>(SyntaxKind.Count);
|
||||
|
||||
export function getFullWidth(node: Node) {
|
||||
return node.end - node.pos;
|
||||
}
|
||||
|
||||
function hasFlag(val: number, flag: number): boolean {
|
||||
return (val & flag) !== 0;
|
||||
}
|
||||
|
||||
// Returns true if this node contains a parse error anywhere underneath it.
|
||||
export function containsParseError(node: Node): boolean {
|
||||
if (!hasFlag(node.parserContextFlags, ParserContextFlags.HasPropagatedChildContainsErrorFlag)) {
|
||||
// A node is considered to contain a parse error if:
|
||||
// a) the parser explicitly marked that it had an error
|
||||
// b) any of it's children reported that it had an error.
|
||||
var val = hasFlag(node.parserContextFlags, ParserContextFlags.ContainsError) ||
|
||||
forEachChild(node, containsParseError);
|
||||
|
||||
// If so, mark ourselves accordingly.
|
||||
if (val) {
|
||||
node.parserContextFlags |= ParserContextFlags.ContainsError;
|
||||
}
|
||||
|
||||
// Also mark that we've propogated the child information to this node. This way we can
|
||||
// always consult the bit directly on this node without needing to check its children
|
||||
// again.
|
||||
node.parserContextFlags |= ParserContextFlags.HasPropagatedChildContainsErrorFlag;
|
||||
}
|
||||
|
||||
return hasFlag(node.parserContextFlags, ParserContextFlags.ContainsError);
|
||||
}
|
||||
|
||||
export function getNodeConstructor(kind: SyntaxKind): new () => Node {
|
||||
return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind));
|
||||
}
|
||||
|
@ -54,181 +24,6 @@ module ts {
|
|||
amdModuleName: string;
|
||||
}
|
||||
|
||||
export function getSourceFileOfNode(node: Node): SourceFile {
|
||||
while (node && node.kind !== SyntaxKind.SourceFile) node = node.parent;
|
||||
return <SourceFile>node;
|
||||
}
|
||||
|
||||
// This is a useful function for debugging purposes.
|
||||
export function nodePosToString(node: Node): string {
|
||||
var file = getSourceFileOfNode(node);
|
||||
var loc = file.getLineAndCharacterFromPosition(node.pos);
|
||||
return file.filename + "(" + loc.line + "," + loc.character + ")";
|
||||
}
|
||||
|
||||
export function getStartPosOfNode(node: Node): number {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
export function isMissingNode(node: Node) {
|
||||
return node.pos === node.end && node.kind !== SyntaxKind.EndOfFileToken;
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
|
||||
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
|
||||
// want to skip trivia because this will launch us forward to the next token.
|
||||
if (isMissingNode(node)) {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos);
|
||||
}
|
||||
|
||||
export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node): string {
|
||||
if (isMissingNode(node)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var text = sourceFile.text;
|
||||
return text.substring(skipTrivia(text, node.pos), node.end);
|
||||
}
|
||||
|
||||
export function getTextOfNodeFromSourceText(sourceText: string, node: Node): string {
|
||||
if (isMissingNode(node)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return sourceText.substring(skipTrivia(sourceText, node.pos), node.end);
|
||||
}
|
||||
|
||||
export function getTextOfNode(node: Node): string {
|
||||
return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node);
|
||||
}
|
||||
|
||||
// Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__'
|
||||
export function escapeIdentifier(identifier: string): string {
|
||||
return identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier;
|
||||
}
|
||||
|
||||
// Remove extra underscore from escaped identifier
|
||||
export function unescapeIdentifier(identifier: string): string {
|
||||
return identifier.length >= 3 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ && identifier.charCodeAt(2) === CharacterCodes._ ? identifier.substr(1) : identifier;
|
||||
}
|
||||
|
||||
// Return display name of an identifier
|
||||
// Computed property names will just be emitted as "[<expr>]", where <expr> is the source
|
||||
// text of the expression in the computed property.
|
||||
export function declarationNameToString(name: DeclarationName) {
|
||||
return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name);
|
||||
}
|
||||
|
||||
export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): Diagnostic {
|
||||
node = getErrorSpanForNode(node);
|
||||
var file = getSourceFileOfNode(node);
|
||||
|
||||
var start = getFullWidth(node) === 0 ? node.pos : skipTrivia(file.text, node.pos);
|
||||
var length = node.end - start;
|
||||
|
||||
return createFileDiagnostic(file, start, length, message, arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain, newLine: string): Diagnostic {
|
||||
node = getErrorSpanForNode(node);
|
||||
var file = getSourceFileOfNode(node);
|
||||
var start = skipTrivia(file.text, node.pos);
|
||||
var length = node.end - start;
|
||||
return flattenDiagnosticChain(file, start, length, messageChain, newLine);
|
||||
}
|
||||
|
||||
export function getErrorSpanForNode(node: Node): Node {
|
||||
var errorSpan: Node;
|
||||
switch (node.kind) {
|
||||
// This list is a work in progress. Add missing node kinds to improve their error
|
||||
// spans.
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.EnumMember:
|
||||
errorSpan = (<Declaration>node).name;
|
||||
break;
|
||||
}
|
||||
|
||||
// We now have the ideal error span, but it may be a node that is optional and absent
|
||||
// (e.g. the name of a function expression), in which case errorSpan will be undefined.
|
||||
// Alternatively, it might be required and missing (e.g. the name of a module), in which
|
||||
// case its pos will equal its end (length 0). In either of these cases, we should fall
|
||||
// back to the original node that the error was issued on.
|
||||
return errorSpan && errorSpan.pos < errorSpan.end ? errorSpan : node;
|
||||
}
|
||||
|
||||
export function isExternalModule(file: SourceFile): boolean {
|
||||
return file.externalModuleIndicator !== undefined;
|
||||
}
|
||||
|
||||
export function isDeclarationFile(file: SourceFile): boolean {
|
||||
return (file.flags & NodeFlags.DeclarationFile) !== 0;
|
||||
}
|
||||
|
||||
export function isConstEnumDeclaration(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.EnumDeclaration && isConst(node);
|
||||
}
|
||||
|
||||
export function isConst(node: Node): boolean {
|
||||
return !!(node.flags & NodeFlags.Const);
|
||||
}
|
||||
|
||||
export function isLet(node: Node): boolean {
|
||||
return !!(node.flags & NodeFlags.Let);
|
||||
}
|
||||
|
||||
export function isPrologueDirective(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.ExpressionStatement && (<ExpressionStatement>node).expression.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.Identifier &&
|
||||
(<Identifier>node).text &&
|
||||
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
|
||||
}
|
||||
|
||||
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
|
||||
function isUseStrictPrologueDirective(node: Node): boolean {
|
||||
Debug.assert(isPrologueDirective(node));
|
||||
return (<Identifier>(<ExpressionStatement>node).expression).text === "use strict";
|
||||
}
|
||||
|
||||
export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode?: SourceFile) {
|
||||
sourceFileOfNode = sourceFileOfNode || getSourceFileOfNode(node);
|
||||
|
||||
// If parameter/type parameter, the prev token trailing comments are part of this node too
|
||||
if (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) {
|
||||
// e.g. (/** blah */ a, /** blah */ b);
|
||||
return concatenate(getTrailingCommentRanges(sourceFileOfNode.text, node.pos),
|
||||
// e.g.: (
|
||||
// /** blah */ a,
|
||||
// /** blah */ b);
|
||||
getLeadingCommentRanges(sourceFileOfNode.text, node.pos));
|
||||
}
|
||||
else {
|
||||
return getLeadingCommentRanges(sourceFileOfNode.text, node.pos);
|
||||
}
|
||||
}
|
||||
|
||||
export function getJsDocComments(node: Node, sourceFileOfNode: SourceFile) {
|
||||
return filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), isJsDocComment);
|
||||
|
||||
function isJsDocComment(comment: CommentRange) {
|
||||
// True if the comment starts with '/**' but not if it is '/**/'
|
||||
return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk &&
|
||||
sourceFileOfNode.text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash;
|
||||
}
|
||||
}
|
||||
|
||||
export var fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/
|
||||
|
||||
// Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
|
||||
// stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
|
||||
// embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
|
||||
|
@ -473,400 +268,78 @@ module ts {
|
|||
}
|
||||
}
|
||||
|
||||
// Warning: This has the same semantics as the forEach family of functions,
|
||||
// in that traversal terminates in the event that 'visitor' supplies a truthy value.
|
||||
export function forEachReturnStatement<T>(body: Block, visitor: (stmt: ReturnStatement) => T): T {
|
||||
// TODO (drosen, mhegazy): Move to a more appropriate file.
|
||||
export function createCompilerHost(options: CompilerOptions): CompilerHost {
|
||||
var currentDirectory: string;
|
||||
var existingDirectories: Map<boolean> = {};
|
||||
|
||||
return traverse(body);
|
||||
|
||||
function traverse(node: Node): T {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ReturnStatement:
|
||||
return visitor(<ReturnStatement>node);
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.DefaultClause:
|
||||
case SyntaxKind.LabeledStatement:
|
||||
case SyntaxKind.TryStatement:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchClause:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
return forEachChild(node, traverse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isAnyFunction(node: Node): boolean {
|
||||
if (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isFunctionBlock(node: Node) {
|
||||
return node !== undefined && node.kind === SyntaxKind.Block && isAnyFunction(node.parent);
|
||||
}
|
||||
|
||||
export function isObjectLiteralMethod(node: Node) {
|
||||
return node !== undefined && node.kind === SyntaxKind.Method && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
|
||||
}
|
||||
|
||||
export function getContainingFunction(node: Node): FunctionLikeDeclaration {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node || isAnyFunction(node)) {
|
||||
return <FunctionLikeDeclaration>node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if (!includeArrowFunctions) {
|
||||
continue;
|
||||
}
|
||||
// Fall through
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.SourceFile:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getSuperContainer(node: Node): Node {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getInvokedExpression(node: CallLikeExpression): Expression {
|
||||
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
return (<TaggedTemplateExpression>node).tag;
|
||||
function getCanonicalFileName(fileName: string): string {
|
||||
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
||||
// otherwise use toLowerCase as a canonical form.
|
||||
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
// Will either be a CallExpression or NewExpression.
|
||||
return (<CallExpression>node).expression;
|
||||
}
|
||||
// returned by CScript sys environment
|
||||
var unsupportedFileEncodingErrorCode = -2147024809;
|
||||
|
||||
export function isExpression(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.SuperKeyword:
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.VoidExpression:
|
||||
case SyntaxKind.DeleteExpression:
|
||||
case SyntaxKind.TypeOfExpression:
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
case SyntaxKind.BinaryExpression:
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
case SyntaxKind.TemplateExpression:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.OmittedExpression:
|
||||
return true;
|
||||
case SyntaxKind.QualifiedName:
|
||||
while (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
node = node.parent;
|
||||
function getSourceFile(filename: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
|
||||
try {
|
||||
var text = sys.readFile(filename, options.charset);
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
onError(e.number === unsupportedFileEncodingErrorCode ?
|
||||
createCompilerDiagnostic(Diagnostics.Unsupported_file_encoding).messageText :
|
||||
e.message);
|
||||
}
|
||||
text = "";
|
||||
}
|
||||
return text !== undefined ? createSourceFile(filename, text, languageVersion, /*version:*/ "0") : undefined;
|
||||
}
|
||||
|
||||
return node.parent.kind === SyntaxKind.TypeQuery;
|
||||
case SyntaxKind.Identifier:
|
||||
if (node.parent.kind === SyntaxKind.TypeQuery) {
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
|
||||
|
||||
function directoryExists(directoryPath: string): boolean {
|
||||
if (hasProperty(existingDirectories, directoryPath)) {
|
||||
return true;
|
||||
}
|
||||
// fall through
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
var parent = node.parent;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
return (<VariableDeclaration>parent).initializer === node;
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.ThrowStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
return (<ExpressionStatement>parent).expression === node;
|
||||
case SyntaxKind.ForStatement:
|
||||
return (<ForStatement>parent).initializer === node ||
|
||||
(<ForStatement>parent).condition === node ||
|
||||
(<ForStatement>parent).iterator === node;
|
||||
case SyntaxKind.ForInStatement:
|
||||
return (<ForInStatement>parent).variable === node ||
|
||||
(<ForInStatement>parent).expression === node;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
return node === (<TypeAssertion>parent).expression;
|
||||
case SyntaxKind.TemplateSpan:
|
||||
return node === (<TemplateSpan>parent).expression;
|
||||
default:
|
||||
if (isExpression(parent)) {
|
||||
return true;
|
||||
}
|
||||
if (sys.directoryExists(directoryPath)) {
|
||||
existingDirectories[directoryPath] = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isExternalModuleImportDeclaration(node: Node) {
|
||||
return node.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
|
||||
}
|
||||
|
||||
export function getExternalModuleImportDeclarationExpression(node: Node) {
|
||||
Debug.assert(isExternalModuleImportDeclaration(node));
|
||||
return (<ExternalModuleReference>(<ImportDeclaration>node).moduleReference).expression;
|
||||
}
|
||||
|
||||
export function isInternalModuleImportDeclaration(node: Node) {
|
||||
return node.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node).moduleReference.kind !== SyntaxKind.ExternalModuleReference;
|
||||
}
|
||||
|
||||
export function hasDotDotDotToken(node: Node) {
|
||||
return node && node.kind === SyntaxKind.Parameter && (<ParameterDeclaration>node).dotDotDotToken !== undefined;
|
||||
}
|
||||
|
||||
export function hasQuestionToken(node: Node) {
|
||||
if (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
return (<ParameterDeclaration>node).questionToken !== undefined;
|
||||
case SyntaxKind.Method:
|
||||
return (<MethodDeclaration>node).questionToken !== undefined;
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.Property:
|
||||
return (<PropertyDeclaration>node).questionToken !== undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasRestParameters(s: SignatureDeclaration): boolean {
|
||||
return s.parameters.length > 0 && s.parameters[s.parameters.length - 1].dotDotDotToken !== undefined;
|
||||
}
|
||||
|
||||
export function isLiteralKind(kind: SyntaxKind): boolean {
|
||||
return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
|
||||
}
|
||||
|
||||
export function isTextualLiteralKind(kind: SyntaxKind): boolean {
|
||||
return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NoSubstitutionTemplateLiteral;
|
||||
}
|
||||
|
||||
export function isTemplateLiteralKind(kind: SyntaxKind): boolean {
|
||||
return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
|
||||
}
|
||||
|
||||
export function isInAmbientContext(node: Node): boolean {
|
||||
while (node) {
|
||||
if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true;
|
||||
node = node.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isDeclaration(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isStatement(n: Node): boolean {
|
||||
switch(n.kind) {
|
||||
case SyntaxKind.BreakStatement:
|
||||
case SyntaxKind.ContinueStatement:
|
||||
case SyntaxKind.DebuggerStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.EmptyStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.LabeledStatement:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.ThrowKeyword:
|
||||
case SyntaxKind.TryStatement:
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.ExportAssignment:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// True if the given identifier, string literal, or number literal is the name of a declaration node
|
||||
export function isDeclarationOrFunctionExpressionOrCatchVariableName(name: Node): boolean {
|
||||
if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) {
|
||||
return false;
|
||||
}
|
||||
function ensureDirectoriesExist(directoryPath: string) {
|
||||
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
||||
var parentDirectory = getDirectoryPath(directoryPath);
|
||||
ensureDirectoriesExist(parentDirectory);
|
||||
sys.createDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
var parent = name.parent;
|
||||
if (isDeclaration(parent) || parent.kind === SyntaxKind.FunctionExpression) {
|
||||
return (<Declaration>parent).name === name;
|
||||
}
|
||||
|
||||
if (parent.kind === SyntaxKind.CatchClause) {
|
||||
return (<CatchClause>parent).name === name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getClassBaseTypeNode(node: ClassDeclaration) {
|
||||
var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
|
||||
return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined;
|
||||
}
|
||||
|
||||
export function getClassImplementedTypeNodes(node: ClassDeclaration) {
|
||||
var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ImplementsKeyword);
|
||||
return heritageClause ? heritageClause.types : undefined;
|
||||
}
|
||||
|
||||
export function getInterfaceBaseTypeNodes(node: InterfaceDeclaration) {
|
||||
var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
|
||||
return heritageClause ? heritageClause.types : undefined;
|
||||
}
|
||||
|
||||
export function getHeritageClause(clauses: NodeArray<HeritageClause>, kind: SyntaxKind) {
|
||||
if (clauses) {
|
||||
for (var i = 0, n = clauses.length; i < n; i++) {
|
||||
if (clauses[i].token === kind) {
|
||||
return clauses[i];
|
||||
try {
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
onError(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return {
|
||||
getSourceFile,
|
||||
getDefaultLibFilename: options => combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), options.target === ScriptTarget.ES6 ? "lib.es6.d.ts" : "lib.d.ts"),
|
||||
writeFile,
|
||||
getCurrentDirectory: () => currentDirectory || (currentDirectory = sys.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => sys.newLine
|
||||
};
|
||||
}
|
||||
|
||||
export function tryResolveScriptReference(program: Program, sourceFile: SourceFile, reference: FileReference) {
|
||||
if (!program.getCompilerOptions().noResolve) {
|
||||
var referenceFileName = isRootedDiskPath(reference.filename) ? reference.filename : combinePaths(getDirectoryPath(sourceFile.filename), reference.filename);
|
||||
referenceFileName = getNormalizedAbsolutePath(referenceFileName, program.getCompilerHost().getCurrentDirectory());
|
||||
return program.getSourceFile(referenceFileName);
|
||||
}
|
||||
}
|
||||
|
||||
export function getAncestor(node: Node, kind: SyntaxKind): Node {
|
||||
switch (kind) {
|
||||
// special-cases that can be come first
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
while (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return <ClassDeclaration>node;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
// early exit cases - declarations cannot be nested in classes
|
||||
return undefined;
|
||||
default:
|
||||
node = node.parent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
while (node) {
|
||||
if (node.kind === kind) {
|
||||
return node;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const enum ParsingContext {
|
||||
SourceElements, // Elements in source file
|
||||
|
@ -919,68 +392,6 @@ module ts {
|
|||
}
|
||||
};
|
||||
|
||||
export interface ReferencePathMatchResult {
|
||||
fileReference?: FileReference
|
||||
diagnosticMessage?: DiagnosticMessage
|
||||
isNoDefaultLib?: boolean
|
||||
}
|
||||
|
||||
export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult {
|
||||
var simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
|
||||
var isNoDefaultLibRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/gim;
|
||||
if (simpleReferenceRegEx.exec(comment)) {
|
||||
if (isNoDefaultLibRegEx.exec(comment)) {
|
||||
return {
|
||||
isNoDefaultLib: true
|
||||
}
|
||||
}
|
||||
else {
|
||||
var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
|
||||
if (matchResult) {
|
||||
var start = commentRange.pos;
|
||||
var end = commentRange.end;
|
||||
return {
|
||||
fileReference: {
|
||||
pos: start,
|
||||
end: end,
|
||||
filename: matchResult[3]
|
||||
},
|
||||
isNoDefaultLib: false
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax,
|
||||
isNoDefaultLib: false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function isKeyword(token: SyntaxKind): boolean {
|
||||
return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword;
|
||||
}
|
||||
|
||||
export function isTrivia(token: SyntaxKind) {
|
||||
return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken;
|
||||
}
|
||||
|
||||
export function isModifier(token: SyntaxKind): boolean {
|
||||
switch (token) {
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.StaticKeyword:
|
||||
case SyntaxKind.ExportKeyword:
|
||||
case SyntaxKind.DeclareKeyword:
|
||||
case SyntaxKind.ConstKeyword:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function modifierToFlag(token: SyntaxKind): NodeFlags {
|
||||
switch (token) {
|
||||
case SyntaxKind.StaticKeyword: return NodeFlags.Static;
|
||||
|
@ -994,6 +405,18 @@ module ts {
|
|||
return 0;
|
||||
}
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.Identifier &&
|
||||
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
|
||||
}
|
||||
|
||||
/// Should be called only on prologue directives (isPrologueDirective(node) should be true)
|
||||
function isUseStrictPrologueDirective(sourceFile: SourceFile, node: Node): boolean {
|
||||
Debug.assert(isPrologueDirective(node));
|
||||
var nodeText = getSourceTextOfNodeFromSourceFile(sourceFile,(<ExpressionStatement>node).expression);
|
||||
return nodeText === '"use strict"' || nodeText === "'use strict'";
|
||||
}
|
||||
|
||||
export function createSourceFile(filename: string, sourceText: string, languageVersion: ScriptTarget, version: string, isOpen: boolean = false): SourceFile {
|
||||
var token: SyntaxKind;
|
||||
var parsingContext: ParsingContext;
|
||||
|
@ -1651,7 +1074,7 @@ module ts {
|
|||
// test elements only if we are not already in strict mode
|
||||
if (checkForStrictMode && !inStrictModeContext()) {
|
||||
if (isPrologueDirective(element)) {
|
||||
if (isUseStrictPrologueDirective(element)) {
|
||||
if (isUseStrictPrologueDirective(sourceFile, element)) {
|
||||
setStrictModeContext(true);
|
||||
checkForStrictMode = false;
|
||||
}
|
||||
|
|
|
@ -1,252 +1,255 @@
|
|||
|
||||
interface System {
|
||||
args: string[];
|
||||
newLine: string;
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
write(s: string): void;
|
||||
readFile(fileName: string, encoding?: string): string;
|
||||
writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
watchFile?(fileName: string, callback: (fileName: string) => void): FileWatcher;
|
||||
resolvePath(path: string): string;
|
||||
fileExists(path: string): boolean;
|
||||
directoryExists(path: string): boolean;
|
||||
createDirectory(directoryName: string): void;
|
||||
getExecutingFilePath(): string;
|
||||
getCurrentDirectory(): string;
|
||||
getMemoryUsage?(): number;
|
||||
exit(exitCode?: number): void;
|
||||
}
|
||||
module ts {
|
||||
export interface System {
|
||||
args: string[];
|
||||
newLine: string;
|
||||
useCaseSensitiveFileNames: boolean;
|
||||
write(s: string): void;
|
||||
readFile(fileName: string, encoding?: string): string;
|
||||
writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
watchFile? (fileName: string, callback: (fileName: string) => void): FileWatcher;
|
||||
resolvePath(path: string): string;
|
||||
fileExists(path: string): boolean;
|
||||
directoryExists(path: string): boolean;
|
||||
createDirectory(directoryName: string): void;
|
||||
getExecutingFilePath(): string;
|
||||
getCurrentDirectory(): string;
|
||||
getMemoryUsage? (): number;
|
||||
exit(exitCode?: number): void;
|
||||
}
|
||||
|
||||
interface FileWatcher {
|
||||
close(): void;
|
||||
}
|
||||
export interface FileWatcher {
|
||||
close(): void;
|
||||
}
|
||||
|
||||
declare var require: any;
|
||||
declare var module: any;
|
||||
declare var process: any;
|
||||
declare var global: any;
|
||||
declare var require: any;
|
||||
declare var module: any;
|
||||
declare var process: any;
|
||||
declare var global: any;
|
||||
declare var __filename: string;
|
||||
|
||||
var sys: System = (function () {
|
||||
export var sys: System = (function () {
|
||||
|
||||
function getWScriptSystem(): System {
|
||||
function getWScriptSystem(): System {
|
||||
|
||||
var fso = new ActiveXObject("Scripting.FileSystemObject");
|
||||
var fso = new ActiveXObject("Scripting.FileSystemObject");
|
||||
|
||||
var fileStream = new ActiveXObject("ADODB.Stream");
|
||||
fileStream.Type = 2 /*text*/;
|
||||
var fileStream = new ActiveXObject("ADODB.Stream");
|
||||
fileStream.Type = 2 /*text*/;
|
||||
|
||||
var binaryStream = new ActiveXObject("ADODB.Stream");
|
||||
binaryStream.Type = 1 /*binary*/;
|
||||
var binaryStream = new ActiveXObject("ADODB.Stream");
|
||||
binaryStream.Type = 1 /*binary*/;
|
||||
|
||||
var args: string[] = [];
|
||||
for (var i = 0; i < WScript.Arguments.length; i++) {
|
||||
args[i] = WScript.Arguments.Item(i);
|
||||
}
|
||||
|
||||
function readFile(fileName: string, encoding?: string): string {
|
||||
if (!fso.FileExists(fileName)) {
|
||||
return undefined;
|
||||
var args: string[] = [];
|
||||
for (var i = 0; i < WScript.Arguments.length; i++) {
|
||||
args[i] = WScript.Arguments.Item(i);
|
||||
}
|
||||
fileStream.Open();
|
||||
try {
|
||||
if (encoding) {
|
||||
fileStream.Charset = encoding;
|
||||
fileStream.LoadFromFile(fileName);
|
||||
|
||||
function readFile(fileName: string, encoding?: string): string {
|
||||
if (!fso.FileExists(fileName)) {
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
// Load file and read the first two bytes into a string with no interpretation
|
||||
fileStream.Charset = "x-ansi";
|
||||
fileStream.LoadFromFile(fileName);
|
||||
var bom = fileStream.ReadText(2) || "";
|
||||
// Position must be at 0 before encoding can be changed
|
||||
fileStream.Position = 0;
|
||||
// [0xFF,0xFE] and [0xFE,0xFF] mean utf-16 (little or big endian), otherwise default to utf-8
|
||||
fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8";
|
||||
}
|
||||
// ReadText method always strips byte order mark from resulting string
|
||||
return fileStream.ReadText();
|
||||
}
|
||||
catch (e) {
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
fileStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
||||
fileStream.Open();
|
||||
binaryStream.Open();
|
||||
try {
|
||||
// Write characters in UTF-8 encoding
|
||||
fileStream.Charset = "utf-8";
|
||||
fileStream.WriteText(data);
|
||||
// If we don't want the BOM, then skip it by setting the starting location to 3 (size of BOM).
|
||||
// If not, start from position 0, as the BOM will be added automatically when charset==utf8.
|
||||
if (writeByteOrderMark) {
|
||||
fileStream.Position = 0;
|
||||
}
|
||||
else {
|
||||
fileStream.Position = 3;
|
||||
}
|
||||
fileStream.CopyTo(binaryStream);
|
||||
binaryStream.SaveToFile(fileName, 2 /*overwrite*/);
|
||||
}
|
||||
finally {
|
||||
binaryStream.Close();
|
||||
fileStream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
args,
|
||||
newLine: "\r\n",
|
||||
useCaseSensitiveFileNames: false,
|
||||
write(s: string): void {
|
||||
WScript.StdOut.Write(s);
|
||||
},
|
||||
readFile,
|
||||
writeFile,
|
||||
resolvePath(path: string): string {
|
||||
return fso.GetAbsolutePathName(path);
|
||||
},
|
||||
fileExists(path: string): boolean {
|
||||
return fso.FileExists(path);
|
||||
},
|
||||
directoryExists(path: string) {
|
||||
return fso.FolderExists(path);
|
||||
},
|
||||
createDirectory(directoryName: string) {
|
||||
if (!this.directoryExists(directoryName)) {
|
||||
fso.CreateFolder(directoryName);
|
||||
}
|
||||
},
|
||||
getExecutingFilePath() {
|
||||
return WScript.ScriptFullName;
|
||||
},
|
||||
getCurrentDirectory() {
|
||||
return new ActiveXObject("WScript.Shell").CurrentDirectory;
|
||||
},
|
||||
exit(exitCode?: number): void {
|
||||
fileStream.Open();
|
||||
try {
|
||||
WScript.Quit(exitCode);
|
||||
if (encoding) {
|
||||
fileStream.Charset = encoding;
|
||||
fileStream.LoadFromFile(fileName);
|
||||
}
|
||||
else {
|
||||
// Load file and read the first two bytes into a string with no interpretation
|
||||
fileStream.Charset = "x-ansi";
|
||||
fileStream.LoadFromFile(fileName);
|
||||
var bom = fileStream.ReadText(2) || "";
|
||||
// Position must be at 0 before encoding can be changed
|
||||
fileStream.Position = 0;
|
||||
// [0xFF,0xFE] and [0xFE,0xFF] mean utf-16 (little or big endian), otherwise default to utf-8
|
||||
fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8";
|
||||
}
|
||||
// ReadText method always strips byte order mark from resulting string
|
||||
return fileStream.ReadText();
|
||||
}
|
||||
catch (e) {
|
||||
throw e;
|
||||
}
|
||||
finally {
|
||||
fileStream.Close();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function getNodeSystem(): System {
|
||||
var _fs = require("fs");
|
||||
var _path = require("path");
|
||||
var _os = require('os');
|
||||
|
||||
var platform: string = _os.platform();
|
||||
// win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive
|
||||
var useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin";
|
||||
|
||||
function readFile(fileName: string, encoding?: string): string {
|
||||
if (!_fs.existsSync(fileName)) {
|
||||
return undefined;
|
||||
}
|
||||
var buffer = _fs.readFileSync(fileName);
|
||||
var len = buffer.length;
|
||||
if (len >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
|
||||
// Big endian UTF-16 byte order mark detected. Since big endian is not supported by node.js,
|
||||
// flip all byte pairs and treat as little endian.
|
||||
len &= ~1;
|
||||
for (var i = 0; i < len; i += 2) {
|
||||
var temp = buffer[i];
|
||||
buffer[i] = buffer[i + 1];
|
||||
buffer[i + 1] = temp;
|
||||
}
|
||||
return buffer.toString("utf16le", 2);
|
||||
}
|
||||
if (len >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
|
||||
// Little endian UTF-16 byte order mark detected
|
||||
return buffer.toString("utf16le", 2);
|
||||
}
|
||||
if (len >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
|
||||
// UTF-8 byte order mark detected
|
||||
return buffer.toString("utf8", 3);
|
||||
}
|
||||
// Default is UTF-8 with no byte order mark
|
||||
return buffer.toString("utf8");
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
||||
// If a BOM is required, emit one
|
||||
if (writeByteOrderMark) {
|
||||
data = '\uFEFF' + data;
|
||||
}
|
||||
|
||||
_fs.writeFileSync(fileName, data, "utf8");
|
||||
}
|
||||
|
||||
return {
|
||||
args: process.argv.slice(2),
|
||||
newLine: _os.EOL,
|
||||
useCaseSensitiveFileNames: useCaseSensitiveFileNames,
|
||||
write(s: string): void {
|
||||
// 1 is a standard descriptor for stdout
|
||||
_fs.writeSync(1, s);
|
||||
},
|
||||
readFile,
|
||||
writeFile,
|
||||
watchFile: (fileName, callback) => {
|
||||
// watchFile polls a file every 250ms, picking up file notifications.
|
||||
_fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged);
|
||||
|
||||
return {
|
||||
close() { _fs.unwatchFile(fileName, fileChanged); }
|
||||
};
|
||||
|
||||
function fileChanged(curr: any, prev: any) {
|
||||
if (+curr.mtime <= +prev.mtime) {
|
||||
return;
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
||||
fileStream.Open();
|
||||
binaryStream.Open();
|
||||
try {
|
||||
// Write characters in UTF-8 encoding
|
||||
fileStream.Charset = "utf-8";
|
||||
fileStream.WriteText(data);
|
||||
// If we don't want the BOM, then skip it by setting the starting location to 3 (size of BOM).
|
||||
// If not, start from position 0, as the BOM will be added automatically when charset==utf8.
|
||||
if (writeByteOrderMark) {
|
||||
fileStream.Position = 0;
|
||||
}
|
||||
|
||||
callback(fileName);
|
||||
};
|
||||
},
|
||||
resolvePath: function (path: string): string {
|
||||
return _path.resolve(path);
|
||||
},
|
||||
fileExists(path: string): boolean {
|
||||
return _fs.existsSync(path);
|
||||
},
|
||||
directoryExists(path: string) {
|
||||
return _fs.existsSync(path) && _fs.statSync(path).isDirectory();
|
||||
},
|
||||
createDirectory(directoryName: string) {
|
||||
if (!this.directoryExists(directoryName)) {
|
||||
_fs.mkdirSync(directoryName);
|
||||
else {
|
||||
fileStream.Position = 3;
|
||||
}
|
||||
fileStream.CopyTo(binaryStream);
|
||||
binaryStream.SaveToFile(fileName, 2 /*overwrite*/);
|
||||
}
|
||||
},
|
||||
getExecutingFilePath() {
|
||||
return process.mainModule.filename;
|
||||
},
|
||||
getCurrentDirectory() {
|
||||
return (<any>process).cwd();
|
||||
},
|
||||
getMemoryUsage() {
|
||||
if (global.gc) {
|
||||
global.gc();
|
||||
finally {
|
||||
binaryStream.Close();
|
||||
fileStream.Close();
|
||||
}
|
||||
return process.memoryUsage().heapUsed;
|
||||
},
|
||||
exit(exitCode?: number): void {
|
||||
process.exit(exitCode);
|
||||
}
|
||||
};
|
||||
}
|
||||
if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
||||
return getWScriptSystem();
|
||||
}
|
||||
else if (typeof module !== "undefined" && module.exports) {
|
||||
return getNodeSystem();
|
||||
}
|
||||
else {
|
||||
return undefined; // Unsupported host
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
args,
|
||||
newLine: "\r\n",
|
||||
useCaseSensitiveFileNames: false,
|
||||
write(s: string): void {
|
||||
WScript.StdOut.Write(s);
|
||||
},
|
||||
readFile,
|
||||
writeFile,
|
||||
resolvePath(path: string): string {
|
||||
return fso.GetAbsolutePathName(path);
|
||||
},
|
||||
fileExists(path: string): boolean {
|
||||
return fso.FileExists(path);
|
||||
},
|
||||
directoryExists(path: string) {
|
||||
return fso.FolderExists(path);
|
||||
},
|
||||
createDirectory(directoryName: string) {
|
||||
if (!this.directoryExists(directoryName)) {
|
||||
fso.CreateFolder(directoryName);
|
||||
}
|
||||
},
|
||||
getExecutingFilePath() {
|
||||
return WScript.ScriptFullName;
|
||||
},
|
||||
getCurrentDirectory() {
|
||||
return new ActiveXObject("WScript.Shell").CurrentDirectory;
|
||||
},
|
||||
exit(exitCode?: number): void {
|
||||
try {
|
||||
WScript.Quit(exitCode);
|
||||
}
|
||||
catch (e) {
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
function getNodeSystem(): System {
|
||||
var _fs = require("fs");
|
||||
var _path = require("path");
|
||||
var _os = require('os');
|
||||
|
||||
var platform: string = _os.platform();
|
||||
// win32\win64 are case insensitive platforms, MacOS (darwin) by default is also case insensitive
|
||||
var useCaseSensitiveFileNames = platform !== "win32" && platform !== "win64" && platform !== "darwin";
|
||||
|
||||
function readFile(fileName: string, encoding?: string): string {
|
||||
if (!_fs.existsSync(fileName)) {
|
||||
return undefined;
|
||||
}
|
||||
var buffer = _fs.readFileSync(fileName);
|
||||
var len = buffer.length;
|
||||
if (len >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
|
||||
// Big endian UTF-16 byte order mark detected. Since big endian is not supported by node.js,
|
||||
// flip all byte pairs and treat as little endian.
|
||||
len &= ~1;
|
||||
for (var i = 0; i < len; i += 2) {
|
||||
var temp = buffer[i];
|
||||
buffer[i] = buffer[i + 1];
|
||||
buffer[i + 1] = temp;
|
||||
}
|
||||
return buffer.toString("utf16le", 2);
|
||||
}
|
||||
if (len >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
|
||||
// Little endian UTF-16 byte order mark detected
|
||||
return buffer.toString("utf16le", 2);
|
||||
}
|
||||
if (len >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
|
||||
// UTF-8 byte order mark detected
|
||||
return buffer.toString("utf8", 3);
|
||||
}
|
||||
// Default is UTF-8 with no byte order mark
|
||||
return buffer.toString("utf8");
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
|
||||
// If a BOM is required, emit one
|
||||
if (writeByteOrderMark) {
|
||||
data = '\uFEFF' + data;
|
||||
}
|
||||
|
||||
_fs.writeFileSync(fileName, data, "utf8");
|
||||
}
|
||||
|
||||
return {
|
||||
args: process.argv.slice(2),
|
||||
newLine: _os.EOL,
|
||||
useCaseSensitiveFileNames: useCaseSensitiveFileNames,
|
||||
write(s: string): void {
|
||||
// 1 is a standard descriptor for stdout
|
||||
_fs.writeSync(1, s);
|
||||
},
|
||||
readFile,
|
||||
writeFile,
|
||||
watchFile: (fileName, callback) => {
|
||||
// watchFile polls a file every 250ms, picking up file notifications.
|
||||
_fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged);
|
||||
|
||||
return {
|
||||
close() { _fs.unwatchFile(fileName, fileChanged); }
|
||||
};
|
||||
|
||||
function fileChanged(curr: any, prev: any) {
|
||||
if (+curr.mtime <= +prev.mtime) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(fileName);
|
||||
};
|
||||
},
|
||||
resolvePath: function (path: string): string {
|
||||
return _path.resolve(path);
|
||||
},
|
||||
fileExists(path: string): boolean {
|
||||
return _fs.existsSync(path);
|
||||
},
|
||||
directoryExists(path: string) {
|
||||
return _fs.existsSync(path) && _fs.statSync(path).isDirectory();
|
||||
},
|
||||
createDirectory(directoryName: string) {
|
||||
if (!this.directoryExists(directoryName)) {
|
||||
_fs.mkdirSync(directoryName);
|
||||
}
|
||||
},
|
||||
getExecutingFilePath() {
|
||||
return __filename;
|
||||
},
|
||||
getCurrentDirectory() {
|
||||
return process.cwd();
|
||||
},
|
||||
getMemoryUsage() {
|
||||
if (global.gc) {
|
||||
global.gc();
|
||||
}
|
||||
return process.memoryUsage().heapUsed;
|
||||
},
|
||||
exit(exitCode?: number): void {
|
||||
process.exit(exitCode);
|
||||
}
|
||||
};
|
||||
}
|
||||
if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
||||
return getWScriptSystem();
|
||||
}
|
||||
else if (typeof module !== "undefined" && module.exports) {
|
||||
return getNodeSystem();
|
||||
}
|
||||
else {
|
||||
return undefined; // Unsupported host
|
||||
}
|
||||
})();
|
||||
}
|
|
@ -133,75 +133,6 @@ module ts {
|
|||
reportStatisticalValue(name, (time / 1000).toFixed(2) + "s");
|
||||
}
|
||||
|
||||
function createCompilerHost(options: CompilerOptions): CompilerHost {
|
||||
var currentDirectory: string;
|
||||
var existingDirectories: Map<boolean> = {};
|
||||
|
||||
function getCanonicalFileName(fileName: string): string {
|
||||
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
||||
// otherwise use toLowerCase as a canonical form.
|
||||
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
// returned by CScript sys environment
|
||||
var unsupportedFileEncodingErrorCode = -2147024809;
|
||||
|
||||
function getSourceFile(filename: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile {
|
||||
try {
|
||||
var text = sys.readFile(filename, options.charset);
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) {
|
||||
onError(e.number === unsupportedFileEncodingErrorCode ?
|
||||
getDiagnosticText(Diagnostics.Unsupported_file_encoding) :
|
||||
e.message);
|
||||
}
|
||||
text = "";
|
||||
}
|
||||
return text !== undefined ? createSourceFile(filename, text, languageVersion, /*version:*/ "0") : undefined;
|
||||
}
|
||||
|
||||
function writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void) {
|
||||
|
||||
function directoryExists(directoryPath: string): boolean {
|
||||
if (hasProperty(existingDirectories, directoryPath)) {
|
||||
return true;
|
||||
}
|
||||
if (sys.directoryExists(directoryPath)) {
|
||||
existingDirectories[directoryPath] = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function ensureDirectoriesExist(directoryPath: string) {
|
||||
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
||||
var parentDirectory = getDirectoryPath(directoryPath);
|
||||
ensureDirectoriesExist(parentDirectory);
|
||||
sys.createDirectory(directoryPath);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
|
||||
sys.writeFile(fileName, data, writeByteOrderMark);
|
||||
}
|
||||
catch (e) {
|
||||
if (onError) onError(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
getSourceFile,
|
||||
getDefaultLibFilename: options => combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), options.target === ScriptTarget.ES6 ? "lib.es6.d.ts" : "lib.d.ts"),
|
||||
writeFile,
|
||||
getCurrentDirectory: () => currentDirectory || (currentDirectory = sys.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => sys.newLine
|
||||
};
|
||||
}
|
||||
|
||||
export function executeCommandLine(args: string[]): void {
|
||||
var commandLine = parseCommandLine(args);
|
||||
var compilerOptions = commandLine.options;
|
||||
|
@ -447,12 +378,12 @@ module ts {
|
|||
var usageText = " ";
|
||||
if (option.shortName) {
|
||||
usageText += "-" + option.shortName;
|
||||
usageText += getParamName(option);
|
||||
usageText += getParamType(option);
|
||||
usageText += ", ";
|
||||
}
|
||||
|
||||
usageText += "--" + option.name;
|
||||
usageText += getParamName(option);
|
||||
usageText += getParamType(option);
|
||||
|
||||
usageColumn.push(usageText);
|
||||
descriptionColumn.push(getDiagnosticText(option.description));
|
||||
|
@ -477,9 +408,9 @@ module ts {
|
|||
sys.write(output);
|
||||
return;
|
||||
|
||||
function getParamName(option: CommandLineOption) {
|
||||
if (option.paramName !== undefined) {
|
||||
return " " + getDiagnosticText(option.paramName);
|
||||
function getParamType(option: CommandLineOption) {
|
||||
if (option.paramType !== undefined) {
|
||||
return " " + getDiagnosticText(option.paramType);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
@ -490,4 +421,4 @@ module ts {
|
|||
}
|
||||
}
|
||||
|
||||
ts.executeCommandLine(sys.args);
|
||||
ts.executeCommandLine(ts.sys.args);
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/// <reference path="core.ts"/>
|
||||
|
||||
module ts {
|
||||
export interface Map<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
export interface TextRange {
|
||||
pos: number;
|
||||
|
@ -1201,7 +1204,6 @@ module ts {
|
|||
StringLike = String | StringLiteral,
|
||||
NumberLike = Number | Enum,
|
||||
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
|
||||
Structured = Any | ObjectType | Union | TypeParameter
|
||||
}
|
||||
|
||||
// Properties common to all types
|
||||
|
@ -1356,6 +1358,7 @@ module ts {
|
|||
}
|
||||
|
||||
export interface CompilerOptions {
|
||||
allowNonTsExtensions?: boolean;
|
||||
charset?: string;
|
||||
codepage?: number;
|
||||
declaration?: boolean;
|
||||
|
@ -1373,14 +1376,14 @@ module ts {
|
|||
noResolve?: boolean;
|
||||
out?: string;
|
||||
outDir?: string;
|
||||
preserveConstEnums?: boolean;
|
||||
removeComments?: boolean;
|
||||
sourceMap?: boolean;
|
||||
sourceRoot?: string;
|
||||
suppressImplicitAnyIndexErrors?: boolean;
|
||||
target?: ScriptTarget;
|
||||
version?: boolean;
|
||||
watch?: boolean;
|
||||
preserveConstEnums?: boolean;
|
||||
allowNonTsExtensions?: boolean;
|
||||
[option: string]: string | number | boolean;
|
||||
}
|
||||
|
||||
|
@ -1417,7 +1420,7 @@ module ts {
|
|||
type: string | Map<number>; // "string", "number", "boolean", or an object literal mapping named values to actual values
|
||||
shortName?: string; // A short mnemonic 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.
|
||||
paramType?: 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'.
|
||||
}
|
||||
|
||||
|
@ -1555,7 +1558,7 @@ module ts {
|
|||
tab = 0x09, // \t
|
||||
verticalTab = 0x0B, // \v
|
||||
}
|
||||
|
||||
|
||||
export interface CancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
}
|
||||
|
|
709
src/compiler/utilities.ts
Normal file
709
src/compiler/utilities.ts
Normal file
|
@ -0,0 +1,709 @@
|
|||
/// <reference path="types.ts" />
|
||||
|
||||
module ts {
|
||||
export interface ReferencePathMatchResult {
|
||||
fileReference?: FileReference
|
||||
diagnosticMessage?: DiagnosticMessage
|
||||
isNoDefaultLib?: boolean
|
||||
}
|
||||
|
||||
export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
|
||||
var declarations = symbol.declarations;
|
||||
for (var i = 0; i < declarations.length; i++) {
|
||||
var declaration = declarations[i];
|
||||
if (declaration.kind === kind) {
|
||||
return declaration;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface StringSymbolWriter extends SymbolWriter {
|
||||
string(): string;
|
||||
}
|
||||
|
||||
// Pool writers to avoid needing to allocate them for every symbol we write.
|
||||
var stringWriters: StringSymbolWriter[] = [];
|
||||
export function getSingleLineStringWriter(): StringSymbolWriter {
|
||||
if (stringWriters.length == 0) {
|
||||
var str = "";
|
||||
|
||||
var writeText: (text: string) => void = text => str += text;
|
||||
return {
|
||||
string: () => str,
|
||||
writeKeyword: writeText,
|
||||
writeOperator: writeText,
|
||||
writePunctuation: writeText,
|
||||
writeSpace: writeText,
|
||||
writeStringLiteral: writeText,
|
||||
writeParameter: writeText,
|
||||
writeSymbol: writeText,
|
||||
|
||||
// Completely ignore indentation for string writers. And map newlines to
|
||||
// a single space.
|
||||
writeLine: () => str += " ",
|
||||
increaseIndent: () => { },
|
||||
decreaseIndent: () => { },
|
||||
clear: () => str = "",
|
||||
trackSymbol: () => { }
|
||||
};
|
||||
}
|
||||
|
||||
return stringWriters.pop();
|
||||
}
|
||||
|
||||
export function releaseStringWriter(writer: StringSymbolWriter) {
|
||||
writer.clear()
|
||||
stringWriters.push(writer);
|
||||
}
|
||||
|
||||
export function getFullWidth(node: Node) {
|
||||
return node.end - node.pos;
|
||||
}
|
||||
|
||||
export function hasFlag(val: number, flag: number): boolean {
|
||||
return (val & flag) !== 0;
|
||||
}
|
||||
|
||||
// Returns true if this node contains a parse error anywhere underneath it.
|
||||
export function containsParseError(node: Node): boolean {
|
||||
if (!hasFlag(node.parserContextFlags, ParserContextFlags.HasPropagatedChildContainsErrorFlag)) {
|
||||
// A node is considered to contain a parse error if:
|
||||
// a) the parser explicitly marked that it had an error
|
||||
// b) any of it's children reported that it had an error.
|
||||
var val = hasFlag(node.parserContextFlags, ParserContextFlags.ContainsError) ||
|
||||
forEachChild(node, containsParseError);
|
||||
|
||||
// If so, mark ourselves accordingly.
|
||||
if (val) {
|
||||
node.parserContextFlags |= ParserContextFlags.ContainsError;
|
||||
}
|
||||
|
||||
// Also mark that we've propogated the child information to this node. This way we can
|
||||
// always consult the bit directly on this node without needing to check its children
|
||||
// again.
|
||||
node.parserContextFlags |= ParserContextFlags.HasPropagatedChildContainsErrorFlag;
|
||||
}
|
||||
|
||||
return hasFlag(node.parserContextFlags, ParserContextFlags.ContainsError);
|
||||
}
|
||||
|
||||
export function getSourceFileOfNode(node: Node): SourceFile {
|
||||
while (node && node.kind !== SyntaxKind.SourceFile) {
|
||||
node = node.parent;
|
||||
}
|
||||
return <SourceFile>node;
|
||||
}
|
||||
|
||||
// This is a useful function for debugging purposes.
|
||||
export function nodePosToString(node: Node): string {
|
||||
var file = getSourceFileOfNode(node);
|
||||
var loc = file.getLineAndCharacterFromPosition(node.pos);
|
||||
return file.filename + "(" + loc.line + "," + loc.character + ")";
|
||||
}
|
||||
|
||||
export function getStartPosOfNode(node: Node): number {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
export function isMissingNode(node: Node) {
|
||||
return node.pos === node.end && node.kind !== SyntaxKind.EndOfFileToken;
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
|
||||
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
|
||||
// want to skip trivia because this will launch us forward to the next token.
|
||||
if (isMissingNode(node)) {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos);
|
||||
}
|
||||
|
||||
export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node): string {
|
||||
if (isMissingNode(node)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
var text = sourceFile.text;
|
||||
return text.substring(skipTrivia(text, node.pos), node.end);
|
||||
}
|
||||
|
||||
export function getTextOfNodeFromSourceText(sourceText: string, node: Node): string {
|
||||
if (isMissingNode(node)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return sourceText.substring(skipTrivia(sourceText, node.pos), node.end);
|
||||
}
|
||||
|
||||
export function getTextOfNode(node: Node): string {
|
||||
return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node);
|
||||
}
|
||||
|
||||
// Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__'
|
||||
export function escapeIdentifier(identifier: string): string {
|
||||
return identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier;
|
||||
}
|
||||
|
||||
// Remove extra underscore from escaped identifier
|
||||
export function unescapeIdentifier(identifier: string): string {
|
||||
return identifier.length >= 3 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ && identifier.charCodeAt(2) === CharacterCodes._ ? identifier.substr(1) : identifier;
|
||||
}
|
||||
|
||||
// Return display name of an identifier
|
||||
// Computed property names will just be emitted as "[<expr>]", where <expr> is the source
|
||||
// text of the expression in the computed property.
|
||||
export function declarationNameToString(name: DeclarationName) {
|
||||
return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name);
|
||||
}
|
||||
|
||||
export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): Diagnostic {
|
||||
node = getErrorSpanForNode(node);
|
||||
var file = getSourceFileOfNode(node);
|
||||
|
||||
var start = getTokenPosOfNode(node, file);
|
||||
var length = node.end - start;
|
||||
|
||||
return createFileDiagnostic(file, start, length, message, arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain, newLine: string): Diagnostic {
|
||||
node = getErrorSpanForNode(node);
|
||||
var file = getSourceFileOfNode(node);
|
||||
var start = skipTrivia(file.text, node.pos);
|
||||
var length = node.end - start;
|
||||
return flattenDiagnosticChain(file, start, length, messageChain, newLine);
|
||||
}
|
||||
|
||||
export function getErrorSpanForNode(node: Node): Node {
|
||||
var errorSpan: Node;
|
||||
switch (node.kind) {
|
||||
// This list is a work in progress. Add missing node kinds to improve their error
|
||||
// spans.
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.EnumMember:
|
||||
errorSpan = (<Declaration>node).name;
|
||||
break;
|
||||
}
|
||||
|
||||
// We now have the ideal error span, but it may be a node that is optional and absent
|
||||
// (e.g. the name of a function expression), in which case errorSpan will be undefined.
|
||||
// Alternatively, it might be required and missing (e.g. the name of a module), in which
|
||||
// case its pos will equal its end (length 0). In either of these cases, we should fall
|
||||
// back to the original node that the error was issued on.
|
||||
return errorSpan && errorSpan.pos < errorSpan.end ? errorSpan : node;
|
||||
}
|
||||
|
||||
export function isExternalModule(file: SourceFile): boolean {
|
||||
return file.externalModuleIndicator !== undefined;
|
||||
}
|
||||
|
||||
export function isDeclarationFile(file: SourceFile): boolean {
|
||||
return (file.flags & NodeFlags.DeclarationFile) !== 0;
|
||||
}
|
||||
|
||||
export function isConstEnumDeclaration(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.EnumDeclaration && isConst(node);
|
||||
}
|
||||
|
||||
export function isConst(node: Node): boolean {
|
||||
return !!(node.flags & NodeFlags.Const);
|
||||
}
|
||||
|
||||
export function isLet(node: Node): boolean {
|
||||
return !!(node.flags & NodeFlags.Let);
|
||||
}
|
||||
|
||||
export function isPrologueDirective(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.ExpressionStatement && (<ExpressionStatement>node).expression.kind === SyntaxKind.StringLiteral;
|
||||
}
|
||||
|
||||
export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode?: SourceFile) {
|
||||
sourceFileOfNode = sourceFileOfNode || getSourceFileOfNode(node);
|
||||
|
||||
// If parameter/type parameter, the prev token trailing comments are part of this node too
|
||||
if (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) {
|
||||
// e.g. (/** blah */ a, /** blah */ b);
|
||||
return concatenate(getTrailingCommentRanges(sourceFileOfNode.text, node.pos),
|
||||
// e.g.: (
|
||||
// /** blah */ a,
|
||||
// /** blah */ b);
|
||||
getLeadingCommentRanges(sourceFileOfNode.text, node.pos));
|
||||
}
|
||||
else {
|
||||
return getLeadingCommentRanges(sourceFileOfNode.text, node.pos);
|
||||
}
|
||||
}
|
||||
|
||||
export function getJsDocComments(node: Node, sourceFileOfNode: SourceFile) {
|
||||
return filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), isJsDocComment);
|
||||
|
||||
function isJsDocComment(comment: CommentRange) {
|
||||
// True if the comment starts with '/**' but not if it is '/**/'
|
||||
return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
|
||||
sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk &&
|
||||
sourceFileOfNode.text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash;
|
||||
}
|
||||
}
|
||||
|
||||
export var fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/
|
||||
|
||||
|
||||
// Warning: This has the same semantics as the forEach family of functions,
|
||||
// in that traversal terminates in the event that 'visitor' supplies a truthy value.
|
||||
export function forEachReturnStatement<T>(body: Block, visitor: (stmt: ReturnStatement) => T): T {
|
||||
|
||||
return traverse(body);
|
||||
|
||||
function traverse(node: Node): T {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ReturnStatement:
|
||||
return visitor(<ReturnStatement>node);
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.DefaultClause:
|
||||
case SyntaxKind.LabeledStatement:
|
||||
case SyntaxKind.TryStatement:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchClause:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
return forEachChild(node, traverse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isAnyFunction(node: Node): boolean {
|
||||
if (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isFunctionBlock(node: Node) {
|
||||
return node !== undefined && node.kind === SyntaxKind.Block && isAnyFunction(node.parent);
|
||||
}
|
||||
|
||||
export function isObjectLiteralMethod(node: Node) {
|
||||
return node !== undefined && node.kind === SyntaxKind.Method && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
|
||||
}
|
||||
|
||||
export function getContainingFunction(node: Node): FunctionLikeDeclaration {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node || isAnyFunction(node)) {
|
||||
return <FunctionLikeDeclaration>node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if (!includeArrowFunctions) {
|
||||
continue;
|
||||
}
|
||||
// Fall through
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.SourceFile:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getSuperContainer(node: Node): Node {
|
||||
while (true) {
|
||||
node = node.parent;
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getInvokedExpression(node: CallLikeExpression): Expression {
|
||||
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
return (<TaggedTemplateExpression>node).tag;
|
||||
}
|
||||
|
||||
// Will either be a CallExpression or NewExpression.
|
||||
return (<CallExpression>node).expression;
|
||||
}
|
||||
|
||||
export function isExpression(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ThisKeyword:
|
||||
case SyntaxKind.SuperKeyword:
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.VoidExpression:
|
||||
case SyntaxKind.DeleteExpression:
|
||||
case SyntaxKind.TypeOfExpression:
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
case SyntaxKind.BinaryExpression:
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
case SyntaxKind.TemplateExpression:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.OmittedExpression:
|
||||
return true;
|
||||
case SyntaxKind.QualifiedName:
|
||||
while (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return node.parent.kind === SyntaxKind.TypeQuery;
|
||||
case SyntaxKind.Identifier:
|
||||
if (node.parent.kind === SyntaxKind.TypeQuery) {
|
||||
return true;
|
||||
}
|
||||
// fall through
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.StringLiteral:
|
||||
var parent = node.parent;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
return (<VariableDeclaration>parent).initializer === node;
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.CaseClause:
|
||||
case SyntaxKind.ThrowStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
return (<ExpressionStatement>parent).expression === node;
|
||||
case SyntaxKind.ForStatement:
|
||||
return (<ForStatement>parent).initializer === node ||
|
||||
(<ForStatement>parent).condition === node ||
|
||||
(<ForStatement>parent).iterator === node;
|
||||
case SyntaxKind.ForInStatement:
|
||||
return (<ForInStatement>parent).variable === node ||
|
||||
(<ForInStatement>parent).expression === node;
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
return node === (<TypeAssertion>parent).expression;
|
||||
case SyntaxKind.TemplateSpan:
|
||||
return node === (<TemplateSpan>parent).expression;
|
||||
default:
|
||||
if (isExpression(parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isExternalModuleImportDeclaration(node: Node) {
|
||||
return node.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
|
||||
}
|
||||
|
||||
export function getExternalModuleImportDeclarationExpression(node: Node) {
|
||||
Debug.assert(isExternalModuleImportDeclaration(node));
|
||||
return (<ExternalModuleReference>(<ImportDeclaration>node).moduleReference).expression;
|
||||
}
|
||||
|
||||
export function isInternalModuleImportDeclaration(node: Node) {
|
||||
return node.kind === SyntaxKind.ImportDeclaration && (<ImportDeclaration>node).moduleReference.kind !== SyntaxKind.ExternalModuleReference;
|
||||
}
|
||||
|
||||
export function hasDotDotDotToken(node: Node) {
|
||||
return node && node.kind === SyntaxKind.Parameter && (<ParameterDeclaration>node).dotDotDotToken !== undefined;
|
||||
}
|
||||
|
||||
export function hasQuestionToken(node: Node) {
|
||||
if (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
return (<ParameterDeclaration>node).questionToken !== undefined;
|
||||
case SyntaxKind.Method:
|
||||
return (<MethodDeclaration>node).questionToken !== undefined;
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.Property:
|
||||
return (<PropertyDeclaration>node).questionToken !== undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function hasRestParameters(s: SignatureDeclaration): boolean {
|
||||
return s.parameters.length > 0 && s.parameters[s.parameters.length - 1].dotDotDotToken !== undefined;
|
||||
}
|
||||
|
||||
export function isLiteralKind(kind: SyntaxKind): boolean {
|
||||
return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
|
||||
}
|
||||
|
||||
export function isTextualLiteralKind(kind: SyntaxKind): boolean {
|
||||
return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NoSubstitutionTemplateLiteral;
|
||||
}
|
||||
|
||||
export function isTemplateLiteralKind(kind: SyntaxKind): boolean {
|
||||
return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
|
||||
}
|
||||
|
||||
export function isInAmbientContext(node: Node): boolean {
|
||||
while (node) {
|
||||
if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true;
|
||||
node = node.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isDeclaration(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.TypeParameter:
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function isStatement(n: Node): boolean {
|
||||
switch (n.kind) {
|
||||
case SyntaxKind.BreakStatement:
|
||||
case SyntaxKind.ContinueStatement:
|
||||
case SyntaxKind.DebuggerStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.EmptyStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.LabeledStatement:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.ThrowKeyword:
|
||||
case SyntaxKind.TryStatement:
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.ExportAssignment:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// True if the given identifier, string literal, or number literal is the name of a declaration node
|
||||
export function isDeclarationOrFunctionExpressionOrCatchVariableName(name: Node): boolean {
|
||||
if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var parent = name.parent;
|
||||
if (isDeclaration(parent) || parent.kind === SyntaxKind.FunctionExpression) {
|
||||
return (<Declaration>parent).name === name;
|
||||
}
|
||||
|
||||
if (parent.kind === SyntaxKind.CatchClause) {
|
||||
return (<CatchClause>parent).name === name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getClassBaseTypeNode(node: ClassDeclaration) {
|
||||
var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
|
||||
return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined;
|
||||
}
|
||||
|
||||
export function getClassImplementedTypeNodes(node: ClassDeclaration) {
|
||||
var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ImplementsKeyword);
|
||||
return heritageClause ? heritageClause.types : undefined;
|
||||
}
|
||||
|
||||
export function getInterfaceBaseTypeNodes(node: InterfaceDeclaration) {
|
||||
var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
|
||||
return heritageClause ? heritageClause.types : undefined;
|
||||
}
|
||||
|
||||
export function getHeritageClause(clauses: NodeArray<HeritageClause>, kind: SyntaxKind) {
|
||||
if (clauses) {
|
||||
for (var i = 0, n = clauses.length; i < n; i++) {
|
||||
if (clauses[i].token === kind) {
|
||||
return clauses[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function tryResolveScriptReference(program: Program, sourceFile: SourceFile, reference: FileReference) {
|
||||
if (!program.getCompilerOptions().noResolve) {
|
||||
var referenceFileName = isRootedDiskPath(reference.filename) ? reference.filename : combinePaths(getDirectoryPath(sourceFile.filename), reference.filename);
|
||||
referenceFileName = getNormalizedAbsolutePath(referenceFileName, program.getCompilerHost().getCurrentDirectory());
|
||||
return program.getSourceFile(referenceFileName);
|
||||
}
|
||||
}
|
||||
|
||||
export function getAncestor(node: Node, kind: SyntaxKind): Node {
|
||||
switch (kind) {
|
||||
// special-cases that can be come first
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
while (node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return <ClassDeclaration>node;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
// early exit cases - declarations cannot be nested in classes
|
||||
return undefined;
|
||||
default:
|
||||
node = node.parent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
while (node) {
|
||||
if (node.kind === kind) {
|
||||
return node;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult {
|
||||
var simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
|
||||
var isNoDefaultLibRegEx = /^(\/\/\/\s*<reference\s+no-default-lib\s*=\s*)('|")(.+?)\2\s*\/>/gim;
|
||||
if (simpleReferenceRegEx.exec(comment)) {
|
||||
if (isNoDefaultLibRegEx.exec(comment)) {
|
||||
return {
|
||||
isNoDefaultLib: true
|
||||
}
|
||||
}
|
||||
else {
|
||||
var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
|
||||
if (matchResult) {
|
||||
var start = commentRange.pos;
|
||||
var end = commentRange.end;
|
||||
return {
|
||||
fileReference: {
|
||||
pos: start,
|
||||
end: end,
|
||||
filename: matchResult[3]
|
||||
},
|
||||
isNoDefaultLib: false
|
||||
};
|
||||
}
|
||||
else {
|
||||
return {
|
||||
diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax,
|
||||
isNoDefaultLib: false
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function isKeyword(token: SyntaxKind): boolean {
|
||||
return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword;
|
||||
}
|
||||
|
||||
export function isTrivia(token: SyntaxKind) {
|
||||
return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken;
|
||||
}
|
||||
|
||||
export function isModifier(token: SyntaxKind): boolean {
|
||||
switch (token) {
|
||||
case SyntaxKind.PublicKeyword:
|
||||
case SyntaxKind.PrivateKeyword:
|
||||
case SyntaxKind.ProtectedKeyword:
|
||||
case SyntaxKind.StaticKeyword:
|
||||
case SyntaxKind.ExportKeyword:
|
||||
case SyntaxKind.DeclareKeyword:
|
||||
case SyntaxKind.ConstKeyword:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -364,7 +364,7 @@ module FourSlash {
|
|||
this.formatCodeOptions = {
|
||||
IndentSize: 4,
|
||||
TabSize: 4,
|
||||
NewLineCharacter: sys.newLine,
|
||||
NewLineCharacter: ts.sys.newLine,
|
||||
ConvertTabsToSpaces: true,
|
||||
InsertSpaceAfterCommaDelimiter: true,
|
||||
InsertSpaceAfterSemicolonInForStatements: true,
|
||||
|
@ -751,11 +751,11 @@ module FourSlash {
|
|||
}
|
||||
|
||||
private getMemberListAtCaret() {
|
||||
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition, true);
|
||||
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
}
|
||||
|
||||
private getCompletionListAtCaret() {
|
||||
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition, false);
|
||||
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
}
|
||||
|
||||
private getCompletionEntryDetails(entryName: string) {
|
||||
|
@ -1365,7 +1365,7 @@ module FourSlash {
|
|||
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset);
|
||||
} else if (prevChar === ' ' && /A-Za-z_/.test(ch)) {
|
||||
/* Completions */
|
||||
this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset, false);
|
||||
this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset);
|
||||
}
|
||||
|
||||
if (i % errorCadence === 0) {
|
||||
|
@ -1748,9 +1748,9 @@ module FourSlash {
|
|||
}
|
||||
|
||||
function jsonMismatchString() {
|
||||
return sys.newLine +
|
||||
"expected: '" + sys.newLine + JSON.stringify(expected, (k,v) => v, 2) + "'" + sys.newLine +
|
||||
"actual: '" + sys.newLine + JSON.stringify(actual, (k, v) => v, 2) + "'";
|
||||
return ts.sys.newLine +
|
||||
"expected: '" + ts.sys.newLine + JSON.stringify(expected, (k,v) => v, 2) + "'" + ts.sys.newLine +
|
||||
"actual: '" + ts.sys.newLine + JSON.stringify(actual, (k, v) => v, 2) + "'";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2247,9 +2247,9 @@ module FourSlash {
|
|||
{ unitName: fileName, content: content }],
|
||||
(fn, contents) => result = contents,
|
||||
ts.ScriptTarget.Latest,
|
||||
sys.useCaseSensitiveFileNames);
|
||||
ts.sys.useCaseSensitiveFileNames);
|
||||
// TODO (drosen): We need to enforce checking on these tests.
|
||||
var program = ts.createProgram([Harness.Compiler.fourslashFilename, fileName], { out: "fourslashTestOutput.js", noResolve: true }, host);
|
||||
var program = ts.createProgram([Harness.Compiler.fourslashFilename, fileName], { out: "fourslashTestOutput.js", noResolve: true, target: ts.ScriptTarget.ES3 }, host);
|
||||
var checker = ts.createTypeChecker(program, /*fullTypeCheckMode*/ true);
|
||||
|
||||
var errors = program.getDiagnostics().concat(checker.getDiagnostics());
|
||||
|
|
|
@ -22,10 +22,13 @@
|
|||
/// <reference path='external\chai.d.ts'/>
|
||||
/// <reference path='sourceMapRecorder.ts'/>
|
||||
|
||||
declare var require: any;
|
||||
declare var process: any;
|
||||
|
||||
// this will work in the browser via browserify
|
||||
var _chai: typeof chai = require('chai');
|
||||
var assert: typeof _chai.assert = _chai.assert;
|
||||
declare var __dirname: any; // Node-specific
|
||||
declare var __dirname: string; // Node-specific
|
||||
var global = <any>Function("return this").call(null);
|
||||
|
||||
module Utils {
|
||||
|
@ -41,7 +44,7 @@ module Utils {
|
|||
export function getExecutionEnvironment() {
|
||||
if (typeof WScript !== "undefined" && typeof ActiveXObject === "function") {
|
||||
return ExecutionEnvironment.CScript;
|
||||
} else if (process && (<any>process).execPath && (<any>process).execPath.indexOf("node") !== -1) {
|
||||
} else if (process && process.execPath && process.execPath.indexOf("node") !== -1) {
|
||||
return ExecutionEnvironment.Node;
|
||||
} else {
|
||||
return ExecutionEnvironment.Browser;
|
||||
|
@ -89,7 +92,7 @@ module Utils {
|
|||
}
|
||||
|
||||
try {
|
||||
var content = sys.readFile(Harness.userSpecifiedroot + path);
|
||||
var content = ts.sys.readFile(Harness.userSpecifiedroot + path);
|
||||
}
|
||||
catch (err) {
|
||||
return undefined;
|
||||
|
@ -156,8 +159,8 @@ module Harness {
|
|||
fso = {};
|
||||
}
|
||||
|
||||
export var readFile: typeof IO.readFile = sys.readFile;
|
||||
export var writeFile: typeof IO.writeFile = sys.writeFile;
|
||||
export var readFile: typeof IO.readFile = ts.sys.readFile;
|
||||
export var writeFile: typeof IO.writeFile = ts.sys.writeFile;
|
||||
export var directoryName: typeof IO.directoryName = fso.GetParentFolderName;
|
||||
export var directoryExists: typeof IO.directoryExists = fso.FolderExists;
|
||||
export var fileExists: typeof IO.fileExists = fso.FileExists;
|
||||
|
@ -218,8 +221,8 @@ module Harness {
|
|||
fs = pathModule = {};
|
||||
}
|
||||
|
||||
export var readFile: typeof IO.readFile = sys.readFile;
|
||||
export var writeFile: typeof IO.writeFile = sys.writeFile;
|
||||
export var readFile: typeof IO.readFile = ts.sys.readFile;
|
||||
export var writeFile: typeof IO.writeFile = ts.sys.writeFile;
|
||||
export var fileExists: typeof IO.fileExists = fs.existsSync;
|
||||
export var log: typeof IO.log = console.log;
|
||||
|
||||
|
@ -547,7 +550,7 @@ module Harness {
|
|||
export var fourslashSourceFile: ts.SourceFile;
|
||||
|
||||
export function getCanonicalFileName(fileName: string): string {
|
||||
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
return ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
}
|
||||
|
||||
export function createCompilerHost(inputFiles: { unitName: string; content: string; }[],
|
||||
|
@ -571,8 +574,7 @@ module Harness {
|
|||
inputFiles.forEach(register);
|
||||
|
||||
return {
|
||||
getCurrentDirectory: sys.getCurrentDirectory,
|
||||
getCancellationToken: (): any => undefined,
|
||||
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
||||
getSourceFile: (fn, languageVersion) => {
|
||||
if (Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(fn))) {
|
||||
return filemap[getCanonicalFileName(fn)];
|
||||
|
@ -594,7 +596,7 @@ module Harness {
|
|||
writeFile,
|
||||
getCanonicalFileName,
|
||||
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
||||
getNewLine: ()=> sys.newLine
|
||||
getNewLine: ()=> ts.sys.newLine
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -664,7 +666,7 @@ module Harness {
|
|||
settingsCallback(null);
|
||||
}
|
||||
|
||||
var useCaseSensitiveFileNames = sys.useCaseSensitiveFileNames;
|
||||
var useCaseSensitiveFileNames = ts.sys.useCaseSensitiveFileNames;
|
||||
this.settings.forEach(setting => {
|
||||
switch (setting.flag.toLowerCase()) {
|
||||
// "filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noimplicitany", "noresolve"
|
||||
|
@ -742,7 +744,7 @@ module Harness {
|
|||
|
||||
case 'newline':
|
||||
case 'newlines':
|
||||
sys.newLine = setting.value;
|
||||
ts.sys.newLine = setting.value;
|
||||
break;
|
||||
|
||||
case 'comments':
|
||||
|
@ -774,9 +776,19 @@ module Harness {
|
|||
case 'errortruncation':
|
||||
options.noErrorTruncation = setting.value === 'false';
|
||||
break;
|
||||
|
||||
case 'preserveconstenums':
|
||||
options.preserveConstEnums = setting.value === 'true';
|
||||
break;
|
||||
|
||||
case 'suppressimplicitanyindexerrors':
|
||||
options.suppressImplicitAnyIndexErrors = setting.value === 'true';
|
||||
break;
|
||||
|
||||
case 'includebuiltfile':
|
||||
inputFiles.push({ unitName: setting.value, content: IO.readFile(libFolder + setting.value)});
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error('Unsupported compiler setting ' + setting.flag);
|
||||
}
|
||||
|
@ -817,11 +829,11 @@ module Harness {
|
|||
});
|
||||
this.lastErrors = errors;
|
||||
|
||||
var result = new CompilerResult(fileOutputs, errors, program, sys.getCurrentDirectory(), emitResult ? emitResult.sourceMaps : undefined);
|
||||
var result = new CompilerResult(fileOutputs, errors, program, ts.sys.getCurrentDirectory(), emitResult ? emitResult.sourceMaps : undefined);
|
||||
onComplete(result, checker);
|
||||
|
||||
// reset what newline means in case the last test changed it
|
||||
sys.newLine = '\r\n';
|
||||
ts.sys.newLine = '\r\n';
|
||||
return options;
|
||||
}
|
||||
|
||||
|
@ -916,7 +928,7 @@ module Harness {
|
|||
errorOutput += diagnotic.filename + "(" + diagnotic.line + "," + diagnotic.character + "): ";
|
||||
}
|
||||
|
||||
errorOutput += diagnotic.category + " TS" + diagnotic.code + ": " + diagnotic.message + sys.newLine;
|
||||
errorOutput += diagnotic.category + " TS" + diagnotic.code + ": " + diagnotic.message + ts.sys.newLine;
|
||||
});
|
||||
|
||||
return errorOutput;
|
||||
|
@ -1014,7 +1026,7 @@ module Harness {
|
|||
assert.equal(totalErrorsReported + numLibraryDiagnostics, diagnostics.length, 'total number of errors');
|
||||
|
||||
return minimalDiagnosticsToString(diagnostics) +
|
||||
sys.newLine + sys.newLine + outputLines.join('\r\n');
|
||||
ts.sys.newLine + ts.sys.newLine + outputLines.join('\r\n');
|
||||
}
|
||||
|
||||
export function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[], clean?: (s: string) => string) {
|
||||
|
@ -1162,7 +1174,8 @@ 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", "preserveconstenums"];
|
||||
|
||||
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums", "includebuiltfile", "suppressimplicitanyindexerrors"];
|
||||
|
||||
function extractCompilerSettings(content: string): CompilerSetting[] {
|
||||
|
||||
|
|
|
@ -139,6 +139,9 @@ module Harness.LanguageService {
|
|||
constructor(private cancellationToken: ts.CancellationToken = CancellationToken.None) {
|
||||
}
|
||||
|
||||
public trace(s: string) {
|
||||
}
|
||||
|
||||
public addDefaultLibrary() {
|
||||
this.addScript(Harness.Compiler.defaultLibFileName, Harness.Compiler.defaultLibSourceFile.text);
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ module Playback {
|
|||
return run;
|
||||
}
|
||||
|
||||
export interface PlaybackSystem extends System, PlaybackControl { }
|
||||
export interface PlaybackSystem extends ts.System, PlaybackControl { }
|
||||
|
||||
function createEmptyLog(): IOLog {
|
||||
return {
|
||||
|
@ -221,7 +221,7 @@ module Playback {
|
|||
//console.log("Swallowed write operation during replay: " + name);
|
||||
}
|
||||
|
||||
export function wrapSystem(underlying: System): PlaybackSystem {
|
||||
export function wrapSystem(underlying: ts.System): PlaybackSystem {
|
||||
var wrapper: PlaybackSystem = <any>{};
|
||||
initWrapper(wrapper, underlying);
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ class ProjectRunner extends RunnerBase {
|
|||
var testCase: ProjectRunnerTestCase;
|
||||
|
||||
try {
|
||||
var testFileText = sys.readFile(testCaseFileName);
|
||||
var testFileText = ts.sys.readFile(testCaseFileName);
|
||||
}
|
||||
catch (e) {
|
||||
assert(false, "Unable to open testcase file: " + testCaseFileName + ": " + e.message);
|
||||
|
@ -96,7 +96,7 @@ class ProjectRunner extends RunnerBase {
|
|||
}
|
||||
|
||||
function cleanProjectUrl(url: string) {
|
||||
var diskProjectPath = ts.normalizeSlashes(sys.resolvePath(testCase.projectRoot));
|
||||
var diskProjectPath = ts.normalizeSlashes(ts.sys.resolvePath(testCase.projectRoot));
|
||||
var projectRootUrl = "file:///" + diskProjectPath;
|
||||
var normalizedProjectRoot = ts.normalizeSlashes(testCase.projectRoot);
|
||||
diskProjectPath = diskProjectPath.substr(0, diskProjectPath.lastIndexOf(normalizedProjectRoot));
|
||||
|
@ -119,7 +119,7 @@ class ProjectRunner extends RunnerBase {
|
|||
}
|
||||
|
||||
function getCurrentDirectory() {
|
||||
return sys.resolvePath(testCase.projectRoot);
|
||||
return ts.sys.resolvePath(testCase.projectRoot);
|
||||
}
|
||||
|
||||
function compileProjectFiles(moduleKind: ts.ModuleKind, getInputFiles: ()=> string[],
|
||||
|
@ -161,8 +161,8 @@ class ProjectRunner extends RunnerBase {
|
|||
sourceMap: !!testCase.sourceMap,
|
||||
out: testCase.out,
|
||||
outDir: testCase.outDir,
|
||||
mapRoot: testCase.resolveMapRoot && testCase.mapRoot ? sys.resolvePath(testCase.mapRoot) : testCase.mapRoot,
|
||||
sourceRoot: testCase.resolveSourceRoot && testCase.sourceRoot ? sys.resolvePath(testCase.sourceRoot) : testCase.sourceRoot,
|
||||
mapRoot: testCase.resolveMapRoot && testCase.mapRoot ? ts.sys.resolvePath(testCase.mapRoot) : testCase.mapRoot,
|
||||
sourceRoot: testCase.resolveSourceRoot && testCase.sourceRoot ? ts.sys.resolvePath(testCase.sourceRoot) : testCase.sourceRoot,
|
||||
module: moduleKind,
|
||||
noResolve: testCase.noResolve
|
||||
};
|
||||
|
@ -190,8 +190,8 @@ class ProjectRunner extends RunnerBase {
|
|||
writeFile,
|
||||
getCurrentDirectory,
|
||||
getCanonicalFileName: Harness.Compiler.getCanonicalFileName,
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getNewLine: () => sys.newLine
|
||||
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
|
||||
getNewLine: () => ts.sys.newLine
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ class ProjectRunner extends RunnerBase {
|
|||
|
||||
function getSourceFileText(filename: string): string {
|
||||
try {
|
||||
var text = sys.readFile(ts.isRootedDiskPath(filename)
|
||||
var text = ts.sys.readFile(ts.isRootedDiskPath(filename)
|
||||
? filename
|
||||
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(filename));
|
||||
}
|
||||
|
@ -260,14 +260,14 @@ class ProjectRunner extends RunnerBase {
|
|||
// Actual writing of file as in tc.ts
|
||||
function ensureDirectoryStructure(directoryname: string) {
|
||||
if (directoryname) {
|
||||
if (!sys.directoryExists(directoryname)) {
|
||||
if (!ts.sys.directoryExists(directoryname)) {
|
||||
ensureDirectoryStructure(ts.getDirectoryPath(directoryname));
|
||||
sys.createDirectory(directoryname);
|
||||
ts.sys.createDirectory(directoryname);
|
||||
}
|
||||
}
|
||||
}
|
||||
ensureDirectoryStructure(ts.getDirectoryPath(ts.normalizePath(outputFilePath)));
|
||||
sys.writeFile(outputFilePath, data, writeByteOrderMark);
|
||||
ts.sys.writeFile(outputFilePath, data, writeByteOrderMark);
|
||||
|
||||
outputFiles.push({ emittedFileName: filename, code: data, fileName: diskRelativeName, writeByteOrderMark: writeByteOrderMark });
|
||||
}
|
||||
|
@ -374,7 +374,7 @@ class ProjectRunner extends RunnerBase {
|
|||
it('Baseline of emitted result (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, () => {
|
||||
Harness.Baseline.runBaseline('Baseline of emitted result (' + moduleNameToString(compilerResult.moduleKind) + '): ' + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + outputFile.fileName, () => {
|
||||
try {
|
||||
return sys.readFile(getProjectOutputFolder(outputFile.fileName, compilerResult.moduleKind));
|
||||
return ts.sys.readFile(getProjectOutputFolder(outputFile.fileName, compilerResult.moduleKind));
|
||||
}
|
||||
catch (e) {
|
||||
return undefined;
|
||||
|
|
|
@ -94,6 +94,6 @@ if (runners.length === 0) {
|
|||
//runners.push(new GeneratedFourslashRunner());
|
||||
}
|
||||
|
||||
sys.newLine = '\r\n';
|
||||
ts.sys.newLine = '\r\n';
|
||||
|
||||
runTests(runners);
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
|
||||
module RWC {
|
||||
function runWithIOLog(ioLog: IOLog, fn: () => void) {
|
||||
var oldSys = sys;
|
||||
var oldSys = ts.sys;
|
||||
|
||||
var wrappedSys = Playback.wrapSystem(sys);
|
||||
var wrappedSys = Playback.wrapSystem(ts.sys);
|
||||
wrappedSys.startReplayFromData(ioLog);
|
||||
sys = wrappedSys;
|
||||
ts.sys = wrappedSys;
|
||||
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
wrappedSys.endReplay();
|
||||
sys = oldSys;
|
||||
ts.sys = oldSys;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ module RWC {
|
|||
}
|
||||
|
||||
ts.forEach(ioLog.filesRead, fileRead => {
|
||||
var resolvedPath = ts.normalizeSlashes(sys.resolvePath(fileRead.path));
|
||||
var resolvedPath = ts.normalizeSlashes(ts.sys.resolvePath(fileRead.path));
|
||||
var inInputList = ts.forEach(inputFiles, inputFile=> inputFile.unitName === resolvedPath);
|
||||
if (!inInputList) {
|
||||
// Add the file to other files
|
||||
|
@ -92,9 +92,9 @@ module RWC {
|
|||
});
|
||||
|
||||
function getHarnessCompilerInputUnit(fileName: string) {
|
||||
var unitName = ts.normalizeSlashes(sys.resolvePath(fileName));
|
||||
var unitName = ts.normalizeSlashes(ts.sys.resolvePath(fileName));
|
||||
try {
|
||||
var content = sys.readFile(unitName);
|
||||
var content = ts.sys.readFile(unitName);
|
||||
}
|
||||
catch (e) {
|
||||
// Leave content undefined.
|
||||
|
@ -160,7 +160,7 @@ module RWC {
|
|||
}
|
||||
|
||||
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
|
||||
sys.newLine + sys.newLine +
|
||||
ts.sys.newLine + ts.sys.newLine +
|
||||
Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
|
||||
}, false, baselineOpts);
|
||||
}
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
|
||||
// See LICENSE.txt in the project root for complete license information.
|
||||
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services {
|
||||
export class FindReferenceHelpers {
|
||||
public static compareSymbolsForLexicalIdentity(firstSymbol: TypeScript.PullSymbol, secondSymbol: TypeScript.PullSymbol): boolean {
|
||||
// Unwrap modules so that we're always referring to the variable.
|
||||
if (!firstSymbol.isAlias() && firstSymbol.isContainer()) {
|
||||
var containerForFirstSymbol = (<TypeScript.PullContainerSymbol>firstSymbol);
|
||||
if (containerForFirstSymbol.getInstanceSymbol()) {
|
||||
firstSymbol = containerForFirstSymbol.getInstanceSymbol();
|
||||
}
|
||||
}
|
||||
|
||||
if (!secondSymbol.isAlias() && secondSymbol.isContainer()) {
|
||||
var containerForSecondSymbol = (<TypeScript.PullContainerSymbol>secondSymbol);
|
||||
if (containerForSecondSymbol.getInstanceSymbol()) {
|
||||
secondSymbol = containerForSecondSymbol.getInstanceSymbol();
|
||||
}
|
||||
}
|
||||
|
||||
if (firstSymbol.kind === secondSymbol.kind) {
|
||||
if (firstSymbol === secondSymbol) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we have two variables and they have the same name and the same parent, then
|
||||
// they are the same symbol.
|
||||
if (firstSymbol.kind === TypeScript.PullElementKind.Variable &&
|
||||
firstSymbol.name === secondSymbol.name &&
|
||||
firstSymbol.getDeclarations() && firstSymbol.getDeclarations().length >= 1 &&
|
||||
secondSymbol.getDeclarations() && secondSymbol.getDeclarations().length >= 1) {
|
||||
|
||||
var firstSymbolDecl = firstSymbol.getDeclarations()[0];
|
||||
var secondSymbolDecl = secondSymbol.getDeclarations()[0];
|
||||
|
||||
return firstSymbolDecl.getParentDecl() === secondSymbolDecl.getParentDecl();
|
||||
}
|
||||
|
||||
// If we have two properties that belong to an object literal, then we need ot see
|
||||
// if they came from teh same object literal ast.
|
||||
if (firstSymbol.kind === TypeScript.PullElementKind.Property &&
|
||||
firstSymbol.name === secondSymbol.name &&
|
||||
firstSymbol.getDeclarations() && firstSymbol.getDeclarations().length >= 1 &&
|
||||
secondSymbol.getDeclarations() && secondSymbol.getDeclarations().length >= 1) {
|
||||
|
||||
var firstSymbolDecl = firstSymbol.getDeclarations()[0];
|
||||
var secondSymbolDecl = secondSymbol.getDeclarations()[0];
|
||||
|
||||
var firstParentDecl = firstSymbolDecl.getParentDecl();
|
||||
var secondParentDecl = secondSymbolDecl.getParentDecl();
|
||||
|
||||
if (firstParentDecl.kind === TypeScript.PullElementKind.ObjectLiteral &&
|
||||
secondParentDecl.kind === TypeScript.PullElementKind.ObjectLiteral) {
|
||||
|
||||
return firstParentDecl.ast() === secondParentDecl.ast();
|
||||
}
|
||||
}
|
||||
|
||||
// check if we are dealing with the implementation of interface method or a method override
|
||||
if (firstSymbol.name === secondSymbol.name) {
|
||||
// at this point firstSymbol.kind === secondSymbol.kind so we can pick any of those
|
||||
switch (firstSymbol.kind) {
|
||||
case PullElementKind.Property:
|
||||
case PullElementKind.Method:
|
||||
case PullElementKind.GetAccessor:
|
||||
case PullElementKind.SetAccessor:
|
||||
// these kinds can only be defined in types
|
||||
var t1 = <PullTypeSymbol>firstSymbol.getContainer();
|
||||
var t2 = <PullTypeSymbol>secondSymbol.getContainer();
|
||||
t1._resolveDeclaredSymbol();
|
||||
t2._resolveDeclaredSymbol();
|
||||
|
||||
return t1.hasBase(t2) || t2.hasBase(t1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
switch (firstSymbol.kind) {
|
||||
case TypeScript.PullElementKind.Class: {
|
||||
return this.checkSymbolsForDeclarationEquality(firstSymbol, secondSymbol);
|
||||
}
|
||||
case TypeScript.PullElementKind.Property: {
|
||||
if (firstSymbol.isAccessor()) {
|
||||
var getterSymbol = (<TypeScript.PullAccessorSymbol>firstSymbol).getGetter();
|
||||
var setterSymbol = (<TypeScript.PullAccessorSymbol>firstSymbol).getSetter();
|
||||
|
||||
if (getterSymbol && getterSymbol === secondSymbol) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (setterSymbol && setterSymbol === secondSymbol) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case TypeScript.PullElementKind.Function: {
|
||||
if (secondSymbol.isAccessor()) {
|
||||
var getterSymbol = (<TypeScript.PullAccessorSymbol>secondSymbol).getGetter();
|
||||
var setterSymbol = (<TypeScript.PullAccessorSymbol>secondSymbol).getSetter();
|
||||
|
||||
if (getterSymbol && getterSymbol === firstSymbol) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (setterSymbol && setterSymbol === firstSymbol) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case TypeScript.PullElementKind.ConstructorMethod: {
|
||||
return this.checkSymbolsForDeclarationEquality(firstSymbol, secondSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return firstSymbol === secondSymbol;
|
||||
}
|
||||
|
||||
private static checkSymbolsForDeclarationEquality(firstSymbol: TypeScript.PullSymbol, secondSymbol: TypeScript.PullSymbol): boolean {
|
||||
var firstSymbolDeclarations: TypeScript.PullDecl[] = firstSymbol.getDeclarations();
|
||||
var secondSymbolDeclarations: TypeScript.PullDecl[] = secondSymbol.getDeclarations();
|
||||
for (var i = 0, iLen = firstSymbolDeclarations.length; i < iLen; i++) {
|
||||
for (var j = 0, jLen = secondSymbolDeclarations.length; j < jLen; j++) {
|
||||
if (this.declarationsAreSameOrParents(firstSymbolDeclarations[i], secondSymbolDeclarations[j])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static declarationsAreSameOrParents(firstDecl: TypeScript.PullDecl, secondDecl: TypeScript.PullDecl): boolean {
|
||||
var firstParent: TypeScript.PullDecl = firstDecl.getParentDecl();
|
||||
var secondParent: TypeScript.PullDecl = secondDecl.getParentDecl();
|
||||
if (firstDecl === secondDecl ||
|
||||
firstDecl === secondParent ||
|
||||
firstParent === secondDecl ||
|
||||
firstParent === secondParent) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
///<reference path='services.ts' />
|
||||
///<reference path='formatting\indentation.ts' />
|
||||
///<reference path='formatting\formattingScanner.ts' />
|
||||
///<reference path='formatting\rulesProvider.ts' />
|
||||
///<reference path='..\services.ts' />
|
||||
///<reference path='formattingScanner.ts' />
|
||||
///<reference path='rulesProvider.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module ts.formatting {
|
||||
|
||||
|
@ -983,4 +983,56 @@ module ts.formatting {
|
|||
|
||||
return SyntaxKind.Unknown;
|
||||
}
|
||||
|
||||
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,4 +1,4 @@
|
|||
/// <reference path="..\formatting.ts"/>
|
||||
/// <reference path="formatting.ts"/>
|
||||
/// <reference path="..\..\compiler\scanner.ts"/>
|
||||
|
||||
module ts.formatting {
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='..\text.ts' />
|
||||
///<reference path='..\services.ts' />
|
||||
///<reference path='formattingContext.ts' />
|
||||
///<reference path='formattingRequestKind.ts' />
|
||||
|
@ -25,5 +24,4 @@
|
|||
///<reference path='ruleOperationContext.ts' />
|
||||
///<reference path='rules.ts' />
|
||||
///<reference path='rulesMap.ts' />
|
||||
///<reference path='tokenRange.ts' />
|
||||
///<reference path='tokenSpan.ts' />
|
||||
///<reference path='tokenRange.ts' />
|
|
@ -1,4 +1,4 @@
|
|||
///<reference path='services.ts' />
|
||||
///<reference path='..\services.ts' />
|
||||
|
||||
module ts.formatting {
|
||||
export module SmartIndenter {
|
|
@ -1,24 +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 ts.formatting {
|
||||
export class TokenSpan extends TextSpan {
|
||||
constructor(public kind: SyntaxKind, start: number, length: number) {
|
||||
super(start, length);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,22 +14,6 @@
|
|||
//
|
||||
|
||||
module ts {
|
||||
|
||||
export interface OutliningSpan {
|
||||
/**
|
||||
* @param textSpan The span of the document to actually collapse.
|
||||
* @param hintSpan The span of the document to display when the user hovers over the
|
||||
* collapsed span.
|
||||
* @param bannerText The text to display in the editor for the collapsed region.
|
||||
* @param autoCollapse Whether or not this region should be automatically collapsed when
|
||||
* the 'Collapse to Definitions' command is invoked.
|
||||
*/
|
||||
textSpan: TextSpan;
|
||||
hintSpan: TextSpan;
|
||||
bannerText: string;
|
||||
autoCollapse: boolean;
|
||||
}
|
||||
|
||||
export module OutliningElementsCollector {
|
||||
export function collectElements(sourceFile: SourceFile): OutliningSpan[] {
|
||||
var elements: OutliningSpan[] = [];
|
||||
|
|
|
@ -4,16 +4,18 @@
|
|||
/// <reference path="..\compiler\parser.ts"/>
|
||||
/// <reference path="..\compiler\checker.ts"/>
|
||||
|
||||
/// <reference path='text.ts' />
|
||||
/// <reference path='breakpoints.ts' />
|
||||
/// <reference path='outliningElementsCollector.ts' />
|
||||
/// <reference path='navigationBar.ts' />
|
||||
/// <reference path='breakpoints.ts' />
|
||||
/// <reference path='signatureHelp.ts' />
|
||||
/// <reference path='utilities.ts' />
|
||||
/// <reference path='smartIndenter.ts' />
|
||||
/// <reference path='formatting.ts' />
|
||||
/// <reference path='formatting\formatting.ts' />
|
||||
/// <reference path='formatting\smartIndenter.ts' />
|
||||
|
||||
module ts {
|
||||
|
||||
export var servicesVersion = "0.4"
|
||||
|
||||
export interface Node {
|
||||
getSourceFile(): SourceFile;
|
||||
getChildCount(sourceFile?: SourceFile): number;
|
||||
|
@ -876,8 +878,8 @@ module ts {
|
|||
getScriptVersion(fileName: string): string;
|
||||
getScriptIsOpen(fileName: string): boolean;
|
||||
getScriptSnapshot(fileName: string): IScriptSnapshot;
|
||||
getLocalizedDiagnosticMessages(): any;
|
||||
getCancellationToken(): CancellationToken;
|
||||
getLocalizedDiagnosticMessages?(): any;
|
||||
getCancellationToken?(): CancellationToken;
|
||||
getCurrentDirectory(): string;
|
||||
getDefaultLibFilename(options: CompilerOptions): string;
|
||||
}
|
||||
|
@ -896,7 +898,7 @@ module ts {
|
|||
getSyntacticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[];
|
||||
getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[];
|
||||
|
||||
getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): CompletionInfo;
|
||||
getCompletionsAtPosition(fileName: string, position: number): CompletionInfo;
|
||||
getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails;
|
||||
|
||||
getQuickInfoAtPosition(fileName: string, position: number): QuickInfo;
|
||||
|
@ -933,6 +935,301 @@ module ts {
|
|||
dispose(): void;
|
||||
}
|
||||
|
||||
export class TextSpan {
|
||||
private _start: number;
|
||||
private _length: number;
|
||||
|
||||
/**
|
||||
* Creates a TextSpan instance beginning with the position Start and having the Length
|
||||
* specified with length.
|
||||
*/
|
||||
constructor(start: number, length: number) {
|
||||
Debug.assert(start >= 0, "start");
|
||||
Debug.assert(length >= 0, "length");
|
||||
|
||||
this._start = start;
|
||||
this._length = length;
|
||||
}
|
||||
|
||||
public toJSON(key: any): any {
|
||||
return { start: this._start, length: this._length };
|
||||
}
|
||||
|
||||
public start(): number {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
public length(): number {
|
||||
return this._length;
|
||||
}
|
||||
|
||||
public end(): number {
|
||||
return this._start + this._length;
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return this._length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the position lies within the span. Returns true if the position is greater than or equal to Start and strictly less
|
||||
* than End, otherwise false.
|
||||
* @param position The position to check.
|
||||
*/
|
||||
public containsPosition(position: number): boolean {
|
||||
return position >= this._start && position < this.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether span falls completely within this span. Returns true if the specified span falls completely within this span, otherwise false.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public containsTextSpan(span: TextSpan): boolean {
|
||||
return span._start >= this._start && span.end() <= this.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given span overlaps this span. Two spans are considered to overlap
|
||||
* if they have positions in common and neither is empty. Empty spans do not overlap with any
|
||||
* other span. Returns true if the spans overlap, false otherwise.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public overlapsWith(span: TextSpan): boolean {
|
||||
var overlapStart = Math.max(this._start, span._start);
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
|
||||
return overlapStart < overlapEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overlap with the given span, or undefined if there is no overlap.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public overlap(span: TextSpan): TextSpan {
|
||||
var overlapStart = Math.max(this._start, span._start);
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
|
||||
if (overlapStart < overlapEnd) {
|
||||
return TextSpan.fromBounds(overlapStart, overlapEnd);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether span intersects this span. Two spans are considered to
|
||||
* intersect if they have positions in common or the end of one span
|
||||
* coincides with the start of the other span. Returns true if the spans intersect, false otherwise.
|
||||
* @param The span to check.
|
||||
*/
|
||||
public intersectsWithTextSpan(span: TextSpan): boolean {
|
||||
return span._start <= this.end() && span.end() >= this._start;
|
||||
}
|
||||
|
||||
public intersectsWith(start: number, length: number): boolean {
|
||||
var end = start + length;
|
||||
return start <= this.end() && end >= this._start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given position intersects this span.
|
||||
* A position is considered to intersect if it is between the start and
|
||||
* end positions (inclusive) of this span. Returns true if the position intersects, false otherwise.
|
||||
* @param position The position to check.
|
||||
*/
|
||||
public intersectsWithPosition(position: number): boolean {
|
||||
return position <= this.end() && position >= this._start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intersection with the given span, or undefined if there is no intersection.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public intersection(span: TextSpan): TextSpan {
|
||||
var intersectStart = Math.max(this._start, span._start);
|
||||
var intersectEnd = Math.min(this.end(), span.end());
|
||||
|
||||
if (intersectStart <= intersectEnd) {
|
||||
return TextSpan.fromBounds(intersectStart, intersectEnd);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextSpan from the given start and end positions
|
||||
* as opposed to a position and length.
|
||||
*/
|
||||
public static fromBounds(start: number, end: number): TextSpan {
|
||||
Debug.assert(start >= 0);
|
||||
Debug.assert(end - start >= 0);
|
||||
return new TextSpan(start, end - start);
|
||||
}
|
||||
}
|
||||
|
||||
export class TextChangeRange {
|
||||
public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0);
|
||||
|
||||
private _span: TextSpan;
|
||||
private _newLength: number;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of TextChangeRange.
|
||||
*/
|
||||
constructor(span: TextSpan, newLength: number) {
|
||||
Debug.assert(newLength >= 0, "newLength");
|
||||
|
||||
this._span = span;
|
||||
this._newLength = newLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* The span of text before the edit which is being changed
|
||||
*/
|
||||
public span(): TextSpan {
|
||||
return this._span;
|
||||
}
|
||||
|
||||
/**
|
||||
* Width of the span after the edit. A 0 here would represent a delete
|
||||
*/
|
||||
public newLength(): number {
|
||||
return this._newLength;
|
||||
}
|
||||
|
||||
public newSpan(): TextSpan {
|
||||
return new TextSpan(this.span().start(), this.newLength());
|
||||
}
|
||||
|
||||
public isUnchanged(): boolean {
|
||||
return this.span().isEmpty() && this.newLength() === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to merge all the changes that occurred across several versions of a script snapshot
|
||||
* into a single change. i.e. if a user keeps making successive edits to a script we will
|
||||
* have a text change from V1 to V2, V2 to V3, ..., Vn.
|
||||
*
|
||||
* This function will then merge those changes into a single change range valid between V1 and
|
||||
* Vn.
|
||||
*/
|
||||
public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
|
||||
if (changes.length === 0) {
|
||||
return TextChangeRange.unchanged;
|
||||
}
|
||||
|
||||
if (changes.length === 1) {
|
||||
return changes[0];
|
||||
}
|
||||
|
||||
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
|
||||
// as it makes things much easier to reason about.
|
||||
var change0 = changes[0];
|
||||
|
||||
var oldStartN = change0.span().start();
|
||||
var oldEndN = change0.span().end();
|
||||
var newEndN = oldStartN + change0.newLength();
|
||||
|
||||
for (var i = 1; i < changes.length; i++) {
|
||||
var nextChange = changes[i];
|
||||
|
||||
// Consider the following case:
|
||||
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
|
||||
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
|
||||
// i.e. the span starting at 30 with length 30 is increased to length 40.
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | \
|
||||
// | \
|
||||
// T2 | \
|
||||
// | \
|
||||
// | \
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
|
||||
// it's just the min of the old and new starts. i.e.:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// ------------------------------------------------------------*------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ----------------------------------------$-------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// (Note the dots represent the newly inferrred start.
|
||||
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
|
||||
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
|
||||
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
|
||||
// means:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// --------------------------------------------------------------------------------*----------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ------------------------------------------------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
|
||||
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
|
||||
// that's the same as if we started at char 80 instead of 60.
|
||||
//
|
||||
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
|
||||
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
|
||||
// first.
|
||||
//
|
||||
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
|
||||
// semantics: { { start: 10, length: 70 }, newLength: 60 }
|
||||
//
|
||||
// The math then works out as follows.
|
||||
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
|
||||
// final result like so:
|
||||
//
|
||||
// {
|
||||
// oldStart3: Min(oldStart1, oldStart2),
|
||||
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
|
||||
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
|
||||
// }
|
||||
|
||||
var oldStart1 = oldStartN;
|
||||
var oldEnd1 = oldEndN;
|
||||
var newEnd1 = newEndN;
|
||||
|
||||
var oldStart2 = nextChange.span().start();
|
||||
var oldEnd2 = nextChange.span().end();
|
||||
var newEnd2 = oldStart2 + nextChange.newLength();
|
||||
|
||||
oldStartN = Math.min(oldStart1, oldStart2);
|
||||
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
|
||||
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
|
||||
}
|
||||
|
||||
return new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
|
||||
}
|
||||
}
|
||||
|
||||
export interface ClassifiedSpan {
|
||||
textSpan: TextSpan;
|
||||
classificationType: string; // ClassificationTypeNames
|
||||
|
@ -1115,6 +1412,23 @@ module ts {
|
|||
documentation: SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
export interface OutliningSpan {
|
||||
/** The span of the document to actually collapse. */
|
||||
textSpan: TextSpan;
|
||||
|
||||
/** The span of the document to display when the user hovers over the collapsed span. */
|
||||
hintSpan: TextSpan;
|
||||
|
||||
/** The text to display in the editor for the collapsed region. */
|
||||
bannerText: string;
|
||||
|
||||
/**
|
||||
* Whether or not this region should be automatically collapsed when
|
||||
* the 'Collapse to Definitions' command is invoked.
|
||||
*/
|
||||
autoCollapse: boolean;
|
||||
}
|
||||
|
||||
export interface EmitOutput {
|
||||
outputFiles: OutputFile[];
|
||||
emitOutputStatus: EmitReturnStatus;
|
||||
|
@ -1332,6 +1646,10 @@ module ts {
|
|||
owners: string[];
|
||||
}
|
||||
|
||||
export interface DisplayPartsSymbolWriter extends SymbolWriter {
|
||||
displayParts(): SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
export function displayPartsToString(displayParts: SymbolDisplayPart[]) {
|
||||
if (displayParts) {
|
||||
return map(displayParts, displayPart => displayPart.text).join("");
|
||||
|
@ -1340,100 +1658,6 @@ module ts {
|
|||
return "";
|
||||
}
|
||||
|
||||
export interface DisplayPartsSymbolWriter extends SymbolWriter {
|
||||
displayParts(): SymbolDisplayPart[];
|
||||
}
|
||||
|
||||
var displayPartWriter = getDisplayPartWriter();
|
||||
function getDisplayPartWriter(): DisplayPartsSymbolWriter {
|
||||
var displayParts: SymbolDisplayPart[];
|
||||
var lineStart: boolean;
|
||||
var indent: number;
|
||||
|
||||
resetWriter();
|
||||
return {
|
||||
displayParts: () => displayParts,
|
||||
writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword),
|
||||
writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator),
|
||||
writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation),
|
||||
writeSpace: text => writeKind(text, SymbolDisplayPartKind.space),
|
||||
writeStringLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
|
||||
writeParameter: text => writeKind(text, SymbolDisplayPartKind.parameterName),
|
||||
writeSymbol,
|
||||
writeLine,
|
||||
increaseIndent: () => { indent++; },
|
||||
decreaseIndent: () => { indent--; },
|
||||
clear: resetWriter,
|
||||
trackSymbol: () => { }
|
||||
};
|
||||
|
||||
function writeIndent() {
|
||||
if (lineStart) {
|
||||
var indentString = getIndentString(indent);
|
||||
if (indentString) {
|
||||
displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space));
|
||||
}
|
||||
lineStart = false;
|
||||
}
|
||||
}
|
||||
|
||||
function writeKind(text: string, kind: SymbolDisplayPartKind) {
|
||||
writeIndent();
|
||||
displayParts.push(displayPart(text, kind));
|
||||
}
|
||||
|
||||
function writeSymbol(text: string, symbol: Symbol) {
|
||||
writeIndent();
|
||||
displayParts.push(symbolPart(text, symbol));
|
||||
}
|
||||
|
||||
function writeLine() {
|
||||
displayParts.push(lineBreakPart());
|
||||
lineStart = true;
|
||||
}
|
||||
|
||||
function resetWriter() {
|
||||
displayParts = []
|
||||
lineStart = true;
|
||||
indent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function displayPart(text: string, kind: SymbolDisplayPartKind, symbol?: Symbol): SymbolDisplayPart {
|
||||
return <SymbolDisplayPart> {
|
||||
text: text,
|
||||
kind: SymbolDisplayPartKind[kind]
|
||||
};
|
||||
}
|
||||
|
||||
export function spacePart() {
|
||||
return displayPart(" ", SymbolDisplayPartKind.space);
|
||||
}
|
||||
|
||||
export function keywordPart(kind: SyntaxKind) {
|
||||
return displayPart(tokenToString(kind), SymbolDisplayPartKind.keyword);
|
||||
}
|
||||
|
||||
export function punctuationPart(kind: SyntaxKind) {
|
||||
return displayPart(tokenToString(kind), SymbolDisplayPartKind.punctuation);
|
||||
}
|
||||
|
||||
export function operatorPart(kind: SyntaxKind) {
|
||||
return displayPart(tokenToString(kind), SymbolDisplayPartKind.operator);
|
||||
}
|
||||
|
||||
export function textPart(text: string) {
|
||||
return displayPart(text, SymbolDisplayPartKind.text);
|
||||
}
|
||||
|
||||
export function lineBreakPart() {
|
||||
return displayPart("\n", SymbolDisplayPartKind.lineBreak);
|
||||
}
|
||||
|
||||
function isFirstDeclarationOfSymbolParameter(symbol: Symbol) {
|
||||
return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter;
|
||||
}
|
||||
|
||||
function isLocalVariableOrFunction(symbol: Symbol) {
|
||||
if (symbol.parent) {
|
||||
return false; // This is exported symbol
|
||||
|
@ -1462,59 +1686,6 @@ module ts {
|
|||
});
|
||||
}
|
||||
|
||||
export function symbolPart(text: string, symbol: Symbol) {
|
||||
return displayPart(text, displayPartKind(symbol), symbol);
|
||||
|
||||
function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
|
||||
var flags = symbol.flags;
|
||||
|
||||
if (flags & SymbolFlags.Variable) {
|
||||
return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName;
|
||||
}
|
||||
else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; }
|
||||
else if (flags & SymbolFlags.GetAccessor) { return SymbolDisplayPartKind.propertyName; }
|
||||
else if (flags & SymbolFlags.SetAccessor) { return SymbolDisplayPartKind.propertyName; }
|
||||
else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; }
|
||||
else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; }
|
||||
else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; }
|
||||
else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; }
|
||||
else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; }
|
||||
else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; }
|
||||
else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; }
|
||||
else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; }
|
||||
else if (flags & SymbolFlags.TypeAlias) { return SymbolDisplayPartKind.aliasName; }
|
||||
else if (flags & SymbolFlags.Import) { return SymbolDisplayPartKind.aliasName; }
|
||||
|
||||
|
||||
return SymbolDisplayPartKind.text;
|
||||
}
|
||||
}
|
||||
|
||||
export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
|
||||
writeDisplayParts(displayPartWriter);
|
||||
var result = displayPartWriter.displayParts();
|
||||
displayPartWriter.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
|
||||
return mapToDisplayParts(writer => {
|
||||
typechecker.getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
|
||||
});
|
||||
}
|
||||
|
||||
export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): SymbolDisplayPart[] {
|
||||
return mapToDisplayParts(writer => {
|
||||
typeChecker.getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning, flags);
|
||||
});
|
||||
}
|
||||
|
||||
function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[]{
|
||||
return mapToDisplayParts(writer => {
|
||||
typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags);
|
||||
});
|
||||
}
|
||||
|
||||
export function getDefaultCompilerOptions(): CompilerOptions {
|
||||
// Set "ScriptTarget.Latest" target by default for language service
|
||||
return {
|
||||
|
@ -1523,20 +1694,6 @@ module ts {
|
|||
};
|
||||
}
|
||||
|
||||
export function compareDataObjects(dst: any, src: any): boolean {
|
||||
for (var e in dst) {
|
||||
if (typeof dst[e] === "object") {
|
||||
if (!compareDataObjects(dst[e], src[e]))
|
||||
return false;
|
||||
}
|
||||
else if (typeof dst[e] !== "function") {
|
||||
if (dst[e] !== src[e])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export class OperationCanceledException { }
|
||||
|
||||
export class CancellationTokenObject {
|
||||
|
@ -1893,20 +2050,6 @@ module ts {
|
|||
}
|
||||
|
||||
/// Helpers
|
||||
export function getNodeModifiers(node: Node): string {
|
||||
var flags = node.flags;
|
||||
var result: string[] = [];
|
||||
|
||||
if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier);
|
||||
if (flags & NodeFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier);
|
||||
if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier);
|
||||
if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier);
|
||||
if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier);
|
||||
if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier);
|
||||
|
||||
return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none;
|
||||
}
|
||||
|
||||
function getTargetLabel(referenceNode: Node, labelName: string): Identifier {
|
||||
while (referenceNode) {
|
||||
if (referenceNode.kind === SyntaxKind.LabeledStatement && (<LabeledStatement>referenceNode).label.text === labelName) {
|
||||
|
@ -2084,12 +2227,12 @@ module ts {
|
|||
var useCaseSensitivefilenames = false;
|
||||
var sourceFilesByName: Map<SourceFile> = {};
|
||||
var documentRegistry = documentRegistry;
|
||||
var cancellationToken = new CancellationTokenObject(host.getCancellationToken());
|
||||
var cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
|
||||
var activeCompletionSession: CompletionSession; // The current active completion session, used to get the completion entry details
|
||||
var writer: (filename: string, data: string, writeByteOrderMark: boolean) => void = undefined;
|
||||
|
||||
// Check if the localized messages json is set, otherwise query the host for it
|
||||
if (!localizedDiagnosticMessages) {
|
||||
if (!localizedDiagnosticMessages && host.getLocalizedDiagnosticMessages) {
|
||||
localizedDiagnosticMessages = host.getLocalizedDiagnosticMessages();
|
||||
}
|
||||
|
||||
|
@ -2355,7 +2498,7 @@ module ts {
|
|||
};
|
||||
}
|
||||
|
||||
function getCompletionsAtPosition(filename: string, position: number, isMemberCompletion: boolean) {
|
||||
function getCompletionsAtPosition(filename: string, position: number) {
|
||||
synchronizeHostData();
|
||||
|
||||
filename = normalizeSlashes(filename);
|
||||
|
@ -2430,7 +2573,7 @@ module ts {
|
|||
if (isRightOfDot) {
|
||||
// Right of dot member completion list
|
||||
var symbols: Symbol[] = [];
|
||||
isMemberCompletion = true;
|
||||
var isMemberCompletion = true;
|
||||
|
||||
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.QualifiedName || node.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
var symbol = typeInfoResolver.getSymbolAtLocation(node);
|
||||
|
|
|
@ -88,7 +88,7 @@ module ts {
|
|||
|
||||
getSyntacticClassifications(fileName: string, start: number, length: number): string;
|
||||
|
||||
getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): string;
|
||||
getCompletionsAtPosition(fileName: string, position: number): string;
|
||||
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
|
||||
|
||||
getQuickInfoAtPosition(fileName: string, position: number): string;
|
||||
|
@ -559,11 +559,11 @@ module ts {
|
|||
* to provide at the given source position and providing a member completion
|
||||
* list if requested.
|
||||
*/
|
||||
public getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean) {
|
||||
public getCompletionsAtPosition(fileName: string, position: number) {
|
||||
return this.forwardJSONCall(
|
||||
"getCompletionsAtPosition('" + fileName + "', " + position + ", " + isMemberCompletion + ")",
|
||||
"getCompletionsAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
var completion = this.languageService.getCompletionsAtPosition(fileName, position, isMemberCompletion);
|
||||
var completion = this.languageService.getCompletionsAtPosition(fileName, position);
|
||||
return completion;
|
||||
});
|
||||
}
|
||||
|
@ -732,6 +732,13 @@ module ts {
|
|||
private _shims: Shim[] = [];
|
||||
private documentRegistry: DocumentRegistry = createDocumentRegistry();
|
||||
|
||||
/*
|
||||
* Returns script API version.
|
||||
*/
|
||||
public getServicesVersion(): string {
|
||||
return servicesVersion;
|
||||
}
|
||||
|
||||
public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim {
|
||||
try {
|
||||
var hostAdapter = new LanguageServiceShimHostAdapter(host);
|
||||
|
|
|
@ -1,296 +0,0 @@
|
|||
module ts {
|
||||
export class TextSpan {
|
||||
private _start: number;
|
||||
private _length: number;
|
||||
|
||||
/**
|
||||
* Creates a TextSpan instance beginning with the position Start and having the Length
|
||||
* specified with length.
|
||||
*/
|
||||
constructor(start: number, length: number) {
|
||||
Debug.assert(start >= 0, "start");
|
||||
Debug.assert(length >= 0, "length");
|
||||
|
||||
this._start = start;
|
||||
this._length = length;
|
||||
}
|
||||
|
||||
public toJSON(key: any): any {
|
||||
return { start: this._start, length: this._length };
|
||||
}
|
||||
|
||||
public start(): number {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
public length(): number {
|
||||
return this._length;
|
||||
}
|
||||
|
||||
public end(): number {
|
||||
return this._start + this._length;
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return this._length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the position lies within the span. Returns true if the position is greater than or equal to Start and strictly less
|
||||
* than End, otherwise false.
|
||||
* @param position The position to check.
|
||||
*/
|
||||
public containsPosition(position: number): boolean {
|
||||
return position >= this._start && position < this.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether span falls completely within this span. Returns true if the specified span falls completely within this span, otherwise false.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public containsTextSpan(span: TextSpan): boolean {
|
||||
return span._start >= this._start && span.end() <= this.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given span overlaps this span. Two spans are considered to overlap
|
||||
* if they have positions in common and neither is empty. Empty spans do not overlap with any
|
||||
* other span. Returns true if the spans overlap, false otherwise.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public overlapsWith(span: TextSpan): boolean {
|
||||
var overlapStart = Math.max(this._start, span._start);
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
|
||||
return overlapStart < overlapEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overlap with the given span, or undefined if there is no overlap.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public overlap(span: TextSpan): TextSpan {
|
||||
var overlapStart = Math.max(this._start, span._start);
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
|
||||
if (overlapStart < overlapEnd) {
|
||||
return TextSpan.fromBounds(overlapStart, overlapEnd);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether span intersects this span. Two spans are considered to
|
||||
* intersect if they have positions in common or the end of one span
|
||||
* coincides with the start of the other span. Returns true if the spans intersect, false otherwise.
|
||||
* @param The span to check.
|
||||
*/
|
||||
public intersectsWithTextSpan(span: TextSpan): boolean {
|
||||
return span._start <= this.end() && span.end() >= this._start;
|
||||
}
|
||||
|
||||
public intersectsWith(start: number, length: number): boolean {
|
||||
var end = start + length;
|
||||
return start <= this.end() && end >= this._start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given position intersects this span.
|
||||
* A position is considered to intersect if it is between the start and
|
||||
* end positions (inclusive) of this span. Returns true if the position intersects, false otherwise.
|
||||
* @param position The position to check.
|
||||
*/
|
||||
public intersectsWithPosition(position: number): boolean {
|
||||
return position <= this.end() && position >= this._start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intersection with the given span, or undefined if there is no intersection.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public intersection(span: TextSpan): TextSpan {
|
||||
var intersectStart = Math.max(this._start, span._start);
|
||||
var intersectEnd = Math.min(this.end(), span.end());
|
||||
|
||||
if (intersectStart <= intersectEnd) {
|
||||
return TextSpan.fromBounds(intersectStart, intersectEnd);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextSpan from the given start and end positions
|
||||
* as opposed to a position and length.
|
||||
*/
|
||||
public static fromBounds(start: number, end: number): TextSpan {
|
||||
Debug.assert(start >= 0);
|
||||
Debug.assert(end - start >= 0);
|
||||
return new TextSpan(start, end - start);
|
||||
}
|
||||
}
|
||||
|
||||
export class TextChangeRange {
|
||||
public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0);
|
||||
|
||||
private _span: TextSpan;
|
||||
private _newLength: number;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of TextChangeRange.
|
||||
*/
|
||||
constructor(span: TextSpan, newLength: number) {
|
||||
Debug.assert(newLength >= 0, "newLength");
|
||||
|
||||
this._span = span;
|
||||
this._newLength = newLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* The span of text before the edit which is being changed
|
||||
*/
|
||||
public span(): TextSpan {
|
||||
return this._span;
|
||||
}
|
||||
|
||||
/**
|
||||
* Width of the span after the edit. A 0 here would represent a delete
|
||||
*/
|
||||
public newLength(): number {
|
||||
return this._newLength;
|
||||
}
|
||||
|
||||
public newSpan(): TextSpan {
|
||||
return new TextSpan(this.span().start(), this.newLength());
|
||||
}
|
||||
|
||||
public isUnchanged(): boolean {
|
||||
return this.span().isEmpty() && this.newLength() === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to merge all the changes that occurred across several versions of a script snapshot
|
||||
* into a single change. i.e. if a user keeps making successive edits to a script we will
|
||||
* have a text change from V1 to V2, V2 to V3, ..., Vn.
|
||||
*
|
||||
* This function will then merge those changes into a single change range valid between V1 and
|
||||
* Vn.
|
||||
*/
|
||||
public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
|
||||
if (changes.length === 0) {
|
||||
return TextChangeRange.unchanged;
|
||||
}
|
||||
|
||||
if (changes.length === 1) {
|
||||
return changes[0];
|
||||
}
|
||||
|
||||
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
|
||||
// as it makes things much easier to reason about.
|
||||
var change0 = changes[0];
|
||||
|
||||
var oldStartN = change0.span().start();
|
||||
var oldEndN = change0.span().end();
|
||||
var newEndN = oldStartN + change0.newLength();
|
||||
|
||||
for (var i = 1; i < changes.length; i++) {
|
||||
var nextChange = changes[i];
|
||||
|
||||
// Consider the following case:
|
||||
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
|
||||
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
|
||||
// i.e. the span starting at 30 with length 30 is increased to length 40.
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | \
|
||||
// | \
|
||||
// T2 | \
|
||||
// | \
|
||||
// | \
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
|
||||
// it's just the min of the old and new starts. i.e.:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// ------------------------------------------------------------*------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ----------------------------------------$-------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// (Note the dots represent the newly inferrred start.
|
||||
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
|
||||
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
|
||||
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
|
||||
// means:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// --------------------------------------------------------------------------------*----------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ------------------------------------------------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
|
||||
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
|
||||
// that's the same as if we started at char 80 instead of 60.
|
||||
//
|
||||
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
|
||||
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
|
||||
// first.
|
||||
//
|
||||
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
|
||||
// semantics: { { start: 10, length: 70 }, newLength: 60 }
|
||||
//
|
||||
// The math then works out as follows.
|
||||
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
|
||||
// final result like so:
|
||||
//
|
||||
// {
|
||||
// oldStart3: Min(oldStart1, oldStart2),
|
||||
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
|
||||
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
|
||||
// }
|
||||
|
||||
var oldStart1 = oldStartN;
|
||||
var oldEnd1 = oldEndN;
|
||||
var newEnd1 = newEndN;
|
||||
|
||||
var oldStart2 = nextChange.span().start();
|
||||
var oldEnd2 = nextChange.span().end();
|
||||
var newEnd2 = oldStart2 + nextChange.newLength();
|
||||
|
||||
oldStartN = Math.min(oldStart1, oldStart2);
|
||||
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
|
||||
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
|
||||
}
|
||||
|
||||
return new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -270,7 +270,21 @@ module ts {
|
|||
return n.getWidth() !== 0;
|
||||
}
|
||||
|
||||
export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray<Node> {
|
||||
export function getNodeModifiers(node: Node): string {
|
||||
var flags = node.flags;
|
||||
var result: string[] = [];
|
||||
|
||||
if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier);
|
||||
if (flags & NodeFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier);
|
||||
if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier);
|
||||
if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier);
|
||||
if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier);
|
||||
if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier);
|
||||
|
||||
return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none;
|
||||
}
|
||||
|
||||
export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray<Node> {
|
||||
if (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.CallExpression) {
|
||||
return (<CallExpression>node).typeArguments;
|
||||
}
|
||||
|
@ -306,4 +320,166 @@ module ts {
|
|||
return isTemplateLiteralKind(node.kind)
|
||||
&& (node.getStart() < position && position < node.getEnd()) || (!!node.isUnterminated && position === node.getEnd());
|
||||
}
|
||||
|
||||
export function compareDataObjects(dst: any, src: any): boolean {
|
||||
for (var e in dst) {
|
||||
if (typeof dst[e] === "object") {
|
||||
if (!compareDataObjects(dst[e], src[e])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (typeof dst[e] !== "function") {
|
||||
if (dst[e] !== src[e]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Display-part writer helpers
|
||||
module ts {
|
||||
export function isFirstDeclarationOfSymbolParameter(symbol: Symbol) {
|
||||
return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter;
|
||||
}
|
||||
|
||||
var displayPartWriter = getDisplayPartWriter();
|
||||
function getDisplayPartWriter(): DisplayPartsSymbolWriter {
|
||||
var displayParts: SymbolDisplayPart[];
|
||||
var lineStart: boolean;
|
||||
var indent: number;
|
||||
|
||||
resetWriter();
|
||||
return {
|
||||
displayParts: () => displayParts,
|
||||
writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword),
|
||||
writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator),
|
||||
writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation),
|
||||
writeSpace: text => writeKind(text, SymbolDisplayPartKind.space),
|
||||
writeStringLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
|
||||
writeParameter: text => writeKind(text, SymbolDisplayPartKind.parameterName),
|
||||
writeSymbol,
|
||||
writeLine,
|
||||
increaseIndent: () => { indent++; },
|
||||
decreaseIndent: () => { indent--; },
|
||||
clear: resetWriter,
|
||||
trackSymbol: () => { }
|
||||
};
|
||||
|
||||
function writeIndent() {
|
||||
if (lineStart) {
|
||||
var indentString = getIndentString(indent);
|
||||
if (indentString) {
|
||||
displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space));
|
||||
}
|
||||
lineStart = false;
|
||||
}
|
||||
}
|
||||
|
||||
function writeKind(text: string, kind: SymbolDisplayPartKind) {
|
||||
writeIndent();
|
||||
displayParts.push(displayPart(text, kind));
|
||||
}
|
||||
|
||||
function writeSymbol(text: string, symbol: Symbol) {
|
||||
writeIndent();
|
||||
displayParts.push(symbolPart(text, symbol));
|
||||
}
|
||||
|
||||
function writeLine() {
|
||||
displayParts.push(lineBreakPart());
|
||||
lineStart = true;
|
||||
}
|
||||
|
||||
function resetWriter() {
|
||||
displayParts = []
|
||||
lineStart = true;
|
||||
indent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function symbolPart(text: string, symbol: Symbol) {
|
||||
return displayPart(text, displayPartKind(symbol), symbol);
|
||||
|
||||
function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
|
||||
var flags = symbol.flags;
|
||||
|
||||
if (flags & SymbolFlags.Variable) {
|
||||
return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName;
|
||||
}
|
||||
else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; }
|
||||
else if (flags & SymbolFlags.GetAccessor) { return SymbolDisplayPartKind.propertyName; }
|
||||
else if (flags & SymbolFlags.SetAccessor) { return SymbolDisplayPartKind.propertyName; }
|
||||
else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; }
|
||||
else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; }
|
||||
else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; }
|
||||
else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; }
|
||||
else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; }
|
||||
else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; }
|
||||
else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; }
|
||||
else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; }
|
||||
else if (flags & SymbolFlags.TypeAlias) { return SymbolDisplayPartKind.aliasName; }
|
||||
else if (flags & SymbolFlags.Import) { return SymbolDisplayPartKind.aliasName; }
|
||||
|
||||
|
||||
return SymbolDisplayPartKind.text;
|
||||
}
|
||||
}
|
||||
|
||||
export function displayPart(text: string, kind: SymbolDisplayPartKind, symbol?: Symbol): SymbolDisplayPart {
|
||||
return <SymbolDisplayPart> {
|
||||
text: text,
|
||||
kind: SymbolDisplayPartKind[kind]
|
||||
};
|
||||
}
|
||||
|
||||
export function spacePart() {
|
||||
return displayPart(" ", SymbolDisplayPartKind.space);
|
||||
}
|
||||
|
||||
export function keywordPart(kind: SyntaxKind) {
|
||||
return displayPart(tokenToString(kind), SymbolDisplayPartKind.keyword);
|
||||
}
|
||||
|
||||
export function punctuationPart(kind: SyntaxKind) {
|
||||
return displayPart(tokenToString(kind), SymbolDisplayPartKind.punctuation);
|
||||
}
|
||||
|
||||
export function operatorPart(kind: SyntaxKind) {
|
||||
return displayPart(tokenToString(kind), SymbolDisplayPartKind.operator);
|
||||
}
|
||||
|
||||
export function textPart(text: string) {
|
||||
return displayPart(text, SymbolDisplayPartKind.text);
|
||||
}
|
||||
|
||||
export function lineBreakPart() {
|
||||
return displayPart("\n", SymbolDisplayPartKind.lineBreak);
|
||||
}
|
||||
|
||||
export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
|
||||
writeDisplayParts(displayPartWriter);
|
||||
var result = displayPartWriter.displayParts();
|
||||
displayPartWriter.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
|
||||
return mapToDisplayParts(writer => {
|
||||
typechecker.getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
|
||||
});
|
||||
}
|
||||
|
||||
export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): SymbolDisplayPart[] {
|
||||
return mapToDisplayParts(writer => {
|
||||
typeChecker.getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning, flags);
|
||||
});
|
||||
}
|
||||
|
||||
export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
|
||||
return mapToDisplayParts(writer => {
|
||||
typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags);
|
||||
});
|
||||
}
|
||||
}
|
1865
tests/baselines/reference/APISample_node_compile.js
Normal file
1865
tests/baselines/reference/APISample_node_compile.js
Normal file
File diff suppressed because it is too large
Load diff
5749
tests/baselines/reference/APISample_node_compile.types
Normal file
5749
tests/baselines/reference/APISample_node_compile.types
Normal file
File diff suppressed because it is too large
Load diff
1862
tests/baselines/reference/APISample_standalone_compile.js
Normal file
1862
tests/baselines/reference/APISample_standalone_compile.js
Normal file
File diff suppressed because it is too large
Load diff
5756
tests/baselines/reference/APISample_standalone_compile.types
Normal file
5756
tests/baselines/reference/APISample_standalone_compile.types
Normal file
File diff suppressed because it is too large
Load diff
81
tests/baselines/reference/noImplicitAnyIndexingSuppressed.js
Normal file
81
tests/baselines/reference/noImplicitAnyIndexingSuppressed.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
//// [noImplicitAnyIndexingSuppressed.ts]
|
||||
|
||||
enum MyEmusEnum {
|
||||
emu
|
||||
}
|
||||
|
||||
// Should be okay; should be a string.
|
||||
var strRepresentation1 = MyEmusEnum[0]
|
||||
|
||||
// Should be okay; should be a string.
|
||||
var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu]
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var strRepresentation3 = MyEmusEnum["monehh"];
|
||||
|
||||
// Should be okay; should be a MyEmusEnum
|
||||
var strRepresentation4 = MyEmusEnum["emu"];
|
||||
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var x = {}["hi"];
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var y = {}[10];
|
||||
|
||||
var hi: any = "hi";
|
||||
|
||||
var emptyObj = {};
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var z1 = emptyObj[hi];
|
||||
var z2 = (<any>emptyObj)[hi];
|
||||
|
||||
interface MyMap<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
var m: MyMap<number> = {
|
||||
"0": 0,
|
||||
"1": 1,
|
||||
"2": 2,
|
||||
"Okay that's enough for today.": NaN
|
||||
};
|
||||
|
||||
var mResult1 = m[MyEmusEnum.emu];
|
||||
var mResult2 = m[MyEmusEnum[MyEmusEnum.emu]];
|
||||
var mResult3 = m[hi];
|
||||
|
||||
|
||||
|
||||
//// [noImplicitAnyIndexingSuppressed.js]
|
||||
var MyEmusEnum;
|
||||
(function (MyEmusEnum) {
|
||||
MyEmusEnum[MyEmusEnum["emu"] = 0] = "emu";
|
||||
})(MyEmusEnum || (MyEmusEnum = {}));
|
||||
// Should be okay; should be a string.
|
||||
var strRepresentation1 = MyEmusEnum[0];
|
||||
// Should be okay; should be a string.
|
||||
var strRepresentation2 = MyEmusEnum[0 /* emu */];
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var strRepresentation3 = MyEmusEnum["monehh"];
|
||||
// Should be okay; should be a MyEmusEnum
|
||||
var strRepresentation4 = 0 /* "emu" */;
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var x = {}["hi"];
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var y = {}[10];
|
||||
var hi = "hi";
|
||||
var emptyObj = {};
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var z1 = emptyObj[hi];
|
||||
var z2 = emptyObj[hi];
|
||||
var m = {
|
||||
"0": 0,
|
||||
"1": 1,
|
||||
"2": 2,
|
||||
"Okay that's enough for today.": NaN
|
||||
};
|
||||
var mResult1 = m[0 /* emu */];
|
||||
var mResult2 = m[MyEmusEnum[0 /* emu */]];
|
||||
var mResult3 = m[hi];
|
118
tests/baselines/reference/noImplicitAnyIndexingSuppressed.types
Normal file
118
tests/baselines/reference/noImplicitAnyIndexingSuppressed.types
Normal file
|
@ -0,0 +1,118 @@
|
|||
=== tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts ===
|
||||
|
||||
enum MyEmusEnum {
|
||||
>MyEmusEnum : MyEmusEnum
|
||||
|
||||
emu
|
||||
>emu : MyEmusEnum
|
||||
}
|
||||
|
||||
// Should be okay; should be a string.
|
||||
var strRepresentation1 = MyEmusEnum[0]
|
||||
>strRepresentation1 : string
|
||||
>MyEmusEnum[0] : string
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
|
||||
// Should be okay; should be a string.
|
||||
var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu]
|
||||
>strRepresentation2 : string
|
||||
>MyEmusEnum[MyEmusEnum.emu] : string
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
>MyEmusEnum.emu : MyEmusEnum
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
>emu : MyEmusEnum
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var strRepresentation3 = MyEmusEnum["monehh"];
|
||||
>strRepresentation3 : any
|
||||
>MyEmusEnum["monehh"] : any
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
|
||||
// Should be okay; should be a MyEmusEnum
|
||||
var strRepresentation4 = MyEmusEnum["emu"];
|
||||
>strRepresentation4 : MyEmusEnum
|
||||
>MyEmusEnum["emu"] : MyEmusEnum
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var x = {}["hi"];
|
||||
>x : any
|
||||
>{}["hi"] : any
|
||||
>{} : {}
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var y = {}[10];
|
||||
>y : any
|
||||
>{}[10] : any
|
||||
>{} : {}
|
||||
|
||||
var hi: any = "hi";
|
||||
>hi : any
|
||||
|
||||
var emptyObj = {};
|
||||
>emptyObj : {}
|
||||
>{} : {}
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var z1 = emptyObj[hi];
|
||||
>z1 : any
|
||||
>emptyObj[hi] : any
|
||||
>emptyObj : {}
|
||||
>hi : any
|
||||
|
||||
var z2 = (<any>emptyObj)[hi];
|
||||
>z2 : any
|
||||
>(<any>emptyObj)[hi] : any
|
||||
>(<any>emptyObj) : any
|
||||
><any>emptyObj : any
|
||||
>emptyObj : {}
|
||||
>hi : any
|
||||
|
||||
interface MyMap<T> {
|
||||
>MyMap : MyMap<T>
|
||||
>T : T
|
||||
|
||||
[key: string]: T;
|
||||
>key : string
|
||||
>T : T
|
||||
}
|
||||
|
||||
var m: MyMap<number> = {
|
||||
>m : MyMap<number>
|
||||
>MyMap : MyMap<T>
|
||||
>{ "0": 0, "1": 1, "2": 2, "Okay that's enough for today.": NaN} : { [x: string]: number; "0": number; "1": number; "2": number; "Okay that's enough for today.": number; }
|
||||
|
||||
"0": 0,
|
||||
"1": 1,
|
||||
"2": 2,
|
||||
"Okay that's enough for today.": NaN
|
||||
>NaN : number
|
||||
|
||||
};
|
||||
|
||||
var mResult1 = m[MyEmusEnum.emu];
|
||||
>mResult1 : number
|
||||
>m[MyEmusEnum.emu] : number
|
||||
>m : MyMap<number>
|
||||
>MyEmusEnum.emu : MyEmusEnum
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
>emu : MyEmusEnum
|
||||
|
||||
var mResult2 = m[MyEmusEnum[MyEmusEnum.emu]];
|
||||
>mResult2 : number
|
||||
>m[MyEmusEnum[MyEmusEnum.emu]] : number
|
||||
>m : MyMap<number>
|
||||
>MyEmusEnum[MyEmusEnum.emu] : string
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
>MyEmusEnum.emu : MyEmusEnum
|
||||
>MyEmusEnum : typeof MyEmusEnum
|
||||
>emu : MyEmusEnum
|
||||
|
||||
var mResult3 = m[hi];
|
||||
>mResult3 : number
|
||||
>m[hi] : number
|
||||
>m : MyMap<number>
|
||||
>hi : any
|
||||
|
||||
|
18
tests/baselines/reference/typeGuardsWithAny.js
Normal file
18
tests/baselines/reference/typeGuardsWithAny.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
//// [typeGuardsWithAny.ts]
|
||||
var x: any = { p: 0 };
|
||||
if (x instanceof Object) {
|
||||
x.p; // No error, type any unaffected by type guard
|
||||
}
|
||||
else {
|
||||
x.p; // No error, type any unaffected by type guard
|
||||
}
|
||||
|
||||
|
||||
//// [typeGuardsWithAny.js]
|
||||
var x = { p: 0 };
|
||||
if (x instanceof Object) {
|
||||
x.p; // No error, type any unaffected by type guard
|
||||
}
|
||||
else {
|
||||
x.p; // No error, type any unaffected by type guard
|
||||
}
|
23
tests/baselines/reference/typeGuardsWithAny.types
Normal file
23
tests/baselines/reference/typeGuardsWithAny.types
Normal file
|
@ -0,0 +1,23 @@
|
|||
=== tests/cases/conformance/expressions/typeGuards/typeGuardsWithAny.ts ===
|
||||
var x: any = { p: 0 };
|
||||
>x : any
|
||||
>{ p: 0 } : { p: number; }
|
||||
>p : number
|
||||
|
||||
if (x instanceof Object) {
|
||||
>x instanceof Object : boolean
|
||||
>x : any
|
||||
>Object : ObjectConstructor
|
||||
|
||||
x.p; // No error, type any unaffected by type guard
|
||||
>x.p : any
|
||||
>x : any
|
||||
>p : any
|
||||
}
|
||||
else {
|
||||
x.p; // No error, type any unaffected by type guard
|
||||
>x.p : any
|
||||
>x : any
|
||||
>p : any
|
||||
}
|
||||
|
11
tests/cases/compiler/APISample_node_compile.ts
Normal file
11
tests/cases/compiler/APISample_node_compile.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
// @includeBuiltFile: typescript.d.ts
|
||||
// @noImplicitAny: true
|
||||
// @target: ES3
|
||||
// @module: CommonJs
|
||||
// @noresolve: true
|
||||
|
||||
import ts = require("typescript");
|
||||
|
||||
var sourceFile = ts.createSourceFile("file1.ts", "var x = 0;", ts.ScriptTarget.Latest, "0.0");
|
||||
|
||||
var program = ts.createProgram(["file1.ts"], {}, undefined);
|
7
tests/cases/compiler/APISample_standalone_compile.ts
Normal file
7
tests/cases/compiler/APISample_standalone_compile.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
// @includeBuiltFile: typescriptServices.d.ts
|
||||
// @noImplicitAny: true
|
||||
// @target: ES3
|
||||
|
||||
var sourceFile = ts.createSourceFile("file1.ts", "var x = 0;", ts.ScriptTarget.Latest, "0.0");
|
||||
|
||||
var program = ts.createProgram(["file1.ts"], {}, undefined);
|
49
tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts
Normal file
49
tests/cases/compiler/noImplicitAnyIndexingSuppressed.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
//@noImplicitAny: true
|
||||
//@suppressImplicitAnyIndexErrors: true
|
||||
|
||||
enum MyEmusEnum {
|
||||
emu
|
||||
}
|
||||
|
||||
// Should be okay; should be a string.
|
||||
var strRepresentation1 = MyEmusEnum[0]
|
||||
|
||||
// Should be okay; should be a string.
|
||||
var strRepresentation2 = MyEmusEnum[MyEmusEnum.emu]
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var strRepresentation3 = MyEmusEnum["monehh"];
|
||||
|
||||
// Should be okay; should be a MyEmusEnum
|
||||
var strRepresentation4 = MyEmusEnum["emu"];
|
||||
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var x = {}["hi"];
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var y = {}[10];
|
||||
|
||||
var hi: any = "hi";
|
||||
|
||||
var emptyObj = {};
|
||||
|
||||
// Should be okay, as we suppress implicit 'any' property access checks
|
||||
var z1 = emptyObj[hi];
|
||||
var z2 = (<any>emptyObj)[hi];
|
||||
|
||||
interface MyMap<T> {
|
||||
[key: string]: T;
|
||||
}
|
||||
|
||||
var m: MyMap<number> = {
|
||||
"0": 0,
|
||||
"1": 1,
|
||||
"2": 2,
|
||||
"Okay that's enough for today.": NaN
|
||||
};
|
||||
|
||||
var mResult1 = m[MyEmusEnum.emu];
|
||||
var mResult2 = m[MyEmusEnum[MyEmusEnum.emu]];
|
||||
var mResult3 = m[hi];
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
var x: any = { p: 0 };
|
||||
if (x instanceof Object) {
|
||||
x.p; // No error, type any unaffected by type guard
|
||||
}
|
||||
else {
|
||||
x.p; // No error, type any unaffected by type guard
|
||||
}
|
Loading…
Reference in a new issue