mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into JSLS
Conflicts: src/services/services.ts
This commit is contained in:
+60
-183
@@ -5,6 +5,12 @@ module ts {
|
||||
let nextNodeId = 1;
|
||||
let nextMergeId = 1;
|
||||
|
||||
// @internal
|
||||
export function getNodeId(node: Node): number {
|
||||
if (!node.id) node.id = nextNodeId++;
|
||||
return node.id;
|
||||
}
|
||||
|
||||
/* @internal */ export let checkTime = 0;
|
||||
|
||||
/* @internal */
|
||||
@@ -264,8 +270,8 @@ module ts {
|
||||
}
|
||||
|
||||
function getNodeLinks(node: Node): NodeLinks {
|
||||
if (!node.id) node.id = nextNodeId++;
|
||||
return nodeLinks[node.id] || (nodeLinks[node.id] = {});
|
||||
let nodeId = getNodeId(node);
|
||||
return nodeLinks[nodeId] || (nodeLinks[nodeId] = {});
|
||||
}
|
||||
|
||||
function getSourceFile(node: Node): SourceFile {
|
||||
@@ -7248,7 +7254,6 @@ module ts {
|
||||
case SyntaxKind.ElementAccessExpression: {
|
||||
let index = (<ElementAccessExpression>n).argumentExpression;
|
||||
let symbol = findSymbol((<ElementAccessExpression>n).expression);
|
||||
|
||||
if (symbol && index && index.kind === SyntaxKind.StringLiteral) {
|
||||
let name = (<LiteralExpression>index).text;
|
||||
let prop = getPropertyOfType(getTypeOfSymbol(symbol), name);
|
||||
@@ -7263,14 +7268,37 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function isImportedNameFromExternalModule(n: Node): boolean {
|
||||
switch (n.kind) {
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
case SyntaxKind.PropertyAccessExpression: {
|
||||
// all bindings for external module should be immutable
|
||||
// so attempt to use a.b or a[b] as lhs will always fail
|
||||
// no matter what b is
|
||||
let symbol = findSymbol((<PropertyAccessExpression | ElementAccessExpression>n).expression);
|
||||
return symbol && symbol.flags & SymbolFlags.Alias && isExternalModuleSymbol(resolveAlias(symbol));
|
||||
}
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return isImportedNameFromExternalModule((<ParenthesizedExpression>n).expression);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isReferenceOrErrorExpression(n)) {
|
||||
error(n, invalidReferenceMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isConstVariableReference(n)) {
|
||||
error(n, constantVariableMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isImportedNameFromExternalModule(n)) {
|
||||
error(n, invalidReferenceMessage);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10556,7 +10584,7 @@ module ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getSymbolsInScope(location: Node, meaning: SymbolFlags, predicate?: (symbol: Symbol) => boolean): Symbol[] {
|
||||
function getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[] {
|
||||
let symbols: SymbolTable = {};
|
||||
let memberFlags: NodeFlags = 0;
|
||||
|
||||
@@ -10572,85 +10600,58 @@ module ts {
|
||||
function populateSymbols() {
|
||||
while (location) {
|
||||
if (location.locals && !isGlobalSourceFile(location)) {
|
||||
if (copySymbols(location.locals, meaning)) {
|
||||
return;
|
||||
}
|
||||
copySymbols(location.locals, meaning);
|
||||
}
|
||||
|
||||
switch (location.kind) {
|
||||
case SyntaxKind.SourceFile:
|
||||
if (!isExternalModule(<SourceFile>location)) {
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
if (copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember)) {
|
||||
return;
|
||||
}
|
||||
copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember);
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
if (copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.EnumMember)) {
|
||||
return;
|
||||
}
|
||||
copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.EnumMember);
|
||||
break;
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
if (!(memberFlags & NodeFlags.Static)) {
|
||||
if (copySymbols(getSymbolOfNode(location).members, meaning & SymbolFlags.Type)) {
|
||||
return;
|
||||
}
|
||||
copySymbols(getSymbolOfNode(location).members, meaning & SymbolFlags.Type);
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.FunctionExpression:
|
||||
if ((<FunctionExpression>location).name) {
|
||||
if (copySymbol(location.symbol, meaning)) {
|
||||
return;
|
||||
}
|
||||
copySymbol(location.symbol, meaning);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
memberFlags = location.flags;
|
||||
location = location.parent;
|
||||
}
|
||||
if (copySymbols(globals, meaning)) {
|
||||
return;
|
||||
}
|
||||
|
||||
copySymbols(globals, meaning);
|
||||
}
|
||||
|
||||
// Returns 'true' if we should stop processing symbols.
|
||||
function copySymbol(symbol: Symbol, meaning: SymbolFlags): boolean {
|
||||
function copySymbol(symbol: Symbol, meaning: SymbolFlags): void {
|
||||
if (symbol.flags & meaning) {
|
||||
let id = symbol.name;
|
||||
if (!isReservedMemberName(id) && !hasProperty(symbols, id)) {
|
||||
if (predicate) {
|
||||
// If we were supplied a predicate function, then check if this symbol
|
||||
// matches with it. If so, we're done and can immediately return.
|
||||
// Otherwise, just ignore this symbol and keep going.
|
||||
if (predicate(symbol)) {
|
||||
symbols[id] = symbol;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If no predicate was supplied, then just add the symbol as is.
|
||||
symbols[id] = symbol;
|
||||
}
|
||||
symbols[id] = symbol;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function copySymbols(source: SymbolTable, meaning: SymbolFlags): boolean {
|
||||
function copySymbols(source: SymbolTable, meaning: SymbolFlags): void {
|
||||
if (meaning) {
|
||||
for (let id in source) {
|
||||
if (hasProperty(source, id)) {
|
||||
if (copySymbol(source[id], meaning)) {
|
||||
return true;
|
||||
}
|
||||
copySymbol(source[id], meaning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11003,134 +11004,7 @@ module ts {
|
||||
return symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length === 1 && symbol.declarations[0].kind === SyntaxKind.SourceFile;
|
||||
}
|
||||
|
||||
function isNodeDescendentOf(node: Node, ancestor: Node): boolean {
|
||||
while (node) {
|
||||
if (node === ancestor) return true;
|
||||
node = node.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isUniqueLocalName(name: string, container: Node): boolean {
|
||||
for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) {
|
||||
if (node.locals && hasProperty(node.locals, name)) {
|
||||
// We conservatively include alias symbols to cover cases where they're emitted as locals
|
||||
if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getGeneratedNamesForSourceFile(sourceFile: SourceFile): Map<string> {
|
||||
let links = getNodeLinks(sourceFile);
|
||||
let generatedNames = links.generatedNames;
|
||||
if (!generatedNames) {
|
||||
generatedNames = links.generatedNames = {};
|
||||
generateNames(sourceFile);
|
||||
}
|
||||
return generatedNames;
|
||||
|
||||
function generateNames(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
generateNameForFunctionOrClassDeclaration(<Declaration>node);
|
||||
break;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
generateNameForModuleOrEnum(<ModuleDeclaration>node);
|
||||
generateNames((<ModuleDeclaration>node).body);
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
generateNameForModuleOrEnum(<EnumDeclaration>node);
|
||||
break;
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
generateNameForImportDeclaration(<ImportDeclaration>node);
|
||||
break;
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
generateNameForExportDeclaration(<ExportDeclaration>node);
|
||||
break;
|
||||
case SyntaxKind.ExportAssignment:
|
||||
generateNameForExportAssignment(<ExportAssignment>node);
|
||||
break;
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
forEach((<SourceFile | ModuleBlock>node).statements, generateNames);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function isExistingName(name: string) {
|
||||
return hasProperty(globals, name) || hasProperty(sourceFile.identifiers, name) || hasProperty(generatedNames, name);
|
||||
}
|
||||
|
||||
function makeUniqueName(baseName: string): string {
|
||||
let name = generateUniqueName(baseName, isExistingName);
|
||||
return generatedNames[name] = name;
|
||||
}
|
||||
|
||||
function assignGeneratedName(node: Node, name: string) {
|
||||
getNodeLinks(node).generatedName = unescapeIdentifier(name);
|
||||
}
|
||||
|
||||
function generateNameForFunctionOrClassDeclaration(node: Declaration) {
|
||||
if (!node.name) {
|
||||
assignGeneratedName(node, makeUniqueName("default"));
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) {
|
||||
if (node.name.kind === SyntaxKind.Identifier) {
|
||||
let name = node.name.text;
|
||||
// Use module/enum name itself if it is unique, otherwise make a unique variation
|
||||
assignGeneratedName(node, isUniqueLocalName(name, node) ? name : makeUniqueName(name));
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) {
|
||||
let expr = getExternalModuleName(node);
|
||||
let baseName = expr.kind === SyntaxKind.StringLiteral ?
|
||||
escapeIdentifier(makeIdentifierFromModuleName((<LiteralExpression>expr).text)) : "module";
|
||||
assignGeneratedName(node, makeUniqueName(baseName));
|
||||
}
|
||||
|
||||
function generateNameForImportDeclaration(node: ImportDeclaration) {
|
||||
if (node.importClause && node.importClause.namedBindings && node.importClause.namedBindings.kind === SyntaxKind.NamedImports) {
|
||||
generateNameForImportOrExportDeclaration(node);
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameForExportDeclaration(node: ExportDeclaration) {
|
||||
if (node.moduleSpecifier) {
|
||||
generateNameForImportOrExportDeclaration(node);
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameForExportAssignment(node: ExportAssignment) {
|
||||
if (node.expression && node.expression.kind !== SyntaxKind.Identifier) {
|
||||
assignGeneratedName(node, makeUniqueName("default"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getGeneratedNameForNode(node: Node) {
|
||||
let links = getNodeLinks(node);
|
||||
if (!links.generatedName) {
|
||||
getGeneratedNamesForSourceFile(getSourceFile(node));
|
||||
}
|
||||
return links.generatedName;
|
||||
}
|
||||
|
||||
function getLocalNameOfContainer(container: ModuleDeclaration | EnumDeclaration): string {
|
||||
return getGeneratedNameForNode(container);
|
||||
}
|
||||
|
||||
function getLocalNameForImportDeclaration(node: ImportDeclaration): string {
|
||||
return getGeneratedNameForNode(node);
|
||||
}
|
||||
|
||||
function getAliasNameSubstitution(symbol: Symbol): string {
|
||||
function getAliasNameSubstitution(symbol: Symbol, getGeneratedNameForNode: (Node: Node) => string): string {
|
||||
let declaration = getDeclarationOfAliasSymbol(symbol);
|
||||
if (declaration && declaration.kind === SyntaxKind.ImportSpecifier) {
|
||||
let moduleName = getGeneratedNameForNode(<ImportDeclaration>declaration.parent.parent.parent);
|
||||
@@ -11139,7 +11013,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getExportNameSubstitution(symbol: Symbol, location: Node): string {
|
||||
function getExportNameSubstitution(symbol: Symbol, location: Node, getGeneratedNameForNode: (Node: Node) => string): string {
|
||||
if (isExternalModuleSymbol(symbol.parent)) {
|
||||
var symbolName = unescapeIdentifier(symbol.name);
|
||||
// If this is es6 or higher, just use the name of the export
|
||||
@@ -11161,24 +11035,24 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getExpressionNameSubstitution(node: Identifier): string {
|
||||
function getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (Node: Node) => string): string {
|
||||
let symbol = getNodeLinks(node).resolvedSymbol;
|
||||
if (symbol) {
|
||||
// Whan an identifier resolves to a parented symbol, it references an exported entity from
|
||||
// another declaration of the same internal module.
|
||||
if (symbol.parent) {
|
||||
return getExportNameSubstitution(symbol, node.parent);
|
||||
return getExportNameSubstitution(symbol, node.parent, getGeneratedNameForNode);
|
||||
}
|
||||
// If we reference an exported entity within the same module declaration, then whether
|
||||
// we prefix depends on the kind of entity. SymbolFlags.ExportHasLocal encompasses all the
|
||||
// kinds that we do NOT prefix.
|
||||
let exportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
|
||||
if (symbol !== exportSymbol && !(exportSymbol.flags & SymbolFlags.ExportHasLocal)) {
|
||||
return getExportNameSubstitution(exportSymbol, node.parent);
|
||||
return getExportNameSubstitution(exportSymbol, node.parent, getGeneratedNameForNode);
|
||||
}
|
||||
// Named imports from ES6 import declarations are rewritten
|
||||
if (symbol.flags & SymbolFlags.Alias && languageVersion < ScriptTarget.ES6) {
|
||||
return getAliasNameSubstitution(symbol);
|
||||
return getAliasNameSubstitution(symbol, getGeneratedNameForNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11281,10 +11155,13 @@ module ts {
|
||||
getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
|
||||
}
|
||||
|
||||
function isUnknownIdentifier(location: Node, name: string): boolean {
|
||||
Debug.assert(!nodeIsSynthesized(location), "isUnknownIdentifier called with a synthesized location");
|
||||
return !resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined) &&
|
||||
!hasProperty(getGeneratedNamesForSourceFile(getSourceFile(location)), name);
|
||||
function hasGlobalName(name: string): boolean {
|
||||
return hasProperty(globals, name);
|
||||
}
|
||||
|
||||
function resolvesToSomeValue(location: Node, name: string): boolean {
|
||||
Debug.assert(!nodeIsSynthesized(location), "resolvesToSomeValue called with a synthesized location");
|
||||
return !!resolveName(location, name, SymbolFlags.Value, /*nodeNotFoundMessage*/ undefined, /*nameArg*/ undefined);
|
||||
}
|
||||
|
||||
function getBlockScopedVariableId(n: Identifier): number {
|
||||
@@ -11314,8 +11191,8 @@ module ts {
|
||||
|
||||
function createResolver(): EmitResolver {
|
||||
return {
|
||||
getGeneratedNameForNode,
|
||||
getExpressionNameSubstitution,
|
||||
hasGlobalName,
|
||||
hasExportDefaultValue,
|
||||
isReferencedAliasDeclaration,
|
||||
getNodeCheckFlags,
|
||||
@@ -11328,7 +11205,7 @@ module ts {
|
||||
isSymbolAccessible,
|
||||
isEntityNameVisible,
|
||||
getConstantValue,
|
||||
isUnknownIdentifier,
|
||||
resolvesToSomeValue,
|
||||
collectLinkedAliases,
|
||||
getBlockScopedVariableId,
|
||||
};
|
||||
|
||||
+269
-132
@@ -19,6 +19,14 @@ module ts {
|
||||
return isExternalModule(sourceFile) || isDeclarationFile(sourceFile);
|
||||
}
|
||||
|
||||
// flag enum used to request and track usages of few dedicated temp variables
|
||||
// enum values are used to set/check bit values and thus should not have bit collisions.
|
||||
const enum TempVariableKind {
|
||||
auto = 0,
|
||||
_i = 1,
|
||||
_n = 2,
|
||||
}
|
||||
|
||||
// @internal
|
||||
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
|
||||
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult {
|
||||
@@ -60,6 +68,26 @@ module ts {
|
||||
sourceMaps: sourceMapDataList
|
||||
};
|
||||
|
||||
function isNodeDescendentOf(node: Node, ancestor: Node): boolean {
|
||||
while (node) {
|
||||
if (node === ancestor) return true;
|
||||
node = node.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isUniqueLocalName(name: string, container: Node): boolean {
|
||||
for (let node = container; isNodeDescendentOf(node, container); node = node.nextContainer) {
|
||||
if (node.locals && hasProperty(node.locals, name)) {
|
||||
// We conservatively include alias symbols to cover cases where they're emitted as locals
|
||||
if (node.locals[name].flags & (SymbolFlags.Value | SymbolFlags.ExportValue | SymbolFlags.Alias)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function emitJavaScript(jsFilePath: string, root?: SourceFile) {
|
||||
let writer = createTextWriter(newLine);
|
||||
let write = writer.write;
|
||||
@@ -71,15 +99,17 @@ module ts {
|
||||
|
||||
let currentSourceFile: SourceFile;
|
||||
|
||||
let lastFrame: ScopeFrame;
|
||||
let currentScopeNames: Map<string>;
|
||||
|
||||
let generatedBlockScopeNames: string[];
|
||||
let generatedNameSet: Map<string>;
|
||||
let nodeToGeneratedName: string[];
|
||||
let blockScopedVariableToGeneratedName: string[];
|
||||
|
||||
let extendsEmitted = false;
|
||||
|
||||
let tempCount = 0;
|
||||
let tempVariables: Identifier[];
|
||||
let tempParameters: Identifier[];
|
||||
let predefinedTempsInUse = TempVariableKind.auto;
|
||||
|
||||
let externalImports: ExternalImportInfo[];
|
||||
let exportSpecifiers: Map<ExportSpecifier[]>;
|
||||
let exportDefault: FunctionDeclaration | ClassDeclaration | ExportAssignment | ExportSpecifier;
|
||||
@@ -144,81 +174,197 @@ module ts {
|
||||
emit(sourceFile);
|
||||
}
|
||||
|
||||
// enters the new lexical environment
|
||||
// return value should be passed to matching call to exitNameScope.
|
||||
function enterNameScope(): boolean {
|
||||
let names = currentScopeNames;
|
||||
currentScopeNames = undefined;
|
||||
if (names) {
|
||||
lastFrame = { names, previous: lastFrame };
|
||||
return true;
|
||||
function generateNameForNode(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
generateNameForFunctionOrClassDeclaration(<Declaration>node);
|
||||
break;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
generateNameForModuleOrEnum(<ModuleDeclaration>node);
|
||||
generateNameForNode((<ModuleDeclaration>node).body);
|
||||
break;
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
generateNameForModuleOrEnum(<EnumDeclaration>node);
|
||||
break;
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
generateNameForImportDeclaration(<ImportDeclaration>node);
|
||||
break;
|
||||
case SyntaxKind.ExportDeclaration:
|
||||
generateNameForExportDeclaration(<ExportDeclaration>node);
|
||||
break;
|
||||
case SyntaxKind.ExportAssignment:
|
||||
generateNameForExportAssignment(<ExportAssignment>node);
|
||||
break;
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
forEach((<SourceFile | ModuleBlock>node).statements, generateNameForNode);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function exitNameScope(popFrame: boolean): void {
|
||||
if (popFrame) {
|
||||
currentScopeNames = lastFrame.names;
|
||||
lastFrame = lastFrame.previous;
|
||||
function isUniqueName(name: string): boolean {
|
||||
return !resolver.hasGlobalName(name) &&
|
||||
!hasProperty(currentSourceFile.identifiers, name) &&
|
||||
(!generatedNameSet || !hasProperty(generatedNameSet, name))
|
||||
}
|
||||
|
||||
// in cases like
|
||||
// for (var x of []) {
|
||||
// _i;
|
||||
// }
|
||||
// we should be able to detect if let _i was shadowed by some temp variable that was allocated in scope
|
||||
function nameConflictsWithSomeTempVariable(name: string): boolean {
|
||||
// temp variable names always start with '_'
|
||||
if (name.length < 2 || name.charCodeAt(0) !== CharacterCodes._) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (name === "_i") {
|
||||
return !!(predefinedTempsInUse & TempVariableKind._i);
|
||||
}
|
||||
|
||||
if (name === "_n") {
|
||||
return !!(predefinedTempsInUse & TempVariableKind._n);
|
||||
}
|
||||
|
||||
if (name.length === 2 && name.charCodeAt(1) >= CharacterCodes.a && name.charCodeAt(1) <= CharacterCodes.z) {
|
||||
// handles _a .. _z
|
||||
let n = name.charCodeAt(1) - CharacterCodes.a;
|
||||
return n < tempCount;
|
||||
}
|
||||
else {
|
||||
currentScopeNames = undefined;
|
||||
// handles _1, _2...
|
||||
let n = +name.substring(1);
|
||||
return !isNaN(n) && n >= 0 && n < (tempCount - 26);
|
||||
}
|
||||
}
|
||||
|
||||
function generateUniqueNameForLocation(location: Node, baseName: string): string {
|
||||
let name: string
|
||||
// first try to check if base name can be used as is
|
||||
if (!isExistingName(location, baseName)) {
|
||||
name = baseName;
|
||||
}
|
||||
else {
|
||||
name = generateUniqueName(baseName, n => isExistingName(location, n));
|
||||
}
|
||||
|
||||
return recordNameInCurrentScope(name);
|
||||
}
|
||||
|
||||
function recordNameInCurrentScope(name: string): string {
|
||||
if (!currentScopeNames) {
|
||||
currentScopeNames = {};
|
||||
}
|
||||
|
||||
return currentScopeNames[name] = name;
|
||||
}
|
||||
|
||||
function isExistingName(location: Node, name: string) {
|
||||
// check if resolver is aware of this name (if name was seen during the typecheck)
|
||||
if (!resolver.isUnknownIdentifier(location, name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check if name is present in generated names that were introduced by the emitter
|
||||
if (currentScopeNames && hasProperty(currentScopeNames, name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check generated names in outer scopes
|
||||
// let x;
|
||||
// function foo() {
|
||||
// let x; // 1
|
||||
// function bar() {
|
||||
// {
|
||||
// let x; // 2
|
||||
// }
|
||||
// console.log(x); // 3
|
||||
// }
|
||||
//}
|
||||
// here both x(1) and x(2) should be renamed and their names should be different
|
||||
// so x in (3) will refer to x(1)
|
||||
let frame = lastFrame;
|
||||
while (frame) {
|
||||
if (hasProperty(frame.names, name)) {
|
||||
return true;
|
||||
// This function generates a name using the following pattern:
|
||||
// _a .. _h, _j ... _z, _0, _1, ...
|
||||
// It is guaranteed that generated name will not shadow any existing user-defined names,
|
||||
// however it can hide another name generated by this function higher in the scope.
|
||||
// NOTE: names generated by 'makeTempVariableName' and 'makeUniqueName' will never conflict.
|
||||
// see comment for 'makeTempVariableName' for more information.
|
||||
function makeTempVariableName(location: Node, tempVariableKind: TempVariableKind): string {
|
||||
let tempName: string;
|
||||
if (tempVariableKind !== TempVariableKind.auto && !(predefinedTempsInUse & tempVariableKind)) {
|
||||
tempName = tempVariableKind === TempVariableKind._i ? "_i" : "_n";
|
||||
if (!resolver.resolvesToSomeValue(location, tempName)) {
|
||||
predefinedTempsInUse |= tempVariableKind;
|
||||
return tempName;
|
||||
}
|
||||
frame = frame.previous;
|
||||
}
|
||||
return false;
|
||||
|
||||
do {
|
||||
// Note: we avoid generating _i and _n as those are common names we want in other places.
|
||||
var char = CharacterCodes.a + tempCount;
|
||||
if (char !== CharacterCodes.i && char !== CharacterCodes.n) {
|
||||
if (tempCount < 26) {
|
||||
tempName = "_" + String.fromCharCode(char);
|
||||
}
|
||||
else {
|
||||
tempName = "_" + (tempCount - 26);
|
||||
}
|
||||
}
|
||||
|
||||
tempCount++;
|
||||
}
|
||||
while (resolver.resolvesToSomeValue(location, tempName));
|
||||
|
||||
return tempName;
|
||||
}
|
||||
|
||||
// Generates a name that is unique within current file and does not collide with
|
||||
// any names in global scope.
|
||||
// NOTE: names generated by 'makeTempVariableName' and 'makeUniqueName' will never conflict
|
||||
// because of the way how these names are generated
|
||||
// - makeUniqueName builds a name by picking a base name (which should not be empty string)
|
||||
// and appending suffix '_<number>'
|
||||
// - makeTempVariableName creates a name using the following pattern:
|
||||
// _a .. _h, _j ... _z, _0, _1, ...
|
||||
// This means that names from 'makeTempVariableName' will have only one underscore at the beginning
|
||||
// and names from 'makeUniqieName' will have at least one underscore in the middle
|
||||
// so they will never collide.
|
||||
function makeUniqueName(baseName: string): string {
|
||||
Debug.assert(!!baseName);
|
||||
|
||||
// Find the first unique 'name_n', where n is a positive number
|
||||
if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) {
|
||||
baseName += "_";
|
||||
}
|
||||
|
||||
let i = 1;
|
||||
let generatedName: string;
|
||||
while (true) {
|
||||
generatedName = baseName + i;
|
||||
if (isUniqueName(generatedName)) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!generatedNameSet) {
|
||||
generatedNameSet = {};
|
||||
}
|
||||
return generatedNameSet[generatedName] = generatedName;
|
||||
}
|
||||
|
||||
function renameNode(node: Node, name: string): string {
|
||||
var nodeId = getNodeId(node);
|
||||
|
||||
if (!nodeToGeneratedName) {
|
||||
nodeToGeneratedName = [];
|
||||
}
|
||||
|
||||
return nodeToGeneratedName[nodeId] = unescapeIdentifier(name);
|
||||
}
|
||||
|
||||
function generateNameForFunctionOrClassDeclaration(node: Declaration) {
|
||||
if (!node.name) {
|
||||
renameNode(node, makeUniqueName("default"));
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameForModuleOrEnum(node: ModuleDeclaration | EnumDeclaration) {
|
||||
if (node.name.kind === SyntaxKind.Identifier) {
|
||||
let name = node.name.text;
|
||||
// Use module/enum name itself if it is unique, otherwise make a unique variation
|
||||
renameNode(node, isUniqueLocalName(name, node) ? name : makeUniqueName(name));
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameForImportOrExportDeclaration(node: ImportDeclaration | ExportDeclaration) {
|
||||
let expr = getExternalModuleName(node);
|
||||
let baseName = expr.kind === SyntaxKind.StringLiteral ?
|
||||
escapeIdentifier(makeIdentifierFromModuleName((<LiteralExpression>expr).text)) : "module";
|
||||
renameNode(node, makeUniqueName(baseName));
|
||||
}
|
||||
|
||||
function generateNameForImportDeclaration(node: ImportDeclaration) {
|
||||
if (node.importClause && node.importClause.namedBindings && node.importClause.namedBindings.kind === SyntaxKind.NamedImports) {
|
||||
generateNameForImportOrExportDeclaration(node);
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameForExportDeclaration(node: ExportDeclaration) {
|
||||
if (node.moduleSpecifier) {
|
||||
generateNameForImportOrExportDeclaration(node);
|
||||
}
|
||||
}
|
||||
|
||||
function generateNameForExportAssignment(node: ExportAssignment) {
|
||||
if (node.expression && node.expression.kind !== SyntaxKind.Identifier) {
|
||||
renameNode(node, makeUniqueName("default"));
|
||||
}
|
||||
}
|
||||
|
||||
function getGeneratedNameForNode(node: Node) {
|
||||
let nodeId = getNodeId(node);
|
||||
if (!nodeToGeneratedName || !nodeToGeneratedName[nodeId]) {
|
||||
generateNameForNode(node);
|
||||
}
|
||||
return nodeToGeneratedName ? nodeToGeneratedName[nodeId] : undefined;
|
||||
}
|
||||
|
||||
function initializeEmitterWithSourceMaps() {
|
||||
@@ -585,32 +731,10 @@ module ts {
|
||||
writeFile(host, diagnostics, jsFilePath, emitOutput, writeByteOrderMark);
|
||||
}
|
||||
|
||||
// Create a temporary variable with a unique unused name. The forLoopVariable parameter signals that the
|
||||
// name should be one that is appropriate for a for loop variable.
|
||||
function createTempVariable(location: Node, preferredName?: string): Identifier {
|
||||
for (var name = preferredName; !name || isExistingName(location, name); tempCount++) {
|
||||
// _a .. _h, _j ... _z, _0, _1, ...
|
||||
|
||||
// Note: we avoid generating _i and _n as those are common names we want in other places.
|
||||
var char = CharacterCodes.a + tempCount;
|
||||
if (char === CharacterCodes.i || char === CharacterCodes.n) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tempCount < 26) {
|
||||
name = "_" + String.fromCharCode(char);
|
||||
}
|
||||
else {
|
||||
name = "_" + (tempCount - 26);
|
||||
}
|
||||
}
|
||||
|
||||
// This is necessary so that a name generated via renameNonTopLevelLetAndConst will see the name
|
||||
// we just generated.
|
||||
recordNameInCurrentScope(name);
|
||||
|
||||
// Create a temporary variable with a unique unused name.
|
||||
function createTempVariable(location: Node, tempVariableKind = TempVariableKind.auto): Identifier {
|
||||
let result = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
|
||||
result.text = name;
|
||||
result.text = makeTempVariableName(location, tempVariableKind);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -621,8 +745,8 @@ module ts {
|
||||
tempVariables.push(name);
|
||||
}
|
||||
|
||||
function createAndRecordTempVariable(location: Node, preferredName?: string): Identifier {
|
||||
let temp = createTempVariable(location, preferredName);
|
||||
function createAndRecordTempVariable(location: Node, tempVariableKind?: TempVariableKind): Identifier {
|
||||
let temp = createTempVariable(location, tempVariableKind);
|
||||
recordTempDeclaration(temp);
|
||||
|
||||
return temp;
|
||||
@@ -1085,7 +1209,7 @@ module ts {
|
||||
}
|
||||
|
||||
function emitExpressionIdentifier(node: Identifier) {
|
||||
let substitution = resolver.getExpressionNameSubstitution(node);
|
||||
let substitution = resolver.getExpressionNameSubstitution(node, getGeneratedNameForNode);
|
||||
if (substitution) {
|
||||
write(substitution);
|
||||
}
|
||||
@@ -1095,7 +1219,7 @@ module ts {
|
||||
}
|
||||
|
||||
function getGeneratedNameForIdentifier(node: Identifier): string {
|
||||
if (nodeIsSynthesized(node) || !generatedBlockScopeNames) {
|
||||
if (nodeIsSynthesized(node) || !blockScopedVariableToGeneratedName) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1104,7 +1228,7 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return generatedBlockScopeNames[variableId];
|
||||
return blockScopedVariableToGeneratedName[variableId];
|
||||
}
|
||||
|
||||
function emitIdentifier(node: Identifier, allowGeneratedIdentifiers: boolean) {
|
||||
@@ -1332,7 +1456,7 @@ module ts {
|
||||
// manage by just emitting strings (which is a lot more performant).
|
||||
//let prefix = createIdentifier(resolver.getExpressionNamePrefix((<ShorthandPropertyAssignment>property).name));
|
||||
//return createPropertyAccessExpression(prefix, (<ShorthandPropertyAssignment>property).name);
|
||||
return createIdentifier(resolver.getExpressionNameSubstitution((<ShorthandPropertyAssignment>property).name));
|
||||
return createIdentifier(resolver.getExpressionNameSubstitution((<ShorthandPropertyAssignment>property).name, getGeneratedNameForNode));
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
return createFunctionExpression((<MethodDeclaration>property).parameters, (<MethodDeclaration>property).body);
|
||||
@@ -1546,7 +1670,7 @@ module ts {
|
||||
emitExpressionIdentifier(node.name);
|
||||
}
|
||||
}
|
||||
else if (resolver.getExpressionNameSubstitution(node.name)) {
|
||||
else if (resolver.getExpressionNameSubstitution(node.name, getGeneratedNameForNode)) {
|
||||
// Emit identifier as an identifier
|
||||
write(": ");
|
||||
// Even though this is stored as identifier treat it as an expression
|
||||
@@ -2079,10 +2203,10 @@ module ts {
|
||||
//
|
||||
// we don't want to emit a temporary variable for the RHS, just use it directly.
|
||||
let rhsIsIdentifier = node.expression.kind === SyntaxKind.Identifier;
|
||||
let counter = createTempVariable(node, /*preferredName*/ "_i");
|
||||
let counter = createTempVariable(node, TempVariableKind._i);
|
||||
let rhsReference = rhsIsIdentifier ? <Identifier>node.expression : createTempVariable(node);
|
||||
|
||||
var cachedLength = compilerOptions.cacheDownlevelForOfLength ? createTempVariable(node, /*preferredName:*/ "_n") : undefined;
|
||||
var cachedLength = compilerOptions.cacheDownlevelForOfLength ? createTempVariable(node, TempVariableKind._n) : undefined;
|
||||
|
||||
// This is the let keyword for the counter and rhsReference. The let keyword for
|
||||
// the LHS will be emitted inside the body.
|
||||
@@ -2323,7 +2447,7 @@ module ts {
|
||||
|
||||
function emitContainingModuleName(node: Node) {
|
||||
let container = getContainingModule(node);
|
||||
write(container ? resolver.getGeneratedNameForNode(container) : "exports");
|
||||
write(container ? getGeneratedNameForNode(container) : "exports");
|
||||
}
|
||||
|
||||
function emitModuleMemberName(node: Declaration) {
|
||||
@@ -2331,7 +2455,7 @@ module ts {
|
||||
if (getCombinedNodeFlags(node) & NodeFlags.Export) {
|
||||
var container = getContainingModule(node);
|
||||
if (container) {
|
||||
write(resolver.getGeneratedNameForNode(container));
|
||||
write(getGeneratedNameForNode(container));
|
||||
write(".");
|
||||
}
|
||||
else if (languageVersion < ScriptTarget.ES6) {
|
||||
@@ -2673,9 +2797,14 @@ module ts {
|
||||
|
||||
// here it is known that node is a block scoped variable
|
||||
let list = getAncestor(node, SyntaxKind.VariableDeclarationList);
|
||||
if (list.parent.kind === SyntaxKind.VariableStatement && list.parent.parent.kind === SyntaxKind.SourceFile) {
|
||||
// do not rename variables that are defined on source file level
|
||||
return;
|
||||
if (list.parent.kind === SyntaxKind.VariableStatement) {
|
||||
let isSourceFileLevelBinding = list.parent.parent.kind === SyntaxKind.SourceFile;
|
||||
let isModuleLevelBinding = list.parent.parent.kind === SyntaxKind.ModuleBlock;
|
||||
let isFunctionLevelBinding =
|
||||
list.parent.parent.kind === SyntaxKind.Block && isFunctionLike(list.parent.parent.parent);
|
||||
if (isSourceFileLevelBinding || isModuleLevelBinding || isFunctionLevelBinding) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let blockScopeContainer = getEnclosingBlockScopeContainer(node);
|
||||
@@ -2683,12 +2812,19 @@ module ts {
|
||||
? blockScopeContainer
|
||||
: blockScopeContainer.parent;
|
||||
|
||||
let generatedName = generateUniqueNameForLocation(parent, (<Identifier>node).text);
|
||||
let variableId = resolver.getBlockScopedVariableId(<Identifier>node);
|
||||
if (!generatedBlockScopeNames) {
|
||||
generatedBlockScopeNames = [];
|
||||
var hasConflictsInEnclosingScope =
|
||||
resolver.resolvesToSomeValue(parent, (<Identifier>node).text) ||
|
||||
nameConflictsWithSomeTempVariable((<Identifier>node).text);
|
||||
|
||||
if (hasConflictsInEnclosingScope) {
|
||||
let variableId = resolver.getBlockScopedVariableId(<Identifier>node);
|
||||
if (!blockScopedVariableToGeneratedName) {
|
||||
blockScopedVariableToGeneratedName = [];
|
||||
}
|
||||
|
||||
let generatedName = makeUniqueName((<Identifier>node).text);
|
||||
blockScopedVariableToGeneratedName[variableId] = generatedName;
|
||||
}
|
||||
generatedBlockScopeNames[variableId] = generatedName;
|
||||
}
|
||||
|
||||
function isES6ModuleMemberDeclaration(node: Node) {
|
||||
@@ -2770,7 +2906,7 @@ module ts {
|
||||
if (languageVersion < ScriptTarget.ES6 && hasRestParameters(node)) {
|
||||
let restIndex = node.parameters.length - 1;
|
||||
let restParam = node.parameters[restIndex];
|
||||
let tempName = createTempVariable(node, /*preferredName:*/ "_i").text;
|
||||
let tempName = createTempVariable(node, TempVariableKind._i).text;
|
||||
writeLine();
|
||||
emitLeadingComments(restParam);
|
||||
emitStart(restParam);
|
||||
@@ -2820,7 +2956,7 @@ module ts {
|
||||
emitNodeWithoutSourceMap(node.name);
|
||||
}
|
||||
else {
|
||||
write(resolver.getGeneratedNameForNode(node));
|
||||
write(getGeneratedNameForNode(node));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2906,11 +3042,12 @@ module ts {
|
||||
let saveTempCount = tempCount;
|
||||
let saveTempVariables = tempVariables;
|
||||
let saveTempParameters = tempParameters;
|
||||
let savePredefinedTempsInUse = predefinedTempsInUse;
|
||||
|
||||
tempCount = 0;
|
||||
tempVariables = undefined;
|
||||
tempParameters = undefined;
|
||||
|
||||
let popFrame = enterNameScope()
|
||||
predefinedTempsInUse = TempVariableKind.auto;
|
||||
|
||||
// When targeting ES6, emit arrow function natively in ES6
|
||||
if (shouldEmitAsArrowFunction(node)) {
|
||||
@@ -2943,8 +3080,7 @@ module ts {
|
||||
write(";");
|
||||
}
|
||||
|
||||
exitNameScope(popFrame);
|
||||
|
||||
predefinedTempsInUse = savePredefinedTempsInUse;
|
||||
tempCount = saveTempCount;
|
||||
tempVariables = saveTempVariables;
|
||||
tempParameters = saveTempParameters;
|
||||
@@ -3241,11 +3377,12 @@ module ts {
|
||||
let saveTempCount = tempCount;
|
||||
let saveTempVariables = tempVariables;
|
||||
let saveTempParameters = tempParameters;
|
||||
let savePredefinedTempsInUse = predefinedTempsInUse;
|
||||
tempCount = 0;
|
||||
tempVariables = undefined;
|
||||
tempParameters = undefined;
|
||||
predefinedTempsInUse = TempVariableKind.auto;
|
||||
|
||||
let popFrame = enterNameScope();
|
||||
// Check if we have property assignment inside class declaration.
|
||||
// If there is property assignment, we need to emit constructor whether users define it or not
|
||||
// If there is no property assignment, we can omit constructor if users do not define it
|
||||
@@ -3354,8 +3491,7 @@ module ts {
|
||||
emitTrailingComments(ctor);
|
||||
}
|
||||
|
||||
exitNameScope(popFrame);
|
||||
|
||||
predefinedTempsInUse = savePredefinedTempsInUse;
|
||||
tempCount = saveTempCount;
|
||||
tempVariables = saveTempVariables;
|
||||
tempParameters = saveTempParameters;
|
||||
@@ -3494,7 +3630,7 @@ module ts {
|
||||
emitStart(node);
|
||||
write("(function (");
|
||||
emitStart(node.name);
|
||||
write(resolver.getGeneratedNameForNode(node));
|
||||
write(getGeneratedNameForNode(node));
|
||||
emitEnd(node.name);
|
||||
write(") {");
|
||||
increaseIndent();
|
||||
@@ -3531,9 +3667,9 @@ module ts {
|
||||
function emitEnumMember(node: EnumMember) {
|
||||
let enumParent = <EnumDeclaration>node.parent;
|
||||
emitStart(node);
|
||||
write(resolver.getGeneratedNameForNode(enumParent));
|
||||
write(getGeneratedNameForNode(enumParent));
|
||||
write("[");
|
||||
write(resolver.getGeneratedNameForNode(enumParent));
|
||||
write(getGeneratedNameForNode(enumParent));
|
||||
write("[");
|
||||
emitExpressionForPropertyName(node.name);
|
||||
write("] = ");
|
||||
@@ -3586,19 +3722,20 @@ module ts {
|
||||
emitStart(node);
|
||||
write("(function (");
|
||||
emitStart(node.name);
|
||||
write(resolver.getGeneratedNameForNode(node));
|
||||
write(getGeneratedNameForNode(node));
|
||||
emitEnd(node.name);
|
||||
write(") ");
|
||||
if (node.body.kind === SyntaxKind.ModuleBlock) {
|
||||
let saveTempCount = tempCount;
|
||||
let saveTempVariables = tempVariables;
|
||||
let savePredefinedTempsInUse = predefinedTempsInUse;
|
||||
tempCount = 0;
|
||||
tempVariables = undefined;
|
||||
let popFrame = enterNameScope();
|
||||
predefinedTempsInUse = TempVariableKind.auto;
|
||||
|
||||
emit(node.body);
|
||||
|
||||
exitNameScope(popFrame);
|
||||
predefinedTempsInUse = savePredefinedTempsInUse;
|
||||
tempCount = saveTempCount;
|
||||
tempVariables = saveTempVariables;
|
||||
}
|
||||
@@ -3762,7 +3899,7 @@ module ts {
|
||||
}
|
||||
else if (namedImports) {
|
||||
write("var ");
|
||||
write(resolver.getGeneratedNameForNode(<ImportDeclaration>node));
|
||||
write(getGeneratedNameForNode(<ImportDeclaration>node));
|
||||
write(" = ");
|
||||
emitRequire(moduleName);
|
||||
}
|
||||
@@ -3817,7 +3954,7 @@ module ts {
|
||||
if (languageVersion < ScriptTarget.ES6 || node.parent.kind !== SyntaxKind.SourceFile) {
|
||||
if (node.moduleSpecifier) {
|
||||
emitStart(node);
|
||||
let generatedName = resolver.getGeneratedNameForNode(node);
|
||||
let generatedName = getGeneratedNameForNode(node);
|
||||
if (compilerOptions.module !== ModuleKind.AMD) {
|
||||
write("var ");
|
||||
write(generatedName);
|
||||
@@ -3920,7 +4057,7 @@ module ts {
|
||||
return {
|
||||
rootNode: <ImportDeclaration>node,
|
||||
namedImports: <NamedImports>importClause.namedBindings,
|
||||
localName: resolver.getGeneratedNameForNode(<ImportDeclaration>node)
|
||||
localName: getGeneratedNameForNode(<ImportDeclaration>node)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -4025,7 +4162,7 @@ module ts {
|
||||
emit(info.declarationNode.name);
|
||||
}
|
||||
else {
|
||||
write(resolver.getGeneratedNameForNode(<ImportDeclaration | ExportDeclaration>info.rootNode));
|
||||
write(getGeneratedNameForNode(<ImportDeclaration | ExportDeclaration>info.rootNode));
|
||||
}
|
||||
});
|
||||
forEach(node.amdDependencies, amdDependency => {
|
||||
|
||||
@@ -1095,7 +1095,7 @@ module ts {
|
||||
|
||||
// If 'predicate' is supplied, then only the first symbol in scope matching the predicate
|
||||
// will be returned. Otherwise, all symbols in scope will be returned.
|
||||
getSymbolsInScope(location: Node, meaning: SymbolFlags, predicate?: (symbol: Symbol) => boolean): Symbol[];
|
||||
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
|
||||
getSymbolAtLocation(node: Node): Symbol;
|
||||
getShorthandAssignmentValueSymbol(location: Node): Symbol;
|
||||
getTypeAtLocation(node: Node): Type;
|
||||
@@ -1206,8 +1206,8 @@ module ts {
|
||||
}
|
||||
|
||||
export interface EmitResolver {
|
||||
getGeneratedNameForNode(node: Node): string;
|
||||
getExpressionNameSubstitution(node: Identifier): string;
|
||||
hasGlobalName(name: string): boolean;
|
||||
getExpressionNameSubstitution(node: Identifier, getGeneratedNameForNode: (node: Node) => string): string;
|
||||
hasExportDefaultValue(node: SourceFile): boolean;
|
||||
isReferencedAliasDeclaration(node: Node): boolean;
|
||||
isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean;
|
||||
@@ -1222,7 +1222,7 @@ module ts {
|
||||
isEntityNameVisible(entityName: EntityName, enclosingDeclaration: Node): SymbolVisibilityResult;
|
||||
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
|
||||
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): number;
|
||||
isUnknownIdentifier(location: Node, name: string): boolean;
|
||||
resolvesToSomeValue(location: Node, name: string): boolean;
|
||||
getBlockScopedVariableId(node: Identifier): number;
|
||||
}
|
||||
|
||||
|
||||
@@ -1212,28 +1212,6 @@ module ts {
|
||||
return node;
|
||||
}
|
||||
|
||||
export function generateUniqueName(baseName: string, isExistingName: (name: string) => boolean): string {
|
||||
// First try '_name'
|
||||
if (baseName.charCodeAt(0) !== CharacterCodes._) {
|
||||
baseName = "_" + baseName;
|
||||
if (!isExistingName(baseName)) {
|
||||
return baseName;
|
||||
}
|
||||
}
|
||||
// Find the first unique '_name_n', where n is a positive number
|
||||
if (baseName.charCodeAt(baseName.length - 1) !== CharacterCodes._) {
|
||||
baseName += "_";
|
||||
}
|
||||
let i = 1;
|
||||
while (true) {
|
||||
let name = baseName + i;
|
||||
if (!isExistingName(name)) {
|
||||
return name;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// @internal
|
||||
export function createDiagnosticCollection(): DiagnosticCollection {
|
||||
let nonFileDiagnostics: Diagnostic[] = [];
|
||||
|
||||
+44
-64
@@ -2565,9 +2565,9 @@ module ts {
|
||||
}
|
||||
|
||||
/// Completion
|
||||
function getValidCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget): string {
|
||||
function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string {
|
||||
let displayName = symbol.getName();
|
||||
if (displayName && displayName.length > 0) {
|
||||
if (displayName) {
|
||||
let firstCharCode = displayName.charCodeAt(0);
|
||||
// First check of the displayName is not external module; if it is an external module, it is not valid entry
|
||||
if ((symbol.flags & SymbolFlags.Namespace) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
|
||||
@@ -2575,31 +2575,18 @@ module ts {
|
||||
// (i.e declare module "http" { let x; } | // <= request completion here, "http" should not be there)
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (displayName && displayName.length >= 2 &&
|
||||
firstCharCode === displayName.charCodeAt(displayName.length - 1) &&
|
||||
(firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
|
||||
// If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
|
||||
// invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
|
||||
displayName = displayName.substring(1, displayName.length - 1);
|
||||
}
|
||||
|
||||
let isValid = isIdentifierStart(displayName.charCodeAt(0), target);
|
||||
for (let i = 1, n = displayName.length; isValid && i < n; i++) {
|
||||
isValid = isIdentifierPart(displayName.charCodeAt(i), target);
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
return unescapeIdentifier(displayName);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return getCompletionEntryDisplayName(displayName, target, performCharacterChecks);
|
||||
}
|
||||
|
||||
function getValidCompletionEntryDisplayName(displayName: string, target: ScriptTarget): string {
|
||||
function getCompletionEntryDisplayName(displayName: string, target: ScriptTarget, performCharacterChecks: boolean): string {
|
||||
if (!displayName) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let firstCharCode = displayName.charCodeAt(0);
|
||||
if (displayName && displayName.length >= 2 &&
|
||||
if (displayName.length >= 2 &&
|
||||
firstCharCode === displayName.charCodeAt(displayName.length - 1) &&
|
||||
(firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
|
||||
// If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
|
||||
@@ -2607,19 +2594,30 @@ module ts {
|
||||
displayName = displayName.substring(1, displayName.length - 1);
|
||||
}
|
||||
|
||||
let isValid = isIdentifierStart(displayName.charCodeAt(0), target);
|
||||
for (let i = 1, n = displayName.length; isValid && i < n; i++) {
|
||||
isValid = isIdentifierPart(displayName.charCodeAt(i), target);
|
||||
if (!displayName) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return isValid ? unescapeIdentifier(displayName) : undefined;
|
||||
if (performCharacterChecks) {
|
||||
if (!isIdentifierStart(displayName.charCodeAt(0), target)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (let i = 1, n = displayName.length; i < n; i++) {
|
||||
if (!isIdentifierPart(displayName.charCodeAt(i), target)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return unescapeIdentifier(displayName);
|
||||
}
|
||||
|
||||
function createCompletionEntry(symbol: Symbol, typeChecker: TypeChecker, location: Node): CompletionEntry {
|
||||
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
|
||||
// We would like to only show things that can be added after a dot, so for instance numeric properties can
|
||||
// not be accessed with a dot (a.1 <- invalid)
|
||||
let displayName = getValidCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target);
|
||||
let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true);
|
||||
if (!displayName) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -2640,37 +2638,18 @@ module ts {
|
||||
};
|
||||
}
|
||||
|
||||
// If symbolName is undefined, all symbols at the specified are returned. If symbolName
|
||||
// is not undefined, then the first symbol with that name at the specified position
|
||||
// will be returned. Calling without symbolName is useful when you want the entire
|
||||
// list of symbols (like for getCompletionsAtPosition). Calling with a symbolName is
|
||||
// useful when you want information about a single symbol (like for getCompletionEntryDetails).
|
||||
function getCompletionData(fileName: string, position: number, symbolName?: string) {
|
||||
let result = getCompletionDataWorker(fileName, position, symbolName);
|
||||
if (!result) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (result.symbols && symbolName) {
|
||||
var target = program.getCompilerOptions().target;
|
||||
result.symbols = filter(result.symbols, s => getValidCompletionEntryDisplayNameForSymbol(s, target) === symbolName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function getCompletionDataWorker(fileName: string, position: number, symbolName: string) {
|
||||
function getCompletionData(fileName: string, position: number) {
|
||||
let syntacticStart = new Date().getTime();
|
||||
let sourceFile = getValidSourceFile(fileName);
|
||||
|
||||
let start = new Date().getTime();
|
||||
let currentToken = getTokenAtPosition(sourceFile, position);
|
||||
log("getCompletionsAtPosition: Get current token: " + (new Date().getTime() - start));
|
||||
log("getCompletionData: Get current token: " + (new Date().getTime() - start));
|
||||
|
||||
start = new Date().getTime();
|
||||
// Completion not allowed inside comments, bail out if this is the case
|
||||
let insideComment = isInsideComment(sourceFile, currentToken, position);
|
||||
log("getCompletionsAtPosition: Is inside comment: " + (new Date().getTime() - start));
|
||||
log("getCompletionData: Is inside comment: " + (new Date().getTime() - start));
|
||||
|
||||
if (insideComment) {
|
||||
log("Returning an empty list because completion was inside a comment.");
|
||||
@@ -2681,14 +2660,14 @@ module ts {
|
||||
// Note: previousToken can be undefined if we are the beginning of the file
|
||||
start = new Date().getTime();
|
||||
let previousToken = findPrecedingToken(position, sourceFile);
|
||||
log("getCompletionsAtPosition: Get previous token 1: " + (new Date().getTime() - start));
|
||||
log("getCompletionData: Get previous token 1: " + (new Date().getTime() - start));
|
||||
|
||||
// The caret is at the end of an identifier; this is a partial identifier that we want to complete: e.g. a.toS|
|
||||
// Skip this partial identifier to the previous token
|
||||
if (previousToken && position <= previousToken.end && previousToken.kind === SyntaxKind.Identifier) {
|
||||
let start = new Date().getTime();
|
||||
previousToken = findPrecedingToken(previousToken.pos, sourceFile);
|
||||
log("getCompletionsAtPosition: Get previous token 2: " + (new Date().getTime() - start));
|
||||
log("getCompletionData: Get previous token 2: " + (new Date().getTime() - start));
|
||||
}
|
||||
|
||||
// Check if this is a valid completion location
|
||||
@@ -2731,8 +2710,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
// Add keywords if this is not a member completion list
|
||||
log("getCompletionsAtPosition: Semantic work: " + (new Date().getTime() - semanticStart));
|
||||
log("getCompletionData: Semantic work: " + (new Date().getTime() - semanticStart));
|
||||
|
||||
return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot };
|
||||
|
||||
@@ -2808,12 +2786,7 @@ module ts {
|
||||
/// TODO filter meaning based on the current context
|
||||
let scopeNode = getScopeNode(previousToken, position, sourceFile);
|
||||
let symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias;
|
||||
|
||||
// Filter down to the symbol that matches the symbolName if we were given one.
|
||||
let predicate = symbolName !== undefined
|
||||
? (s: Symbol) => getValidCompletionEntryDisplayNameForSymbol(s, target) === symbolName
|
||||
: undefined;
|
||||
symbols = typeInfoResolver.getSymbolsInScope(scopeNode, symbolMeanings, predicate);
|
||||
symbols = typeInfoResolver.getSymbolsInScope(scopeNode, symbolMeanings);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -3160,7 +3133,7 @@ module ts {
|
||||
|
||||
var target = program.getCompilerOptions().target;
|
||||
for (let name in allIdentifiers) {
|
||||
let displayName = getValidCompletionEntryDisplayName(name, target);
|
||||
let displayName = getCompletionEntryDisplayName(name, target, /*performCharacterChecks:*/ true);
|
||||
if (displayName) {
|
||||
// Use '1' so that all javascript identifier entries sort after Symbol entries.
|
||||
entries.push({
|
||||
@@ -3201,12 +3174,19 @@ module ts {
|
||||
function getCompletionEntryDetails(fileName: string, position: number, entryName: string): CompletionEntryDetails {
|
||||
synchronizeHostData();
|
||||
|
||||
// Look up a completion symbol with this name.
|
||||
let completionData = getCompletionData(fileName, position, entryName);
|
||||
// Compute all the completion symbols again.
|
||||
let completionData = getCompletionData(fileName, position);
|
||||
if (completionData) {
|
||||
let { symbols, location } = completionData;
|
||||
if (symbols && symbols.length > 0) {
|
||||
let symbol = symbols[0];
|
||||
|
||||
// Find the symbol with the matching entry name.
|
||||
let target = program.getCompilerOptions().target;
|
||||
// We don't need to perform character checks here because we're only comparing the
|
||||
// name against 'entryName' (which is known to be good), not building a new
|
||||
// completion entry.
|
||||
let symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, target, /*performCharacterChecks:*/ false) === entryName ? s : undefined);
|
||||
|
||||
if (symbol) {
|
||||
let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, typeInfoResolver, location, SemanticMeaning.All);
|
||||
return {
|
||||
name: entryName,
|
||||
|
||||
Reference in New Issue
Block a user