JS: Remove code path for TypeScript full extraction

This commit is contained in:
Asger F
2025-06-24 17:16:06 +02:00
parent 8efa38be79
commit 74b817b642
9 changed files with 51 additions and 2753 deletions

View File

@@ -51,10 +51,8 @@ import com.semmle.js.extractor.trapcache.DummyTrapCache;
import com.semmle.js.extractor.trapcache.ITrapCache;
import com.semmle.js.parser.ParseError;
import com.semmle.js.parser.ParsedProject;
import com.semmle.ts.extractor.TypeExtractor;
import com.semmle.ts.extractor.TypeScriptParser;
import com.semmle.ts.extractor.TypeScriptWrapperOOMError;
import com.semmle.ts.extractor.TypeTable;
import com.semmle.util.data.StringUtil;
import com.semmle.util.diagnostic.DiagnosticLevel;
import com.semmle.util.diagnostic.DiagnosticLocation;
@@ -1065,75 +1063,26 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path>
FileExtractors extractors,
List<Path> tsconfig,
DependencyInstallationResult deps) {
if (hasTypeScriptFiles(files) || !tsconfig.isEmpty()) {
List<Path> typeScriptFiles = new ArrayList<>();
// Get all TypeScript files.
for (Path f : files) {
if (extractors.fileType(f) == FileType.TYPESCRIPT) {
typeScriptFiles.add(f);
}
}
// Also get TypeScript files from HTML file snippets.
for (Map.Entry<Path, FileSnippet> entry : state.getSnippets().entrySet()) {
if (!extractedFiles.contains(entry.getKey())
&& FileType.forFileExtension(entry.getKey().toFile()) == FileType.TYPESCRIPT) {
typeScriptFiles.add(entry.getKey());
}
}
if (!typeScriptFiles.isEmpty()) {
TypeScriptParser tsParser = state.getTypeScriptParser();
verifyTypeScriptInstallation(state);
// Collect all files included in a tsconfig.json inclusion pattern.
// If a given file is referenced by multiple tsconfig files, we prefer to extract it using
// one that includes it rather than just references it.
Set<File> explicitlyIncludedFiles = new LinkedHashSet<>();
if (tsconfig.size() > 1) { // No prioritization needed if there's only one tsconfig.
for (Path projectPath : tsconfig) {
explicitlyIncludedFiles.addAll(tsParser.getOwnFiles(projectPath.toFile(), deps, virtualSourceRoot));
}
}
// Extract TypeScript projects
for (Path projectPath : tsconfig) {
File projectFile = projectPath.toFile();
long start = logBeginProcess("Opening project " + projectFile);
ParsedProject project = tsParser.openProject(projectFile, deps, virtualSourceRoot);
logEndProcess(start, "Done opening project " + projectFile);
// Extract all files belonging to this project which are also matched
// by our include/exclude filters.
List<Path> typeScriptFiles = new ArrayList<Path>();
for (File sourceFile : project.getAllFiles()) {
Path sourcePath = sourceFile.toPath();
Path normalizedFile = normalizePath(sourcePath);
if (!files.contains(normalizedFile) && !state.getSnippets().containsKey(normalizedFile)) {
continue;
}
if (!project.getOwnFiles().contains(sourceFile) && explicitlyIncludedFiles.contains(sourceFile)) continue;
if (extractors.fileType(sourcePath) != FileType.TYPESCRIPT) {
// For the time being, skip non-TypeScript files, even if the TypeScript
// compiler can parse them for us.
continue;
}
if (extractedFiles.contains(sourcePath)) {
continue;
}
typeScriptFiles.add(sourcePath);
}
typeScriptFiles.sort(PATH_ORDERING);
extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractors);
tsParser.closeProject(projectFile);
}
// Extract all the types discovered when extracting the ASTs.
if (!tsconfig.isEmpty()) {
TypeTable typeTable = tsParser.getTypeTable();
extractTypeTable(tsconfig.iterator().next(), typeTable);
}
// Extract remaining TypeScript files.
List<Path> remainingTypeScriptFiles = new ArrayList<>();
for (Path f : files) {
if (!extractedFiles.contains(f)
&& extractors.fileType(f) == FileType.TYPESCRIPT) {
remainingTypeScriptFiles.add(f);
}
}
for (Map.Entry<Path, FileSnippet> entry : state.getSnippets().entrySet()) {
if (!extractedFiles.contains(entry.getKey())
&& FileType.forFileExtension(entry.getKey().toFile()) == FileType.TYPESCRIPT) {
remainingTypeScriptFiles.add(entry.getKey());
}
}
if (!remainingTypeScriptFiles.isEmpty()) {
extractTypeScriptFiles(remainingTypeScriptFiles, extractedFiles, extractors);
}
extractTypeScriptFiles(typeScriptFiles, extractedFiles, extractors);
// The TypeScript compiler instance is no longer needed.
tsParser.killProcess();
}
@@ -1246,18 +1195,6 @@ protected DependencyInstallationResult preparePackagesAndDependencies(Set<Path>
return path.toAbsolutePath().normalize();
}
private void extractTypeTable(Path fileHandle, TypeTable table) {
TrapWriter trapWriter =
outputConfig
.getTrapWriterFactory()
.mkTrapWriter(new File(fileHandle.toString() + ".codeql-typescript-typetable"));
try {
new TypeExtractor(trapWriter, table).extract();
} finally {
FileUtil.close(trapWriter);
}
}
/**
* Get the source type specified in <code>LGTM_INDEX_SOURCE_TYPE</code>, or the default of {@link
* SourceType#AUTO}.

View File

@@ -18,9 +18,7 @@ import com.semmle.js.extractor.ExtractorConfig.SourceType;
import com.semmle.js.extractor.FileExtractor.FileType;
import com.semmle.js.extractor.trapcache.ITrapCache;
import com.semmle.js.parser.ParsedProject;
import com.semmle.ts.extractor.TypeExtractor;
import com.semmle.ts.extractor.TypeScriptParser;
import com.semmle.ts.extractor.TypeTable;
import com.semmle.util.data.StringUtil;
import com.semmle.util.data.UnitParser;
import com.semmle.util.exception.ResourceError;
@@ -142,53 +140,22 @@ public class Main {
tsParser.verifyInstallation(!ap.has(P_QUIET));
}
for (File projectFile : projectFiles) {
long start = verboseLogStartTimer(ap, "Opening project " + projectFile);
ParsedProject project = tsParser.openProject(projectFile, DependencyInstallationResult.empty, extractorConfig.getVirtualSourceRoot());
verboseLogEndTimer(ap, start);
// Extract all files belonging to this project which are also matched
// by our include/exclude filters.
List<File> filesToExtract = new ArrayList<>();
for (File sourceFile : project.getOwnFiles()) {
File normalizedFile = normalizeFile(sourceFile);
if ((files.contains(normalizedFile) || extractorState.getSnippets().containsKey(normalizedFile.toPath()))
&& !extractedFiles.contains(sourceFile.getAbsoluteFile())
&& FileType.TYPESCRIPT.getExtensions().contains(FileUtil.extension(sourceFile))) {
filesToExtract.add(sourceFile);
}
}
tsParser.prepareFiles(filesToExtract);
for (int i = 0; i < filesToExtract.size(); ++i) {
ensureFileIsExtracted(filesToExtract.get(i), ap);
}
// Close the project to free memory. This does not need to be in a `finally` as
// the project is not a system resource.
tsParser.closeProject(projectFile);
}
if (!projectFiles.isEmpty()) {
// Extract all the types discovered when extracting the ASTs.
TypeTable typeTable = tsParser.getTypeTable();
extractTypeTable(projectFiles.iterator().next(), typeTable);
}
List<File> remainingTypescriptFiles = new ArrayList<>();
List<File> typeScriptFiles = new ArrayList<>();
for (File f : files) {
if (!extractedFiles.contains(f.getAbsoluteFile())
&& FileType.forFileExtension(f) == FileType.TYPESCRIPT) {
remainingTypescriptFiles.add(f);
typeScriptFiles.add(f);
}
}
for (Map.Entry<Path, FileSnippet> entry : extractorState.getSnippets().entrySet()) {
if (!extractedFiles.contains(entry.getKey().toFile())
&& FileType.forFileExtension(entry.getKey().toFile()) == FileType.TYPESCRIPT) {
remainingTypescriptFiles.add(entry.getKey().toFile());
typeScriptFiles.add(entry.getKey().toFile());
}
}
if (!remainingTypescriptFiles.isEmpty()) {
tsParser.prepareFiles(remainingTypescriptFiles);
for (File f : remainingTypescriptFiles) {
if (!typeScriptFiles.isEmpty()) {
tsParser.prepareFiles(typeScriptFiles);
for (File f : typeScriptFiles) {
ensureFileIsExtracted(f, ap);
}
}
@@ -225,21 +192,6 @@ public class Main {
return false;
}
private void extractTypeTable(File fileHandle, TypeTable table) {
TrapWriter trapWriter =
extractorOutputConfig
.getTrapWriterFactory()
.mkTrapWriter(
new File(
fileHandle.getParentFile(),
fileHandle.getName() + ".codeql-typescript-typetable"));
try {
new TypeExtractor(trapWriter, table).extract();
} finally {
FileUtil.close(trapWriter);
}
}
private void ensureFileIsExtracted(File f, ArgsParser ap) {
if (!extractedFiles.add(f.getAbsoluteFile())) {
// The file has already been extracted as part of a project.

View File

@@ -1,330 +0,0 @@
package com.semmle.ts.extractor;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.semmle.util.trap.TrapWriter;
import com.semmle.util.trap.TrapWriter.Label;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Extracts type and symbol information into TRAP files.
*
* <p>This is closely coupled with the <code>type_table.ts</code> file in the parser-wrapper. Type
* strings and symbol strings generated in that file are parsed here. See that file for reference
* and documentation.
*/
public class TypeExtractor {
private final TrapWriter trapWriter;
private final TypeTable table;
private static final Map<String, Integer> tagToKind = new LinkedHashMap<String, Integer>();
private static final int referenceKind = 6;
private static final int objectKind = 7;
private static final int typevarKind = 8;
private static final int typeofKind = 9;
private static final int uniqueSymbolKind = 15;
private static final int tupleKind = 18;
private static final int lexicalTypevarKind = 19;
private static final int thisKind = 20;
private static final int numberLiteralTypeKind = 21;
private static final int stringLiteralTypeKind = 22;
private static final int bigintLiteralTypeKind = 25;
static {
tagToKind.put("any", 0);
tagToKind.put("string", 1);
tagToKind.put("number", 2);
tagToKind.put("union", 3);
tagToKind.put("true", 4);
tagToKind.put("false", 5);
tagToKind.put("reference", referenceKind);
tagToKind.put("object", objectKind);
tagToKind.put("typevar", typevarKind);
tagToKind.put("typeof", typeofKind);
tagToKind.put("void", 10);
tagToKind.put("undefined", 11);
tagToKind.put("null", 12);
tagToKind.put("never", 13);
tagToKind.put("plainsymbol", 14);
tagToKind.put("uniquesymbol", uniqueSymbolKind);
tagToKind.put("objectkeyword", 16);
tagToKind.put("intersection", 17);
tagToKind.put("tuple", tupleKind);
tagToKind.put("lextypevar", lexicalTypevarKind);
tagToKind.put("this", thisKind);
tagToKind.put("numlit", numberLiteralTypeKind);
tagToKind.put("strlit", stringLiteralTypeKind);
tagToKind.put("unknown", 23);
tagToKind.put("bigint", 24);
tagToKind.put("bigintlit", bigintLiteralTypeKind);
}
private static final Map<String, Integer> symbolKind = new LinkedHashMap<String, Integer>();
static {
symbolKind.put("root", 0);
symbolKind.put("member", 1);
symbolKind.put("other", 2);
}
public TypeExtractor(TrapWriter trapWriter, TypeTable table) {
this.trapWriter = trapWriter;
this.table = table;
}
public void extract() {
for (int i = 0; i < table.getNumberOfTypes(); ++i) {
extractType(i);
}
extractPropertyLookups(table.getPropertyLookups());
extractTypeAliases(table.getTypeAliases());
for (int i = 0; i < table.getNumberOfSymbols(); ++i) {
extractSymbol(i);
}
extractSymbolNameMapping("symbol_module", table.getModuleMappings());
extractSymbolNameMapping("symbol_global", table.getGlobalMappings());
extractSignatureMappings(table.getSignatureMappings());
for (int i = 0; i < table.getNumberOfSignatures(); ++i) {
extractSignature(i);
}
extractIndexTypeTable(table.getNumberIndexTypes(), "number_index_type");
extractIndexTypeTable(table.getStringIndexTypes(), "string_index_type");
extractBaseTypes(table.getBaseTypes());
extractSelfTypes(table.getSelfTypes());
}
private void extractType(int id) {
Label lbl = trapWriter.globalID("type;" + id);
String contents = table.getTypeString(id);
String[] parts = split(contents);
int kind = tagToKind.get(parts[0]);
trapWriter.addTuple("types", lbl, kind, table.getTypeToStringValue(id));
int firstChild = 1;
switch (kind) {
case referenceKind:
case typevarKind:
case typeofKind:
case uniqueSymbolKind:
{
// The first part of a reference is the symbol for name binding.
Label symbol = trapWriter.globalID("symbol;" + parts[1]);
trapWriter.addTuple("type_symbol", lbl, symbol);
++firstChild;
break;
}
case tupleKind:
{
// The first two parts denote minimum length and index of rest element (or -1 if no rest element).
trapWriter.addTuple("tuple_type_min_length", lbl, Integer.parseInt(parts[1]));
int restIndex = Integer.parseInt(parts[2]);
if (restIndex != -1) {
trapWriter.addTuple("tuple_type_rest_index", lbl, restIndex);
}
firstChild += 2;
break;
}
case objectKind:
case lexicalTypevarKind:
firstChild = parts.length; // No children.
break;
case numberLiteralTypeKind:
case stringLiteralTypeKind:
case bigintLiteralTypeKind:
firstChild = parts.length; // No children.
// The string value may contain `;` so don't use the split().
String value = contents.substring(parts[0].length() + 1);
trapWriter.addTuple("type_literal_value", lbl, value);
break;
}
for (int i = firstChild; i < parts.length; ++i) {
Label childLabel = trapWriter.globalID("type;" + parts[i]);
trapWriter.addTuple("type_child", childLabel, lbl, i - firstChild);
}
}
private void extractPropertyLookups(JsonObject lookups) {
JsonArray baseTypes = lookups.get("baseTypes").getAsJsonArray();
JsonArray names = lookups.get("names").getAsJsonArray();
JsonArray propertyTypes = lookups.get("propertyTypes").getAsJsonArray();
for (int i = 0; i < baseTypes.size(); ++i) {
int baseType = baseTypes.get(i).getAsInt();
String name = names.get(i).getAsString();
int propertyType = propertyTypes.get(i).getAsInt();
trapWriter.addTuple(
"type_property",
trapWriter.globalID("type;" + baseType),
name,
trapWriter.globalID("type;" + propertyType));
}
}
private void extractTypeAliases(JsonObject aliases) {
JsonArray aliasTypes = aliases.get("aliasTypes").getAsJsonArray();
JsonArray underlyingTypes = aliases.get("underlyingTypes").getAsJsonArray();
for (int i = 0; i < aliasTypes.size(); ++i) {
int aliasType = aliasTypes.get(i).getAsInt();
int underlyingType = underlyingTypes.get(i).getAsInt();
trapWriter.addTuple(
"type_alias",
trapWriter.globalID("type;" + aliasType),
trapWriter.globalID("type;" + underlyingType));
}
}
private void extractSymbol(int index) {
// Format is: kind;decl;parent;name
String[] parts = split(table.getSymbolString(index), 4);
int kind = symbolKind.get(parts[0]);
String name = parts[3];
Label label = trapWriter.globalID("symbol;" + index);
trapWriter.addTuple("symbols", label, kind, name);
String parentStr = parts[2];
if (parentStr.length() > 0) {
Label parentLabel = trapWriter.globalID("symbol;" + parentStr);
trapWriter.addTuple("symbol_parent", label, parentLabel);
}
}
private void extractSymbolNameMapping(String relationName, JsonObject mappings) {
JsonArray symbols = mappings.get("symbols").getAsJsonArray();
JsonArray names = mappings.get("names").getAsJsonArray();
for (int i = 0; i < symbols.size(); ++i) {
Label symbol = trapWriter.globalID("symbol;" + symbols.get(i).getAsInt());
String moduleName = names.get(i).getAsString();
trapWriter.addTuple(relationName, symbol, moduleName);
}
}
private void extractSignature(int index) {
// Format is:
// kind;isAbstract;numTypeParams;requiredParams;restParamType;returnType(;paramName;paramType)*
String[] parts = split(table.getSignatureString(index));
Label label = trapWriter.globalID("signature;" + index);
int kind = Integer.parseInt(parts[0]);
boolean isAbstract = parts[1].equals("t");
if (isAbstract) {
trapWriter.addTuple("is_abstract_signature", label);
}
int numberOfTypeParameters = Integer.parseInt(parts[2]);
int requiredParameters = Integer.parseInt(parts[3]);
String restParamTypeTag = parts[4];
if (!restParamTypeTag.isEmpty()) {
trapWriter.addTuple(
"signature_rest_parameter", label, trapWriter.globalID("type;" + restParamTypeTag));
}
Label returnType = trapWriter.globalID("type;" + parts[5]);
trapWriter.addTuple(
"signature_types",
label,
kind,
table.getSignatureToStringValue(index),
numberOfTypeParameters,
requiredParameters);
trapWriter.addTuple("signature_contains_type", returnType, label, -1);
int numberOfParameters = (parts.length - 6) / 2; // includes type parameters
for (int i = 0; i < numberOfParameters; ++i) {
int partIndex = 6 + (2 * i);
String paramName = parts[partIndex];
String paramTypeId = parts[partIndex + 1];
if (paramTypeId.length() > 0) { // Unconstrained type parameters have an empty type ID.
Label paramType = trapWriter.globalID("type;" + parts[partIndex + 1]);
trapWriter.addTuple("signature_contains_type", paramType, label, i);
}
trapWriter.addTuple("signature_parameter_name", label, i, paramName);
}
}
private void extractSignatureMappings(JsonObject mappings) {
JsonArray baseTypes = mappings.get("baseTypes").getAsJsonArray();
JsonArray kinds = mappings.get("kinds").getAsJsonArray();
JsonArray indices = mappings.get("indices").getAsJsonArray();
JsonArray signatures = mappings.get("signatures").getAsJsonArray();
for (int i = 0; i < baseTypes.size(); ++i) {
int baseType = baseTypes.get(i).getAsInt();
int kind = kinds.get(i).getAsInt();
int index = indices.get(i).getAsInt();
int signatureId = signatures.get(i).getAsInt();
trapWriter.addTuple(
"type_contains_signature",
trapWriter.globalID("type;" + baseType),
kind,
index,
trapWriter.globalID("signature;" + signatureId));
}
}
private void extractIndexTypeTable(JsonObject table, String relationName) {
JsonArray baseTypes = table.get("baseTypes").getAsJsonArray();
JsonArray propertyTypes = table.get("propertyTypes").getAsJsonArray();
for (int i = 0; i < baseTypes.size(); ++i) {
int baseType = baseTypes.get(i).getAsInt();
int propertyType = propertyTypes.get(i).getAsInt();
trapWriter.addTuple(
relationName,
trapWriter.globalID("type;" + baseType),
trapWriter.globalID("type;" + propertyType));
}
}
private void extractBaseTypes(JsonObject table) {
JsonArray symbols = table.get("symbols").getAsJsonArray();
JsonArray baseTypeSymbols = table.get("baseTypeSymbols").getAsJsonArray();
for (int i = 0; i < symbols.size(); ++i) {
int symbolId = symbols.get(i).getAsInt();
int baseTypeSymbolId = baseTypeSymbols.get(i).getAsInt();
trapWriter.addTuple(
"base_type_names",
trapWriter.globalID("symbol;" + symbolId),
trapWriter.globalID("symbol;" + baseTypeSymbolId));
}
}
private void extractSelfTypes(JsonObject table) {
JsonArray symbols = table.get("symbols").getAsJsonArray();
JsonArray selfTypes = table.get("selfTypes").getAsJsonArray();
for (int i = 0; i < symbols.size(); ++i) {
int symbolId = symbols.get(i).getAsInt();
int typeId = selfTypes.get(i).getAsInt();
trapWriter.addTuple(
"self_types",
trapWriter.globalID("symbol;" + symbolId),
trapWriter.globalID("type;" + typeId));
}
}
/** Like {@link #split(String)} without a limit. */
private static String[] split(String input) {
return split(input, -1);
}
/**
* Splits the input around the semicolon (<code>;</code>) character, preserving all empty
* substrings.
*
* <p>At most <code>limit</code> substrings will be extracted. If the limit is reached, the last
* substring will extend to the end of the string, possibly itself containing semicolons.
*
* <p>Note that the {@link String#split(String)} method does not preserve empty substrings at the
* end of the string in case the string ends with a semicolon.
*/
private static String[] split(String input, int limit) {
List<String> result = new ArrayList<String>();
int lastPos = 0;
for (int i = 0; i < input.length(); ++i) {
if (input.charAt(i) == ';') {
result.add(input.substring(lastPos, i));
lastPos = i + 1;
if (result.size() == limit - 1) break;
}
}
result.add(input.substring(lastPos));
return result.toArray(EMPTY_STRING_ARRAY);
}
private static final String[] EMPTY_STRING_ARRAY = new String[0];
}

View File

@@ -463,113 +463,6 @@ public class TypeScriptParser {
checkResponseType(response, "ok");
}
/**
* Converts a map to an array of [key, value] pairs.
*/
private JsonArray mapToArray(Map<String, Path> map) {
JsonArray result = new JsonArray();
map.forEach(
(key, path) -> {
JsonArray entry = new JsonArray();
entry.add(key);
entry.add(path.toString());
result.add(entry);
});
return result;
}
private static Set<File> getFilesFromJsonArray(JsonArray array) {
Set<File> files = new LinkedHashSet<>();
for (JsonElement elm : array) {
files.add(new File(elm.getAsString()));
}
return files;
}
/**
* Returns the set of files included by the inclusion pattern in the given tsconfig.json file.
*/
public Set<File> getOwnFiles(File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) {
JsonObject request = makeLoadCommand("get-own-files", tsConfigFile, deps, vroot);
JsonObject response = talkToParserWrapper(request);
try {
checkResponseType(response, "file-list");
return getFilesFromJsonArray(response.get("ownFiles").getAsJsonArray());
} catch (IllegalStateException e) {
throw new CatastrophicError(
"TypeScript parser wrapper sent unexpected response: " + response, e);
}
}
/**
* Opens a new project based on a tsconfig.json file. The compiler will analyze all files in the
* project.
*
* <p>Call {@link #parse} to access individual files in the project.
*
* <p>Only one project should be opened at once.
*/
public ParsedProject openProject(File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) {
JsonObject request = makeLoadCommand("open-project", tsConfigFile, deps, vroot);
JsonObject response = talkToParserWrapper(request);
try {
checkResponseType(response, "project-opened");
ParsedProject project = new ParsedProject(tsConfigFile,
getFilesFromJsonArray(response.get("ownFiles").getAsJsonArray()),
getFilesFromJsonArray(response.get("allFiles").getAsJsonArray()));
return project;
} catch (IllegalStateException e) {
throw new CatastrophicError(
"TypeScript parser wrapper sent unexpected response: " + response, e);
}
}
private JsonObject makeLoadCommand(String command, File tsConfigFile, DependencyInstallationResult deps, VirtualSourceRoot vroot) {
JsonObject request = new JsonObject();
request.add("command", new JsonPrimitive(command));
request.add("tsConfig", new JsonPrimitive(tsConfigFile.getPath()));
request.add("packageEntryPoints", mapToArray(deps.getPackageEntryPoints()));
request.add("packageJsonFiles", mapToArray(deps.getPackageJsonFiles()));
request.add("sourceRoot", vroot.getSourceRoot() == null
? JsonNull.INSTANCE
: new JsonPrimitive(vroot.getSourceRoot().toString()));
request.add("virtualSourceRoot", vroot.getVirtualSourceRoot() == null
? JsonNull.INSTANCE
: new JsonPrimitive(vroot.getVirtualSourceRoot().toString()));
return request;
}
/**
* Closes a project previously opened.
*
* <p>This main purpose is to free heap space in the Node.js process.
*/
public void closeProject(File tsConfigFile) {
JsonObject request = new JsonObject();
request.add("command", new JsonPrimitive("close-project"));
request.add("tsConfig", new JsonPrimitive(tsConfigFile.getPath()));
JsonObject response = talkToParserWrapper(request);
try {
checkResponseType(response, "project-closed");
} catch (IllegalStateException e) {
throw new CatastrophicError(
"TypeScript parser wrapper sent unexpected response: " + response, e);
}
}
public TypeTable getTypeTable() {
JsonObject request = new JsonObject();
request.add("command", new JsonPrimitive("get-type-table"));
JsonObject response = talkToParserWrapper(request);
try {
checkResponseType(response, "type-table");
return new TypeTable(response.get("typeTable").getAsJsonObject());
} catch (IllegalStateException e) {
throw new CatastrophicError(
"TypeScript parser wrapper sent unexpected response: " + response, e);
}
}
/**
* Closes any open project, and in general, brings the TypeScript wrapper to a fresh state as if
* it had just been restarted.

View File

@@ -1,119 +0,0 @@
package com.semmle.ts.extractor;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* Holds the output of the <code>get-type-table</code> command.
*
* <p>See documentation in <code>parser-wrapper/src/type_table.ts</code>.
*/
public class TypeTable {
private final JsonArray typeStrings;
private final JsonArray typeToStringValues;
private final JsonObject propertyLookups;
private final JsonObject typeAliases;
private final JsonArray symbolStrings;
private final JsonObject moduleMappings;
private final JsonObject globalMappings;
private final JsonArray signatureStrings;
private final JsonObject signatureMappings;
private final JsonArray signatureToStringValues;
private final JsonObject stringIndexTypes;
private final JsonObject numberIndexTypes;
private final JsonObject baseTypes;
private final JsonObject selfTypes;
public TypeTable(JsonObject typeTable) {
this.typeStrings = typeTable.get("typeStrings").getAsJsonArray();
this.typeToStringValues = typeTable.get("typeToStringValues").getAsJsonArray();
this.propertyLookups = typeTable.get("propertyLookups").getAsJsonObject();
this.typeAliases = typeTable.get("typeAliases").getAsJsonObject();
this.symbolStrings = typeTable.get("symbolStrings").getAsJsonArray();
this.moduleMappings = typeTable.get("moduleMappings").getAsJsonObject();
this.globalMappings = typeTable.get("globalMappings").getAsJsonObject();
this.signatureStrings = typeTable.get("signatureStrings").getAsJsonArray();
this.signatureMappings = typeTable.get("signatureMappings").getAsJsonObject();
this.signatureToStringValues = typeTable.get("signatureToStringValues").getAsJsonArray();
this.numberIndexTypes = typeTable.get("numberIndexTypes").getAsJsonObject();
this.stringIndexTypes = typeTable.get("stringIndexTypes").getAsJsonObject();
this.baseTypes = typeTable.get("baseTypes").getAsJsonObject();
this.selfTypes = typeTable.get("selfTypes").getAsJsonObject();
}
public String getTypeString(int index) {
return typeStrings.get(index).getAsString();
}
public String getTypeToStringValue(int index) {
return typeToStringValues.get(index).getAsString();
}
public JsonObject getPropertyLookups() {
return propertyLookups;
}
public JsonObject getTypeAliases() {
return typeAliases;
}
public int getNumberOfTypes() {
return typeStrings.size();
}
public String getSymbolString(int index) {
return symbolStrings.get(index).getAsString();
}
public int getNumberOfSymbols() {
return symbolStrings.size();
}
public JsonObject getModuleMappings() {
return moduleMappings;
}
public JsonObject getGlobalMappings() {
return globalMappings;
}
public JsonArray getSignatureStrings() {
return signatureStrings;
}
public int getNumberOfSignatures() {
return signatureStrings.size();
}
public String getSignatureString(int i) {
return signatureStrings.get(i).getAsString();
}
public JsonObject getSignatureMappings() {
return signatureMappings;
}
public JsonArray getSignatureToStringValues() {
return signatureToStringValues;
}
public String getSignatureToStringValue(int i) {
return signatureToStringValues.get(i).getAsString();
}
public JsonObject getNumberIndexTypes() {
return numberIndexTypes;
}
public JsonObject getStringIndexTypes() {
return stringIndexTypes;
}
public JsonObject getBaseTypes() {
return baseTypes;
}
public JsonObject getSelfTypes() {
return selfTypes;
}
}