Move allocators.ts to services.ts, meaning.ts to utilities.ts, and transpile functions to a new file transpile.ts

This commit is contained in:
Andy Hanson 2016-09-07 14:25:52 -07:00
parent 67c2ed6199
commit c3e63ee1f1
11 changed files with 962 additions and 968 deletions

View file

@ -122,7 +122,6 @@ var servicesSources = [
}).concat([
"types.ts",
"utilities.ts",
"allocators.ts",
"breakpoints.ts",
"classifier.ts",
"completions.ts",
@ -131,7 +130,6 @@ var servicesSources = [
"goToDefinition.ts",
"jsDoc.ts",
"jsTyping.ts",
"meaning.ts",
"navigateTo.ts",
"navigationBar.ts",
"outliningElementsCollector.ts",
@ -142,6 +140,7 @@ var servicesSources = [
"shims.ts",
"signatureHelp.ts",
"symbolDisplay.ts",
"transpile.ts",
"formatting/formatting.ts",
"formatting/formattingContext.ts",
"formatting/formattingRequestKind.ts",

View file

@ -1,633 +0,0 @@
/* @internal */
namespace ts.Allocators {
function createNode(kind: SyntaxKind, pos: number, end: number, parent?: Node): NodeObject | TokenObject | IdentifierObject {
const node = kind >= SyntaxKind.FirstNode ? new NodeObject(kind, pos, end) :
kind === SyntaxKind.Identifier ? new IdentifierObject(kind, pos, end) :
new TokenObject(kind, pos, end);
node.parent = parent;
return node;
}
class NodeObject implements Node {
public kind: SyntaxKind;
public pos: number;
public end: number;
public flags: NodeFlags;
public parent: Node;
public jsDocComments: JSDocComment[];
public original: Node;
public transformFlags: TransformFlags;
public excludeTransformFlags: TransformFlags;
private _children: Node[];
constructor(kind: SyntaxKind, pos: number, end: number) {
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.transformFlags = undefined;
this.excludeTransformFlags = undefined;
this.parent = undefined;
this.kind = kind;
}
public getSourceFile(): SourceFile {
return getSourceFileOfNode(this);
}
public getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number {
return getTokenPosOfNode(this, sourceFile, includeJsDocComment);
}
public getFullStart(): number {
return this.pos;
}
public getEnd(): number {
return this.end;
}
public getWidth(sourceFile?: SourceFile): number {
return this.getEnd() - this.getStart(sourceFile);
}
public getFullWidth(): number {
return this.end - this.pos;
}
public getLeadingTriviaWidth(sourceFile?: SourceFile): number {
return this.getStart(sourceFile) - this.pos;
}
public getFullText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end);
}
public getText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd());
}
private addSyntheticNodes(nodes: Node[], pos: number, end: number, useJSDocScanner?: boolean): number {
scanner.setTextPos(pos);
while (pos < end) {
const token = useJSDocScanner ? scanner.scanJSDocToken() : scanner.scan();
const textPos = scanner.getTextPos();
if (textPos <= end) {
nodes.push(createNode(token, pos, textPos, this));
}
pos = textPos;
}
return pos;
}
private createSyntaxList(nodes: NodeArray<Node>): Node {
const list = <NodeObject>createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, this);
list._children = [];
let pos = nodes.pos;
for (const node of nodes) {
if (pos < node.pos) {
pos = this.addSyntheticNodes(list._children, pos, node.pos);
}
list._children.push(node);
pos = node.end;
}
if (pos < nodes.end) {
this.addSyntheticNodes(list._children, pos, nodes.end);
}
return list;
}
private createChildren(sourceFile?: SourceFile) {
let children: Node[];
if (this.kind >= SyntaxKind.FirstNode) {
scanner.setText((sourceFile || this.getSourceFile()).text);
children = [];
let pos = this.pos;
const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode;
const processNode = (node: Node) => {
const isJSDocTagNode = isJSDocTag(node);
if (!isJSDocTagNode && pos < node.pos) {
pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner);
}
children.push(node);
if (!isJSDocTagNode) {
pos = node.end;
}
};
const processNodes = (nodes: NodeArray<Node>) => {
if (pos < nodes.pos) {
pos = this.addSyntheticNodes(children, pos, nodes.pos, useJSDocScanner);
}
children.push(this.createSyntaxList(<NodeArray<Node>>nodes));
pos = nodes.end;
};
// jsDocComments need to be the first children
if (this.jsDocComments) {
for (const jsDocComment of this.jsDocComments) {
processNode(jsDocComment);
}
}
// For syntactic classifications, all trivia are classcified together, including jsdoc comments.
// For that to work, the jsdoc comments should still be the leading trivia of the first child.
// Restoring the scanner position ensures that.
pos = this.pos;
forEachChild(this, processNode, processNodes);
if (pos < this.end) {
this.addSyntheticNodes(children, pos, this.end);
}
scanner.setText(undefined);
}
this._children = children || emptyArray;
}
public getChildCount(sourceFile?: SourceFile): number {
if (!this._children) this.createChildren(sourceFile);
return this._children.length;
}
public getChildAt(index: number, sourceFile?: SourceFile): Node {
if (!this._children) this.createChildren(sourceFile);
return this._children[index];
}
public getChildren(sourceFile?: SourceFile): Node[] {
if (!this._children) this.createChildren(sourceFile);
return this._children;
}
public getFirstToken(sourceFile?: SourceFile): Node {
const children = this.getChildren(sourceFile);
if (!children.length) {
return undefined;
}
const child = children[0];
return child.kind < SyntaxKind.FirstNode ? child : child.getFirstToken(sourceFile);
}
public getLastToken(sourceFile?: SourceFile): Node {
const children = this.getChildren(sourceFile);
const child = lastOrUndefined(children);
if (!child) {
return undefined;
}
return child.kind < SyntaxKind.FirstNode ? child : child.getLastToken(sourceFile);
}
}
class TokenOrIdentifierObject implements Token {
public kind: SyntaxKind;
public pos: number;
public end: number;
public flags: NodeFlags;
public parent: Node;
public jsDocComments: JSDocComment[];
public __tokenTag: any;
constructor(pos: number, end: number) {
// Set properties in same order as NodeObject
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.parent = undefined;
}
public getSourceFile(): SourceFile {
return getSourceFileOfNode(this);
}
public getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number {
return getTokenPosOfNode(this, sourceFile, includeJsDocComment);
}
public getFullStart(): number {
return this.pos;
}
public getEnd(): number {
return this.end;
}
public getWidth(sourceFile?: SourceFile): number {
return this.getEnd() - this.getStart(sourceFile);
}
public getFullWidth(): number {
return this.end - this.pos;
}
public getLeadingTriviaWidth(sourceFile?: SourceFile): number {
return this.getStart(sourceFile) - this.pos;
}
public getFullText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end);
}
public getText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd());
}
public getChildCount(sourceFile?: SourceFile): number {
return 0;
}
public getChildAt(index: number, sourceFile?: SourceFile): Node {
return undefined;
}
public getChildren(sourceFile?: SourceFile): Node[] {
return emptyArray;
}
public getFirstToken(sourceFile?: SourceFile): Node {
return undefined;
}
public getLastToken(sourceFile?: SourceFile): Node {
return undefined;
}
}
class SymbolObject implements Symbol {
flags: SymbolFlags;
name: string;
declarations: Declaration[];
// Undefined is used to indicate the value has not been computed. If, after computing, the
// symbol has no doc comment, then the empty string will be returned.
documentationComment: SymbolDisplayPart[];
constructor(flags: SymbolFlags, name: string) {
this.flags = flags;
this.name = name;
}
getFlags(): SymbolFlags {
return this.flags;
}
getName(): string {
return this.name;
}
getDeclarations(): Declaration[] {
return this.declarations;
}
getDocumentationComment(): SymbolDisplayPart[] {
if (this.documentationComment === undefined) {
this.documentationComment = JsDoc.getJsDocCommentsFromDeclarations(this.declarations, this.name, !(this.flags & SymbolFlags.Property));
}
return this.documentationComment;
}
}
class TokenObject extends TokenOrIdentifierObject {
public kind: SyntaxKind;
constructor(kind: SyntaxKind, pos: number, end: number) {
super(pos, end);
this.kind = kind;
}
}
class IdentifierObject extends TokenOrIdentifierObject {
constructor(kind: SyntaxKind, pos: number, end: number) {
super(pos, end);
}
}
IdentifierObject.prototype.kind = SyntaxKind.Identifier;
class TypeObject implements Type {
checker: TypeChecker;
flags: TypeFlags;
id: number;
symbol: Symbol;
constructor(checker: TypeChecker, flags: TypeFlags) {
this.checker = checker;
this.flags = flags;
}
getFlags(): TypeFlags {
return this.flags;
}
getSymbol(): Symbol {
return this.symbol;
}
getProperties(): Symbol[] {
return this.checker.getPropertiesOfType(this);
}
getProperty(propertyName: string): Symbol {
return this.checker.getPropertyOfType(this, propertyName);
}
getApparentProperties(): Symbol[] {
return this.checker.getAugmentedPropertiesOfType(this);
}
getCallSignatures(): Signature[] {
return this.checker.getSignaturesOfType(this, SignatureKind.Call);
}
getConstructSignatures(): Signature[] {
return this.checker.getSignaturesOfType(this, SignatureKind.Construct);
}
getStringIndexType(): Type {
return this.checker.getIndexTypeOfType(this, IndexKind.String);
}
getNumberIndexType(): Type {
return this.checker.getIndexTypeOfType(this, IndexKind.Number);
}
getBaseTypes(): ObjectType[] {
return this.flags & (TypeFlags.Class | TypeFlags.Interface)
? this.checker.getBaseTypes(<InterfaceType><Type>this)
: undefined;
}
getNonNullableType(): Type {
return this.checker.getNonNullableType(this);
}
}
class SignatureObject implements Signature {
checker: TypeChecker;
declaration: SignatureDeclaration;
typeParameters: TypeParameter[];
parameters: Symbol[];
thisParameter: Symbol;
resolvedReturnType: Type;
minArgumentCount: number;
hasRestParameter: boolean;
hasLiteralTypes: boolean;
// Undefined is used to indicate the value has not been computed. If, after computing, the
// symbol has no doc comment, then the empty string will be returned.
documentationComment: SymbolDisplayPart[];
constructor(checker: TypeChecker) {
this.checker = checker;
}
getDeclaration(): SignatureDeclaration {
return this.declaration;
}
getTypeParameters(): Type[] {
return this.typeParameters;
}
getParameters(): Symbol[] {
return this.parameters;
}
getReturnType(): Type {
return this.checker.getReturnTypeOfSignature(this);
}
getDocumentationComment(): SymbolDisplayPart[] {
if (this.documentationComment === undefined) {
this.documentationComment = this.declaration ? JsDoc.getJsDocCommentsFromDeclarations(
[this.declaration],
/*name*/ undefined,
/*canUseParsedParamTagComments*/ false) : [];
}
return this.documentationComment;
}
}
class SourceFileObject extends NodeObject implements SourceFile {
public _declarationBrand: any;
public fileName: string;
public path: Path;
public text: string;
public scriptSnapshot: IScriptSnapshot;
public lineMap: number[];
public statements: NodeArray<Statement>;
public endOfFileToken: Node;
public amdDependencies: { name: string; path: string }[];
public moduleName: string;
public referencedFiles: FileReference[];
public typeReferenceDirectives: FileReference[];
public syntacticDiagnostics: Diagnostic[];
public referenceDiagnostics: Diagnostic[];
public parseDiagnostics: Diagnostic[];
public bindDiagnostics: Diagnostic[];
public isDeclarationFile: boolean;
public isDefaultLib: boolean;
public hasNoDefaultLib: boolean;
public externalModuleIndicator: Node; // The first node that causes this file to be an external module
public commonJsModuleIndicator: Node; // The first node that causes this file to be a CommonJS module
public nodeCount: number;
public identifierCount: number;
public symbolCount: number;
public version: string;
public scriptKind: ScriptKind;
public languageVersion: ScriptTarget;
public languageVariant: LanguageVariant;
public identifiers: Map<string>;
public nameTable: Map<number>;
public resolvedModules: Map<ResolvedModule>;
public resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
public imports: LiteralExpression[];
public moduleAugmentations: LiteralExpression[];
private namedDeclarations: Map<Declaration[]>;
constructor(kind: SyntaxKind, pos: number, end: number) {
super(kind, pos, end);
}
public update(newText: string, textChangeRange: TextChangeRange): SourceFile {
return updateSourceFile(this, newText, textChangeRange);
}
public getLineAndCharacterOfPosition(position: number): LineAndCharacter {
return ts.getLineAndCharacterOfPosition(this, position);
}
public getLineStarts(): number[] {
return getLineStarts(this);
}
public getPositionOfLineAndCharacter(line: number, character: number): number {
return ts.getPositionOfLineAndCharacter(this, line, character);
}
public getNamedDeclarations(): Map<Declaration[]> {
if (!this.namedDeclarations) {
this.namedDeclarations = this.computeNamedDeclarations();
}
return this.namedDeclarations;
}
private computeNamedDeclarations(): Map<Declaration[]> {
const result = createMap<Declaration[]>();
forEachChild(this, visit);
return result;
function addDeclaration(declaration: Declaration) {
const name = getDeclarationName(declaration);
if (name) {
multiMapAdd(result, name, declaration);
}
}
function getDeclarations(name: string) {
return result[name] || (result[name] = []);
}
function getDeclarationName(declaration: Declaration) {
if (declaration.name) {
const result = getTextOfIdentifierOrLiteral(declaration.name);
if (result !== undefined) {
return result;
}
if (declaration.name.kind === SyntaxKind.ComputedPropertyName) {
const expr = (<ComputedPropertyName>declaration.name).expression;
if (expr.kind === SyntaxKind.PropertyAccessExpression) {
return (<PropertyAccessExpression>expr).name.text;
}
return getTextOfIdentifierOrLiteral(expr);
}
}
return undefined;
}
function getTextOfIdentifierOrLiteral(node: Node) {
if (node) {
if (node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.StringLiteral ||
node.kind === SyntaxKind.NumericLiteral) {
return (<Identifier | LiteralExpression>node).text;
}
}
return undefined;
}
function visit(node: Node): void {
switch (node.kind) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
const functionDeclaration = <FunctionLikeDeclaration>node;
const declarationName = getDeclarationName(functionDeclaration);
if (declarationName) {
const declarations = getDeclarations(declarationName);
const lastDeclaration = lastOrUndefined(declarations);
// Check whether this declaration belongs to an "overload group".
if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) {
// Overwrite the last declaration if it was an overload
// and this one is an implementation.
if (functionDeclaration.body && !(<FunctionLikeDeclaration>lastDeclaration).body) {
declarations[declarations.length - 1] = functionDeclaration;
}
}
else {
declarations.push(functionDeclaration);
}
forEachChild(node, visit);
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ExportSpecifier:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ImportClause:
case SyntaxKind.NamespaceImport:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.TypeLiteral:
addDeclaration(<Declaration>node);
forEachChild(node, visit);
break;
case SyntaxKind.Parameter:
// Only consider parameter properties
if (!hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
break;
}
// fall through
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement: {
const decl = <VariableDeclaration>node;
if (isBindingPattern(decl.name)) {
forEachChild(decl.name, visit);
break;
}
if (decl.initializer)
visit(decl.initializer);
}
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
addDeclaration(<Declaration>node);
break;
case SyntaxKind.ExportDeclaration:
// Handle named exports case e.g.:
// export {a, b as B} from "mod";
if ((<ExportDeclaration>node).exportClause) {
forEach((<ExportDeclaration>node).exportClause.elements, visit);
}
break;
case SyntaxKind.ImportDeclaration:
const importClause = (<ImportDeclaration>node).importClause;
if (importClause) {
// Handle default import case e.g.:
// import d from "mod";
if (importClause.name) {
addDeclaration(importClause);
}
// Handle named bindings in imports e.g.:
// import * as NS from "mod";
// import {a, b as B} from "mod";
if (importClause.namedBindings) {
if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
addDeclaration(<NamespaceImport>importClause.namedBindings);
}
else {
forEach((<NamedImports>importClause.namedBindings).elements, visit);
}
}
}
break;
default:
forEachChild(node, visit);
}
}
}
}
export function getServicesObjectAllocator(): ObjectAllocator {
return {
getNodeConstructor: () => NodeObject,
getTokenConstructor: () => TokenObject,
getIdentifierConstructor: () => IdentifierObject,
getSourceFileConstructor: () => SourceFileObject,
getSymbolConstructor: () => SymbolObject,
getTypeConstructor: () => TypeObject,
getSignatureConstructor: () => SignatureObject,
};
}
}

View file

@ -498,7 +498,7 @@ namespace ts.Classifier {
result.push(type);
}
function classifySymbol(symbol: Symbol, meaningAtPosition: Meaning.SemanticMeaning): ClassificationType {
function classifySymbol(symbol: Symbol, meaningAtPosition: SemanticMeaning): ClassificationType {
const flags = symbol.getFlags();
if ((flags & SymbolFlags.Classifiable) === SymbolFlags.None) {
return;
@ -513,7 +513,7 @@ namespace ts.Classifier {
else if (flags & SymbolFlags.TypeAlias) {
return ClassificationType.typeAliasName;
}
else if (meaningAtPosition & Meaning.SemanticMeaning.Type) {
else if (meaningAtPosition & SemanticMeaning.Type) {
if (flags & SymbolFlags.Interface) {
return ClassificationType.interfaceName;
}
@ -525,8 +525,8 @@ namespace ts.Classifier {
// Only classify a module as such if
// - It appears in a namespace context.
// - There exists a module declaration which actually impacts the value side.
if (meaningAtPosition & Meaning.SemanticMeaning.Namespace ||
(meaningAtPosition & Meaning.SemanticMeaning.Value && hasValueSideModule(symbol))) {
if (meaningAtPosition & SemanticMeaning.Namespace ||
(meaningAtPosition & SemanticMeaning.Value && hasValueSideModule(symbol))) {
return ClassificationType.moduleName;
}
}
@ -559,7 +559,7 @@ namespace ts.Classifier {
if (classifiableNames[identifier.text]) {
const symbol = typeChecker.getSymbolAtLocation(node);
if (symbol) {
const type = classifySymbol(symbol, Meaning.getMeaningFromLocation(node));
const type = classifySymbol(symbol, getMeaningFromLocation(node));
if (type) {
pushClassification(node.getStart(), node.getWidth(), type);
}

View file

@ -710,7 +710,7 @@ namespace ts.Completions {
const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(typeChecker, s, compilerOptions.target, /*performCharacterChecks*/ false, location) === entryName ? s : undefined);
if (symbol) {
const { displayParts, documentation, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, Meaning.SemanticMeaning.All);
const { displayParts, documentation, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
return {
name: entryName,
kindModifiers: SymbolDisplay.getSymbolModifiers(symbol),

View file

@ -69,7 +69,7 @@ namespace ts.FindAllReferences {
let result: ReferencedSymbol[];
// Compute the meaning from the location and the symbol it references
const searchMeaning = getIntersectingMeaningFromDeclarations(Meaning.getMeaningFromLocation(node), declarations);
const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations);
// Get the text to search for.
// Note: if this is an external module symbol, the name doesn't include quotes.
@ -363,7 +363,7 @@ namespace ts.FindAllReferences {
searchSymbol: Symbol,
searchText: string,
searchLocation: Node,
searchMeaning: Meaning.SemanticMeaning,
searchMeaning: SemanticMeaning,
findInStrings: boolean,
findInComments: boolean,
result: ReferencedSymbol[],
@ -406,7 +406,7 @@ namespace ts.FindAllReferences {
return;
}
if (!(Meaning.getMeaningFromLocation(referenceLocation) & searchMeaning)) {
if (!(getMeaningFromLocation(referenceLocation) & searchMeaning)) {
return;
}
@ -995,9 +995,9 @@ namespace ts.FindAllReferences {
* module, we want to keep the search limited to only types, as the two declarations (interface and uninstantiated module)
* do not intersect in any of the three spaces.
*/
function getIntersectingMeaningFromDeclarations(meaning: Meaning.SemanticMeaning, declarations: Declaration[]): Meaning.SemanticMeaning {
function getIntersectingMeaningFromDeclarations(meaning: SemanticMeaning, declarations: Declaration[]): SemanticMeaning {
if (declarations) {
let lastIterationMeaning: Meaning.SemanticMeaning;
let lastIterationMeaning: SemanticMeaning;
do {
// The result is order-sensitive, for instance if initialMeaning === Namespace, and declarations = [class, instantiated module]
// we need to consider both as they initialMeaning intersects with the module in the namespace space, and the module
@ -1008,7 +1008,7 @@ namespace ts.FindAllReferences {
lastIterationMeaning = meaning;
for (const declaration of declarations) {
const declarationMeaning = Meaning.getMeaningFromDeclaration(declaration);
const declarationMeaning = getMeaningFromDeclaration(declaration);
if (declarationMeaning & meaning) {
meaning |= declarationMeaning;

View file

@ -1,160 +0,0 @@
/* @internal */
namespace ts.Meaning {
export const enum SemanticMeaning {
None = 0x0,
Value = 0x1,
Type = 0x2,
Namespace = 0x4,
All = Value | Type | Namespace
}
export function getMeaningFromDeclaration(node: Node): SemanticMeaning {
switch (node.kind) {
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.EnumMember:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.CatchClause:
return SemanticMeaning.Value;
case SyntaxKind.TypeParameter:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.TypeLiteral:
return SemanticMeaning.Type;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.EnumDeclaration:
return SemanticMeaning.Value | SemanticMeaning.Type;
case SyntaxKind.ModuleDeclaration:
if (isAmbientModule(<ModuleDeclaration>node)) {
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
else if (getModuleInstanceState(node) === ModuleInstanceState.Instantiated) {
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
else {
return SemanticMeaning.Namespace;
}
case SyntaxKind.NamedImports:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportAssignment:
case SyntaxKind.ExportDeclaration:
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
// An external module can be a Value
case SyntaxKind.SourceFile:
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
}
export function getMeaningFromLocation(node: Node): SemanticMeaning {
if (node.parent.kind === SyntaxKind.ExportAssignment) {
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
}
else if (isInRightSideOfImport(node)) {
return getMeaningFromRightHandSideOfImportEquals(node);
}
else if (isDeclarationName(node)) {
return getMeaningFromDeclaration(node.parent);
}
else if (isTypeReference(node)) {
return SemanticMeaning.Type;
}
else if (isNamespaceReference(node)) {
return SemanticMeaning.Namespace;
}
else {
return SemanticMeaning.Value;
}
}
function getMeaningFromRightHandSideOfImportEquals(node: Node) {
Debug.assert(node.kind === SyntaxKind.Identifier);
// import a = |b|; // Namespace
// import a = |b.c|; // Value, type, namespace
// import a = |b.c|.d; // Namespace
if (node.parent.kind === SyntaxKind.QualifiedName &&
(<QualifiedName>node.parent).right === node &&
node.parent.parent.kind === SyntaxKind.ImportEqualsDeclaration) {
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
}
return SemanticMeaning.Namespace;
}
function isInRightSideOfImport(node: Node) {
while (node.parent.kind === SyntaxKind.QualifiedName) {
node = node.parent;
}
return isInternalModuleImportEqualsDeclaration(node.parent) && (<ImportEqualsDeclaration>node.parent).moduleReference === node;
}
function isNamespaceReference(node: Node): boolean {
return isQualifiedNameNamespaceReference(node) || isPropertyAccessNamespaceReference(node);
}
function isQualifiedNameNamespaceReference(node: Node): boolean {
let root = node;
let isLastClause = true;
if (root.parent.kind === SyntaxKind.QualifiedName) {
while (root.parent && root.parent.kind === SyntaxKind.QualifiedName) {
root = root.parent;
}
isLastClause = (<QualifiedName>root).right === node;
}
return root.parent.kind === SyntaxKind.TypeReference && !isLastClause;
}
function isPropertyAccessNamespaceReference(node: Node): boolean {
let root = node;
let isLastClause = true;
if (root.parent.kind === SyntaxKind.PropertyAccessExpression) {
while (root.parent && root.parent.kind === SyntaxKind.PropertyAccessExpression) {
root = root.parent;
}
isLastClause = (<PropertyAccessExpression>root).name === node;
}
if (!isLastClause && root.parent.kind === SyntaxKind.ExpressionWithTypeArguments && root.parent.parent.kind === SyntaxKind.HeritageClause) {
const decl = root.parent.parent.parent;
return (decl.kind === SyntaxKind.ClassDeclaration && (<HeritageClause>root.parent.parent).token === SyntaxKind.ImplementsKeyword) ||
(decl.kind === SyntaxKind.InterfaceDeclaration && (<HeritageClause>root.parent.parent).token === SyntaxKind.ExtendsKeyword);
}
return false;
}
function isTypeReference(node: Node): boolean {
if (isRightSideOfQualifiedNameOrPropertyAccess(node)) {
node = node.parent;
}
return node.parent.kind === SyntaxKind.TypeReference ||
(node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent)) ||
(node.kind === SyntaxKind.ThisKeyword && !isPartOfExpression(node)) ||
node.kind === SyntaxKind.ThisType;
}
}

View file

@ -3,7 +3,6 @@
/// <reference path='types.ts' />
/// <reference path='utilities.ts' />
/// <reference path='allocators.ts' />
/// <reference path='breakpoints.ts' />
/// <reference path='classifier.ts' />
/// <reference path='completions.ts' />
@ -12,7 +11,6 @@
/// <reference path='goToDefinition.ts' />
/// <reference path='jsDoc.ts' />
/// <reference path='jsTyping.ts' />
/// <reference path='meaning.ts' />
/// <reference path='navigateTo.ts' />
/// <reference path='navigationBar.ts' />
/// <reference path='outliningElementsCollector.ts' />
@ -21,6 +19,7 @@
/// <reference path='rename.ts' />
/// <reference path='signatureHelp.ts' />
/// <reference path='symbolDisplay.ts' />
/// <reference path='transpile.ts' />
/// <reference path='formatting\formatting.ts' />
/// <reference path='formatting\smartIndenter.ts' />
@ -28,6 +27,637 @@ namespace ts {
/** The version of the language service API */
export const servicesVersion = "0.5";
function createNode(kind: SyntaxKind, pos: number, end: number, parent?: Node): NodeObject | TokenObject | IdentifierObject {
const node = kind >= SyntaxKind.FirstNode ? new NodeObject(kind, pos, end) :
kind === SyntaxKind.Identifier ? new IdentifierObject(kind, pos, end) :
new TokenObject(kind, pos, end);
node.parent = parent;
return node;
}
class NodeObject implements Node {
public kind: SyntaxKind;
public pos: number;
public end: number;
public flags: NodeFlags;
public parent: Node;
public jsDocComments: JSDocComment[];
public original: Node;
public transformFlags: TransformFlags;
public excludeTransformFlags: TransformFlags;
private _children: Node[];
constructor(kind: SyntaxKind, pos: number, end: number) {
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.transformFlags = undefined;
this.excludeTransformFlags = undefined;
this.parent = undefined;
this.kind = kind;
}
public getSourceFile(): SourceFile {
return getSourceFileOfNode(this);
}
public getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number {
return getTokenPosOfNode(this, sourceFile, includeJsDocComment);
}
public getFullStart(): number {
return this.pos;
}
public getEnd(): number {
return this.end;
}
public getWidth(sourceFile?: SourceFile): number {
return this.getEnd() - this.getStart(sourceFile);
}
public getFullWidth(): number {
return this.end - this.pos;
}
public getLeadingTriviaWidth(sourceFile?: SourceFile): number {
return this.getStart(sourceFile) - this.pos;
}
public getFullText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end);
}
public getText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd());
}
private addSyntheticNodes(nodes: Node[], pos: number, end: number, useJSDocScanner?: boolean): number {
scanner.setTextPos(pos);
while (pos < end) {
const token = useJSDocScanner ? scanner.scanJSDocToken() : scanner.scan();
const textPos = scanner.getTextPos();
if (textPos <= end) {
nodes.push(createNode(token, pos, textPos, this));
}
pos = textPos;
}
return pos;
}
private createSyntaxList(nodes: NodeArray<Node>): Node {
const list = <NodeObject>createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, this);
list._children = [];
let pos = nodes.pos;
for (const node of nodes) {
if (pos < node.pos) {
pos = this.addSyntheticNodes(list._children, pos, node.pos);
}
list._children.push(node);
pos = node.end;
}
if (pos < nodes.end) {
this.addSyntheticNodes(list._children, pos, nodes.end);
}
return list;
}
private createChildren(sourceFile?: SourceFile) {
let children: Node[];
if (this.kind >= SyntaxKind.FirstNode) {
scanner.setText((sourceFile || this.getSourceFile()).text);
children = [];
let pos = this.pos;
const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode;
const processNode = (node: Node) => {
const isJSDocTagNode = isJSDocTag(node);
if (!isJSDocTagNode && pos < node.pos) {
pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner);
}
children.push(node);
if (!isJSDocTagNode) {
pos = node.end;
}
};
const processNodes = (nodes: NodeArray<Node>) => {
if (pos < nodes.pos) {
pos = this.addSyntheticNodes(children, pos, nodes.pos, useJSDocScanner);
}
children.push(this.createSyntaxList(<NodeArray<Node>>nodes));
pos = nodes.end;
};
// jsDocComments need to be the first children
if (this.jsDocComments) {
for (const jsDocComment of this.jsDocComments) {
processNode(jsDocComment);
}
}
// For syntactic classifications, all trivia are classcified together, including jsdoc comments.
// For that to work, the jsdoc comments should still be the leading trivia of the first child.
// Restoring the scanner position ensures that.
pos = this.pos;
forEachChild(this, processNode, processNodes);
if (pos < this.end) {
this.addSyntheticNodes(children, pos, this.end);
}
scanner.setText(undefined);
}
this._children = children || emptyArray;
}
public getChildCount(sourceFile?: SourceFile): number {
if (!this._children) this.createChildren(sourceFile);
return this._children.length;
}
public getChildAt(index: number, sourceFile?: SourceFile): Node {
if (!this._children) this.createChildren(sourceFile);
return this._children[index];
}
public getChildren(sourceFile?: SourceFile): Node[] {
if (!this._children) this.createChildren(sourceFile);
return this._children;
}
public getFirstToken(sourceFile?: SourceFile): Node {
const children = this.getChildren(sourceFile);
if (!children.length) {
return undefined;
}
const child = children[0];
return child.kind < SyntaxKind.FirstNode ? child : child.getFirstToken(sourceFile);
}
public getLastToken(sourceFile?: SourceFile): Node {
const children = this.getChildren(sourceFile);
const child = lastOrUndefined(children);
if (!child) {
return undefined;
}
return child.kind < SyntaxKind.FirstNode ? child : child.getLastToken(sourceFile);
}
}
class TokenOrIdentifierObject implements Token {
public kind: SyntaxKind;
public pos: number;
public end: number;
public flags: NodeFlags;
public parent: Node;
public jsDocComments: JSDocComment[];
public __tokenTag: any;
constructor(pos: number, end: number) {
// Set properties in same order as NodeObject
this.pos = pos;
this.end = end;
this.flags = NodeFlags.None;
this.parent = undefined;
}
public getSourceFile(): SourceFile {
return getSourceFileOfNode(this);
}
public getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number {
return getTokenPosOfNode(this, sourceFile, includeJsDocComment);
}
public getFullStart(): number {
return this.pos;
}
public getEnd(): number {
return this.end;
}
public getWidth(sourceFile?: SourceFile): number {
return this.getEnd() - this.getStart(sourceFile);
}
public getFullWidth(): number {
return this.end - this.pos;
}
public getLeadingTriviaWidth(sourceFile?: SourceFile): number {
return this.getStart(sourceFile) - this.pos;
}
public getFullText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end);
}
public getText(sourceFile?: SourceFile): string {
return (sourceFile || this.getSourceFile()).text.substring(this.getStart(), this.getEnd());
}
public getChildCount(sourceFile?: SourceFile): number {
return 0;
}
public getChildAt(index: number, sourceFile?: SourceFile): Node {
return undefined;
}
public getChildren(sourceFile?: SourceFile): Node[] {
return emptyArray;
}
public getFirstToken(sourceFile?: SourceFile): Node {
return undefined;
}
public getLastToken(sourceFile?: SourceFile): Node {
return undefined;
}
}
class SymbolObject implements Symbol {
flags: SymbolFlags;
name: string;
declarations: Declaration[];
// Undefined is used to indicate the value has not been computed. If, after computing, the
// symbol has no doc comment, then the empty string will be returned.
documentationComment: SymbolDisplayPart[];
constructor(flags: SymbolFlags, name: string) {
this.flags = flags;
this.name = name;
}
getFlags(): SymbolFlags {
return this.flags;
}
getName(): string {
return this.name;
}
getDeclarations(): Declaration[] {
return this.declarations;
}
getDocumentationComment(): SymbolDisplayPart[] {
if (this.documentationComment === undefined) {
this.documentationComment = JsDoc.getJsDocCommentsFromDeclarations(this.declarations, this.name, !(this.flags & SymbolFlags.Property));
}
return this.documentationComment;
}
}
class TokenObject extends TokenOrIdentifierObject {
public kind: SyntaxKind;
constructor(kind: SyntaxKind, pos: number, end: number) {
super(pos, end);
this.kind = kind;
}
}
class IdentifierObject extends TokenOrIdentifierObject {
constructor(kind: SyntaxKind, pos: number, end: number) {
super(pos, end);
}
}
IdentifierObject.prototype.kind = SyntaxKind.Identifier;
class TypeObject implements Type {
checker: TypeChecker;
flags: TypeFlags;
id: number;
symbol: Symbol;
constructor(checker: TypeChecker, flags: TypeFlags) {
this.checker = checker;
this.flags = flags;
}
getFlags(): TypeFlags {
return this.flags;
}
getSymbol(): Symbol {
return this.symbol;
}
getProperties(): Symbol[] {
return this.checker.getPropertiesOfType(this);
}
getProperty(propertyName: string): Symbol {
return this.checker.getPropertyOfType(this, propertyName);
}
getApparentProperties(): Symbol[] {
return this.checker.getAugmentedPropertiesOfType(this);
}
getCallSignatures(): Signature[] {
return this.checker.getSignaturesOfType(this, SignatureKind.Call);
}
getConstructSignatures(): Signature[] {
return this.checker.getSignaturesOfType(this, SignatureKind.Construct);
}
getStringIndexType(): Type {
return this.checker.getIndexTypeOfType(this, IndexKind.String);
}
getNumberIndexType(): Type {
return this.checker.getIndexTypeOfType(this, IndexKind.Number);
}
getBaseTypes(): ObjectType[] {
return this.flags & (TypeFlags.Class | TypeFlags.Interface)
? this.checker.getBaseTypes(<InterfaceType><Type>this)
: undefined;
}
getNonNullableType(): Type {
return this.checker.getNonNullableType(this);
}
}
class SignatureObject implements Signature {
checker: TypeChecker;
declaration: SignatureDeclaration;
typeParameters: TypeParameter[];
parameters: Symbol[];
thisParameter: Symbol;
resolvedReturnType: Type;
minArgumentCount: number;
hasRestParameter: boolean;
hasLiteralTypes: boolean;
// Undefined is used to indicate the value has not been computed. If, after computing, the
// symbol has no doc comment, then the empty string will be returned.
documentationComment: SymbolDisplayPart[];
constructor(checker: TypeChecker) {
this.checker = checker;
}
getDeclaration(): SignatureDeclaration {
return this.declaration;
}
getTypeParameters(): Type[] {
return this.typeParameters;
}
getParameters(): Symbol[] {
return this.parameters;
}
getReturnType(): Type {
return this.checker.getReturnTypeOfSignature(this);
}
getDocumentationComment(): SymbolDisplayPart[] {
if (this.documentationComment === undefined) {
this.documentationComment = this.declaration ? JsDoc.getJsDocCommentsFromDeclarations(
[this.declaration],
/*name*/ undefined,
/*canUseParsedParamTagComments*/ false) : [];
}
return this.documentationComment;
}
}
class SourceFileObject extends NodeObject implements SourceFile {
public _declarationBrand: any;
public fileName: string;
public path: Path;
public text: string;
public scriptSnapshot: IScriptSnapshot;
public lineMap: number[];
public statements: NodeArray<Statement>;
public endOfFileToken: Node;
public amdDependencies: { name: string; path: string }[];
public moduleName: string;
public referencedFiles: FileReference[];
public typeReferenceDirectives: FileReference[];
public syntacticDiagnostics: Diagnostic[];
public referenceDiagnostics: Diagnostic[];
public parseDiagnostics: Diagnostic[];
public bindDiagnostics: Diagnostic[];
public isDeclarationFile: boolean;
public isDefaultLib: boolean;
public hasNoDefaultLib: boolean;
public externalModuleIndicator: Node; // The first node that causes this file to be an external module
public commonJsModuleIndicator: Node; // The first node that causes this file to be a CommonJS module
public nodeCount: number;
public identifierCount: number;
public symbolCount: number;
public version: string;
public scriptKind: ScriptKind;
public languageVersion: ScriptTarget;
public languageVariant: LanguageVariant;
public identifiers: Map<string>;
public nameTable: Map<number>;
public resolvedModules: Map<ResolvedModule>;
public resolvedTypeReferenceDirectiveNames: Map<ResolvedTypeReferenceDirective>;
public imports: LiteralExpression[];
public moduleAugmentations: LiteralExpression[];
private namedDeclarations: Map<Declaration[]>;
constructor(kind: SyntaxKind, pos: number, end: number) {
super(kind, pos, end);
}
public update(newText: string, textChangeRange: TextChangeRange): SourceFile {
return updateSourceFile(this, newText, textChangeRange);
}
public getLineAndCharacterOfPosition(position: number): LineAndCharacter {
return ts.getLineAndCharacterOfPosition(this, position);
}
public getLineStarts(): number[] {
return getLineStarts(this);
}
public getPositionOfLineAndCharacter(line: number, character: number): number {
return ts.getPositionOfLineAndCharacter(this, line, character);
}
public getNamedDeclarations(): Map<Declaration[]> {
if (!this.namedDeclarations) {
this.namedDeclarations = this.computeNamedDeclarations();
}
return this.namedDeclarations;
}
private computeNamedDeclarations(): Map<Declaration[]> {
const result = createMap<Declaration[]>();
forEachChild(this, visit);
return result;
function addDeclaration(declaration: Declaration) {
const name = getDeclarationName(declaration);
if (name) {
multiMapAdd(result, name, declaration);
}
}
function getDeclarations(name: string) {
return result[name] || (result[name] = []);
}
function getDeclarationName(declaration: Declaration) {
if (declaration.name) {
const result = getTextOfIdentifierOrLiteral(declaration.name);
if (result !== undefined) {
return result;
}
if (declaration.name.kind === SyntaxKind.ComputedPropertyName) {
const expr = (<ComputedPropertyName>declaration.name).expression;
if (expr.kind === SyntaxKind.PropertyAccessExpression) {
return (<PropertyAccessExpression>expr).name.text;
}
return getTextOfIdentifierOrLiteral(expr);
}
}
return undefined;
}
function getTextOfIdentifierOrLiteral(node: Node) {
if (node) {
if (node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.StringLiteral ||
node.kind === SyntaxKind.NumericLiteral) {
return (<Identifier | LiteralExpression>node).text;
}
}
return undefined;
}
function visit(node: Node): void {
switch (node.kind) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
const functionDeclaration = <FunctionLikeDeclaration>node;
const declarationName = getDeclarationName(functionDeclaration);
if (declarationName) {
const declarations = getDeclarations(declarationName);
const lastDeclaration = lastOrUndefined(declarations);
// Check whether this declaration belongs to an "overload group".
if (lastDeclaration && functionDeclaration.parent === lastDeclaration.parent && functionDeclaration.symbol === lastDeclaration.symbol) {
// Overwrite the last declaration if it was an overload
// and this one is an implementation.
if (functionDeclaration.body && !(<FunctionLikeDeclaration>lastDeclaration).body) {
declarations[declarations.length - 1] = functionDeclaration;
}
}
else {
declarations.push(functionDeclaration);
}
forEachChild(node, visit);
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ExportSpecifier:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ImportClause:
case SyntaxKind.NamespaceImport:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.TypeLiteral:
addDeclaration(<Declaration>node);
forEachChild(node, visit);
break;
case SyntaxKind.Parameter:
// Only consider parameter properties
if (!hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
break;
}
// fall through
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement: {
const decl = <VariableDeclaration>node;
if (isBindingPattern(decl.name)) {
forEachChild(decl.name, visit);
break;
}
if (decl.initializer)
visit(decl.initializer);
}
case SyntaxKind.EnumMember:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
addDeclaration(<Declaration>node);
break;
case SyntaxKind.ExportDeclaration:
// Handle named exports case e.g.:
// export {a, b as B} from "mod";
if ((<ExportDeclaration>node).exportClause) {
forEach((<ExportDeclaration>node).exportClause.elements, visit);
}
break;
case SyntaxKind.ImportDeclaration:
const importClause = (<ImportDeclaration>node).importClause;
if (importClause) {
// Handle default import case e.g.:
// import d from "mod";
if (importClause.name) {
addDeclaration(importClause);
}
// Handle named bindings in imports e.g.:
// import * as NS from "mod";
// import {a, b as B} from "mod";
if (importClause.namedBindings) {
if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
addDeclaration(<NamespaceImport>importClause.namedBindings);
}
else {
forEach((<NamedImports>importClause.namedBindings).elements, visit);
}
}
}
break;
default:
forEachChild(node, visit);
}
}
}
}
function getServicesObjectAllocator(): ObjectAllocator {
return {
getNodeConstructor: () => NodeObject,
getTokenConstructor: () => TokenObject,
getIdentifierConstructor: () => IdentifierObject,
getSourceFileConstructor: () => SourceFileObject,
getSymbolConstructor: () => SymbolObject,
getTypeConstructor: () => TypeObject,
getSignatureConstructor: () => SignatureObject,
};
}
/// Language Service
// Information about a specific host file.
@ -202,159 +832,6 @@ namespace ts {
sourceFile.scriptSnapshot = scriptSnapshot;
}
export interface TranspileOptions {
compilerOptions?: CompilerOptions;
fileName?: string;
reportDiagnostics?: boolean;
moduleName?: string;
renamedDependencies?: MapLike<string>;
}
export interface TranspileOutput {
outputText: string;
diagnostics?: Diagnostic[];
sourceMapText?: string;
}
let commandLineOptionsStringToEnum: CommandLineOptionOfCustomType[];
/** JS users may pass in string values for enum compiler options (such as ModuleKind), so convert. */
function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions {
// Lazily create this value to fix module loading errors.
commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || <CommandLineOptionOfCustomType[]>filter(optionDeclarations, o =>
typeof o.type === "object" && !forEachProperty(o.type, v => typeof v !== "number"));
options = clone(options);
for (const opt of commandLineOptionsStringToEnum) {
if (!hasProperty(options, opt.name)) {
continue;
}
const value = options[opt.name];
// Value should be a key of opt.type
if (typeof value === "string") {
// If value is not a string, this will fail
options[opt.name] = parseCustomTypeOption(opt, value, diagnostics);
}
else {
if (!forEachProperty(opt.type, v => v === value)) {
// Supplied value isn't a valid enum value.
diagnostics.push(createCompilerDiagnosticForInvalidCustomType(opt));
}
}
}
return options;
}
/*
* This function will compile source text from 'input' argument using specified compiler options.
* If not options are provided - it will use a set of default compiler options.
* Extra compiler options that will unconditionally be used by this function are:
* - isolatedModules = true
* - allowNonTsExtensions = true
* - noLib = true
* - noResolve = true
*/
export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput {
const diagnostics: Diagnostic[] = [];
const options: CompilerOptions = transpileOptions.compilerOptions ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : getDefaultCompilerOptions();
options.isolatedModules = true;
// transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths.
options.suppressOutputPathCheck = true;
// Filename can be non-ts file.
options.allowNonTsExtensions = true;
// We are not returning a sourceFile for lib file when asked by the program,
// so pass --noLib to avoid reporting a file not found error.
options.noLib = true;
// Clear out other settings that would not be used in transpiling this module
options.lib = undefined;
options.types = undefined;
options.noEmit = undefined;
options.noEmitOnError = undefined;
options.paths = undefined;
options.rootDirs = undefined;
options.declaration = undefined;
options.declarationDir = undefined;
options.out = undefined;
options.outFile = undefined;
// We are not doing a full typecheck, we are not resolving the whole context,
// so pass --noResolve to avoid reporting missing file errors.
options.noResolve = true;
// if jsx is specified then treat file as .tsx
const inputFileName = transpileOptions.fileName || (options.jsx ? "module.tsx" : "module.ts");
const sourceFile = createSourceFile(inputFileName, input, options.target);
if (transpileOptions.moduleName) {
sourceFile.moduleName = transpileOptions.moduleName;
}
if (transpileOptions.renamedDependencies) {
sourceFile.renamedDependencies = createMap(transpileOptions.renamedDependencies);
}
const newLine = getNewLineCharacter(options);
// Output
let outputText: string;
let sourceMapText: string;
// Create a compilerHost object to allow the compiler to read and write files
const compilerHost: CompilerHost = {
getSourceFile: (fileName, target) => fileName === normalizePath(inputFileName) ? sourceFile : undefined,
writeFile: (name, text, writeByteOrderMark) => {
if (fileExtensionIs(name, ".map")) {
Debug.assert(sourceMapText === undefined, `Unexpected multiple source map outputs for the file '${name}'`);
sourceMapText = text;
}
else {
Debug.assert(outputText === undefined, `Unexpected multiple outputs for the file: '${name}'`);
outputText = text;
}
},
getDefaultLibFileName: () => "lib.d.ts",
useCaseSensitiveFileNames: () => false,
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: () => "",
getNewLine: () => newLine,
fileExists: (fileName): boolean => fileName === inputFileName,
readFile: (fileName): string => "",
directoryExists: directoryExists => true,
getDirectories: (path: string) => []
};
const program = createProgram([inputFileName], options, compilerHost);
if (transpileOptions.reportDiagnostics) {
addRange(/*to*/ diagnostics, /*from*/ program.getSyntacticDiagnostics(sourceFile));
addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics());
}
// Emit
program.emit();
Debug.assert(outputText !== undefined, "Output generation failed");
return { outputText, diagnostics, sourceMapText };
}
/*
* This is a shortcut function for transpileModule - it accepts transpileOptions as parameters and returns only outputText part of the result.
*/
export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string {
const output = transpileModule(input, { compilerOptions, fileName, reportDiagnostics: !!diagnostics, moduleName });
// addRange correctly handles cases when wither 'from' or 'to' argument is missing
addRange(diagnostics, output.diagnostics);
return output.outputText;
}
export function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean, scriptKind?: ScriptKind): SourceFile {
const text = scriptSnapshot.getText(0, scriptSnapshot.getLength());
const sourceFile = createSourceFile(fileName, text, scriptTarget, setNodeParents, scriptKind);
@ -1535,7 +2012,7 @@ namespace ts {
}
function initializeServices() {
objectAllocator = Allocators.getServicesObjectAllocator();
objectAllocator = getServicesObjectAllocator();
}
initializeServices();

View file

@ -85,7 +85,7 @@ namespace ts.SymbolDisplay {
// TODO(drosen): Currently completion entry details passes the SemanticMeaning.All instead of using semanticMeaning of location
export function getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker: TypeChecker, symbol: Symbol, sourceFile: SourceFile, enclosingDeclaration: Node,
location: Node, semanticMeaning = Meaning.getMeaningFromLocation(location)) {
location: Node, semanticMeaning = getMeaningFromLocation(location)) {
const displayParts: SymbolDisplayPart[] = [];
let documentation: SymbolDisplayPart[];
@ -229,7 +229,7 @@ namespace ts.SymbolDisplay {
addFullSymbolName(symbol);
writeTypeParametersOfSymbol(symbol, sourceFile);
}
if ((symbolFlags & SymbolFlags.Interface) && (semanticMeaning & Meaning.SemanticMeaning.Type)) {
if ((symbolFlags & SymbolFlags.Interface) && (semanticMeaning & SemanticMeaning.Type)) {
addNewLineIfDisplayPartsExist();
displayParts.push(keywordPart(SyntaxKind.InterfaceKeyword));
displayParts.push(spacePart());
@ -265,7 +265,7 @@ namespace ts.SymbolDisplay {
displayParts.push(spacePart());
addFullSymbolName(symbol);
}
if ((symbolFlags & SymbolFlags.TypeParameter) && (semanticMeaning & Meaning.SemanticMeaning.Type)) {
if ((symbolFlags & SymbolFlags.TypeParameter) && (semanticMeaning & SemanticMeaning.Type)) {
addNewLineIfDisplayPartsExist();
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
displayParts.push(textPart("type parameter"));

154
src/services/transpile.ts Normal file
View file

@ -0,0 +1,154 @@
namespace ts {
export interface TranspileOptions {
compilerOptions?: CompilerOptions;
fileName?: string;
reportDiagnostics?: boolean;
moduleName?: string;
renamedDependencies?: MapLike<string>;
}
export interface TranspileOutput {
outputText: string;
diagnostics?: Diagnostic[];
sourceMapText?: string;
}
/*
* This function will compile source text from 'input' argument using specified compiler options.
* If not options are provided - it will use a set of default compiler options.
* Extra compiler options that will unconditionally be used by this function are:
* - isolatedModules = true
* - allowNonTsExtensions = true
* - noLib = true
* - noResolve = true
*/
export function transpileModule(input: string, transpileOptions: TranspileOptions): TranspileOutput {
const diagnostics: Diagnostic[] = [];
const options: CompilerOptions = transpileOptions.compilerOptions ? fixupCompilerOptions(transpileOptions.compilerOptions, diagnostics) : getDefaultCompilerOptions();
options.isolatedModules = true;
// transpileModule does not write anything to disk so there is no need to verify that there are no conflicts between input and output paths.
options.suppressOutputPathCheck = true;
// Filename can be non-ts file.
options.allowNonTsExtensions = true;
// We are not returning a sourceFile for lib file when asked by the program,
// so pass --noLib to avoid reporting a file not found error.
options.noLib = true;
// Clear out other settings that would not be used in transpiling this module
options.lib = undefined;
options.types = undefined;
options.noEmit = undefined;
options.noEmitOnError = undefined;
options.paths = undefined;
options.rootDirs = undefined;
options.declaration = undefined;
options.declarationDir = undefined;
options.out = undefined;
options.outFile = undefined;
// We are not doing a full typecheck, we are not resolving the whole context,
// so pass --noResolve to avoid reporting missing file errors.
options.noResolve = true;
// if jsx is specified then treat file as .tsx
const inputFileName = transpileOptions.fileName || (options.jsx ? "module.tsx" : "module.ts");
const sourceFile = createSourceFile(inputFileName, input, options.target);
if (transpileOptions.moduleName) {
sourceFile.moduleName = transpileOptions.moduleName;
}
if (transpileOptions.renamedDependencies) {
sourceFile.renamedDependencies = createMap(transpileOptions.renamedDependencies);
}
const newLine = getNewLineCharacter(options);
// Output
let outputText: string;
let sourceMapText: string;
// Create a compilerHost object to allow the compiler to read and write files
const compilerHost: CompilerHost = {
getSourceFile: (fileName, target) => fileName === normalizePath(inputFileName) ? sourceFile : undefined,
writeFile: (name, text, writeByteOrderMark) => {
if (fileExtensionIs(name, ".map")) {
Debug.assert(sourceMapText === undefined, `Unexpected multiple source map outputs for the file '${name}'`);
sourceMapText = text;
}
else {
Debug.assert(outputText === undefined, `Unexpected multiple outputs for the file: '${name}'`);
outputText = text;
}
},
getDefaultLibFileName: () => "lib.d.ts",
useCaseSensitiveFileNames: () => false,
getCanonicalFileName: fileName => fileName,
getCurrentDirectory: () => "",
getNewLine: () => newLine,
fileExists: (fileName): boolean => fileName === inputFileName,
readFile: (fileName): string => "",
directoryExists: directoryExists => true,
getDirectories: (path: string) => []
};
const program = createProgram([inputFileName], options, compilerHost);
if (transpileOptions.reportDiagnostics) {
addRange(/*to*/ diagnostics, /*from*/ program.getSyntacticDiagnostics(sourceFile));
addRange(/*to*/ diagnostics, /*from*/ program.getOptionsDiagnostics());
}
// Emit
program.emit();
Debug.assert(outputText !== undefined, "Output generation failed");
return { outputText, diagnostics, sourceMapText };
}
/*
* This is a shortcut function for transpileModule - it accepts transpileOptions as parameters and returns only outputText part of the result.
*/
export function transpile(input: string, compilerOptions?: CompilerOptions, fileName?: string, diagnostics?: Diagnostic[], moduleName?: string): string {
const output = transpileModule(input, { compilerOptions, fileName, reportDiagnostics: !!diagnostics, moduleName });
// addRange correctly handles cases when wither 'from' or 'to' argument is missing
addRange(diagnostics, output.diagnostics);
return output.outputText;
}
let commandLineOptionsStringToEnum: CommandLineOptionOfCustomType[];
/** JS users may pass in string values for enum compiler options (such as ModuleKind), so convert. */
function fixupCompilerOptions(options: CompilerOptions, diagnostics: Diagnostic[]): CompilerOptions {
// Lazily create this value to fix module loading errors.
commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || <CommandLineOptionOfCustomType[]>filter(optionDeclarations, o =>
typeof o.type === "object" && !forEachProperty(o.type, v => typeof v !== "number"));
options = clone(options);
for (const opt of commandLineOptionsStringToEnum) {
if (!hasProperty(options, opt.name)) {
continue;
}
const value = options[opt.name];
// Value should be a key of opt.type
if (typeof value === "string") {
// If value is not a string, this will fail
options[opt.name] = parseCustomTypeOption(opt, value, diagnostics);
}
else {
if (!forEachProperty(opt.type, v => v === value)) {
// Supplied value isn't a valid enum value.
diagnostics.push(createCompilerDiagnosticForInvalidCustomType(opt));
}
}
}
return options;
}
}

View file

@ -42,7 +42,6 @@
"../compiler/diagnosticInformationMap.generated.ts",
"types.ts",
"utilities.ts",
"allocators.ts",
"breakpoints.ts",
"classifier.ts",
"completions.ts",
@ -51,7 +50,6 @@
"goToDefinition.ts",
"jsDoc.ts",
"jsTyping.ts",
"meaning.ts",
"navigateTo.ts",
"navigationBar.ts",
"outliningElementsCollector.ts",
@ -59,6 +57,7 @@
"preProcess.ts",
"rename.ts",
"services.ts",
"transpile.ts",
"shims.ts",
"signatureHelp.ts",
"symbolDisplay.ts",

View file

@ -4,6 +4,164 @@ namespace ts {
export const scanner: Scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);
export const emptyArray: any[] = [];
export const enum SemanticMeaning {
None = 0x0,
Value = 0x1,
Type = 0x2,
Namespace = 0x4,
All = Value | Type | Namespace
}
export function getMeaningFromDeclaration(node: Node): SemanticMeaning {
switch (node.kind) {
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.BindingElement:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.EnumMember:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.CatchClause:
return SemanticMeaning.Value;
case SyntaxKind.TypeParameter:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.TypeLiteral:
return SemanticMeaning.Type;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.EnumDeclaration:
return SemanticMeaning.Value | SemanticMeaning.Type;
case SyntaxKind.ModuleDeclaration:
if (isAmbientModule(<ModuleDeclaration>node)) {
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
else if (getModuleInstanceState(node) === ModuleInstanceState.Instantiated) {
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
else {
return SemanticMeaning.Namespace;
}
case SyntaxKind.NamedImports:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ImportEqualsDeclaration:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ExportAssignment:
case SyntaxKind.ExportDeclaration:
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
// An external module can be a Value
case SyntaxKind.SourceFile:
return SemanticMeaning.Namespace | SemanticMeaning.Value;
}
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
}
export function getMeaningFromLocation(node: Node): SemanticMeaning {
if (node.parent.kind === SyntaxKind.ExportAssignment) {
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
}
else if (isInRightSideOfImport(node)) {
return getMeaningFromRightHandSideOfImportEquals(node);
}
else if (isDeclarationName(node)) {
return getMeaningFromDeclaration(node.parent);
}
else if (isTypeReference(node)) {
return SemanticMeaning.Type;
}
else if (isNamespaceReference(node)) {
return SemanticMeaning.Namespace;
}
else {
return SemanticMeaning.Value;
}
}
function getMeaningFromRightHandSideOfImportEquals(node: Node) {
Debug.assert(node.kind === SyntaxKind.Identifier);
// import a = |b|; // Namespace
// import a = |b.c|; // Value, type, namespace
// import a = |b.c|.d; // Namespace
if (node.parent.kind === SyntaxKind.QualifiedName &&
(<QualifiedName>node.parent).right === node &&
node.parent.parent.kind === SyntaxKind.ImportEqualsDeclaration) {
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
}
return SemanticMeaning.Namespace;
}
function isInRightSideOfImport(node: Node) {
while (node.parent.kind === SyntaxKind.QualifiedName) {
node = node.parent;
}
return isInternalModuleImportEqualsDeclaration(node.parent) && (<ImportEqualsDeclaration>node.parent).moduleReference === node;
}
function isNamespaceReference(node: Node): boolean {
return isQualifiedNameNamespaceReference(node) || isPropertyAccessNamespaceReference(node);
}
function isQualifiedNameNamespaceReference(node: Node): boolean {
let root = node;
let isLastClause = true;
if (root.parent.kind === SyntaxKind.QualifiedName) {
while (root.parent && root.parent.kind === SyntaxKind.QualifiedName) {
root = root.parent;
}
isLastClause = (<QualifiedName>root).right === node;
}
return root.parent.kind === SyntaxKind.TypeReference && !isLastClause;
}
function isPropertyAccessNamespaceReference(node: Node): boolean {
let root = node;
let isLastClause = true;
if (root.parent.kind === SyntaxKind.PropertyAccessExpression) {
while (root.parent && root.parent.kind === SyntaxKind.PropertyAccessExpression) {
root = root.parent;
}
isLastClause = (<PropertyAccessExpression>root).name === node;
}
if (!isLastClause && root.parent.kind === SyntaxKind.ExpressionWithTypeArguments && root.parent.parent.kind === SyntaxKind.HeritageClause) {
const decl = root.parent.parent.parent;
return (decl.kind === SyntaxKind.ClassDeclaration && (<HeritageClause>root.parent.parent).token === SyntaxKind.ImplementsKeyword) ||
(decl.kind === SyntaxKind.InterfaceDeclaration && (<HeritageClause>root.parent.parent).token === SyntaxKind.ExtendsKeyword);
}
return false;
}
function isTypeReference(node: Node): boolean {
if (isRightSideOfQualifiedNameOrPropertyAccess(node)) {
node = node.parent;
}
return node.parent.kind === SyntaxKind.TypeReference ||
(node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent)) ||
(node.kind === SyntaxKind.ThisKeyword && !isPartOfExpression(node)) ||
node.kind === SyntaxKind.ThisType;
}
export function isCallExpressionTarget(node: Node): boolean {
return isCallOrNewExpressionTarget(node, SyntaxKind.CallExpression);
}