JS: rewrite source map generator to use specialized JSON writer

Fixes problems with string escaping. See KT-20005
This commit is contained in:
Alexey Andreev
2017-09-05 16:23:22 +03:00
committed by Alexey Andreev
parent 187ca71dc6
commit 361d6dfca0
7 changed files with 48 additions and 39 deletions
+7
View File
@@ -0,0 +1,7 @@
$TESTDATA_DIR$/sourceMapCharEscape.kt
-no-stdlib
-source-map
-source-map-embed-sources
always
-output
$TEMP_DIR$/out.js
+1
View File
@@ -0,0 +1 @@
fun foo() = "©∑\n"
+1
View File
@@ -0,0 +1 @@
OK
+2
View File
@@ -0,0 +1,2 @@
// EXISTS: out.js
// CONTAINS: out.js.map, \"©∑\\n\"\n
@@ -545,6 +545,12 @@ public class CliTestGenerated extends AbstractCliTest {
doJsTest(fileName); doJsTest(fileName);
} }
@TestMetadata("sourceMapCharEscape.args")
public void testSourceMapCharEscape() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/js/sourceMapCharEscape.args");
doJsTest(fileName);
}
@TestMetadata("sourceMapDuplicateRelativePaths.args") @TestMetadata("sourceMapDuplicateRelativePaths.args")
public void testSourceMapDuplicateRelativePaths() throws Exception { public void testSourceMapDuplicateRelativePaths() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/js/sourceMapDuplicateRelativePaths.args"); String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/cli/js/sourceMapDuplicateRelativePaths.args");
+1
View File
@@ -15,5 +15,6 @@
<orderEntry type="module" module-name="js.parser" /> <orderEntry type="module" module-name="js.parser" />
<orderEntry type="module" module-name="js.serializer" /> <orderEntry type="module" module-name="js.serializer" />
<orderEntry type="module" module-name="util" /> <orderEntry type="module" module-name="util" />
<orderEntry type="library" name="json-org" level="project" />
</component> </component>
</module> </module>
@@ -21,11 +21,13 @@ import gnu.trove.TObjectIntHashMap;
import kotlin.io.TextStreamsKt; import kotlin.io.TextStreamsKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor;
import org.jetbrains.kotlin.js.util.TextOutput; import org.jetbrains.kotlin.js.util.TextOutput;
import org.json.JSONWriter;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -70,55 +72,44 @@ public class SourceMap3Builder implements SourceMapBuilder {
@Override @Override
public String build() { public String build() {
StringBuilder sb = new StringBuilder(out.length() + (128 * orderedSources.size())); try {
sb.append("{\"version\":3,\"file\":\"").append(generatedFile.getName()).append('"').append(','); StringWriter stringWriter = new StringWriter();
JSONWriter writer = new JSONWriter(stringWriter);
writer.object();
writer.key("version").value(3);
writer.key("file").value(generatedFile.getName());
appendSources(sb); appendSources(writer);
sb.append(","); appendSourcesContent(writer);
appendSourcesContent(sb);
sb.append(",\"names\":["); writer.key("names").array().endArray();
sb.append("],\"mappings\":\""); writer.key("mappings").value(out.toString());
sb.append(out);
sb.append("\"}"); writer.endObject();
return sb.toString(); stringWriter.close();
return stringWriter.toString();
}
catch (IOException e) {
throw new AssertionError("This exception should have not been thrown from StringWriter", e);
}
} }
private void appendSources(StringBuilder sb) { private void appendSources(JSONWriter writer) {
boolean isNotFirst = false; writer.key("sources").array();
sb.append('"').append("sources").append("\":[");
for (String source : orderedSources) { for (String source : orderedSources) {
if (isNotFirst) { writer.value(pathPrefix + source);
sb.append(',');
}
else {
isNotFirst = true;
}
sb.append(JsToStringGenerationVisitor.javaScriptString(pathPrefix + source, true));
} }
sb.append(']'); writer.endArray();
} }
private void appendSourcesContent(StringBuilder sb) { private void appendSourcesContent(JSONWriter writer) {
boolean isNotFirst = false; writer.key("sourcesContent").array();
sb.append('"').append("sourcesContent").append("\":[");
for (Supplier<Reader> contentSupplier : orderedSourceContentSuppliers) { for (Supplier<Reader> contentSupplier : orderedSourceContentSuppliers) {
if (isNotFirst) {
sb.append(',');
}
else {
isNotFirst = true;
}
Reader reader = contentSupplier.get(); Reader reader = contentSupplier.get();
if (reader != null) { writer.value(reader != null ? TextStreamsKt.readText(reader) : null);
sb.append(JsToStringGenerationVisitor.javaScriptString(TextStreamsKt.readText(reader), true));
}
else {
sb.append("null");
}
} }
sb.append(']'); writer.endArray();
} }
@Override @Override