Merge branch 'master' into master-16763

This commit is contained in:
Kanchalai Tanglertsampan
2017-07-10 13:13:35 -07:00
23 changed files with 584 additions and 389 deletions
+2 -2
View File
@@ -27,7 +27,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
/** Skip certain function/method names whose parameter names are not informative. */
function shouldIgnoreCalledExpression(expression: ts.Expression): boolean {
if (expression.kind === ts.SyntaxKind.PropertyAccessExpression) {
const methodName = (expression as ts.PropertyAccessExpression).name.text;
const methodName = (expression as ts.PropertyAccessExpression).name.text as string;
if (methodName.indexOf("set") === 0) {
return true;
}
@@ -44,7 +44,7 @@ function walk(ctx: Lint.WalkContext<void>): void {
}
}
else if (expression.kind === ts.SyntaxKind.Identifier) {
const functionName = (expression as ts.Identifier).text;
const functionName = (expression as ts.Identifier).text as string;
if (functionName.indexOf("set") === 0) {
return true;
}
+60 -27
View File
@@ -56,7 +56,6 @@ namespace ts {
let enumCount = 0;
let symbolInstantiationDepth = 0;
const emptyArray: any[] = [];
const emptySymbols = createSymbolTable();
const compilerOptions = host.getCompilerOptions();
@@ -84,9 +83,9 @@ namespace ts {
// extra cost of calling `getParseTreeNode` when calling these functions from inside the
// checker.
const checker: TypeChecker = {
getNodeCount: () => sum(host.getSourceFiles(), "nodeCount"),
getIdentifierCount: () => sum(host.getSourceFiles(), "identifierCount"),
getSymbolCount: () => sum(host.getSourceFiles(), "symbolCount") + symbolCount,
getNodeCount: () => sum<"nodeCount">(host.getSourceFiles(), "nodeCount"),
getIdentifierCount: () => sum<"identifierCount">(host.getSourceFiles(), "identifierCount"),
getSymbolCount: () => sum<"symbolCount">(host.getSourceFiles(), "symbolCount") + symbolCount,
getTypeCount: () => typeCount,
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
@@ -8735,11 +8734,12 @@ namespace ts {
containingMessageChain?: DiagnosticMessageChain): boolean {
let errorInfo: DiagnosticMessageChain;
let maybeKeys: string[];
let sourceStack: Type[];
let targetStack: Type[];
let maybeStack: Map<RelationComparisonResult>[];
let expandingFlags: number;
let maybeCount = 0;
let depth = 0;
let expandingFlags = 0;
let overflow = false;
let isIntersectionConstituent = false;
@@ -9107,10 +9107,15 @@ namespace ts {
return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
}
}
if (depth > 0) {
for (let i = 0; i < depth; i++) {
if (!maybeKeys) {
maybeKeys = [];
sourceStack = [];
targetStack = [];
}
else {
for (let i = 0; i < maybeCount; i++) {
// If source and target are already being compared, consider them related with assumptions
if (maybeStack[i].get(id)) {
if (id === maybeKeys[i]) {
return Ternary.Maybe;
}
}
@@ -9119,16 +9124,11 @@ namespace ts {
return Ternary.False;
}
}
else {
sourceStack = [];
targetStack = [];
maybeStack = [];
expandingFlags = 0;
}
const maybeStart = maybeCount;
maybeKeys[maybeCount] = id;
maybeCount++;
sourceStack[depth] = source;
targetStack[depth] = target;
maybeStack[depth] = createMap<RelationComparisonResult>();
maybeStack[depth].set(id, RelationComparisonResult.Succeeded);
depth++;
const saveExpandingFlags = expandingFlags;
if (!(expandingFlags & 1) && isDeeplyNestedType(source, sourceStack, depth)) expandingFlags |= 1;
@@ -9137,15 +9137,19 @@ namespace ts {
expandingFlags = saveExpandingFlags;
depth--;
if (result) {
const maybeCache = maybeStack[depth];
// If result is definitely true, copy assumptions to global cache, else copy to next level up
const destinationCache = (result === Ternary.True || depth === 0) ? relation : maybeStack[depth - 1];
copyEntries(maybeCache, destinationCache);
if (result === Ternary.True || depth === 0) {
// If result is definitely true, record all maybe keys as having succeeded
for (let i = maybeStart; i < maybeCount; i++) {
relation.set(maybeKeys[i], RelationComparisonResult.Succeeded);
}
maybeCount = maybeStart;
}
}
else {
// A false result goes straight into global cache (when something is false under assumptions it
// will also be false without assumptions)
// A false result goes straight into global cache (when something is false under
// assumptions it will also be false without assumptions)
relation.set(id, reportErrors ? RelationComparisonResult.FailedAndReported : RelationComparisonResult.Failed);
maybeCount = maybeStart;
}
return result;
}
@@ -12004,9 +12008,9 @@ namespace ts {
}
const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol);
let declaration = localOrExportSymbol.valueDeclaration;
if (localOrExportSymbol.flags & SymbolFlags.Class) {
const declaration = localOrExportSymbol.valueDeclaration;
// Due to the emit for class decorators, any reference to the class from inside of the class body
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
// behavior of class names in ES6.
@@ -12048,7 +12052,6 @@ namespace ts {
checkNestedBlockScopedBinding(node, symbol);
const type = getDeclaredOrApparentType(localOrExportSymbol, node);
const declaration = localOrExportSymbol.valueDeclaration;
const assignmentKind = getAssignmentTargetKind(node);
if (assignmentKind) {
@@ -12062,11 +12065,26 @@ namespace ts {
}
}
const isAlias = localOrExportSymbol.flags & SymbolFlags.Alias;
// We only narrow variables and parameters occurring in a non-assignment position. For all other
// entities we simply return the declared type.
if (!(localOrExportSymbol.flags & SymbolFlags.Variable) || assignmentKind === AssignmentKind.Definite || !declaration) {
if (localOrExportSymbol.flags & SymbolFlags.Variable) {
if (assignmentKind === AssignmentKind.Definite) {
return type;
}
}
else if (isAlias) {
declaration = find<Declaration>(symbol.declarations, isSomeImportDeclaration);
}
else {
return type;
}
if (!declaration) {
return type;
}
// The declaration container is the innermost function that encloses the declaration of the variable
// or parameter. The flow container is the innermost function starting with which we analyze the control
// flow graph to determine the control flow based type.
@@ -12085,7 +12103,7 @@ namespace ts {
// We only look for uninitialized variables in strict null checking mode, and only when we can analyze
// the entire control flow graph from the variable's declaration (i.e. when the flow container and
// declaration container are the same).
const assumeInitialized = isParameter || isOuterVariable ||
const assumeInitialized = isParameter || isAlias || isOuterVariable ||
type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) ||
node.parent.kind === SyntaxKind.NonNullExpression ||
isInAmbientContext(declaration);
@@ -24771,4 +24789,19 @@ namespace ts {
return isDeclarationName(name);
}
}
function isSomeImportDeclaration(decl: Node): boolean {
switch (decl.kind) {
case SyntaxKind.ImportClause: // For default import
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.NamespaceImport:
case SyntaxKind.ImportSpecifier: // For rename import `x as y`
return true;
case SyntaxKind.Identifier:
// For regular import, `decl` is an Identifier under the ImportSpecifier.
return decl.parent.kind === SyntaxKind.ImportSpecifier;
default:
return false;
}
}
}
+1 -45
View File
@@ -162,50 +162,6 @@ namespace ts {
};
}
export function createFileMap<T>(keyMapper: (key: string) => string): FileMap<T> {
const files = createMap<T>();
return {
get,
set,
contains,
remove,
forEachValue: forEachValueInMap,
getKeys,
clear,
};
function forEachValueInMap(f: (key: Path, value: T) => void) {
files.forEach((file, key) => {
f(<Path>key, file);
});
}
function getKeys() {
return arrayFrom(files.keys()) as Path[];
}
// path should already be well-formed so it does not need to be normalized
function get(path: Path): T {
return files.get(keyMapper(path));
}
function set(path: Path, value: T) {
files.set(keyMapper(path), value);
}
function contains(path: Path) {
return files.has(keyMapper(path));
}
function remove(path: Path) {
files.delete(keyMapper(path));
}
function clear() {
files.clear();
}
}
export function toPath(fileName: string, basePath: string, getCanonicalFileName: (path: string) => string): Path {
const nonCanonicalizedPath = isRootedDiskPath(fileName)
? normalizePath(fileName)
@@ -744,7 +700,7 @@ namespace ts {
return result;
}
export function sum(array: any[], prop: string): number {
export function sum<K extends string>(array: { [x in K]: number }[], prop: K): number {
let result = 0;
for (const v of array) {
result += v[prop];
+79 -89
View File
@@ -22,20 +22,15 @@ namespace ts {
}
}
function visitNode<T>(cbNode: (node: Node) => T, node?: Node): T | undefined {
if (node) {
return cbNode(node);
}
function visitNode<T>(cbNode: (node: Node) => T, node: Node): T | undefined {
return node && cbNode(node);
}
function visitNodeArray<T>(cbNodes: (nodes: Node[]) => T, nodes?: Node[]): T | undefined {
if (nodes) {
return cbNodes(nodes);
}
}
function visitEachNode<T>(cbNode: (node: Node) => T, nodes?: Node[]): T | undefined {
function visitNodes<T>(cbNode: (node: Node) => T, cbNodes: (node: NodeArray<Node>) => T | undefined, nodes: NodeArray<Node>): T | undefined {
if (nodes) {
if (cbNodes) {
return cbNodes(nodes);
}
for (const node of nodes) {
const result = cbNode(node);
if (result) {
@@ -53,17 +48,12 @@ namespace ts {
*
* @param node a given node to visit its children
* @param cbNode a callback to be invoked for all child nodes
* @param cbNodeArray a callback to be invoked for embedded array
* @param cbNodes a callback to be invoked for embedded array
*/
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodeArray?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
if (!node) {
export function forEachChild<T>(node: Node, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray<Node>) => T | undefined): T | undefined {
if (!node || node.kind <= SyntaxKind.LastToken) {
return;
}
// The visitXXX functions could be written as local functions that close over the cbNode and cbNodeArray
// callback parameters, but that causes a closure allocation for each invocation with noticeable effects
// on performance.
const visitNodes: (cb: ((node?: Node) => T | undefined) | ((node?: Node[]) => T | undefined), nodes?: Node[]) => T | undefined = cbNodeArray ? visitNodeArray : visitEachNode;
const cbNodes = cbNodeArray || cbNode;
switch (node.kind) {
case SyntaxKind.QualifiedName:
return visitNode(cbNode, (<QualifiedName>node).left) ||
@@ -74,8 +64,8 @@ namespace ts {
visitNode(cbNode, (<TypeParameterDeclaration>node).default) ||
visitNode(cbNode, (<TypeParameterDeclaration>node).expression);
case SyntaxKind.ShorthandPropertyAssignment:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).name) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) ||
@@ -88,8 +78,8 @@ namespace ts {
case SyntaxKind.PropertyAssignment:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<VariableLikeDeclaration>node).propertyName) ||
visitNode(cbNode, (<VariableLikeDeclaration>node).dotDotDotToken) ||
visitNode(cbNode, (<VariableLikeDeclaration>node).name) ||
@@ -101,10 +91,10 @@ namespace ts {
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
visitNodes(cbNodes, (<SignatureDeclaration>node).typeParameters) ||
visitNodes(cbNodes, (<SignatureDeclaration>node).parameters) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNodes(cbNode, cbNodes, (<SignatureDeclaration>node).typeParameters) ||
visitNodes(cbNode, cbNodes, (<SignatureDeclaration>node).parameters) ||
visitNode(cbNode, (<SignatureDeclaration>node).type);
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
@@ -114,33 +104,33 @@ namespace ts {
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).asteriskToken) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).name) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).questionToken) ||
visitNodes(cbNodes, (<FunctionLikeDeclaration>node).typeParameters) ||
visitNodes(cbNodes, (<FunctionLikeDeclaration>node).parameters) ||
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).typeParameters) ||
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).parameters) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).type) ||
visitNode(cbNode, (<ArrowFunction>node).equalsGreaterThanToken) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).body);
case SyntaxKind.TypeReference:
return visitNode(cbNode, (<TypeReferenceNode>node).typeName) ||
visitNodes(cbNodes, (<TypeReferenceNode>node).typeArguments);
visitNodes(cbNode, cbNodes, (<TypeReferenceNode>node).typeArguments);
case SyntaxKind.TypePredicate:
return visitNode(cbNode, (<TypePredicateNode>node).parameterName) ||
visitNode(cbNode, (<TypePredicateNode>node).type);
case SyntaxKind.TypeQuery:
return visitNode(cbNode, (<TypeQueryNode>node).exprName);
case SyntaxKind.TypeLiteral:
return visitNodes(cbNodes, (<TypeLiteralNode>node).members);
return visitNodes(cbNode, cbNodes, (<TypeLiteralNode>node).members);
case SyntaxKind.ArrayType:
return visitNode(cbNode, (<ArrayTypeNode>node).elementType);
case SyntaxKind.TupleType:
return visitNodes(cbNodes, (<TupleTypeNode>node).elementTypes);
return visitNodes(cbNode, cbNodes, (<TupleTypeNode>node).elementTypes);
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
return visitNodes(cbNodes, (<UnionOrIntersectionTypeNode>node).types);
return visitNodes(cbNode, cbNodes, (<UnionOrIntersectionTypeNode>node).types);
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TypeOperator:
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
@@ -156,11 +146,11 @@ namespace ts {
return visitNode(cbNode, (<LiteralTypeNode>node).literal);
case SyntaxKind.ObjectBindingPattern:
case SyntaxKind.ArrayBindingPattern:
return visitNodes(cbNodes, (<BindingPattern>node).elements);
return visitNodes(cbNode, cbNodes, (<BindingPattern>node).elements);
case SyntaxKind.ArrayLiteralExpression:
return visitNodes(cbNodes, (<ArrayLiteralExpression>node).elements);
return visitNodes(cbNode, cbNodes, (<ArrayLiteralExpression>node).elements);
case SyntaxKind.ObjectLiteralExpression:
return visitNodes(cbNodes, (<ObjectLiteralExpression>node).properties);
return visitNodes(cbNode, cbNodes, (<ObjectLiteralExpression>node).properties);
case SyntaxKind.PropertyAccessExpression:
return visitNode(cbNode, (<PropertyAccessExpression>node).expression) ||
visitNode(cbNode, (<PropertyAccessExpression>node).name);
@@ -170,8 +160,8 @@ namespace ts {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return visitNode(cbNode, (<CallExpression>node).expression) ||
visitNodes(cbNodes, (<CallExpression>node).typeArguments) ||
visitNodes(cbNodes, (<CallExpression>node).arguments);
visitNodes(cbNode, cbNodes, (<CallExpression>node).typeArguments) ||
visitNodes(cbNode, cbNodes, (<CallExpression>node).arguments);
case SyntaxKind.TaggedTemplateExpression:
return visitNode(cbNode, (<TaggedTemplateExpression>node).tag) ||
visitNode(cbNode, (<TaggedTemplateExpression>node).template);
@@ -216,16 +206,16 @@ namespace ts {
return visitNode(cbNode, (<SpreadElement>node).expression);
case SyntaxKind.Block:
case SyntaxKind.ModuleBlock:
return visitNodes(cbNodes, (<Block>node).statements);
return visitNodes(cbNode, cbNodes, (<Block>node).statements);
case SyntaxKind.SourceFile:
return visitNodes(cbNodes, (<SourceFile>node).statements) ||
return visitNodes(cbNode, cbNodes, (<SourceFile>node).statements) ||
visitNode(cbNode, (<SourceFile>node).endOfFileToken);
case SyntaxKind.VariableStatement:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<VariableStatement>node).declarationList);
case SyntaxKind.VariableDeclarationList:
return visitNodes(cbNodes, (<VariableDeclarationList>node).declarations);
return visitNodes(cbNode, cbNodes, (<VariableDeclarationList>node).declarations);
case SyntaxKind.ExpressionStatement:
return visitNode(cbNode, (<ExpressionStatement>node).expression);
case SyntaxKind.IfStatement:
@@ -264,12 +254,12 @@ namespace ts {
return visitNode(cbNode, (<SwitchStatement>node).expression) ||
visitNode(cbNode, (<SwitchStatement>node).caseBlock);
case SyntaxKind.CaseBlock:
return visitNodes(cbNodes, (<CaseBlock>node).clauses);
return visitNodes(cbNode, cbNodes, (<CaseBlock>node).clauses);
case SyntaxKind.CaseClause:
return visitNode(cbNode, (<CaseClause>node).expression) ||
visitNodes(cbNodes, (<CaseClause>node).statements);
visitNodes(cbNode, cbNodes, (<CaseClause>node).statements);
case SyntaxKind.DefaultClause:
return visitNodes(cbNodes, (<DefaultClause>node).statements);
return visitNodes(cbNode, cbNodes, (<DefaultClause>node).statements);
case SyntaxKind.LabeledStatement:
return visitNode(cbNode, (<LabeledStatement>node).label) ||
visitNode(cbNode, (<LabeledStatement>node).statement);
@@ -286,46 +276,46 @@ namespace ts {
return visitNode(cbNode, (<Decorator>node).expression);
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ClassLikeDeclaration>node).name) ||
visitNodes(cbNodes, (<ClassLikeDeclaration>node).typeParameters) ||
visitNodes(cbNodes, (<ClassLikeDeclaration>node).heritageClauses) ||
visitNodes(cbNodes, (<ClassLikeDeclaration>node).members);
visitNodes(cbNode, cbNodes, (<ClassLikeDeclaration>node).typeParameters) ||
visitNodes(cbNode, cbNodes, (<ClassLikeDeclaration>node).heritageClauses) ||
visitNodes(cbNode, cbNodes, (<ClassLikeDeclaration>node).members);
case SyntaxKind.InterfaceDeclaration:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<InterfaceDeclaration>node).name) ||
visitNodes(cbNodes, (<InterfaceDeclaration>node).typeParameters) ||
visitNodes(cbNodes, (<ClassDeclaration>node).heritageClauses) ||
visitNodes(cbNodes, (<InterfaceDeclaration>node).members);
visitNodes(cbNode, cbNodes, (<InterfaceDeclaration>node).typeParameters) ||
visitNodes(cbNode, cbNodes, (<ClassDeclaration>node).heritageClauses) ||
visitNodes(cbNode, cbNodes, (<InterfaceDeclaration>node).members);
case SyntaxKind.TypeAliasDeclaration:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<TypeAliasDeclaration>node).name) ||
visitNodes(cbNodes, (<TypeAliasDeclaration>node).typeParameters) ||
visitNodes(cbNode, cbNodes, (<TypeAliasDeclaration>node).typeParameters) ||
visitNode(cbNode, (<TypeAliasDeclaration>node).type);
case SyntaxKind.EnumDeclaration:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<EnumDeclaration>node).name) ||
visitNodes(cbNodes, (<EnumDeclaration>node).members);
visitNodes(cbNode, cbNodes, (<EnumDeclaration>node).members);
case SyntaxKind.EnumMember:
return visitNode(cbNode, (<EnumMember>node).name) ||
visitNode(cbNode, (<EnumMember>node).initializer);
case SyntaxKind.ModuleDeclaration:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ModuleDeclaration>node).name) ||
visitNode(cbNode, (<ModuleDeclaration>node).body);
case SyntaxKind.ImportEqualsDeclaration:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ImportEqualsDeclaration>node).name) ||
visitNode(cbNode, (<ImportEqualsDeclaration>node).moduleReference);
case SyntaxKind.ImportDeclaration:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ImportDeclaration>node).importClause) ||
visitNode(cbNode, (<ImportDeclaration>node).moduleSpecifier);
case SyntaxKind.ImportClause:
@@ -338,10 +328,10 @@ namespace ts {
return visitNode(cbNode, (<NamespaceImport>node).name);
case SyntaxKind.NamedImports:
case SyntaxKind.NamedExports:
return visitNodes(cbNodes, (<NamedImportsOrExports>node).elements);
return visitNodes(cbNode, cbNodes, (<NamedImportsOrExports>node).elements);
case SyntaxKind.ExportDeclaration:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ExportDeclaration>node).exportClause) ||
visitNode(cbNode, (<ExportDeclaration>node).moduleSpecifier);
case SyntaxKind.ImportSpecifier:
@@ -349,37 +339,37 @@ namespace ts {
return visitNode(cbNode, (<ImportOrExportSpecifier>node).propertyName) ||
visitNode(cbNode, (<ImportOrExportSpecifier>node).name);
case SyntaxKind.ExportAssignment:
return visitNodes(cbNodes, node.decorators) ||
visitNodes(cbNodes, node.modifiers) ||
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ExportAssignment>node).expression);
case SyntaxKind.TemplateExpression:
return visitNode(cbNode, (<TemplateExpression>node).head) || visitNodes(cbNodes, (<TemplateExpression>node).templateSpans);
return visitNode(cbNode, (<TemplateExpression>node).head) || visitNodes(cbNode, cbNodes, (<TemplateExpression>node).templateSpans);
case SyntaxKind.TemplateSpan:
return visitNode(cbNode, (<TemplateSpan>node).expression) || visitNode(cbNode, (<TemplateSpan>node).literal);
case SyntaxKind.ComputedPropertyName:
return visitNode(cbNode, (<ComputedPropertyName>node).expression);
case SyntaxKind.HeritageClause:
return visitNodes(cbNodes, (<HeritageClause>node).types);
return visitNodes(cbNode, cbNodes, (<HeritageClause>node).types);
case SyntaxKind.ExpressionWithTypeArguments:
return visitNode(cbNode, (<ExpressionWithTypeArguments>node).expression) ||
visitNodes(cbNodes, (<ExpressionWithTypeArguments>node).typeArguments);
visitNodes(cbNode, cbNodes, (<ExpressionWithTypeArguments>node).typeArguments);
case SyntaxKind.ExternalModuleReference:
return visitNode(cbNode, (<ExternalModuleReference>node).expression);
case SyntaxKind.MissingDeclaration:
return visitNodes(cbNodes, node.decorators);
return visitNodes(cbNode, cbNodes, node.decorators);
case SyntaxKind.CommaListExpression:
return visitNodes(cbNodes, (<CommaListExpression>node).elements);
return visitNodes(cbNode, cbNodes, (<CommaListExpression>node).elements);
case SyntaxKind.JsxElement:
return visitNode(cbNode, (<JsxElement>node).openingElement) ||
visitNodes(cbNodes, (<JsxElement>node).children) ||
visitNodes(cbNode, cbNodes, (<JsxElement>node).children) ||
visitNode(cbNode, (<JsxElement>node).closingElement);
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxOpeningElement:
return visitNode(cbNode, (<JsxOpeningLikeElement>node).tagName) ||
visitNode(cbNode, (<JsxOpeningLikeElement>node).attributes);
case SyntaxKind.JsxAttributes:
return visitNodes(cbNodes, (<JsxAttributes>node).properties);
return visitNodes(cbNode, cbNodes, (<JsxAttributes>node).properties);
case SyntaxKind.JsxAttribute:
return visitNode(cbNode, (<JsxAttribute>node).name) ||
visitNode(cbNode, (<JsxAttribute>node).initializer);
@@ -394,9 +384,9 @@ namespace ts {
case SyntaxKind.JSDocTypeExpression:
return visitNode(cbNode, (<JSDocTypeExpression>node).type);
case SyntaxKind.JSDocUnionType:
return visitNodes(cbNodes, (<JSDocUnionType>node).types);
return visitNodes(cbNode, cbNodes, (<JSDocUnionType>node).types);
case SyntaxKind.JSDocTupleType:
return visitNodes(cbNodes, (<JSDocTupleType>node).types);
return visitNodes(cbNode, cbNodes, (<JSDocTupleType>node).types);
case SyntaxKind.JSDocArrayType:
return visitNode(cbNode, (<JSDocArrayType>node).elementType);
case SyntaxKind.JSDocNonNullableType:
@@ -407,11 +397,11 @@ namespace ts {
return visitNode(cbNode, (<JSDocRecordType>node).literal);
case SyntaxKind.JSDocTypeReference:
return visitNode(cbNode, (<JSDocTypeReference>node).name) ||
visitNodes(cbNodes, (<JSDocTypeReference>node).typeArguments);
visitNodes(cbNode, cbNodes, (<JSDocTypeReference>node).typeArguments);
case SyntaxKind.JSDocOptionalType:
return visitNode(cbNode, (<JSDocOptionalType>node).type);
case SyntaxKind.JSDocFunctionType:
return visitNodes(cbNodes, (<JSDocFunctionType>node).parameters) ||
return visitNodes(cbNode, cbNodes, (<JSDocFunctionType>node).parameters) ||
visitNode(cbNode, (<JSDocFunctionType>node).type);
case SyntaxKind.JSDocVariadicType:
return visitNode(cbNode, (<JSDocVariadicType>node).type);
@@ -423,7 +413,7 @@ namespace ts {
return visitNode(cbNode, (<JSDocRecordMember>node).name) ||
visitNode(cbNode, (<JSDocRecordMember>node).type);
case SyntaxKind.JSDocComment:
return visitNodes(cbNodes, (<JSDoc>node).tags);
return visitNodes(cbNode, cbNodes, (<JSDoc>node).tags);
case SyntaxKind.JSDocParameterTag:
return visitNode(cbNode, (<JSDocParameterTag>node).preParameterName) ||
visitNode(cbNode, (<JSDocParameterTag>node).typeExpression) ||
@@ -435,14 +425,14 @@ namespace ts {
case SyntaxKind.JSDocAugmentsTag:
return visitNode(cbNode, (<JSDocAugmentsTag>node).typeExpression);
case SyntaxKind.JSDocTemplateTag:
return visitNodes(cbNodes, (<JSDocTemplateTag>node).typeParameters);
return visitNodes(cbNode, cbNodes, (<JSDocTemplateTag>node).typeParameters);
case SyntaxKind.JSDocTypedefTag:
return visitNode(cbNode, (<JSDocTypedefTag>node).typeExpression) ||
visitNode(cbNode, (<JSDocTypedefTag>node).fullName) ||
visitNode(cbNode, (<JSDocTypedefTag>node).name) ||
visitNode(cbNode, (<JSDocTypedefTag>node).jsDocTypeLiteral);
case SyntaxKind.JSDocTypeLiteral:
return visitNodes(cbNodes, (<JSDocTypeLiteral>node).jsDocPropertyTags);
return visitNodes(cbNode, cbNodes, (<JSDocTypeLiteral>node).jsDocPropertyTags);
case SyntaxKind.JSDocPropertyTag:
return visitNode(cbNode, (<JSDocPropertyTag>node).typeExpression) ||
visitNode(cbNode, (<JSDocPropertyTag>node).name);
+21 -15
View File
@@ -441,7 +441,7 @@ namespace ts {
const supportedExtensions = getSupportedExtensions(options);
// Map storing if there is emit blocking diagnostics for given input
const hasEmitBlockingDiagnostics = createFileMap<boolean>(getCanonicalFileName);
const hasEmitBlockingDiagnostics = createMap<boolean>();
let _compilerOptionsObjectLiteralSyntax: ObjectLiteralExpression;
let moduleResolutionCache: ModuleResolutionCache;
@@ -475,7 +475,7 @@ namespace ts {
const filesByName = createMap<SourceFile | undefined>();
// stores 'filename -> file association' ignoring case
// used to track cases when two file names differ only in casing
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createFileMap<SourceFile>(fileName => fileName.toLowerCase()) : undefined;
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createMap<SourceFile>() : undefined;
const structuralIsReused = tryReuseStructureFromOldProgram();
if (structuralIsReused !== StructureIsReused.Completely) {
@@ -556,6 +556,10 @@ namespace ts {
return program;
function toPath(fileName: string): Path {
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
}
function getCommonSourceDirectory() {
if (commonSourceDirectory === undefined) {
const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary));
@@ -934,7 +938,7 @@ namespace ts {
}
function isEmitBlocked(emitFileName: string): boolean {
return hasEmitBlockingDiagnostics.contains(toPath(emitFileName, currentDirectory, getCanonicalFileName));
return hasEmitBlockingDiagnostics.has(toPath(emitFileName));
}
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
@@ -993,7 +997,7 @@ namespace ts {
}
function getSourceFile(fileName: string): SourceFile {
return getSourceFileByPath(toPath(fileName, currentDirectory, getCanonicalFileName));
return getSourceFileByPath(toPath(fileName));
}
function getSourceFileByPath(path: Path): SourceFile {
@@ -1484,7 +1488,7 @@ namespace ts {
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
function getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined {
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName, currentDirectory, getCanonicalFileName)));
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName)));
}
function getSourceFileFromReferenceWorker(
@@ -1528,7 +1532,7 @@ namespace ts {
/** This has side effects through `findSourceFile`. */
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
getSourceFileFromReferenceWorker(fileName,
fileName => findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd),
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, refFile, refPos, refEnd),
(diagnostic, ...args) => {
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
@@ -1597,13 +1601,14 @@ namespace ts {
file.path = path;
if (host.useCaseSensitiveFileNames()) {
const pathLowerCase = path.toLowerCase();
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
const existingFile = filesByNameIgnoreCase.get(path);
const existingFile = filesByNameIgnoreCase.get(pathLowerCase);
if (existingFile) {
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
}
else {
filesByNameIgnoreCase.set(path, file);
filesByNameIgnoreCase.set(pathLowerCase, file);
}
}
@@ -1750,7 +1755,7 @@ namespace ts {
modulesWithElidedImports.set(file.path, true);
}
else if (shouldAddFile) {
const path = toPath(resolvedFileName, currentDirectory, getCanonicalFileName);
const path = toPath(resolvedFileName);
const pos = skipTrivia(file.text, file.imports[i].pos);
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, file, pos, file.imports[i].end);
}
@@ -1969,7 +1974,7 @@ namespace ts {
// If the emit is enabled make sure that every output file is unique and not overwriting any of the input files
if (!options.noEmit && !options.suppressOutputPathCheck) {
const emitHost = getEmitHost();
const emitFilesSeen = createFileMap<boolean>(!host.useCaseSensitiveFileNames() ? key => key.toLocaleLowerCase() : key => key);
const emitFilesSeen = createMap<true>();
forEachEmittedFile(emitHost, (emitFileNames) => {
verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen);
verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen);
@@ -1977,9 +1982,9 @@ namespace ts {
}
// Verify that all the emit files are unique and don't overwrite input files
function verifyEmitFilePath(emitFileName: string, emitFilesSeen: FileMap<boolean>) {
function verifyEmitFilePath(emitFileName: string, emitFilesSeen: Map<true>) {
if (emitFileName) {
const emitFilePath = toPath(emitFileName, currentDirectory, getCanonicalFileName);
const emitFilePath = toPath(emitFileName);
// Report error if the output overwrites input file
if (filesByName.has(emitFilePath)) {
let chain: DiagnosticMessageChain;
@@ -1991,13 +1996,14 @@ namespace ts {
blockEmittingOfFile(emitFileName, createCompilerDiagnosticFromMessageChain(chain));
}
const emitFileKey = !host.useCaseSensitiveFileNames() ? emitFilePath.toLocaleLowerCase() : emitFilePath;
// Report error if multiple files write into same file
if (emitFilesSeen.contains(emitFilePath)) {
if (emitFilesSeen.has(emitFileKey)) {
// Already seen the same emit file - report error
blockEmittingOfFile(emitFileName, createCompilerDiagnostic(Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, emitFileName));
}
else {
emitFilesSeen.set(emitFilePath, true);
emitFilesSeen.set(emitFileKey, true);
}
}
}
@@ -2089,7 +2095,7 @@ namespace ts {
}
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
hasEmitBlockingDiagnostics.set(toPath(emitFileName, currentDirectory, getCanonicalFileName), true);
hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
programDiagnostics.add(diag);
}
}
+2 -13
View File
@@ -31,17 +31,6 @@ namespace ts {
// arbitrary file name can be converted to Path via toPath function
export type Path = string & { __pathBrand: any };
export interface FileMap<T> {
get(fileName: Path): T;
set(fileName: Path, value: T): void;
contains(fileName: Path): boolean;
remove(fileName: Path): void;
forEachValue(f: (key: Path, v: T) => void): void;
getKeys(): Path[];
clear(): void;
}
export interface TextRange {
pos: number;
end: number;
@@ -527,7 +516,7 @@ namespace ts {
/* @internal */ original?: Node; // The original node if this is an updated node.
/* @internal */ startsOnNewLine?: boolean; // Whether a synthesized node should start on a new line (used by transforms).
/* @internal */ jsDoc?: JSDoc[]; // JSDoc that directly precedes this node
/* @internal */ jsDocCache?: (JSDoc | JSDocTag)[]; // All JSDoc that applies to the node, including parent docs and @param tags
/* @internal */ jsDocCache?: JSDocTag[]; // Cache for getJSDocTags
/* @internal */ symbol?: Symbol; // Symbol declared by node (initialized by binding)
/* @internal */ locals?: SymbolTable; // Locals associated with node (initialized by binding)
/* @internal */ nextContainer?: Node; // Next container in declaration order (initialized by binding)
@@ -4350,7 +4339,7 @@ namespace ts {
*/
export type Visitor = (node: Node) => VisitResult<Node>;
export type VisitResult<T extends Node> = T | T[];
export type VisitResult<T extends Node> = T | T[] | undefined;
export interface Printer {
/**
+44 -36
View File
@@ -2,6 +2,8 @@
/* @internal */
namespace ts {
export const emptyArray: never[] = [] as never[];
export const externalHelpersModuleNameText = "tslib";
export interface ReferencePathMatchResult {
@@ -1445,39 +1447,37 @@ namespace ts {
(<JSDocFunctionType>node).parameters[0].type.kind === SyntaxKind.JSDocConstructorType;
}
export function getCommentsFromJSDoc(node: Node): string[] {
return map(getJSDocs(node), doc => doc.comment);
export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration): boolean {
return !!getFirstJSDocTag(node, SyntaxKind.JSDocParameterTag);
}
export function hasJSDocParameterTags(node: FunctionLikeDeclaration | SignatureDeclaration) {
const parameterTags = getJSDocTags(node, SyntaxKind.JSDocParameterTag);
return parameterTags && parameterTags.length > 0;
function getFirstJSDocTag(node: Node, kind: SyntaxKind): JSDocTag | undefined {
const tags = getJSDocTags(node);
return find(tags, doc => doc.kind === kind);
}
function getJSDocTags(node: Node, kind: SyntaxKind): JSDocTag[] {
return flatMap(getJSDocs(node), doc =>
doc.kind === SyntaxKind.JSDocComment
? filter((doc as JSDoc).tags, tag => tag.kind === kind)
: doc.kind === kind && doc);
}
function getFirstJSDocTag(node: Node, kind: SyntaxKind): JSDocTag {
return node && firstOrUndefined(getJSDocTags(node, kind));
}
export function getJSDocs(node: Node): (JSDoc | JSDocTag)[] {
export function getAllJSDocs(node: Node): (JSDoc | JSDocTag)[] {
if (isJSDocTypedefTag(node)) {
return [node.parent];
}
return getJSDocCommentsAndTags(node);
}
let cache: (JSDoc | JSDocTag)[] = node.jsDocCache;
if (!cache) {
getJSDocsWorker(node);
node.jsDocCache = cache;
export function getJSDocTags(node: Node): JSDocTag[] | undefined {
let tags = node.jsDocCache;
// If cache is 'null', that means we did the work of searching for JSDoc tags and came up with nothing.
if (tags === undefined) {
node.jsDocCache = tags = flatMap(getJSDocCommentsAndTags(node), j => isJSDoc(j) ? j.tags : j);
}
return cache;
return tags;
}
function getJSDocsWorker(node: Node) {
function getJSDocCommentsAndTags(node: Node): (JSDoc | JSDocTag)[] {
let result: Array<JSDoc | JSDocTag> | undefined;
getJSDocCommentsAndTagsWorker(node);
return result || emptyArray;
function getJSDocCommentsAndTagsWorker(node: Node): void {
const parent = node.parent;
// Try to recognize this pattern when node is initializer of variable declaration and JSDoc comments are on containing variable statement.
// /**
@@ -1496,7 +1496,7 @@ namespace ts {
isVariableOfVariableDeclarationStatement ? parent.parent :
undefined;
if (variableStatementNode) {
getJSDocsWorker(variableStatementNode);
getJSDocCommentsAndTagsWorker(variableStatementNode);
}
// Also recognize when the node is the RHS of an assignment expression
@@ -1506,43 +1506,51 @@ namespace ts {
(parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken &&
parent.parent.kind === SyntaxKind.ExpressionStatement;
if (isSourceOfAssignmentExpressionStatement) {
getJSDocsWorker(parent.parent);
getJSDocCommentsAndTagsWorker(parent.parent);
}
const isModuleDeclaration = node.kind === SyntaxKind.ModuleDeclaration &&
parent && parent.kind === SyntaxKind.ModuleDeclaration;
const isPropertyAssignmentExpression = parent && parent.kind === SyntaxKind.PropertyAssignment;
if (isModuleDeclaration || isPropertyAssignmentExpression) {
getJSDocsWorker(parent);
getJSDocCommentsAndTagsWorker(parent);
}
// Pull parameter comments from declaring function as well
if (node.kind === SyntaxKind.Parameter) {
cache = concatenate(cache, getJSDocParameterTags(node as ParameterDeclaration));
result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration));
}
if (isVariableLike(node) && node.initializer) {
cache = concatenate(cache, node.initializer.jsDoc);
result = addRange(result, node.initializer.jsDoc);
}
cache = concatenate(cache, node.jsDoc);
result = addRange(result, node.jsDoc);
}
}
export function getJSDocParameterTags(param: ParameterDeclaration): JSDocParameterTag[] {
export function getJSDocParameterTags(param: ParameterDeclaration): JSDocParameterTag[] | undefined {
const func = param.parent;
const tags = getJSDocTags(func, SyntaxKind.JSDocParameterTag) as JSDocParameterTag[];
const tags = getJSDocTags(func);
if (!tags) return undefined;
if (!param.name) {
// this is an anonymous jsdoc param from a `function(type1, type2): type3` specification
const i = func.parameters.indexOf(param);
const paramTags = filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag);
if (paramTags && 0 <= i && i < paramTags.length) {
return [paramTags[i]];
const paramIndex = func.parameters.indexOf(param);
Debug.assert(paramIndex !== -1);
let curParamIndex = 0;
for (const tag of tags) {
if (isJSDocParameterTag(tag)) {
if (curParamIndex === paramIndex) {
return [tag];
}
curParamIndex++;
}
}
}
else if (param.name.kind === SyntaxKind.Identifier) {
const name = (param.name as Identifier).text;
return filter(tags, tag => tag.kind === SyntaxKind.JSDocParameterTag && tag.name.text === name);
return tags.filter((tag): tag is JSDocParameterTag => isJSDocParameterTag(tag) && tag.name.text === name) as JSDocParameterTag[];
}
else {
// TODO: it's a destructured parameter, so it should look up an "object type" series of multiple lines
+4 -8
View File
@@ -7,8 +7,7 @@ namespace ts {
}
function lineColToPosition(lineIndex: server.LineIndex, line: number, col: number) {
const lineInfo = lineIndex.lineNumberToInfo(line);
return (lineInfo.offset + col - 1);
return lineIndex.absolutePositionOfStartOfLine(line) + (col - 1);
}
function validateEdit(lineIndex: server.LineIndex, sourceText: string, position: number, deleteLength: number, insertString: string): void {
@@ -298,20 +297,17 @@ and grew 1cm per day`;
it("Line/offset from pos", () => {
for (let i = 0; i < iterationCount; i++) {
const lp = lineIndex.charOffsetToLineNumberAndPos(rsa[i]);
const lp = lineIndex.positionToLineOffset(rsa[i]);
const lac = ts.computeLineAndCharacterOfPosition(lineMap, rsa[i]);
assert.equal(lac.line + 1, lp.line, "Line number mismatch " + (lac.line + 1) + " " + lp.line + " " + i);
assert.equal(lac.character, (lp.offset), "Charachter offset mismatch " + lac.character + " " + lp.offset + " " + i);
assert.equal(lac.character, lp.offset - 1, "Character offset mismatch " + lac.character + " " + (lp.offset - 1) + " " + i);
}
});
it("Start pos from line", () => {
for (let i = 0; i < iterationCount; i++) {
for (let j = 0; j < lines.length; j++) {
const lineInfo = lineIndex.lineNumberToInfo(j + 1);
const lineIndexOffset = lineInfo.offset;
const lineMapOffset = lineMap[j];
assert.equal(lineIndexOffset, lineMapOffset);
assert.equal(lineIndex.absolutePositionOfStartOfLine(j + 1), lineMap[j]);
}
}
});
+1 -1
View File
@@ -640,7 +640,7 @@ namespace ts.server.protocol {
}
/**
* Location in source code expressed as (one-based) line and character offset.
* Location in source code expressed as (one-based) line and (one-based) column offset.
*/
export interface Location {
line: number;
+9 -28
View File
@@ -61,7 +61,7 @@ namespace ts.server {
: ScriptSnapshot.fromString(this.getOrLoadText());
}
public getLineInfo(line: number) {
public getLineInfo(line: number): AbsolutePositionAndLineText {
return this.switchToScriptVersionCache().getSnapshot().index.lineNumberToInfo(line);
}
/**
@@ -75,16 +75,9 @@ namespace ts.server {
return ts.createTextSpanFromBounds(start, end);
}
const index = this.svc.getSnapshot().index;
const lineInfo = index.lineNumberToInfo(line + 1);
let len: number;
if (lineInfo.leaf) {
len = lineInfo.leaf.text.length;
}
else {
const nextLineInfo = index.lineNumberToInfo(line + 2);
len = nextLineInfo.offset - lineInfo.offset;
}
return ts.createTextSpan(lineInfo.offset, len);
const { lineText, absolutePosition } = index.lineNumberToInfo(line + 1);
const len = lineText !== undefined ? lineText.length : index.absolutePositionOfStartOfLine(line + 2) - absolutePosition;
return ts.createTextSpan(absolutePosition, len);
}
/**
@@ -95,25 +88,17 @@ namespace ts.server {
if (!this.svc) {
return computePositionOfLineAndCharacter(this.getLineMap(), line - 1, offset - 1);
}
const index = this.svc.getSnapshot().index;
const lineInfo = index.lineNumberToInfo(line);
// TODO: assert this offset is actually on the line
return (lineInfo.offset + offset - 1);
return this.svc.getSnapshot().index.absolutePositionOfStartOfLine(line) + (offset - 1);
}
/**
* @param line 1-based index
* @param offset 1-based index
*/
positionToLineOffset(position: number): ILineInfo {
positionToLineOffset(position: number): protocol.Location {
if (!this.svc) {
const { line, character } = computeLineAndCharacterOfPosition(this.getLineMap(), position);
return { line: line + 1, offset: character + 1 };
}
const index = this.svc.getSnapshot().index;
const lineOffset = index.charOffsetToLineNumberAndPos(position);
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
return this.svc.getSnapshot().index.positionToLineOffset(position);
}
private getFileText(tempFileName?: string) {
@@ -334,7 +319,7 @@ namespace ts.server {
}
}
getLineInfo(line: number) {
getLineInfo(line: number): AbsolutePositionAndLineText {
return this.textStorage.getLineInfo(line);
}
@@ -364,11 +349,7 @@ namespace ts.server {
return this.textStorage.lineOffsetToPosition(line, offset);
}
/**
* @param line 1-based index
* @param offset 1-based index
*/
positionToLineOffset(position: number): ILineInfo {
positionToLineOffset(position: number): protocol.Location {
return this.textStorage.positionToLineOffset(position);
}
+58 -62
View File
@@ -8,15 +8,13 @@ namespace ts.server {
export interface LineCollection {
charCount(): number;
lineCount(): number;
isLeaf(): boolean;
isLeaf(): this is LineLeaf;
walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker): void;
}
export interface ILineInfo {
line: number;
offset: number;
text?: string;
leaf?: LineLeaf;
export interface AbsolutePositionAndLineText {
absolutePosition: number;
lineText: string | undefined;
}
export enum CharRangeSection {
@@ -397,22 +395,27 @@ namespace ts.server {
// set this to true to check each edit for accuracy
checkEdits = false;
charOffsetToLineNumberAndPos(charOffset: number) {
return this.root.charOffsetToLineNumberAndPos(1, charOffset);
absolutePositionOfStartOfLine(oneBasedLine: number): number {
return this.lineNumberToInfo(oneBasedLine).absolutePosition;
}
lineNumberToInfo(lineNumber: number): ILineInfo {
positionToLineOffset(position: number): protocol.Location {
const { oneBasedLine, zeroBasedColumn } = this.root.charOffsetToLineInfo(1, position);
return { line: oneBasedLine, offset: zeroBasedColumn + 1 };
}
private positionToColumnAndLineText(position: number): { zeroBasedColumn: number, lineText: string } {
return this.root.charOffsetToLineInfo(1, position);
}
lineNumberToInfo(oneBasedLine: number): AbsolutePositionAndLineText {
const lineCount = this.root.lineCount();
if (lineNumber <= lineCount) {
const lineInfo = this.root.lineNumberToInfo(lineNumber, 0);
lineInfo.line = lineNumber;
return lineInfo;
if (oneBasedLine <= lineCount) {
const { position, leaf } = this.root.lineNumberToInfo(oneBasedLine, 0);
return { absolutePosition: position, lineText: leaf && leaf.text };
}
else {
return {
line: lineNumber,
offset: this.root.charCount()
};
return { absolutePosition: this.root.charCount(), lineText: undefined };
}
}
@@ -502,17 +505,12 @@ namespace ts.server {
else if (deleteLength > 0) {
// check whether last characters deleted are line break
const e = pos + deleteLength;
const lineInfo = this.charOffsetToLineNumberAndPos(e);
if ((lineInfo && (lineInfo.offset === 0))) {
const { zeroBasedColumn, lineText } = this.positionToColumnAndLineText(e);
if (zeroBasedColumn === 0) {
// move range end just past line that will merge with previous line
deleteLength += lineInfo.text.length;
deleteLength += lineText.length;
// store text by appending to end of insertedText
if (newText) {
newText = newText + lineInfo.text;
}
else {
newText = lineInfo.text;
}
newText = newText ? newText + lineText : lineText;
}
}
if (pos < this.root.charCount()) {
@@ -676,90 +674,88 @@ namespace ts.server {
}
}
charOffsetToLineNumberAndPos(lineNumber: number, charOffset: number): ILineInfo {
const childInfo = this.childFromCharOffset(lineNumber, charOffset);
// Input position is relative to the start of this node.
// Output line number is absolute.
charOffsetToLineInfo(lineNumberAccumulator: number, relativePosition: number): { oneBasedLine: number, zeroBasedColumn: number, lineText: string | undefined } {
const childInfo = this.childFromCharOffset(lineNumberAccumulator, relativePosition);
if (!childInfo.child) {
return {
line: lineNumber,
offset: charOffset,
oneBasedLine: lineNumberAccumulator,
zeroBasedColumn: relativePosition,
lineText: undefined,
};
}
else if (childInfo.childIndex < this.children.length) {
if (childInfo.child.isLeaf()) {
return {
line: childInfo.lineNumber,
offset: childInfo.charOffset,
text: (<LineLeaf>(childInfo.child)).text,
leaf: (<LineLeaf>(childInfo.child))
oneBasedLine: childInfo.lineNumberAccumulator,
zeroBasedColumn: childInfo.relativePosition,
lineText: childInfo.child.text,
};
}
else {
const lineNode = <LineNode>(childInfo.child);
return lineNode.charOffsetToLineNumberAndPos(childInfo.lineNumber, childInfo.charOffset);
return lineNode.charOffsetToLineInfo(childInfo.lineNumberAccumulator, childInfo.relativePosition);
}
}
else {
const lineInfo = this.lineNumberToInfo(this.lineCount(), 0);
return { line: this.lineCount(), offset: lineInfo.leaf.charCount() };
return { oneBasedLine: this.lineCount(), zeroBasedColumn: lineInfo.leaf.charCount(), lineText: undefined };
}
}
lineNumberToInfo(lineNumber: number, charOffset: number): ILineInfo {
const childInfo = this.childFromLineNumber(lineNumber, charOffset);
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
const childInfo = this.childFromLineNumber(relativeOneBasedLine, positionAccumulator);
if (!childInfo.child) {
return {
line: lineNumber,
offset: charOffset
};
return { position: positionAccumulator, leaf: undefined };
}
else if (childInfo.child.isLeaf()) {
return {
line: lineNumber,
offset: childInfo.charOffset,
text: (<LineLeaf>(childInfo.child)).text,
leaf: (<LineLeaf>(childInfo.child))
};
return { position: childInfo.positionAccumulator, leaf: childInfo.child };
}
else {
const lineNode = <LineNode>(childInfo.child);
return lineNode.lineNumberToInfo(childInfo.relativeLineNumber, childInfo.charOffset);
return lineNode.lineNumberToInfo(childInfo.relativeOneBasedLine, childInfo.positionAccumulator);
}
}
childFromLineNumber(lineNumber: number, charOffset: number) {
/**
* Input line number is relative to the start of this node.
* Output line number is relative to the child.
* positionAccumulator will be an absolute position once relativeLineNumber reaches 0.
*/
private childFromLineNumber(relativeOneBasedLine: number, positionAccumulator: number): { child: LineCollection, relativeOneBasedLine: number, positionAccumulator: number } {
let child: LineCollection;
let relativeLineNumber = lineNumber;
let i: number;
let len: number;
for (i = 0, len = this.children.length; i < len; i++) {
for (i = 0; i < this.children.length; i++) {
child = this.children[i];
const childLineCount = child.lineCount();
if (childLineCount >= relativeLineNumber) {
if (childLineCount >= relativeOneBasedLine) {
break;
}
else {
relativeLineNumber -= childLineCount;
charOffset += child.charCount();
relativeOneBasedLine -= childLineCount;
positionAccumulator += child.charCount();
}
}
return { child, childIndex: i, relativeLineNumber, charOffset };
return { child, relativeOneBasedLine, positionAccumulator };
}
childFromCharOffset(lineNumber: number, charOffset: number) {
private childFromCharOffset(lineNumberAccumulator: number, relativePosition: number
): { child: LineCollection, childIndex: number, relativePosition: number, lineNumberAccumulator: number } {
let child: LineCollection;
let i: number;
let len: number;
for (i = 0, len = this.children.length; i < len; i++) {
child = this.children[i];
if (child.charCount() > charOffset) {
if (child.charCount() > relativePosition) {
break;
}
else {
charOffset -= child.charCount();
lineNumber += child.lineCount();
relativePosition -= child.charCount();
lineNumberAccumulator += child.lineCount();
}
}
return { child, childIndex: i, charOffset, lineNumber };
return { child, childIndex: i, relativePosition, lineNumberAccumulator };
}
private splitAfter(childIndex: number) {
+28 -31
View File
@@ -49,7 +49,7 @@ namespace ts.server {
interface FileStart {
file: string;
start: ILineInfo;
start: protocol.Location;
}
function compareNumber(a: number, b: number) {
@@ -84,15 +84,15 @@ namespace ts.server {
};
}
function convertToILineInfo(lineAndCharacter: LineAndCharacter): ILineInfo {
function convertToLocation(lineAndCharacter: LineAndCharacter): protocol.Location {
return { line: lineAndCharacter.line + 1, offset: lineAndCharacter.character + 1 };
}
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: true): protocol.DiagnosticWithFileName;
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: false): protocol.Diagnostic;
function formatConfigFileDiag(diag: ts.Diagnostic, includeFileName: boolean): protocol.Diagnostic | protocol.DiagnosticWithFileName {
const start = diag.file && convertToILineInfo(getLineAndCharacterOfPosition(diag.file, diag.start));
const end = diag.file && convertToILineInfo(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
const start = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start));
const end = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length));
const text = ts.flattenDiagnosticMessageText(diag.messageText, "\n");
const { code, source } = diag;
const category = DiagnosticCategory[diag.category].toLowerCase();
@@ -555,8 +555,8 @@ namespace ts.server {
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
code: d.code,
startLocation: d.file && convertToILineInfo(getLineAndCharacterOfPosition(d.file, d.start)),
endLocation: d.file && convertToILineInfo(getLineAndCharacterOfPosition(d.file, d.start + d.length))
startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)),
endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length))
});
}
@@ -1131,32 +1131,29 @@ namespace ts.server {
// only to the previous line. If all this is true, then
// add edits necessary to properly indent the current line.
if ((args.key === "\n") && ((!edits) || (edits.length === 0) || allEditsBeforePos(edits, position))) {
const lineInfo = scriptInfo.getLineInfo(args.line);
if (lineInfo && (lineInfo.leaf) && (lineInfo.leaf.text)) {
const lineText = lineInfo.leaf.text;
if (lineText.search("\\S") < 0) {
const preferredIndent = project.getLanguageService(/*ensureSynchronized*/ false).getIndentationAtPosition(file, position, formatOptions);
let hasIndent = 0;
let i: number, len: number;
for (i = 0, len = lineText.length; i < len; i++) {
if (lineText.charAt(i) === " ") {
hasIndent++;
}
else if (lineText.charAt(i) === "\t") {
hasIndent += formatOptions.tabSize;
}
else {
break;
}
const { lineText, absolutePosition } = scriptInfo.getLineInfo(args.line);
if (lineText && lineText.search("\\S") < 0) {
const preferredIndent = project.getLanguageService(/*ensureSynchronized*/ false).getIndentationAtPosition(file, position, formatOptions);
let hasIndent = 0;
let i: number, len: number;
for (i = 0, len = lineText.length; i < len; i++) {
if (lineText.charAt(i) === " ") {
hasIndent++;
}
// i points to the first non whitespace character
if (preferredIndent !== hasIndent) {
const firstNoWhiteSpacePosition = lineInfo.offset + i;
edits.push({
span: ts.createTextSpanFromBounds(lineInfo.offset, firstNoWhiteSpacePosition),
newText: formatting.getIndentationString(preferredIndent, formatOptions)
});
else if (lineText.charAt(i) === "\t") {
hasIndent += formatOptions.tabSize;
}
else {
break;
}
}
// i points to the first non whitespace character
if (preferredIndent !== hasIndent) {
const firstNoWhiteSpacePosition = absolutePosition + i;
edits.push({
span: ts.createTextSpanFromBounds(absolutePosition, firstNoWhiteSpacePosition),
newText: formatting.getIndentationString(preferredIndent, formatOptions)
});
}
}
}
@@ -1514,7 +1511,7 @@ namespace ts.server {
if (simplifiedResult) {
const file = result.renameFilename;
let location: ILineInfo | undefined = undefined;
let location: protocol.Location | undefined;
if (file !== undefined && result.renameLocation !== undefined) {
const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(file));
location = renameScriptInfo.positionToLineOffset(result.renameLocation);
+7 -20
View File
@@ -53,18 +53,14 @@ namespace ts.JsDoc {
// from Array<T> - Array<string> and Array<number>
const documentationComment = <SymbolDisplayPart[]>[];
forEachUnique(declarations, declaration => {
const comments = getCommentsFromJSDoc(declaration);
if (!comments) {
return;
}
for (const comment of comments) {
if (comment) {
forEach(getAllJSDocs(declaration), doc => {
if (doc.comment) {
if (documentationComment.length) {
documentationComment.push(lineBreakPart());
}
documentationComment.push(textPart(comment));
documentationComment.push(textPart(doc.comment));
}
}
});
});
return documentationComment;
}
@@ -73,18 +69,9 @@ namespace ts.JsDoc {
// Only collect doc comments from duplicate declarations once.
const tags: JSDocTagInfo[] = [];
forEachUnique(declarations, declaration => {
const jsDocs = getJSDocs(declaration);
if (!jsDocs) {
return;
}
for (const doc of jsDocs) {
const tagsForDoc = (doc as JSDoc).tags;
if (tagsForDoc) {
tags.push(...tagsForDoc.filter(tag => tag.kind === SyntaxKind.JSDocTag).map(jsDocTag => {
return {
name: unescapeLeadingUnderscores(jsDocTag.tagName.text),
text: jsDocTag.comment
}; }));
for (const tag of getJSDocTags(declaration)) {
if (tag.kind === SyntaxKind.JSDocTag) {
tags.push({ name: unescapeLeadingUnderscores(tag.tagName.text), text: tag.comment });
}
}
});
+7 -11
View File
@@ -29,8 +29,6 @@ namespace ts.JsTyping {
// that we are confident require typings
let safeList: Map<string>;
const EmptySafeList: Map<string> = createMap<string>();
/* @internal */
export const nodeCoreModuleList: ReadonlyArray<string> = [
"buffer", "querystring", "events", "http", "cluster",
@@ -177,16 +175,14 @@ namespace ts.JsTyping {
* @param fileNames are the names for source files in the project
*/
function getTypingNamesFromSourceFileNames(fileNames: string[]) {
if (safeList !== EmptySafeList) {
for (const j of fileNames) {
if (!hasJavaScriptFileExtension(j)) continue;
for (const j of fileNames) {
if (!hasJavaScriptFileExtension(j)) continue;
const inferredTypingName = removeFileExtension(getBaseFileName(j.toLowerCase()));
const cleanedTypingName = inferredTypingName.replace(/((?:\.|-)min(?=\.|$))|((?:-|\.)\d+)/g, "");
const safe = safeList.get(cleanedTypingName);
if (safe !== undefined) {
addInferredTyping(safe);
}
const inferredTypingName = removeFileExtension(getBaseFileName(j.toLowerCase()));
const cleanedTypingName = inferredTypingName.replace(/((?:\.|-)min(?=\.|$))|((?:-|\.)\d+)/g, "");
const safe = safeList.get(cleanedTypingName);
if (safe !== undefined) {
addInferredTyping(safe);
}
}
-1
View File
@@ -2,7 +2,6 @@
/* @internal */
namespace ts {
export const scanner: Scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);
export const emptyArray: any[] = [];
export const enum SemanticMeaning {
None = 0x0,
@@ -0,0 +1,43 @@
//// [tests/cases/compiler/narrowedImports.ts] ////
//// [a.d.ts]
declare const a0: number | undefined;
export default a0;
export const a1: number | undefined;
//// [b.d.ts]
declare const b: number | undefined;
declare namespace b {}
export = b;
//// [x.ts]
import a0, { a1, a1 as a2 } from "./a";
import * as b0 from "./b";
import b1 = require("./b");
let x: number;
if (a0) x = a0;
if (a1) x = a1;
if (a2) x = a2;
if (b0) x = b0;
if (b1) x = b1;
//// [x.js]
"use strict";
exports.__esModule = true;
var a_1 = require("./a");
var b0 = require("./b");
var b1 = require("./b");
var x;
if (a_1["default"])
x = a_1["default"];
if (a_1.a1)
x = a_1.a1;
if (a_1.a1)
x = a_1.a1;
if (b0)
x = b0;
if (b1)
x = b1;
@@ -0,0 +1,61 @@
=== /x.ts ===
import a0, { a1, a1 as a2 } from "./a";
>a0 : Symbol(a0, Decl(x.ts, 0, 6))
>a1 : Symbol(a1, Decl(x.ts, 0, 12))
>a1 : Symbol(a2, Decl(x.ts, 0, 16))
>a2 : Symbol(a2, Decl(x.ts, 0, 16))
import * as b0 from "./b";
>b0 : Symbol(b0, Decl(x.ts, 1, 6))
import b1 = require("./b");
>b1 : Symbol(b1, Decl(x.ts, 1, 26))
let x: number;
>x : Symbol(x, Decl(x.ts, 4, 3))
if (a0) x = a0;
>a0 : Symbol(a0, Decl(x.ts, 0, 6))
>x : Symbol(x, Decl(x.ts, 4, 3))
>a0 : Symbol(a0, Decl(x.ts, 0, 6))
if (a1) x = a1;
>a1 : Symbol(a1, Decl(x.ts, 0, 12))
>x : Symbol(x, Decl(x.ts, 4, 3))
>a1 : Symbol(a1, Decl(x.ts, 0, 12))
if (a2) x = a2;
>a2 : Symbol(a2, Decl(x.ts, 0, 16))
>x : Symbol(x, Decl(x.ts, 4, 3))
>a2 : Symbol(a2, Decl(x.ts, 0, 16))
if (b0) x = b0;
>b0 : Symbol(b0, Decl(x.ts, 1, 6))
>x : Symbol(x, Decl(x.ts, 4, 3))
>b0 : Symbol(b0, Decl(x.ts, 1, 6))
if (b1) x = b1;
>b1 : Symbol(b1, Decl(x.ts, 1, 26))
>x : Symbol(x, Decl(x.ts, 4, 3))
>b1 : Symbol(b1, Decl(x.ts, 1, 26))
=== /a.d.ts ===
declare const a0: number | undefined;
>a0 : Symbol(a0, Decl(a.d.ts, 0, 13))
export default a0;
>a0 : Symbol(a0, Decl(a.d.ts, 0, 13))
export const a1: number | undefined;
>a1 : Symbol(a1, Decl(a.d.ts, 2, 12))
=== /b.d.ts ===
declare const b: number | undefined;
>b : Symbol(b, Decl(b.d.ts, 0, 13), Decl(b.d.ts, 0, 36))
declare namespace b {}
>b : Symbol(b, Decl(b.d.ts, 0, 13), Decl(b.d.ts, 0, 36))
export = b;
>b : Symbol(b, Decl(b.d.ts, 0, 13), Decl(b.d.ts, 0, 36))
@@ -0,0 +1,66 @@
=== /x.ts ===
import a0, { a1, a1 as a2 } from "./a";
>a0 : number | undefined
>a1 : number | undefined
>a1 : number | undefined
>a2 : number | undefined
import * as b0 from "./b";
>b0 : number | undefined
import b1 = require("./b");
>b1 : number | undefined
let x: number;
>x : number
if (a0) x = a0;
>a0 : number | undefined
>x = a0 : number
>x : number
>a0 : number
if (a1) x = a1;
>a1 : number | undefined
>x = a1 : number
>x : number
>a1 : number
if (a2) x = a2;
>a2 : number | undefined
>x = a2 : number
>x : number
>a2 : number
if (b0) x = b0;
>b0 : number | undefined
>x = b0 : number
>x : number
>b0 : number
if (b1) x = b1;
>b1 : number | undefined
>x = b1 : number
>x : number
>b1 : number
=== /a.d.ts ===
declare const a0: number | undefined;
>a0 : number | undefined
export default a0;
>a0 : number | undefined
export const a1: number | undefined;
>a1 : number | undefined
=== /b.d.ts ===
declare const b: number | undefined;
>b : number | undefined
declare namespace b {}
>b : number | undefined
export = b;
>b : number | undefined
@@ -0,0 +1,18 @@
//// [tests/cases/compiler/narrowedImports_assumeInitialized.ts] ////
//// [a.d.ts]
declare namespace a {
export const x: number;
}
export = a;
//// [b.ts]
import a = require("./a");
a.x;
//// [b.js]
"use strict";
exports.__esModule = true;
var a = require("./a");
a.x;
@@ -0,0 +1,19 @@
=== /b.ts ===
import a = require("./a");
>a : Symbol(a, Decl(b.ts, 0, 0))
a.x;
>a.x : Symbol(a.x, Decl(a.d.ts, 1, 16))
>a : Symbol(a, Decl(b.ts, 0, 0))
>x : Symbol(a.x, Decl(a.d.ts, 1, 16))
=== /a.d.ts ===
declare namespace a {
>a : Symbol(a, Decl(a.d.ts, 0, 0))
export const x: number;
>x : Symbol(x, Decl(a.d.ts, 1, 16))
}
export = a;
>a : Symbol(a, Decl(a.d.ts, 0, 0))
@@ -0,0 +1,19 @@
=== /b.ts ===
import a = require("./a");
>a : typeof a
a.x;
>a.x : number
>a : typeof a
>x : number
=== /a.d.ts ===
declare namespace a {
>a : typeof a
export const x: number;
>x : number
}
export = a;
>a : typeof a
+24
View File
@@ -0,0 +1,24 @@
// @strictNullChecks: true
// @Filename: /a.d.ts
declare const a0: number | undefined;
export default a0;
export const a1: number | undefined;
// @Filename: /b.d.ts
declare const b: number | undefined;
declare namespace b {}
export = b;
// @Filename: /x.ts
import a0, { a1, a1 as a2 } from "./a";
import * as b0 from "./b";
import b1 = require("./b");
let x: number;
if (a0) x = a0;
if (a1) x = a1;
if (a2) x = a2;
if (b0) x = b0;
if (b1) x = b1;
@@ -0,0 +1,11 @@
// @strictNullChecks: true
// @Filename: /a.d.ts
declare namespace a {
export const x: number;
}
export = a;
// @Filename: /b.ts
import a = require("./a");
a.x;