Properly support string-literal property names and escape external module names.

This commit is contained in:
Daniel Rosenwasser
2014-09-25 13:10:04 -07:00
parent 1e884a96e9
commit a98cca7723
6 changed files with 113 additions and 40 deletions

View File

@@ -535,6 +535,29 @@ module ts {
return path;
}
var escapedCharsRegExp = /[\t\v\f\b\0\r\n\"\\\u2028\u2029\u0085]/g;
var escapedCharsMap: Map<string> = {
"\t": "\\t",
"\v": "\\v",
"\f": "\\f",
"\b": "\\b",
"\0": "\\0",
"\r": "\\r",
"\n": "\\n",
"\"": "\\\"",
"\u2028": "\\u2028", // lineSeparator
"\u2029": "\\u2029", // paragraphSeparator
"\u0085": "\\u0085" // nextLine
};
/** NOTE: This *does not* support the full escape characters, it only supports the subset that can be used in file names
* or string literals. If the information encoded in the map changes, this needs to be revisited. */
export function escapeString(s: string): string {
return escapedCharsRegExp.test(s) ? s.replace(escapedCharsRegExp, c => {
return escapedCharsMap[c] || c;
}) : s;
}
export interface ObjectAllocator {
getNodeConstructor(kind: SyntaxKind): new () => Node;
getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol;

View File

@@ -591,21 +591,6 @@ module ts {
recordSourceMapSpan(comment.end);
}
var escapedCharsRegExp = /[\t\v\f\b\0\r\n\"\u2028\u2029\u0085]/g;
var escapedCharsMap: Map<string> = {
"\t": "\\t",
"\v": "\\v",
"\f": "\\f",
"\b": "\\b",
"\0": "\\0",
"\r": "\\r",
"\n": "\\n",
"\"": "\\\"",
"\u2028": "\\u2028", // lineSeparator
"\u2029": "\\u2029", // paragraphSeparator
"\u0085": "\\u0085" // nextLine
};
function serializeSourceMapContents(version: number, file: string, sourceRoot: string, sources: string[], names: string[], mappings: string) {
if (typeof JSON !== "undefined") {
return JSON.stringify({
@@ -620,14 +605,6 @@ module ts {
return "{\"version\":" + version + ",\"file\":\"" + escapeString(file) + "\",\"sourceRoot\":\"" + escapeString(sourceRoot) + "\",\"sources\":[" + serializeStringArray(sources) + "],\"names\":[" + serializeStringArray(names) + "],\"mappings\":\"" + escapeString(mappings) + "\"}";
/** This does not support the full escape characters, it only supports the subset that can be used in file names
* or string literals. If the information encoded in the map changes, this needs to be revisited. */
function escapeString(s: string): string {
return escapedCharsRegExp.test(s) ? s.replace(escapedCharsRegExp, c => {
return escapedCharsMap[c] || c;
}) : s;
}
function serializeStringArray(list: string[]): string {
var output = "";
for (var i = 0, n = list.length; i < n; i++) {

View File

@@ -151,23 +151,23 @@ module ts {
return basicChildItem(node, parameter.name.text, ts.ScriptElementKind.memberVariableElement);
case SyntaxKind.Method:
var memberFunction = <MethodDeclaration>node;
return basicChildItem(node, memberFunction.name.text, ts.ScriptElementKind.memberFunctionElement);
var method = <MethodDeclaration>node;
return basicChildItem(node, getPropertyText(method.name), ts.ScriptElementKind.memberFunctionElement);
case SyntaxKind.GetAccessor:
var getAccessor = <AccessorDeclaration>node;
return basicChildItem(node, getAccessor.name.text, ts.ScriptElementKind.memberGetAccessorElement);
return basicChildItem(node, getPropertyText(getAccessor.name), ts.ScriptElementKind.memberGetAccessorElement);
case SyntaxKind.SetAccessor:
var setAccessor = <AccessorDeclaration>node;
return basicChildItem(node, setAccessor.name.text, ts.ScriptElementKind.memberSetAccessorElement);
return basicChildItem(node, getPropertyText(setAccessor.name), ts.ScriptElementKind.memberSetAccessorElement);
case SyntaxKind.IndexSignature:
return basicChildItem(node, "[]", ts.ScriptElementKind.indexSignatureElement);
case SyntaxKind.EnumMember:
var enumElement = <EnumMember>node;
return basicChildItem(node, enumElement.name.text, ts.ScriptElementKind.memberVariableElement);
var enumMember = <EnumMember>node;
return basicChildItem(node, getPropertyText(enumMember.name), ts.ScriptElementKind.memberVariableElement);
case SyntaxKind.CallSignature:
return basicChildItem(node, "()", ts.ScriptElementKind.callSignatureElement);
@@ -176,8 +176,8 @@ module ts {
return basicChildItem(node, "new()", ts.ScriptElementKind.constructSignatureElement);
case SyntaxKind.Property:
var propertySignature = <PropertyDeclaration>node;
return basicChildItem(node, propertySignature.name.text, ts.ScriptElementKind.memberVariableElement);
var property = <PropertyDeclaration>node;
return basicChildItem(node, getPropertyText(property.name), ts.ScriptElementKind.memberVariableElement);
case SyntaxKind.FunctionDeclaration:
var functionDeclaration = <FunctionDeclaration>node;
@@ -224,13 +224,13 @@ module ts {
return undefined;
function getModuleNames(moduleDeclaration: ModuleDeclaration): string[]{
function getModuleName(moduleDeclaration: ModuleDeclaration): string {
// We want to maintain quotation marks.
if (moduleDeclaration.name.kind === SyntaxKind.StringLiteral) {
return [getSourceTextOfNode(moduleDeclaration.name)];
return getPropertyText(moduleDeclaration.name);
}
// Otherwise, we need to aggregate each identifier of the qualified name.
// Otherwise, we need to aggregate each identifier to build up the qualified name.
var result: string[] = [];
result.push(moduleDeclaration.name.text);
@@ -241,15 +241,15 @@ module ts {
result.push(moduleDeclaration.name.text);
}
return result;
return result.join(".");
}
function createModuleItem(node: ModuleDeclaration): NavigationBarItem {
var moduleNames = getModuleNames(node);
var moduleName = getModuleName(node);
var childItems = getItemsWorker(getChildNodes((<Block>getInnermostModule(node).body).statements), createChildItem);
return new ts.NavigationBarItem(moduleNames.join("."),
return new ts.NavigationBarItem(moduleName,
ts.ScriptElementKind.moduleElement,
getNodeModifiers(node),
[getNodeSpan(node)],
@@ -281,7 +281,7 @@ module ts {
hasGlobalNode = true;
var rootName = isExternalModule(node) ?
"\"" + getBaseFilename(removeFileExtension(normalizePath(node.filename))) + "\"" :
"\"" + escapeString(getBaseFilename(removeFileExtension(normalizePath(node.filename)))) + "\"" :
"<global>"
return new ts.NavigationBarItem(rootName,
@@ -340,7 +340,6 @@ module ts {
}
function getInnermostModule(node: ModuleDeclaration): ModuleDeclaration {
while (node.body.kind === SyntaxKind.ModuleDeclaration) {
node = <ModuleDeclaration>node.body;
}
@@ -351,5 +350,24 @@ module ts {
function getNodeSpan(node: Node) {
return TypeScript.TextSpan.fromBounds(node.getStart(), node.getEnd());
}
function getPropertyText(node: Node): string {
if (node.kind === SyntaxKind.Identifier) {
return (<Identifier>node).text;
}
if (node.kind === SyntaxKind.StringLiteral) {
// normalize the quotes and remove all '\{newline}'s from the original text.
var text = getSourceTextOfNodeFromSourceText(sourceFile.text, node);
text = text.substring(1, text.length - 1).replace(/\\\r?\n/g, "");
return "\"" + text + "\"";
}
if (node.kind === SyntaxKind.NumericLiteral) {
return (<LiteralExpression>node).text;
}
Debug.fail("getPropertyText given a property that is neither an identifier nor a literal expression.");
}
}
}