Emit unexported aliases that need to be emitted to .d.ts to make correct result

This commit is contained in:
Sheetal Nandi 2014-08-04 17:59:33 -07:00
parent 0b227d5196
commit 875d0c0c75
3 changed files with 101 additions and 24 deletions

View File

@ -726,6 +726,7 @@ module ts {
}
function isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessiblityResult {
var aliasesToMakeVisible: ImportDeclaration[];
if (symbol && enclosingDeclaration && !(symbol.flags & SymbolFlags.TypeParameter)) {
var initialSymbol = symbol;
var meaningToLook = meaning;
@ -733,14 +734,14 @@ module ts {
// Symbol is accessible if it by itself is accessible
var accessibleSymbol = getAccessibleSymbol(symbol, enclosingDeclaration, meaningToLook);
if (accessibleSymbol) {
if (forEach(accessibleSymbol.declarations, declaration => !isDeclarationVisible(declaration))) {
if (forEach(accessibleSymbol.declarations, declaration => !getIsDeclarationVisible(declaration))) {
return {
accessibility: SymbolAccessibility.NotAccessible,
errorSymbolName: symbolToString(initialSymbol, enclosingDeclaration, meaning),
errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined
errorModuleName: symbol !== initialSymbol ? symbolToString(symbol, enclosingDeclaration, SymbolFlags.Namespace) : undefined,
};
}
return { accessibility: SymbolAccessibility.Accessible };
return { accessibility: SymbolAccessibility.Accessible, aliasesToMakeVisible: aliasesToMakeVisible };
}
// TODO(shkamat): Handle static method of class
@ -769,6 +770,32 @@ module ts {
}
return { accessibility: SymbolAccessibility.Accessible };
function getIsDeclarationVisible(declaration: Declaration) {
if (!isDeclarationVisible(declaration)) {
// Mark the unexported alias as visible if its parent is visible
// because these kind of aliases can be used to name types in declaration file
if (declaration.kind === SyntaxKind.ImportDeclaration &&
!(declaration.flags & NodeFlags.Export) &&
isDeclarationVisible(declaration.parent)) {
getNodeLinks(declaration).isVisible = true;
if (aliasesToMakeVisible) {
if (!contains(aliasesToMakeVisible, declaration)) {
aliasesToMakeVisible.push(declaration);
}
}
else {
aliasesToMakeVisible = [declaration];
}
return true;
}
// Declaration is not visible
return false;
}
return true;
}
}
// Enclosing declaration is optional when we dont want to get qualified name in the enclosing declaration scope
@ -1091,7 +1118,6 @@ module ts {
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ImportDeclaration:
if (!(node.flags & NodeFlags.Export)) {
// TODO(shkamat): non exported aliases can be visible if they are referenced else where for value/type/namespace
return isGlobalSourceFile(node.parent) || isUsedInExportAssignment(node);
}
// Exported members are visible if parent is visible
@ -1125,7 +1151,7 @@ module ts {
if (node) {
var links = getNodeLinks(node);
if (links.isVisible === undefined) {
links.isVisible = determineIfDeclarationIsVisible();
links.isVisible = !!determineIfDeclarationIsVisible();
}
return links.isVisible;
}

View File

@ -9,6 +9,7 @@ module ts {
getTextPos(): number;
getLine(): number;
getColumn(): number;
getIndent(): number;
}
var indentStrings: string[] = [];
@ -141,6 +142,7 @@ module ts {
writeLine: writeLine,
increaseIndent: () => indent++,
decreaseIndent: () => indent--,
getIndent: () => indent,
getTextPos: () => output.length,
getLine: () => lineCount + 1,
getColumn: () => lineStart ? indent * 4 + 1 : output.length - linePos + 1,
@ -1867,6 +1869,13 @@ module ts {
var enclosingDeclaration: Node;
var reportedDeclarationError = false;
var aliasDeclarationEmitInfo: {
declaration: ImportDeclaration;
outputPos: number;
indent: number;
asynchronousOutput?: string; // If the output for alias was written asynchronously, the corresponding output
}[] = [];
var getSymbolVisibilityDiagnosticMessage: (symbolAccesibilityResult: SymbolAccessiblityResult) => {
errorNode: Node;
diagnosticMessage: DiagnosticMessage;
@ -1875,9 +1884,25 @@ module ts {
function writeSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) {
var symbolAccesibilityResult = resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning);
// TODO(shkamat): Since we dont have error reporting for all the cases as yet we have this check on handler being present
// TODO(shkamat): Since we dont have error reporting for all the cases as yet we have this check on handler being present
if (!getSymbolVisibilityDiagnosticMessage || symbolAccesibilityResult.accessibility === SymbolAccessibility.Accessible) {
resolver.writeSymbol(symbol, enclosingDeclaration, meaning, writer);
// write the aliases
if (symbolAccesibilityResult && symbolAccesibilityResult.aliasesToMakeVisible) {
var oldWriter = writer;
forEach(symbolAccesibilityResult.aliasesToMakeVisible.sort(), aliasToWrite => {
var aliasEmitInfo = forEach(aliasDeclarationEmitInfo, declEmitInfo => declEmitInfo.declaration === aliasToWrite ? declEmitInfo : undefined);
writer = createTextWriter(writeSymbol);
for (var declarationIndent = aliasEmitInfo.indent; declarationIndent; declarationIndent--) {
writer.increaseIndent();
}
writeImportDeclaration(aliasToWrite);
aliasEmitInfo.asynchronousOutput = writer.getText();
});
writer = oldWriter;
}
}
else {
// Report error
@ -1951,26 +1976,39 @@ module ts {
}
function emitImportDeclaration(node: ImportDeclaration) {
if (resolver.isDeclarationVisible(node)) {
if (node.flags & NodeFlags.Export) {
write("export ");
}
write("import ");
emitSourceTextOfNode(node.name);
write(" = ");
if (node.entityName) {
emitSourceTextOfNode(node.entityName);
write(";");
}
else {
write("require(");
emitSourceTextOfNode(node.externalModuleName);
write(");");
}
writeLine();
var nodeEmitInfo = {
declaration: node,
outputPos: writer.getTextPos(),
indent: writer.getIndent(),
hasWritten: resolver.isDeclarationVisible(node)
};
aliasDeclarationEmitInfo.push(nodeEmitInfo);
if (nodeEmitInfo.hasWritten) {
writeImportDeclaration(node);
}
}
function writeImportDeclaration(node: ImportDeclaration) {
// note usage of writer. methods instead of aliases created, just to make sure we are using
// correct writer especially to handle asynchronous alias writing
if (node.flags & NodeFlags.Export) {
writer.write("export ");
}
writer.write("import ");
writer.write(getSourceTextOfLocalNode(node.name));
writer.write(" = ");
if (node.entityName) {
writer.write(getSourceTextOfLocalNode(node.entityName));
writer.write(";");
}
else {
writer.write("require(");
writer.write(getSourceTextOfLocalNode(node.externalModuleName));
writer.write(");");
}
writer.writeLine();
}
function emitModuleDeclaration(node: ModuleDeclaration) {
if (resolver.isDeclarationVisible(node)) {
emitDeclarationFlags(node);
@ -2484,7 +2522,19 @@ module ts {
// TODO(shkamat): Should we not write any declaration file if any of them can produce error,
// or should we just not write this file like we are doing now
if (!reportedDeclarationError) {
writeFile(getModuleNameFromFilename(jsFilePath) + ".d.ts", referencePathsOutput + writer.getText());
var declarationOutput = referencePathsOutput;
var synchronousDeclarationOutput = writer.getText();
// apply additions
var appliedSyncOutputPos = 0;
forEach(aliasDeclarationEmitInfo, aliasEmitInfo => {
if (aliasEmitInfo.asynchronousOutput) {
declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos, aliasEmitInfo.outputPos);
declarationOutput += aliasEmitInfo.asynchronousOutput;
appliedSyncOutputPos = aliasEmitInfo.outputPos;
}
});
declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos);
writeFile(getModuleNameFromFilename(jsFilePath) + ".d.ts", declarationOutput);
}
}

View File

@ -638,6 +638,7 @@ module ts {
accessibility: SymbolAccessibility;
errorSymbolName?: string // Optional symbol name that results in error
errorModuleName?: string // If the symbol is not visibile from module, module's name
aliasesToMakeVisible?: ImportDeclaration[]; // aliases that need to have this symbol visible
}
export interface EmitResolver {