diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 41bc399de..50adb5b09 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,28 +8,31 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up JDK 11 - uses: actions/setup-java@v1 + uses: actions/setup-java@v3 with: + distribution: 'temurin' java-version: 11 + cache: 'maven' - name: runs exhaustive tests run: | export JSWEET_VERBOSE=false - cd transpiler - mvn clean install -DskipSigning=true - cd .. - echo 'clone test repositories' - git clone https://github.com/lgrignon/jsweet-java-runtime-transpilation-tests.git - git clone https://github.com/lgrignon/j4ts-example.git - echo 'transpile legacy j4ts sources' - cd jsweet-java-runtime-transpilation-tests - mvn clean generate-sources - cd .. - echo 'run j4ts tests' - cd j4ts-example - mvn clean compile && node target/j4ts-example-bundle.js + mvn clean install + #cd transpiler + #mvn clean install + #cd .. + #echo 'clone test repositories' + #git clone https://github.com/lgrignon/jsweet-java-runtime-transpilation-tests.git + #git clone https://github.com/lgrignon/j4ts-example.git + #echo 'transpile legacy j4ts sources' + #cd jsweet-java-runtime-transpilation-tests + #mvn clean generate-sources + #cd .. + #echo 'run j4ts tests' + #cd j4ts-example + #mvn clean compile && node target/j4ts-example-bundle.js diff --git a/candy-generator/pom.xml b/candy-generator/pom.xml index 9d52f25bd..3ba9f2a89 100644 --- a/candy-generator/pom.xml +++ b/candy-generator/pom.xml @@ -229,7 +229,7 @@ org.jsweet jsweet-core - 5-SNAPSHOT + 5.3.1-SNAPSHOT @@ -277,4 +277,4 @@ - \ No newline at end of file + diff --git a/core-lib/es5/pom.xml b/core-lib/es5/pom.xml index 497248310..3c06c6456 100644 --- a/core-lib/es5/pom.xml +++ b/core-lib/es5/pom.xml @@ -6,7 +6,7 @@ jsweet-core JSweet Core Lib JavaScript API for JSweet - 5.3.0 + 5.3.1-SNAPSHOT ${maven.build.timestamp} yyyy-MM-dd HH:mm:ss @@ -99,26 +99,6 @@ - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - ${skipSigning} - - - - - sign-artifacts - verify - - sign - - - - - @@ -152,6 +132,68 @@ + + + signed + + + signed + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + ${skipSigning} + + + + sign-artifacts + verify + + sign + + + + + + + + + use-snapshots + + + use-snapshots + + + + + snapshots-repo + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + apache.snapshots + https://repository.apache.org/snapshots/ + + + sonatype.snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + + jsweet-release diff --git a/core-lib/es6/pom.xml b/core-lib/es6/pom.xml index 752dbb33b..c289ee83f 100644 --- a/core-lib/es6/pom.xml +++ b/core-lib/es6/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.jsweet jsweet-core - 6.3.0 + 6.3.1-SNAPSHOT JSweet Core Lib JavaScript API for JSweet http://www.jsweet.org @@ -166,24 +166,6 @@ - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - ${skipSigning} - - - - sign-artifacts - verify - - sign - - - - @@ -223,6 +205,69 @@ + + + + signed + + + signed + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + ${skipSigning} + + + + sign-artifacts + verify + + sign + + + + + + + + + use-snapshots + + + use-snapshots + + + + + snapshots-repo + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + apache.snapshots + https://repository.apache.org/snapshots/ + + + sonatype.snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + + jsweet-release diff --git a/file-visitor/.gitignore b/file-visitor/.gitignore new file mode 100644 index 000000000..b83d22266 --- /dev/null +++ b/file-visitor/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/file-visitor/README.md b/file-visitor/README.md new file mode 100644 index 000000000..c3419b94b --- /dev/null +++ b/file-visitor/README.md @@ -0,0 +1,12 @@ +# file-visitor + +This utility written in Java allows for visiting a set of files within a directory an apply bulk action written in so-called file visitors. It can be specialized to perform any job on the visited files. + +## How to use + +- Implement the ``FileVisitor`` interface. +- Invoke the ``FileVisitor.scan(root, fileVisitors)`` method, where ``root`` is the root file to be scanned, and ``fileVisitors`` are you ``FileVisitor`` implementations. + +## Licence + +Open Source Apache 2 diff --git a/file-visitor/pom.xml b/file-visitor/pom.xml new file mode 100644 index 000000000..2260fa863 --- /dev/null +++ b/file-visitor/pom.xml @@ -0,0 +1,71 @@ + + 4.0.0 + org.cincheo + file-visitor + 1.0.0 + + + + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + + + + org.codehaus.mojo + exec-maven-plugin + 1.3.2 + + + + java + + + + + java + + -classpath + + org.cincheo.file_visitor.Main + + ${dir} + + + + + + + com.google.code.gson + gson + 2.7 + + + commons-io + commons-io + 2.4 + + + org.apache.commons + commons-lang3 + 3.3.2 + + + + + + + jsweet-release + libs-release + http://repository.jsweet.org/artifactory/libs-release-local + + + jsweet-snapshots + libs-snapshot + http://repository.jsweet.org/artifactory/libs-snapshot-local + + + \ No newline at end of file diff --git a/file-visitor/src/main/java/org/cincheo/filevisitor/FileVisitor.java b/file-visitor/src/main/java/org/cincheo/filevisitor/FileVisitor.java new file mode 100644 index 000000000..2043419cf --- /dev/null +++ b/file-visitor/src/main/java/org/cincheo/filevisitor/FileVisitor.java @@ -0,0 +1,74 @@ +package org.cincheo.filevisitor; + +import java.io.File; + +/** + * An interface to be implemented to create actual actions on files being + * visited. + */ +public interface FileVisitor { + + /** + * Applies a list of file visitors to a root file, which will be scanned + * recursively, including sub-directories. + * + * @param root + * the root file to be scanned + * @param fileVisitors + * the file visitors to be applied while scanning + */ + public static void scan(File root, FileVisitor... fileVisitors) { + FileScanner.scan(root, fileVisitors); + } + + /** + * This method is called right before the visiting process begins. + */ + public void onBegin(); + + /** + * This method is called each time a file is visited. + * + * @param the + * file being visited + * @return should return true in order to continue, or false to end visiting + * (on a directory, returning false will skip all the remaining + * files in the directory) + */ + public boolean visit(File file); + + /** + * This method is called right after the visiting process ends. + */ + public boolean onEnd(); +} + +class FileScanner { + static void scan(File root, FileVisitor... fileVisitors) { + for (FileVisitor fileVisitor : fileVisitors) { + fileVisitor.onBegin(); + scan(root, fileVisitor); + if (!fileVisitor.onEnd()) { + break; + } + } + } + + private static void scan(File f, FileVisitor fileVisitor) { + if (fileVisitor.visit(f)) { + if (f.isDirectory()) { + for (File child : f.listFiles()) { + if (child.isFile()) { + scan(child, fileVisitor); + } + } + for (File child : f.listFiles()) { + if (child.isDirectory()) { + scan(child, fileVisitor); + } + } + } + } + } + +} diff --git a/file-visitor/src/main/java/org/cincheo/filevisitor/ProcessUtil.java b/file-visitor/src/main/java/org/cincheo/filevisitor/ProcessUtil.java new file mode 100644 index 000000000..f12316825 --- /dev/null +++ b/file-visitor/src/main/java/org/cincheo/filevisitor/ProcessUtil.java @@ -0,0 +1,309 @@ +/* + * JSweet transpiler - http://www.jsweet.org + * Copyright (C) 2015 CINCHEO SAS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +package org.cincheo.filevisitor; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; + +/** + * A set of utilities to launch external processes from Java. + * + * @author Renaud Pawlak + */ +public class ProcessUtil { + + public static final String NODE_MINIMUM_VERSION = "v4.4.0"; + + private static boolean initialized = false; + + /** + * Initializes the node command paths (OS-specific initializations). + */ + public static void initNode() { + if (!initialized) { + // hack for OSX Eclipse's path issue + if (!System.getenv("PATH").contains("/usr/local/bin") && new File("/usr/local/bin/node").exists()) { + ProcessUtil.EXTRA_PATH = "/usr/local/bin"; + ProcessUtil.NODE_COMMAND = "/usr/local/bin/node"; + ProcessUtil.NPM_COMMAND = "/usr/local/bin/npm"; + } + initialized = true; + } + } + + /** + * A static field that stores the user home directory. + */ + public static File USER_HOME_DIR = new File(System.getProperty("user.home")); + + /** + * A static field that stores the JSweet npm directory. + */ + public static File NPM_DIR = new File(USER_HOME_DIR, ".jsweet-node_modules"); + + private static List nodeCommands = Arrays.asList("tsc", "browserify"); + + /** + * The node command name (can be full path in some environments). + */ + public static String NODE_COMMAND = "node"; + + /** + * The npm command name (can be full path in some environments). + */ + public static String NPM_COMMAND = "npm"; + + /** + * Some extra paths to be added to the PATH environment variable in some + * environments. Typically Eclipse on Mac OSX misses the /usr/local/bin + * path, which is required to run node. + */ + public static String EXTRA_PATH; + + /** + * Gets the full path of a command installed with npm. + */ + private static String getNpmPath(String command) { + if (System.getProperty("os.name").startsWith("Windows")) { + return NPM_DIR.getPath() + File.separator + command + ".cmd"; + } else { + return NPM_DIR.getPath() + File.separator + "bin" + File.separator + command; + } + } + + /** + * Tells if this node command is installed. + */ + public static boolean isInstalledWithNpm(String command) { + return new File(getNpmPath(command)).exists(); + } + + /** + * Runs the given command. + * + * @param command + * the command name + * @param stdoutConsumer + * consumes the standard output stream as lines of characters + * @param errorHandler + * upcalled when the command does not terminate successfully + * @param args + * the command-line arguments + * @return the process that was created to execute the command (exited at + * this point) + */ + public static Process runCommand(String command, Consumer stdoutConsumer, Runnable errorHandler, + String... args) { + return runCommand(command, null, false, stdoutConsumer, null, errorHandler, args); + } + + /** + * Runs the given command in an asynchronous manner. + * + * @param command + * the command name + * @param stdoutConsumer + * consumes the standard output stream as lines of characters + * @param endConsumer + * called when the process actually ends + * @param errorHandler + * upcalled when the command does not terminate successfully + * @param args + * the command-line arguments + * @return the process that was created to execute the command (can be still + * running at this point) + */ + public static Process runAsyncCommand(String command, Consumer stdoutConsumer, + Consumer endConsumer, Runnable errorHandler, String... args) { + return runCommand(command, null, true, stdoutConsumer, endConsumer, errorHandler, args); + } + + /** + * Runs the given command. + * + * @param command + * the command name + * @param directory + * the working directory of the created process + * @param async + * tells if the command should be run asynchronously (in a + * separate thread) + * @param stdoutConsumer + * consumes the standard output stream as lines of characters + * @param endConsumer + * called when the process actually ends + * @param errorHandler + * upcalled when the command does not terminate successfully + * @param args + * the command-line arguments + * @return the process that was created to execute the command (can be still + * running at this point if async is true) + */ + public static Process runCommand(String command, File directory, boolean async, Consumer stdoutConsumer, + Consumer endConsumer, Runnable errorHandler, String... args) { + + String[] cmd; + if (System.getProperty("os.name").startsWith("Windows")) { + if (nodeCommands.contains(command)) { + cmd = new String[] { getNpmPath(command) }; + } else { + cmd = new String[] { "cmd", "/c", command }; + } + } else { + if (nodeCommands.contains(command)) { + cmd = new String[] { getNpmPath(command) }; + } else { + cmd = new String[] { command }; + } + } + cmd = ArrayUtils.addAll(cmd, args); + + System.out.println("run command: " + StringUtils.join(cmd, " ")); + Process[] process = { null }; + try { + ProcessBuilder processBuilder = new ProcessBuilder(cmd); + processBuilder.redirectErrorStream(true); + if (directory != null) { + processBuilder.directory(directory); + } + if (!StringUtils.isBlank(EXTRA_PATH)) { + processBuilder.environment().put("PATH", + processBuilder.environment().get("PATH") + File.pathSeparator + EXTRA_PATH); + } + + process[0] = processBuilder.start(); + + Runnable runnable = new Runnable() { + + @Override + public void run() { + try { + try (BufferedReader in = new BufferedReader( + new InputStreamReader(process[0].getInputStream(), "UTF-8"))) { + String line; + while ((line = in.readLine()) != null) { + if (stdoutConsumer != null) { + stdoutConsumer.accept(line); + } else { + System.out.println(command + " - " + line); + } + } + } + + process[0].waitFor(); + if (endConsumer != null) { + endConsumer.accept(process[0]); + } + if (process[0].exitValue() != 0) { + if (errorHandler != null) { + errorHandler.run(); + } + } + } catch (Exception e) { + e.printStackTrace(); + if (errorHandler != null) { + errorHandler.run(); + } + } + } + }; + if (async) { + new Thread(runnable).start(); + } else { + runnable.run(); + } + + } catch (Exception e) { + e.printStackTrace(); + if (errorHandler != null) { + errorHandler.run(); + } + return null; + } + return process[0]; + } + + /** + * Installs a node package with npm (assumes that + * node is installed). + * + * @param nodePackageName + * the package name + * @param global + * true for adding the -g option + */ + public static void installNodePackage(String nodePackageName, String version, boolean global) { + System.out.println("installing " + nodePackageName + " with npm"); + initNode(); + if (global) { + runCommand(NPM_COMMAND, USER_HOME_DIR, false, null, null, null, "install", "--prefix", NPM_DIR.getPath(), + version == null ? nodePackageName : nodePackageName + "@" + version, "-g"); + } else { + runCommand(NPM_COMMAND, USER_HOME_DIR, false, null, null, null, "install", + version == null ? nodePackageName : nodePackageName + "@" + version, "--save"); + } + } + + /** + * Checks if a node package has been installed locally. + * + * @param nodePackageName + * the node module to be tested + * @return true if already installed locally + */ + public static boolean isNodePackageInstalled(String nodePackageName) { + System.out.println("checking installation of " + nodePackageName + " with npm"); + initNode(); + boolean[] installed = { false }; + runCommand(NPM_COMMAND, USER_HOME_DIR, false, line -> { + if (!installed[0]) { + installed[0] = line.endsWith("/" + nodePackageName); + } + }, null, null, "ls", "--parseable", nodePackageName); + return installed[0]; + } + + /** + * Uninstalls a node package with npm (assumes that + * node is installed). + * + * @param nodePackageName + * the package name + * @param global + * true for adding the -g option + */ + public static void uninstallNodePackage(String nodePackageName, boolean global) { + System.out.println("uninstalling " + nodePackageName + " with npm"); + initNode(); + if (global) { + runCommand(NPM_COMMAND, USER_HOME_DIR, false, null, null, null, "uninstall", "--prefix", NPM_DIR.getPath(), + nodePackageName, "-g"); + } else { + runCommand(NPM_COMMAND, USER_HOME_DIR, false, null, null, null, "uninstall", nodePackageName); + } + } + +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..41aba3731 --- /dev/null +++ b/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + org.jsweet + jsweet-parent + 1.0.0-SNAPSHOT + pom + + + ${project.basedir} + + + + file-visitor + typescript.java-ts.core + core-lib/es5 + core-lib/es6 + candy-generator + transpiler + + diff --git a/transpiler/pom.xml b/transpiler/pom.xml index 072b069e2..3c066f2e0 100644 --- a/transpiler/pom.xml +++ b/transpiler/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.jsweet jsweet-transpiler - 3.2.0-SNAPSHOT + 4.0.0-SNAPSHOT JSweet transpiler A Java to TypeScript/JavaScript Open Transpiler http://www.jsweet.org @@ -174,26 +174,41 @@ - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - ${skipSigning} - - - - sign-artifacts - verify - - sign - - - - + + + + signed + + + signed + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + ${skipSigning} + + + + sign-artifacts + verify + + sign + + + + + + + + + org.apache.commons @@ -267,7 +282,7 @@ org.jsweet jsweet-core - 6.3.0 + 6.3.1-SNAPSHOT compile true diff --git a/transpiler/src/main/java/org/jsweet/transpiler/CleanerProvider.java b/transpiler/src/main/java/org/jsweet/transpiler/CleanerProvider.java new file mode 100644 index 000000000..5548dc181 --- /dev/null +++ b/transpiler/src/main/java/org/jsweet/transpiler/CleanerProvider.java @@ -0,0 +1,11 @@ +package org.jsweet.transpiler; + +import java.lang.ref.Cleaner; + +final class CleanerProvider { + private static final Cleaner CLEANER = Cleaner.create(); + + public static Cleaner getCleaner() { + return CLEANER; + } +} diff --git a/transpiler/src/main/java/org/jsweet/transpiler/ConfiguredDirectory.java b/transpiler/src/main/java/org/jsweet/transpiler/ConfiguredDirectory.java new file mode 100644 index 000000000..af31c8759 --- /dev/null +++ b/transpiler/src/main/java/org/jsweet/transpiler/ConfiguredDirectory.java @@ -0,0 +1,161 @@ +package org.jsweet.transpiler; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.lang.ref.Cleaner.Cleanable; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Objects; + +/** + * A wrapper for directories that are either simple paths, or temporary ones + * that should be removed whenever possible. + * + * @author Christian Kohlschütter + */ +public class ConfiguredDirectory implements Closeable { + private static final String TEMPORARY_PREFIX_DEFAULT = "javatmp"; + private Path path; + + public static final ConfiguredDirectory ofDir(Path p) throws IOException { + if (p == null) { + return ofTemporaryDir(); + } + return new ConfiguredDirectory(p); + } + + public static final ConfiguredDirectory ofDir(File f) throws IOException { + if (f == null) { + return ofTemporaryDir(); + } + return ofDir(f.toPath()); + } + + public static ConfiguredDirectory ofOrTemporaryDir(ConfiguredDirectory cd) throws IOException { + return cd == null ? ofTemporaryDir() : cd; + } + + public static ConfiguredDirectory ofOrTemporaryDir(ConfiguredDirectory cd, String prefix) throws IOException { + return cd == null ? ofTemporaryDir(prefix) : cd; + } + + public static ConfiguredDirectory ofTemporaryDir() throws IOException { + return ofTemporaryDir(TEMPORARY_PREFIX_DEFAULT); + } + + public static final ConfiguredDirectory ofDirOrNull(Path p) throws IOException { + if (p == null) { + return null; + } + return new ConfiguredDirectory(p); + } + + public static final ConfiguredDirectory ofDirOrNull(File f) throws IOException { + if (f == null) { + return null; + } + return ofDir(f.toPath()); + } + + public static final ConfiguredDirectory ofTemporaryDir(Path p) throws IOException { + p.toFile().deleteOnExit(); + return new Temporary(p); + } + + public static final ConfiguredDirectory ofTemporaryDir(File f) throws IOException { + return ofTemporaryDir(f.toPath()); + } + + public static final ConfiguredDirectory ofTemporaryDir(String prefix) throws IOException { + return ofTemporaryDir(Files.createTempDirectory(prefix)); + } + + protected ConfiguredDirectory(Path p) { + this.path = p; + } + + public Path getPath() { + return path; + } + + static final class Temporary extends ConfiguredDirectory { + private final Cleanable cleanable; + + private Temporary(Path p) throws IOException { + super(p); + + CleanAction ca = new CleanAction(p); + this.cleanable = CleanerProvider.getCleaner().register(this, ca); + ca.setShutdownHook(cleanable::clean); + } + + @Override + public void close() throws IOException { + cleanable.clean(); + } + } + + @Override + public void close() throws IOException { + } + + @Override + public String toString() { + return super.toString() + "[path=" + getPath() + "]"; + } + + private static final class CleanAction implements Runnable { + private static final FileVisitor VISITOR = new FileVisitor<>() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.deleteIfExists(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.deleteIfExists(dir); + return FileVisitResult.CONTINUE; + } + }; + private final Path path; + private Thread shutdownHook; + + CleanAction(Path p) { + this.path = Objects.requireNonNull(p); + } + + void setShutdownHook(Runnable runnable) { + this.shutdownHook = new Thread(runnable); + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + + @Override + public void run() { + try { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } catch (RuntimeException ignore) { + // shutdown in progress + } + try { + Files.walkFileTree(Objects.requireNonNull(path), VISITOR); + } catch (RuntimeException | IOException ignore) { + // nothing we can do + } + } + } +} diff --git a/transpiler/src/main/java/org/jsweet/transpiler/JSweetContext.java b/transpiler/src/main/java/org/jsweet/transpiler/JSweetContext.java index 7b90a1abd..1393e8a23 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/JSweetContext.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/JSweetContext.java @@ -602,7 +602,7 @@ private void addConfigurationEntry(Entry untypedEntry) { } - private boolean usingJavaRuntime = false; + private File usingJavaRuntime = null; public final Locale locale = Locale.getDefault(); @@ -2008,15 +2008,17 @@ public boolean isPackageErased(PackageElement pkg) { * Tells if the transpiler is using J4TS Java runtime. If yes, it will use the * adapter that tries to delegate to the Java emulation layer for the Java API. */ - public boolean isUsingJavaRuntime() { + public File getUsingJavaRuntime() { return usingJavaRuntime; } /** * Sets the transpiler to use the J4TS Java runtime. + * + * @param pathToJ4TsJs Path to j4ts.js, or {@code null} to disable. */ - public void setUsingJavaRuntime(boolean usingJavaRuntime) { - this.usingJavaRuntime = usingJavaRuntime; + public void setUsingJavaRuntime(File pathToJ4TsJs) { + this.usingJavaRuntime = pathToJ4TsJs; } public final Map getLangTypeMappings() { diff --git a/transpiler/src/main/java/org/jsweet/transpiler/JSweetFactory.java b/transpiler/src/main/java/org/jsweet/transpiler/JSweetFactory.java index 24ca58f67..9bc682f12 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/JSweetFactory.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/JSweetFactory.java @@ -79,7 +79,7 @@ public PrinterAdapter createAdapter(JSweetContext context) { } if (constructor == null) { logger.debug("constructing default adapter"); - adapter = context.isUsingJavaRuntime() ? new Java2TypeScriptAdapter(context) + adapter = context.getUsingJavaRuntime() != null ? new Java2TypeScriptAdapter(context) : new RemoveJavaDependenciesAdapter(context); try { constructor = adapterClass.getConstructor(PrinterAdapter.class); @@ -114,7 +114,7 @@ public PrinterAdapter createAdapter(JSweetContext context) { throw new RuntimeException(e); } } else { - if (context.isUsingJavaRuntime()) { + if (context.getUsingJavaRuntime() != null) { return new Java2TypeScriptAdapter(context); } else { return new RemoveJavaDependenciesAdapter(context); diff --git a/transpiler/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java b/transpiler/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java index cbd272a9b..98f387b35 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/JSweetTranspiler.java @@ -21,7 +21,6 @@ import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static org.jsweet.transpiler.util.ProcessUtil.isVersionHighEnough; -import ts.client.TypeScriptServiceClient; import java.io.File; import java.io.FileNotFoundException; @@ -152,11 +151,6 @@ public static EcmaScriptComplianceLevel getEcmaTargetVersion(String targetVersio } } - /** - * The constant for the name of the directory that stores temporary files. - */ - public static final String TMP_WORKING_DIR_NAME = ".jsweet"; - /** * A constant that is used for exporting variables. * @@ -194,7 +188,8 @@ public static EcmaScriptComplianceLevel getEcmaTargetVersion(String targetVersio private CandyProcessor candiesProcessor; private boolean generateSourceMaps = false; - private File workingDir; + private final ConfiguredDirectory workingDirectory; + private final File workingDir; private File tsOutputDir; private File jsOutputDir; private String classPath; @@ -219,7 +214,7 @@ public static EcmaScriptComplianceLevel getEcmaTargetVersion(String targetVersio private boolean ignoreTypeScriptErrors = false; private boolean ignoreJavaErrors = false; private boolean forceJavaRuntime = false; - private boolean isUsingJavaRuntime = false; + private File javaRuntimeJ4TsJs = null; private File headerFile = null; private boolean debugMode = false; private boolean skipTypeScriptChecks = false; @@ -246,9 +241,9 @@ public static EcmaScriptComplianceLevel getEcmaTargetVersion(String targetVersio * Calling this method is usually not needed since JSweet auto-detects the J4TS * candy. Use only to manually force the transpiler in a mode or another. */ - public void setUsingJavaRuntime(boolean usingJavaRuntime) { + public void setUsingJavaRuntime(File pathToJ4TsJs) { forceJavaRuntime = true; - isUsingJavaRuntime = usingJavaRuntime; + javaRuntimeJ4TsJs = pathToJ4TsJs; } @Override @@ -272,8 +267,9 @@ public String toString() { * System.getProperty("java.class.path"). * * @param factory the factory used to create the transpiler objects + * @throws IOException on error. */ - public JSweetTranspiler(JSweetFactory factory) { + public JSweetTranspiler(JSweetFactory factory) throws IOException { this(factory, new File(System.getProperty("java.io.tmpdir")), null, null, System.getProperty("java.class.path")); } @@ -292,9 +288,10 @@ public JSweetTranspiler(JSweetFactory factory) { * @param classPath the classpath as a string (check out * system-specific requirements for Java * classpathes) + * @throws IOException on error. */ public JSweetTranspiler(JSweetFactory factory, File tsOutputDir, File jsOutputDir, - File extractedCandiesJavascriptDir, String classPath) { + File extractedCandiesJavascriptDir, String classPath) throws IOException { this(factory, null, tsOutputDir, jsOutputDir, extractedCandiesJavascriptDir, classPath); } @@ -440,9 +437,10 @@ private void readConfiguration() { * @param classPath the classpath as a string (check out * system-specific requirements for Java * classpaths) + * @throws IOException on error. */ public JSweetTranspiler(JSweetFactory factory, File workingDir, File tsOutputDir, File jsOutputDir, - File extractedCandiesJavascriptDir, String classPath) { + File extractedCandiesJavascriptDir, String classPath) throws IOException { this(null, factory, workingDir, tsOutputDir, tsOutputDir, extractedCandiesJavascriptDir, classPath); } @@ -464,9 +462,10 @@ public JSweetTranspiler(JSweetFactory factory, File workingDir, File tsOutputDir * @param classPath the classpath as a string (check out * system-specific requirements for Java * classpaths) + * @throws IOException on error. */ public JSweetTranspiler(File configurationFile, JSweetFactory factory, File workingDir, File tsOutputDir, - File jsOutputDir, File extractedCandiesJavascriptDir, String classPath) { + File jsOutputDir, File extractedCandiesJavascriptDir, String classPath) throws IOException { this(null, configurationFile, factory, workingDir, tsOutputDir, jsOutputDir, extractedCandiesJavascriptDir, classPath); } @@ -489,9 +488,35 @@ public JSweetTranspiler(File configurationFile, JSweetFactory factory, File work * @param classPath the classpath as a string (check out * system-specific requirements for Java * classpaths) + * @throws IOException on error. */ public JSweetTranspiler(File baseDirectory, File configurationFile, JSweetFactory factory, File workingDir, - File tsOutputDir, File jsOutputDir, File extractedCandiesJavascriptDir, String classPath) { + File tsOutputDir, File jsOutputDir, File extractedCandiesJavascriptDir, String classPath) throws IOException { + this(baseDirectory, configurationFile, factory, ConfiguredDirectory.ofDirOrNull(workingDir), tsOutputDir, jsOutputDir, ConfiguredDirectory.ofDirOrNull(extractedCandiesJavascriptDir), classPath); + } + + /** + * Creates a JSweet transpiler. + * + * @param configurationFile the configurationFile (uses default one + * if null) + * @param factory the factory used to create the + * transpiler objects + * @param workingDir the working directory (uses default one + * if null) + * @param tsOutputDir the directory where TypeScript files are + * written + * @param jsOutputDir the directory where JavaScript files are + * written + * @param extractedCandiesJavascriptDir see + * {@link #getExtractedCandyJavascriptDir()} + * @param classPath the classpath as a string (check out + * system-specific requirements for Java + * classpaths) + * @throws IOException on error. + */ + public JSweetTranspiler(File baseDirectory, File configurationFile, JSweetFactory factory, ConfiguredDirectory workingDir, + File tsOutputDir, File jsOutputDir, ConfiguredDirectory extractedCandiesJavascriptDir, String classPath) throws IOException { if (baseDirectory == null) { baseDirectory = new File("."); } @@ -504,9 +529,13 @@ public JSweetTranspiler(File baseDirectory, File configurationFile, JSweetFactor if (tsOutputDir == null) { tsOutputDir = new File(baseDirectory, "target/ts"); } - this.workingDir = workingDir == null ? new File(baseDirectory, TMP_WORKING_DIR_NAME).getAbsoluteFile() - : workingDir.getAbsoluteFile(); - this.extractedCandyJavascriptDir = extractedCandiesJavascriptDir; + + this.workingDirectory = ConfiguredDirectory.ofOrTemporaryDir(workingDir, "jsweet"); + this.workingDir = workingDirectory.getPath().toFile(); + + this.extractedCandyJavascriptDirectory = extractedCandiesJavascriptDir; + this.extractedCandyJavascriptDir = extractedCandiesJavascriptDir == null ? null + : extractedCandiesJavascriptDir.getPath().toFile(); try { tsOutputDir.mkdirs(); this.tsOutputDir = tsOutputDir.getCanonicalFile(); @@ -669,7 +698,7 @@ public EvaluationResult eval(String engineName, TranspilationHandler transpilati if ("Java".equals(engineName)) { - JavaEval evaluator = new JavaEval(this, new EvalOptions(isUsingModules(), workingDir, false)); + JavaEval evaluator = new JavaEval(this, new EvalOptions(isUsingModules(), workingDir, null)); return evaluator.performEval(sourceFiles); } else { if (!areAllTranspiled(sourceFiles)) { @@ -701,7 +730,7 @@ public EvaluationResult eval(String engineName, TranspilationHandler transpilati } JavaScriptEval evaluator = new JavaScriptEval( - new EvalOptions(isUsingModules(), workingDir, context.isUsingJavaRuntime()), + new EvalOptions(isUsingModules(), workingDir, context.getUsingJavaRuntime()), JavaScriptRuntime.NodeJs); return evaluator.performEval(jsFiles); } @@ -713,8 +742,8 @@ public JSweetContext prepareForJavaFiles(List javaFiles, ErrorCountTranspi transpilationHandler.setDisabled(isIgnoreJavaErrors()); context = factory.createContext(this); - context.setUsingJavaRuntime(forceJavaRuntime ? isUsingJavaRuntime - : (candiesProcessor == null ? false : candiesProcessor.isUsingJavaRuntime())); + context.setUsingJavaRuntime(forceJavaRuntime ? javaRuntimeJ4TsJs + : (candiesProcessor == null ? null : candiesProcessor.getUsingJavaRuntime())); context.useModules = isUsingModules(); context.useRequireForModules = moduleKind != ModuleKind.es2015; @@ -1228,6 +1257,7 @@ private void createBundle(ErrorCountTranspilationHandler transpilationHandler, S } + private ConfiguredDirectory extractedCandyJavascriptDirectory; private File extractedCandyJavascriptDir; /** @@ -1922,13 +1952,18 @@ public String[] getJavaCompilerExtraOptions() { public void setJavaCompilerExtraOptions(String[] javaCompilerExtraOptions) { this.javaCompilerExtraOptions = javaCompilerExtraOptions; } - + @Override public void close() throws Exception { if (javaCompilationComponents != null) { javaCompilationComponents.close(); } - } + workingDirectory.close(); + ConfiguredDirectory d = extractedCandyJavascriptDirectory; + if (d != null) { + d.close(); + } + } public JSweetFactory getFactory() { return factory; diff --git a/transpiler/src/main/java/org/jsweet/transpiler/candy/CandyProcessor.java b/transpiler/src/main/java/org/jsweet/transpiler/candy/CandyProcessor.java index 9cad14c52..a5cb7f949 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/candy/CandyProcessor.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/candy/CandyProcessor.java @@ -181,17 +181,17 @@ public void processCandies(TranspilationHandler transpilationHandler) throws IOE /** * Returns true if the candy store contains the J4TS candy. */ - public boolean isUsingJavaRuntime() { + public File getUsingJavaRuntime() { if (candyStore == null) { - return false; + return null; } else { for (CandyDescriptor c : candyStore.getCandies()) { if (c.name != null && c.name.equals("j4ts")) { logger.info("found j4ts Java runtime in classpath"); - return true; + return null; // FIXME } } - return false; + return null; } } diff --git a/transpiler/src/main/java/org/jsweet/transpiler/eval/EvalOptions.java b/transpiler/src/main/java/org/jsweet/transpiler/eval/EvalOptions.java index f1cb18de5..267a71689 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/eval/EvalOptions.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/eval/EvalOptions.java @@ -3,14 +3,13 @@ import java.io.File; public class EvalOptions { - public final boolean useModules; - public final File workingDir; - public final boolean useJavaRuntime; + final boolean useModules; + final File workingDir; + final File useJavaRuntime; - public EvalOptions(boolean useModules, File workingDir, boolean useJavaRuntime) { + public EvalOptions(boolean useModules, File workingDir, File pathToJ4TsJs) { this.useModules = useModules; this.workingDir = workingDir; - this.useJavaRuntime = useJavaRuntime; + this.useJavaRuntime = pathToJ4TsJs; } - } diff --git a/transpiler/src/main/java/org/jsweet/transpiler/eval/JavaScriptEval.java b/transpiler/src/main/java/org/jsweet/transpiler/eval/JavaScriptEval.java index 856d1730c..c078250ba 100644 --- a/transpiler/src/main/java/org/jsweet/transpiler/eval/JavaScriptEval.java +++ b/transpiler/src/main/java/org/jsweet/transpiler/eval/JavaScriptEval.java @@ -54,9 +54,11 @@ public EvaluationResult performEval(Collection jsFiles) throws Exception { File tmpFile = new File(options.workingDir, "eval.tmp_" + System.currentTimeMillis() + ".js"); FileUtils.deleteQuietly(tmpFile); - if (options.useJavaRuntime) { + + File j4tsJsPath = options.useJavaRuntime; + if (j4tsJsPath != null) { List newFiles = new ArrayList<>(jsFiles); - newFiles.add(0, new File("src/test/resources/j4ts.js")); + newFiles.add(0, j4tsJsPath); jsFiles = newFiles; } diff --git a/transpiler/src/test/java/org/jsweet/test/transpiler/AbstractTest.java b/transpiler/src/test/java/org/jsweet/test/transpiler/AbstractTest.java index f2661e4d2..4840c2288 100644 --- a/transpiler/src/test/java/org/jsweet/test/transpiler/AbstractTest.java +++ b/transpiler/src/test/java/org/jsweet/test/transpiler/AbstractTest.java @@ -59,7 +59,13 @@ public class AbstractTest { - protected static final String TEST_DIRECTORY_NAME = "src/test/java"; + protected static final boolean MVN_FROM_PARENT_PROJECT = new File("transpiler/src/test/java") + .isDirectory(); + protected static final String TEST_DIRECTORY_NAME = MVN_FROM_PARENT_PROJECT + ? "transpiler/src/test/java" : "src/test/java"; + + protected static final File TEST_PATH_TO_J4TSJS = new File(MVN_FROM_PARENT_PROJECT + ? "transpiler/src/test/resources/j4ts.js" : "src/test/resources/j4ts.js"); protected final Logger logger = Logger.getLogger(getClass()); @@ -87,8 +93,8 @@ protected final String getCurrentTestName() { private TranspilerTestRunner transpilerTest; - protected static final String TMPOUT_DIR = "tempOut"; - + protected static final File TMPOUT_DIR = new File(MVN_FROM_PARENT_PROJECT ? "transpiler/tempOut" : "tempOut"); + protected Types types() { return transpilerTest.types(); } @@ -117,7 +123,7 @@ public void tearDownAbstractTest() throws Exception { } protected File getCurrentTestOutDir() { - return new File(new File(TMPOUT_DIR), getCurrentTestName()); + return new File(TMPOUT_DIR, getCurrentTestName()); } protected Pair getSourcePublicClassDeclaration(SourceFile sourceFile) diff --git a/transpiler/src/test/java/org/jsweet/test/transpiler/ApiTests.java b/transpiler/src/test/java/org/jsweet/test/transpiler/ApiTests.java index bbf5565e6..8102c93cf 100644 --- a/transpiler/src/test/java/org/jsweet/test/transpiler/ApiTests.java +++ b/transpiler/src/test/java/org/jsweet/test/transpiler/ApiTests.java @@ -83,12 +83,12 @@ public void testWrongJdkInvocations() { public void testJ4TSInvocations() { // TODO JSweet3 This will work with new (v3) J4TS candy // with J4TS -// transpilerTest().getTranspiler().setUsingJavaRuntime(true); +// transpilerTest().getTranspiler().setUsingJavaRuntime(TEST_PATH_TO_J4TSJS); // eval(ModuleKind.none, (logHandler, result) -> { // logHandler.assertNoProblems(); // }, getSourceFile(J4TSInvocations.class)); // without J4TS - transpilerTest().getTranspiler().setUsingJavaRuntime(false); + transpilerTest().getTranspiler().setUsingJavaRuntime(null); eval(ModuleKind.none, (logHandler, result) -> { logHandler.assertNoProblems(); }, getSourceFile(J4TSInvocations.class)); diff --git a/transpiler/src/test/java/org/jsweet/test/transpiler/OverloadTests.java b/transpiler/src/test/java/org/jsweet/test/transpiler/OverloadTests.java index 90a894871..29593636c 100644 --- a/transpiler/src/test/java/org/jsweet/test/transpiler/OverloadTests.java +++ b/transpiler/src/test/java/org/jsweet/test/transpiler/OverloadTests.java @@ -303,11 +303,11 @@ public void testConstructorOverloadFieldInitOrderWithThisCall() { @Ignore @Test public void testOverloadClassAndObjectWithJ4TS() { - transpilerTest().getTranspiler().setUsingJavaRuntime(true); + transpilerTest().getTranspiler().setUsingJavaRuntime(TEST_PATH_TO_J4TSJS); eval(ModuleKind.none, (logHandler, r) -> { logHandler.assertNoProblems(); }, getSourceFile(OverLoadClassAndObject.class)); - transpilerTest().getTranspiler().setUsingJavaRuntime(false); + transpilerTest().getTranspiler().setUsingJavaRuntime(null); } @Test @@ -319,11 +319,11 @@ public void testOverloadClassAndObject() { @Test public void testOverloadVarargs() { - transpilerTest().getTranspiler().setUsingJavaRuntime(true); + transpilerTest().getTranspiler().setUsingJavaRuntime(TEST_PATH_TO_J4TSJS); eval(ModuleKind.none, (logHandler, r) -> { logHandler.assertNoProblems(); }, getSourceFile(OverLoadVarags.class)); - transpilerTest().getTranspiler().setUsingJavaRuntime(false); + transpilerTest().getTranspiler().setUsingJavaRuntime(null); } @Test diff --git a/transpiler/src/test/java/org/jsweet/test/transpiler/TranspilerTests.java b/transpiler/src/test/java/org/jsweet/test/transpiler/TranspilerTests.java index 388b946e2..ee76f8cfd 100644 --- a/transpiler/src/test/java/org/jsweet/test/transpiler/TranspilerTests.java +++ b/transpiler/src/test/java/org/jsweet/test/transpiler/TranspilerTests.java @@ -77,7 +77,7 @@ public class TranspilerTests extends AbstractTest { @Before public void init() throws Throwable { - outDir = new File(new File(TMPOUT_DIR), getCurrentTestName() + "/" + ModuleKind.none); + outDir = new File(TMPOUT_DIR, getCurrentTestName() + "/" + ModuleKind.none); gameDir = new File(TEST_DIRECTORY_NAME + "/" + Ball.class.getPackage().getName().replace(".", "/")); calculusDir = new File(TEST_DIRECTORY_NAME + "/" + MathApi.class.getPackage().getName().replace(".", "/")); FileUtils.deleteQuietly(outDir); @@ -432,39 +432,61 @@ public void testHeaderFile() { } }, f); } + + /** + * If we're running from the parent project, the path to the header (as specified in + * either configuration-nobundle.json or configuration-bundle.json) is wrong; this + * method adjusts the path if necessary. + * + * @param transpiler The transpiler to check. + */ + private static void fixHeaderFilePath(JSweetTranspiler transpiler) { + File headerFile = transpiler.getHeaderFile(); + String headerFilePath = headerFile.getPath(); + if (MVN_FROM_PARENT_PROJECT && headerFile.toString() + .startsWith("src/test")) { + transpiler.setHeaderFile(new File(new File("transpiler"), headerFilePath)); + } + } @Test - public void testConfigurationFile() { - SourceFile f = getSourceFile(CanvasDrawing.class); - File configurationFile = new File(f.getJavaFile().getParentFile(), "configuration-nobundle.json"); - TranspilerTestRunner transpilerTest = new TranspilerTestRunner(configurationFile, getCurrentTestOutDir(), - new JSweetFactory()); + public void testConfigurationFile() throws Exception { + SourceFile f = getSourceFile(CanvasDrawing.class); + File configurationFile = new File(f.getJavaFile().getParentFile(), "configuration-nobundle.json"); + try (TranspilerTestRunner transpilerTest = new TranspilerTestRunner(configurationFile, getCurrentTestOutDir(), + new JSweetFactory())) { + fixHeaderFilePath(transpilerTest.getTranspiler()); assertTrue(transpilerTest.getTranspiler().getHeaderFile().getPath().endsWith("header.txt")); assertFalse(transpilerTest.getTranspiler().isBundle()); transpilerTest.transpile(logHandler -> { - logHandler.assertNoProblems(); - try { - String generatedCode = FileUtils.readFileToString(f.getTsFile()); - assertTrue(generatedCode.startsWith("// This is a test header...")); - } catch (Exception e) { - e.printStackTrace(); - fail(e.getMessage()); - } + logHandler.assertNoProblems(); + try { + String generatedCode = FileUtils.readFileToString(f.getTsFile()); + assertTrue(generatedCode.startsWith("// This is a test header...")); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } }, f); - configurationFile = new File(f.getJavaFile().getParentFile(), "configuration-bundle.json"); - transpilerTest = new TranspilerTestRunner(configurationFile, getCurrentTestOutDir(), new JSweetFactory()); + } + + configurationFile = new File(f.getJavaFile().getParentFile(), "configuration-bundle.json"); + try (TranspilerTestRunner transpilerTest = new TranspilerTestRunner(configurationFile, getCurrentTestOutDir(), + new JSweetFactory())) { + fixHeaderFilePath(transpilerTest.getTranspiler()); assertTrue(transpilerTest.getTranspiler().getHeaderFile().getPath().endsWith("header.txt")); assertTrue(transpilerTest.getTranspiler().isBundle()); transpilerTest.transpile(ModuleKind.none, logHandler -> { - logHandler.assertNoProblems(); - try { - String generatedCode = FileUtils.readFileToString(f.getTsFile()); - assertTrue(generatedCode.startsWith("// This is a test header...")); - } catch (Exception e) { - e.printStackTrace(); - fail(e.getMessage()); - } + logHandler.assertNoProblems(); + try { + String generatedCode = FileUtils.readFileToString(f.getTsFile()); + assertTrue(generatedCode.startsWith("// This is a test header...")); + } catch (Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } }, f); + } } } diff --git a/transpiler/src/test/java/org/jsweet/test/transpiler/util/TranspilerTestRunner.java b/transpiler/src/test/java/org/jsweet/test/transpiler/util/TranspilerTestRunner.java index 6a8390790..21fd423d9 100644 --- a/transpiler/src/test/java/org/jsweet/test/transpiler/util/TranspilerTestRunner.java +++ b/transpiler/src/test/java/org/jsweet/test/transpiler/util/TranspilerTestRunner.java @@ -21,6 +21,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.log4j.Logger; import org.jsweet.test.transpiler.TestTranspilationHandler; +import org.jsweet.transpiler.ConfiguredDirectory; import org.jsweet.transpiler.EcmaScriptComplianceLevel; import org.jsweet.transpiler.JSweetFactory; import org.jsweet.transpiler.JSweetTranspiler; @@ -33,7 +34,7 @@ * * @author Louis Grignon */ -public class TranspilerTestRunner { +public class TranspilerTestRunner implements AutoCloseable { private final static Logger logger = Logger.getLogger(TranspilerTestRunner.class); @@ -110,14 +111,18 @@ public TranspilerTestRunner( // logger.info("classPath: " + classPath); logger.info("modulePath: " + modulePath); - transpiler = new JSweetTranspiler( // - configurationFile, // - factory, // - null, // - baseTsOutputDir, // - null, // - new File(JSweetTranspiler.TMP_WORKING_DIR_NAME + "/candies/js"), // - classPath); + try { + transpiler = new JSweetTranspiler(null, // + configurationFile, // + factory, // + null, // + baseTsOutputDir, // + null, // + ConfiguredDirectory.ofTemporaryDir("jsweet-candies"), // + classPath); + } catch (IOException e) { + throw new IllegalStateException(e); + } transpiler.setEcmaTargetVersion(EcmaScriptComplianceLevel.ES6); transpiler.setEncoding("UTF-8"); transpiler.setSkipTypeScriptChecks(true); @@ -125,7 +130,7 @@ public TranspilerTestRunner( // transpiler.setGenerateSourceMaps(false); transpiler.setUseTsserver(true); transpiler.setVerbose(verbose); - transpiler.setUsingJavaRuntime(false); + transpiler.setUsingJavaRuntime(null); if (verbose) { logger.info("remove transpiler working dir: " + transpiler.getWorkingDirectory()); @@ -247,6 +252,7 @@ public void eval(ModuleKind moduleKind, boolean testBundle, } + @Override public void close() throws Exception { transpiler.close(); } diff --git a/typescript.java-ts.core/.gitignore b/typescript.java-ts.core/.gitignore new file mode 100644 index 000000000..b83d22266 --- /dev/null +++ b/typescript.java-ts.core/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/typescript.java-ts.core/LICENSE b/typescript.java-ts.core/LICENSE new file mode 100644 index 000000000..294706726 --- /dev/null +++ b/typescript.java-ts.core/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Angelo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/typescript.java-ts.core/README.md b/typescript.java-ts.core/README.md new file mode 100644 index 000000000..5979959d3 --- /dev/null +++ b/typescript.java-ts.core/README.md @@ -0,0 +1,9 @@ +# typescript.java ts.core, modified for jsweet + +This is a modified copy of [typescript.java](https://github.com/angelozerr/typescript.java)'s ts.core module. + +The source code has been reconstructed from the source jar available at https://repository.jsweet.org/artifactory/libs-release-local/org/jsweet/ext/typescript.java-ts.core/2.0.4/ since no other place could be found. + +## Licence + +The MIT License (MIT) diff --git a/typescript.java-ts.core/pom.xml b/typescript.java-ts.core/pom.xml new file mode 100644 index 000000000..38bd1c7a4 --- /dev/null +++ b/typescript.java-ts.core/pom.xml @@ -0,0 +1,141 @@ + + 4.0.0 + org.jsweet.ext + typescript.java-ts.core + jar + 2.0.4 + + ${maven.build.timestamp} + yyyy-MM-dd HH:mm:ss + UTF-8 + 11 + 1.${java.version.release} + + + src + + + src/main/resources + true + + + + + maven-compiler-plugin + 3.8.1 + + ${java.version.release} + ${java.version} + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.18.1 + + + **/*.java + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.0 + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + 1.8 + src + ${project.build.sourceEncoding} + ${skipJavadoc} + all + false + javadoc-out + javadoc-out/ts.core-${project.version} + + + + attach-javadocs + + jar + + + + + + + + + com.eclipsesource.minimal-json + minimal-json + 0.9.4 + + + com.google.code.gson + gson + 2.8.6 + + + org.tukaani + xz + 1.8 + + + org.osgi + org.osgi.core + 4.3.0 + provided + + + + + + + jsweet-central + libs-release + http://repository.jsweet.org/artifactory/libs-release-local + + + + jsweet-snapshots + libs-snapshot + http://repository.jsweet.org/artifactory/libs-snapshot-local + + + jsweet-external + libs-release + http://repository.jsweet.org/artifactory/ext-release-local + + + + + jsweet-release + libs-release + http://repository.jsweet.org/artifactory/libs-release-local + + + jsweet-snapshots + libs-snapshot + http://repository.jsweet.org/artifactory/libs-snapshot-local + + + diff --git a/typescript.java-ts.core/src/main/java/ts/OS.java b/typescript.java-ts.core/src/main/java/ts/OS.java new file mode 100644 index 000000000..cf78bf6d4 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/OS.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2016-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts; + +/** + * OS enumerations. + * + */ +public enum OS { + + Windows, MacOS, Linux; +} diff --git a/typescript.java-ts.core/src/main/java/ts/ScriptElementKind.java b/typescript.java-ts.core/src/main/java/ts/ScriptElementKind.java new file mode 100644 index 000000000..4dc6f4300 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/ScriptElementKind.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts; + +/** + * TypeScript model kind. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/services/types.ts + * + */ +public enum ScriptElementKind { + + ALIAS, PRIMITIVE_TYPE, KEYWORD, CLASS, INTERFACE, MODULE, SCRIPT, DIRECTORY, PROPERTY, METHOD, CONSTRUCTOR, FUNCTION, VAR, LET, ENUM, TYPE, ELEMENT, ATTRIBUTE, COMPONENT, CONST, GETTER, SETTER, WARNING; + + public static ScriptElementKind getKind(String kind) { + try { + return ScriptElementKind.valueOf(kind.toUpperCase()); + } catch (Exception e) { + return ScriptElementKind.WARNING; + } + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/ScriptElementKindModifier.java b/typescript.java-ts.core/src/main/java/ts/ScriptElementKindModifier.java new file mode 100644 index 000000000..28110c5e2 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/ScriptElementKindModifier.java @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * TypeScript model kind modifier. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/services/types.ts + * + */ +public enum ScriptElementKindModifier { + + none(""), publicMemberModifier("public"), privateMemberModifier("private"), protectedMemberModifier( + "protected"), exportedModifier( + "export"), ambientModifier("declare"), staticModifier("static"), abstractModifier("abstract"); + + private static final Map cache = Collections.unmodifiableMap(initializeCache()); + + private final String name; + + private ScriptElementKindModifier(String name) { + this.name = name; + } + + private static Map initializeCache() { + Map cache = new HashMap<>(); + ScriptElementKindModifier[] values = ScriptElementKindModifier.values(); + for (int i = 0; i < values.length; i++) { + ScriptElementKindModifier value = values[i]; + cache.put(value.getName(), value); + } + return cache; + } + + public String getName() { + return name; + } + + public static ScriptElementKindModifier getKindModifier(String modifier) { + return cache.get(modifier); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/TypeScriptException.java b/typescript.java-ts.core/src/main/java/ts/TypeScriptException.java new file mode 100644 index 000000000..1a3bb89a4 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/TypeScriptException.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts; + +/** + * TypeScript Exception. + * + */ +@SuppressWarnings("serial") +public class TypeScriptException extends Exception { + + public TypeScriptException(String message) { + super(message); + } + + public TypeScriptException(Throwable e) { + super(e); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/TypeScriptNoContentAvailableException.java b/typescript.java-ts.core/src/main/java/ts/TypeScriptNoContentAvailableException.java new file mode 100644 index 000000000..c08285bf3 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/TypeScriptNoContentAvailableException.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts; + +/** + * TypeScript exception thown when tsserver throws error "No content + * available." + * + */ +@SuppressWarnings("serial") +public class TypeScriptNoContentAvailableException extends TypeScriptException { + + public TypeScriptNoContentAvailableException(String message) { + super(message); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/CodeEdit.java b/typescript.java-ts.core/src/main/java/ts/client/CodeEdit.java new file mode 100644 index 000000000..f692c4e04 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/CodeEdit.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +/** + * Object found in response messages defining an editing instruction for a span + * of text in source code. The effect of this instruction is to replace the text + * starting at start and ending one character before end with newText. For an + * insertion, the text span is empty. For a deletion, newText is empty. + */ +public class CodeEdit { + + /** + * First character of the text span to edit. + */ + private Location start; + + /** + * One character past last character of the text span to edit. + */ + private Location end; + + /** + * Replace the span defined above with this string (may be the empty + * string). + */ + private String newText; + + /** + * Returns first character of the text span to edit. + * + * @return first character of the text span to edit. + */ + public Location getStart() { + return start; + } + + /** + * Returns one character past last character of the text span to edit. + * + * @return one character past last character of the text span to edit. + */ + public Location getEnd() { + return end; + } + + /** + * Replace the span defined above with this string (may be the empty string) + * + * @return replace the span defined above with this string (may be the empty + * string) + */ + public String getNewText() { + return newText; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/CommandCapability.java b/typescript.java-ts.core/src/main/java/ts/client/CommandCapability.java new file mode 100644 index 000000000..aa45b65ae --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/CommandCapability.java @@ -0,0 +1,26 @@ +package ts.client; + +import ts.utils.VersionHelper; + +public enum CommandCapability implements ISupportable { + + DiagnosticWithCategory("2.3.1"); + + private String sinceVersion; + + private CommandCapability(String version) { + this.sinceVersion = version; + } + + /** + * Return true if the tsc compiler option support the given version and + * false otherwise. + * + * @param version + * @return true if the tsc compiler option support the given version and + * false otherwise. + */ + public boolean canSupport(String version) { + return VersionHelper.canSupport(version, sinceVersion); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/CommandNames.java b/typescript.java-ts.core/src/main/java/ts/client/CommandNames.java new file mode 100644 index 000000000..64341fbb8 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/CommandNames.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +import ts.utils.VersionHelper; + +/** + * Command names of tsserver. + * + */ +public enum CommandNames implements ISupportable { + + Open("open"), + Close("close"), + Change("change"), + NavBar("navbar"), + Completions("completions"), + CompletionEntryDetails("completionEntryDetails"), + Reload("reload"), + Definition("definition"), + SignatureHelp("signatureHelp"), + QuickInfo("quickinfo"), + Geterr("geterr"), + GeterrForProject("geterrForProject"), + Format("format"), + References("references"), + Occurrences("occurrences"), + Configure("configure"), + ProjectInfo("projectInfo"), + Rename("rename"), + NavTo("navto"), + + // 2.0.0 + SemanticDiagnosticsSync("semanticDiagnosticsSync", "2.0.0"), + SyntacticDiagnosticsSync("syntacticDiagnosticsSync", "2.0.0"), + + // 2.0.5 + CompileOnSaveAffectedFileList("compileOnSaveAffectedFileList", "2.0.5"), + CompileOnSaveEmitFile("compileOnSaveEmitFile", "2.0.5"), + + // 2.0.6 + NavTree("navtree", "2.0.6"), + DocCommentTemplate("docCommentTemplate", "2.0.6"), + + // 2.1.0 + Implementation("implementation", "2.1.0"), + GetSupportedCodeFixes("getSupportedCodeFixes", "2.1.0"), + GetCodeFixes("getCodeFixes", "2.1.0"), + + // 2.4.0 + GetApplicableRefactors("getApplicableRefactors", "2.4.0"), + GetEditsForRefactor("getEditsForRefactor", "2.4.0"), + + OpenExternalProject("openExternalProject"), + CloseExternalProject("closeExternalProject"); + + private final String name; + private final String sinceVersion; + + private CommandNames(String name) { + this(name, null); + } + + private CommandNames(String name, String sinceVersion) { + this.name = name; + this.sinceVersion = sinceVersion; + } + + public String getName() { + return name; + } + + /** + * Return true if the tsserver command support the given version and false + * otherwise. + * + * @param version + * @return true if the tsserver command support the given version and false + * otherwise. + */ + public boolean canSupport(String version) { + return VersionHelper.canSupport(version, sinceVersion); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/Event.java b/typescript.java-ts.core/src/main/java/ts/client/Event.java new file mode 100644 index 000000000..34507183b --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/Event.java @@ -0,0 +1,29 @@ +package ts.client; + +import ts.internal.client.protocol.Message; + +/** + * Server-initiated event message + * + * @param + */ +public class Event extends Message { + + /** + * Name fo event. + */ + private String event; + + /** + * Event-specific information + */ + private T body; + + public String getEvent() { + return event; + } + + public T getBody() { + return body; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/ExternalFile.java b/typescript.java-ts.core/src/main/java/ts/client/ExternalFile.java new file mode 100644 index 000000000..705971c67 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/ExternalFile.java @@ -0,0 +1,29 @@ +package ts.client; + +public class ExternalFile { + /** + * Name of file file + */ + String fileName; + /** + * Script kind of the file + */ + ScriptKindName scriptKind; + /** + * Whether file has mixed content (i.e. .cshtml file that combines html markup + * with C#/JavaScript) + */ + Boolean hasMixedContent; + /** + * Content of the file + */ + String content; + + public ExternalFile(String fileName, ScriptKindName scriptKind, Boolean hasMixedContent, String content) { + this.fileName = fileName; + this.scriptKind = scriptKind; + this.hasMixedContent = hasMixedContent; + this.content = content; + } + +} \ No newline at end of file diff --git a/typescript.java-ts.core/src/main/java/ts/client/FileSpan.java b/typescript.java-ts.core/src/main/java/ts/client/FileSpan.java new file mode 100644 index 000000000..c2db635a6 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/FileSpan.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +/** + * Object found in response messages defining a span of text in a specific + * source file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class FileSpan extends TextSpan { + + /** + * File containing text span. + */ + private String file; + + public String getFile() { + return file; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/IInterceptor.java b/typescript.java-ts.core/src/main/java/ts/client/IInterceptor.java new file mode 100644 index 000000000..8a2a87e08 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/IInterceptor.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +import ts.internal.client.protocol.Response; +import ts.internal.client.protocol.Request; + +public interface IInterceptor { + + void handleRequest(Request request, String json, ITypeScriptServiceClient client); + + void handleResponse(Response response, String json, + long ellapsedTime, TypeScriptServiceClient typeScriptServiceClient); + + void handleError(Throwable error, ITypeScriptServiceClient client, String methodName, + long ellapsedTime); +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/IKindProvider.java b/typescript.java-ts.core/src/main/java/ts/client/IKindProvider.java new file mode 100644 index 000000000..495f1616a --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/IKindProvider.java @@ -0,0 +1,8 @@ +package ts.client; + +public interface IKindProvider { + + String getKind(); + + String getKindModifiers(); +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/IPositionProvider.java b/typescript.java-ts.core/src/main/java/ts/client/IPositionProvider.java new file mode 100644 index 000000000..0906e7043 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/IPositionProvider.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +import ts.TypeScriptException; + +/** + * Position provider. + * + */ +public interface IPositionProvider { + + /** + * Returns the location (line/offset) from the given position. + * + * @param position + * @return the location (line/offset) from the given position. + * @throws TypeScriptException + */ + Location getLocation(int position) throws TypeScriptException; + + /** + * Returns the position from the given line, offset. + * + * @param line + * @param offset + * @return the position from the given line, offset. + * @throws TypeScriptException + */ + int getPosition(int line, int offset) throws TypeScriptException; + + /** + * Returns the position from the given location (line/offset). + * + * @param loc + * @return the position from the given location (line/offset) + * @throws TypeScriptException + */ + int getPosition(Location loc) throws TypeScriptException; + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/ISupportable.java b/typescript.java-ts.core/src/main/java/ts/client/ISupportable.java new file mode 100644 index 000000000..456a571e6 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/ISupportable.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +/** + * Supportable API. + * + */ +public interface ISupportable { + + /** + * Returns true if the given tsserver command can be supported by the + * TypeScript version configured for the project and false otherwise. + * + * @param command + * @return true if the given tsserver command can be supported by the + * TypeScript version configured for the project and false + * otherwise. + */ + boolean canSupport(String version); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/ITypeScriptClientListener.java b/typescript.java-ts.core/src/main/java/ts/client/ITypeScriptClientListener.java new file mode 100644 index 000000000..623205fd1 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/ITypeScriptClientListener.java @@ -0,0 +1,18 @@ +package ts.client; + +public interface ITypeScriptClientListener { + + /** + * Method called when the given tsserver starts. + * + * @param server + */ + void onStart(ITypeScriptServiceClient client); + + /** + * Method called when the given tsserver stops. + * + * @param server + */ + void onStop(ITypeScriptServiceClient client); +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/ITypeScriptServiceClient.java b/typescript.java-ts.core/src/main/java/ts/client/ITypeScriptServiceClient.java new file mode 100644 index 000000000..0bd018417 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/ITypeScriptServiceClient.java @@ -0,0 +1,335 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import ts.TypeScriptException; +import ts.client.codefixes.CodeAction; +import ts.client.compileonsave.CompileOnSaveAffectedFileListSingleProject; +import ts.client.completions.CompletionEntry; +import ts.client.completions.CompletionEntryDetails; +import ts.client.completions.ICompletionEntryFactory; +import ts.client.configure.ConfigureRequestArguments; +import ts.client.diagnostics.DiagnosticEvent; +import ts.client.diagnostics.DiagnosticEventBody; +import ts.client.installtypes.IInstallTypesListener; +import ts.client.jsdoc.TextInsertion; +import ts.client.navbar.NavigationBarItem; +import ts.client.navto.NavtoItem; +import ts.client.occurrences.OccurrencesResponseItem; +import ts.client.projectinfo.ProjectInfo; +import ts.client.quickinfo.QuickInfo; +import ts.client.refactors.ApplicableRefactorInfo; +import ts.client.refactors.RefactorEditInfo; +import ts.client.references.ReferencesResponseBody; +import ts.client.rename.RenameResponseBody; +import ts.client.signaturehelp.SignatureHelpItems; +import ts.cmd.tsc.CompilerOptions; + +/** + * TypeScript client API which communicates with tsserver. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/client.ts + * + */ +public interface ITypeScriptServiceClient { + + /** + * Open the given file name. + * + * @param fileName + * @param content + * @throws TypeScriptException + */ + void openFile(String fileName, String content) throws TypeScriptException; + + /** + * Open the given file name. + * + * @param fileName + * @param content + * @param scriptKindName + * @throws TypeScriptException + */ + void openFile(String fileName, String content, ScriptKindName scriptKindName) throws TypeScriptException; + + /** + * Open an external project based on a project name and its files with explicit + * options + * + * @param projectFileName + * @param rootFiles + * @param options + * @throws TypeScriptException + */ + void openExternalProject(String projectFileName, List rootFiles, CompilerOptions options) + throws TypeScriptException; + + /** + * Closes a previously opened external project + * + * @see #openExternalProject(String, List, CompilerOptions) + * + * @param projectFileName + * @throws TypeScriptException + */ + void closeExternalProject(String projectFileName) throws TypeScriptException; + + /** + * Close the given file name. + * + * @param fileName + * @param content + * @throws TypeScriptException + */ + void closeFile(String fileName) throws TypeScriptException; + + /** + * Change file content at the given positions. + * + * @param fileName + * @param position + * @param endPosition + * @param insertString + * @throws TypeScriptException + */ + // void changeFile(String fileName, int position, int endPosition, String + // insertString) throws TypeScriptException; + + /** + * Change file content at the given lines/offsets. + * + * @param fileName + * @param line + * @param offset + * @param endLine + * @param endOffset + * @param insertString + * @throws TypeScriptException + */ + void changeFile(String fileName, int line, int offset, int endLine, int endOffset, String insertString) + throws TypeScriptException; + + void updateFile(String fileName, String newText) throws TypeScriptException; + + void updateFile(String fileName, String newText, long timeout, TimeUnit timeoutUnit) throws TypeScriptException; + + /** + * Completion for the given fileName at the given position. + * + * @param fileName + * @param position + * @return completion for the given fileName at the given position. + * @throws TypeScriptException + */ + // CompletableFuture> completions(String fileName, int + // position) throws TypeScriptException; + + /** + * Completion for the given fileName at the given line/offset. + * + * @param fileName + * @param line + * @param offset + * @return completion for the given fileName at the given line/offset + * @throws TypeScriptException + */ + CompletableFuture> completions(String fileName, int line, int offset) + throws TypeScriptException; + + CompletableFuture> completions(String name, int line, int offset, + ICompletionEntryFactory instanceCreator) throws TypeScriptException; + + CompletableFuture> completionEntryDetails(String fileName, int line, int offset, + String[] entryNames, CompletionEntry completionEntry) throws TypeScriptException; + + /** + * Definition for the given fileName at the given line/offset. + * + * @param fileName + * @param line + * @param offset + * @return + * @throws TypeScriptException + */ + CompletableFuture> definition(String fileName, int line, int offset) throws TypeScriptException; + + /** + * Signature help for the given fileName at the given line/offset. + * + * @param fileName + * @param line + * @param offset + * @return + * @throws TypeScriptException + */ + CompletableFuture signatureHelp(String fileName, int line, int offset) + throws TypeScriptException; + + /** + * Quick info for the given fileName at the given line/offset. + * + * @param fileName + * @param line + * @param offset + * @return + * @throws TypeScriptException + */ + CompletableFuture quickInfo(String fileName, int line, int offset) throws TypeScriptException; + + CompletableFuture> geterr(String[] files, int delay) throws TypeScriptException; + + CompletableFuture> geterrForProject(String file, int delay, ProjectInfo projectInfo) + throws TypeScriptException; + + /** + * Format for the given fileName at the given line/offset. + * + * @param fileName + * @param line + * @param offset + * @param endLine + * @param endOffset + * @return + * @throws TypeScriptException + */ + CompletableFuture> format(String fileName, int line, int offset, int endLine, int endOffset) + throws TypeScriptException; + + /** + * Find references for the given fileName at the given line/offset. + * + * @param fileName + * @param line + * @param offset + * @return + * @throws TypeScriptException + */ + CompletableFuture references(String fileName, int line, int offset) + throws TypeScriptException; + + /** + * Find occurrences for the given fileName at the given line/offset. + * + * @param fileName + * @param line + * @param offset + * @return + * @throws TypeScriptException + */ + CompletableFuture> occurrences(String fileName, int line, int offset) + throws TypeScriptException; + + CompletableFuture rename(String file, int line, int offset, Boolean findInComments, + Boolean findInStrings) throws TypeScriptException; + + CompletableFuture> navto(String fileName, String searchValue, Integer maxResultCount, + Boolean currentFileOnly, String projectFileName) throws TypeScriptException; + + CompletableFuture> navbar(String fileName, IPositionProvider positionProvider) + throws TypeScriptException; + + void configure(ConfigureRequestArguments arguments) throws TypeScriptException; + + CompletableFuture projectInfo(String file, String projectFileName, boolean needFileNameList) + throws TypeScriptException; + + // Since 2.0.3 + + /** + * Execute semantic diagnostics for the given file. + * + * @param includeLinePosition + * @return + * @throws TypeScriptException + */ + CompletableFuture semanticDiagnosticsSync(String file, Boolean includeLinePosition) + throws TypeScriptException; + + /** + * Execute syntactic diagnostics for the given file. + * + * @param includeLinePosition + * @return + * @throws TypeScriptException + */ + CompletableFuture syntacticDiagnosticsSync(String file, Boolean includeLinePosition) + throws TypeScriptException; + + // Since 2.0.5 + + CompletableFuture compileOnSaveEmitFile(String fileName, Boolean forced) throws TypeScriptException; + + CompletableFuture> compileOnSaveAffectedFileList(String fileName) + throws TypeScriptException; + + // Since 2.0.6 + + CompletableFuture navtree(String fileName, IPositionProvider positionProvider) + throws TypeScriptException; + + CompletableFuture docCommentTemplate(String fileName, int line, int offset) + throws TypeScriptException; + + // Since 2.1.0 + + CompletableFuture> getCodeFixes(String fileName, IPositionProvider positionProvider, int startLine, + int startOffset, int endLine, int endOffset, List errorCodes) throws TypeScriptException; + + CompletableFuture> getSupportedCodeFixes() throws TypeScriptException; + + /** + * Definition for the given fileName at the given line/offset. + * + * @param fileName + * @param line + * @param offset + * @return + * @throws TypeScriptException + */ + CompletableFuture> implementation(String fileName, int line, int offset) throws TypeScriptException; + + // Since 2.4.0 + + CompletableFuture> getApplicableRefactors(String fileName, int line, int offset) + throws TypeScriptException; + + CompletableFuture> getApplicableRefactors(String fileName, int startLine, + int startOffset, int endLine, int endOffset) throws TypeScriptException; + + CompletableFuture getEditsForRefactor(String fileName, int line, int offset, String refactor, + String action) throws TypeScriptException; + + CompletableFuture getEditsForRefactor(String fileName, int startLine, int startOffset, + int endLine, int endOffset, String refactor, String action) throws TypeScriptException; + + void addClientListener(ITypeScriptClientListener listener); + + void removeClientListener(ITypeScriptClientListener listener); + + void addInstallTypesListener(IInstallTypesListener listener); + + void removeInstallTypesListener(IInstallTypesListener listener); + + void addInterceptor(IInterceptor interceptor); + + void removeInterceptor(IInterceptor interceptor); + + void join() throws InterruptedException; + + boolean isDisposed(); + + void dispose(); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/Location.java b/typescript.java-ts.core/src/main/java/ts/client/Location.java new file mode 100644 index 000000000..d46597e4d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/Location.java @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +import ts.TypeScriptException; + +/** + * Bean for location line/offset used by tsserver. + * + */ +public class Location { + + private static final int NO_POSITION = -1; + + private final IPositionProvider positionProvider; + private int line; + private int offset; + private int position; + + public Location(IPositionProvider positionProvider) { + this.positionProvider = positionProvider; + this.position = NO_POSITION; + } + + public Location() { + this(null); + } + + public Location(int line, int offset, int position) { + this(); + this.line = line; + this.offset = offset; + this.position = position; + } + + public Location(int line, int offset) { + this(line, offset, NO_POSITION); + } + + /** + * Returns the line location. + * + * @return the line location. + */ + public int getLine() { + return line; + } + + /** + * Returns the offset location. + * + * @return the offset location. + */ + public int getOffset() { + return offset; + } + + public int getPosition() { + if (position == NO_POSITION && positionProvider != null) { + try { + position = positionProvider.getPosition(line, offset); + } catch (TypeScriptException e) { + e.printStackTrace(); + } + } + return position; + } + + public void setPosition(int position) { + this.position = position; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/LoggingInterceptor.java b/typescript.java-ts.core/src/main/java/ts/client/LoggingInterceptor.java new file mode 100644 index 000000000..bf557e38b --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/LoggingInterceptor.java @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +import ts.internal.client.protocol.Request; +import ts.internal.client.protocol.Response; + +public class LoggingInterceptor implements IInterceptor { + + private static final IInterceptor INSTANCE = new LoggingInterceptor(); + + public static IInterceptor getInstance() { + return INSTANCE; + } + + @Override + public void handleRequest(Request request, String json, ITypeScriptServiceClient client) { + outPrintln("-----------------------------------"); + outPrintln("TypeScript request#" + request.getCommand() + ": "); + outPrintln(json); + } + + @Override + public void handleResponse(Response response, String json, long ellapsedTime, + TypeScriptServiceClient typeScriptServiceClient) { + outPrintln(""); + outPrintln("TypeScript response#" + response.getCommand() + " with " + ellapsedTime + "ms: "); + outPrintln(json); + outPrintln("-----------------------------------"); + } + + @Override + public void handleError(Throwable error, ITypeScriptServiceClient server, String methodName, long ellapsedTime) { + errPrintln(""); + errPrintln("TypeScript error#" + methodName + " with " + ellapsedTime + "ms: "); + printStackTrace(error); + errPrintln("-----------------------------------"); + } + + protected void outPrintln(String line) { + System.out.println(line); + } + + protected void errPrintln(String line) { + System.err.println(line); + } + + protected void printStackTrace(Throwable error) { + error.printStackTrace(System.err); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/ScriptKindName.java b/typescript.java-ts.core/src/main/java/ts/client/ScriptKindName.java new file mode 100644 index 000000000..12999be06 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/ScriptKindName.java @@ -0,0 +1,6 @@ +package ts.client; + +public enum ScriptKindName { + + TS ,JS ,TSX ,JSX +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/TextSpan.java b/typescript.java-ts.core/src/main/java/ts/client/TextSpan.java new file mode 100644 index 000000000..038d481f8 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/TextSpan.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +import ts.TypeScriptException; + +/** + * Object found in response messages defining a span of text in source code. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class TextSpan { + + /** + * First character of the definition. + */ + private Location start; + + /** + * One character past last character of the definition. + */ + private Location end; + + public Location getStart() { + return start; + } + + public Location getEnd() { + return end; + } + + public boolean contains(int position) throws TypeScriptException { + int positionStart = start.getPosition(); + return positionStart <= position && position < (positionStart + getLength()); + } + + public int getLength() throws TypeScriptException { + int positionStart = start.getPosition(); + int positionEnd = end.getPosition(); + return positionEnd - positionStart; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/TypeScriptServerAdapter.java b/typescript.java-ts.core/src/main/java/ts/client/TypeScriptServerAdapter.java new file mode 100644 index 000000000..eb7654635 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/TypeScriptServerAdapter.java @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +/** + * This adapter class provides default implementations for the methods described + * by the {@link ITypeScriptClientListener} interface. + * + * Classes that wish to deal with event can extend this class and override only + * the methods which they are interested in. + * + */ +public class TypeScriptServerAdapter implements ITypeScriptClientListener { + + @Override + public void onStart(ITypeScriptServiceClient server) { + + } + + @Override + public void onStop(ITypeScriptServiceClient server) { + + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/TypeScriptServiceClient.java b/typescript.java-ts.core/src/main/java/ts/client/TypeScriptServiceClient.java new file mode 100644 index 000000000..28bc9b4d1 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/TypeScriptServiceClient.java @@ -0,0 +1,934 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Consumer; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import ts.TypeScriptException; +import ts.TypeScriptNoContentAvailableException; +import ts.client.codefixes.CodeAction; +import ts.client.compileonsave.CompileOnSaveAffectedFileListSingleProject; +import ts.client.completions.CompletionEntry; +import ts.client.completions.CompletionEntryDetails; +import ts.client.completions.ICompletionEntryFactory; +import ts.client.completions.ICompletionEntryMatcherProvider; +import ts.client.configure.ConfigureRequestArguments; +import ts.client.diagnostics.DiagnosticEvent; +import ts.client.diagnostics.DiagnosticEventBody; +import ts.client.diagnostics.IDiagnostic; +import ts.client.installtypes.BeginInstallTypesEventBody; +import ts.client.installtypes.EndInstallTypesEventBody; +import ts.client.installtypes.IInstallTypesListener; +import ts.client.jsdoc.TextInsertion; +import ts.client.navbar.NavigationBarItem; +import ts.client.navto.NavtoItem; +import ts.client.occurrences.OccurrencesResponseItem; +import ts.client.projectinfo.ProjectInfo; +import ts.client.quickinfo.QuickInfo; +import ts.client.refactors.ApplicableRefactorInfo; +import ts.client.refactors.RefactorEditInfo; +import ts.client.references.ReferencesResponseBody; +import ts.client.rename.RenameResponseBody; +import ts.client.signaturehelp.SignatureHelpItems; +import ts.cmd.tsc.CompilerOptions; +import ts.internal.FileTempHelper; +import ts.internal.SequenceHelper; +import ts.internal.client.protocol.ChangeRequest; +import ts.internal.client.protocol.CloseExternalProjectRequest; +import ts.internal.client.protocol.CloseRequest; +import ts.internal.client.protocol.CodeFixRequest; +import ts.internal.client.protocol.CompileOnSaveAffectedFileListRequest; +import ts.internal.client.protocol.CompileOnSaveEmitFileRequest; +import ts.internal.client.protocol.CompletionDetailsRequest; +import ts.internal.client.protocol.CompletionsRequest; +import ts.internal.client.protocol.ConfigureRequest; +import ts.internal.client.protocol.DefinitionRequest; +import ts.internal.client.protocol.DocCommentTemplateRequest; +import ts.internal.client.protocol.FormatRequest; +import ts.internal.client.protocol.GetApplicableRefactorsRequest; +import ts.internal.client.protocol.GetEditsForRefactorRequest; +import ts.internal.client.protocol.GetSupportedCodeFixesRequest; +import ts.internal.client.protocol.GeterrForProjectRequest; +import ts.internal.client.protocol.GeterrRequest; +import ts.internal.client.protocol.GsonHelper; +import ts.internal.client.protocol.IRequestEventable; +import ts.internal.client.protocol.ImplementationRequest; +import ts.internal.client.protocol.MessageType; +import ts.internal.client.protocol.NavBarRequest; +import ts.internal.client.protocol.NavToRequest; +import ts.internal.client.protocol.NavTreeRequest; +import ts.internal.client.protocol.OccurrencesRequest; +import ts.internal.client.protocol.OpenExternalProjectRequest; +import ts.internal.client.protocol.OpenRequest; +import ts.internal.client.protocol.ProjectInfoRequest; +import ts.internal.client.protocol.QuickInfoRequest; +import ts.internal.client.protocol.ReferencesRequest; +import ts.internal.client.protocol.ReloadRequest; +import ts.internal.client.protocol.RenameRequest; +import ts.internal.client.protocol.Request; +import ts.internal.client.protocol.Response; +import ts.internal.client.protocol.SemanticDiagnosticsSyncRequest; +import ts.internal.client.protocol.SignatureHelpRequest; +import ts.internal.client.protocol.SyntacticDiagnosticsSyncRequest; +import ts.nodejs.INodejsLaunchConfiguration; +import ts.nodejs.INodejsProcess; +import ts.nodejs.INodejsProcessListener; +import ts.nodejs.NodejsProcess; +import ts.nodejs.NodejsProcessAdapter; +import ts.nodejs.NodejsProcessManager; +import ts.repository.TypeScriptRepositoryManager; +import ts.utils.FileUtils; + +/** + * TypeScript service client implementation. + * + */ +public class TypeScriptServiceClient implements ITypeScriptServiceClient { + + private static final String NO_CONTENT_AVAILABLE = "No content available."; + private static final String TSSERVER_FILE_TYPE = "tsserver"; + + private INodejsProcess process; + private List nodeListeners; + private final List listeners; + private final List installTypesListener; + private final ReentrantReadWriteLock stateLock; + private boolean dispose; + + private final Map sentRequestMap; + private final Map receivedRequestMap; + private List interceptors; + + private ICompletionEntryMatcherProvider completionEntryMatcherProvider; + + private final INodejsProcessListener listener = new NodejsProcessAdapter() { + + @Override + public void onStart(INodejsProcess process) { + TypeScriptServiceClient.this.fireStartServer(); + } + + @Override + public void onStop(INodejsProcess process) { + dispose(); + fireEndServer(); + } + + public void onMessage(INodejsProcess process, String message) { + if (message.startsWith("{")) { + TypeScriptServiceClient.this.dispatchMessage(message); + } + }; + + }; + private String cancellationPipeName; + + private static class PendingRequestInfo { + Request requestMessage; + Consumer> responseHandler; + long startTime; + + PendingRequestInfo(Request requestMessage, Consumer> responseHandler) { + this.requestMessage = requestMessage; + this.responseHandler = responseHandler; + this.startTime = System.nanoTime(); + } + } + + private static class PendingRequestEventInfo { + Request requestMessage; + Consumer> eventHandler; + long startTime; + + PendingRequestEventInfo(Request requestMessage, Consumer> eventHandler) { + this.requestMessage = requestMessage; + this.eventHandler = eventHandler; + this.startTime = System.nanoTime(); + } + } + + public TypeScriptServiceClient(final File projectDir, File tsserverFile, File nodeFile) throws TypeScriptException { + this(projectDir, tsserverFile, nodeFile, false, false, null, null, null); + } + + public TypeScriptServiceClient(final File projectDir, File typescriptDir, File nodeFile, boolean enableTelemetry, + boolean disableAutomaticTypingAcquisition, String cancellationPipeName, File tsserverPluginsFile, + TypeScriptServiceLogConfiguration logConfiguration) throws TypeScriptException { + this(NodejsProcessManager.getInstance().create(projectDir, + tsserverPluginsFile != null ? tsserverPluginsFile + : TypeScriptRepositoryManager.getTsserverFile(typescriptDir), + nodeFile, new INodejsLaunchConfiguration() { + + @Override + public List createNodeArgs() { + List args = new ArrayList(); + // args.add("-p"); + // args.add(FileUtils.getPath(projectDir)); + if (enableTelemetry) { + args.add("--enableTelemetry"); + } + if (disableAutomaticTypingAcquisition) { + args.add("--disableAutomaticTypingAcquisition"); + } + if (tsserverPluginsFile != null) { + args.add("--typescriptDir"); + args.add(FileUtils.getPath(typescriptDir)); + } + if (cancellationPipeName != null) { + args.add("--cancellationPipeName"); + args.add(cancellationPipeName + "*"); + } + // args.add("--useSingleInferredProject"); + return args; + } + + @Override + public Map createNodeEnvironmentVariables() { + Map environmentVariables = new HashMap<>(); + if (logConfiguration != null) { + environmentVariables.put("TSS_LOG", + "-level " + logConfiguration.level.name() + " -file " + logConfiguration.file); + } + return environmentVariables; + } + }, TSSERVER_FILE_TYPE), cancellationPipeName); + } + + public TypeScriptServiceClient(INodejsProcess process, String cancellationPipeName) { + this.listeners = new ArrayList<>(); + this.installTypesListener = new ArrayList<>(); + this.stateLock = new ReentrantReadWriteLock(); + this.dispose = false; + this.sentRequestMap = new LinkedHashMap<>(); + this.receivedRequestMap = new LinkedHashMap<>(); + this.process = process; + process.addProcessListener(listener); + setCompletionEntryMatcherProvider(ICompletionEntryMatcherProvider.LCS_PROVIDER); + this.cancellationPipeName = cancellationPipeName; + } + + public static enum TypeScriptServiceLogLevel { + verbose, normal, terse, requestTime + } + + public static class TypeScriptServiceLogConfiguration { + String file; + TypeScriptServiceLogLevel level; + + public TypeScriptServiceLogConfiguration(String file, TypeScriptServiceLogLevel level) { + this.file = file; + this.level = level; + } + } + + private void dispatchMessage(String message) { + JsonObject json = GsonHelper.parse(message).getAsJsonObject(); + JsonElement typeElement = json.get("type"); + if (typeElement != null) { + MessageType messageType = MessageType.getType(typeElement.getAsString()); + if (messageType == null) { + throw new IllegalStateException("Unknown response type message " + json); + } + switch (messageType) { + case response: + int seq = json.get("request_seq").getAsInt(); + PendingRequestInfo pendingRequestInfo; + synchronized (sentRequestMap) { + pendingRequestInfo = sentRequestMap.remove(seq); + } + if (pendingRequestInfo == null) { + // throw new IllegalStateException("Unmatched response + // message " + json); + return; + } + Response responseMessage = pendingRequestInfo.requestMessage.parseResponse(json); + try { + handleResponse(responseMessage, message, pendingRequestInfo.startTime); + pendingRequestInfo.responseHandler.accept(responseMessage); + } catch (RuntimeException e) { + // LOG.log(Level.WARNING, "Handling repsonse + // "+responseMessage+" threw an exception.", e); + } + + break; + case event: + String event = json.get("event").getAsString(); + if ("syntaxDiag".equals(event) || "semanticDiag".equals(event)) { + DiagnosticEvent response = GsonHelper.DEFAULT_GSON.fromJson(json, DiagnosticEvent.class); + PendingRequestEventInfo pendingRequestEventInfo; + synchronized (receivedRequestMap) { + pendingRequestEventInfo = receivedRequestMap.remove(response.getKey()); + } + if (pendingRequestEventInfo != null) { + pendingRequestEventInfo.eventHandler.accept(response); + } + } else if ("telemetry".equals(event)) { + // TelemetryEventBody telemetryData = + // GsonHelper.DEFAULT_GSON.fromJson(json, + // TelemetryEvent.class) + // .getBody(); + // + JsonObject telemetryData = json.get("body").getAsJsonObject(); + JsonObject payload = telemetryData.has("payload") ? telemetryData.get("payload").getAsJsonObject() + : null; + if (payload != null) { + String telemetryEventName = telemetryData.get("telemetryEventName").getAsString(); + fireLogTelemetry(telemetryEventName, payload); + } + } else if ("beginInstallTypes".equals(event)) { + BeginInstallTypesEventBody data = GsonHelper.DEFAULT_GSON.fromJson(json, + BeginInstallTypesEventBody.class); + fireBeginInstallTypes(data); + } else if ("endInstallTypes".equals(event)) { + EndInstallTypesEventBody data = GsonHelper.DEFAULT_GSON.fromJson(json, + EndInstallTypesEventBody.class); + fireEndInstallTypes(data); + } + break; + default: + // Do nothing + } + } + } + + @Override + public void openFile(String fileName, String content) throws TypeScriptException { + openFile(fileName, content, null); + } + + @Override + public void openFile(String fileName, String content, ScriptKindName scriptKindName) throws TypeScriptException { + execute(new OpenRequest(fileName, null, content, scriptKindName), false); + } + + @Override + public void openExternalProject(String projectFileName, List rootFiles, CompilerOptions options) + throws TypeScriptException { + execute(new OpenExternalProjectRequest(projectFileName, rootFiles, options), false); + } + + @Override + public void closeExternalProject(String projectFileName) throws TypeScriptException { + execute(new CloseExternalProjectRequest(projectFileName), false); + } + + @Override + public void closeFile(String fileName) throws TypeScriptException { + execute(new CloseRequest(fileName), false); + } + + @Override + public void changeFile(String fileName, int line, int offset, int endLine, int endOffset, String insertString) + throws TypeScriptException { + execute(new ChangeRequest(fileName, line, offset, endLine, endOffset, insertString), false); + } + + /** + * Write the buffer of editor content to a temporary file and have the server + * reload it + * + * @param fileName + * @param newText + */ + @Override + public void updateFile(String fileName, String newText) throws TypeScriptException { + updateFile(fileName, newText,10,TimeUnit.SECONDS); + } + /** + * Write the buffer of editor content to a temporary file and have the server + * reload it + * + * @param fileName + * @param newText + * @param timeout + * @param timeoutUnit + */ + @Override + public void updateFile(String fileName, String newText, long timeout, TimeUnit timeoutUnit) throws TypeScriptException { + int seq = SequenceHelper.getRequestSeq(); + String tempFileName = null; + if (newText != null) { + tempFileName = FileTempHelper.updateTempFile(newText, seq); + } + try { + execute(new ReloadRequest(fileName, tempFileName, seq), true).get(timeout, timeoutUnit); + } catch (Exception e) { + if (e instanceof TypeScriptException) { + throw (TypeScriptException) e; + } + throw new TypeScriptException(e); + } + } + + @Override + public CompletableFuture> completions(String fileName, int line, int offset) + throws TypeScriptException { + return completions(fileName, line, offset, ICompletionEntryFactory.DEFAULT); + } + + @Override + public CompletableFuture> completions(String fileName, int line, int offset, + ICompletionEntryFactory factory) throws TypeScriptException { + return execute( + new CompletionsRequest(fileName, line, offset, getCompletionEntryMatcherProvider(), this, factory), + true); + } + + @Override + public CompletableFuture> completionEntryDetails(String fileName, int line, int offset, + String[] entryNames, CompletionEntry completionEntry) throws TypeScriptException { + return execute(new CompletionDetailsRequest(fileName, line, offset, null, entryNames), true); + } + + @Override + public CompletableFuture> definition(String fileName, int line, int offset) + throws TypeScriptException { + return execute(new DefinitionRequest(fileName, line, offset), true); + } + + @Override + public CompletableFuture signatureHelp(String fileName, int line, int offset) + throws TypeScriptException { + return execute(new SignatureHelpRequest(fileName, line, offset), true); + } + + @Override + public CompletableFuture quickInfo(String fileName, int line, int offset) throws TypeScriptException { + return execute(new QuickInfoRequest(fileName, line, offset), true); + } + + @Override + public CompletableFuture> geterr(String[] files, int delay) throws TypeScriptException { + return execute(new GeterrRequest(files, delay), true); + } + + @Override + public CompletableFuture> geterrForProject(String file, int delay, ProjectInfo projectInfo) + throws TypeScriptException { + return execute(new GeterrForProjectRequest(file, delay, projectInfo), true); + } + + @Override + public CompletableFuture> format(String fileName, int line, int offset, int endLine, int endOffset) + throws TypeScriptException { + return execute(new FormatRequest(fileName, line, offset, endLine, endOffset), true); + } + + @Override + public CompletableFuture references(String fileName, int line, int offset) + throws TypeScriptException { + return execute(new ReferencesRequest(fileName, line, offset), true); + } + + @Override + public CompletableFuture> occurrences(String fileName, int line, int offset) + throws TypeScriptException { + return execute(new OccurrencesRequest(fileName, line, offset), true); + } + + @Override + public CompletableFuture rename(String file, int line, int offset, Boolean findInComments, + Boolean findInStrings) throws TypeScriptException { + return execute(new RenameRequest(file, line, offset, findInComments, findInStrings), true); + } + + @Override + public CompletableFuture> navto(String fileName, String searchValue, Integer maxResultCount, + Boolean currentFileOnly, String projectFileName) throws TypeScriptException { + return execute(new NavToRequest(fileName, searchValue, maxResultCount, currentFileOnly, projectFileName), true); + } + + @Override + public CompletableFuture> navbar(String fileName, IPositionProvider positionProvider) + throws TypeScriptException { + return execute(new NavBarRequest(fileName, positionProvider), true); + } + + @Override + public void configure(ConfigureRequestArguments arguments) throws TypeScriptException { + execute(new ConfigureRequest(arguments), true); + } + + @Override + public CompletableFuture projectInfo(String file, String projectFileName, boolean needFileNameList) + throws TypeScriptException { + return execute(new ProjectInfoRequest(file, needFileNameList), true); + } + + // Since 2.0.3 + + @Override + public CompletableFuture semanticDiagnosticsSync(String file, Boolean includeLinePosition) + throws TypeScriptException { + return execute(new SemanticDiagnosticsSyncRequest(file, includeLinePosition), true).thenApply(d -> { + return new DiagnosticEventBody(file, (List) d); + }); + } + + @Override + public CompletableFuture syntacticDiagnosticsSync(String file, Boolean includeLinePosition) + throws TypeScriptException { + return execute(new SyntacticDiagnosticsSyncRequest(file, includeLinePosition), true).thenApply(d -> { + return new DiagnosticEventBody(file, (List) d); + }); + } + + // Since 2.0.5 + + @Override + public CompletableFuture compileOnSaveEmitFile(String fileName, Boolean forced) + throws TypeScriptException { + return execute(new CompileOnSaveEmitFileRequest(fileName, forced), true); + } + + @Override + public CompletableFuture> compileOnSaveAffectedFileList( + String fileName) throws TypeScriptException { + return execute(new CompileOnSaveAffectedFileListRequest(fileName), true); + } + + // Since 2.0.6 + + @Override + public CompletableFuture navtree(String fileName, IPositionProvider positionProvider) + throws TypeScriptException { + return execute(new NavTreeRequest(fileName, positionProvider), true); + } + + @Override + public CompletableFuture docCommentTemplate(String fileName, int line, int offset) + throws TypeScriptException { + return execute(new DocCommentTemplateRequest(fileName, line, offset), true); + } + + // Since 2.1.0 + + @Override + public CompletableFuture> getCodeFixes(String fileName, IPositionProvider positionProvider, + int startLine, int startOffset, int endLine, int endOffset, List errorCodes) + throws TypeScriptException { + return execute(new CodeFixRequest(fileName, startLine, startOffset, endLine, endOffset, errorCodes), true); + } + + @Override + public CompletableFuture> getSupportedCodeFixes() throws TypeScriptException { + return execute(new GetSupportedCodeFixesRequest(), true); + } + + @Override + public CompletableFuture> implementation(String fileName, int line, int offset) + throws TypeScriptException { + return execute(new ImplementationRequest(fileName, line, offset), true); + } + + // Since 2.4.0 + + @Override + public CompletableFuture> getApplicableRefactors(String fileName, int line, int offset) + throws TypeScriptException { + return execute(new GetApplicableRefactorsRequest(fileName, line, offset), true); + } + + @Override + public CompletableFuture> getApplicableRefactors(String fileName, int startLine, + int startOffset, int endLine, int endOffset) throws TypeScriptException { + return execute(new GetApplicableRefactorsRequest(fileName, startLine, startOffset, endLine, endOffset), true); + } + + @Override + public CompletableFuture getEditsForRefactor(String fileName, int line, int offset, + String refactor, String action) throws TypeScriptException { + return execute(new GetEditsForRefactorRequest(fileName, line, offset, refactor, action), true); + } + + @Override + public CompletableFuture getEditsForRefactor(String fileName, int startLine, int startOffset, + int endLine, int endOffset, String refactor, String action) throws TypeScriptException { + return execute( + new GetEditsForRefactorRequest(fileName, startLine, startOffset, endLine, endOffset, refactor, action), + true); + } + + private CompletableFuture execute(Request request, boolean expectsResult) throws TypeScriptException { + if (!expectsResult) { + sendRequest(request); + return null; + } + final CompletableFuture result = new CompletableFuture() { + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + tryCancelRequest(request); + return super.cancel(mayInterruptIfRunning); + } + + /** + * Try to cancel the given request: + * + *
    + *
  • on client side : remove request from the received request queue.
  • + *
  • on server side (tsserver) : cancel the request.
  • + *
+ * + * @param request + */ + private void tryCancelRequest(Request request) { + try { + cancelServerRequest(request); + } finally { + cancelClientRequest(request); + } + } + + private void cancelClientRequest(Request request) { + if (request instanceof IRequestEventable) { + List keys = ((IRequestEventable) request).getKeys(); + synchronized (receivedRequestMap) { + for (String key : keys) { + receivedRequestMap.remove(key); + } + } + } else { + synchronized (sentRequestMap) { + sentRequestMap.remove(request.getSeq()); + } + } + } + + private void cancelServerRequest(Request request) { + // Generate en empty file in the temp directory (ex: + // $TMP_DIR/eclipse-tscancellation-4df2438b-ca7a-4ef3-9a46-83e8afef61b3.sock844 + // where 844 is request sequence) + // for the given request sequence waited by tsserver + // typescript/lib/cancellationToken.js. + // to cancel request from tsserver. + if (cancellationPipeName != null) { + File tempFile = new File(TypeScriptServiceClient.this.cancellationPipeName + request.getSeq()); + try { + tempFile.createNewFile(); + tempFile.deleteOnExit(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + }; + if (request instanceof IRequestEventable) { + Consumer> responseHandler = (event) -> { + if (((IRequestEventable) request).accept(event)) { + result.complete((T) ((IRequestEventable) request).getEvents()); + } + }; + List keys = ((IRequestEventable) request).getKeys(); + PendingRequestEventInfo info = new PendingRequestEventInfo(request, responseHandler); + synchronized (receivedRequestMap) { + for (String key : keys) { + receivedRequestMap.put(key, info); + } + } + } else { + Consumer> responseHandler = (response) -> { + if (response.isSuccess()) { + // tsserver response with success + result.complete((T) response.getBody()); + } else { + // tsserver response with error + result.completeExceptionally(createException(response.getMessage())); + } + }; + int seq = request.getSeq(); + synchronized (sentRequestMap) { + sentRequestMap.put(seq, new PendingRequestInfo(request, responseHandler)); + } + } + sendRequest(request); + return result; + } + + private TypeScriptException createException(String message) { + if (NO_CONTENT_AVAILABLE.equals(message)) { + return new TypeScriptNoContentAvailableException(message); + } + return new TypeScriptException(message); + } + + private void sendRequest(Request request) throws TypeScriptException { + String req = GsonHelper.DEFAULT_GSON.toJson(request); + handleRequest(request, req); + getProcess().sendRequest(req); + } + + private INodejsProcess getProcess() throws TypeScriptException { + if (process == null) { + throw new RuntimeException("unexpected error: process was stopped/killed before trying to use it again"); + } + + if (!process.isStarted()) { + process.start(); + } + return process; + } + + @Override + public void addClientListener(ITypeScriptClientListener listener) { + synchronized (listeners) { + listeners.add(listener); + } + } + + @Override + public void removeClientListener(ITypeScriptClientListener listener) { + synchronized (listeners) { + listeners.remove(listener); + } + } + + private void fireStartServer() { + synchronized (listeners) { + for (ITypeScriptClientListener listener : listeners) { + listener.onStart(this); + } + } + } + + private void fireEndServer() { + synchronized (listeners) { + for (ITypeScriptClientListener listener : listeners) { + listener.onStop(this); + } + } + } + + @Override + public void addInstallTypesListener(IInstallTypesListener listener) { + synchronized (installTypesListener) { + installTypesListener.add(listener); + } + } + + @Override + public void removeInstallTypesListener(IInstallTypesListener listener) { + synchronized (installTypesListener) { + installTypesListener.remove(listener); + } + } + + private void fireBeginInstallTypes(BeginInstallTypesEventBody body) { + synchronized (installTypesListener) { + for (IInstallTypesListener listener : installTypesListener) { + listener.onBegin(body); + } + } + } + + private void fireEndInstallTypes(EndInstallTypesEventBody body) { + synchronized (installTypesListener) { + for (IInstallTypesListener listener : installTypesListener) { + listener.onEnd(body); + } + } + } + + private void fireLogTelemetry(String telemetryEventName, JsonObject payload) { + synchronized (installTypesListener) { + for (IInstallTypesListener listener : installTypesListener) { + listener.logTelemetry(telemetryEventName, payload); + } + } + } + + @Override + public void addInterceptor(IInterceptor interceptor) { + beginWriteState(); + try { + if (interceptors == null) { + interceptors = new ArrayList(); + } + interceptors.add(interceptor); + } finally { + endWriteState(); + } + } + + @Override + public void removeInterceptor(IInterceptor interceptor) { + beginWriteState(); + try { + if (interceptors != null) { + interceptors.remove(interceptor); + } + } finally { + endWriteState(); + } + } + + public void addProcessListener(INodejsProcessListener listener) { + beginWriteState(); + try { + if (nodeListeners == null) { + nodeListeners = new ArrayList(); + } + nodeListeners.add(listener); + if (process != null) { + process.addProcessListener(listener); + } + } finally { + endWriteState(); + } + } + + public void removeProcessListener(INodejsProcessListener listener) { + beginWriteState(); + try { + if (nodeListeners != null && listener != null) { + nodeListeners.remove(listener); + } + if (process != null) { + process.removeProcessListener(listener); + } + } finally { + endWriteState(); + } + } + + @Override + public void join() throws InterruptedException { + if (process != null) { + this.process.join(); + } + } + + @Override + public boolean isDisposed() { + return dispose; + } + + @Override + public final void dispose() { + beginWriteState(); + try { + if (!isDisposed()) { + this.dispose = true; + System.out.println("dispose client - process=" + process); + if (NodejsProcess.logProcessStopStack) { + Thread.dumpStack(); + } + if (process != null) { + process.kill(); + } + this.process = null; + } + } finally { + endWriteState(); + } + } + + private void beginReadState() { + stateLock.readLock().lock(); + } + + private void endReadState() { + stateLock.readLock().unlock(); + } + + private void beginWriteState() { + stateLock.writeLock().lock(); + } + + private void endWriteState() { + stateLock.writeLock().unlock(); + } + + public void setCompletionEntryMatcherProvider(ICompletionEntryMatcherProvider completionEntryMatcherProvider) { + this.completionEntryMatcherProvider = completionEntryMatcherProvider; + } + + public ICompletionEntryMatcherProvider getCompletionEntryMatcherProvider() { + return completionEntryMatcherProvider; + } + + // --------------------------- Handler for Request/response/Error + // ------------------------------------ + + /** + * Handle the given request. + * + * @param request + */ + private void handleRequest(Request request, String json) { + if (interceptors == null) { + return; + } + for (IInterceptor interceptor : interceptors) { + interceptor.handleRequest(request, json, this); + } + } + + /** + * Handle the given reponse. + * + * @param request + * @param response + * @param startTime + */ + private void handleResponse(Response response, String json, long startTime) { + if (interceptors == null) { + return; + } + long ellapsedTime = getElapsedTimeInMs(startTime); + for (IInterceptor interceptor : interceptors) { + interceptor.handleResponse(response, json, ellapsedTime, this); + } + } + + /** + * Handle the given error. + * + * @param request + * @param e + * @param startTime + */ + private void handleError(String command, Throwable e, long startTime) { + if (interceptors == null) { + return; + } + long ellapsedTime = getElapsedTimeInMs(startTime); + for (IInterceptor interceptor : interceptors) { + interceptor.handleError(e, this, command, ellapsedTime); + } + } + + /** + * Returns the elappsed time in ms. + * + * @param startTime + * in nano time. + * @return the elappsed time in ms. + */ + private static long getElapsedTimeInMs(long startTime) { + return ((System.nanoTime() - startTime) / 1000000L); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/codefixes/CodeAction.java b/typescript.java-ts.core/src/main/java/ts/client/codefixes/CodeAction.java new file mode 100644 index 000000000..dca928949 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/codefixes/CodeAction.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.codefixes; + +import java.util.List; + +public class CodeAction { + + /** Description of the code action to display in the UI of the editor */ + private String description; + /** Text changes to apply to each file as part of the code action */ + private List changes; + + public String getDescription() { + return description; + } + + public List getChanges() { + return changes; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/codefixes/FileCodeEdits.java b/typescript.java-ts.core/src/main/java/ts/client/codefixes/FileCodeEdits.java new file mode 100644 index 000000000..71c7f4402 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/codefixes/FileCodeEdits.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.codefixes; + +import java.util.List; + +import ts.client.CodeEdit; + +public class FileCodeEdits { + + private String fileName; + private List textChanges; + + public String getFileName() { + return fileName; + } + + public List getTextChanges() { + return textChanges; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/compileonsave/CompileOnSaveAffectedFileListSingleProject.java b/typescript.java-ts.core/src/main/java/ts/client/compileonsave/CompileOnSaveAffectedFileListSingleProject.java new file mode 100644 index 000000000..64b39bc06 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/compileonsave/CompileOnSaveAffectedFileListSingleProject.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.compileonsave; + +import java.util.List; + +/** + * Contains a list of files that should be regenerated in a project + * + */ +public class CompileOnSaveAffectedFileListSingleProject { + + /** + * Project name + */ + private String projectFileName; + /** + * List of files names that should be recompiled + */ + private List fileNames; + + public String getProjectFileName() { + return projectFileName; + } + + public List getFileNames() { + return fileNames; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/completions/CompletionEntry.java b/typescript.java-ts.core/src/main/java/ts/client/completions/CompletionEntry.java new file mode 100644 index 000000000..c7eb60233 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/completions/CompletionEntry.java @@ -0,0 +1,208 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.completions; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import ts.TypeScriptException; +import ts.ScriptElementKind; +import ts.client.IKindProvider; +import ts.client.ITypeScriptServiceClient; +import ts.client.TextSpan; +import ts.internal.matcher.LCSS; +import ts.utils.StringUtils; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CompletionEntry implements IKindProvider { + + // Negative value ensures subsequence matches have a lower relevance than + // standard JDT or template proposals + private static final int SUBWORDS_RANGE_START = -9000; + private static final int minPrefixLengthForTypes = 1; + + /** + * The symbol's name. + */ + private String name; + /** + * The symbol's kind (such as 'className' or 'parameterName'). + */ + private String kind; + /** + * Optional modifiers for the kind (such as 'public'). + */ + private String kindModifiers; + /** + * A string that is used for comparing completion items so that they can be + * ordered. This is often the same as the name but may be different in + * certain circumstances. + */ + private String sortText; + /** + * An optional span that indicates the text to be replaced by this + * completion item. If present, this span should be used instead of the + * default one. + */ + private TextSpan replacementSpan; + + /** + * Indicating if commiting this completion entry will require additional + * code action to be made to avoid errors. The code action is normally + * adding an additional import statement. + */ + private Boolean hasAction; + + private Boolean isFunction; + + private int relevance; + + private final String fileName; + private final int line; + private final int offset; + + private final transient ICompletionEntryMatcher matcher; + + private final transient ITypeScriptServiceClient client; + + private List entryDetails; + + public CompletionEntry(ICompletionEntryMatcher matcher, String fileName, int line, int offset, + ITypeScriptServiceClient client) { + this.matcher = matcher; + this.fileName = fileName; + this.line = line; + this.offset = offset; + this.client = client; + } + + /** + * Returns the file name where completion was done. + * + * @return the file name where completion was done. + */ + public String getFileName() { + return fileName; + } + + /** + * Returns the line number where completion was done. + * + * @return the line number where completion was done. + */ + public int getLine() { + return line; + } + + /** + * Returns the offset where completion was done. + * + * @return the offset where completion was done. + */ + public int getOffset() { + return offset; + } + + public String getName() { + return name; + } + + public String getKind() { + return kind; + } + + public String getKindModifiers() { + return kindModifiers; + } + + public String getSortText() { + return sortText; + } + + public TextSpan getReplacementSpan() { + return replacementSpan; + } + + public boolean isFunction() { + if (isFunction == null) { + ScriptElementKind tsKind = ScriptElementKind.getKind(getKind()); + isFunction = (tsKind != null && (ScriptElementKind.CONSTRUCTOR == tsKind || ScriptElementKind.FUNCTION == tsKind + || ScriptElementKind.METHOD == tsKind)); + } + return isFunction; + } + + public int getRelevance() { + return relevance; + } + + public boolean updatePrefix(String prefix) { + Integer relevanceBoost = null; + int[] bestSequence = null; + if (StringUtils.isEmpty(prefix)) { + relevanceBoost = 0; + } else { + bestSequence = matcher.bestSubsequence(name, prefix); + if ((bestSequence != null && bestSequence.length > 0)) { + relevanceBoost = 0; + if (name.equals(prefix)) { + if (minPrefixLengthForTypes < prefix.length()) { + relevanceBoost = 16 * (RelevanceConstants.R_EXACT_NAME + RelevanceConstants.R_CASE); + } + } else if (name.equalsIgnoreCase(prefix)) { + if (minPrefixLengthForTypes < prefix.length()) { + relevanceBoost = 16 * RelevanceConstants.R_EXACT_NAME; + } + } else if (startsWithIgnoreCase(prefix, name)) { + // Don't adjust score + } else { + int score = LCSS.scoreSubsequence(bestSequence); + relevanceBoost = SUBWORDS_RANGE_START + score; + } + } + } + if (relevanceBoost != null) { + relevance = relevanceBoost; + return true; + } + return false; + } + + private boolean startsWithIgnoreCase(String prefix, String name) { + return prefix.toUpperCase().startsWith(name.toUpperCase()); + } + + public ICompletionEntryMatcher getMatcher() { + return matcher; + } + + public List getEntryDetails() throws TypeScriptException { + if (entryDetails != null) { + return entryDetails; + } + try { + this.entryDetails = client.completionEntryDetails(fileName, line, offset, new String[] { name }, this) + .get(5000, TimeUnit.MILLISECONDS); + } catch (Exception e) { + e.printStackTrace(); + } + return this.entryDetails; + } + + public boolean hasActions() { + return hasAction != null && hasAction; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/completions/CompletionEntryDetails.java b/typescript.java-ts.core/src/main/java/ts/client/completions/CompletionEntryDetails.java new file mode 100644 index 000000000..6f1863b15 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/completions/CompletionEntryDetails.java @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.completions; + +import java.util.List; + +import ts.client.codefixes.CodeAction; + +/** + * Additional completion entry details, available on demand + */ +public class CompletionEntryDetails { + + /** + * The symbol's name. + */ + String name; + /** + * The symbol's kind (such as 'className' or 'parameterName'). + */ + String kind; + /** + * Optional modifiers for the kind (such as 'public'). + */ + String kindModifiers; + /** + * Display parts of the symbol (similar to quick info). + */ + List displayParts; + + /** + * Documentation strings for the symbol. + */ + List documentation; + + /** + * JSDoc tags for the symbol. + */ + List tags; + + /** + * The associated code actions for this entry + */ + List codeActions; + + public String getName() { + return name; + } + + public String getKind() { + return kind; + } + + public String getKindModifiers() { + return kindModifiers; + } + + public List getDisplayParts() { + return displayParts; + } + + public List getDocumentation() { + return documentation; + } + + public List getTags() { + return tags; + } + + public List getCodeActions() { + return codeActions; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryFactory.java b/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryFactory.java new file mode 100644 index 000000000..639cf824a --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryFactory.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.completions; + +import ts.client.ITypeScriptServiceClient; + +/** + * TypeScript {@link CompletionEntry} factory. + * + */ +public interface ICompletionEntryFactory { + + /** + * Default factory. + */ + public static final ICompletionEntryFactory DEFAULT = new ICompletionEntryFactory() { + + @Override + public CompletionEntry create(ICompletionEntryMatcher matcher, String fileName, int line, int offset, + ITypeScriptServiceClient client) { + return new CompletionEntry(matcher, fileName, line, offset, client); + } + }; + + /** + * Create {@link CompletionEntry} instance. + * + * @param matcher + * @param fileName + * @param line + * @param offset + * @param client + * @return + */ + public CompletionEntry create(ICompletionEntryMatcher matcher, String fileName, int line, int offset, + ITypeScriptServiceClient client); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryMatcher.java b/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryMatcher.java new file mode 100644 index 000000000..7f147d4d0 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryMatcher.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.completions; + +import ts.internal.matcher.LCSS; + +/** + * Matcher for completion entry. + * + */ +public interface ICompletionEntryMatcher { + + public static ICompletionEntryMatcher LCS = new ICompletionEntryMatcher() { + + @Override + public int[] bestSubsequence(String completion, String token) { + return LCSS.bestSubsequence(completion, token); + } + + }; + + public static ICompletionEntryMatcher START_WITH_MATCHER = new ICompletionEntryMatcher() { + + @Override + public int[] bestSubsequence(String completion, String token) { + if (!completion.startsWith(token)) { + return null; + } + return new int[] { 0, token.length() - 1 }; + } + }; + + int[] bestSubsequence(String completion, String token); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryMatcherProvider.java b/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryMatcherProvider.java new file mode 100644 index 000000000..c20a3d374 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/completions/ICompletionEntryMatcherProvider.java @@ -0,0 +1,20 @@ +package ts.client.completions; + +public interface ICompletionEntryMatcherProvider { + + public static ICompletionEntryMatcherProvider LCS_PROVIDER = new ICompletionEntryMatcherProvider() { + @Override + public ICompletionEntryMatcher getMatcher() { + return ICompletionEntryMatcher.LCS; + } + }; + + public static ICompletionEntryMatcherProvider START_WITH_MATCHER_PROVIDER = new ICompletionEntryMatcherProvider() { + @Override + public ICompletionEntryMatcher getMatcher() { + return ICompletionEntryMatcher.START_WITH_MATCHER; + } + }; + + ICompletionEntryMatcher getMatcher(); +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/completions/JSDocTagInfo.java b/typescript.java-ts.core/src/main/java/ts/client/completions/JSDocTagInfo.java new file mode 100644 index 000000000..cb5102d37 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/completions/JSDocTagInfo.java @@ -0,0 +1,16 @@ +package ts.client.completions; + +public class JSDocTagInfo { + + private String name; + + private String text; + + public String getName() { + return name; + } + + public String getText() { + return text; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/completions/RelevanceConstants.java b/typescript.java-ts.core/src/main/java/ts/client/completions/RelevanceConstants.java new file mode 100644 index 000000000..ba35b7db1 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/completions/RelevanceConstants.java @@ -0,0 +1,8 @@ +package ts.client.completions; + +public interface RelevanceConstants { + + public static final int R_EXACT_NAME = 4; + + public static final int R_CASE = 10; +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/completions/SymbolDisplayPart.java b/typescript.java-ts.core/src/main/java/ts/client/completions/SymbolDisplayPart.java new file mode 100644 index 000000000..36fd84473 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/completions/SymbolDisplayPart.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.completions; + +/** + * Part of a symbol description. + * + */ +public class SymbolDisplayPart { + + private static final String PARAMETER_NAME_KIND = "parameterName"; + + /** + * Text of an item describing the symbol. + */ + private String text; + + /** + * The symbol's kind (such as 'className' or 'parameterName' or plain + * 'text'). + */ + private String kind; + + public String getText() { + return text; + } + + public String getKind() { + return kind; + } + + public boolean isParameterName() { + return PARAMETER_NAME_KIND.equals(kind); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/configure/ConfigureRequestArguments.java b/typescript.java-ts.core/src/main/java/ts/client/configure/ConfigureRequestArguments.java new file mode 100644 index 000000000..154809499 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/configure/ConfigureRequestArguments.java @@ -0,0 +1,59 @@ +package ts.client.configure; + +import ts.client.format.FormatCodeSettings; + +/** + * Information found in a configure request. + */ +public class ConfigureRequestArguments { + + /** + * Information about the host, for example 'Emacs 24.4' or 'Sublime Text + * version 3075' + */ + private String hostInfo; + + /** + * If present, tab settings apply only to this file. + */ + private String file; + + /** + * The format options to use during formatting and other code editing + * features. + */ + private FormatCodeSettings formatOptions; + + /** + * The host's additional supported file extensions + */ + // extraFileExtensions?: FileExtensionInfo[]; + + public String getHostInfo() { + return hostInfo; + } + + public ConfigureRequestArguments setHostInfo(String hostInfo) { + this.hostInfo = hostInfo; + return this; + } + + public String getFile() { + return file; + } + + public ConfigureRequestArguments setFile(String file) { + this.file = file; + return this; + } + + public FormatCodeSettings getFormatOptions() { + return formatOptions; + } + + public ConfigureRequestArguments setFormatOptions(FormatCodeSettings formatOptions) { + this.formatOptions = formatOptions; + return this; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/diagnostics/AbstractDiagnostic.java b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/AbstractDiagnostic.java new file mode 100644 index 000000000..b7b876ed9 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/AbstractDiagnostic.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.diagnostics; + +/** + * Item of diagnostic information found in a DiagnosticEvent message. + * + */ +public abstract class AbstractDiagnostic implements IDiagnostic { + + private static final String TS_SOURCE = "ts"; + + /** + * Text of diagnostic message. + */ + private String text; + + /** + * The error code of the diagnostic message. + */ + private Integer code; + + private String category; + + /** + * The name of the plugin reporting the message. + */ + private String source; + + @Override + public String getText() { + return text; + } + + @Override + public String getFullText() { + String text = getText(); + String source = getSource(); + return new StringBuilder("[").append(source).append("] ").append(text != null ? text : "").toString(); + } + + @Override + public Integer getCode() { + return code; + } + + @Override + public DiagnosticCategory getCategory() { + return DiagnosticCategory.getCategory(category); + } + + @Override + public String getSource() { + return source != null ? source : TS_SOURCE; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/diagnostics/Diagnostic.java b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/Diagnostic.java new file mode 100644 index 000000000..e519e10c7 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/Diagnostic.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.diagnostics; + +import ts.client.Location; + +/** + * Item of diagnostic information found in a DiagnosticEvent message. + * + */ +public class Diagnostic extends AbstractDiagnostic { + + /** + * Starting file location at which text applies. + */ + private Location start; + + /** + * The last file location at which the text applies. + */ + private Location end; + + public Location getStartLocation() { + return start; + } + + public Location getEndLocation() { + return end; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticEvent.java b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticEvent.java new file mode 100644 index 000000000..237741472 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticEvent.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.diagnostics; + +import ts.client.Event; + +/** + * Event message for "syntaxDiag" and "semanticDiag" event types. These events + * provide syntactic and semantic errors for a file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class DiagnosticEvent extends Event { + + public String getKey() { + return getEvent() + "_" + getBody().getFile(); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticEventBody.java b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticEventBody.java new file mode 100644 index 000000000..4dbb1e809 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticEventBody.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.diagnostics; + +import java.util.List; + +public class DiagnosticEventBody { + + /** + * The file for which diagnostic information is reported. + */ + private String file; + + /** + * An array of diagnostic informatdiion items. + */ + private List diagnostics; + + public DiagnosticEventBody() { + } + + public DiagnosticEventBody(String file, List diagnostics) { + this.file = file; + this.diagnostics = diagnostics; + } + + public String getFile() { + return file; + } + + public List getDiagnostics() { + return diagnostics; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticWithLinePosition.java b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticWithLinePosition.java new file mode 100644 index 000000000..6da51307f --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/DiagnosticWithLinePosition.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.diagnostics; + +import ts.client.Location; + +/** + * Represents diagnostic info that includes location of diagnostic in two forms + * - start position and length of the error span - startLocation and endLocation + * - a pair of Location objects that store start/end line and offset of the + * error span. + */ +public class DiagnosticWithLinePosition extends AbstractDiagnostic { + + private Integer start; + + private Integer end; + + /** + * Starting file location at which text applies. + */ + private Location startLocation; + + /** + * The last file location at which the text applies. + */ + private Location endLocation; + + /** + * Text of diagnostic message. + */ + private String message; + + @Override + public Location getStartLocation() { + return startLocation; + } + + @Override + public Location getEndLocation() { + return endLocation; + } + + public Integer getStart() { + return start; + } + + public Integer getEnd() { + return end; + } + + @Override + public String getText() { + return message != null ? message : super.getText(); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/diagnostics/IDiagnostic.java b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/IDiagnostic.java new file mode 100644 index 000000000..4b1d88673 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/diagnostics/IDiagnostic.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.diagnostics; + +import ts.client.Location; +import ts.utils.StringUtils; + +/** + * Diagnostic API. + * + */ +public interface IDiagnostic { + + public enum DiagnosticCategory { + Warning, Error, Message; + + public static DiagnosticCategory getCategory(String category) { + if (!StringUtils.isEmpty(category)) { + DiagnosticCategory[] values = DiagnosticCategory.values(); + for (int i = 0; i < values.length; i++) { + DiagnosticCategory c = values[i]; + if (category.equalsIgnoreCase(c.name())) { + return c; + } + } + } + return Error; + } + } + + /** + * Return text of diagnostic message. + * + * @return text of diagnostic message. + */ + String getText(); + + String getFullText(); + + Location getStartLocation(); + + Location getEndLocation(); + + /** + * Returns the error code of the diagnostic message. + * + * @return the error code of the diagnostic message. + */ + Integer getCode(); + + /** + * + * @return + */ + DiagnosticCategory getCategory(); + + /** + * Return the name of the plugin reporting the message. + * + * @return the name of the plugin reporting the message. + */ + String getSource(); +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/format/EditorSettings.java b/typescript.java-ts.core/src/main/java/ts/client/format/EditorSettings.java new file mode 100644 index 000000000..4b9e73f3b --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/format/EditorSettings.java @@ -0,0 +1,61 @@ +package ts.client.format; + +public class EditorSettings { + + private Integer baseIndentSize; + + private Integer indentSize; + private Integer tabSize; + private String newLineCharacter; + private Boolean convertTabsToSpaces; + private IndentStyle indentStyle; + + public Integer getBaseIndentSize() { + return baseIndentSize; + } + + public void setBaseIndentSize(Integer baseIndentSize) { + this.baseIndentSize = baseIndentSize; + } + + public Integer getIndentSize() { + return indentSize; + } + + public void setIndentSize(Integer indentSize) { + this.indentSize = indentSize; + } + + public Integer getTabSize() { + return tabSize; + } + + public void setTabSize(Integer tabSize) { + this.tabSize = tabSize; + } + + public String getNewLineCharacter() { + return newLineCharacter; + } + + public void setNewLineCharacter(String newLineCharacter) { + this.newLineCharacter = newLineCharacter; + } + + public Boolean getConvertTabsToSpaces() { + return convertTabsToSpaces; + } + + public void setConvertTabsToSpaces(Boolean convertTabsToSpaces) { + this.convertTabsToSpaces = convertTabsToSpaces; + } + + public IndentStyle getIndentStyle() { + return indentStyle; + } + + public void setIndentStyle(IndentStyle indentStyle) { + this.indentStyle = indentStyle; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/format/FormatCodeSettings.java b/typescript.java-ts.core/src/main/java/ts/client/format/FormatCodeSettings.java new file mode 100644 index 000000000..3dc9a9699 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/format/FormatCodeSettings.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.format; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class FormatCodeSettings extends EditorSettings { + + private Boolean insertSpaceAfterCommaDelimiter; + private Boolean insertSpaceAfterSemicolonInForStatements; + private Boolean insertSpaceBeforeAndAfterBinaryOperators; + private Boolean insertSpaceAfterConstructor; + private Boolean insertSpaceAfterKeywordsInControlFlowStatements; + private Boolean insertSpaceAfterFunctionKeywordForAnonymousFunctions; + private Boolean insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; + private Boolean insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets; + private Boolean insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces; + private Boolean insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces; + private Boolean insertSpaceBeforeFunctionParenthesis; + private Boolean placeOpenBraceOnNewLineForFunctions; + private Boolean placeOpenBraceOnNewLineForControlBlocks; + + public Boolean getInsertSpaceAfterCommaDelimiter() { + return insertSpaceAfterCommaDelimiter; + } + + public void setInsertSpaceAfterCommaDelimiter(Boolean insertSpaceAfterCommaDelimiter) { + this.insertSpaceAfterCommaDelimiter = insertSpaceAfterCommaDelimiter; + } + + public Boolean getInsertSpaceAfterSemicolonInForStatements() { + return insertSpaceAfterSemicolonInForStatements; + } + + public void setInsertSpaceAfterSemicolonInForStatements(Boolean insertSpaceAfterSemicolonInForStatements) { + this.insertSpaceAfterSemicolonInForStatements = insertSpaceAfterSemicolonInForStatements; + } + + public Boolean getInsertSpaceBeforeAndAfterBinaryOperators() { + return insertSpaceBeforeAndAfterBinaryOperators; + } + + public void setInsertSpaceBeforeAndAfterBinaryOperators(Boolean insertSpaceBeforeAndAfterBinaryOperators) { + this.insertSpaceBeforeAndAfterBinaryOperators = insertSpaceBeforeAndAfterBinaryOperators; + } + + public Boolean getInsertSpaceAfterConstructor() { + return insertSpaceAfterConstructor; + } + + public void setInsertSpaceAfterConstructor(Boolean insertSpaceAfterConstructor) { + this.insertSpaceAfterConstructor = insertSpaceAfterConstructor; + } + + public Boolean getInsertSpaceAfterKeywordsInControlFlowStatements() { + return insertSpaceAfterKeywordsInControlFlowStatements; + } + + public void setInsertSpaceAfterKeywordsInControlFlowStatements( + Boolean insertSpaceAfterKeywordsInControlFlowStatements) { + this.insertSpaceAfterKeywordsInControlFlowStatements = insertSpaceAfterKeywordsInControlFlowStatements; + } + + public Boolean getInsertSpaceAfterFunctionKeywordForAnonymousFunctions() { + return insertSpaceAfterFunctionKeywordForAnonymousFunctions; + } + + public void setInsertSpaceAfterFunctionKeywordForAnonymousFunctions( + Boolean insertSpaceAfterFunctionKeywordForAnonymousFunctions) { + this.insertSpaceAfterFunctionKeywordForAnonymousFunctions = insertSpaceAfterFunctionKeywordForAnonymousFunctions; + } + + public Boolean getInsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis() { + return insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; + } + + public void setInsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis( + Boolean insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis) { + this.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis = insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis; + } + + public Boolean getInsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets() { + return insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets; + } + + public void setInsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets( + Boolean insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets) { + this.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets = insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets; + } + + public Boolean getInsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces() { + return insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces; + } + + public void setInsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces( + Boolean insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces) { + this.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces = insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces; + } + + public Boolean getInsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces() { + return insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces; + } + + public void setInsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces( + Boolean insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces) { + this.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces = insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces; + } + + public Boolean getInsertSpaceBeforeFunctionParenthesis() { + return insertSpaceBeforeFunctionParenthesis; + } + + public void setInsertSpaceBeforeFunctionParenthesis(Boolean insertSpaceBeforeFunctionParenthesis) { + this.insertSpaceBeforeFunctionParenthesis = insertSpaceBeforeFunctionParenthesis; + } + + public Boolean getPlaceOpenBraceOnNewLineForFunctions() { + return placeOpenBraceOnNewLineForFunctions; + } + + public void setPlaceOpenBraceOnNewLineForFunctions(Boolean placeOpenBraceOnNewLineForFunctions) { + this.placeOpenBraceOnNewLineForFunctions = placeOpenBraceOnNewLineForFunctions; + } + + public Boolean getPlaceOpenBraceOnNewLineForControlBlocks() { + return placeOpenBraceOnNewLineForControlBlocks; + } + + public void setPlaceOpenBraceOnNewLineForControlBlocks(Boolean placeOpenBraceOnNewLineForControlBlocks) { + this.placeOpenBraceOnNewLineForControlBlocks = placeOpenBraceOnNewLineForControlBlocks; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/format/IndentStyle.java b/typescript.java-ts.core/src/main/java/ts/client/format/IndentStyle.java new file mode 100644 index 000000000..b4873734b --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/format/IndentStyle.java @@ -0,0 +1,6 @@ +package ts.client.format; + +public enum IndentStyle { + + None, Block, Smart; +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/installtypes/BeginInstallTypesEventBody.java b/typescript.java-ts.core/src/main/java/ts/client/installtypes/BeginInstallTypesEventBody.java new file mode 100644 index 000000000..7919e9f9d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/installtypes/BeginInstallTypesEventBody.java @@ -0,0 +1,5 @@ +package ts.client.installtypes; + +public class BeginInstallTypesEventBody extends InstallTypesEventBody { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/installtypes/EndInstallTypesEventBody.java b/typescript.java-ts.core/src/main/java/ts/client/installtypes/EndInstallTypesEventBody.java new file mode 100644 index 000000000..bd7dd1f6b --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/installtypes/EndInstallTypesEventBody.java @@ -0,0 +1,13 @@ +package ts.client.installtypes; + +public class EndInstallTypesEventBody extends InstallTypesEventBody { + + /** + * true if installation succeeded, otherwise false + */ + private boolean success; + + public boolean isSuccess() { + return success; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/installtypes/IInstallTypesListener.java b/typescript.java-ts.core/src/main/java/ts/client/installtypes/IInstallTypesListener.java new file mode 100644 index 000000000..aa9d9c3ed --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/installtypes/IInstallTypesListener.java @@ -0,0 +1,13 @@ +package ts.client.installtypes; + +import com.google.gson.JsonObject; + +public interface IInstallTypesListener { + + void onBegin(BeginInstallTypesEventBody body); + + void logTelemetry(String telemetryEventName, JsonObject payload); + + void onEnd(EndInstallTypesEventBody body); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/installtypes/InstallTypesEventBody.java b/typescript.java-ts.core/src/main/java/ts/client/installtypes/InstallTypesEventBody.java new file mode 100644 index 000000000..19256d7c3 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/installtypes/InstallTypesEventBody.java @@ -0,0 +1,24 @@ +package ts.client.installtypes; + +import java.util.List; + +public class InstallTypesEventBody { + + /** + * correlation id to match begin and end events + */ + int eventId; + + /** + * list of packages to install + */ + List packages; + + public int getEventId() { + return eventId; + } + + public List getPackages() { + return packages; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/jsdoc/TextInsertion.java b/typescript.java-ts.core/src/main/java/ts/client/jsdoc/TextInsertion.java new file mode 100644 index 000000000..f14541830 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/jsdoc/TextInsertion.java @@ -0,0 +1,23 @@ +package ts.client.jsdoc; + +/** + * @see https://github.com/Microsoft/TypeScript/blob/master/src/services/types.ts + * + */ +public class TextInsertion { + + private String newText; + + /** + * The position in newText the caret should point to after the insertion. + */ + private int caretOffset; + + public String getNewText() { + return newText; + } + + public int getCaretOffset() { + return caretOffset; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationBarItem.java b/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationBarItem.java new file mode 100644 index 000000000..38520bac6 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationBarItem.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.navbar; + +import java.util.List; + +import ts.client.IKindProvider; + +/** + * Navigation bar item. + * + */ +public class NavigationBarItem implements IKindProvider { + + /** + * The item's display text. + */ + private String text; + + /** + * The symbol's kind (such as 'className' or 'parameterName'). + */ + private String kind; + + /** + * Optional modifiers for the kind (such as 'public'). + */ + private String kindModifiers; + private List spans; + private List childItems; + private boolean parentAlreadyUpdated; + NavigationBarItem parent; + + public String getText() { + return text; + } + + @Override + public String getKind() { + return kind; + } + + @Override + public String getKindModifiers() { + return kindModifiers; + } + + public void setText(String text) { + this.text = text; + } + + public void setSpans(List spans) { + this.spans = spans; + this.parentAlreadyUpdated = false; + } + + public List getSpans() { + updateParentIfNeeded(); + return spans; + } + + public boolean hasSpans() { + return spans != null && spans.size() > 0; + } + + public List getChildItems() { + updateParentIfNeeded(); + return childItems; + } + + private void updateParentIfNeeded() { + if (!parentAlreadyUpdated) { + if (childItems != null) { + for (NavigationBarItem item : childItems) { + item.parent = this; + } + } + if (spans != null) { + for (NavigationTextSpan span : spans) { + span.parent = this; + } + } + parentAlreadyUpdated = true; + } + } + + public void setChildItems(List childItems) { + this.childItems = childItems; + this.parentAlreadyUpdated = false; + } + + public boolean hasChildItems() { + return childItems != null && childItems.size() > 0; + } + + public NavigationBarItem getParent() { + return parent; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationBarItemRoot.java b/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationBarItemRoot.java new file mode 100644 index 000000000..cb5dc8f62 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationBarItemRoot.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.navbar; + +import java.util.Arrays; +import java.util.List; + +/** + * Root of the list of navigation bar items. + * + */ +public class NavigationBarItemRoot extends NavigationBarItem { + + private boolean navtree; + + public NavigationBarItemRoot(NavigationBarItem item) { + this(Arrays.asList(item)); + this.navtree = true; + } + + public NavigationBarItemRoot(List items) { + setChildItems(items); + this.navtree = false; + } + + public boolean isNavTree() { + return navtree; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationTextSpan.java b/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationTextSpan.java new file mode 100644 index 000000000..310a0eb79 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/navbar/NavigationTextSpan.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.navbar; + +import ts.client.TextSpan; + +public class NavigationTextSpan extends TextSpan { + + NavigationBarItem parent; + + public NavigationBarItem getParent() { + return parent; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/navto/NavtoItem.java b/typescript.java-ts.core/src/main/java/ts/client/navto/NavtoItem.java new file mode 100644 index 000000000..5a1e7e1fa --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/navto/NavtoItem.java @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.navto; + +import ts.client.FileSpan; +import ts.client.IKindProvider; + +/** + * An item found in a navto response. + */ +public class NavtoItem extends FileSpan implements IKindProvider { + + /** + * The symbol's name. + */ + private String name; + + /** + * The symbol's kind (such as 'className' or 'parameterName'). + */ + private String kind; + + /** + * exact, substring, or prefix. + */ + private String matchKind; + + /** + * If this was a case sensitive or insensitive match. + */ + private Boolean isCaseSensitive; + + /** + * Optional modifiers for the kind (such as 'public'). + */ + private String kindModifiers; + + /** + * Name of symbol's container symbol (if any); for example, the class name if + * symbol is a class member. + */ + private String containerName; + + /** + * Kind of symbol's container symbol (if any). + */ + private String containerKind; + + public String getName() { + return name; + } + + @Override + public String getKind() { + return kind; + } + + public String getMatchKind() { + return matchKind; + } + + public Boolean getIsCaseSensitive() { + return isCaseSensitive; + } + + @Override + public String getKindModifiers() { + return kindModifiers; + } + + public String getContainerName() { + return containerName; + } + + public String getContainerKind() { + return containerKind; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/occurrences/OccurrencesResponseItem.java b/typescript.java-ts.core/src/main/java/ts/client/occurrences/OccurrencesResponseItem.java new file mode 100644 index 000000000..cd04014ec --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/occurrences/OccurrencesResponseItem.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.occurrences; + +import ts.client.FileSpan; + +public class OccurrencesResponseItem extends FileSpan { + /** + * True if the occurrence is a write location, false otherwise. + */ + private boolean isWriteAccess; + + public boolean isWriteAccess() { + return isWriteAccess; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/projectinfo/ProjectInfo.java b/typescript.java-ts.core/src/main/java/ts/client/projectinfo/ProjectInfo.java new file mode 100644 index 000000000..7404fcaef --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/projectinfo/ProjectInfo.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.projectinfo; + +import java.util.List; + +/** + * Response message body for "projectInfo" request + * + */ +public class ProjectInfo { + + /** + * For configured project, this is the normalized path of the + * 'tsconfig.json' file For inferred project, this is undefined + */ + private String configFileName; + /** + * The list of normalized file name in the project, including 'lib.d.ts' + */ + private List fileNames; + /** + * Indicates if the project has a active language service instance + */ + private Boolean languageServiceDisabled; + + public String getConfigFileName() { + return configFileName; + } + + public List getFileNames() { + return fileNames; + } + + public Boolean getLanguageServiceDisabled() { + return languageServiceDisabled; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/quickinfo/QuickInfo.java b/typescript.java-ts.core/src/main/java/ts/client/quickinfo/QuickInfo.java new file mode 100644 index 000000000..663c457aa --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/quickinfo/QuickInfo.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.quickinfo; + +import ts.client.Location; + +public class QuickInfo { + + /** + * The symbol's kind (such as 'className' or 'parameterName' or plain + * 'text'). + */ + private String kind; + + /** + * Optional modifiers for the kind (such as 'public'). + */ + private String kindModifiers; + + /** + * Starting file location of symbol. + */ + private Location start; + + /** + * One past last character of symbol. + */ + private Location end; + + /** + * Type and kind of symbol. + */ + private String displayString; + + /** + * Documentation associated with symbol. + */ + private String documentation; + + public String getKind() { + return kind; + } + + public String getKindModifiers() { + return kindModifiers; + } + + public Location getStart() { + return start; + } + + public Location getEnd() { + return end; + } + + public String getDisplayString() { + return displayString; + } + + public String getDocumentation() { + return documentation; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/refactors/ApplicableRefactorInfo.java b/typescript.java-ts.core/src/main/java/ts/client/refactors/ApplicableRefactorInfo.java new file mode 100644 index 000000000..6f35245a6 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/refactors/ApplicableRefactorInfo.java @@ -0,0 +1,52 @@ +package ts.client.refactors; + +import java.util.List; + +/** + * A set of one or more available refactoring actions, grouped under a parent + * refactoring. + */ +public class ApplicableRefactorInfo { + + /** + * The programmatic name of the refactoring + */ + private String name; + + /** + * A description of this refactoring category to show to the user. If the + * refactoring gets inlined (see below), this text will not be visible. + */ + private String description; + + /** + * Inlineable refactorings can have their actions hoisted out to the top level + * of a context menu. Non-inlineanable refactorings should always be shown + * inside their parent grouping. + * + * If not specified, this value is assumed to be 'true' + */ + private Boolean inlineable; + + private List actions; + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public Boolean getInlineable() { + return inlineable; + } + + public List getActions() { + return actions; + } + + public boolean isInlineable() { + return inlineable == null ? true : inlineable; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/refactors/RefactorActionInfo.java b/typescript.java-ts.core/src/main/java/ts/client/refactors/RefactorActionInfo.java new file mode 100644 index 000000000..bdf15b08d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/refactors/RefactorActionInfo.java @@ -0,0 +1,29 @@ +package ts.client.refactors; + +/** + * Represents a single refactoring action - for example, the "Extract Method..." + * refactor might offer several actions, each corresponding to a surround class + * or closure to extract into. + */ +public class RefactorActionInfo { + + /** + * The programmatic name of the refactoring action + */ + private String name; + + /** + * A description of this refactoring action to show to the user. If the parent + * refactoring is inlined away, this will be the only text shown, so this + * description should make sense by itself if the parent is inlineable=true + */ + private String description; + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/refactors/RefactorEditInfo.java b/typescript.java-ts.core/src/main/java/ts/client/refactors/RefactorEditInfo.java new file mode 100644 index 000000000..4f427e4fb --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/refactors/RefactorEditInfo.java @@ -0,0 +1,31 @@ +package ts.client.refactors; + +import java.util.List; + +import ts.client.Location; +import ts.client.codefixes.FileCodeEdits; + +public class RefactorEditInfo { + + private List edits; + + /** + * An optional location where the editor should start a rename operation once + * the refactoring edits have been applied + */ + private Location renameLocation; + + private String renameFilename; + + public List getEdits() { + return edits; + } + + public Location getRenameLocation() { + return renameLocation; + } + + public String getRenameFilename() { + return renameFilename; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/references/ReferencesResponseBody.java b/typescript.java-ts.core/src/main/java/ts/client/references/ReferencesResponseBody.java new file mode 100644 index 000000000..3cf9044c2 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/references/ReferencesResponseBody.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.references; + +import java.util.List; + +/** + * + * The body of a "references" response message. + * + */ +public class ReferencesResponseBody { + + /** + * The file locations referencing the symbol. + */ + private List refs; + + /** + * The name of the symbol. + */ + private String symbolName; + + /** + * The start character offset of the symbol (on the line provided by the + * references request). + */ + private int symbolStartOffset; + + /** + * The full display name of the symbol. + */ + private String symbolDisplayString; + + public List getRefs() { + return refs; + } + + public String getSymbolName() { + return symbolName; + } + + public int getSymbolStartOffset() { + return symbolStartOffset; + } + + public String getSymbolDisplayString() { + return symbolDisplayString; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/references/ReferencesResponseItem.java b/typescript.java-ts.core/src/main/java/ts/client/references/ReferencesResponseItem.java new file mode 100644 index 000000000..9756a7d0d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/references/ReferencesResponseItem.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.references; + +import ts.client.FileSpan; + +public class ReferencesResponseItem extends FileSpan { + /** + * Text of line containing the reference. Including this with the response + * avoids latency of editor loading files to show text of reference line + * (the server already has loaded the referencing files). + */ + private String lineText; + + /** + * True if reference is a write location, false otherwise. + */ + private boolean isWriteAccess; + + /** + * True if reference is a definition, false otherwise. + */ + private boolean isDefinition; + + public String getLineText() { + return lineText; + } + + public boolean isWriteAccess() { + return isWriteAccess; + } + + public boolean isDefinition() { + return isDefinition; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/rename/RenameInfo.java b/typescript.java-ts.core/src/main/java/ts/client/rename/RenameInfo.java new file mode 100644 index 000000000..fcda54a15 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/rename/RenameInfo.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.rename; + +/** + * Information about the item to be renamed. + * + */ +public class RenameInfo { + + /** + * True if item can be renamed. + */ + private boolean canRename; + + /** + * Error message if item can not be renamed. + */ + private String localizedErrorMessage; + + /** + * Display name of the item to be renamed. + */ + private String displayName; + + /** + * Full display name of item to be renamed. + */ + private String fullDisplayName; + + /** + * The items's kind (such as 'className' or 'parameterName' or plain + * 'text'). + */ + private String kind; + + /** + * Optional modifiers for the kind (such as 'public'). + */ + private String kindModifiers; + + public boolean isCanRename() { + return canRename; + } + + public String getLocalizedErrorMessage() { + return localizedErrorMessage; + } + + public String getDisplayName() { + return displayName; + } + + public String getFullDisplayName() { + return fullDisplayName; + } + + public String getKind() { + return kind; + } + + public String getKindModifiers() { + return kindModifiers; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/rename/RenameResponseBody.java b/typescript.java-ts.core/src/main/java/ts/client/rename/RenameResponseBody.java new file mode 100644 index 000000000..2ab4eb8a2 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/rename/RenameResponseBody.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.rename; + +import java.util.List; + +public class RenameResponseBody { + + /** + * Information about the item to be renamed. + */ + private RenameInfo info; + + /** + * An array of span groups (one per file) that refer to the item to be + * renamed. + */ + private List locs; + + public RenameInfo getInfo() { + return info; + } + + public List getLocs() { + return locs; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/rename/SpanGroup.java b/typescript.java-ts.core/src/main/java/ts/client/rename/SpanGroup.java new file mode 100644 index 000000000..16e705923 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/rename/SpanGroup.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.rename; + +import java.util.List; + +import ts.client.TextSpan; + +/** + * A group of text spans, all in 'file'. + * + */ +public class SpanGroup { + + /** + * The file to which the spans apply + */ + private String file; + + /** + * The text spans in this group + */ + private List locs; + + public String getFile() { + return file; + } + + public List getLocs() { + return locs; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/client/signaturehelp/SignatureHelpItems.java b/typescript.java-ts.core/src/main/java/ts/client/signaturehelp/SignatureHelpItems.java new file mode 100644 index 000000000..2421d4c9b --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/client/signaturehelp/SignatureHelpItems.java @@ -0,0 +1,18 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.client.signaturehelp; + +/** + * Signature help items found in the response of a signature help request. + */ +public class SignatureHelpItems { + +} \ No newline at end of file diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/AbstractCmd.java b/typescript.java-ts.core/src/main/java/ts/cmd/AbstractCmd.java new file mode 100644 index 000000000..f21d4b055 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/AbstractCmd.java @@ -0,0 +1,71 @@ +package ts.cmd; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import ts.TypeScriptException; +import ts.nodejs.INodejsLaunchConfiguration; +import ts.nodejs.INodejsProcess; +import ts.nodejs.INodejsProcessListener; +import ts.nodejs.NodejsProcess; +import ts.nodejs.NodejsProcessManager; + +public class AbstractCmd { + + private final File binFile; + private final File nodejsFile; + private final String binFileType; + + public AbstractCmd(File binFile, File nodejsFile, String binFileType) { + this.binFile = binFile; + this.nodejsFile = nodejsFile; + this.binFileType = binFileType; + } + + public List createCommands(T options, List filenames) { + List cmds = NodejsProcess.createNodeCommands(nodejsFile, binFile); + fillOptions(options, filenames, cmds); + return cmds; + } + + public INodejsProcess execute(File baseDir, final T options, final List filenames, + INodejsProcessListener listener) throws TypeScriptException { + INodejsProcess process = NodejsProcessManager.getInstance().create(baseDir, binFile, nodejsFile, + new INodejsLaunchConfiguration() { + + @Override + public List createNodeArgs() { + List args = new ArrayList(); + fillOptions(options, filenames, args); + return args; + } + + @Override + public Map createNodeEnvironmentVariables() { + return null; + } + }, binFileType); + + if (listener != null) { + process.addProcessListener(listener); + } + process.start(); + try { + process.join(); + } catch (InterruptedException e) { + throw new TypeScriptException(e); + } + return process; + } + + private void fillOptions(T options, List filenames, List args) { + if (filenames != null) { + args.addAll(filenames); + } + if (options != null) { + options.fillOptions(args); + } + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/AbstractOptions.java b/typescript.java-ts.core/src/main/java/ts/cmd/AbstractOptions.java new file mode 100644 index 000000000..d392836c0 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/AbstractOptions.java @@ -0,0 +1,22 @@ +package ts.cmd; + +import java.util.List; + +import ts.utils.StringUtils; + +public abstract class AbstractOptions implements IOptions{ + + protected void fillOption(String name, Boolean value, List args) { + if (value != null && value) { + args.add(name); + } + } + + protected void fillOption(String name, String value, List args) { + if (!StringUtils.isEmpty(value)) { + args.add(name); + args.add(value); + } + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/IOptions.java b/typescript.java-ts.core/src/main/java/ts/cmd/IOptions.java new file mode 100644 index 000000000..343414f11 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/IOptions.java @@ -0,0 +1,9 @@ +package ts.cmd; + +import java.util.List; + +public interface IOptions { + + void fillOptions(List args); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/ITypeScriptLinterHandler.java b/typescript.java-ts.core/src/main/java/ts/cmd/ITypeScriptLinterHandler.java new file mode 100644 index 000000000..bcb14ceca --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/ITypeScriptLinterHandler.java @@ -0,0 +1,9 @@ +package ts.cmd; + +import ts.client.Location; + +public interface ITypeScriptLinterHandler { + + void addError(String file, Location startLoc, Location endLoc, + Severity severity, String code, String message); +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/Severity.java b/typescript.java-ts.core/src/main/java/ts/cmd/Severity.java new file mode 100644 index 000000000..f075475e5 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/Severity.java @@ -0,0 +1,7 @@ +package ts.cmd; + +public enum Severity { + + error, warning, info; + +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tsc/CompilerOptionCapability.java b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/CompilerOptionCapability.java new file mode 100644 index 000000000..33b88f037 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/CompilerOptionCapability.java @@ -0,0 +1,26 @@ +package ts.cmd.tsc; + +import ts.utils.VersionHelper; + +public enum CompilerOptionCapability { + + listEmittedFiles("2.0.0"); + + private String sinceVersion; + + private CompilerOptionCapability(String version) { + this.sinceVersion = version; + } + + /** + * Return true if the tsc compiler option support the given version and + * false otherwise. + * + * @param version + * @return true if the tsc compiler option support the given version and + * false otherwise. + */ + public boolean canSupport(String version) { + return VersionHelper.canSupport(version, sinceVersion); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tsc/CompilerOptions.java b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/CompilerOptions.java new file mode 100644 index 000000000..262a94646 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/CompilerOptions.java @@ -0,0 +1,1305 @@ +package ts.cmd.tsc; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import ts.cmd.AbstractOptions; +import ts.utils.BooleanUtils; + +/** + * Instructs the TypeScript compiler how to compile .ts files. + * + * @see http://json.schemastore.org/tsconfig + * @se https://www.typescriptlang.org/docs/handbook/compiler-html + * + */ +public class CompilerOptions extends AbstractOptions { + + private Boolean allowJs; + private Boolean allowSyntheticDefaultImports; + private Boolean allowUnreachableCode; + private Boolean allowUnusedLabels; + private String charset; + private Boolean declaration; + private Boolean diagnostics; + private Boolean emitBOM; + private Boolean emitDecoratorMetadata; + private Boolean experimentalDecorators; + private Boolean forceConsistentCasingInFileNames; + private Boolean help; + private Boolean inlineSourceMap; + private Boolean inlineSources; + private Boolean init; + private Boolean isolatedModules; + private String jsx; + private Boolean listEmittedFiles; + private Boolean listFiles; + private String locale; + private String mapRoot; + private String module; + private String moduleResolution; + private String newLine; + private Boolean noEmit; + private Boolean noEmitHelpers; + private Boolean noEmitOnError; + private Boolean noFallthroughCasesInSwitch; + private Boolean noImplicitAny; + private Boolean noImplicitReturns; + private Boolean noImplicitUseStrict; + private Boolean noLib; + private Boolean noResolve; + private String out; + private String outDir; + private String outFile; + private Map> paths; + private Boolean preserveConstEnums; + private Boolean pretty; + private String project; + private String reactNamespace; + private Boolean removeComments; + private String rootDir; + private List rootDirs; + private Boolean skipDefaultLibCheck; + private Boolean sourceMap; + private String sourceRoot; + private Boolean strictNullChecks; + private Boolean stripInternal; + private Boolean suppressExcessPropertyErrors; + private Boolean suppressImplicitAnyIndexErrors; + private String target; + private Boolean traceResolution; + private Boolean version; + private Boolean watch; + + private List plugins; + + public CompilerOptions() { + } + + public CompilerOptions(CompilerOptions options) { + this.setAllowJs(options.allowJs); + this.setAllowSyntheticDefaultImports(options.allowSyntheticDefaultImports); + this.setAllowUnreachableCode(options.allowUnreachableCode); + this.setAllowUnusedLabels(options.allowUnusedLabels); + this.setCharset(options.charset); + this.setDeclaration(options.declaration); + this.setDiagnostics(options.diagnostics); + this.setEmitBOM(options.emitBOM); + this.setEmitDecoratorMetadata(options.emitDecoratorMetadata); + this.setExperimentalDecorators(options.experimentalDecorators); + this.setForceConsistentCasingInFileNames(options.forceConsistentCasingInFileNames); + this.setHelp(options.help); + this.setInlineSourceMap(options.inlineSourceMap); + this.setInlineSources(options.inlineSources); + this.setInit(options.init); + this.setIsolatedModules(options.isolatedModules); + this.setJsx(options.jsx); + this.setListEmittedFiles(options.listEmittedFiles); + this.setListFiles(options.listFiles); + this.setLocale(options.locale); + this.setMapRoot(options.mapRoot); + this.setModule(options.module); + this.setModuleResolution(options.moduleResolution); + this.setNewLine(options.newLine); + this.setNoEmit(options.noEmit); + this.setNoEmitHelpers(options.noEmitHelpers); + this.setNoEmitOnError(options.noEmitOnError); + this.setNoFallthroughCasesInSwitch(options.noFallthroughCasesInSwitch); + this.setNoImplicitAny(options.noImplicitAny); + this.setNoImplicitReturns(options.noImplicitReturns); + this.setNoImplicitUseStrict(options.noImplicitUseStrict); + this.setNoLib(options.noLib); + this.setNoResolve(options.noResolve); + this.setOut(options.out); + this.setOutDir(options.outDir); + this.setOutFile(options.outFile); + this.setPreserveConstEnums(options.preserveConstEnums); + this.setPretty(options.pretty); + this.setProject(options.project); + this.setReactNamespace(options.reactNamespace); + this.setRemoveComments(options.removeComments); + this.setRootDir(options.rootDir); + this.setSkipDefaultLibCheck(options.skipDefaultLibCheck); + this.setSourceMap(options.sourceMap); + this.setSourceRoot(options.sourceRoot); + this.setStrictNullChecks(options.strictNullChecks); + this.setStripInternal(options.stripInternal); + this.setSuppressExcessPropertyErrors(options.suppressExcessPropertyErrors); + this.setSuppressImplicitAnyIndexErrors(options.suppressImplicitAnyIndexErrors); + this.setTarget(options.target); + this.setTraceResolution(options.traceResolution); + this.setVersion(options.version); + this.setWatch(options.watch); + } + + /** + * Returns true if allow JavaScript files to be compiled and false + * otherwise. + * + * @return true if allow JavaScript files to be compiled and false + * otherwise. + */ + public Boolean isAllowJs() { + return BooleanUtils.toBoolean(allowJs); + } + + /** + * Allow JavaScript files to be compiled. + * + * @param allowJs + */ + public void setAllowJs(Boolean allowJs) { + this.allowJs = allowJs; + } + + /** + * Allow default imports from modules with no default export. This does not + * affect code emit, just typechecking. + * + * @return + */ + public boolean isAllowSyntheticDefaultImports() { + return BooleanUtils.toBoolean(allowSyntheticDefaultImports); + } + + /** + * Allow default imports from modules with no default export. This does not + * affect code emit, just typechecking. + * + * @param allowSyntheticDefaultImports + */ + public void setAllowSyntheticDefaultImports(Boolean allowSyntheticDefaultImports) { + this.allowSyntheticDefaultImports = allowSyntheticDefaultImports; + } + + /** + * Do not report errors on unreachable code. + * + * @return + */ + public boolean isAllowUnreachableCode() { + return BooleanUtils.toBoolean(allowUnreachableCode); + } + + /** + * Do not report errors on unreachable code. + * + * @param allowUnreachableCode + */ + public void setAllowUnreachableCode(Boolean allowUnreachableCode) { + this.allowUnreachableCode = allowUnreachableCode; + } + + /** + * Do not report errors on unused labels. + * + * @return + */ + public boolean isAllowUnusedLabels() { + return BooleanUtils.toBoolean(allowUnusedLabels); + } + + /** + * Do not report errors on unused labels. + * + * @param allowUnusedLabels + */ + public void setAllowUnusedLabels(Boolean allowUnusedLabels) { + this.allowUnusedLabels = allowUnusedLabels; + } + + /** + * Returns the character set of the input files. + * + * @return the character set of the input files. + */ + public String getCharset() { + return charset; + } + + /** + * The character set of the input files. + * + * @param charset + */ + public void setCharset(String charset) { + this.charset = charset; + } + + /** + * Returns true of generates corresponding d.ts files and false otherwise. + * + * @return true of generates corresponding d.ts files and false otherwise. + */ + public boolean isDeclaration() { + return BooleanUtils.toBoolean(declaration); + } + + /** + * Set to true of generates corresponding d.ts files and false otherwise. + * + * @param declaration + */ + public void setDeclaration(Boolean declaration) { + this.declaration = declaration; + } + + /** + * Show diagnostic information. + * + * @return + */ + public boolean isDiagnostics() { + return BooleanUtils.toBoolean(diagnostics); + } + + /** + * Show diagnostic information. + * + * @param diagnostics + */ + public void setDiagnostics(Boolean diagnostics) { + this.diagnostics = diagnostics; + } + + /** + * Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. + * + * @return + */ + public boolean isEmitBOM() { + return BooleanUtils.toBoolean(emitBOM); + } + + /** + * Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. + * + * @param emitBOM + */ + public void setEmitBOM(Boolean emitBOM) { + this.emitBOM = emitBOM; + } + + /** + * Emit design-type metadata for decorated declarations in source. See issue + * https://github.com/Microsoft/TypeScript/issues/2577 for details. + * + * @return + */ + public boolean isEmitDecoratorMetadata() { + return BooleanUtils.toBoolean(emitDecoratorMetadata); + } + + /** + * Emit design-type metadata for decorated declarations in source. See issue + * https://github.com/Microsoft/TypeScript/issues/2577 for details. + * + * @param emitDecoratorMetadata + */ + public void setEmitDecoratorMetadata(Boolean emitDecoratorMetadata) { + this.emitDecoratorMetadata = emitDecoratorMetadata; + } + + /** + * Enables experimental support for ES7 decorators. + * + * @return + */ + public boolean isExperimentalDecorators() { + return BooleanUtils.toBoolean(experimentalDecorators); + } + + /** + * Enables experimental support for ES7 decorators. + * + * @param experimentalDecorators + */ + public void setExperimentalDecorators(Boolean experimentalDecorators) { + this.experimentalDecorators = experimentalDecorators; + } + + /** + * Disallow inconsistently-cased references to the same file. + * + * @return + */ + public boolean isForceConsistentCasingInFileNames() { + return BooleanUtils.toBoolean(forceConsistentCasingInFileNames); + } + + /** + * Disallow inconsistently-cased references to the same file. + * + * @param forceConsistentCasingInFileNames + */ + public void setForceConsistentCasingInFileNames(Boolean forceConsistentCasingInFileNames) { + this.forceConsistentCasingInFileNames = forceConsistentCasingInFileNames; + } + + /** + * Print help message. + * + * @return + */ + public boolean isHelp() { + return BooleanUtils.toBoolean(help); + } + + /** + * Print help message. + * + * @param help + */ + public void setHelp(Boolean help) { + this.help = help; + } + + /** + * Emit a single file with source maps instead of having a separate file. + * + * @return + */ + public boolean isInlineSourceMap() { + return BooleanUtils.toBoolean(inlineSourceMap); + } + + /** + * Emit a single file with source maps instead of having a separate file. + * + * @param inlineSourceMap + */ + public void setInlineSourceMap(Boolean inlineSourceMap) { + this.inlineSourceMap = inlineSourceMap; + } + + /** + * Emit the source alongside the sourcemaps within a single file; requires + * --inlineSourceMap or --sourceMap to be set. + * + * @return + */ + public boolean isInlineSources() { + return BooleanUtils.toBoolean(inlineSources); + } + + /** + * Emit the source alongside the sourcemaps within a single file; requires + * --inlineSourceMap or --sourceMap to be set. + * + * @param inlineSources + */ + public void setInlineSources(Boolean inlineSources) { + this.inlineSources = inlineSources; + } + + /** + * Initializes a TypeScript project and creates a tsconfig.json file. + * + * @return + */ + public boolean isInit() { + return BooleanUtils.toBoolean(init); + } + + /** + * Initializes a TypeScript project and creates a tsconfig.json file. + * + * @param init + */ + public void setInit(Boolean init) { + this.init = init; + } + + /** + * Unconditionally emit imports for unresolved files. + * + * @return + */ + public boolean isIsolatedModules() { + return BooleanUtils.toBoolean(isolatedModules); + } + + /** + * Unconditionally emit imports for unresolved files. + * + * @param isolatedModules + */ + public void setIsolatedModules(Boolean isolatedModules) { + this.isolatedModules = isolatedModules; + } + + /** + * Support JSX in ‘.tsx’ files: 'React' or 'Preserve'. + * + * @see https://www.typescriptlang.org/docs/handbook/jsx.html + * + * @return + */ + public String getJsx() { + return jsx; + } + + /** + * Support JSX in ‘.tsx’ files: 'React' or 'Preserve'. + * + * @see https://www.typescriptlang.org/docs/handbook/jsx.html + * + * @param jsx + */ + public void setJsx(String jsx) { + this.jsx = jsx; + } + + /** + * Print names of generated files part of the compilation. + * + * @return + */ + public boolean isListEmittedFiles() { + return BooleanUtils.toBoolean(listEmittedFiles); + } + + /** + * Print names of generated files part of the compilation. + * + * @param listEmittedFiles + */ + public void setListEmittedFiles(Boolean listEmittedFiles) { + this.listEmittedFiles = listEmittedFiles; + } + + /** + * Returns Print names of files part of the compilation. + * + * @return + * + */ + public boolean isListFiles() { + return BooleanUtils.toBoolean(listFiles); + } + + /** + * Set Print names of files part of the compilation. + * + * @param listFiles + */ + public void setListFiles(Boolean listFiles) { + this.listFiles = listFiles; + } + + /** + * The locale to use to show error messages, e.g. en-us. + * + * @return + */ + public String getLocale() { + return locale; + } + + /** + * The locale to use to show error messages, e.g. en-us. + * + * @param locale + */ + public void setLocale(String locale) { + this.locale = locale; + } + + /** + * Specifies the location where debugger should locate map files instead of + * generated locations. Use this flag if the .map files will be located at + * run-time in a different location than than the .js files. The location + * specified will be embedded in the sourceMap to direct the debugger where + * the map files where be located. + * + * @return + */ + public String getMapRoot() { + return mapRoot; + } + + /** + * Specifies the location where debugger should locate map files instead of + * generated locations. Use this flag if the .map files will be located at + * run-time in a different location than than the .js files. The location + * specified will be embedded in the sourceMap to direct the debugger where + * the map files where be located. + * + * @param mapRoot + */ + public void setMapRoot(String mapRoot) { + this.mapRoot = mapRoot; + } + + /** + * Specify module code generation: 'none', 'commonjs', 'amd', 'system', + * 'umd', 'es6', or 'es2015'. ► Only 'amd' and 'system' can be used in + * conjunction with --outFile. ► 'es6' and 'es2015' values may not be used + * when targeting ES5 or lower. + * + * @return + */ + public String getModule() { + return module; + } + + /** + * Specify module code generation: 'none', 'commonjs', 'amd', 'system', + * 'umd', 'es6', or 'es2015'. ► Only 'amd' and 'system' can be used in + * conjunction with --outFile. ► 'es6' and 'es2015' values may not be used + * when targeting ES5 or lower. + * + * @param module + */ + public void setModule(String module) { + this.module = module; + } + + /** + * Determine how modules get resolved. Either 'node' for Node.js/io.js style + * resolution, or 'classic' (default). See + * https://www.typescriptlang.org/docs/handbook/module-resolution.html + * documentation for more details. + * + * @return + */ + public String getModuleResolution() { + return moduleResolution; + } + + /** + * Determine how modules get resolved. Either 'node' for Node.js/io.js style + * resolution, or 'classic' (default). See + * https://www.typescriptlang.org/docs/handbook/module-resolution.html + * documentation for more details. + * + * @param moduleResolution + */ + public void setModuleResolution(String moduleResolution) { + this.moduleResolution = moduleResolution; + } + + /** + * Use the specified end of line sequence to be used when emitting files: + * 'crlf' (windows) or 'lf' (unix).” + * + * @return + */ + public String getNewLine() { + return newLine; + } + + /** + * Use the specified end of line sequence to be used when emitting files: + * 'crlf' (windows) or 'lf' (unix).” + * + * @param newLine + */ + public void setNewLine(String newLine) { + this.newLine = newLine; + } + + /** + * Do not emit outputs. + * + * @return + */ + public boolean isNoEmit() { + return BooleanUtils.toBoolean(noEmit); + } + + /** + * Do not emit outputs. + * + * @param noEmit + */ + public void setNoEmit(Boolean noEmit) { + this.noEmit = noEmit; + } + + /** + * Do not generate custom helper functions like __extends in compiled + * output. + * + * @return + */ + public boolean isNoEmitHelpers() { + return BooleanUtils.toBoolean(noEmitHelpers); + } + + /** + * Do not generate custom helper functions like __extends in compiled + * output. + * + * @param noEmitHelpers + */ + public void setNoEmitHelpers(Boolean noEmitHelpers) { + this.noEmitHelpers = noEmitHelpers; + } + + /** + * Do not emit outputs if any errors were reported. + * + * @return + */ + public boolean isNoEmitOnError() { + return BooleanUtils.toBoolean(noEmitOnError); + } + + /** + * Do not emit outputs if any errors were reported. + * + * @param noEmitOnError + */ + public void setNoEmitOnError(Boolean noEmitOnError) { + this.noEmitOnError = noEmitOnError; + } + + /** + * Report errors for fallthrough cases in switch statement. + * + * @return + */ + public boolean isNoFallthroughCasesInSwitch() { + return BooleanUtils.toBoolean(noFallthroughCasesInSwitch); + } + + /** + * Report errors for fallthrough cases in switch statement. + * + * @param noFallthroughCasesInSwitch + */ + public void setNoFallthroughCasesInSwitch(Boolean noFallthroughCasesInSwitch) { + this.noFallthroughCasesInSwitch = noFallthroughCasesInSwitch; + } + + /** + * Raise error on expressions and declarations with an implied ‘any’ type. + * + * @return + */ + public boolean isNoImplicitAny() { + return BooleanUtils.toBoolean(noImplicitAny); + } + + /** + * Raise error on expressions and declarations with an implied ‘any’ type. + * + * @param noImplicitAny + */ + public void setNoImplicitAny(Boolean noImplicitAny) { + this.noImplicitAny = noImplicitAny; + } + + /** + * Report error when not all code paths in function return a value. + * + * @return + */ + public boolean isNoImplicitReturns() { + return BooleanUtils.toBoolean(noImplicitReturns); + } + + /** + * Report error when not all code paths in function return a value. + * + * @param noImplicitReturns + */ + public void setNoImplicitReturns(Boolean noImplicitReturns) { + this.noImplicitReturns = noImplicitReturns; + } + + /** + * Do not emit "use strict" directives in module output. + * + * @return + */ + public boolean isNoImplicitUseStrict() { + return BooleanUtils.toBoolean(noImplicitUseStrict); + } + + /** + * Do not emit "use strict" directives in module output. + * + * @param noImplicitUseStrict + */ + public void setNoImplicitUseStrict(Boolean noImplicitUseStrict) { + this.noImplicitUseStrict = noImplicitUseStrict; + } + + /** + * Do not include the default library file (lib.d.ts). + * + * @return + */ + public boolean isNoLib() { + return BooleanUtils.toBoolean(noLib); + } + + /** + * Do not include the default library file (lib.d.ts). + * + * @param noLib + */ + public void setNoLib(Boolean noLib) { + this.noLib = noLib; + } + + /** + * Do not add triple-slash references or module import targets to the list + * of compiled files. + * + * @return + */ + public boolean isNoResolve() { + return BooleanUtils.toBoolean(noResolve); + } + + /** + * Do not add triple-slash references or module import targets to the list + * of compiled files. + * + * @param noResolve + */ + public void setNoResolve(Boolean noResolve) { + this.noResolve = noResolve; + } + + /** + * Same thing than outFile but deprectaed. + * + * @return + */ + public String getOut() { + return out; + } + + /** + * Same thing than outFile but deprectaed. + * + * @param out + */ + public void setOut(String out) { + this.out = out; + } + + /** + * Redirect output structure to the directory. + * + * @return + */ + public String getOutDir() { + return outDir; + } + + /** + * Redirect output structure to the directory. + * + * @param outDir + */ + public void setOutDir(String outDir) { + this.outDir = outDir; + } + + /** + * Concatenate and emit output to single file. The order of concatenation is + * determined by the list of files passed to the compiler on the command + * line along with triple-slash references and imports. See output file + * order documentation for more details. + * + * @return + */ + public String getOutFile() { + return outFile; + } + + /** + * Concatenate and emit output to single file. The order of concatenation is + * determined by the list of files passed to the compiler on the command + * line along with triple-slash references and imports. See output file + * order documentation for more details. + * + * @param outFile + */ + public void setOutFile(String outFile) { + this.outFile = outFile; + } + + /** + * Specify path mapping to be computed relative to baseUrl option. + * + * @return key patterns to which paths are mapped. + */ + public Set getPathsKeys() { + if (paths == null) { + return Collections.emptySet(); + } + return Collections.unmodifiableSet(paths.keySet()); + } + + /** + * Specify path mapping to be computed relative to baseUrl option. + * + * @param pathsKey + * a path key pattern. + * @return paths mapped to the key pattern. + */ + public List getPathsKeyValues(String pathsKey) { + if (paths == null) { + return Collections.emptyList(); + } + List values = paths.get(pathsKey); + if (values == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(values); + } + + /** + * Specify path mapping to be computed relative to baseUrl option. + * + * @param paths + */ + public void setPaths(Map> paths) { + Map> pathsCopy = new HashMap<>(paths.size()); + for (Map.Entry> entry : paths.entrySet()) { + pathsCopy.put(entry.getKey(), new ArrayList<>(entry.getValue())); + } + this.paths = pathsCopy; + } + + /** + * Do not erase const enum declarations in generated code. See const enums + * https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#94-constant-enum-declarations + * documentation for more details. + * + * @return + */ + public boolean isPreserveConstEnums() { + return BooleanUtils.toBoolean(preserveConstEnums); + } + + /** + * Do not erase const enum declarations in generated code. See const enums + * https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#94-constant-enum-declarations + * documentation for more details. + * + * @param preserveConstEnums + */ + public void setPreserveConstEnums(Boolean preserveConstEnums) { + this.preserveConstEnums = preserveConstEnums; + } + + /** + * Stylize errors and messages using color and context. + * + * @return + */ + public boolean isPretty() { + return BooleanUtils.toBoolean(pretty); + } + + /** + * Stylize errors and messages using color and context. + * + * @param pretty + */ + public void setPretty(Boolean pretty) { + this.pretty = pretty; + } + + /** + * Compile the project in the given directory. The directory needs to + * contain a tsconfig.json file to direct compilation. See tsconfig.json + * documentation for more details. + * + * @return + */ + public String getProject() { + return project; + } + + /** + * Compile the project in the given directory. The directory needs to + * contain a tsconfig.json file to direct compilation. See tsconfig.json + * documentation for more details. + * + * @param project + */ + public void setProject(String project) { + this.project = project; + } + + /** + * Specifies the object invoked for createElement and __spread when + * targeting ‘react’ JSX emit. + * + * @return + */ + public String getReactNamespace() { + return reactNamespace; + } + + /** + * Specifies the object invoked for createElement and __spread when + * targeting ‘react’ JSX emit. + * + * @param reactNamespace + */ + public void setReactNamespace(String reactNamespace) { + this.reactNamespace = reactNamespace; + } + + /** + * Remove all comments except copy-right header comments beginning with /*! + * + * @return + */ + public boolean isRemoveComments() { + return BooleanUtils.toBoolean(removeComments); + } + + /** + * Remove all comments except copy-right header comments beginning with /*! + * + * @param removeComments + */ + public void setRemoveComments(Boolean removeComments) { + this.removeComments = removeComments; + } + + /** + * Specifies the root directory of input files. Only use to control the + * output directory structure with --outDir. + * + * @return + */ + public String getRootDir() { + return rootDir; + } + + /** + * Specifies the root directory of input files. Only use to control the + * output directory structure with --outDir. + * + * @param rootDir + */ + public void setRootDir(String rootDir) { + this.rootDir = rootDir; + } + + /** + * Specify list of root directory to be used when resolving modules. + * + * @return + */ + public List getRootDirs() { + if (rootDirs == null) { + return Collections.emptyList(); + } + return Collections.unmodifiableList(rootDirs); + } + + /** + * Specify list of root directory to be used when resolving modules. + * + * @param rootDirs + */ + public void setRootDirs(List rootDirs) { + this.rootDirs = new ArrayList<>(rootDirs); + } + + /** + * Don’t check a user-defined default lib file’s valitidy. + * + * @return + */ + public boolean isSkipDefaultLibCheck() { + return BooleanUtils.toBoolean(skipDefaultLibCheck); + } + + /** + * Don’t check a user-defined default lib file’s valitidy. + * + * @param skipDefaultLibCheck + */ + public void setSkipDefaultLibCheck(Boolean skipDefaultLibCheck) { + this.skipDefaultLibCheck = skipDefaultLibCheck; + } + + /** + * Generates corresponding '.map' file. + * + * @return + */ + public boolean isSourceMap() { + return BooleanUtils.toBoolean(sourceMap); + } + + /** + * Generates corresponding '.map' file. + * + * @param sourceMap + */ + public void setSourceMap(Boolean sourceMap) { + this.sourceMap = sourceMap; + } + + /** + * Specifies the location where debugger should locate TypeScript files + * instead of source locations. Use this flag if the sources will be located + * at run-time in a different location than that at design-time. The + * location specified will be embedded in the sourceMap to direct the + * debugger where the source files where be located. + * + * @return + */ + public String getSourceRoot() { + return sourceRoot; + } + + /** + * Specifies the location where debugger should locate TypeScript files + * instead of source locations. Use this flag if the sources will be located + * at run-time in a different location than that at design-time. The + * location specified will be embedded in the sourceMap to direct the + * debugger where the source files where be located. + * + * @param sourceRoot + */ + public void setSourceRoot(String sourceRoot) { + this.sourceRoot = sourceRoot; + } + + /** + * In strict null checking mode, the null and undefined values are not in + * the domain of every type and are only assignable to themselves and any + * (the one exception being that undefined is also assignable to void). + * + * @return + */ + public boolean isStrictNullChecks() { + return BooleanUtils.toBoolean(strictNullChecks); + } + + /** + * In strict null checking mode, the null and undefined values are not in + * the domain of every type and are only assignable to themselves and any + * (the one exception being that undefined is also assignable to void). + * + * @param strictNullChecks + */ + public void setStrictNullChecks(Boolean strictNullChecks) { + this.strictNullChecks = strictNullChecks; + } + + /** + * Do not emit declarations for code that has an @internal JSDoc annotation. + * + * @return + */ + public boolean isStripInternal() { + return BooleanUtils.toBoolean(stripInternal); + } + + /** + * Do not emit declarations for code that has an @internal JSDoc annotation. + * + * @param stripInternal + */ + public void setStripInternal(Boolean stripInternal) { + this.stripInternal = stripInternal; + } + + /** + * Suppress excess property checks for object literals. + * + * @return + */ + public boolean isSuppressExcessPropertyErrors() { + return BooleanUtils.toBoolean(suppressExcessPropertyErrors); + } + + /** + * Suppress excess property checks for object literals. + * + * @param suppressExcessPropertyErrors + */ + public void setSuppressExcessPropertyErrors(Boolean suppressExcessPropertyErrors) { + this.suppressExcessPropertyErrors = suppressExcessPropertyErrors; + } + + /** + * Suppress --noImplicitAny errors for indexing objects lacking index + * signatures. See issue #1232 + * https://github.com/Microsoft/TypeScript/issues/1232#issuecomment-64510362 + * for more details. + * + * @return + */ + public boolean isSuppressImplicitAnyIndexErrors() { + return BooleanUtils.toBoolean(suppressImplicitAnyIndexErrors); + } + + /** + * Suppress --noImplicitAny errors for indexing objects lacking index + * signatures. See issue #1232 + * https://github.com/Microsoft/TypeScript/issues/1232#issuecomment-64510362 + * for more details. + * + * @param suppressImplicitAnyIndexErrors + */ + public void setSuppressImplicitAnyIndexErrors(Boolean suppressImplicitAnyIndexErrors) { + this.suppressImplicitAnyIndexErrors = suppressImplicitAnyIndexErrors; + } + + /** + * Specify ECMAScript target version: 'es3' (default), 'es5', or 'es6'. + * + * @return + */ + public String getTarget() { + return target; + } + + /** + * Specify ECMAScript target version: 'es3' (default), 'es5', or 'es6'. + * + * @param target + */ + public void setTarget(String target) { + this.target = target; + } + + /** + * Report module resolution log messages. + * + * @return + */ + public boolean isTraceResolution() { + return BooleanUtils.toBoolean(traceResolution); + } + + /** + * Report module resolution log messages. + * + * @param traceResolution + */ + public void setTraceResolution(Boolean traceResolution) { + this.traceResolution = traceResolution; + } + + /** + * Print the compiler’s version. + * + * @return + */ + public boolean isVersion() { + return BooleanUtils.toBoolean(version); + } + + /** + * Print the compiler’s version. + * + * @param version + */ + public void setVersion(Boolean version) { + this.version = version; + } + + /** + * Run the compiler in watch mode. Watch input files and trigger + * recompilation on changes. + * + * @param watch + */ + public void setWatch(Boolean watch) { + this.watch = watch; + } + + /** + * Run the compiler in watch mode. Watch input files and trigger + * recompilation on changes. + * + * @return + */ + public Boolean isWatch() { + return BooleanUtils.toBoolean(watch); + } + + public List getPlugins() { + return plugins; + } + + public void setPlugins(List plugins) { + this.plugins = plugins; + } + + public void fillOptions(List args) { + if (isHelp()) { + args.add("--help"); + return; + } + if (isVersion()) { + args.add("--version"); + return; + } + fillOption("--allowJs", isAllowJs(), args); + fillOption("--allowSyntheticDefaultImports", isAllowSyntheticDefaultImports(), args); + fillOption("--allowUnreachableCode", isAllowUnreachableCode(), args); + fillOption("--allowUnusedLabels", isAllowUnusedLabels(), args); + fillOption("--charset", getCharset(), args); + fillOption("--declaration", isDeclaration(), args); + fillOption("--diagnostics", isDiagnostics(), args); + fillOption("--emitBOM", isEmitBOM(), args); + fillOption("--emitDecoratorMetadata", isEmitDecoratorMetadata(), args); + fillOption("--experimentalDecorators", isExperimentalDecorators(), args); + fillOption("--forceConsistentCasingInFileNames", isForceConsistentCasingInFileNames(), args); + fillOption("--inlineSourceMap", isInlineSourceMap(), args); + fillOption("--inlineSources", isInlineSources(), args); + fillOption("--init", isInit(), args); + fillOption("--isolatedModules", isIsolatedModules(), args); + fillOption("--jsx", getJsx(), args); + fillOption("--listEmittedFiles", isListEmittedFiles(), args); + fillOption("--listFiles", isListFiles(), args); + fillOption("--locale", getLocale(), args); + fillOption("--mapRoot", getMapRoot(), args); + fillOption("--module", getModule(), args); + fillOption("--moduleResolution", getModuleResolution(), args); + fillOption("--newLine", getNewLine(), args); + fillOption("--noEmit", isNoEmit(), args); + fillOption("--noEmitHelpers", isNoEmitHelpers(), args); + fillOption("--noEmitOnError", isNoEmitOnError(), args); + fillOption("--noEmitOnError", isNoEmitOnError(), args); + fillOption("--noFallthroughCasesInSwitch", isNoFallthroughCasesInSwitch(), args); + fillOption("--noImplicitAny", isNoImplicitAny(), args); + fillOption("--noImplicitReturns", isNoImplicitReturns(), args); + fillOption("--noImplicitUseStrict", isNoImplicitUseStrict(), args); + fillOption("--noLib", isNoLib(), args); + fillOption("--noResolve", isNoResolve(), args); + fillOption("--out", getOut(), args); + fillOption("--outDir", getOutDir(), args); + fillOption("--outFile", getOutFile(), args); + fillOption("--preserveConstEnums", isPreserveConstEnums(), args); + fillOption("--pretty", isPretty(), args); + fillOption("--project", getProject(), args); + fillOption("--reactNamespace", getReactNamespace(), args); + fillOption("--removeComments", isRemoveComments(), args); + fillOption("--rootDir", getRootDir(), args); + fillOption("--skipDefaultLibCheck", isSkipDefaultLibCheck(), args); + fillOption("--sourceMap", isSourceMap(), args); + fillOption("--strictNullChecks", isStrictNullChecks(), args); + fillOption("--stripInternal", isStripInternal(), args); + fillOption("--suppressExcessPropertyErrors", isSuppressExcessPropertyErrors(), args); + fillOption("--suppressImplicitAnyIndexErrors", isSuppressImplicitAnyIndexErrors(), args); + fillOption("--target", getTarget(), args); + fillOption("--traceResolution", isTraceResolution(), args); + fillOption("--version", isVersion(), args); + fillOption("--watch", isWatch(), args); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tsc/ITypeScriptCompiler.java b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/ITypeScriptCompiler.java new file mode 100644 index 000000000..4ffcf999d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/ITypeScriptCompiler.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.cmd.tsc; + +import java.io.File; +import java.util.List; + +import ts.TypeScriptException; +import ts.nodejs.INodejsProcess; +import ts.nodejs.INodejsProcessListener; + +/** + * API for TypeScript compiler which uses 'tsc' + * + */ +public interface ITypeScriptCompiler { + + /** + * Execute 'tsc' command from the given directory. + * + * @param baseDir + * the directory where 'tsc' must be executed. + * @return + * @throws TypeScriptException + */ + INodejsProcess execute(File baseDir, CompilerOptions options, List filenames, + INodejsProcessListener listener) throws TypeScriptException; + + /** + * Dispose the compiler. + */ + void dispose(); + + List createCommands(CompilerOptions options, List filenames); +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tsc/ITypeScriptCompilerMessageHandler.java b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/ITypeScriptCompilerMessageHandler.java new file mode 100644 index 000000000..73742bcde --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/ITypeScriptCompilerMessageHandler.java @@ -0,0 +1,11 @@ +package ts.cmd.tsc; + +import ts.cmd.ITypeScriptLinterHandler; + +public interface ITypeScriptCompilerMessageHandler extends ITypeScriptLinterHandler { + + void addFile(String file, boolean emitted); + + void onCompilationCompleteWatchingForFileChanges(); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tsc/Plugin.java b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/Plugin.java new file mode 100644 index 000000000..c6f63c66c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/Plugin.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + * + */ +package ts.cmd.tsc; + +/** + * TypeScript 2.3 compilerOptions/plugins + * + */ +public class Plugin { + + private String name; + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tsc/TypeScriptCompiler.java b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/TypeScriptCompiler.java new file mode 100644 index 000000000..ca1938a5a --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/TypeScriptCompiler.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.cmd.tsc; + +import java.io.File; + +import ts.cmd.AbstractCmd; + +public class TypeScriptCompiler extends AbstractCmd implements ITypeScriptCompiler { + + private static final String TSC_FILE_TYPE = "tsc"; + + public TypeScriptCompiler(File tscFile, File nodejsFile) { + super(tscFile, nodejsFile, TSC_FILE_TYPE); + } + + @Override + public void dispose() { + + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tsc/TypeScriptCompilerHelper.java b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/TypeScriptCompilerHelper.java new file mode 100644 index 000000000..457176965 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tsc/TypeScriptCompilerHelper.java @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.cmd.tsc; + +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import ts.client.Location; +import ts.cmd.Severity; +import ts.utils.FileUtils; +import ts.utils.StringUtils; + +/** + * TypeScript Compiler (tsc) helper. + * + */ +public class TypeScriptCompilerHelper { + + private static final Pattern TSC_ERROR_PATTERN = Pattern.compile( + "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$"); + + private static final String COMPILATION_COMPLETE_WATCHING_FOR_FILE_CHANGES = "Compilation complete. Watching for file changes."; + + private static final String TSFILE = "TSFILE:"; + + /** + * Process "tsc" message and call the well + * {@link ITypeScriptCompilerMessageHandler} method. + * + * @param text + * @param handler + */ + public static void processMessage(String text, ITypeScriptCompilerMessageHandler handler) { + if (StringUtils.isEmpty(text)) { + return; + } + + Scanner scanner = null; + try { + scanner = new Scanner(text); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + line = line.trim(); // remove leading whitespace + if (line.endsWith(FileUtils.TS_EXTENSION) || line.endsWith(FileUtils.TSX_EXTENSION)) { + // Occurs when tsc is called with --listFiles + handler.addFile(line, false); + } else if (line.contains(COMPILATION_COMPLETE_WATCHING_FOR_FILE_CHANGES)) { + // Occurs when tsc is called with --watch when compilation + // is finished. + handler.onCompilationCompleteWatchingForFileChanges(); + } else if (line.startsWith(TSFILE)) { + handler.addFile(line.substring(TSFILE.length(), line.length()).trim(), true); + } else { + Matcher m = TSC_ERROR_PATTERN.matcher(line); + if (m.matches()) { + // Error in an ts file. + String file = m.group(1); + String[] location = m.group(2).split(","); + Location startLoc = createLocation(location, true); + Location endLoc = createLocation(location, false); + String severity = m.group(3); + String code = m.group(4); + String message = m.group(5); + handler.addError(file, startLoc, endLoc, + StringUtils.isEmpty(severity) ? Severity.info : Severity.valueOf(severity), code, + message); + } + } + } + } finally + + { + if (scanner != null) { + scanner.close(); + } + } + } + + private static Location createLocation(String[] location, boolean start) { + if (start) { + int line = getInt(location, 0); + int offset = getInt(location, 1); + return new Location(line, offset); + } + return null; + } + + private static int getInt(String[] location, int index) { + if (index < location.length) { + return Integer.parseInt(location[index]); + } + return 0; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tslint/ITypeScriptLint.java b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/ITypeScriptLint.java new file mode 100644 index 000000000..402237793 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/ITypeScriptLint.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.cmd.tslint; + +import java.io.File; +import java.util.List; + +import ts.TypeScriptException; +import ts.nodejs.INodejsProcess; +import ts.nodejs.INodejsProcessListener; + +public interface ITypeScriptLint { + + /** + * Execute 'tslint' command from the given directory. + * + * @param baseDir + * the directory where 'tsc' must be executed. + * @return + * @throws TypeScriptException + */ + INodejsProcess execute(File baseDir, TSLintOptions options, List filenames, INodejsProcessListener listener) + throws TypeScriptException; + + List createCommands(TSLintOptions options, List filenames); +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TSLintOptions.java b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TSLintOptions.java new file mode 100644 index 000000000..ca5a00b81 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TSLintOptions.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.cmd.tslint; + +import java.io.File; +import java.util.List; + +import ts.cmd.AbstractOptions; +import ts.utils.FileUtils; + +/** + * tslint options. + * + * @see http://palantir.github.io/tslint/usage/cli/ + * + */ +public class TSLintOptions extends AbstractOptions { + + private String config; + private String format; + + public String getConfig() { + return config; + } + + public void setConfig(String config) { + this.config = config; + } + + public void setConfig(File configFile) { + if (configFile != null) { + setConfig(FileUtils.getPath(configFile)); + } + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public void setFormat(TslintFormat format) { + setFormat(format.name()); + } + + @Override + public void fillOptions(List args) { + super.fillOption("--config", getConfig(), args); + super.fillOption("--format", getFormat(), args); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintFormat.java b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintFormat.java new file mode 100644 index 000000000..7136986f6 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintFormat.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.cmd.tslint; + +/** + * Supported tslint --format. + * + */ +public enum TslintFormat { + + prose, json, verbose, pmd, msbuild, checkstyle +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintHelper.java b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintHelper.java new file mode 100644 index 000000000..f427de251 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintHelper.java @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.cmd.tslint; + +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonArray; +import com.eclipsesource.json.JsonObject; +import com.eclipsesource.json.JsonValue; + +import ts.client.Location; +import ts.cmd.ITypeScriptLinterHandler; +import ts.cmd.Severity; +import ts.utils.StringUtils; + +/** + * TypeScript Compiler (tsc) helper. + * + */ +public class TslintHelper { + + // ex: "(no-var-keyword) sample.ts[1, 1]: forbidden 'var' keyword, use 'let' + // or 'const' instead", errors); + // sample.ts(1,14): error TS1003: Identifier expected. + + private static final Pattern TSLINT_PATTERN = Pattern + .compile("^\\(\\s*(.*)\\)\\s([^\\s].*)\\[(\\d+,\\s*\\d+)\\]:\\s*(.*)$"); + + /** + * Process "tslint" message and call the well + * {@link ITypeScriptLinterHandler} method. + * + * @param text + * @param handler + */ + public static void processVerboseMessage(String text, ITypeScriptLinterHandler handler) { + if (StringUtils.isEmpty(text)) { + return; + } + + Scanner scanner = null; + try { + scanner = new Scanner(text); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + line = line.trim(); // remove leading whitespace + Matcher m = TSLINT_PATTERN.matcher(line); + if (m.matches()) { + // Error in an ts file. + String code = m.group(1); + String file = m.group(2); + String[] location = m.group(3).split(","); + Location startLoc = createLocation(location, true); + Location endLoc = null; // createLocation(location, false); + String message = m.group(4); + handler.addError(file, startLoc, endLoc, Severity.error, code, message); + } + } + } finally { + if (scanner != null) { + scanner.close(); + } + } + } + + private static Location createLocation(String[] location, boolean start) { + if (start) { + int line = getInt(location, 0); + int offset = getInt(location, 1); + return new Location(line, offset); + } + return null; + } + + private static int getInt(String[] location, int index) { + if (index < location.length) { + return Integer.parseInt(location[index].trim()); + } + return 0; + } + + public static void processJsonMessage(String text, ITypeScriptLinterHandler handler) { + if (StringUtils.isEmpty(text)) { + return; + } + + Scanner scanner = null; + try { + scanner = new Scanner(text); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + line = line.trim(); // remove leading whitespace + JsonArray array = Json.parse(line).asArray(); + for (JsonValue value : array) { + // [{"endPosition":{"character":3,"line":0,"position":3},"failure":"forbidden + // 'var' keyword, use 'let' or 'const' + // instead","name":"sample.ts","ruleName":"no-var-keyword","startPosition":{"character":0,"line":0,"position":0}},{"endPosition":{"character":13,"line":0,"position":13},"failure":"missing + // semicolon","name":"sample.ts","ruleName":"semicolon","startPosition":{"character":13,"line":0,"position":13}},{"endPosition":{"character":12,"line":0,"position":12},"failure":"missing + // whitespace","name":"sample.ts","ruleName":"whitespace","startPosition":{"character":11,"line":0,"position":11}}] + JsonObject item = value.asObject(); + String name = item.getString("name", null); + String ruleName = item.getString("ruleName", null); + String failure = item.getString("failure", null); + Location startLoc = createLocation(item.get("startPosition")); + Location endLoc = createLocation(item.get("endPosition")); + handler.addError(name, startLoc, endLoc, Severity.error, ruleName, failure); + } + } + } finally { + if (scanner != null) { + scanner.close(); + } + } + } + + private static Location createLocation(JsonValue value) { + if (value == null || !value.isObject()) { + return null; + } + JsonObject loc = value.asObject(); + return new Location(loc.getInt("line", -1), loc.getInt("character", -1), loc.getInt("position", -1)); + } + +} \ No newline at end of file diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintSettingsStrategy.java b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintSettingsStrategy.java new file mode 100644 index 000000000..598a94aca --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TslintSettingsStrategy.java @@ -0,0 +1,7 @@ +package ts.cmd.tslint; + +public enum TslintSettingsStrategy { + + DisableTslint, UseDefaultTslintJson, UseCustomTslintJson, SearchForTslintJson + +} diff --git a/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TypeScriptLint.java b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TypeScriptLint.java new file mode 100644 index 000000000..8ad020953 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/cmd/tslint/TypeScriptLint.java @@ -0,0 +1,22 @@ +package ts.cmd.tslint; + +import java.io.File; + +import ts.cmd.AbstractCmd; + +public class TypeScriptLint extends AbstractCmd implements ITypeScriptLint { + + private static final String TSLINT_FILE_TYPE = "tslint"; + + private final File tslintJsonFile; + + public TypeScriptLint(File tslintFile, File tslintJsonFile, File nodejsFile) { + super(tslintFile, nodejsFile, TSLINT_FILE_TYPE); + this.tslintJsonFile = tslintJsonFile; + } + + public File getTslintJsonFile() { + return tslintJsonFile; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/Activator.java b/typescript.java-ts.core/src/main/java/ts/internal/Activator.java new file mode 100644 index 000000000..ad117f5e0 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/Activator.java @@ -0,0 +1,30 @@ +package ts.internal; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class Activator implements BundleActivator { + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Activator.context = null; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/FileTempHelper.java b/typescript.java-ts.core/src/main/java/ts/internal/FileTempHelper.java new file mode 100644 index 000000000..4f247030d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/FileTempHelper.java @@ -0,0 +1,73 @@ +package ts.internal; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; + +import ts.TypeScriptException; + +public class FileTempHelper { + + private final static Stack availableTempFileList = new Stack(); + private final static Map seq_to_tempfile_name = new HashMap(); + + public static String updateTempFile(String newText, int seq) throws TypeScriptException { + Writer writer = null; + try { + File tempFile = getTempFile(seq); + writer = new FileWriter(tempFile); + writer.write(newText); + writer.flush(); + return tempFile.getCanonicalPath(); + } catch (Exception e) { + throw new TypeScriptException(e); + } finally { + try { + if (writer != null) { + writer.close(); + } + } catch (IOException e) { + throw new TypeScriptException(e); + } + } + } + + /** + * Get the first unused temp file name to avoid conflicts. + * + * @return + * @throws IOException + */ + private static File getTempFile(int seq) throws IOException { + File tempFile = null; + synchronized (availableTempFileList) { + if (!availableTempFileList.isEmpty()) { + tempFile = availableTempFileList.pop(); + } else { + tempFile = File.createTempFile("tmptsjava." + SequenceHelper.getTempSeq(), null); + tempFile.deleteOnExit(); + } + seq_to_tempfile_name.put(seq, tempFile); + } + return tempFile; + } + + /** + * Post process after receiving a reload response + * + * @param seq + */ + public static void freeTempFile(int seq) { + synchronized (availableTempFileList) { + File tempFile = seq_to_tempfile_name.remove(seq); + if (tempFile != null) { + availableTempFileList.push(tempFile); + } + } + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/LocationReader.java b/typescript.java-ts.core/src/main/java/ts/internal/LocationReader.java new file mode 100644 index 000000000..7772df0d3 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/LocationReader.java @@ -0,0 +1,57 @@ +package ts.internal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +import ts.client.Location; + +public class LocationReader { + + private Location loc; + + public LocationReader(String contents, int position) { + List lines = readLines(contents); + int offset = position; + int current = position; + int line = 0; + for (Integer lineOffset : lines) { + if (line > 0) { + current -= "\r\n".length(); + } + if (current <= lineOffset) { + offset = current; + break; + } else { + current -= lineOffset; + } + line++; + } + this.loc = new Location(line + 1, offset + 1); + } + + public Location getLineOffset() { + return loc; + } + + private List readLines(final String input) { + final List list = new ArrayList(); + try { + final BufferedReader reader = new BufferedReader(new StringReader(input)); + String line = reader.readLine(); + while (line != null) { + if (list.size() > 0) { + list.add(line.length());// "\r\n".length()); + } else { + list.add(line.length()); + } + line = reader.readLine(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return list; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/SequenceHelper.java b/typescript.java-ts.core/src/main/java/ts/internal/SequenceHelper.java new file mode 100644 index 000000000..9eec6d515 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/SequenceHelper.java @@ -0,0 +1,17 @@ +package ts.internal; + +import java.util.concurrent.atomic.AtomicInteger; + +public class SequenceHelper { + + private final static AtomicInteger requestSeq = new AtomicInteger(); + private final static AtomicInteger tmpSeq = new AtomicInteger(); + + public static int getRequestSeq() { + return requestSeq.getAndIncrement(); + } + + public static int getTempSeq() { + return tmpSeq.getAndIncrement(); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/AbstractFormatRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/AbstractFormatRequest.java new file mode 100644 index 000000000..c9d4c5736 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/AbstractFormatRequest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Format request; value of command field is "format". Return response giving + * zero or more edit instructions. The edit instructions will be sorted in file + * order. Applying the edit instructions in reverse to file will result in + * correctly reformatted text. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public abstract class AbstractFormatRequest extends FileLocationRequest { + + public AbstractFormatRequest(String command, T arguments) { + super(command, arguments); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ChangeRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ChangeRequest.java new file mode 100644 index 000000000..ffb1ed2b2 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ChangeRequest.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; + +/** + * Change request message; value of command field is "change". Update the + * server's view of the file named by argument 'file'. Server does not currently + * send a response to a change request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class ChangeRequest extends AbstractFormatRequest { + + public ChangeRequest(String fileName, int position, int endPosition, String insertString) { + super(CommandNames.Change.getName(), new ChangeRequestArgs(fileName, position, endPosition, insertString)); + } + + public ChangeRequest(String fileName, int line, int offset, int endLine, int endOffset, String insertString) { + super(CommandNames.Change.getName(), + new ChangeRequestArgs(fileName, line, offset, endLine, endOffset, insertString)); + } + + @Override + public Response parseResponse(JsonObject json) { + // This request doesn't return response. + return null; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ChangeRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ChangeRequestArgs.java new file mode 100644 index 000000000..c9bd9cead --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ChangeRequestArgs.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for change request message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ChangeRequestArgs extends FormatRequestArgs { + + /** + * Optional string to insert at location (file, line, offset). + */ + private final String insertString; + + public ChangeRequestArgs(String file, int position, int endPosition, String insertString) { + super(file, position, endPosition); + this.insertString = insertString; + } + + public ChangeRequestArgs(String file, int line, int offset, int endLine, int endOffset, String insertString) { + super(file, line, offset, endLine, endOffset); + this.insertString = insertString; + } + + public String getInsertString() { + return insertString; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseExternalProjectRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseExternalProjectRequest.java new file mode 100644 index 000000000..03d048195 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseExternalProjectRequest.java @@ -0,0 +1,25 @@ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; + +/** + * Request to open or update external project. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CloseExternalProjectRequest extends Request { + + public CloseExternalProjectRequest(String projectFileName) { + super(CommandNames.CloseExternalProject.getName(), + new CloseExternalProjectRequestArgs(projectFileName)); + } + + @Override + public Response parseResponse(JsonObject json) { + // This request doesn't return response. + return null; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseExternalProjectRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseExternalProjectRequestArgs.java new file mode 100644 index 000000000..bede58448 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseExternalProjectRequestArgs.java @@ -0,0 +1,16 @@ +package ts.internal.client.protocol; + +/** + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class CloseExternalProjectRequestArgs { + + /** + * Project name + */ + String projectFileName; + + public CloseExternalProjectRequestArgs(String projectFileName) { + this.projectFileName = projectFileName; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseRequest.java new file mode 100644 index 000000000..bbbb13042 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CloseRequest.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; + +/** + * Close request; value of command field is "close". Notify the server that the + * client has closed a previously open file. If file is still referenced by open + * files, the server will resume monitoring the filesystem for changes to file. + * Server does not currently send a response to a close request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class CloseRequest extends FileRequest { + + public CloseRequest(String fileName) { + super(CommandNames.Close.getName(), new FileRequestArgs(fileName, null)); + } + + @Override + public Response parseResponse(JsonObject json) { + // This request doesn't return response. + return null; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CodeFixRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CodeFixRequest.java new file mode 100644 index 000000000..9d9329bf8 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CodeFixRequest.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.codefixes.CodeAction; + +/** + * Configure request; value of command field is "configure". Specifies host + * information, such as host type, tab size, and indent size. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class CodeFixRequest extends Request { + + public CodeFixRequest(String file, int startLine, int startOffset, int endLine, int endOffset, + List errorCodes) { + super(CommandNames.GetCodeFixes.getName(), + new CodeFixRequestArgs(file, startLine, startOffset, endLine, endOffset, errorCodes)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, GetCodeFixesResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CodeFixRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CodeFixRequestArgs.java new file mode 100644 index 000000000..a807bba87 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CodeFixRequestArgs.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +/** + * Instances of this interface specify errorcodes on a specific location in a + * sourcefile. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CodeFixRequestArgs extends FileRangeRequestArgs { + + /** + * Errorcodes we want to get the fixes for. + */ + private List errorCodes; + + public CodeFixRequestArgs(String file, int startLine, int startOffset, int endLine, int endOffset, + List errorCodes) { + this(file, startLine, startOffset, endLine, endOffset, errorCodes, null, null, null); + } + + private CodeFixRequestArgs(String file, Integer startLine, Integer startOffset, Integer endLine, Integer endOffset, + List errorCodes, Integer startPosition, Integer endPosition, String projectName) { + super(file, startLine, startOffset, endLine, endOffset); + this.errorCodes = errorCodes; + } + + public List getErrorCodes() { + return errorCodes; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveAffectedFileListRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveAffectedFileListRequest.java new file mode 100644 index 000000000..0a8319ee3 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveAffectedFileListRequest.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.compileonsave.CompileOnSaveAffectedFileListSingleProject; + +/** + * Request to obtain the list of files that should be regenerated if target file + * is recompiled. NOTE: this us query-only operation and does not generate any + * output on disk. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class CompileOnSaveAffectedFileListRequest extends FileRequest { + + public CompileOnSaveAffectedFileListRequest(String fileName) { + super(CommandNames.CompileOnSaveAffectedFileList.getName(), new FileRequestArgs(fileName, null)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, CompileOnSaveAffectedFileListResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveAffectedFileListResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveAffectedFileListResponse.java new file mode 100644 index 000000000..405c50e51 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveAffectedFileListResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.compileonsave.CompileOnSaveAffectedFileListSingleProject; + +/** + * Response for CompileOnSaveAffectedFileListRequest request; + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class CompileOnSaveAffectedFileListResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileRequest.java new file mode 100644 index 000000000..7bf81b723 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileRequest.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; + +/** + * Request to recompile the file. All generated outputs (.js, .d.ts or .js.map + * files) is written on disk. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class CompileOnSaveEmitFileRequest extends Request { + + public CompileOnSaveEmitFileRequest(String file, Boolean forced) { + super(CommandNames.CompileOnSaveEmitFile.getName(), new CompileOnSaveEmitFileRequestArgs(file, forced)); + } + + @Override + public Response parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, CompileOnSaveEmitFileResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileRequestArgs.java new file mode 100644 index 000000000..f67bc60d9 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileRequestArgs.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for CompileOnSaveEmitFileRequest + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CompileOnSaveEmitFileRequestArgs extends FileRequestArgs { + + /** + * if true - then file should be recompiled even if it does not have any + * changes. + */ + private final Boolean forced; + + public CompileOnSaveEmitFileRequestArgs(String file, Boolean forced) { + super(file, null); + this.forced = forced; + } + + public Boolean getForced() { + return forced; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileResponse.java new file mode 100644 index 000000000..ee49f138d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompileOnSaveEmitFileResponse.java @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Response for CompileOnSaveRequest request; + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class CompileOnSaveEmitFileResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsRequest.java new file mode 100644 index 000000000..d070660e1 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsRequest.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.completions.CompletionEntryDetails; + +/** + * Completion entry details request; value of command field is + * "completionEntryDetails". Given a file location (file, line, col) and an + * array of completion entry names return more detailed information for each + * completion entry. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CompletionDetailsRequest extends FileLocationRequest { + + public CompletionDetailsRequest(String file, int line, int offset, String prefix, String[] entryNames) { + super(CommandNames.CompletionEntryDetails.getName(), + new CompletionDetailsRequestArgs(file, line, offset, prefix, entryNames)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, CompletionDetailsResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsRequestArgs.java new file mode 100644 index 000000000..46b3221ee --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsRequestArgs.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CompletionDetailsRequestArgs extends FileLocationRequestArgs { + + /** + * Names of one or more entries for which to obtain details. + */ + private final String[] entryNames; + + private final String prefix; + + public CompletionDetailsRequestArgs(String file, int position, String prefix, String[] entryNames) { + super(file, position); + this.prefix = prefix; + this.entryNames = entryNames; + } + + public CompletionDetailsRequestArgs(String file, int line, int offset, String prefix, String[] entryNames) { + super(file, line, offset); + this.prefix = prefix; + this.entryNames = entryNames; + } + + public String getPrefix() { + return prefix; + } + + public String[] getEntryNames() { + return entryNames; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsResponse.java new file mode 100644 index 000000000..ada8e1e27 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionDetailsResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.completions.CompletionEntryDetails; + +/** + * Completion details response message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class CompletionDetailsResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsRequest.java new file mode 100644 index 000000000..6334c5a4f --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsRequest.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.lang.reflect.Type; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.InstanceCreator; +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.ITypeScriptServiceClient; +import ts.client.completions.CompletionEntry; +import ts.client.completions.ICompletionEntryFactory; +import ts.client.completions.ICompletionEntryMatcherProvider; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CompletionsRequest extends FileLocationRequest { + + private final transient ICompletionEntryMatcherProvider matcherProvider; + private final transient ITypeScriptServiceClient client; + private final transient ICompletionEntryFactory factory; + + public CompletionsRequest(String fileName, int line, int offset, ICompletionEntryMatcherProvider matcherProvider, + ITypeScriptServiceClient client, ICompletionEntryFactory factory) { + super(CommandNames.Completions.getName(), new CompletionsRequestArgs(fileName, line, offset, null)); + this.matcherProvider = matcherProvider; + this.client = client; + this.factory = factory; + } + + @Override + public Response> parseResponse(JsonObject json) { + String fileName = super.getArguments().getFile(); + int line = super.getArguments().getLine(); + int offset = super.getArguments().getOffset(); + Gson gson = new GsonBuilder() + .registerTypeAdapter(CompletionEntry.class, new InstanceCreator() { + @Override + public CompletionEntry createInstance(Type type) { + return factory.create(matcherProvider.getMatcher(), fileName, line, offset, client); + } + }).create(); + return gson.fromJson(json, CompletionsResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsRequestArgs.java new file mode 100644 index 000000000..beb6d1c74 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsRequestArgs.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CompletionsRequestArgs extends FileLocationRequestArgs { + + private final String prefix; + + public CompletionsRequestArgs(String file, int position, String prefix) { + super(file, position); + this.prefix = prefix; + } + + public CompletionsRequestArgs(String file, int line, int offset, String prefix) { + super(file, line, offset); + this.prefix = prefix; + } + + public String getPrefix() { + return prefix; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsResponse.java new file mode 100644 index 000000000..596de7a9f --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/CompletionsResponse.java @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.completions.CompletionEntry; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class CompletionsResponse extends Response> { +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ConfigFileDiagnosticEvent.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ConfigFileDiagnosticEvent.java new file mode 100644 index 000000000..ce5ab9f26 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ConfigFileDiagnosticEvent.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.Event; +import ts.client.diagnostics.DiagnosticEventBody; + +/** + * Event message for "configFileDiag" event type. This event provides errors for + * a found config file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ConfigFileDiagnosticEvent extends Event { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ConfigureRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ConfigureRequest.java new file mode 100644 index 000000000..0b363fd56 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ConfigureRequest.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.configure.ConfigureRequestArguments; + +/** + * Configure request; value of command field is "configure". Specifies host + * information, such as host type, tab size, and indent size. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ConfigureRequest extends Request { + + public ConfigureRequest(ConfigureRequestArguments arguments) { + super(CommandNames.Configure.getName(), arguments); + } + + @Override + public Response parseResponse(JsonObject json) { + return null; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DefinitionRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DefinitionRequest.java new file mode 100644 index 000000000..2113113eb --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DefinitionRequest.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.FileSpan; + +/** + * Go to definition request; value of command field is "definition". Return + * response giving the file locations that define the symbol found in file at + * location line, col. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class DefinitionRequest extends FileLocationRequest { + + public DefinitionRequest(String file, int line, int offset) { + super(CommandNames.Definition.getName(), new FileLocationRequestArgs(file, line, offset)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, DefinitionResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DefinitionResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DefinitionResponse.java new file mode 100644 index 000000000..e3192b296 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DefinitionResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.FileSpan; + +/** + * Definition response message. Gives text range for definition. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class DefinitionResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DocCommandTemplateResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DocCommandTemplateResponse.java new file mode 100644 index 000000000..a40f974b8 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DocCommandTemplateResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.jsdoc.TextInsertion; + +/** + * Response to DocCommentTemplateRequest. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class DocCommandTemplateResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DocCommentTemplateRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DocCommentTemplateRequest.java new file mode 100644 index 000000000..7ad9f6e40 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/DocCommentTemplateRequest.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.jsdoc.TextInsertion; + +/** + * Requests a JS Doc comment template for a given position. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class DocCommentTemplateRequest extends FileLocationRequest { + + public DocCommentTemplateRequest(String file, int line, int offset) { + super(CommandNames.DocCommentTemplate.getName(), new FileLocationRequestArgs(file, line, offset)); + } + + @Override + public Response parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, DocCommandTemplateResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileLocationRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileLocationRequest.java new file mode 100644 index 000000000..f4fd1bcdf --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileLocationRequest.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * A request whose arguments specify a file location (file, line, col). + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public abstract class FileLocationRequest extends FileRequest { + + public FileLocationRequest(String command, T arguments) { + super(command, arguments); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileLocationRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileLocationRequestArgs.java new file mode 100644 index 000000000..4ee4c6cc4 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileLocationRequestArgs.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class FileLocationRequestArgs extends FileRequestArgs { + + /** + * The line number for the request (1-based). + */ + private final Integer line; + + /** + * The character offset (on the line) for the request (1-based). + */ + private final Integer offset; + + /** + * Position (can be specified instead of line/offset pair) + */ + private final Integer position; + + public FileLocationRequestArgs(String file, int line, int offset) { + this(file, line, offset, null); + } + + public FileLocationRequestArgs(String file, int line, int offset, String projectName) { + this(file, line, offset, null, projectName); + } + + public FileLocationRequestArgs(String file, int position) { + this(file, position, null); + } + + public FileLocationRequestArgs(String file, int position, String projectName) { + this(file, null, null, position, projectName); + } + + private FileLocationRequestArgs(String file, Integer line, Integer offset, Integer position, String projectName) { + super(file, projectName); + this.line = line; + this.offset = offset; + this.position = position; + } + + public Integer getLine() { + return line; + } + + public Integer getOffset() { + return offset; + } + + public Integer getPosition() { + return position; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRangeRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRangeRequestArgs.java new file mode 100644 index 000000000..bf077c9d2 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRangeRequestArgs.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class FileRangeRequestArgs extends FileRequestArgs { + + /** + * The line number for the request (1-based). + */ + private Integer startLine; + + /** + * The character offset (on the line) for the request (1-based). + */ + private Integer startOffset; + + /** + * Position (can be specified instead of line/offset pair) + */ + /* @internal */ + private Integer startPosition; + + /** + * The line number for the request (1-based). + */ + private Integer endLine; + + /** + * The character offset (on the line) for the request (1-based). + */ + private Integer endOffset; + + /** + * Position (can be specified instead of line/offset pair) + */ + /* @internal */ + private Integer endPosition; + + public FileRangeRequestArgs(String file, int startLine, int startOffset, int endLine, int endOffset) { + this(file, startLine, startOffset, endLine, endOffset, null, null, null); + } + + public FileRangeRequestArgs(String file, int startPosition, int endPosition) { + this(file, null, null, null, null, startPosition, endPosition, null); + } + + private FileRangeRequestArgs(String file, Integer startLine, Integer startOffset, Integer endLine, + Integer endOffset, Integer startPosition, Integer endPosition, String projectName) { + super(file, projectName); + this.startLine = startLine; + this.startOffset = startOffset; + this.endLine = endLine; + this.endOffset = endOffset; + this.startPosition = startPosition; + this.endPosition = endPosition; + } + + public Integer getStartLine() { + return startLine; + } + + public Integer getStartOffset() { + return startOffset; + } + + public Integer getStartPosition() { + return startPosition; + } + + public Integer getEndLine() { + return endLine; + } + + public Integer getEndOffset() { + return endOffset; + } + + public Integer getEndPosition() { + return endPosition; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRequest.java new file mode 100644 index 000000000..7b246c1bc --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRequest.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public abstract class FileRequest extends Request { + + public FileRequest(String command, T arguments, Integer seq) { + super(command, arguments, seq); + } + + public FileRequest(String command, T arguments) { + super(command, arguments); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRequestArgs.java new file mode 100644 index 000000000..94ba5852f --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FileRequestArgs.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for FileRequest messages. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class FileRequestArgs { + + /** + * The file for the request (absolute pathname required). + */ + private final String file; + + /** + * Optional name of project that contains file + */ + private final String projectFileName; + + public FileRequestArgs(String file, String projectFileName) { + this.file = file; + this.projectFileName = projectFileName; + } + + public String getFile() { + return file; + } + + public String getProjectFileName() { + return projectFileName; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatRequest.java new file mode 100644 index 000000000..97461057e --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatRequest.java @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CodeEdit; +import ts.client.CommandNames; + +/** + * Format request; value of command field is "format". Return response giving + * zero or more edit instructions. The edit instructions will be sorted in file + * order. Applying the edit instructions in reverse to file will result in + * correctly reformatted text. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class FormatRequest extends AbstractFormatRequest { + + public FormatRequest(String file, int line, int offset, int endLine, int endOffset) { + super(CommandNames.Format.getName(), new FormatRequestArgs(file, line, offset, endLine, endOffset)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, FormatResponse.class); + } + + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatRequestArgs.java new file mode 100644 index 000000000..63916b5d9 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatRequestArgs.java @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.format.FormatCodeSettings; + +/** + * Arguments for format messages. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class FormatRequestArgs extends FileLocationRequestArgs { + + /** + * Last line of range for which to format text in file. + */ + private final Integer endLine; + + /** + * Character offset on last line of range for which to format text in file. + */ + private final Integer endOffset; + + /** + * End position of the range for which to format text in file. + */ + private final Integer endPosition; + + /** + * Format options to be used. + */ + private FormatCodeSettings options; + + public FormatRequestArgs(String file, int position, int endPosition) { + super(file, position); + this.endLine = null; + this.endOffset = null; + this.endPosition = endPosition; + this.options = null; + } + + public FormatRequestArgs(String file, int line, int offset, int endLine, int endOffset) { + super(file, line, offset); + this.endLine = endLine; + this.endOffset = endOffset; + this.endPosition = null; + this.options = null; + } + + public Integer getEndLine() { + return endLine; + } + + public Integer getEndOffset() { + return endOffset; + } + + public Integer getEndPosition() { + return endPosition; + } + + public FormatCodeSettings getOptions() { + return options; + } + + public void setOptions(FormatCodeSettings options) { + this.options = options; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatResponse.java new file mode 100644 index 000000000..257d217eb --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/FormatResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.CodeEdit; + +/** + * Format and format on key response message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class FormatResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRangeRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRangeRequestArgs.java new file mode 100644 index 000000000..5572fd341 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRangeRequestArgs.java @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class GetApplicableRefactorsRangeRequestArgs extends FileRangeRequestArgs { + + public GetApplicableRefactorsRangeRequestArgs(String file, int startLine, int startOffset, int endLine, + int endOffset) { + super(file, startLine, startOffset, endLine, endOffset); + } + + public GetApplicableRefactorsRangeRequestArgs(String file, int startPosition, int endPosition) { + super(file, startPosition, endPosition); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRequest.java new file mode 100644 index 000000000..be265c2f6 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRequest.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.refactors.ApplicableRefactorInfo; + +/** + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GetApplicableRefactorsRequest extends Request { + + public GetApplicableRefactorsRequest(String file, int line, int offset) { + super(CommandNames.GetApplicableRefactors.getName(), new GetApplicableRefactorsRequestArgs(file, line, offset)); + } + + public GetApplicableRefactorsRequest(String file, int startLine, int startOffset, int endLine, int endOffset) { + super(CommandNames.GetApplicableRefactors.getName(), + new GetApplicableRefactorsRangeRequestArgs(file, startLine, startOffset, endLine, endOffset)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, GetApplicableRefactorsResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRequestArgs.java new file mode 100644 index 000000000..ff22cdeb3 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsRequestArgs.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class GetApplicableRefactorsRequestArgs extends FileLocationRequestArgs { + + public GetApplicableRefactorsRequestArgs(String file, int position) { + super(file, position); + } + + public GetApplicableRefactorsRequestArgs(String file, int line, int offset) { + super(file, line, offset); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsResponse.java new file mode 100644 index 000000000..5d2d13c30 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetApplicableRefactorsResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.refactors.ApplicableRefactorInfo; + +/** + * Refactors response message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GetApplicableRefactorsResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetCodeFixesResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetCodeFixesResponse.java new file mode 100644 index 000000000..b07c49e1c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetCodeFixesResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.codefixes.CodeAction; + +/** + * Response for GetCodeFixes request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GetCodeFixesResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRangeRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRangeRequestArgs.java new file mode 100644 index 000000000..331971a8a --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRangeRequestArgs.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * Request the edits that a particular refactoring action produces. Callers must + * specify the name of the refactor and the name of the action. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class GetEditsForRefactorRangeRequestArgs extends FileRangeRequestArgs { + + /* The 'name' property from the refactoring that offered this action */ + private String refactor; + /* The 'name' property from the refactoring action */ + private String action; + + public GetEditsForRefactorRangeRequestArgs(String file, int startPosition, int endPosition, String refactor, + String action) { + super(file, startPosition, endPosition); + this.refactor = refactor; + this.action = action; + } + + public GetEditsForRefactorRangeRequestArgs(String file, int startLine, int startOffset, int endLine, int endOffset, + String refactor, String action) { + super(file, startLine, startOffset, endLine, endOffset); + this.refactor = refactor; + this.action = action; + } + + public String getRefactor() { + return refactor; + } + + public String getAction() { + return action; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRequest.java new file mode 100644 index 000000000..570277949 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRequest.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.refactors.RefactorEditInfo; + +/** + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GetEditsForRefactorRequest extends Request { + + public GetEditsForRefactorRequest(String file, int line, int offset, String refactor, String action) { + super(CommandNames.GetEditsForRefactor.getName(), + new GetEditsForRefactorRequestArgs(file, line, offset, refactor, action)); + } + + public GetEditsForRefactorRequest(String file, int startLine, int startOffset, int endtLine, int endOffset, + String refactor, String action) { + super(CommandNames.GetEditsForRefactor.getName(), new GetEditsForRefactorRangeRequestArgs(file, startLine, + startOffset, endtLine, endOffset, refactor, action)); + } + + @Override + public Response parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, GetEditsForRefactorResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRequestArgs.java new file mode 100644 index 000000000..d786b51ba --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorRequestArgs.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * Request the edits that a particular refactoring action produces. Callers must + * specify the name of the refactor and the name of the action. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class GetEditsForRefactorRequestArgs extends FileLocationRequestArgs { + + /* The 'name' property from the refactoring that offered this action */ + private String refactor; + /* The 'name' property from the refactoring action */ + private String action; + + public GetEditsForRefactorRequestArgs(String file, int position, String refactor, String action) { + super(file, position); + this.refactor = refactor; + this.action = action; + } + + public GetEditsForRefactorRequestArgs(String file, int line, int offset, String refactor, String action) { + super(file, line, offset); + this.refactor = refactor; + this.action = action; + } + + public String getRefactor() { + return refactor; + } + + public String getAction() { + return action; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorResponse.java new file mode 100644 index 000000000..812766366 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetEditsForRefactorResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.refactors.RefactorEditInfo; + +/** + * Refactor code actions response message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GetEditsForRefactorResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetSupportedCodeFixesRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetSupportedCodeFixesRequest.java new file mode 100644 index 000000000..f559619e4 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetSupportedCodeFixesRequest.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; + +/** + * A request to get codes of supported code fixes. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GetSupportedCodeFixesRequest extends Request { + + public GetSupportedCodeFixesRequest() { + super(CommandNames.GetSupportedCodeFixes.getName(), null); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, GetSupportedCodeFixesResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetSupportedCodeFixesResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetSupportedCodeFixesResponse.java new file mode 100644 index 000000000..8c57ff0a3 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GetSupportedCodeFixesResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +/** + * A response for GetSupportedCodeFixesRequest request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GetSupportedCodeFixesResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectRequest.java new file mode 100644 index 000000000..bb208bf4c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectRequest.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.diagnostics.DiagnosticEvent; +import ts.client.projectinfo.ProjectInfo; + +/** + * GeterrForProjectRequest request; value of command field is + * "geterrForProject". It works similarly with 'Geterr', only it request for + * every file in this project. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GeterrForProjectRequest extends Request + implements IRequestEventable { + + private final transient ProjectInfo projectInfo; + private final transient List events; + + public GeterrForProjectRequest(String file, int delay, ProjectInfo projectInfo) { + super(CommandNames.GeterrForProject.getName(), new GeterrForProjectRequestArgs(file, delay)); + this.projectInfo = projectInfo; + this.events = new ArrayList<>(); + } + + @Override + public Response parseResponse(JsonObject json) { + return null; + } + + @Override + public List getKeys() { + List files = projectInfo.getFileNames(); + List keys = new ArrayList<>((files.size() - 1) * 2); + for (String file : files) { + if (!file.endsWith("lib.d.ts")) { + keys.add("syntaxDiag_" + file); + keys.add("semanticDiag_" + file); + } + } + return keys; + } + + @Override + public boolean accept(DiagnosticEvent event) { + events.add(event); + return events.size() >= getKeys().size(); + } + + @Override + public List getEvents() { + return events; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectRequestArgs.java new file mode 100644 index 000000000..8604fd0c3 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectRequestArgs.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for GeterrForProject request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class GeterrForProjectRequestArgs { + + /** + * the file requesting project error list + */ + private String file; + + /** + * Delay in milliseconds to wait before starting to compute errors for the + * files in the file list + */ + private int delay; + + public GeterrForProjectRequestArgs(String file, int delay) { + this.file = file; + this.delay = delay; + } + + public String getFile() { + return file; + } + + public int getDelay() { + return delay; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectResponse.java new file mode 100644 index 000000000..5457bc410 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrForProjectResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.diagnostics.DiagnosticEventBody; + +/** + * Response for geterr request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GeterrForProjectResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrRequest.java new file mode 100644 index 000000000..65ee83d10 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrRequest.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.ArrayList; +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.diagnostics.DiagnosticEvent; + +/** + * Geterr request; value of command field is "geterr". Wait for delay + * milliseconds and then, if during the wait no change or reload messages have + * arrived for the first file in the files list, get the syntactic errors for + * the file, field requests, and then get the semantic errors for the file. + * Repeat with a smaller delay for each subsequent file on the files list. Best + * practice for an editor is to send a file list containing each file that is + * currently visible, in most-recently-used order. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GeterrRequest extends Request implements IRequestEventable { + + private final transient List events; + + public GeterrRequest(String[] files, int delay) { + super(CommandNames.Geterr.getName(), new GeterrRequestArgs(files, delay)); + this.events = new ArrayList<>(); + } + + @Override + public Response parseResponse(JsonObject json) { + return null; + } + + @Override + public List getKeys() { + String[] files = super.getArguments().getFiles(); + List keys = new ArrayList<>(files.length * 2); + for (String file : files) { + keys.add("syntaxDiag_" + file); + keys.add("semanticDiag_" + file); + } + return keys; + } + + @Override + public boolean accept(DiagnosticEvent event) { + events.add(event); + return events.size() > 1; + } + + @Override + public List getEvents() { + return events; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrRequestArgs.java new file mode 100644 index 000000000..638bbc40c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrRequestArgs.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for geterr messages. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class GeterrRequestArgs { + + /** + * List of file names for which to compute compiler errors. The files will + * be checked in list order. + */ + private String[] files; + + /** + * Delay in milliseconds to wait before starting to compute errors for the + * files in the file list + */ + private int delay; + + public GeterrRequestArgs(String[] files, int delay) { + this.files = files; + this.delay = delay; + } + + public String[] getFiles() { + return files; + } + + public int getDelay() { + return delay; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrResponse.java new file mode 100644 index 000000000..926bf6e66 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GeterrResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.diagnostics.DiagnosticEventBody; + +/** + * Response for geterr request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class GeterrResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GsonHelper.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GsonHelper.java new file mode 100644 index 000000000..7073ceb95 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/GsonHelper.java @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.lang.reflect.Type; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; + +import ts.client.diagnostics.Diagnostic; +import ts.client.diagnostics.DiagnosticWithLinePosition; +import ts.client.diagnostics.IDiagnostic; + +public class GsonHelper { + + private static final JsonParser JSON_PARSER = new JsonParser(); + + public static final Gson DEFAULT_GSON = new GsonBuilder() + .registerTypeAdapter(IDiagnostic.class, new DiagnosticAdapter()).create(); + + public static JsonElement parse(String json) throws JsonSyntaxException { + return JSON_PARSER.parse(json); + } + + private static class DiagnosticAdapter implements JsonDeserializer { + + @Override + public IDiagnostic deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + if (json.isJsonObject()) { + JsonObject obj = json.getAsJsonObject(); + if (obj.get("start").isJsonObject()) { + // {"start":{"line":1,"offset":13},"end":{"line":1,"offset":13},"text":"Identifier + // expected.","code":1003} + return DEFAULT_GSON.fromJson(json, Diagnostic.class); + } else { + return DEFAULT_GSON.fromJson(json, DiagnosticWithLinePosition.class); + } + } + return null; + } + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/IRequestEventable.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/IRequestEventable.java new file mode 100644 index 000000000..c6f3b356d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/IRequestEventable.java @@ -0,0 +1,14 @@ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.Event; + +public interface IRequestEventable { + + List getKeys(); + + boolean accept(T body); + + List getEvents(); +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ImplementationRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ImplementationRequest.java new file mode 100644 index 000000000..57ddde047 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ImplementationRequest.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.FileSpan; + +/** + * Go to implementation request; value of command field is "implementation". + * Return response giving the file locations that implement the symbol found in + * file at location line, col. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ImplementationRequest extends FileLocationRequest { + + public ImplementationRequest(String file, int line, int offset) { + super(CommandNames.Implementation.getName(), new FileLocationRequestArgs(file, line, offset)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, ImplementationResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ImplementationResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ImplementationResponse.java new file mode 100644 index 000000000..8db346cc4 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ImplementationResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.FileSpan; + +/** + * Implementation response message. Gives text range for implementations. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ImplementationResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Message.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Message.java new file mode 100644 index 000000000..8fc20b33d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Message.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * A TypeScript Server message + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class Message { + + /** + * Sequence number of the message + */ + private int seq; + + /** + * One of "request", "response", or "event" + */ + private String type; + + public Message() { + } + + public Message(MessageType type, int seq) { + this.type = type.name(); + this.seq = seq; + } + + public String getType() { + return type; + } + + public int getSeq() { + return seq; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/MessageType.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/MessageType.java new file mode 100644 index 000000000..b55dafd0d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/MessageType.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * + * TypeScript Server message type. + * + */ +public enum MessageType { + + request, response, event; + + public static MessageType getType(String type) { + try { + return MessageType.valueOf(type); + } catch (Throwable e) { + return null; + } + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavBarRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavBarRequest.java new file mode 100644 index 000000000..026430679 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavBarRequest.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.lang.reflect.Type; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.InstanceCreator; +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.IPositionProvider; +import ts.client.Location; +import ts.client.navbar.NavigationBarItem; + +/** + * NavBar items request; value of command field is "navbar". Return response + * giving the list of navigation bar entries extracted from the requested file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class NavBarRequest extends FileRequest { + + // Set positionProvider to transient to ignore Gson serialization + private final transient IPositionProvider positionProvider; + + public NavBarRequest(String fileName, IPositionProvider positionProvider) { + super(CommandNames.NavBar.getName(), new FileRequestArgs(fileName, null)); + this.positionProvider = positionProvider; + } + + @Override + public Response> parseResponse(JsonObject json) { + Gson gson = GsonHelper.DEFAULT_GSON; + if (positionProvider != null) { + gson = new GsonBuilder().registerTypeAdapter(Location.class, new InstanceCreator() { + @Override + public Location createInstance(Type type) { + return new Location(positionProvider); + } + }).create(); + } + return gson.fromJson(json, NavBarResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavBarResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavBarResponse.java new file mode 100644 index 000000000..3397a1ca4 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavBarResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.navbar.NavigationBarItem; + +/** + * Navigation bar response message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class NavBarResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavToRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavToRequest.java new file mode 100644 index 000000000..38d8b8932 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavToRequest.java @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.navto.NavtoItem; + +/** + * Navto request message; value of command field is "navto". Return list of + * objects giving file locations and symbols that match the search term given in + * argument 'searchTerm'. The context for the search is given by the named file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class NavToRequest extends FileRequest { + + public NavToRequest(String fileName, String searchValue, Integer maxResultCount, Boolean currentFileOnly, + String projectFileName) { + super(CommandNames.NavTo.getName(), + new NavtoRequestArgs(fileName, searchValue, maxResultCount, currentFileOnly, projectFileName)); + } + + @Override + public Response> parseResponse(JsonObject json) { + Gson gson = GsonHelper.DEFAULT_GSON; + return gson.fromJson(json, NavtoResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavTreeRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavTreeRequest.java new file mode 100644 index 000000000..546dcff1c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavTreeRequest.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.lang.reflect.Type; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.InstanceCreator; +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.IPositionProvider; +import ts.client.Location; +import ts.client.navbar.NavigationBarItem; + +/** + * NavTree request; value of command field is "navtree". Return response giving + * the navigation tree of the requested file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class NavTreeRequest extends FileRequest { + + // Set positionProvider to transient to ignore Gson serialization + private final transient IPositionProvider positionProvider; + + public NavTreeRequest(String fileName, IPositionProvider positionProvider) { + super(CommandNames.NavTree.getName(), new FileRequestArgs(fileName, null)); + this.positionProvider = positionProvider; + } + + @Override + public Response parseResponse(JsonObject json) { + Gson gson = GsonHelper.DEFAULT_GSON; + if (positionProvider != null) { + gson = new GsonBuilder().registerTypeAdapter(Location.class, new InstanceCreator() { + @Override + public Location createInstance(Type type) { + return new Location(positionProvider); + } + }).create(); + } + return gson.fromJson(json, NavTreeResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavTreeResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavTreeResponse.java new file mode 100644 index 000000000..4efd1b27c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavTreeResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.navbar.NavigationBarItem; + +/** + * Navigation tree response message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class NavTreeResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavtoRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavtoRequestArgs.java new file mode 100644 index 000000000..e62a44e7b --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavtoRequestArgs.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for CompileOnSaveEmitFileRequest + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class NavtoRequestArgs extends FileRequestArgs { + + /** + * Search term to navigate to from current location; term can be '.*' or an + * identifier prefix. + */ + private final String searchValue; + + /** + * Optional limit on the number of items to return. + */ + private Integer maxResultCount; + /** + * Optional flag to indicate we want results for just the current file or the + * entire project. + */ + private final Boolean currentFileOnly; + + public NavtoRequestArgs(String file, String searchValue, Integer maxResultCount, Boolean currentFileOnly, + String projectFileName) { + super(file, projectFileName); + this.searchValue = searchValue; + this.maxResultCount = maxResultCount; + this.currentFileOnly = currentFileOnly; + } + + public String getSearchValue() { + return searchValue; + } + + public Integer getMaxResultCount() { + return maxResultCount; + } + + public Boolean getCurrentFileOnly() { + return currentFileOnly; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavtoResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavtoResponse.java new file mode 100644 index 000000000..d764e23d1 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/NavtoResponse.java @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.navto.NavtoItem; + +/** + * Navto response message. Body is an array of navto items. Each item gives a + * symbol that matched the search term. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class NavtoResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OccurrencesRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OccurrencesRequest.java new file mode 100644 index 000000000..e93c4daa6 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OccurrencesRequest.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.occurrences.OccurrencesResponseItem; + +/** + * Get occurrences request; value of command field is "occurrences". Return + * response giving spans that are relevant in the file at a given line and + * column. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class OccurrencesRequest extends FileLocationRequest { + + public OccurrencesRequest(String file, int line, int offset) { + super(CommandNames.Occurrences.getName(), new FileLocationRequestArgs(file, line, offset)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, OccurrencesResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OccurrencesResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OccurrencesResponse.java new file mode 100644 index 000000000..adae6946d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OccurrencesResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.occurrences.OccurrencesResponseItem; + +/** + * Occurrences response message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class OccurrencesResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenExternalProjectRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenExternalProjectRequest.java new file mode 100644 index 000000000..8fac68432 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenExternalProjectRequest.java @@ -0,0 +1,29 @@ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.ExternalFile; +import ts.cmd.tsc.CompilerOptions; + +/** + * Request to open or update external project. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class OpenExternalProjectRequest extends Request { + + public OpenExternalProjectRequest(String projectFileName, List rootFiles, CompilerOptions options) { + super(CommandNames.OpenExternalProject.getName(), + new OpenExternalProjectRequestArgs(projectFileName, rootFiles, options)); + } + + @Override + public Response parseResponse(JsonObject json) { + // This request doesn't return response. + return null; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenExternalProjectRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenExternalProjectRequestArgs.java new file mode 100644 index 000000000..e013ea771 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenExternalProjectRequestArgs.java @@ -0,0 +1,35 @@ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.ExternalFile; +import ts.cmd.tsc.CompilerOptions; + +/** + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class OpenExternalProjectRequestArgs { + + /** + * Project name + */ + String projectFileName; + /** + * List of root files in project + */ + List rootFiles; + /** + * Compiler options for the project + */ + CompilerOptions options; + // /** + // * Explicitly specified type acquisition for the project + // */ + // typeAcquisition?: TypeAcquisition; + public OpenExternalProjectRequestArgs(String projectFileName, List rootFiles, + CompilerOptions options) { + this.projectFileName = projectFileName; + this.rootFiles = rootFiles; + this.options = options; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenRequest.java new file mode 100644 index 000000000..3bc02af62 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenRequest.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.ScriptKindName; + +/** + * Open request; value of command field is "open". Notify the server that the + * client has file open. The server will not monitor the filesystem for changes + * in this file and will assume that the client is updating the server (using + * the change and/or reload messages) when the file changes. Server does not + * currently send a response to an open request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class OpenRequest extends Request { + + public OpenRequest(String file, String projectName, String fileContent, ScriptKindName scriptKindName) { + super(CommandNames.Open.getName(), new OpenRequestArgs(file, projectName, fileContent, scriptKindName)); + } + + @Override + public Response parseResponse(JsonObject json) { + // This request doesn't return response. + return null; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenRequestArgs.java new file mode 100644 index 000000000..16b572d1e --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/OpenRequestArgs.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.ScriptKindName; + +/** + * Information found in an "open" request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class OpenRequestArgs extends FileRequestArgs { + + /** + * Used when a version of the file content is known to be more up to date + * than the one on disk. Then the known content will be used upon opening + * instead of the disk copy + */ + private final String fileContent; + /** + * Used to specify the script kind of the file explicitly. It could be one + * of the following: "TS", "JS", "TSX", "JSX" + */ + private final String scriptKindName; + + public OpenRequestArgs(String file, String projectName, String fileContent, ScriptKindName scriptKindName) { + super(file, projectName); + this.fileContent = fileContent; + this.scriptKindName = scriptKindName != null ? scriptKindName.name() : null; + } + + public String getFileContent() { + return fileContent; + } + + public String getScriptKindName() { + return scriptKindName; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoRequest.java new file mode 100644 index 000000000..61151344a --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoRequest.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.projectinfo.ProjectInfo; + +/** + * A request to get the project information of the current file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ProjectInfoRequest extends Request { + + public ProjectInfoRequest(String file, boolean needFileNameList) { + super(CommandNames.ProjectInfo.getName(), new ProjectInfoRequestArgs(file, needFileNameList)); + } + + @Override + public Response parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, ProjectInfoResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoRequestArgs.java new file mode 100644 index 000000000..2d645fe21 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoRequestArgs.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for ProjectInfoRequest request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class ProjectInfoRequestArgs extends FileRequestArgs { + + /** + * Indicate if the file name list of the project is needed + */ + private boolean needFileNameList; + + public ProjectInfoRequestArgs(String file, boolean needFileNameList) { + super(file, null); + this.needFileNameList = needFileNameList; + } + + public boolean isNeedFileNameList() { + return needFileNameList; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoResponse.java new file mode 100644 index 000000000..53b54c693 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ProjectInfoResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.projectinfo.ProjectInfo; + +/** + * Response message for "projectInfo" request + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ProjectInfoResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/QuickInfoRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/QuickInfoRequest.java new file mode 100644 index 000000000..ce03d9e0c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/QuickInfoRequest.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.quickinfo.QuickInfo; + +/** + * Quickinfo request; value of command field is "quickinfo". Return response + * giving a quick type and documentation string for the symbol found in file at + * location line, col. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class QuickInfoRequest extends FileLocationRequest { + + public QuickInfoRequest(String file, int line, int offset) { + super(CommandNames.QuickInfo.getName(), new FileLocationRequestArgs(file, line, offset)); + } + + @Override + public Response parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, QuickInfoResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/QuickInfoResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/QuickInfoResponse.java new file mode 100644 index 000000000..78d25fb58 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/QuickInfoResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.quickinfo.QuickInfo; + +/** + * Response object for a QuickInfo. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class QuickInfoResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReferencesRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReferencesRequest.java new file mode 100644 index 000000000..2ab7b4c45 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReferencesRequest.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.references.ReferencesResponseBody; + +/** + * Find references request; value of command field is "references". Return + * response giving the file locations that reference the symbol found in file at + * location line, col. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ReferencesRequest extends FileLocationRequest { + + public ReferencesRequest(String file, int line, int offset) { + super(CommandNames.References.getName(), new FileLocationRequestArgs(file, line, offset)); + } + + @Override + public Response parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, ReferencesResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReferencesResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReferencesResponse.java new file mode 100644 index 000000000..49ce19b98 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReferencesResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.references.ReferencesResponseBody; + +/** + * Response to "references" request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ReferencesResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReloadRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReloadRequest.java new file mode 100644 index 000000000..00f28b38d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReloadRequest.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.internal.FileTempHelper; + +/** + * Reload request message; value of command field is "reload". Reload contents + * of file with name given by the 'file' argument from temporary file with name + * given by the 'tmpfile' argument. The two names can be identical. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ReloadRequest extends FileRequest { + + public ReloadRequest(String fileName, String tmpfile, int seq) { + super(CommandNames.Reload.getName(), new ReloadRequestArgs(fileName, null, tmpfile), seq); + } + + @Override + public Response parseResponse(JsonObject json) { + int requestSeq = json.get("request_seq").getAsInt(); + FileTempHelper.freeTempFile(requestSeq); + return GsonHelper.DEFAULT_GSON.fromJson(json, Response.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReloadRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReloadRequestArgs.java new file mode 100644 index 000000000..bf4d99698 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/ReloadRequestArgs.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for reload request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class ReloadRequestArgs extends FileRequestArgs { + + /** + * Name of temporary file from which to reload file contents. May be same as + * file. + */ + private final String tmpfile; + + public ReloadRequestArgs(String file, String projectName, String tmpfile) { + super(file, projectName); + this.tmpfile = tmpfile; + } + + public String getTmpfile() { + return tmpfile; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameRequest.java new file mode 100644 index 000000000..9df24d158 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameRequest.java @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.rename.RenameResponseBody; + +/** + * Rename request; value of command field is "rename". Return response giving + * the file locations that reference the symbol found in file at location line, + * col. Also return full display name of the symbol so that client can print it + * unambiguously. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class RenameRequest extends FileLocationRequest { + + public RenameRequest(String file, int line, int offset, Boolean findInComments, Boolean findInStrings) { + super(CommandNames.Rename.getName(), new RenameRequestArgs(file, line, offset, findInComments, findInStrings)); + } + + @Override + public Response parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, RenameResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameRequestArgs.java new file mode 100644 index 000000000..850a0e523 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameRequestArgs.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Argument for RenameRequest request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class RenameRequestArgs extends FileLocationRequestArgs { + + /** + * Should text at specified location be found/changed in comments? + */ + private Boolean findInComments; + /** + * Should text at specified location be found/changed in strings? + */ + private Boolean findInStrings; + + public RenameRequestArgs(String file, int line, int offset, Boolean findInComments, Boolean findInStrings) { + super(file, line, offset); + this.findInComments = findInComments; + this.findInStrings = findInStrings; + } + + public Boolean getFindInComments() { + return findInComments; + } + + public Boolean getFindInStrings() { + return findInStrings; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameResponse.java new file mode 100644 index 000000000..34a78fc3e --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/RenameResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.rename.RenameResponseBody; + +/** + * Rename response message. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class RenameResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Request.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Request.java new file mode 100644 index 000000000..d036efbc8 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Request.java @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; + +import ts.internal.SequenceHelper; + +/** + * Client-initiated request message + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public abstract class Request extends Message { + + /** + * The command to execute + */ + private final String command; + + /** + * Object containing arguments for the command + */ + private final T arguments; + + public Request(String command, T arguments) { + this(command, arguments, null); + } + + public Request(String command, T arguments, Integer seq) { + super(MessageType.request, seq != null ? seq : SequenceHelper.getRequestSeq()); + this.command = command; + this.arguments = arguments; + } + + public String getCommand() { + return command; + } + + public T getArguments() { + return arguments; + } + + public abstract Response parseResponse(JsonObject json); + + protected Gson getGson() { + return GsonHelper.DEFAULT_GSON; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Response.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Response.java new file mode 100644 index 000000000..faf99931b --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/Response.java @@ -0,0 +1,49 @@ +package ts.internal.client.protocol; + +public class Response extends Message { + + /** + * Sequence number of the request message. + */ + private int request_seq; + + /** + * Outcome of the request. + */ + private boolean success; + + /** + * The command requested. + */ + private String command; + + /** + * Contains error message if success === false. + */ + private String message; + + /** + * Contains message body if success === true. + */ + private T body; + + public int getRequest_seq() { + return request_seq; + } + + public boolean isSuccess() { + return success; + } + + public String getCommand() { + return command; + } + + public String getMessage() { + return message; + } + + public T getBody() { + return body; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncRequest.java new file mode 100644 index 000000000..be66446c8 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncRequest.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.diagnostics.IDiagnostic; + +/** + * Synchronous request for semantic diagnostics of one file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class SemanticDiagnosticsSyncRequest extends FileRequest { + + public SemanticDiagnosticsSyncRequest(String file, Boolean includeLinePosition) { + super(CommandNames.SemanticDiagnosticsSync.getName(), + new SemanticDiagnosticsSyncRequestArgs(file, includeLinePosition)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, SemanticDiagnosticsSyncResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncRequestArgs.java new file mode 100644 index 000000000..c9e591582 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncRequestArgs.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for SemanticDiagnosticsSync messages. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class SemanticDiagnosticsSyncRequestArgs extends FileRequestArgs { + + /** + * The file for the request (absolute pathname required). + */ + private final Boolean includeLinePosition; + + public SemanticDiagnosticsSyncRequestArgs(String file, Boolean includeLinePosition) { + super(file, null); + this.includeLinePosition = includeLinePosition; + } + + public Boolean getIncludeLinePosition() { + return includeLinePosition; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncResponse.java new file mode 100644 index 000000000..ec491c784 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SemanticDiagnosticsSyncResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.diagnostics.IDiagnostic; + +/** + * Response object for synchronous sematic diagnostics request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class SemanticDiagnosticsSyncResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpRequest.java new file mode 100644 index 000000000..8d00faeb7 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpRequest.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.signaturehelp.SignatureHelpItems; + +/** + * Signature help request; value of command field is "signatureHelp". Given a + * file location (file, line, col), return the signature help. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class SignatureHelpRequest extends FileLocationRequest { + + public SignatureHelpRequest(String file, int line, int offset) { + super(CommandNames.SignatureHelp.getName(), new SignatureHelpRequestArgs(file, line, offset)); + } + + @Override + public Response parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, SignatureHelpResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpRequestArgs.java new file mode 100644 index 000000000..3894ec638 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpRequestArgs.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments of a signature help request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class SignatureHelpRequestArgs extends FileLocationRequestArgs { + + public SignatureHelpRequestArgs(String file, int line, int offset) { + super(file, line, offset); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpResponse.java new file mode 100644 index 000000000..efca1e885 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SignatureHelpResponse.java @@ -0,0 +1,22 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import ts.client.signaturehelp.SignatureHelpItems; + +/** + * Response object for a SignatureHelpRequest. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class SignatureHelpResponse extends Response { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncRequest.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncRequest.java new file mode 100644 index 000000000..8a7517447 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncRequest.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import com.google.gson.JsonObject; + +import ts.client.CommandNames; +import ts.client.diagnostics.IDiagnostic; + +/** + * Synchronous request for syntactic diagnostics of one file. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class SyntacticDiagnosticsSyncRequest extends FileRequest { + + public SyntacticDiagnosticsSyncRequest(String file, Boolean includeLinePosition) { + super(CommandNames.SyntacticDiagnosticsSync.getName(), + new SyntacticDiagnosticsSyncRequestArgs(file, includeLinePosition)); + } + + @Override + public Response> parseResponse(JsonObject json) { + return GsonHelper.DEFAULT_GSON.fromJson(json, SyntacticDiagnosticsSyncResponse.class); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncRequestArgs.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncRequestArgs.java new file mode 100644 index 000000000..4bfc85a1c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncRequestArgs.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +/** + * Arguments for SyntacticDiagnosticsSync messages. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + * + */ +public class SyntacticDiagnosticsSyncRequestArgs extends FileRequestArgs { + + /** + * The file for the request (absolute pathname required). + */ + private final Boolean includeLinePosition; + + public SyntacticDiagnosticsSyncRequestArgs(String file, Boolean includeLinePosition) { + super(file, null); + this.includeLinePosition = includeLinePosition; + } + + public Boolean getIncludeLinePosition() { + return includeLinePosition; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncResponse.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncResponse.java new file mode 100644 index 000000000..e71dabbbc --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/SyntacticDiagnosticsSyncResponse.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.client.protocol; + +import java.util.List; + +import ts.client.diagnostics.IDiagnostic; + +/** + * Response object for synchronous syntactic diagnostics request. + * + * @see https://github.com/Microsoft/TypeScript/blob/master/src/server/protocol.ts + */ +public class SyntacticDiagnosticsSyncResponse extends Response> { + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/BeginInstallTypesEvent.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/BeginInstallTypesEvent.java new file mode 100644 index 000000000..05ca8883c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/BeginInstallTypesEvent.java @@ -0,0 +1,8 @@ +package ts.internal.client.protocol.installtypes; + +import ts.client.Event; +import ts.client.installtypes.BeginInstallTypesEventBody; + +public class BeginInstallTypesEvent extends Event{ + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/EndInstallTypesEvent.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/EndInstallTypesEvent.java new file mode 100644 index 000000000..a415ed726 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/EndInstallTypesEvent.java @@ -0,0 +1,8 @@ +package ts.internal.client.protocol.installtypes; + +import ts.client.Event; +import ts.client.installtypes.EndInstallTypesEventBody; + +public class EndInstallTypesEvent extends Event{ + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TelemetryEvent.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TelemetryEvent.java new file mode 100644 index 000000000..1d7270eb4 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TelemetryEvent.java @@ -0,0 +1,7 @@ +package ts.internal.client.protocol.installtypes; + +import ts.client.Event; + +public class TelemetryEvent extends Event{ + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TelemetryEventBody.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TelemetryEventBody.java new file mode 100644 index 000000000..7fe5b9cb5 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TelemetryEventBody.java @@ -0,0 +1,16 @@ +package ts.internal.client.protocol.installtypes; + +public class TelemetryEventBody { + + private String telemetryEventName; + + private Object paylod; + + public String getTelemetryEventName() { + return telemetryEventName; + } + + public Object getPaylod() { + return paylod; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TypingsInstalledTelemetryEventBody.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TypingsInstalledTelemetryEventBody.java new file mode 100644 index 000000000..b93e9a0c6 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TypingsInstalledTelemetryEventBody.java @@ -0,0 +1,5 @@ +package ts.internal.client.protocol.installtypes; + +public class TypingsInstalledTelemetryEventBody extends TelemetryEventBody{ + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TypingsInstalledTelemetryEventPayload.java b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TypingsInstalledTelemetryEventPayload.java new file mode 100644 index 000000000..babc48869 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/client/protocol/installtypes/TypingsInstalledTelemetryEventPayload.java @@ -0,0 +1,30 @@ +package ts.internal.client.protocol.installtypes; + +public class TypingsInstalledTelemetryEventPayload { + + /** + * Comma separated list of installed typing packages + */ + private String installedPackages; + /** + * true if install request succeeded, otherwise - false + */ + private boolean installSuccess; + + /** + * version of typings installer + */ + private String typingsInstallerVersion; + + public String getInstalledPackages() { + return installedPackages; + } + + public boolean isInstallSuccess() { + return installSuccess; + } + + public String getTypingsInstallerVersion() { + return typingsInstallerVersion; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/io/input/ClosedInputStream.java b/typescript.java-ts.core/src/main/java/ts/internal/io/input/ClosedInputStream.java new file mode 100644 index 000000000..4d6f88f42 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/io/input/ClosedInputStream.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.io.input; + +import java.io.InputStream; + +/** + * Closed input stream. This stream returns -1 to all attempts to read + * something from the stream. + *

+ * Typically uses of this class include testing for corner cases in methods + * that accept input streams and acting as a sentinel value instead of a + * null input stream. + * + * @version $Id: ClosedInputStream.java 1304052 2012-03-22 20:55:29Z ggregory $ + * @since 1.4 + */ +public class ClosedInputStream extends InputStream { + + /** + * A singleton. + */ + public static final ClosedInputStream CLOSED_INPUT_STREAM = new ClosedInputStream(); + + /** + * Returns -1 to indicate that the stream is closed. + * + * @return always -1 + */ + @Override + public int read() { + return -1; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/io/output/ByteArrayOutputStream.java b/typescript.java-ts.core/src/main/java/ts/internal/io/output/ByteArrayOutputStream.java new file mode 100644 index 000000000..d729435f8 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/io/output/ByteArrayOutputStream.java @@ -0,0 +1,353 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.io.output; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.SequenceInputStream; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import ts.internal.io.input.ClosedInputStream; + +/** + * This class implements an output stream in which the data is + * written into a byte array. The buffer automatically grows as data + * is written to it. + *

+ * The data can be retrieved using toByteArray() and + * toString(). + *

+ * Closing a ByteArrayOutputStream has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an IOException. + *

+ * This is an alternative implementation of the {@link java.io.ByteArrayOutputStream} + * class. The original implementation only allocates 32 bytes at the beginning. + * As this class is designed for heavy duty it starts at 1024 bytes. In contrast + * to the original it doesn't reallocate the whole memory block but allocates + * additional buffers. This way no buffers need to be garbage collected and + * the contents don't have to be copied to the new buffer. This class is + * designed to behave exactly like the original. The only exception is the + * deprecated toString(int) method that has been ignored. + * + * @version $Id: ByteArrayOutputStream.java 1304052 2012-03-22 20:55:29Z ggregory $ + */ +public class ByteArrayOutputStream extends OutputStream { + + /** A singleton empty byte array. */ + private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; + + /** The list of buffers, which grows and never reduces. */ + private final List buffers = new ArrayList(); + /** The index of the current buffer. */ + private int currentBufferIndex; + /** The total count of bytes in all the filled buffers. */ + private int filledBufferSum; + /** The current buffer. */ + private byte[] currentBuffer; + /** The total count of bytes written. */ + private int count; + + /** + * Creates a new byte array output stream. The buffer capacity is + * initially 1024 bytes, though its size increases if necessary. + */ + public ByteArrayOutputStream() { + this(1024); + } + + /** + * Creates a new byte array output stream, with a buffer capacity of + * the specified size, in bytes. + * + * @param size the initial size + * @throws IllegalArgumentException if size is negative + */ + public ByteArrayOutputStream(int size) { + if (size < 0) { + throw new IllegalArgumentException( + "Negative initial size: " + size); + } + synchronized (this) { + needNewBuffer(size); + } + } + + /** + * Makes a new buffer available either by allocating + * a new one or re-cycling an existing one. + * + * @param newcount the size of the buffer if one is created + */ + private void needNewBuffer(int newcount) { + if (currentBufferIndex < buffers.size() - 1) { + //Recycling old buffer + filledBufferSum += currentBuffer.length; + + currentBufferIndex++; + currentBuffer = buffers.get(currentBufferIndex); + } else { + //Creating new buffer + int newBufferSize; + if (currentBuffer == null) { + newBufferSize = newcount; + filledBufferSum = 0; + } else { + newBufferSize = Math.max( + currentBuffer.length << 1, + newcount - filledBufferSum); + filledBufferSum += currentBuffer.length; + } + + currentBufferIndex++; + currentBuffer = new byte[newBufferSize]; + buffers.add(currentBuffer); + } + } + + /** + * Write the bytes to byte array. + * @param b the bytes to write + * @param off The start offset + * @param len The number of bytes to write + */ + @Override + public void write(byte[] b, int off, int len) { + if ((off < 0) + || (off > b.length) + || (len < 0) + || ((off + len) > b.length) + || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + synchronized (this) { + int newcount = count + len; + int remaining = len; + int inBufferPos = count - filledBufferSum; + while (remaining > 0) { + int part = Math.min(remaining, currentBuffer.length - inBufferPos); + System.arraycopy(b, off + len - remaining, currentBuffer, inBufferPos, part); + remaining -= part; + if (remaining > 0) { + needNewBuffer(newcount); + inBufferPos = 0; + } + } + count = newcount; + } + } + + /** + * Write a byte to byte array. + * @param b the byte to write + */ + @Override + public synchronized void write(int b) { + int inBufferPos = count - filledBufferSum; + if (inBufferPos == currentBuffer.length) { + needNewBuffer(count + 1); + inBufferPos = 0; + } + currentBuffer[inBufferPos] = (byte) b; + count++; + } + + /** + * Writes the entire contents of the specified input stream to this + * byte stream. Bytes from the input stream are read directly into the + * internal buffers of this streams. + * + * @param in the input stream to read from + * @return total number of bytes read from the input stream + * (and written to this stream) + * @throws IOException if an I/O error occurs while reading the input stream + * @since 1.4 + */ + public synchronized int write(InputStream in) throws IOException { + int readCount = 0; + int inBufferPos = count - filledBufferSum; + int n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); + while (n != -1) { + readCount += n; + inBufferPos += n; + count += n; + if (inBufferPos == currentBuffer.length) { + needNewBuffer(currentBuffer.length); + inBufferPos = 0; + } + n = in.read(currentBuffer, inBufferPos, currentBuffer.length - inBufferPos); + } + return readCount; + } + + /** + * Return the current size of the byte array. + * @return the current size of the byte array + */ + public synchronized int size() { + return count; + } + + /** + * Closing a ByteArrayOutputStream has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an IOException. + * + * @throws IOException never (this method should not declare this exception + * but it has to now due to backwards compatability) + */ + @Override + public void close() throws IOException { + //nop + } + + /** + * @see java.io.ByteArrayOutputStream#reset() + */ + public synchronized void reset() { + count = 0; + filledBufferSum = 0; + currentBufferIndex = 0; + currentBuffer = buffers.get(currentBufferIndex); + } + + /** + * Writes the entire contents of this byte stream to the + * specified output stream. + * + * @param out the output stream to write to + * @throws IOException if an I/O error occurs, such as if the stream is closed + * @see java.io.ByteArrayOutputStream#writeTo(OutputStream) + */ + public synchronized void writeTo(OutputStream out) throws IOException { + int remaining = count; + for (byte[] buf : buffers) { + int c = Math.min(buf.length, remaining); + out.write(buf, 0, c); + remaining -= c; + if (remaining == 0) { + break; + } + } + } + + /** + * Fetches entire contents of an InputStream and represent + * same data as result InputStream. + *

+ * This method is useful where, + *

    + *
  • Source InputStream is slow.
  • + *
  • It has network resources associated, so we cannot keep it open for + * long time.
  • + *
  • It has network timeout associated.
  • + *
+ * It can be used in favor of {@link #toByteArray()}, since it + * avoids unnecessary allocation and copy of byte[].
+ * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param input Stream to be fully buffered. + * @return A fully buffered stream. + * @throws IOException if an I/O error occurs + * @since 2.0 + */ + public static InputStream toBufferedInputStream(InputStream input) + throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + output.write(input); + return output.toBufferedInputStream(); + } + + /** + * Gets the current contents of this byte stream as a Input Stream. The + * returned stream is backed by buffers of this stream, + * avoiding memory allocation and copy, thus saving space and time.
+ * + * @return the current contents of this output stream. + * @see java.io.ByteArrayOutputStream#toByteArray() + * @see #reset() + * @since 2.0 + */ + private InputStream toBufferedInputStream() { + int remaining = count; + if (remaining == 0) { + return new ClosedInputStream(); + } + List list = new ArrayList(buffers.size()); + for (byte[] buf : buffers) { + int c = Math.min(buf.length, remaining); + list.add(new ByteArrayInputStream(buf, 0, c)); + remaining -= c; + if (remaining == 0) { + break; + } + } + return new SequenceInputStream(Collections.enumeration(list)); + } + + /** + * Gets the curent contents of this byte stream as a byte array. + * The result is independent of this stream. + * + * @return the current contents of this output stream, as a byte array + * @see java.io.ByteArrayOutputStream#toByteArray() + */ + public synchronized byte[] toByteArray() { + int remaining = count; + if (remaining == 0) { + return EMPTY_BYTE_ARRAY; + } + byte newbuf[] = new byte[remaining]; + int pos = 0; + for (byte[] buf : buffers) { + int c = Math.min(buf.length, remaining); + System.arraycopy(buf, 0, newbuf, pos, c); + pos += c; + remaining -= c; + if (remaining == 0) { + break; + } + } + return newbuf; + } + + /** + * Gets the curent contents of this byte stream as a string. + * @return the contents of the byte array as a String + * @see java.io.ByteArrayOutputStream#toString() + */ + @Override + public String toString() { + return new String(toByteArray()); + } + + /** + * Gets the curent contents of this byte stream as a string + * using the specified encoding. + * + * @param enc the name of the character encoding + * @return the string converted from the byte array + * @throws UnsupportedEncodingException if the encoding is not supported + * @see java.io.ByteArrayOutputStream#toString(String) + */ + public String toString(String enc) throws UnsupportedEncodingException { + return new String(toByteArray(), enc); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/io/output/StringBuilderWriter.java b/typescript.java-ts.core/src/main/java/ts/internal/io/output/StringBuilderWriter.java new file mode 100644 index 000000000..aecfd9e2f --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/io/output/StringBuilderWriter.java @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.internal.io.output; + +import java.io.Serializable; +import java.io.Writer; + +/** + * {@link Writer} implementation that outputs to a {@link StringBuilder}. + *

+ * NOTE: This implementation, as an alternative to + * java.io.StringWriter, provides an un-synchronized + * (i.e. for use in a single thread) implementation for better performance. + * For safe usage with multiple {@link Thread}s then + * java.io.StringWriter should be used. + * + * @version $Id: StringBuilderWriter.java 1304052 2012-03-22 20:55:29Z ggregory $ + * @since 2.0 + */ +public class StringBuilderWriter extends Writer implements Serializable { + + private final StringBuilder builder; + + /** + * Construct a new {@link StringBuilder} instance with default capacity. + */ + public StringBuilderWriter() { + this.builder = new StringBuilder(); + } + + /** + * Construct a new {@link StringBuilder} instance with the specified capacity. + * + * @param capacity The initial capacity of the underlying {@link StringBuilder} + */ + public StringBuilderWriter(int capacity) { + this.builder = new StringBuilder(capacity); + } + + /** + * Construct a new instance with the specified {@link StringBuilder}. + * + * @param builder The String builder + */ + public StringBuilderWriter(StringBuilder builder) { + this.builder = builder != null ? builder : new StringBuilder(); + } + + /** + * Append a single character to this Writer. + * + * @param value The character to append + * @return This writer instance + */ + @Override + public Writer append(char value) { + builder.append(value); + return this; + } + + /** + * Append a character sequence to this Writer. + * + * @param value The character to append + * @return This writer instance + */ + @Override + public Writer append(CharSequence value) { + builder.append(value); + return this; + } + + /** + * Append a portion of a character sequence to the {@link StringBuilder}. + * + * @param value The character to append + * @param start The index of the first character + * @param end The index of the last character + 1 + * @return This writer instance + */ + @Override + public Writer append(CharSequence value, int start, int end) { + builder.append(value, start, end); + return this; + } + + /** + * Closing this writer has no effect. + */ + @Override + public void close() { + } + + /** + * Flushing this writer has no effect. + */ + @Override + public void flush() { + } + + + /** + * Write a String to the {@link StringBuilder}. + * + * @param value The value to write + */ + @Override + public void write(String value) { + if (value != null) { + builder.append(value); + } + } + + /** + * Write a portion of a character array to the {@link StringBuilder}. + * + * @param value The value to write + * @param offset The index of the first character + * @param length The number of characters to write + */ + @Override + public void write(char[] value, int offset, int length) { + if (value != null) { + builder.append(value, offset, length); + } + } + + /** + * Return the underlying builder. + * + * @return The underlying builder + */ + public StringBuilder getBuilder() { + return builder; + } + + /** + * Returns {@link StringBuilder#toString()}. + * + * @return The contents of the String builder. + */ + @Override + public String toString() { + return builder.toString(); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarEntry.java b/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarEntry.java new file mode 100644 index 000000000..99a0f78b5 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarEntry.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2004, 2015 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package ts.internal.io.tar; + +// package org.eclipse.ui.internal.wizards.datatransfer; + +/** + * Representation of a file in a tar archive. + * + * @since 3.1 + */ +public class TarEntry implements Cloneable +{ + private String name; + private long mode, time, size; + private int type; + int filepos; + private String linkName; + + /** + * Entry type for normal files. + */ + public static final int FILE = '0'; + + /** + * Entry type for directories. + */ + public static final int DIRECTORY = '5'; + + /** + * Entry type for links. + */ + public static final int LINK = '1'; + + /** + * Entry type for symbolic link. + */ + public static final int SYM_LINK = '2'; + + /** + * Create a new TarEntry for a file of the given name at the + * given position in the file. + * + * @param name filename + * @param pos position in the file in bytes + */ + TarEntry(String name, int pos) { + this.name = name; + mode = 0644; + type = FILE; + filepos = pos; + time = System.currentTimeMillis() / 1000; + } + + /** + * Create a new TarEntry for a file of the given name. + * + * @param name filename + */ + public TarEntry(String name) { + this(name, -1); + } + + /** + * Returns the type of this file, one of FILE, LINK, SYM_LINK, + * CHAR_DEVICE, BLOCK_DEVICE, DIRECTORY or FIFO. + * + * @return file type + */ + public int getFileType() { + return type; + } + + /** + * Returns the mode of the file in UNIX permissions format. + * + * @return file mode + */ + public long getMode() { + return mode; + } + + /** + * Returns the name of the file. + * + * @return filename + */ + public String getName() { + return name; + } + + /** + * Returns the size of the file in bytes. + * + * @return filesize + */ + public long getSize() { + return size; + } + + /** + * Returns the modification time of the file in seconds since January + * 1st 1970. + * + * @return time + */ + public long getTime() { + return time; + } + + /** + * Sets the type of the file, one of FILE, LINK, SYMLINK, CHAR_DEVICE, + * BLOCK_DEVICE, or DIRECTORY. + * + * @param type + */ + public void setFileType(int type) { + this.type = type; + } + + /** + * Sets the mode of the file in UNIX permissions format. + * + * @param mode + */ + public void setMode(long mode) { + this.mode = mode; + } + + /** + * Sets the size of the file in bytes. + * + * @param size + */ + public void setSize(long size) { + this.size = size; + } + + /** + * Sets the modification time of the file in seconds since January + * 1st 1970. + * + * @param time + */ + public void setTime(long time) { + this.time = time; + } + + public boolean isDirectory() { + return type == DIRECTORY; + } + + public boolean isLink() { + return type == LINK; + } + + public boolean isSymbolicLink() { + return type == SYM_LINK; + } + + public String getLinkName() { + return linkName; + } + + public void setLinkName(String linkName) { + this.linkName = linkName; + } +} \ No newline at end of file diff --git a/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarException.java b/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarException.java new file mode 100644 index 000000000..6766c6bcc --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarException.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2004, 2015 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package ts.internal.io.tar; +// package org.eclipse.ui.internal.wizards.datatransfer; + +/** + * Exception generated upon encountering corrupted tar files. + */ +public class TarException extends Exception { + /** + * Generated serial version UID for this class. + */ + private static final long serialVersionUID = 2886671254518853528L; + + /** + * Constructs a TarException without a detail string. + */ + public TarException() { + super(); + } + + /** + * Constructs a TarException with the specified detail string. + * + * @param s the detail string + */ + public TarException(String s) { + super(s); + } + + /** + * Constructs a TarException with the specified detail string. + * + * @param s the detail string + * @param cause the cause + */ + public TarException(String s, Throwable cause) { + super(s, cause); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarInputStream.java b/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarInputStream.java new file mode 100644 index 000000000..4239cba00 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/io/tar/TarInputStream.java @@ -0,0 +1,363 @@ +/******************************************************************************* + * Copyright (c) 2004, 2016 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package ts.internal.io.tar; + +// package org.eclipse.ui.internal.wizards.datatransfer; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +/** + * Input stream for reading files in ustar format (tar) compatible + * with the specification in IEEE Std 1003.1-2001. Also supports + * long filenames encoded using the GNU @LongLink extension. + * + * @since 3.1 + */ +public class TarInputStream extends FilterInputStream +{ + private int nextEntry = 0; + private int nextEOF = 0; + private int filepos = 0; + private int bytesread = 0; + private TarEntry firstEntry = null; + private String longLinkName = null; + + /** + * Creates a new tar input stream on the given input stream. + * + * @param in input stream + * @throws TarException + * @throws IOException + */ + public TarInputStream(InputStream in) throws TarException, IOException { + super(in); + + // Read in the first TarEntry to make sure + // the input is a valid tar file stream. + firstEntry = getNextEntry(); + } + + /** + * Create a new tar input stream, skipping ahead to the given entry + * in the file. + * + * @param in input stream + * @param entry skips to this entry in the file + * @throws TarException + * @throws IOException + */ + TarInputStream(InputStream in, TarEntry entry) throws TarException, IOException { + super(in); + skipToEntry(entry); + } + + /** + * The checksum of a tar file header is simply the sum of the bytes in + * the header. + * + * @param header + * @return checksum + */ + private long headerChecksum(byte[] header) { + long sum = 0; + for(int i = 0; i < 512; i++) { + sum += header[i] & 0xff; + } + return sum; + } + + /** + * Skips ahead to the position of the given entry in the file. + * + * @param entry + * @returns false if the entry has already been passed + * @throws TarException + * @throws IOException + */ + boolean skipToEntry(TarEntry entry) throws TarException, IOException { + int bytestoskip = entry.filepos - bytesread; + if(bytestoskip < 0) { + return false; + } + while(bytestoskip > 0) { + long ret = in.skip(bytestoskip); + if(ret < 0) { + throw new IOException("early end of stream"); //$NON-NLS-1$ + } + bytestoskip -= ret; + bytesread += ret; + } + filepos = entry.filepos; + nextEntry = 0; + nextEOF = 0; + // Read next header to seek to file data. + getNextEntry(); + return true; + } + + /** + * Returns true if the header checksum is correct. + * + * @param header + * @return true if this header has a valid checksum + */ + private boolean isValidTarHeader(byte[] header) { + long fileChecksum, calculatedChecksum; + int pos, i; + + pos = 148; + StringBuffer checksumString = new StringBuffer(); + for(i = 0; i < 8; i++) { + if(header[pos + i] == ' ') { + continue; + } + if(header[pos + i] == 0 || !Character.isDigit((char) header[pos + i])) { + break; + } + checksumString.append((char) header[pos + i]); + } + if(checksumString.length() == 0) { + return false; + } + if(checksumString.charAt(0) != '0') { + checksumString.insert(0, '0'); + } + try { + fileChecksum = Long.decode(checksumString.toString()).longValue(); + } catch(NumberFormatException exception) { + //This is not valid if it cannot be parsed + return false; + } + + // Blank out the checksum. + for(i = 0; i < 8; i++) { + header[pos + i] = ' '; + } + calculatedChecksum = headerChecksum(header); + + return (fileChecksum == calculatedChecksum); + } + + /** + * Returns the next entry in the tar file. Does not handle + * GNU @LongLink extensions. + * + * @return the next entry in the tar file + * @throws TarException + * @throws IOException + */ + TarEntry getNextEntryInternal() throws TarException, IOException { + byte[] header = new byte[512]; + int pos = 0; + int i; + + if(firstEntry != null) { + TarEntry entryReturn = firstEntry; + firstEntry = null; + return entryReturn; + } + + while(nextEntry > 0) { + long ret = in.skip(nextEntry); + if(ret < 0) { + throw new IOException("early end of stream"); //$NON-NLS-1$ + } + nextEntry -= ret; + bytesread += ret; + } + + int bytestoread = 512; + while(bytestoread > 0) { + int ret = super.read(header, 512 - bytestoread, bytestoread); + if( ret < 0 ) { + throw new IOException("early end of stream"); //$NON-NLS-1$ + } + bytestoread -= ret; + bytesread += ret; + } + + // If we have a header of all zeros, this marks the end of the file. + if(headerChecksum(header) == 0) { + // We are at the end of the file. + if(filepos > 0) { + return null; + } + + // Invalid stream. + throw new TarException("not in tar format"); //$NON-NLS-1$ + } + + // Validate checksum. + if(!isValidTarHeader(header)) { + throw new TarException("not in tar format"); //$NON-NLS-1$ + } + + while (pos < 100 && header[pos] != 0) { + pos++; + } + + // name + String name = new String(header, 0, pos, StandardCharsets.UTF_8); + // Prepend the prefix here. + pos = 345; + if(header[pos] != 0) { + while (pos < 500 && header[pos] != 0) { + pos++; + } + String prefix = new String(header, 345, pos - 345, StandardCharsets.UTF_8); + name = prefix + "/" + name; //$NON-NLS-1$ + } + + TarEntry entry; + if(longLinkName != null) { + entry = new TarEntry(longLinkName, filepos); + longLinkName = null; + } else { + entry = new TarEntry(name, filepos); + } + if(header[156] != 0) { + entry.setFileType(header[156]); + } + + // mode + pos = 100; + StringBuffer mode = new StringBuffer(); + for(i = 0; i < 8; i++) { + if(header[pos + i] == 0) { + break; + } + if(header[pos + i] == ' ') { + continue; + } + mode.append((char) header[pos + i]); + } + if(mode.length() > 0 && mode.charAt(0) != '0') { + mode.insert(0, '0'); + } + try { + long fileMode = Long.decode(mode.toString()).longValue(); + entry.setMode(fileMode); + } catch(NumberFormatException nfe) { + throw new TarException("Not a valid tar format" /* DataTransferMessages.TarImport_invalid_tar_format */, nfe); + } + + // linkname + if (entry.isSymbolicLink() || entry.isLink()) { + pos = 157; + StringBuilder linkName = new StringBuilder(); + for (i = 0; i < 100; i++) { + if (header[pos + i] == 0) { + break; + } + if (header[pos + i] == ' ') { + continue; + } + linkName.append((char) header[pos + i]); + } + entry.setLinkName(linkName.toString()); + } + + // size + pos = 100 + 24; + StringBuffer size = new StringBuffer(); + for(i = 0; i < 12; i++) { + if(header[pos + i] == 0) { + break; + } + if(header[pos + i] == ' ') { + continue; + } + size.append((char) header[pos + i]); + } + if(size.charAt(0) != '0') { + size.insert(0, '0'); + } + int fileSize; + try { + fileSize = Integer.decode(size.toString()).intValue(); + } catch(NumberFormatException nfe) { + throw new TarException("Not a valid tar format" /* DataTransferMessages.TarImport_invalid_tar_format */, nfe); + } + + entry.setSize(fileSize); + nextEOF = fileSize; + if(fileSize % 512 > 0) { + nextEntry = fileSize + (512 - (fileSize % 512)); + } else { + nextEntry = fileSize; + } + filepos += (nextEntry + 512); + return entry; + } + + /** + * Moves ahead to the next file in the tar archive and returns + * a TarEntry object describing it. + * + * @return the next entry in the tar file + * @throws TarException + * @throws IOException + */ + public TarEntry getNextEntry() throws TarException, IOException { + TarEntry entry = getNextEntryInternal(); + + if(entry != null && entry.getName().equals("././@LongLink")) { //$NON-NLS-1$ + // This is a GNU extension for doing long filenames. + // We get a file called ././@LongLink which just contains + // the real pathname. + byte[] longNameData = new byte[(int) entry.getSize()]; + int bytesread = 0; + while (bytesread < longNameData.length) { + int cur = read(longNameData, bytesread, longNameData.length - bytesread); + if (cur < 0) { + throw new IOException("early end of stream"); //$NON-NLS-1$ + } + bytesread += cur; + } + + int pos = 0; + while (pos < longNameData.length && longNameData[pos] != 0) { + pos++; + } + longLinkName = new String(longNameData, 0, pos, StandardCharsets.UTF_8); + return getNextEntryInternal(); + } + return entry; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if(nextEOF == 0) { + return -1; + } + if(len > nextEOF) { + len = nextEOF; + } + int size = super.read(b, off, len); + nextEntry -= size; + nextEOF -= size; + bytesread += size; + return size; + } + + @Override + public int read() throws IOException { + byte[] data = new byte[1]; + int size = read(data, 0, 1); + if (size < 0) { + return size; + } + return data[0]; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/matcher/LCSS.java b/typescript.java-ts.core/src/main/java/ts/internal/matcher/LCSS.java new file mode 100644 index 000000000..0fb7d4c04 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/matcher/LCSS.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2010, 2012 Darmstadt University of Technology. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marcel Bruch - initial API and implementation. + */ +package ts.internal.matcher; + +import java.util.List; + +/** + * Copied from + * https://github.com/eclipse/recommenders/blob/master/plugins/org.eclipse.recommenders.subwords.rcp/src/org/eclipse/recommenders/internal/subwords/rcp/LCSS.java + */ +public final class LCSS { + + private LCSS() { + // Not meant to be instantiated + } + + private static final int[] EMPTY_SEQUENCE = new int[0]; + + /** + * Returns the best, i.e, the longest continuous sequence - or the empty + * sequence if no subsequence could be found. + */ + public static int[] bestSubsequence(String completion, String token) { + int bestScore = -1; + int[] bestSequence = EMPTY_SEQUENCE; + for (int[] s1 : findSequences(completion, token)) { + int score = scoreSubsequence(s1); + if (score > bestScore) { + bestScore = score; + bestSequence = s1; + } + } + return bestSequence; + } + + public static int scoreSubsequence(int[] s1) { + int score = 0; + for (int i = 0; i < s1.length - 1; i++) { + if (s1[i] + 1 == s1[i + 1]) { + score++; + } + } + return score; + } + + public static List findSequences(String completion, String token) { + return new SequenceFinder(completion, token).findSeqeuences(); + } + + public static boolean containsSubsequence(String completion, String token) { + return !findSequences(completion, token).isEmpty(); + } +} \ No newline at end of file diff --git a/typescript.java-ts.core/src/main/java/ts/internal/matcher/SequenceFinder.java b/typescript.java-ts.core/src/main/java/ts/internal/matcher/SequenceFinder.java new file mode 100644 index 000000000..db710e15c --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/matcher/SequenceFinder.java @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2010, 2012 Darmstadt University of Technology. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Marcel Bruch - initial API and implementation. + * Angelo ZERR - remove com.google.common.collect.Lists dependencies + */ +package ts.internal.matcher; + +import static java.lang.Character.isLetter; +import static java.lang.Character.isLowerCase; +import static java.lang.Character.isUpperCase; +import static java.lang.Character.toLowerCase; +import static java.lang.Character.toUpperCase; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * Copied from + * https://github.com/eclipse/recommenders/blob/master/plugins/org.eclipse.recommenders.subwords.rcp/src/org/eclipse/recommenders/internal/subwords/rcp/SequenceFinder.java + * + */ +public class SequenceFinder { + + private static final int[] EMPTY_SEQUENCE = new int[0]; + + private List curSequences = new LinkedList(); // Lists.newLinkedList(); + private List nextSequences = new LinkedList(); // Lists.newLinkedList(); + + private int pCompletion, pToken; + private String completion, token; + + public SequenceFinder(String completion, String token) { + this.completion = completion; + this.token = token; + } + + public List findSeqeuences() { + + if (isConstantName(completion)) { + rewriteCompletion(); + } + + int[] start = EMPTY_SEQUENCE; + curSequences.add(start); + + for (pToken = 0; pToken < token.length(); pToken++) { + char t = token.charAt(pToken); + + for (int[] activeSequence : curSequences) { + boolean mustmatch = false; + int startIndex = activeSequence.length == 0 ? 0 : activeSequence[activeSequence.length - 1] + 1; + + for (pCompletion = startIndex; pCompletion < completion.length(); pCompletion++) { + char c = completion.charAt(pCompletion); + if (!Character.isLetter(c)) { + if (c == t) { + addNewSubsequenceForNext(activeSequence); + continue; + } + mustmatch = true; + continue; + } else if (Character.isUpperCase(c)) { + mustmatch = true; + } + + if (mustmatch && !isSameIgnoreCase(c, t)) { + jumpToEndOfWord(); + } else if (isSameIgnoreCase(c, t)) { + addNewSubsequenceForNext(activeSequence); + } + } + } + curSequences = nextSequences; + nextSequences = new LinkedList(); // Lists.newLinkedList(); + } + + // filter + for (Iterator it = curSequences.iterator(); it.hasNext();) { + int[] candidate = it.next(); + if (candidate.length < token.length()) { + it.remove(); + continue; + } + } + + return curSequences; + } + + private void addNewSubsequenceForNext(int[] activeSequence) { + int[] copy = Arrays.copyOf(activeSequence, activeSequence.length + 1); + copy[pToken] = pCompletion; + nextSequences.add(copy); + } + + private void rewriteCompletion() { + StringBuilder sb = new StringBuilder(); + + boolean toUpperCase = false; + for (char c : completion.toCharArray()) { + if (Character.isLetterOrDigit(c)) { + sb.append(toUpperCase ? Character.toUpperCase(c) : Character.toLowerCase(c)); + toUpperCase = false; + } else { + sb.append(c); + toUpperCase = true; + } + } + completion = sb.toString(); + } + + private void jumpToEndOfWord() { + for (pCompletion++; pCompletion < completion.length(); pCompletion++) { + char next = completion.charAt(pCompletion); + + if (!isLetter(next)) { + // . or _ word boundary found: + // XXX numbers are also considered as word boundaries then. this + // may cause some trouble... + break; + } + + if (isUpperCase(next)) { + pCompletion--; + break; + } + } + } + + private boolean isConstantName(String completion) { + for (char c : completion.toCharArray()) { + if (Character.isLetter(c) && Character.isLowerCase(c)) { + return false; + } + } + return true; + } + + private boolean isSameIgnoreCase(char c1, char c2) { + if (c1 == c2) { + return true; + } + c2 = isLowerCase(c2) ? toUpperCase(c2) : toLowerCase(c2); + return c1 == c2; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/repository/TypeScriptRepository.java b/typescript.java-ts.core/src/main/java/ts/internal/repository/TypeScriptRepository.java new file mode 100644 index 000000000..e433675ab --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/repository/TypeScriptRepository.java @@ -0,0 +1,136 @@ +package ts.internal.repository; + +import java.io.File; + +import ts.repository.ITypeScriptRepository; +import ts.repository.TypeScriptRepositoryException; +import ts.repository.TypeScriptRepositoryManager; + +/** + * + * + */ +public class TypeScriptRepository implements ITypeScriptRepository { + + private final TypeScriptRepositoryManager manager; + private File baseDir; + private String name; + private File typesScriptDir; + private File tscFile; + private File tslintFile; + private String tslintName; + private String typesScriptVersion; + private String tslintVersion; + private File tsserverPluginsFile; + private String tslintLanguageServiceName; + + public TypeScriptRepository(File baseDir) throws TypeScriptRepositoryException { + this(baseDir, null); + } + + public TypeScriptRepository(File baseDir, TypeScriptRepositoryManager manager) + throws TypeScriptRepositoryException { + this.manager = manager; + this.baseDir = baseDir; + updateBaseDir(baseDir); + } + + private void updateBaseDir(File baseDir) throws TypeScriptRepositoryException { + this.typesScriptDir = new File(baseDir, "node_modules/typescript"); + TypeScriptRepositoryManager.validateTypeScriptDir(typesScriptDir); + // tsc file + this.tscFile = TypeScriptRepositoryManager.getTscFile(typesScriptDir); + this.typesScriptVersion = TypeScriptRepositoryManager.getPackageJsonVersion(typesScriptDir); + this.setName(generateName("TypeScript", typesScriptVersion)); + // tslint file + File tslintBaseDir = new File(baseDir, "node_modules/tslint"); + if (tslintBaseDir.exists()) { + this.tslintFile = TypeScriptRepositoryManager.getTslintFile(tslintBaseDir); + this.tslintVersion = TypeScriptRepositoryManager.getPackageJsonVersion(tslintBaseDir); + this.tslintName = generateName("tslint", tslintVersion); + } + // tslint-language-service file + File tslintLanguageServiceBaseDir = new File(baseDir, "node_modules/tslint-language-service"); + if (tslintLanguageServiceBaseDir.exists()) { + String tslintLanguageServiceVersion = TypeScriptRepositoryManager.getPackageJsonVersion(tslintLanguageServiceBaseDir); + this.tslintLanguageServiceName= generateName("tslint-language-service", tslintLanguageServiceVersion); + } + // tsserver-plugins + this.tsserverPluginsFile = new File(baseDir, "tsserver-plugins/bin/tsserver-plugins"); + } + + private String generateName(String prefix, String version) { + StringBuilder name = new StringBuilder(prefix); + name.append(" ("); + if (version != null) { + name.append(version); + } + name.append(")"); + return name.toString(); + } + + @Override + public String getName() { + return name; + } + + public void setName(String name) throws TypeScriptRepositoryException { + ITypeScriptRepository repository = manager != null ? manager.getRepository(name) : null; + if (repository == null || repository.equals(this)) { + this.name = name; + } else { + throw new TypeScriptRepositoryException("It already exists a TypeScript repository with the name " + name); + } + } + + @Override + public File getBaseDir() { + return baseDir; + } + + @Override + public void setBaseDir(File baseDir) { + this.baseDir = baseDir; + } + + @Override + public File getTypesScriptDir() { + return typesScriptDir; + } + + @Override + public String getTypesScriptVersion() { + return typesScriptVersion; + } + + @Override + public File getTscFile() { + return tscFile; + } + + @Override + public String getTslintVersion() { + return tslintVersion; + } + + @Override + public File getTslintFile() { + return tslintFile; + } + + @Override + public String getTslintName() { + return tslintName; + } + + @Override + public File getTsserverPluginsFile() { + return tsserverPluginsFile; + } + + @Override + public String getTslintLanguageServiceName() { + return tslintLanguageServiceName; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/internal/resources/DefaultTypeScriptResourcesManager.java b/typescript.java-ts.core/src/main/java/ts/internal/resources/DefaultTypeScriptResourcesManager.java new file mode 100644 index 000000000..dfdc77415 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/internal/resources/DefaultTypeScriptResourcesManager.java @@ -0,0 +1,122 @@ +package ts.internal.resources; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import ts.resources.ITypeScriptProject; +import ts.resources.ITypeScriptResourcesManagerDelegate; +import ts.resources.TypeScriptProject; +import ts.utils.FileUtils; + +public class DefaultTypeScriptResourcesManager implements ITypeScriptResourcesManagerDelegate { + + private Map projectCache = new HashMap(); + + @Override + public ITypeScriptProject getTypeScriptProject(Object project, boolean force) throws IOException { + if (!(project instanceof File)) { + return null; + } + File projectDir = (File) project; + if (!projectDir.exists()) { + return null; + } + String path = projectDir.toString(); + try { + path = projectDir.getCanonicalPath(); + } catch (Exception e) { + // ignore + } + // cache projects for the particular path + ITypeScriptProject result = projectCache.get(path); + if (result == null) { + result = new TypeScriptProject(projectDir, null); + projectCache.put(path, result); + } + return result; + } + + @Override + public boolean isJsFile(Object fileObject) { + String ext = getExtension(fileObject); + return ext != null && FileUtils.JS_EXTENSION.equals(ext.toLowerCase()); + } + + @Override + public boolean isJsxFile(Object fileObject) { + String ext = getExtension(fileObject); + return ext != null && FileUtils.JSX_EXTENSION.equals(ext.toLowerCase()); + } + + @Override + public boolean isTsFile(Object fileObject) { + String ext = getExtension(fileObject); + return ext != null && FileUtils.TS_EXTENSION.equals(ext.toLowerCase()); + } + + @Override + public boolean isTsxFile(Object fileObject) { + String ext = getExtension(fileObject); + return ext != null && FileUtils.TSX_EXTENSION.equals(ext.toLowerCase()); + } + + @Override + public boolean isTsOrTsxFile(Object fileObject) { + String ext = getExtension(fileObject); + ext = ext != null ? ext.toLowerCase() : null; + return ext != null && (FileUtils.TS_EXTENSION.equals(ext) || FileUtils.TSX_EXTENSION.equals(ext)); + } + + @Override + public boolean isDefinitionTsFile(Object fileObject) { + String name = getFileName(fileObject); + name = name != null ? name.toLowerCase() : null; + return name != null && (name.endsWith(FileUtils.DEFINITION_TS_EXTENSION)); + } + + @Override + public boolean isTsOrTsxOrJsxFile(Object fileObject) { + String ext = getExtension(fileObject); + ext = ext != null ? ext.toLowerCase() : null; + return ext != null && (FileUtils.TS_EXTENSION.equals(ext) || FileUtils.TSX_EXTENSION.equals(ext) + || FileUtils.JSX_EXTENSION.equals(ext)); + } + + protected String getExtension(Object fileObject) { + if (fileObject instanceof File) { + return FileUtils.getFileExtension(((File) fileObject).getName()); + } else if (fileObject instanceof String) { + return FileUtils.getFileExtension((String) fileObject); + } + return null; + } + + protected String getFileName(Object fileObject) { + if (fileObject instanceof File) { + return ((File) fileObject).getName(); + } else if (fileObject instanceof String) { + return (String) fileObject; + } + return null; + } + + @Override + public String getTypeScriptFilename(Object fileObject) { + if (fileObject instanceof File) { + return FileUtils.getTypeScriptFilename(((File) fileObject).getName()); + } else if (fileObject instanceof String) { + return FileUtils.getTypeScriptFilename((String) fileObject); + } + return null; + } + + @Override + public boolean isTsxOrJsxFile(Object fileObject) { + String ext = getExtension(fileObject); + ext = ext != null ? ext.toLowerCase() : null; + return ext != null && (FileUtils.TSX_EXTENSION.equals(ext) || FileUtils.JSX_EXTENSION.equals(ext)); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/module-info.java b/typescript.java-ts.core/src/main/java/ts/module-info.java new file mode 100644 index 000000000..b9addff52 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/module-info.java @@ -0,0 +1,13 @@ +open module typescript.java.core { + requires transitive com.google.gson; + requires transitive minimal.json; + requires transitive org.osgi.core; + requires transitive org.tukaani.xz; + exports ts; + exports ts.client; + exports ts.client.diagnostics; + exports ts.client.projectinfo; + exports ts.cmd.tsc; + exports ts.utils; + exports ts.nodejs; +} \ No newline at end of file diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/AbstractNodejsProcess.java b/typescript.java-ts.core/src/main/java/ts/nodejs/AbstractNodejsProcess.java new file mode 100644 index 000000000..f6693f3ad --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/AbstractNodejsProcess.java @@ -0,0 +1,192 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.nodejs; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import ts.TypeScriptException; +import ts.utils.FileUtils; + +/** + * Abstract class for node.js process. + * + */ +public abstract class AbstractNodejsProcess implements INodejsProcess { + + /** + * The node.js base dir. If null, it uses installed node.js + */ + protected final File nodejsFile; + + /** + * The project dir where tsconfig.json is hosted. + */ + protected final File projectDir; + + private final INodejsLaunchConfiguration launchConfiguration; + + /** + * Process listeners. + */ + protected final List listeners; + + public AbstractNodejsProcess(File nodejsFile, File projectDir) throws TypeScriptException { + this(nodejsFile, projectDir, null); + } + + /** + * Nodejs process constructor. + * + * @param nodejsFile + * the node.exe file. + * @param projectDir + * the project base dir where tsconfig.json is hosted. + * @throws TernException + */ + public AbstractNodejsProcess(File nodejsFile, File projectDir, INodejsLaunchConfiguration launchConfiguration) + throws TypeScriptException { + this.projectDir = checkProjectDir(projectDir); + this.nodejsFile = checkNodejsFile(nodejsFile); + this.listeners = new ArrayList(); + this.launchConfiguration = launchConfiguration; + } + + private File checkProjectDir(File projectDir) throws TypeScriptException { + if (projectDir == null) { + throw new TypeScriptException("project directory cannot be null"); + } + if (!projectDir.exists()) { + throw new TypeScriptException("Cannot find project directory " + FileUtils.getPath(projectDir)); + } + return projectDir; + } + + private File checkNodejsFile(File nodejsFile) throws TypeScriptException { + if (nodejsFile == null) { + // node.js file cannot be null. In this case it uses installed + // node.js + return null; + } + if (!nodejsFile.exists()) { + throw new TypeScriptException("Cannot find node file " + FileUtils.getPath(nodejsFile)); + } + return nodejsFile; + } + + protected List createNodeArgs() { + if (launchConfiguration == null) { + return null; + } + return launchConfiguration.createNodeArgs(); + } + + protected Map createNodeEnvironmentVariables() { + if (launchConfiguration == null) { + return null; + } + return launchConfiguration.createNodeEnvironmentVariables(); + } + + /** + * return the project dir where tsconfig.json is hosted. + * + * @return + */ + public File getProjectDir() { + return projectDir; + } + + /** + * Add the given process listener. + * + * @param listener + */ + public void addProcessListener(INodejsProcessListener listener) { + synchronized (listeners) { + listeners.add(listener); + } + } + + /** + * Remove the given process listener. + * + * @param listener + */ + public void removeProcessListener(INodejsProcessListener listener) { + synchronized (listeners) { + listeners.remove(listener); + } + } + + /** + * Notify start process. + */ + protected void notifyCreateProcess(List commands, File projectDir) { + synchronized (listeners) { + for (INodejsProcessListener listener : listeners) { + listener.onCreate(this, commands, projectDir); + } + } + } + + /** + * Notify start process. + * + * @param startTime + * time when node.js process is started. + */ + protected void notifyStartProcess(long startTime) { + synchronized (listeners) { + for (INodejsProcessListener listener : listeners) { + listener.onStart(this); + } + } + } + + /** + * Notify stop process. + */ + protected void notifyStopProcess() { + synchronized (listeners) { + for (INodejsProcessListener listener : listeners) { + listener.onStop(this); + } + } + } + + /** + * Notify data process. + * + * @param jsonObject + */ + protected void notifyMessage(String message) { + synchronized (listeners) { + for (INodejsProcessListener listener : listeners) { + listener.onMessage(this, message); + } + } + } + + /** + * Notify error process. + */ + protected void notifyErrorProcess(String line) { + synchronized (listeners) { + for (INodejsProcessListener listener : listeners) { + listener.onError(AbstractNodejsProcess.this, line); + } + } + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsLaunchConfiguration.java b/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsLaunchConfiguration.java new file mode 100644 index 000000000..e76d2dfde --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsLaunchConfiguration.java @@ -0,0 +1,16 @@ +package ts.nodejs; + +import java.util.List; +import java.util.Map; + +public interface INodejsLaunchConfiguration { + + /** + * Returns a list of arguments for the node command. + * + * @return a list of arguments for the node command. + */ + List createNodeArgs(); + + Map createNodeEnvironmentVariables(); +} diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsProcess.java b/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsProcess.java new file mode 100644 index 000000000..8b2b3a235 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsProcess.java @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.nodejs; + +import ts.TypeScriptException; + +/** + * Node.js process API. + * + */ +public interface INodejsProcess { + + /** + * Joint to the stdout thread; + * + * @throws InterruptedException + */ + void join() throws InterruptedException; + + /** + * Add the given process listener. + * + * @param listener + */ + void addProcessListener(INodejsProcessListener listener); + + /** + * Remove the given process listener. + * + * @param listener + */ + void removeProcessListener(INodejsProcessListener listener); + + /** + * Start the node.js process. + */ + void start(); + + /** + * Returns true if the node.js process is started and false otherwise. + * + * @return true if the node.js process is started and false otherwise. + */ + boolean isStarted(); + + /** + * Kill the node.js process. + */ + public void kill(); + + /** + * Send request. + * + * @param request + * @throws TypeScriptException + */ + void sendRequest(String request) throws TypeScriptException; +} diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsProcessListener.java b/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsProcessListener.java new file mode 100644 index 000000000..2e637b4d7 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/INodejsProcessListener.java @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.nodejs; + +import java.io.File; +import java.util.List; + +/** + * Listener for node.js process. + * + * @author azerr + * + */ +public interface INodejsProcessListener { + + /** + * Callback called when the given node.js process is created. + * + * @param process + * @param commands + * @param projectDir + */ + void onCreate(INodejsProcess process, List commands, File projectDir); + + /** + * Callback called when the given node.js process start. + * + * @param process + */ + void onStart(INodejsProcess process); + + /** + * Callback called when the given node.js process send data. + * + * @param process + * @param jsonObject + * the data. + */ + void onMessage(INodejsProcess process, String response); + + /** + * Callback called when the given node.js process stop. + * + * @param process + */ + void onStop(INodejsProcess process); + + /** + * Callback called when the given node.js throws error. + * + * @param process + * @param line + * the error. + */ + void onError(INodejsProcess process, String line); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcess.java b/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcess.java new file mode 100644 index 000000000..acd76e17f --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcess.java @@ -0,0 +1,276 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.nodejs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import ts.TypeScriptException; +import ts.utils.FileUtils; + +/** + * Node.js process. + * + */ +public class NodejsProcess extends AbstractNodejsProcess { + + private final File tsFile; + + /** + * node.js process. + */ + private Process process; + + /** + * StdOut thread. + */ + private Thread outThread; + + /** + * StdErr thread. + */ + private Thread errThread; + + private PrintStream out; + + private final Object outputLock; + + public NodejsProcess(File projectDir, File tsFile, File nodejsFile, INodejsLaunchConfiguration configuration, + String fileType) throws TypeScriptException { + super(nodejsFile, projectDir, configuration); + this.tsFile = checkFile(tsFile, fileType); + this.outputLock = new Object(); + } + + /** + * Check if the given tsserver, tsc, etc file is a valid file. + * + * @param tsFile + * the tsserver, tsc, etc file to check. + * @return the tsFile + * @throws TypeScriptException + */ + private static File checkFile(File tsFile, String fileType) throws TypeScriptException { + if (tsFile == null) { + throw new TypeScriptException("[" + fileType + "] file cannot be null"); + } + if (!tsFile.exists()) { + throw new TypeScriptException("Cannot find [" + fileType + "] file " + FileUtils.getPath(tsFile)); + } + if (!tsFile.isFile()) { + throw new TypeScriptException("[" + fileType + "] " + FileUtils.getPath(tsFile) + " is not a file."); + } + return tsFile; + } + + /** + * StdOut of the node.js process. + */ + private class StdOut implements Runnable { + + @Override + public void run() { + try { + try { + notifyStartProcess(0); + BufferedReader r = new BufferedReader( + new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8)); + String line = null; + while ((line = r.readLine()) != null && process != null) { + notifyMessage(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + if (process != null) { + process.waitFor(); + } + kill(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + /** + * StdErr of the node.js process. + */ + private class StdErr implements Runnable { + @Override + public void run() { + String line = null; + InputStream is = process.getErrorStream(); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + try { + while ((line = br.readLine()) != null) { + notifyErrorProcess(line); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void notifyErrorProcess(String line) { + System.err.println(line); + } + + @Override + public void start() { + try { + List commands = createCommands(); + ProcessBuilder builder = new ProcessBuilder(commands); + + Map environmentVariables = this.createNodeEnvironmentVariables(); + if (environmentVariables != null) { + for (Map.Entry environmentVariableEntry : environmentVariables.entrySet()) { + builder.environment().put(environmentVariableEntry.getKey(), environmentVariableEntry.getValue()); + } + } + + builder.directory(getProjectDir()); + + this.process = builder.start(); + this.out = new PrintStream(process.getOutputStream(), false, StandardCharsets.UTF_8.name()); + + errThread = new Thread(new StdErr()); + errThread.setDaemon(true); + errThread.start(); + + outThread = new Thread(new StdOut()); + outThread.setDaemon(true); + outThread.start(); + + // add a shutdown hook to destroy the node process in case its not + // properly disposed + Runtime.getRuntime().addShutdownHook(new ShutdownHookThread()); + + } catch (Throwable e) { + e.printStackTrace(); + } + } + + @Override + public boolean isStarted() { + return process != null; + } + + private class ShutdownHookThread extends Thread { + @Override + public void run() { + Process process = NodejsProcess.this.process; + if (process != null) { + kill(); + } + } + } + + /** + * Create process commands to start tern with node.js + * + * @return + * @throws IOException + */ + private List createCommands() { + List commands = createNodeCommands(nodejsFile, tsFile); + List args = createNodeArgs(); + if (args != null) { + commands.addAll(args); + } + return commands; + } + + public static List createNodeCommands(File nodejsFile, File tsFile) { + List commands = new LinkedList(); + if (nodejsFile == null) { + // for osx, path of node.js should be setted? + if (new File("/usr/local/bin/node").exists()) { + commands.add("/usr/local/bin/node"); + } else if (new File("/opt/local/bin/node").exists()) { + commands.add("/opt/local/bin/node"); + } else { + commands.add("node"); + } + } else { + commands.add(nodejsFile.getPath()); + } + try { + commands.add(tsFile.getCanonicalPath()); + } catch (IOException e) { + commands.add(tsFile.getPath()); + } + return commands; + } + + public File getProjectDir() { + return projectDir; + } + + public static boolean logProcessStopStack = false; + + /** + * Kill the process. + */ + public void kill() { + if (logProcessStopStack) { + System.out.println("kill nodejs process: projectDir=" + getProjectDir() + " nodejsFile=" + nodejsFile + + " tsFile=" + tsFile + " - process=" + process); + Thread.dumpStack(); + } + + if (out != null) { + out.close(); + out = null; + } + if (process != null) { + process.destroy(); + process = null; + notifyStopProcess(); + } + if (outThread != null) { + outThread.interrupt(); + outThread = null; + } + if (errThread != null) { + errThread.interrupt(); + errThread = null; + } + } + + /** + * Join to the stdout thread; + * + * @throws InterruptedException + */ + public void join() throws InterruptedException { + if (outThread != null) { + outThread.join(); + } + } + + @Override + public void sendRequest(String request) throws TypeScriptException { + synchronized (outputLock) { + out.println(request); // add \n for "readline" used by tsserver + out.flush(); + } + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessAdapter.java b/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessAdapter.java new file mode 100644 index 000000000..423ef5765 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessAdapter.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.nodejs; + +import java.io.File; +import java.util.List; + +/** + * This adapter class provides default implementations for the methods described + * by the {@link INodejsProcessListener} interface. + * + * Classes that wish to deal with event can extend this class and override only + * the methods which they are interested in. + * + */ +public class NodejsProcessAdapter implements INodejsProcessListener { + + @Override + public void onCreate(INodejsProcess process, List commands, File projectDir) { + } + + @Override + public void onStart(INodejsProcess process) { + } + + @Override + public void onMessage(INodejsProcess process, String response) { + + } + + @Override + public void onStop(INodejsProcess process) { + } + + @Override + public void onError(INodejsProcess process, String line) { + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessHelper.java b/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessHelper.java new file mode 100644 index 000000000..25e3ce837 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessHelper.java @@ -0,0 +1,118 @@ +/** + * Copyright (c) 2013-2014 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.nodejs; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import ts.OS; +import ts.utils.FileUtils; +import ts.utils.IOUtils; +import ts.utils.ProcessHelper; +import ts.utils.StringUtils; + +/** + * Node path helper. + * + */ +public class NodejsProcessHelper { + + private static final String NODE_FILENAME = "node"; + + private static final String[] WINDOWS_NODE_PATHS = new String[] { + "C:/Program Files/nodejs/node.exe".replace('/', File.separatorChar), + "C:/Program Files (x86)/nodejs/node.exe".replace('/', File.separatorChar), NODE_FILENAME }; + + private static final String[] MACOS_NODE_PATHS = new String[] { "/usr/local/bin/node", "/opt/local/bin/node", + NODE_FILENAME }; + + private static final String[] LINUX_NODE_PATHS = new String[] { "/usr/local/bin/node", NODE_FILENAME }; + + private NodejsProcessHelper() { + } + + public static String getNodejsPath(OS os) { + String path = getDefaultNodejsPath(os); + if (path != null) { + return path; + } + File nodeFile = findNode(os); + if (nodeFile != null) { + return nodeFile.getAbsolutePath(); + } + return NODE_FILENAME; + } + + public static String getDefaultNodejsPath(OS os) { + String[] paths = getDefaultNodejsPaths(os); + String path = null; + for (int i = 0; i < paths.length; i++) { + path = paths[i]; + if (new File(path).exists()) { + return path; + } + } + return null; + } + + public static String[] getDefaultNodejsPaths(OS os) { + switch (os) { + case Windows: + return WINDOWS_NODE_PATHS; + case MacOS: + return MACOS_NODE_PATHS; + default: + return LINUX_NODE_PATHS; + } + } + + public static String[] getNodejsPaths(OS os) { + List paths = new ArrayList<>(Arrays.asList(getDefaultNodejsPaths(os))); + File nodeFile = findNode(os); + if (nodeFile != null) { + paths.add(0, nodeFile.getAbsolutePath()); + } + return paths.toArray(StringUtils.EMPTY_STRING); + } + + public static File findNode(OS os) { + String extension = os == OS.Windows ? ".exe" : null; + return ProcessHelper.findLocation(NODE_FILENAME, os, extension); + } + + /** + * Returns the nodejs version and null otherwise. + * + * @param nodejsFile + * @return the nodejs version and null otherwise. + */ + public static String getNodeVersion(File nodejsFile) { + if (nodejsFile != null) { + BufferedReader reader = null; + try { + String command = FileUtils.getPath(nodejsFile) + " --version"; + Process p = Runtime.getRuntime().exec(command); + reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + return reader.readLine(); + } catch (IOException e) { + return null; + } finally { + IOUtils.closeQuietly(reader); + } + } + return null; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessManager.java b/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessManager.java new file mode 100644 index 000000000..6b678a319 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/NodejsProcessManager.java @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR and Genuitec LLC. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + * Piotr Tomiak - support for tern.js debugging + */ +package ts.nodejs; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import ts.TypeScriptException; + +/** + * {@link NodejsProcess} manager. + * + */ +public class NodejsProcessManager { + + private final static NodejsProcessManager INSTANCE = new NodejsProcessManager(); + + /** + * Returns the manager singleton. + * + * @return + */ + public static NodejsProcessManager getInstance() { + return INSTANCE; + } + + /** + * List of node.js tern processes created. + */ + private final List processes; + + /** + * Listener added for each process created. + */ + private final INodejsProcessListener listener = new NodejsProcessAdapter() { + + @Override + public void onStart(INodejsProcess server) { + synchronized (NodejsProcessManager.this.processes) { + // here the process is started, add it to the list of processes. + NodejsProcessManager.this.processes.add(server); + } + } + + @Override + public void onStop(INodejsProcess server) { + synchronized (NodejsProcessManager.this.processes) { + // here the process is stopped, remove it to the list of + // processes. + NodejsProcessManager.this.processes.remove(server); + } + } + + }; + + public NodejsProcessManager() { + this.processes = new ArrayList(); + } + + /** + * Create the process with the given tern project base dir where + * tsconfig.json is hosted and the given base dir of node.js exe. + * + * @param projectDir + * project base dir where tsconfig.json is hosted. + * @param tsFile + * the tsserver, tsc file. + * @param nodejsFile + * the nodejs exe file + * @return an instance of the node tern process. + * @throws TypeScriptException + */ + public INodejsProcess create(File projectDir, File tsFile, File nodejsFile, + INodejsLaunchConfiguration configuration, String fileType) throws TypeScriptException { + INodejsProcess process = new NodejsProcess(projectDir, tsFile, nodejsFile, configuration, fileType); + process.addProcessListener(listener); + return process; + } + + /** + * Kill all node.js processes created by the manager. + */ + public void dispose() { + synchronized (processes) { + for (INodejsProcess server : processes) { + try { + server.kill(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + processes.clear(); + } + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/nodejs/TraceNodejsProcess.java b/typescript.java-ts.core/src/main/java/ts/nodejs/TraceNodejsProcess.java new file mode 100644 index 000000000..3b9c9e0a4 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/nodejs/TraceNodejsProcess.java @@ -0,0 +1,17 @@ +package ts.nodejs; + +public class TraceNodejsProcess extends NodejsProcessAdapter { + + public static final INodejsProcessListener INSTANCE = new TraceNodejsProcess(); + + @Override + public void onMessage(INodejsProcess process, String response) { + System.out.println(response); + } + + @Override + public void onError(INodejsProcess process, String response) { + System.err.println(response); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/npm/NpmConstants.java b/typescript.java-ts.core/src/main/java/ts/npm/NpmConstants.java new file mode 100644 index 000000000..fff4a4697 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/npm/NpmConstants.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.npm; + +/** + * Npm constants. + * + */ +public final class NpmConstants { + + private NpmConstants() { + } + + public static final String PACKAGE_JSON = "package.json"; //$NON-NLS-1$ + public static final String NODE_MODULES = "node_modules"; //$NON-NLS-1$ + public static final String NPM = "npm"; //$NON-NLS-1$ + public static final String UTF_8 = "UTF-8"; //$NON-NLS-1$ + + // Default package.json values + public static final String DEFAULT_VERSION = "0.0.0"; //$NON-NLS-1$ + public static final String DEFAULT_DESCRIPTION = "Generated with typescript.java"; //$NON-NLS-1$ + public static final String DEFAULT_LICENSE = "MIT"; //$NON-NLS-1$ + +} diff --git a/typescript.java-ts.core/src/main/java/ts/npm/NpmHelper.java b/typescript.java-ts.core/src/main/java/ts/npm/NpmHelper.java new file mode 100644 index 000000000..dc8859bba --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/npm/NpmHelper.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.npm; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +import ts.OS; +import ts.utils.IOUtils; + +/** + * Npm Utilities. + * + */ +public class NpmHelper { + + /** + * Returns the available versions of the given module name. + * + * @param moduleName + * @param os + * @return the available versions of the given module name. + * @throws IOException + */ + public static List getVersions(String moduleName, OS os) throws IOException { + List versions = new ArrayList<>(); + BufferedReader reader = null; + try { + String[] command = { os == OS.Windows ? "npm.cmd" : "npm", "view", "--json", moduleName, "versions" }; + Process p = Runtime.getRuntime().exec(command); + reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (line.startsWith("\"")) { + String version = line.substring(1, line.lastIndexOf('"')); + versions.add(0, version); + } + } + } finally { + IOUtils.closeQuietly(reader); + } + return versions; + } + + /** + * Returns the "npm install" command for the given module name and version. + * + * @param moduleName + * @param version + * @return the "npm install" command for the given module name and version. + */ + public static String getNpmInstallCommand(String moduleName, String version) { + StringBuilder cmd = new StringBuilder("npm install "); + cmd.append(moduleName); + if (version != null) { + cmd.append("@"); + cmd.append(version); + } + return cmd.toString(); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/npm/NpmModule.java b/typescript.java-ts.core/src/main/java/ts/npm/NpmModule.java new file mode 100644 index 000000000..b043bbd8e --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/npm/NpmModule.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.npm; + +import java.io.IOException; +import java.util.List; + +import ts.OS; + +/** + * Npm module. + * + * @author azerr + * + */ +public class NpmModule { + + private final String name; + private final OS os; + private List versions; + + NpmModule(String name, OS os) { + this.name = name; + this.os = os; + } + + public List getAvailableVersions() throws IOException { + if (!isLoaded()) { + versions = NpmHelper.getVersions(name, os); + } + return versions; + } + + public boolean isLoaded() { + return versions != null; + } + + public String getName() { + return name; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/npm/NpmModulesManager.java b/typescript.java-ts.core/src/main/java/ts/npm/NpmModulesManager.java new file mode 100644 index 000000000..46a0c7c49 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/npm/NpmModulesManager.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.npm; + +import java.util.HashMap; +import java.util.Map; + +import ts.OS; + +/** + * Npm modules manager. + * + */ +public class NpmModulesManager { + + private final OS os; + private final Map modules; + + public NpmModulesManager(OS os) { + this.os = os; + this.modules = new HashMap<>(); + } + + public NpmModule getNPMModule(String moduleName) { + NpmModule module = modules.get(moduleName); + if (module == null) { + module = new NpmModule(moduleName, os); + modules.put(moduleName, module); + } + return module; + } + + public void resetCache(String moduleName) { + modules.remove(moduleName); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/npm/PackageJson.java b/typescript.java-ts.core/src/main/java/ts/npm/PackageJson.java new file mode 100644 index 000000000..59912f302 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/npm/PackageJson.java @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.npm; + +/** + * Pojo for package.json + * + * @see https://docs.npmjs.com/files/package.json + */ +public class PackageJson { + + private String author; + private String name; + private String version; + private String description; + private String license; + private String repository; + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLicense() { + return license; + } + + public void setLicense(String license) { + this.license = license; + } + + public String getRepository() { + return repository; + } + + public void setRepository(String repository) { + this.repository = repository; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/repository/ITypeScriptRepository.java b/typescript.java-ts.core/src/main/java/ts/repository/ITypeScriptRepository.java new file mode 100644 index 000000000..b90560e6d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/repository/ITypeScriptRepository.java @@ -0,0 +1,84 @@ +package ts.repository; + +import java.io.File; + +/** + * TypeScript repository which hosts typescript bundle: + * + *

    + *
  • node_modules/typescript/bin/tsc and node_modules/typescript/bin/tsserver + *
  • + *
  • Or bin/tsc and bin/tsserver
  • + *
+ * + */ +public interface ITypeScriptRepository { + + /** + * Returns the TypeScript repository name. + * + * @return the TypeScript repository name. + */ + String getName(); + + /** + * Returns the base directory of the TypeScript repository. + * + * @return the base directory of the TypeScript repository. + */ + File getBaseDir(); + + /** + * Update the base directory of the TypeScript repository. + * + * @param baseDir + */ + void setBaseDir(File baseDir); + + /** + * The TypeScript base directory. + * + * @return the TypeScript base directory. + */ + File getTypesScriptDir(); + + /** + * Returns the TypeScript version and null otherwise. + * + * @return the TypeScript version and null otherwise. + */ + String getTypesScriptVersion(); + + /** + * Returns the tsc file. + * + * @return the tsc file. + */ + File getTscFile(); + + /** + * Returns the tslint version and null otherwise. + * + * @return the tslint version and null otherwise. + */ + String getTslintVersion(); + + /** + * Returns the tslint file. + * + * @return the tslint file. + */ + File getTslintFile(); + + /** + * Returns the tslint repository name. + * + * @return the tslint repository name. + */ + String getTslintName(); + + File getTsserverPluginsFile(); + + String getTslintLanguageServiceName(); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/repository/ITypeScriptRepositoryManager.java b/typescript.java-ts.core/src/main/java/ts/repository/ITypeScriptRepositoryManager.java new file mode 100644 index 000000000..0cdc107b1 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/repository/ITypeScriptRepositoryManager.java @@ -0,0 +1,71 @@ +package ts.repository; + +import java.io.File; + +/** + * Manager for keeping track of the available TypeScript repositories. Each + * repository includes a TypeScript installation and additional software, such + * as TSLint. + * + * Each repository is automatically assigned a name according to the included + * TypeScript version. No two repositories may share the same name. + * + * One repository may be marked as the default (see + * {@link #getDefaultRepository()}). + * + */ +public interface ITypeScriptRepositoryManager { + + /** + * Creates and adds a new repository. The new repository is also set as the + * default. + * + * @param baseDir + * base directory of the new repository. + * @return the created repository. + */ + ITypeScriptRepository createDefaultRepository(File baseDir) throws TypeScriptRepositoryException; + + /** + * Creates and adds a new repository. + * + * @param baseDir + * base directory of the new repository. + * @return the created repository. + */ + ITypeScriptRepository createRepository(File baseDir) throws TypeScriptRepositoryException; + + /** + * Removes a repository. If not present, nothing happens. + * + * @param name + * name of the repository to remove. + * @return the removed repository. + */ + ITypeScriptRepository removeRepository(String name); + + /** + * Gets the current default repository. + * + * @return a repository or {@code null} if there is no default. + */ + ITypeScriptRepository getDefaultRepository(); + + /** + * Gets a managed repository by name. + * + * @param name + * name of the repository to retrieve. + * @return a repository or {@code null} if there is no repository with the + * requested name. + */ + ITypeScriptRepository getRepository(String name); + + /** + * Gets all registered repositories. + * + * @return array of repositories. + */ + ITypeScriptRepository[] getRepositories(); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/repository/TypeScriptRepositoryException.java b/typescript.java-ts.core/src/main/java/ts/repository/TypeScriptRepositoryException.java new file mode 100644 index 000000000..356cc49d3 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/repository/TypeScriptRepositoryException.java @@ -0,0 +1,11 @@ +package ts.repository; + +import ts.TypeScriptException; + +public class TypeScriptRepositoryException extends TypeScriptException { + + public TypeScriptRepositoryException(String message) { + super(message); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/repository/TypeScriptRepositoryManager.java b/typescript.java-ts.core/src/main/java/ts/repository/TypeScriptRepositoryManager.java new file mode 100644 index 000000000..3fa106a56 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/repository/TypeScriptRepositoryManager.java @@ -0,0 +1,146 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + * Lorenzo Dalla Vecchia - protected API for setting default + */ +package ts.repository; + +import java.io.File; +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.eclipsesource.json.Json; +import com.eclipsesource.json.JsonObject; + +import ts.internal.repository.TypeScriptRepository; +import ts.utils.FileUtils; +import ts.utils.IOUtils; +import ts.utils.VersionHelper; + +/** + * TypeScript repository manager implementation. + * + */ +public class TypeScriptRepositoryManager implements ITypeScriptRepositoryManager { + + private final Map repositories; + private ITypeScriptRepository[] sortedRepositories; + private ITypeScriptRepository defaultRepository; + + private static final Comparator REPOSITORY_COMPARATOR = new Comparator() { + + @Override + public int compare(ITypeScriptRepository r1, ITypeScriptRepository r2) { + return VersionHelper.versionCompare(r2.getTypesScriptVersion(), r1.getTypesScriptVersion()); + } + }; + + public TypeScriptRepositoryManager() { + this.repositories = new HashMap(); + } + + @Override + public ITypeScriptRepository createDefaultRepository(File baseDir) throws TypeScriptRepositoryException { + return this.defaultRepository = createRepository(baseDir); + } + + protected final void setDefaultRepository(ITypeScriptRepository repository) { + this.defaultRepository = repository; + } + + @Override + public ITypeScriptRepository createRepository(File baseDir) throws TypeScriptRepositoryException { + synchronized (repositories) { + ITypeScriptRepository repository = new TypeScriptRepository(baseDir, this); + repositories.put(repository.getName(), repository); + reset(); + return repository; + } + } + + public void reset() { + sortedRepositories = null; + } + + @Override + public ITypeScriptRepository removeRepository(String name) { + synchronized (repositories) { + reset(); + return repositories.remove(name); + } + } + + @Override + public ITypeScriptRepository getDefaultRepository() { + return defaultRepository; + } + + @Override + public ITypeScriptRepository getRepository(String name) { + return repositories.get(name); + } + + @Override + public ITypeScriptRepository[] getRepositories() { + if (sortedRepositories == null) { + List reps = new ArrayList(repositories.values()); + Collections.sort(reps, REPOSITORY_COMPARATOR); + sortedRepositories = reps.toArray(new ITypeScriptRepository[reps.size()]); + } + return sortedRepositories; + } + + public static File getTsserverFile(File typesScriptDir) { + if (typesScriptDir.getName().equals("tsserver")) { + return typesScriptDir; + } + return new File(typesScriptDir, "bin/tsserver"); + } + + public static File getTscFile(File typesScriptDir) { + if (typesScriptDir.getName().equals("tsc")) { + return typesScriptDir; + } + return new File(typesScriptDir, "bin/tsc"); + } + + public static File getTslintFile(File tslintScriptDir) { + return new File(tslintScriptDir, "bin/tslint"); + } + + public static String getPackageJsonVersion(File baseDir) { + File packageJsonFile = new File(baseDir, "package.json"); + try { + JsonObject json = Json.parse(IOUtils.toString(new FileInputStream(packageJsonFile))).asObject(); + return json.getString("version", null); + } catch (Exception e) { + return null; + } + } + + public static void validateTypeScriptDir(File typesScriptDir) throws TypeScriptRepositoryException { + File tsserverFile = TypeScriptRepositoryManager.getTsserverFile(typesScriptDir); + if (!tsserverFile.exists()) { + throw new TypeScriptRepositoryException(FileUtils.getPath(typesScriptDir) + + " is not a valid TypeScript repository. Check the directory contains bin/tsserver."); + } + } + + public static File getTsserverPluginsFile(File typesScriptDir) { + if (typesScriptDir.getName().equals("tsserver-plugins")) { + return typesScriptDir; + } + return new File(typesScriptDir, "bin/tsserver-plugins"); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/AbstractTypeScriptFile.java b/typescript.java-ts.core/src/main/java/ts/resources/AbstractTypeScriptFile.java new file mode 100644 index 000000000..bef830850 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/AbstractTypeScriptFile.java @@ -0,0 +1,430 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import ts.TypeScriptException; +import ts.client.CodeEdit; +import ts.client.CommandNames; +import ts.client.FileSpan; +import ts.client.ITypeScriptServiceClient; +import ts.client.Location; +import ts.client.ScriptKindName; +import ts.client.codefixes.CodeAction; +import ts.client.completions.CompletionEntry; +import ts.client.completions.ICompletionEntryFactory; +import ts.client.configure.ConfigureRequestArguments; +import ts.client.diagnostics.DiagnosticEvent; +import ts.client.diagnostics.DiagnosticEventBody; +import ts.client.format.FormatCodeSettings; +import ts.client.jsdoc.TextInsertion; +import ts.client.navbar.NavigationBarItemRoot; +import ts.client.occurrences.OccurrencesResponseItem; +import ts.client.quickinfo.QuickInfo; +import ts.client.refactors.ApplicableRefactorInfo; +import ts.client.refactors.RefactorEditInfo; +import ts.client.references.ReferencesResponseBody; +import ts.client.rename.RenameResponseBody; +import ts.internal.LocationReader; +import ts.utils.CompletableFutureUtils; + +/** + * Abstract TypeScript file. + * + */ +public abstract class AbstractTypeScriptFile implements ITypeScriptFile { + + private final ITypeScriptProject tsProject; + private final ScriptKindName scriptKind; + + private boolean dirty; + protected final Object synchLock = new Object(); + private boolean opened; + + private final List listeners; + private NavigationBarItemRoot navbar; + private FormatCodeSettings formatOptions; + private boolean configureAlreadyDone; + private boolean disableChanged; + + private CompletableFuture navbarPromise; + + public AbstractTypeScriptFile(ITypeScriptProject tsProject, ScriptKindName scriptKind) { + this.tsProject = tsProject; + this.scriptKind = scriptKind; + this.listeners = new ArrayList(); + this.setDirty(false); + this.configureAlreadyDone = false; + } + + @Override + public ITypeScriptProject getProject() { + return tsProject; + } + + @Override + public ScriptKindName getScriptKind() { + return scriptKind; + } + + public void setDirty(boolean dirty) { + this.dirty = dirty; + } + + @Override + public boolean isDirty() { + return dirty; + } + + @Override + public Location getLocation(int position) throws TypeScriptException { + return new LocationReader(getContents(), position).getLineOffset(); + } + + @Override + public int getPosition(int line, int offset) throws TypeScriptException { + // TODO: implement that + throw new UnsupportedOperationException(); + } + + @Override + public int getPosition(Location loc) throws TypeScriptException { + return getPosition(loc.getLine(), loc.getOffset()); + } + + @Override + public void open() throws TypeScriptException { + ((TypeScriptProject) tsProject).openFile(this); + this.opened = true; + } + + @Override + public void close() throws TypeScriptException { + ((TypeScriptProject) tsProject).closeFile(this); + this.opened = false; + } + + @Override + public boolean isOpened() { + return opened; + } + + void setOpened(boolean opened) { + this.opened = opened; + } + + @Override + public CompletableFuture> completions(int position, ICompletionEntryFactory factory) + throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(position); + int line = location.getLine(); + int offset = location.getOffset(); + String prefix = null; + return client.completions(this.getName(), line, offset, factory); + } + + @Override + public CompletableFuture> definition(int position) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(position); + int line = location.getLine(); + int offset = location.getOffset(); + return client.definition(this.getName(), line, offset); + } + + @Override + public CompletableFuture quickInfo(int position) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(position); + int line = location.getLine(); + int offset = location.getOffset(); + return client.quickInfo(this.getName(), line, offset); + } + + @Override + public CompletableFuture> geterr() throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + return client.geterr(new String[] { getName() }, 0); + } + + @Override + public CompletableFuture> format(int startPosition, int endPosition) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + this.ensureFormatCodeSettings(client); + Location start = this.getLocation(startPosition); + Location end = this.getLocation(endPosition); + return client.format(this.getName(), start.getLine(), start.getOffset(), end.getLine(), end.getOffset()); + } + + private void ensureFormatCodeSettings(ITypeScriptServiceClient client) throws TypeScriptException { + FormatCodeSettings oldFormatOptions = formatOptions; + FormatCodeSettings newFormatOptions = getFormatOptions(); + if (!configureAlreadyDone || !newFormatOptions.equals(oldFormatOptions)) { + configureAlreadyDone = true; + client.configure(new ConfigureRequestArguments().setFile(getName()).setFormatOptions(formatOptions)); + } + } + + @Override + public CompletableFuture semanticDiagnosticsSync(Boolean includeLinePosition) + throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + return client.semanticDiagnosticsSync(getName(), includeLinePosition); + } + + @Override + public CompletableFuture syntacticDiagnosticsSync(Boolean includeLinePosition) + throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + return client.syntacticDiagnosticsSync(getName(), includeLinePosition); + } + + // @Override + // public CompletableFuture diagnostics(Boolean + // includeLinePosition) throws TypeScriptException { + // this.synch(); + // ITypeScriptServiceClient client = tsProject.getClient(); + // if (tsProject.canSupport(CommandNames.SemanticDiagnosticsSync)) { + // // TypeScript >=2.0.3, uses syntactic/semantic command names which + // // seems having better performance. + // return client.syntacticDiagnosticsSync(getName(), includeLinePosition) + // .thenApply(client.semanticDiagnosticsSync(getName(), + // includeLinePosition)); + // } else { + // // FIXME + // // client.geterr(new String[] { file.getName() }, 0, collector); + // } + // } + + @Override + public FormatCodeSettings getFormatOptions() { + formatOptions = tsProject.getProjectSettings().getFormatOptions(); + return formatOptions; + } + + public void setFormatOptions(FormatCodeSettings formatOptions) { + this.formatOptions = formatOptions; + } + + @Override + public CompletableFuture references(int position) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(position); + int line = location.getLine(); + int offset = location.getOffset(); + return client.references(this.getName(), line, offset); + } + + @Override + public CompletableFuture> occurrences(int position) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(position); + int line = location.getLine(); + int offset = location.getOffset(); + return client.occurrences(this.getName(), line, offset); + } + + @Override + public CompletableFuture rename(int position, Boolean findInComments, Boolean findInStrings) + throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(position); + int line = location.getLine(); + int offset = location.getOffset(); + return client.rename(this.getName(), line, offset, findInComments, findInStrings); + } + + @Override + public CompletableFuture> implementation(int position) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(position); + int line = location.getLine(); + int offset = location.getOffset(); + return client.implementation(this.getName(), line, offset); + } + + @Override + public CompletableFuture docCommentTemplate(int position) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(position); + int line = location.getLine(); + int offset = location.getOffset(); + return client.docCommentTemplate(this.getName(), line, offset); + } + + @Override + public CompletableFuture> getCodeFixes(int startPosition, int endPosition, + List errorCodes) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location startLocation = this.getLocation(startPosition); + int startLine = startLocation.getLine(); + int startOffset = startLocation.getOffset(); + Location endLocation = this.getLocation(endPosition); + int endLine = endLocation.getLine(); + int endOffset = endLocation.getOffset(); + return client.getCodeFixes(this.getName(), this, startLine, startOffset, endLine, endOffset, errorCodes); + } + + @Override + public void compileOnSaveEmitFile(Boolean forced) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + // FIXME client.compileOnSaveEmitFile(getName(), forced); + } + + @Override + public CompletableFuture> getApplicableRefactors(int startPosition, + Integer endPosition) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location startLocation = this.getLocation(startPosition); + int line = startLocation.getLine(); + int offset = startLocation.getOffset(); + if (endPosition == null) { + return client.getApplicableRefactors(this.getName(), line, offset); + } + Location endLocation = this.getLocation(endPosition); + int endLine = endLocation.getLine(); + int endOffset = endLocation.getOffset(); + return client.getApplicableRefactors(this.getName(), line, offset, endLine, endOffset); + } + + @Override + public CompletableFuture getEditsForRefactor(int startPosition, Integer endPosition, + String refactor, String action) throws TypeScriptException { + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + Location location = this.getLocation(startPosition); + int line = location.getLine(); + int offset = location.getOffset(); + if (endPosition == null) { + return client.getEditsForRefactor(this.getName(), line, offset, refactor, action); + } + Location endLocation = this.getLocation(endPosition); + int endLine = endLocation.getLine(); + int endOffset = endLocation.getOffset(); + return client.getEditsForRefactor(this.getName(), line, offset, endLine, endOffset, refactor, action); + } + + @Override + public void addNavbarListener(INavbarListener listener) { + synchronized (listeners) { + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + if (navbar != null) { + listener.navBarChanged(navbar); + } + } + + private void fireNavBarListeners(NavigationBarItemRoot navbar) { + synchronized (listeners) { + for (INavbarListener listener : listeners) { + listener.navBarChanged(navbar); + } + } + } + + @Override + public void removeNavbarListener(INavbarListener listener) { + synchronized (listeners) { + listeners.remove(listener); + } + } + + @Override + public void refreshNavBar() throws TypeScriptException { + if (listeners.isEmpty()) { + return; + } + this.synch(); + ITypeScriptServiceClient client = tsProject.getClient(); + // cancel last navigation bar/tree if needed. + CompletableFutureUtils.cancel(navbarPromise); + if (tsProject.canSupport(CommandNames.NavTree)) { + // when TypeScript 2.0.6 is consummed, use "navtree" to fill the + // Outline + // see + // https://github.com/Microsoft/TypeScript/pull/11532#issuecomment-254804923 + navbarPromise = client.navtree(this.getName(), this).thenAccept(item -> { + AbstractTypeScriptFile.this.navbar = new NavigationBarItemRoot(item); + fireNavBarListeners(navbar); + navbarPromise = null; + }); + } else { + navbarPromise = client.navbar(this.getName(), this).thenAccept(item -> { + AbstractTypeScriptFile.this.navbar = new NavigationBarItemRoot(item); + fireNavBarListeners(navbar); + navbarPromise = null; + }); + } + } + + @Override + public NavigationBarItemRoot getNavBar() { + return navbar; + } + + @Override + public synchronized void synch() throws TypeScriptException { + if (!isDirty()) { + // no need to synchronize the file content with tsserver. + return; + } + switch (tsProject.getProjectSettings().getSynchStrategy()) { + case RELOAD: + // reload strategy : store the content of the ts file in a temporary + // file and call reload command. + tsProject.getClient().updateFile(this.getName(), this.getContents()); + setDirty(false); + break; + case CHANGE: + // change strategy: wait until "change" command is not finished. + while (isDirty()) { + try { + synchronized (synchLock) { + synchLock.wait(5); + } + } catch (InterruptedException e) { + throw new TypeScriptException(e); + } + } + break; + } + + } + + public void setDisableChanged(boolean disableChanged) { + this.disableChanged = disableChanged; + } + + public boolean isDisableChanged() { + return disableChanged; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/BasicTypeScriptProjectSettings.java b/typescript.java-ts.core/src/main/java/ts/resources/BasicTypeScriptProjectSettings.java new file mode 100644 index 000000000..6a9957f76 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/BasicTypeScriptProjectSettings.java @@ -0,0 +1,149 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +import java.io.File; + +import ts.TypeScriptException; +import ts.client.completions.ICompletionEntryMatcher; +import ts.client.format.FormatCodeSettings; +import ts.cmd.tslint.TslintSettingsStrategy; +import ts.internal.repository.TypeScriptRepository; +import ts.nodejs.NodejsProcess; +import ts.nodejs.NodejsProcessHelper; +import ts.repository.ITypeScriptRepository; +import ts.repository.TypeScriptRepositoryException; + +/** + * Basic project settings. + * + */ +public class BasicTypeScriptProjectSettings implements ITypeScriptProjectSettings { + + private final File nodejsInstallPath; + private final SynchStrategy synchStrategy; + private final ITypeScriptRepository repository; + private ICompletionEntryMatcher completionEntryMatcher; + private TslintSettingsStrategy tslintStrategy; + private boolean enableTelemetry; + + private boolean disableAutomaticTypingAcquisition; + + public BasicTypeScriptProjectSettings(File nodejsInstallPath, File typeScriptDir) + throws TypeScriptRepositoryException { + this(nodejsInstallPath, typeScriptDir, SynchStrategy.RELOAD); + } + + public BasicTypeScriptProjectSettings(File nodejsInstallPath, File typeScriptDir, SynchStrategy synchStrategy) + throws TypeScriptRepositoryException { + this.nodejsInstallPath = nodejsInstallPath; + this.repository = new TypeScriptRepository(typeScriptDir); + this.synchStrategy = synchStrategy; + } + + @Override + public SynchStrategy getSynchStrategy() { + return synchStrategy; + } + + @Override + public File getNodejsInstallPath() { + return nodejsInstallPath; + } + + @Override + public String getNodeVersion() { + File nodejsFile = getNodejsInstallPath(); + return NodejsProcessHelper.getNodeVersion(nodejsFile); + } + + @Override + public File getTscFile() { + return repository.getTscFile(); + } + + @Override + public File getTypesScriptDir() { + return repository.getTypesScriptDir(); + } + + @Override + public File getTsserverPluginsFile() throws TypeScriptException { + return repository.getTsserverPluginsFile(); + } + + @Override + public File getTslintFile() throws TypeScriptException { + return repository.getTslintFile(); + } + + @Override + public ICompletionEntryMatcher getCompletionEntryMatcher() { + return completionEntryMatcher; + } + + public void setCompletionEntryMatcher(ICompletionEntryMatcher completionEntryMatcher) { + this.completionEntryMatcher = completionEntryMatcher; + } + + @Override + public File getCustomTslintJsonFile() { + // TODO Auto-generated method stub + return null; + } + + @Override + public TslintSettingsStrategy getTslintStrategy() { + return tslintStrategy; + } + + public void setTslintStrategy(TslintSettingsStrategy tslintStrategy) { + this.tslintStrategy = tslintStrategy; + } + + @Override + public boolean isUseCodeSnippetsOnMethodSuggest() { + return false; + } + + @Override + public void dispose() { + // Do nothing + } + + @Override + public FormatCodeSettings getFormatOptions() { + return null; + } + + @Override + public String getTypeScriptVersion() { + return repository.getTypesScriptVersion(); + } + + @Override + public boolean isEnableTelemetry() { + return enableTelemetry; + } + + public void setEnableTelemetry(boolean enableTelemetry) { + this.enableTelemetry = enableTelemetry; + } + + @Override + public boolean isDisableAutomaticTypingAcquisition() { + return disableAutomaticTypingAcquisition; + } + + public void setDisableAutomaticTypingAcquisition(boolean disableAutomaticTypingAcquisition) { + this.disableAutomaticTypingAcquisition = disableAutomaticTypingAcquisition; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/ConfigurableTypeScriptResourcesManager.java b/typescript.java-ts.core/src/main/java/ts/resources/ConfigurableTypeScriptResourcesManager.java new file mode 100644 index 000000000..e0bd64b22 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/ConfigurableTypeScriptResourcesManager.java @@ -0,0 +1,33 @@ +package ts.resources; + +import java.io.IOException; + +import ts.internal.resources.DefaultTypeScriptResourcesManager; + +public class ConfigurableTypeScriptResourcesManager { + + private static final ConfigurableTypeScriptResourcesManager INSTANCE = new ConfigurableTypeScriptResourcesManager(); + + private ITypeScriptResourcesManagerDelegate typeScriptResourcesManagerDelegate = new DefaultTypeScriptResourcesManager(); + + public static synchronized ConfigurableTypeScriptResourcesManager getInstance() { + return INSTANCE; + } + + public ITypeScriptProject getTypeScriptProject(Object project, boolean force) throws IOException { + return typeScriptResourcesManagerDelegate.getTypeScriptProject(project, force); + } + + public void setTypeScriptResourcesManagerDelegate( + ITypeScriptResourcesManagerDelegate typeScriptResourcesManagerDelegate) { + this.typeScriptResourcesManagerDelegate = typeScriptResourcesManagerDelegate; + } + + public boolean isTSFile(Object fileObject) { + return typeScriptResourcesManagerDelegate.isTsFile(fileObject); + } + + public boolean isJsFile(Object fileObject) { + return typeScriptResourcesManagerDelegate.isJsFile(fileObject); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/INavbarListener.java b/typescript.java-ts.core/src/main/java/ts/resources/INavbarListener.java new file mode 100644 index 000000000..13f2abdaf --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/INavbarListener.java @@ -0,0 +1,8 @@ +package ts.resources; + +import ts.client.navbar.NavigationBarItemRoot; + +public interface INavbarListener { + + void navBarChanged(NavigationBarItemRoot navbar); +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptFile.java b/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptFile.java new file mode 100644 index 000000000..1dbbff3cd --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptFile.java @@ -0,0 +1,258 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import ts.TypeScriptException; +import ts.client.CodeEdit; +import ts.client.FileSpan; +import ts.client.IPositionProvider; +import ts.client.ScriptKindName; +import ts.client.codefixes.CodeAction; +import ts.client.completions.CompletionEntry; +import ts.client.completions.ICompletionEntryFactory; +import ts.client.diagnostics.DiagnosticEvent; +import ts.client.diagnostics.DiagnosticEventBody; +import ts.client.format.FormatCodeSettings; +import ts.client.jsdoc.TextInsertion; +import ts.client.navbar.NavigationBarItemRoot; +import ts.client.occurrences.OccurrencesResponseItem; +import ts.client.quickinfo.QuickInfo; +import ts.client.refactors.ApplicableRefactorInfo; +import ts.client.refactors.RefactorEditInfo; +import ts.client.references.ReferencesResponseBody; +import ts.client.rename.RenameResponseBody; + +/** + * TypeScript file API. + * + */ +public interface ITypeScriptFile extends IPositionProvider { + + /** + * Returns the owner project of the file. + * + * @return the owner project of the file. + */ + ITypeScriptProject getProject(); + + /** + * Returns the full path of the file. + * + * @return the full path of the file. + */ + String getName(); + + /** + * Returns true if the file is flagged as "open" in tsserver side and false + * otherwise. In the case where tsserver is not started and the file is opened + * in the IDE editor, this method returns false. + * + * @return true if the file is flagged as "open" in tsserver side and false + * otherwise. + */ + boolean isOpened(); + + /** + * Returns true if file content has changed and must be synchronized with + * tsserver and false otherwise. + * + * @return true if file content has changed and must be synchronized with + * tsserver and false otherwise. + */ + boolean isDirty(); + + String getPrefix(int position); + + /** + * Returns the contents of the file. + * + * @return the contents of the file. + */ + String getContents(); + + /** + * Returns the script kind (ts, tsx, js or jsx) of the file. + * + * @return the script kind (ts, tsx, js or jsx) of the file. + */ + ScriptKindName getScriptKind(); + + /** + * Flag the file as "opened" into tsserver side. + * + * @throws TypeScriptException + */ + void open() throws TypeScriptException; + + /** + * Flag the file as "closed" into tsserver side. + * + * @throws TypeScriptException + */ + void close() throws TypeScriptException; + + /** + * Synchronize file content with tsserver according the {@link SynchStrategy}. + * + * @throws TypeScriptException + */ + void synch() throws TypeScriptException; + + /** + * Call completions from the tsserver. + * + * @param position + * @param instanceCreator + * @throws TypeScriptException + */ + CompletableFuture> completions(int position, ICompletionEntryFactory factory) + throws TypeScriptException; + + /** + * Call definition from the tsserver. + * + * @param position + * @throws TypeScriptException + */ + CompletableFuture> definition(int position) throws TypeScriptException; + + /** + * Call quickInfo from the tsserver. + * + * @param position + * @throws TypeScriptException + */ + CompletableFuture quickInfo(int position) throws TypeScriptException; + + /** + * Call getErr from the tsserver. + * + * @return + * @throws TypeScriptException + */ + CompletableFuture> geterr() throws TypeScriptException; + + /** + * Format the file content according start/end position. + * + * @param startPosition + * @param endPosition + * @throws TypeScriptException + */ + CompletableFuture> format(int startPosition, int endPosition) throws TypeScriptException; + + /** + * Execute semantic diagnostics. + * + * @param includeLinePosition + * @return + * @throws TypeScriptException + */ + CompletableFuture semanticDiagnosticsSync(Boolean includeLinePosition) + throws TypeScriptException; + + /** + * Execute syntactic diagnostics. + * + * @param includeLinePosition + * @return + * @throws TypeScriptException + */ + CompletableFuture syntacticDiagnosticsSync(Boolean includeLinePosition) + throws TypeScriptException; + + // /** + // * Execute semantic and syntactic both diagnostics. + // * + // * @param includeLinePosition + // * @return + // * @throws TypeScriptException + // */ + // CompletableFuture diagnostics(Boolean + // includeLinePosition) throws TypeScriptException; + + /** + * Find references of the given position. + * + * @param position + * @throws TypeScriptException + */ + public CompletableFuture references(int position) throws TypeScriptException; + + /** + * Find occurrences of the given position. + * + * @param position + * @throws TypeScriptException + */ + public CompletableFuture> occurrences(int position) throws TypeScriptException; + + CompletableFuture rename(int position, Boolean findInComments, Boolean findInStrings) + throws TypeScriptException; + + /** + * Call implementation from the tsserver. + * + * @param position + * @throws TypeScriptException + */ + CompletableFuture> implementation(int position) throws TypeScriptException; + + CompletableFuture docCommentTemplate(int position) throws TypeScriptException; + + /** + * Get code fixes. + * + * @param startPosition + * @param endPosition + * @param collector + * @throws TypeScriptException + */ + CompletableFuture> getCodeFixes(int startPosition, int endPosition, List errorCodes) + throws TypeScriptException; + + CompletableFuture> getApplicableRefactors(int startPosition, Integer endPosition) + throws TypeScriptException; + + CompletableFuture getEditsForRefactor(int startPosition, Integer endPosition, String refactor, + String action) throws TypeScriptException; + + /** + * Returns the navigation bar root. + * + * @return the navigation bar root. + */ + NavigationBarItemRoot getNavBar(); + + /** + * Refresh the navigation bar root. + * + * @throws TypeScriptException + */ + void refreshNavBar() throws TypeScriptException; + + void compileOnSaveEmitFile(Boolean forced) throws TypeScriptException; + + void addNavbarListener(INavbarListener listener); + + void removeNavbarListener(INavbarListener listener); + + FormatCodeSettings getFormatOptions(); + + void setFormatOptions(FormatCodeSettings formatOptions); + + void setDisableChanged(boolean disableChanged); + + boolean isDisableChanged(); +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptProject.java b/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptProject.java new file mode 100644 index 000000000..fbf195881 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptProject.java @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +import ts.TypeScriptException; +import ts.client.ISupportable; +import ts.client.ITypeScriptClientListener; +import ts.client.ITypeScriptServiceClient; +import ts.client.diagnostics.DiagnosticEvent; +import ts.client.navto.NavtoItem; +import ts.cmd.tsc.CompilerOptionCapability; +import ts.cmd.tsc.ITypeScriptCompiler; +import ts.cmd.tslint.ITypeScriptLint; + +/** + * TypeScript project API. + * + */ +public interface ITypeScriptProject { + + /** + * Returns associated tsclient if any. This call may result in creating one if + * it hasn't been created already. + * + * @return + * @throws TypeScriptException + */ + ITypeScriptServiceClient getClient() throws TypeScriptException; + + /** + * Returns the tsc compiler. + * + * @return + */ + ITypeScriptCompiler getCompiler() throws TypeScriptException; + + List getSupportedCodeFixes() throws TypeScriptException; + + boolean canFix(Integer errorCode); + + ITypeScriptFile getOpenedFile(String fileName); + + void dispose() throws TypeScriptException; + + T getData(String key); + + void setData(String key, Object value); + + // -------------- TypeScript server. + + void addServerListener(ITypeScriptClientListener listener); + + void removeServerListener(ITypeScriptClientListener listener); + + void disposeServer(); + + void disposeCompiler(); + + boolean isServerDisposed(); + + /** + * Returns the tslint linter. + * + * @return + * @throws TypeScriptException + */ + ITypeScriptLint getTslint() throws TypeScriptException; + + ITypeScriptProjectSettings getProjectSettings(); + + void disposeTslint(); + + /** + * Returns true if the given tsserver command can be supported by the TypeScript + * version configured for the project and false otherwise. + * + * @param command + * @return true if the given tsserver command can be supported by the TypeScript + * version configured for the project and false otherwise. + */ + boolean canSupport(ISupportable command); + + /** + * Returns true if the given tsc compiler option can be supported by the + * TypeScript version configured for the project and false otherwise. + * + * @param option + * @return true if the given tsc compiler option can be supported by the + * TypeScript version configured for the project and false otherwise. + */ + boolean canSupport(CompilerOptionCapability option); + + CompletableFuture> geterrForProject(String file, int delay) throws TypeScriptException; + + CompletableFuture> navto(String fileName, String searchValue, Integer maxResultCount, + Boolean currentFileOnly, String projectFileName) throws TypeScriptException; + +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptProjectSettings.java b/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptProjectSettings.java new file mode 100644 index 000000000..24954ad0d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptProjectSettings.java @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +import java.io.File; + +import ts.TypeScriptException; +import ts.client.completions.ICompletionEntryMatcher; +import ts.client.format.FormatCodeSettings; +import ts.cmd.tslint.TslintSettingsStrategy; + +/** + * TypeScript project settings API. + * + */ +public interface ITypeScriptProjectSettings { + + /** + * Returns the strategy to synchronize editor content with tsserver. + * + * @return the strategy to synchronize editor content with tsserver. + */ + SynchStrategy getSynchStrategy(); + + /** + * Returns the node.js install path. + * + * @return the node.js install path. + */ + File getNodejsInstallPath() throws TypeScriptException; + + /** + * Returns the nodejs version. + * + * @return the nodejs version. + */ + String getNodeVersion(); + + /** + * Returns the typescript/bin/tsc file to execute. + * + * @return the typescript/bin/tsc file to execute. + */ + File getTscFile() throws TypeScriptException; + + /** + * Returns the version of the TypeScript runtime and null otherwise. + * + * @return the version of TypeScript runtime and null otherwise. + */ + String getTypeScriptVersion(); + + /** + * Returns the typescript/bin/tsserver file to execute. + * + * @return the typescript/bin/tsserver file to execute. + * @throws TypeScriptException + */ + File getTypesScriptDir() throws TypeScriptException; + + File getTsserverPluginsFile() throws TypeScriptException; + + /** + * Returns the tslint/bin/tslint file to execute. + * + * @return the tslint/bin/tslint file to execute. + */ + File getTslintFile() throws TypeScriptException; + + /** + * Returns the completion entry matcher to use to filter TypeScript + * completion entries. + */ + ICompletionEntryMatcher getCompletionEntryMatcher(); + + boolean isUseCodeSnippetsOnMethodSuggest(); + + // ------------- tslint settings + + TslintSettingsStrategy getTslintStrategy(); + + File getCustomTslintJsonFile(); + + /** + * Dispose the settings. + */ + void dispose(); + + FormatCodeSettings getFormatOptions(); + + /** + * Returns true if telemetry must be enable and false otherwise. + * + * @return true if telemetry must be enable and false otherwise. + */ + boolean isEnableTelemetry(); + + boolean isDisableAutomaticTypingAcquisition(); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptResourcesManagerDelegate.java b/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptResourcesManagerDelegate.java new file mode 100644 index 000000000..07b656139 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/ITypeScriptResourcesManagerDelegate.java @@ -0,0 +1,124 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +import java.io.IOException; + +/** + * TypeScript resources manager. + * + */ +public interface ITypeScriptResourcesManagerDelegate { + + /** + * Return a TypeScript project associated with the specified resource. New + * project should be created only if it is a first such call on the + * resource. + * + * @param project + * @param force + * true if tsconfig.json project must be created if it doesn't + * exists, and false otherwise. + * @return + * @throws IOException + */ + ITypeScriptProject getTypeScriptProject(Object project, boolean force) throws IOException; + + /** + * Returns true if the given file object is a JavaScript file and false + * otherwise. + * + * @param fileObject + * @return true if the given file object is a JavaScript file and false + * otherwise. + */ + boolean isJsFile(Object fileObject); + + /** + * Returns true if the given file object is a JXS file and false otherwise. + * + * @param fileObject + * @return true if the given file object is a JSX file and false otherwise. + */ + boolean isJsxFile(Object fileObject); + + /** + * Returns true if the given file object is a TypeScript/JXS file and false + * otherwise. + * + * @param fileObject + * @return true if the given file object is a TypeScript/JXS file and false + * otherwise. + */ + boolean isTsxFile(Object fileObject); + + /** + * Returns true if the given file object is a TypeScript file and false + * otherwise. + * + * @param fileObject + * @return true if the given file object is a TypeScript file and false + * otherwise. + */ + boolean isTsFile(Object fileObject); + + /** + * Returns true if the given file object is a TypeScript or TypeScript/JSX + * file and false otherwise. + * + * @param fileObject + * @return true if the given file object is a TypeScript or TypeScript/JSX + * file and false otherwise. + */ + boolean isTsOrTsxFile(Object fileObject); + + /** + * Returns true if the given file object is a TypeScript definition file + * *.d.ts and false otherwise. + * + * @param fileObject + * @return true if the given file object is a TypeScript definition file + * *.d.ts and false otherwise. + */ + boolean isDefinitionTsFile(Object fileObject); + + /** + * Returns true if the given file object is a TypeScript or TypeScript/JSX + * or JSX file and false otherwise. + * + * @param fileObject + * @return true if the given file object is a TypeScript or TypeScript/JSX + * or JSX file and false otherwise. + */ + boolean isTsOrTsxOrJsxFile(Object fileObject); + + /** + * Returns true if the given file object is TypeScript/JSX or JSX file and + * false otherwise. + * + * @param fileObject + * @return true if the given file object is a TypeScript or TypeScript/JSX + * or JSX file and false otherwise. + */ + boolean isTsxOrJsxFile(Object fileObject); + + /** + * Returns the corresponding TypeScript file from the js or js.map file and + * null otherwise. + * + * @param file + * *.js or *.js.map file + * @return the corresponding TypeScript file from the js or js.map file and + * null otherwise. + */ + String getTypeScriptFilename(Object file); + +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/SynchStrategy.java b/typescript.java-ts.core/src/main/java/ts/resources/SynchStrategy.java new file mode 100644 index 000000000..32a5b8023 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/SynchStrategy.java @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +/** + * Strategy for synchronize file content from the IDE editor and tsserver: + * + *
    + *
  • {{@value #CHANGE} : this strategy must be used if the IDE editor can + * support change events when user modify the content of the editor: the IDE + * editor send to the tsserver the change of the editor as soon as user modify + * the content of the editor.
  • + *
  • {{@value #RELOAD} : this strategy must be used if the IDE editor cannot + * support change events when user modify the content of the editor: the + * synchronization is done just before completion, hover, etc is executed: a + * temporary file is created with the content of the editor and "reload" command + * is sent to the tsserver by setting the path of the temporary file.
  • + *
      + * + */ +public enum SynchStrategy { + + CHANGE, RELOAD; +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/TypeScriptProject.java b/typescript.java-ts.core/src/main/java/ts/resources/TypeScriptProject.java new file mode 100644 index 000000000..a7af39ff5 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/TypeScriptProject.java @@ -0,0 +1,406 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; + +import ts.TypeScriptException; +import ts.client.CommandNames; +import ts.client.ISupportable; +import ts.client.ITypeScriptClientListener; +import ts.client.ITypeScriptServiceClient; +import ts.client.ScriptKindName; +import ts.client.TypeScriptServiceClient; +import ts.client.completions.ICompletionEntryMatcher; +import ts.client.completions.ICompletionEntryMatcherProvider; +import ts.client.diagnostics.DiagnosticEvent; +import ts.client.navto.NavtoItem; +import ts.client.projectinfo.ProjectInfo; +import ts.cmd.tsc.CompilerOptionCapability; +import ts.cmd.tsc.ITypeScriptCompiler; +import ts.cmd.tsc.TypeScriptCompiler; +import ts.cmd.tslint.ITypeScriptLint; +import ts.cmd.tslint.TypeScriptLint; +import ts.utils.FileUtils; +import ts.utils.VersionHelper; + +/** + * TypeScript project implementation. + * + */ +public class TypeScriptProject implements ITypeScriptProject, ICompletionEntryMatcherProvider { + + private static final ISupportable CANCELLATION_CAPABILITY = new ISupportable() { + + @Override + public boolean canSupport(String version) { + return VersionHelper.canSupport(version, "2.2.2"); + } + }; + private final File projectDir; + private ITypeScriptProjectSettings projectSettings; + + // TypeScript service client + private ITypeScriptServiceClient client; + private final Map openedFiles; + + // TypeScript compiler + private ITypeScriptCompiler compiler; + + private final Map data; + private final List listeners; + protected final Object serverLock = new Object(); + private ITypeScriptLint tslint; + + private final Map serverCapabilities; + private Map compilerCapabilities; + + private List supportedCodeFixes; + + private ProjectInfo projectInfo; + + public TypeScriptProject(File projectDir, ITypeScriptProjectSettings projectSettings) { + this.projectDir = projectDir; + this.projectSettings = projectSettings; + this.openedFiles = new HashMap<>(); + this.data = new HashMap(); + this.listeners = new ArrayList<>(); + this.serverCapabilities = new HashMap<>(); + this.compilerCapabilities = new HashMap<>(); + this.projectInfo = null; + } + + protected void setProjectSettings(ITypeScriptProjectSettings projectSettings) { + this.projectSettings = projectSettings; + } + + /** + * Returns the project base directory. + * + * @return the project base directory. + */ + public File getProjectDir() { + return projectDir; + } + + void openFile(ITypeScriptFile tsFile) throws TypeScriptException { + String name = tsFile.getName(); + String contents = tsFile.getContents(); + ScriptKindName scriptKind = tsFile.getScriptKind(); + getClient().openFile(name, contents, scriptKind); + this.openedFiles.put(name, tsFile); + } + + void closeFile(ITypeScriptFile tsFile) throws TypeScriptException { + String name = tsFile.getName(); + getClient().closeFile(name); + ((AbstractTypeScriptFile) tsFile).setOpened(false); + this.openedFiles.remove(name); + } + + @Override + public List getSupportedCodeFixes() throws TypeScriptException { + if (supportedCodeFixes != null) { + return supportedCodeFixes; + } + if (canSupport(CommandNames.GetSupportedCodeFixes)) { + try { + supportedCodeFixes = getClient().getSupportedCodeFixes().get(5000, TimeUnit.MILLISECONDS); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + supportedCodeFixes = new ArrayList(); + } + return supportedCodeFixes; + } + + @Override + public boolean canFix(Integer errorCode) { + try { + return getSupportedCodeFixes().contains(String.valueOf(errorCode)); + } catch (Throwable e) { + e.printStackTrace(); + return false; + } + } + + @Override + public final ITypeScriptServiceClient getClient() throws TypeScriptException { + synchronized (serverLock) { + if (isServerDisposed()) { + try { + this.client = createServiceClient(getProjectDir()); + copyListeners(); + onCreateClient(client); + } catch (Exception e) { + if (e instanceof TypeScriptException) { + throw (TypeScriptException) e; + } + throw new TypeScriptException(e); + } + + } + return client; + } + } + + protected void onCreateClient(ITypeScriptServiceClient client) { + + } + + @Override + public synchronized ITypeScriptFile getOpenedFile(String fileName) { + return openedFiles.get(fileName); + } + + @Override + public void dispose() throws TypeScriptException { + disposeServer(); + getProjectSettings().dispose(); + } + + /** + * Create service client which consumes tsserver. + * + * @param projectDir + * @return + * @throws TypeScriptException + */ + protected ITypeScriptServiceClient createServiceClient(File projectDir) throws TypeScriptException { + File nodeFile = getProjectSettings().getNodejsInstallPath(); + File typescriptDir = getProjectSettings().getTypesScriptDir(); + TypeScriptServiceClient client = new TypeScriptServiceClient(getProjectDir(), typescriptDir, nodeFile, + getProjectSettings().isEnableTelemetry(), getProjectSettings().isDisableAutomaticTypingAcquisition(), + getCancellationPipeName(), getProjectSettings().getTsserverPluginsFile(), null); + client.setCompletionEntryMatcherProvider(this); + return client; + } + + private String getCancellationPipeName() { + if (canSupport(CANCELLATION_CAPABILITY)) { + String name = new StringBuilder("eclipse-").append("tscancellation-").append(UUID.randomUUID().toString()) + .append(".sock").toString(); + return FileUtils.getPath(new File(System.getProperty("java.io.tmpdir"), name)); + } + return null; + } + + /** + * Create compiler which consumes tsc. + * + * @return + * @throws TypeScriptException + */ + protected ITypeScriptCompiler createCompiler() throws TypeScriptException { + File nodeFile = getProjectSettings().getNodejsInstallPath(); + File tscFile = getProjectSettings().getTscFile(); + return createCompiler(tscFile, nodeFile); + } + + protected ITypeScriptCompiler createCompiler(File tscFile, File nodejsFile) { + return new TypeScriptCompiler(tscFile, nodejsFile); + } + + // ----------------------- TypeScript server listeners. + + @Override + public void addServerListener(ITypeScriptClientListener listener) { + synchronized (listeners) { + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + copyListeners(); + } + + @Override + public void removeServerListener(ITypeScriptClientListener listener) { + synchronized (listeners) { + listeners.remove(listener); + } + synchronized (serverLock) { + if (hasClient()) { + this.client.removeClientListener(listener); + } + } + } + + protected boolean hasClient() { + return client != null; + } + + private void copyListeners() { + synchronized (serverLock) { + if (hasClient()) { + for (ITypeScriptClientListener listener : listeners) { + client.addClientListener(listener); + } + } + } + } + + @Override + public void disposeServer() { + synchronized (serverLock) { + if (!isServerDisposed()) { + if (hasClient()) { + // close opened files + List files = new ArrayList(openedFiles.values()); + for (ITypeScriptFile openedFile : files) { + try { + openedFile.close(); + } catch (TypeScriptException e) { + e.printStackTrace(); + } + } + client.dispose(); + client = null; + } + } + } + serverCapabilities.clear(); + supportedCodeFixes = null; + } + + @Override + public void disposeCompiler() { + if (compiler != null) { + compiler.dispose(); + compiler = null; + compilerCapabilities.clear(); + } + } + + @SuppressWarnings("unchecked") + public T getData(String key) { + synchronized (data) { + return (T) data.get(key); + } + } + + public void setData(String key, Object value) { + synchronized (data) { + data.put(key, value); + } + } + + @Override + public boolean isServerDisposed() { + synchronized (serverLock) { + return client == null || client.isDisposed(); + } + } + + @Override + public ITypeScriptCompiler getCompiler() throws TypeScriptException { + if (compiler == null) { + compiler = createCompiler(); + } + return compiler; + } + + @Override + public ITypeScriptLint getTslint() throws TypeScriptException { + if (tslint == null) { + tslint = createTslint(); + } + return tslint; + } + + @Override + public void disposeTslint() { + if (tslint != null) { + // tslint.dispose(); + tslint = null; + } + } + + protected ITypeScriptLint createTslint() throws TypeScriptException { + File nodeFile = getProjectSettings().getNodejsInstallPath(); + File tslintFile = getProjectSettings().getTslintFile(); + File tslintJsonFile = getProjectSettings().getCustomTslintJsonFile(); + return createTslint(tslintFile, tslintJsonFile, nodeFile); + } + + protected ITypeScriptLint createTslint(File tslintFile, File tslintJsonFile, File nodejsFile) { + return new TypeScriptLint(tslintFile, tslintJsonFile, nodejsFile); + } + + @Override + public ITypeScriptProjectSettings getProjectSettings() { + return projectSettings; + } + + @Override + public boolean canSupport(ISupportable command) { + Boolean support = serverCapabilities.get(command); + if (support == null) { + support = command.canSupport(getProjectSettings().getTypeScriptVersion()); + serverCapabilities.put(command, support); + } + return support; + } + + @Override + public boolean canSupport(CompilerOptionCapability option) { + Boolean support = compilerCapabilities.get(option); + if (support == null) { + support = option.canSupport(getProjectSettings().getTypeScriptVersion()); + compilerCapabilities.put(option, support); + } + return support; + } + + @Override + public ICompletionEntryMatcher getMatcher() { + return getProjectSettings().getCompletionEntryMatcher(); + } + + @Override + public CompletableFuture> geterrForProject(String file, int delay) + throws TypeScriptException { + /* + * if (projectInfo == null) { + * CompletableFuture.allOf(getClient().projectInfo(file, null, true), + * geterrForProjectRequest(file, delay)); CompletableFuture + * projectInfoFuture = getClient().projectInfo(file, null, true); return + * projectInfoFuture. thenAccept(projectInfo -> return + * geterrForProjectRequest(file, delay)); } else { + */ + + try { + ProjectInfo projectInfo = getClient().projectInfo(file, null, true).get(5000, TimeUnit.MILLISECONDS); + return getClient().geterrForProject(file, delay, projectInfo); + } catch (Exception e) { + if (e instanceof TypeScriptException) { + throw (TypeScriptException) e; + } + throw new TypeScriptException(e); + } + + } + + @Override + public CompletableFuture> navto(String fileName, String searchValue, Integer maxResultCount, + Boolean currentFileOnly, String projectFileName) throws TypeScriptException { + ITypeScriptServiceClient client = getClient(); + return client.navto(fileName, searchValue, maxResultCount, currentFileOnly, projectFileName); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/TypeScriptResourcesManager.java b/typescript.java-ts.core/src/main/java/ts/resources/TypeScriptResourcesManager.java new file mode 100644 index 000000000..3dca65214 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/TypeScriptResourcesManager.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources; + +import java.io.IOException; + +public class TypeScriptResourcesManager { + + private static final ConfigurableTypeScriptResourcesManager INSTANCE = ConfigurableTypeScriptResourcesManager + .getInstance(); + + /** + * Returns a TypeScript project object associated with the specified + * resource. May return null if resource doesn't point at a valid TypeScript + * project. + * + * @param project + * @return a TypeScript project object associated with the specified + * resource. May return null if resource doesn't point at a valid + * TypeScript project. + * @throws IOException + */ + public static ITypeScriptProject getTypeScriptProject(Object project) { + try { + return INSTANCE.getTypeScriptProject(project, false); + } catch (IOException e) { + return null; + } + } + + /** + * Returns a TypeScript project object associated with the specified + * resource. May return null if resource doesn't point at a valid TypeScript + * project. + * + * @param project + * @param force + * true if .TypeScript-project must be created if it doesn't + * exists, and false otherwise. + * + * @return a TypeScript project object associated with the specified + * resource. May return null if resource doesn't point at a valid + * TypeScript project. + * @throws IOException + */ + public static ITypeScriptProject getTypeScriptProject(Object project, boolean force) throws IOException { + return INSTANCE.getTypeScriptProject(project, force); + } + + /** + * Returns true if the given file object is a TypeScript file and false + * otherwise. + * + * @param fileObject + * @return true if the given file object is a TypeScript file and false + * otherwise. + */ + public static boolean isTSFile(Object fileObject) { + return INSTANCE.isTSFile(fileObject); + } + + public static boolean isJSFile(Object fileObject) { + return INSTANCE.isJsFile(fileObject); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/resources/jsonconfig/TsconfigJson.java b/typescript.java-ts.core/src/main/java/ts/resources/jsonconfig/TsconfigJson.java new file mode 100644 index 000000000..ba4b1f153 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/resources/jsonconfig/TsconfigJson.java @@ -0,0 +1,297 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.resources.jsonconfig; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; + +import ts.cmd.tsc.CompilerOptions; +import ts.utils.BooleanUtils; +import ts.utils.FileUtils; +import ts.utils.StringUtils; + +/** + * Pojo for tsconfig.json + * + * @see http://www.typescriptlang.org/docs/handbook/tsconfig-json.html + * + */ +public class TsconfigJson { + + // See + // https://github.com/SchemaStore/schemastore/blob/master/src/schemas/json/tsconfig.json + + private static final String DEFAULT_TARGET = "es3"; + private static final String[] AVAILABLE_TARGETS = new String[] { "es3", "es5", "es6", "es2015", "es2016", "es2017", + "esnext" }; + private static final String[] AVAILABLE_MODULES = new String[] { "none", "commonjs", "amd", "umd", "system", "es6", + "es2015" }; + private static final String DEFAULT_MODULE_RESOLUTION = "classic"; + private static final String[] AVAILABLE_MODULE_RESOLUTIONS = new String[] { "node", "classic" }; + + private CompilerOptions compilerOptions; + + private Boolean compileOnSave; + + private Boolean buildOnSave; + + private List files; + + private List exclude; + + private List defaultExclude; + + public TsconfigJson() { + } + + public void setCompilerOptions(CompilerOptions compilerOptions) { + this.compilerOptions = compilerOptions; + } + + public CompilerOptions getCompilerOptions() { + return compilerOptions; + } + + public boolean isCompileOnSave() { + return BooleanUtils.toBoolean(compileOnSave); + } + + public void setCompileOnSave(Boolean compileOnSave) { + this.compileOnSave = compileOnSave; + } + + /** + * Returns true if build must be done on save and false otherwise. This + * property doesn't belong to the standard specification of tsconfig.json, + * it comes from the atom-typescript. + * + * Build means compile all files. Useful if for some reason you are using + * --out. Default is false. Note that build is a slow process, therefore we + * recommend leaving it off. But in case this is the way you want to go its + * there for your convenience. + * + * @see https://github.com/TypeStrong/atom-typescript/blob/master/docs/tsconfig.md#buildonsave + * @return true if build must ne done on save and false otherwise. + */ + public boolean isBuildOnSave() { + return BooleanUtils.toBoolean(buildOnSave); + } + + /** + * Set to true if build must be done on save and false otherwise. This + * property doesn't belong to the standard specification of tsconfig.json, + * it comes from the atom-typescript. + * + * Build means compile all files. Useful if for some reason you are using + * --out. Default is false. Note that build is a slow process, therefore we + * recommend leaving it off. But in case this is the way you want to go its + * there for your convenience. + * + * @see https://github.com/TypeStrong/atom-typescript/blob/master/docs/tsconfig.md#buildonsave + * + * @param buildOnSave + */ + public void setBuildOnSave(boolean buildOnSave) { + this.buildOnSave = buildOnSave; + } + + public List getFiles() { + return files; + } + + public void setFiles(List files) { + this.files = files; + } + + public boolean hasFiles() { + return files != null; + } + + public List getExclude() { + return exclude; + } + + public void setExclude(List exclude) { + this.exclude = exclude; + } + + public boolean hasExclude() { + return exclude != null; + } + + /** + * Returns true if the "compilerOptions" defines "out" or "outFile" and + * false otherwise. + * + * @return true if the "compilerOptions" defines "out" or "outFile" and + * false otherwise. + */ + public boolean hasOutFile() { + CompilerOptions options = getCompilerOptions(); + if (options == null) { + return false; + } + return !StringUtils.isEmpty(options.getOutFile()) || !StringUtils.isEmpty(options.getOut()); + } + + /** + * Returns true if the "compilerOptions" defines "paths" and false + * otherwise. + * + * @return true if the "compilerOptions" defines "paths" and false + * otherwise. + */ + public boolean hasPaths() { + CompilerOptions options = getCompilerOptions(); + if (options == null) { + return false; + } + return !options.getPathsKeys().isEmpty(); + } + + /** + * Returns true if the "compilerOptions" defines "rootDirs" and false + * otherwise. + * + * @return true if the "compilerOptions" defines "rootDirs" and false + * otherwise. + */ + public boolean hasRootDirs() { + CompilerOptions options = getCompilerOptions(); + if (options == null) { + return false; + } + return !options.getRootDirs().isEmpty(); + } + + /** + * Returns the defined "exclude" list from the tsconfig.json other exclude + * by default "node_modules" and "bower_components". + * + * @return the defined "exclude" list from the tsconfig.json other exclude + * by default "node_modules" and "bower_components". + */ + protected List getDefaultOrDefinedExclude() { + if (exclude != null) { + return exclude; + } + if (defaultExclude != null) { + return defaultExclude; + } + // by default exclude node_modules, bower_components and any specificied + // output directory (see this rule used in the tsc.js) + this.defaultExclude = new ArrayList(Arrays.asList(FileUtils.NODE_MODULES, FileUtils.BOWER_COMPONENTS)); + CompilerOptions options = getCompilerOptions(); + if (options != null && !StringUtils.isEmpty(options.getOutDir())) { + defaultExclude.add(options.getOutDir()); + } + return defaultExclude; + } + + /** + * Load tsconfig.json instance from the given reader. + * + * @param reader + * @return tsconfig.json instance from the given reader. + */ + public static TsconfigJson load(Reader reader) { + return load(reader, TsconfigJson.class); + } + + public static T load(Reader json, Class classOfT) { + Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + T o = gson.fromJson(json, classOfT); + if (o == null) { + throw new JsonSyntaxException("JSON Syntax error"); + } + return o; + } + + public static T load(InputStream in, Class classOfT) { + Reader isr = null; + try { + isr = new InputStreamReader(in); + return load(isr, classOfT); + } finally { + if (isr != null) { + try { + isr.close(); + } catch (IOException e) { + } + } + } + } + + /** + * Load tsconfig.json instance from the given input stream. + * + * @param in + * @return tsconfig.json instance from the given input stream + */ + public static TsconfigJson load(InputStream in) { + return load(in, TsconfigJson.class); + } + + /** + * Returns the available targets. + * + * @return the available targets. + */ + public static String[] getAvailableTargets() { + return AVAILABLE_TARGETS; + } + + /** + * Returns the default target. + * + * @return the default target. + */ + public static String getDefaultTarget() { + return DEFAULT_TARGET; + } + + /** + * Returns the available modules. + * + * @return the available modules. + */ + public static String[] getAvailableModules() { + return AVAILABLE_MODULES; + } + + /** + * Returns the available module resolutions. + * + * @return the available module resolutions. + */ + public static String[] getAvailableModuleResolutions() { + return AVAILABLE_MODULE_RESOLUTIONS; + } + + /** + * Returns the default module resolution. + * + * @return the default module resolution. + */ + public static String getDefaultModuleResolution() { + return DEFAULT_MODULE_RESOLUTION; + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/BooleanUtils.java b/typescript.java-ts.core/src/main/java/ts/utils/BooleanUtils.java new file mode 100644 index 000000000..509d3bcc0 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/BooleanUtils.java @@ -0,0 +1,24 @@ +package ts.utils; + +public class BooleanUtils { + + /** + *

      + * Converts a Boolean to a boolean handling {@code null} by returning + * {@code false}. + *

      + * + *
      +	 *   BooleanUtils.toBoolean(Boolean.TRUE)  = true
      +	 *   BooleanUtils.toBoolean(Boolean.FALSE) = false
      +	 *   BooleanUtils.toBoolean(null)          = false
      +	 * 
      + * + * @param bool + * the boolean to convert + * @return {@code true} or {@code false}, {@code null} returns {@code false} + */ + public static boolean toBoolean(final Boolean bool) { + return bool != null && bool.booleanValue(); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/CompletableFutureUtils.java b/typescript.java-ts.core/src/main/java/ts/utils/CompletableFutureUtils.java new file mode 100644 index 000000000..2f139ce51 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/CompletableFutureUtils.java @@ -0,0 +1,26 @@ +/** + * Copyright (c) 2015-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.utils; + +import java.util.concurrent.CompletableFuture; + +/** + * Utilities for {@link CompletableFuture}. + */ +public class CompletableFutureUtils { + + public static void cancel(CompletableFuture promise) { + // cancel future if needed + if (promise != null && !promise.isDone()) { + promise.cancel(true); + } + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/FileUtils.java b/typescript.java-ts.core/src/main/java/ts/utils/FileUtils.java new file mode 100644 index 000000000..c5ca472b0 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/FileUtils.java @@ -0,0 +1,156 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +public class FileUtils { + + /** + * Extension file + */ + public static final String JS_EXTENSION = "js"; + public static final String TS_EXTENSION = "ts"; + public static final String JSX_EXTENSION = "jsx"; + public static final String TSX_EXTENSION = "tsx"; + public static final String MAP_EXTENSION = "map"; + public static final String DEFINITION_TS_EXTENSION = ".d.ts"; + + /** + * Configuration file + */ + public static final String TSCONFIG_START = "tsconfig"; + public static final String TSCONFIG_END = ".json"; + + public static final String TSCONFIG_JSON = "tsconfig.json"; + public static final String JSCONFIG_JSON = "jsconfig.json"; + public static final String TSLINT_JSON = "tslint.json"; + + /** + * Folders + */ + public static final String NODE_MODULES = "node_modules"; + public static final String BOWER_COMPONENTS = "bower_components"; + + public static String getFileExtension(String fileName) { + int index = fileName.lastIndexOf('.'); + if (index == -1) + return null; + if (index == fileName.length() - 1) + return ""; //$NON-NLS-1$ + return fileName.substring(index + 1); + } + + public static String getTypeScriptFilename(String fileName) { + int index = fileName.lastIndexOf('.'); + if (index == -1 || index == fileName.length() - 1) { + return null; + } + String ext = fileName.substring(index + 1); + if (FileUtils.JS_EXTENSION.equals(ext)) { + StringBuilder tsFileName = new StringBuilder(fileName.substring(0, index)); + tsFileName.append('.'); + tsFileName.append(FileUtils.TS_EXTENSION); + return tsFileName.toString(); + } else if (FileUtils.MAP_EXTENSION.equals(ext)) { + return getTypeScriptFilename(fileName.substring(0, index)); + } + return null; + } + + public static boolean isJsOrJsMapFile(String fileName) { + int index = fileName.lastIndexOf('.'); + if (index == -1 || index == fileName.length() - 1) { + return false; + } + String ext = fileName.substring(index + 1); + if (FileUtils.JS_EXTENSION.equals(ext)) { + return true; + } else if (FileUtils.MAP_EXTENSION.equals(ext)) { + return isJsOrJsMapFile(fileName.substring(0, index)); + } + return false; + } + + /** + * Returns the normalized path of the given file. + * + * @param file + * @return the normalized path of the given file. + */ + public static String getPath(File file) { + return getPath(file, true); + } + + /** + * Returns the path of the given file. + * + * @param file + * @param normalize + * @return + */ + public static String getPath(File file, boolean normalize) { + String path = null; + try { + path = file.getCanonicalPath(); + } catch (IOException e) { + path = file.getPath(); + } + return normalize ? normalizeSlashes(path) : null; + } + + /** + * Replace '\' with '/' from the given path because tsserver normalize it + * like this. + * + * @param path + * @return + */ + public static String normalizeSlashes(String path) { + return path.replaceAll("\\\\", "/"); + } + + public static String getContents(final File file) throws IOException { + InputStream in = null; + try { + in = openInputStream(file); + return IOUtils.toString(in, null); + } finally { + IOUtils.closeQuietly(in); + } + } + + public static FileInputStream openInputStream(final File file) throws IOException { + if (file.exists()) { + if (file.isDirectory()) { + throw new IOException("File '" + file + "' exists but is a directory"); + } + if (file.canRead() == false) { + throw new IOException("File '" + file + "' cannot be read"); + } + } else { + throw new FileNotFoundException("File '" + file + "' does not exist"); + } + return new FileInputStream(file); + } + + public static boolean isTsConfigFile(String filename) { + if (FileUtils.TSCONFIG_JSON.equals(filename)) { + return true; + } + return filename.startsWith(TSCONFIG_START) && filename.endsWith(TSCONFIG_END); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/IOUtils.java b/typescript.java-ts.core/src/main/java/ts/utils/IOUtils.java new file mode 100644 index 000000000..9617895ca --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/IOUtils.java @@ -0,0 +1,2305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ +package ts.utils; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.CharArrayWriter; +import java.io.Closeable; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.net.URL; +import java.nio.channels.Selector; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import ts.internal.io.output.ByteArrayOutputStream; +import ts.internal.io.output.StringBuilderWriter; + +/** + * General IO stream manipulation utilities. + *

      + * This class provides static utility methods for input/output operations. + *

        + *
      • closeQuietly - these methods close a stream ignoring nulls and exceptions + *
      • toXxx/read - these methods read data from a stream + *
      • write - these methods write data to a stream + *
      • copy - these methods copy all the data from one stream to another + *
      • contentEquals - these methods compare the content of two streams + *
      + *

      + * The byte-to-char methods and char-to-byte methods involve a conversion step. + * Two methods are provided in each case, one that uses the platform default + * encoding and the other which allows you to specify an encoding. You are + * encouraged to always specify an encoding because relying on the platform + * default can lead to unexpected results, for example when moving from + * development to production. + *

      + * All the methods in this class that read a stream are buffered internally. + * This means that there is no cause to use a BufferedInputStream + * or BufferedReader. The default buffer size of 4K has been shown + * to be efficient in tests. + *

      + * Wherever possible, the methods in this class do not flush or close + * the stream. This is to avoid making non-portable assumptions about the + * streams' origin and further use. Thus the caller is still responsible for + * closing streams after use. + *

      + * Origin of code: Excalibur. + * + * @version $Id: IOUtils.java 1304177 2012-03-23 03:36:44Z ggregory $ + */ +public class IOUtils { + // NOTE: This class is focussed on InputStream, OutputStream, Reader and + // Writer. Each method should take at least one of these as a parameter, + // or return one of them. + + private static final int EOF = -1; + /** + * The Unix directory separator character. + */ + public static final char DIR_SEPARATOR_UNIX = '/'; + /** + * The Windows directory separator character. + */ + public static final char DIR_SEPARATOR_WINDOWS = '\\'; + /** + * The system directory separator character. + */ + public static final char DIR_SEPARATOR = File.separatorChar; + /** + * The Unix line separator string. + */ + public static final String LINE_SEPARATOR_UNIX = "\n"; + /** + * The Windows line separator string. + */ + public static final String LINE_SEPARATOR_WINDOWS = "\r\n"; + /** + * The system line separator string. + */ + public static final String LINE_SEPARATOR; + + static { + // avoid security issues + StringBuilderWriter buf = new StringBuilderWriter(4); + PrintWriter out = new PrintWriter(buf); + out.println(); + LINE_SEPARATOR = buf.toString(); + out.close(); + } + + /** + * The default buffer size ({@value}) to use for + * {@link #copyLarge(InputStream, OutputStream)} + * and + * {@link #copyLarge(Reader, Writer)} + */ + private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; + + /** + * The default buffer size to use for the skip() methods. + */ + private static final int SKIP_BUFFER_SIZE = 2048; + + // Allocated in the relevant skip method if necessary. + /* + * N.B. no need to synchronize these because: + * - we don't care if the buffer is created multiple times (the data is ignored) + * - we always use the same size buffer, so if it it is recreated it will still be OK + * (if the buffer size were variable, we would need to synch. to ensure some other thread + * did not create a smaller one) + */ + private static char[] SKIP_CHAR_BUFFER; + private static byte[] SKIP_BYTE_BUFFER; + + /** + * Instances should NOT be constructed in standard programming. + */ + public IOUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + * Unconditionally close an Reader. + *

      + * Equivalent to {@link Reader#close()}, except any exceptions will be ignored. + * This is typically used in finally blocks. + *

      + * Example code: + *

      +     *   char[] data = new char[1024];
      +     *   Reader in = null;
      +     *   try {
      +     *       in = new FileReader("foo.txt");
      +     *       in.read(data);
      +     *       in.close(); //close errors are handled
      +     *   } catch (Exception e) {
      +     *       // error handling
      +     *   } finally {
      +     *       IOUtils.closeQuietly(in);
      +     *   }
      +     * 
      + * + * @param input the Reader to close, may be null or already closed + */ + public static void closeQuietly(Reader input) { + closeQuietly((Closeable)input); + } + + /** + * Unconditionally close a Writer. + *

      + * Equivalent to {@link Writer#close()}, except any exceptions will be ignored. + * This is typically used in finally blocks. + *

      + * Example code: + *

      +     *   Writer out = null;
      +     *   try {
      +     *       out = new StringWriter();
      +     *       out.write("Hello World");
      +     *       out.close(); //close errors are handled
      +     *   } catch (Exception e) {
      +     *       // error handling
      +     *   } finally {
      +     *       IOUtils.closeQuietly(out);
      +     *   }
      +     * 
      + * + * @param output the Writer to close, may be null or already closed + */ + public static void closeQuietly(Writer output) { + closeQuietly((Closeable)output); + } + + /** + * Unconditionally close an InputStream. + *

      + * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. + * This is typically used in finally blocks. + *

      + * Example code: + *

      +     *   byte[] data = new byte[1024];
      +     *   InputStream in = null;
      +     *   try {
      +     *       in = new FileInputStream("foo.txt");
      +     *       in.read(data);
      +     *       in.close(); //close errors are handled
      +     *   } catch (Exception e) {
      +     *       // error handling
      +     *   } finally {
      +     *       IOUtils.closeQuietly(in);
      +     *   }
      +     * 
      + * + * @param input the InputStream to close, may be null or already closed + */ + public static void closeQuietly(InputStream input) { + closeQuietly((Closeable)input); + } + + /** + * Unconditionally close an OutputStream. + *

      + * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. + * This is typically used in finally blocks. + *

      + * Example code: + *

      +     * byte[] data = "Hello, World".getBytes();
      +     *
      +     * OutputStream out = null;
      +     * try {
      +     *     out = new FileOutputStream("foo.txt");
      +     *     out.write(data);
      +     *     out.close(); //close errors are handled
      +     * } catch (IOException e) {
      +     *     // error handling
      +     * } finally {
      +     *     IOUtils.closeQuietly(out);
      +     * }
      +     * 
      + * + * @param output the OutputStream to close, may be null or already closed + */ + public static void closeQuietly(OutputStream output) { + closeQuietly((Closeable)output); + } + + /** + * Unconditionally close a Closeable. + *

      + * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. + * This is typically used in finally blocks. + *

      + * Example code: + *

      +     *   Closeable closeable = null;
      +     *   try {
      +     *       closeable = new FileReader("foo.txt");
      +     *       // process closeable
      +     *       closeable.close();
      +     *   } catch (Exception e) {
      +     *       // error handling
      +     *   } finally {
      +     *       IOUtils.closeQuietly(closeable);
      +     *   }
      +     * 
      + * + * @param closeable the object to close, may be null or already closed + * @since 2.0 + */ + public static void closeQuietly(Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (IOException ioe) { + // ignore + } + } + + /** + * Unconditionally close a Socket. + *

      + * Equivalent to {@link Socket#close()}, except any exceptions will be ignored. + * This is typically used in finally blocks. + *

      + * Example code: + *

      +     *   Socket socket = null;
      +     *   try {
      +     *       socket = new Socket("http://www.foo.com/", 80);
      +     *       // process socket
      +     *       socket.close();
      +     *   } catch (Exception e) {
      +     *       // error handling
      +     *   } finally {
      +     *       IOUtils.closeQuietly(socket);
      +     *   }
      +     * 
      + * + * @param sock the Socket to close, may be null or already closed + * @since 2.0 + */ + public static void closeQuietly(Socket sock){ + if (sock != null){ + try { + sock.close(); + } catch (IOException ioe) { + // ignored + } + } + } + + /** + * Unconditionally close a Selector. + *

      + * Equivalent to {@link Selector#close()}, except any exceptions will be ignored. + * This is typically used in finally blocks. + *

      + * Example code: + *

      +     *   Selector selector = null;
      +     *   try {
      +     *       selector = Selector.open();
      +     *       // process socket
      +     *       
      +     *   } catch (Exception e) {
      +     *       // error handling
      +     *   } finally {
      +     *       IOUtils.closeQuietly(selector);
      +     *   }
      +     * 
      + * + * @param selector the Selector to close, may be null or already closed + * @since 2.2 + */ + public static void closeQuietly(Selector selector){ + if (selector != null){ + try { + selector.close(); + } catch (IOException ioe) { + // ignored + } + } + } + + /** + * Unconditionally close a ServerSocket. + *

      + * Equivalent to {@link ServerSocket#close()}, except any exceptions will be ignored. + * This is typically used in finally blocks. + *

      + * Example code: + *

      +     *   ServerSocket socket = null;
      +     *   try {
      +     *       socket = new ServerSocket();
      +     *       // process socket
      +     *       socket.close();
      +     *   } catch (Exception e) {
      +     *       // error handling
      +     *   } finally {
      +     *       IOUtils.closeQuietly(socket);
      +     *   }
      +     * 
      + * + * @param sock the ServerSocket to close, may be null or already closed + * @since 2.2 + */ + public static void closeQuietly(ServerSocket sock){ + if (sock != null){ + try { + sock.close(); + } catch (IOException ioe) { + // ignored + } + } + } + + /** + * Fetches entire contents of an InputStream and represent + * same data as result InputStream. + *

      + * This method is useful where, + *

        + *
      • Source InputStream is slow.
      • + *
      • It has network resources associated, so we cannot keep it open for + * long time.
      • + *
      • It has network timeout associated.
      • + *
      + * It can be used in favor of {@link #toByteArray(InputStream)}, since it + * avoids unnecessary allocation and copy of byte[].
      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param input Stream to be fully buffered. + * @return A fully buffered stream. + * @throws IOException if an I/O error occurs + * @since 2.0 + */ + public static InputStream toBufferedInputStream(InputStream input) throws IOException { + return ByteArrayOutputStream.toBufferedInputStream(input); + } + + /** + * Returns the given reader if it is a {@link BufferedReader}, otherwise creates a toBufferedReader for the given + * reader. + * + * @param reader + * the reader to wrap or return + * @return the given reader or a new {@link BufferedReader} for the given reader + * @since 2.2 + */ + public static BufferedReader toBufferedReader(Reader reader) { + return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader); + } + + // read toByteArray + //----------------------------------------------------------------------- + /** + * Get the contents of an InputStream as a byte[]. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param input the InputStream to read from + * @return the requested byte array + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + */ + public static byte[] toByteArray(InputStream input) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + copy(input, output); + return output.toByteArray(); + } + + /** + * Get contents of an InputStream as a byte[]. + * Use this method instead of toByteArray(InputStream) + * when InputStream size is known. + * NOTE: the method checks that the length can safely be cast to an int without truncation + * before using {@link IOUtils#toByteArray(java.io.InputStream, int)} to read into the byte array. + * (Arrays can have no more than Integer.MAX_VALUE entries anyway) + * + * @param input the InputStream to read from + * @param size the size of InputStream + * @return the requested byte array + * @throws IOException if an I/O error occurs or InputStream size differ from parameter size + * @throws IllegalArgumentException if size is less than zero or size is greater than Integer.MAX_VALUE + * @see IOUtils#toByteArray(java.io.InputStream, int) + * @since 2.1 + */ + public static byte[] toByteArray(InputStream input, long size) throws IOException { + + if(size > Integer.MAX_VALUE) { + throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + size); + } + + return toByteArray(input, (int) size); + } + + /** + * Get the contents of an InputStream as a byte[]. + * Use this method instead of toByteArray(InputStream) + * when InputStream size is known + * @param input the InputStream to read from + * @param size the size of InputStream + * @return the requested byte array + * @throws IOException if an I/O error occurs or InputStream size differ from parameter size + * @throws IllegalArgumentException if size is less than zero + * @since 2.1 + */ + public static byte[] toByteArray(InputStream input, int size) throws IOException { + + if (size < 0) { + throw new IllegalArgumentException("Size must be equal or greater than zero: " + size); + } + + if (size == 0) { + return new byte[0]; + } + + byte[] data = new byte[size]; + int offset = 0; + int readed; + + while (offset < size && (readed = input.read(data, offset, size - offset)) != EOF) { + offset += readed; + } + + if (offset != size) { + throw new IOException("Unexpected readed size. current: " + offset + ", excepted: " + size); + } + + return data; + } + + /** + * Get the contents of a Reader as a byte[] + * using the default character encoding of the platform. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + * + * @param input the Reader to read from + * @return the requested byte array + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + */ + public static byte[] toByteArray(Reader input) throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + copy(input, output); + return output.toByteArray(); + } + + /** + * Get the contents of a Reader as a byte[] + * using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + * + * @param input the Reader to read from + * @param encoding the encoding to use, null means platform default + * @return the requested byte array + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static byte[] toByteArray(Reader input, String encoding) + throws IOException { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + copy(input, output, encoding); + return output.toByteArray(); + } + + /** + * Get the contents of a String as a byte[] + * using the default character encoding of the platform. + *

      + * This is the same as {@link String#getBytes()}. + * + * @param input the String to convert + * @return the requested byte array + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs (never occurs) + * @deprecated Use {@link String#getBytes()} + */ + @Deprecated + public static byte[] toByteArray(String input) throws IOException { + return input.getBytes(); + } + + // read char[] + //----------------------------------------------------------------------- + /** + * Get the contents of an InputStream as a character array + * using the default character encoding of the platform. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param is the InputStream to read from + * @return the requested character array + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static char[] toCharArray(InputStream is) throws IOException { + CharArrayWriter output = new CharArrayWriter(); + copy(is, output); + return output.toCharArray(); + } + + /** + * Get the contents of an InputStream as a character array + * using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param is the InputStream to read from + * @param encoding the encoding to use, null means platform default + * @return the requested character array + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static char[] toCharArray(InputStream is, String encoding) + throws IOException { + CharArrayWriter output = new CharArrayWriter(); + copy(is, output, encoding); + return output.toCharArray(); + } + + /** + * Get the contents of a Reader as a character array. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + * + * @param input the Reader to read from + * @return the requested character array + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static char[] toCharArray(Reader input) throws IOException { + CharArrayWriter sw = new CharArrayWriter(); + copy(input, sw); + return sw.toCharArray(); + } + + // read toString + //----------------------------------------------------------------------- + /** + * Get the contents of an InputStream as a String + * using the default character encoding of the platform. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param input the InputStream to read from + * @return the requested String + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + */ + public static String toString(InputStream input) throws IOException { + return toString(input, null); + } + + /** + * Get the contents of an InputStream as a String + * using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param input the InputStream to read from + * @param encoding the encoding to use, null means platform default + * @return the requested String + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + */ + public static String toString(InputStream input, String encoding) + throws IOException { + StringBuilderWriter sw = new StringBuilderWriter(); + copy(input, sw, encoding); + return sw.toString(); + } + + /** + * Get the contents of a Reader as a String. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + * + * @param input the Reader to read from + * @return the requested String + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + */ + public static String toString(Reader input) throws IOException { + StringBuilderWriter sw = new StringBuilderWriter(); + copy(input, sw); + return sw.toString(); + } + + /** + * Gets the contents at the given URI. + * + * @param uri + * The URI source. + * @return The contents of the URL as a String. + * @throws IOException if an I/O exception occurs. + * @since 2.1. + */ + public static String toString(URI uri) throws IOException { + return toString(uri, null); + } + + /** + * Gets the contents at the given URI. + * + * @param uri + * The URI source. + * @param encoding + * The encoding name for the URL contents. + * @return The contents of the URL as a String. + * @throws IOException if an I/O exception occurs. + * @since 2.1. + */ + public static String toString(URI uri, String encoding) throws IOException { + return toString(uri.toURL(), encoding); + } + + /** + * Gets the contents at the given URL. + * + * @param url + * The URL source. + * @return The contents of the URL as a String. + * @throws IOException if an I/O exception occurs. + * @since 2.1. + */ + public static String toString(URL url) throws IOException { + return toString(url, null); + } + + /** + * Gets the contents at the given URL. + * + * @param url + * The URL source. + * @param encoding + * The encoding name for the URL contents. + * @return The contents of the URL as a String. + * @throws IOException if an I/O exception occurs. + * @since 2.1. + */ + public static String toString(URL url, String encoding) throws IOException { + InputStream inputStream = url.openStream(); + try { + return toString(inputStream, encoding); + } finally { + inputStream.close(); + } + } + + /** + * Get the contents of a byte[] as a String + * using the default character encoding of the platform. + * + * @param input the byte array to read from + * @return the requested String + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs (never occurs) + * @deprecated Use {@link String#String(byte[])} + */ + @Deprecated + public static String toString(byte[] input) throws IOException { + return new String(input); + } + + /** + * Get the contents of a byte[] as a String + * using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + * + * @param input the byte array to read from + * @param encoding the encoding to use, null means platform default + * @return the requested String + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs (never occurs) + * @deprecated Use {@link String#String(byte[],String)} + */ + @Deprecated + public static String toString(byte[] input, String encoding) + throws IOException { + if (encoding == null) { + return new String(input); + } else { + return new String(input, encoding); + } + } + + // readLines + //----------------------------------------------------------------------- + /** + * Get the contents of an InputStream as a list of Strings, + * one entry per line, using the default character encoding of the platform. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param input the InputStream to read from, not null + * @return the list of Strings, never null + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static List readLines(InputStream input) throws IOException { + InputStreamReader reader = new InputStreamReader(input); + return readLines(reader); + } + + /** + * Get the contents of an InputStream as a list of Strings, + * one entry per line, using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + * + * @param input the InputStream to read from, not null + * @param encoding the encoding to use, null means platform default + * @return the list of Strings, never null + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static List readLines(InputStream input, String encoding) throws IOException { + if (encoding == null) { + return readLines(input); + } else { + InputStreamReader reader = new InputStreamReader(input, encoding); + return readLines(reader); + } + } + + /** + * Get the contents of a Reader as a list of Strings, + * one entry per line. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + * + * @param input the Reader to read from, not null + * @return the list of Strings, never null + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static List readLines(Reader input) throws IOException { + BufferedReader reader = toBufferedReader(input); + List list = new ArrayList(); + String line = reader.readLine(); + while (line != null) { + list.add(line); + line = reader.readLine(); + } + return list; + } + + // lineIterator + //----------------------------------------------------------------------- + /** + * Return an Iterator for the lines in a Reader. + *

      + * LineIterator holds a reference to the open + * Reader specified here. When you have finished with the + * iterator you should close the reader to free internal resources. + * This can be done by closing the reader directly, or by calling + * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}. + *

      + * The recommended usage pattern is: + *

      +     * try {
      +     *   LineIterator it = IOUtils.lineIterator(reader);
      +     *   while (it.hasNext()) {
      +     *     String line = it.nextLine();
      +     *     /// do something with line
      +     *   }
      +     * } finally {
      +     *   IOUtils.closeQuietly(reader);
      +     * }
      +     * 
      + * + * @param reader the Reader to read from, not null + * @return an Iterator of the lines in the reader, never null + * @throws IllegalArgumentException if the reader is null + * @since 1.2 + */ + /*public static LineIterator lineIterator(Reader reader) { + return new LineIterator(reader); + }*/ + + /** + * Return an Iterator for the lines in an InputStream, using + * the character encoding specified (or default encoding if null). + *

      + * LineIterator holds a reference to the open + * InputStream specified here. When you have finished with + * the iterator you should close the stream to free internal resources. + * This can be done by closing the stream directly, or by calling + * {@link LineIterator#close()} or {@link LineIterator#closeQuietly(LineIterator)}. + *

      + * The recommended usage pattern is: + *

      +     * try {
      +     *   LineIterator it = IOUtils.lineIterator(stream, "UTF-8");
      +     *   while (it.hasNext()) {
      +     *     String line = it.nextLine();
      +     *     /// do something with line
      +     *   }
      +     * } finally {
      +     *   IOUtils.closeQuietly(stream);
      +     * }
      +     * 
      + * + * @param input the InputStream to read from, not null + * @param encoding the encoding to use, null means platform default + * @return an Iterator of the lines in the reader, never null + * @throws IllegalArgumentException if the input is null + * @throws IOException if an I/O error occurs, such as if the encoding is invalid + * @since 1.2 + */ + /*public static LineIterator lineIterator(InputStream input, String encoding) + throws IOException { + Reader reader = null; + if (encoding == null) { + reader = new InputStreamReader(input); + } else { + reader = new InputStreamReader(input, encoding); + } + return new LineIterator(reader); + }*/ + + //----------------------------------------------------------------------- + /** + * Convert the specified CharSequence to an input stream, encoded as bytes + * using the default character encoding of the platform. + * + * @param input the CharSequence to convert + * @return an input stream + * @since 2.0 + */ + public static InputStream toInputStream(CharSequence input) { + return toInputStream(input.toString()); + } + + /** + * Convert the specified CharSequence to an input stream, encoded as bytes + * using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + * + * @param input the CharSequence to convert + * @param encoding the encoding to use, null means platform default + * @throws IOException if the encoding is invalid + * @return an input stream + * @since 2.0 + */ + public static InputStream toInputStream(CharSequence input, String encoding) throws IOException { + return toInputStream(input.toString(), encoding); + } + + //----------------------------------------------------------------------- + /** + * Convert the specified string to an input stream, encoded as bytes + * using the default character encoding of the platform. + * + * @param input the string to convert + * @return an input stream + * @since 1.1 + */ + public static InputStream toInputStream(String input) { + byte[] bytes = input.getBytes(); + return new ByteArrayInputStream(bytes); + } + + /** + * Convert the specified string to an input stream, encoded as bytes + * using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + * + * @param input the string to convert + * @param encoding the encoding to use, null means platform default + * @throws IOException if the encoding is invalid + * @return an input stream + * @since 1.1 + */ + public static InputStream toInputStream(String input, String encoding) throws IOException { + byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes(); + return new ByteArrayInputStream(bytes); + } + + // write byte[] + //----------------------------------------------------------------------- + /** + * Writes bytes from a byte[] to an OutputStream. + * + * @param data the byte array to write, do not modify during output, + * null ignored + * @param output the OutputStream to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(byte[] data, OutputStream output) + throws IOException { + if (data != null) { + output.write(data); + } + } + + /** + * Writes bytes from a byte[] to chars on a Writer + * using the default character encoding of the platform. + *

      + * This method uses {@link String#String(byte[])}. + * + * @param data the byte array to write, do not modify during output, + * null ignored + * @param output the Writer to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(byte[] data, Writer output) throws IOException { + if (data != null) { + output.write(new String(data)); + } + } + + /** + * Writes bytes from a byte[] to chars on a Writer + * using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method uses {@link String#String(byte[], String)}. + * + * @param data the byte array to write, do not modify during output, + * null ignored + * @param output the Writer to write to + * @param encoding the encoding to use, null means platform default + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(byte[] data, Writer output, String encoding) + throws IOException { + if (data != null) { + if (encoding == null) { + write(data, output); + } else { + output.write(new String(data, encoding)); + } + } + } + + // write char[] + //----------------------------------------------------------------------- + /** + * Writes chars from a char[] to a Writer + * using the default character encoding of the platform. + * + * @param data the char array to write, do not modify during output, + * null ignored + * @param output the Writer to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(char[] data, Writer output) throws IOException { + if (data != null) { + output.write(data); + } + } + + /** + * Writes chars from a char[] to bytes on an + * OutputStream. + *

      + * This method uses {@link String#String(char[])} and + * {@link String#getBytes()}. + * + * @param data the char array to write, do not modify during output, + * null ignored + * @param output the OutputStream to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(char[] data, OutputStream output) + throws IOException { + if (data != null) { + output.write(new String(data).getBytes()); + } + } + + /** + * Writes chars from a char[] to bytes on an + * OutputStream using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method uses {@link String#String(char[])} and + * {@link String#getBytes(String)}. + * + * @param data the char array to write, do not modify during output, + * null ignored + * @param output the OutputStream to write to + * @param encoding the encoding to use, null means platform default + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(char[] data, OutputStream output, String encoding) + throws IOException { + if (data != null) { + if (encoding == null) { + write(data, output); + } else { + output.write(new String(data).getBytes(encoding)); + } + } + } + + // write CharSequence + //----------------------------------------------------------------------- + /** + * Writes chars from a CharSequence to a Writer. + * + * @param data the CharSequence to write, null ignored + * @param output the Writer to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 2.0 + */ + public static void write(CharSequence data, Writer output) throws IOException { + if (data != null) { + write(data.toString(), output); + } + } + + /** + * Writes chars from a CharSequence to bytes on an + * OutputStream using the default character encoding of the + * platform. + *

      + * This method uses {@link String#getBytes()}. + * + * @param data the CharSequence to write, null ignored + * @param output the OutputStream to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 2.0 + */ + public static void write(CharSequence data, OutputStream output) + throws IOException { + if (data != null) { + write(data.toString(), output); + } + } + + /** + * Writes chars from a CharSequence to bytes on an + * OutputStream using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method uses {@link String#getBytes(String)}. + * + * @param data the CharSequence to write, null ignored + * @param output the OutputStream to write to + * @param encoding the encoding to use, null means platform default + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 2.0 + */ + public static void write(CharSequence data, OutputStream output, String encoding) + throws IOException { + if (data != null) { + write(data.toString(), output, encoding); + } + } + + // write String + //----------------------------------------------------------------------- + /** + * Writes chars from a String to a Writer. + * + * @param data the String to write, null ignored + * @param output the Writer to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(String data, Writer output) throws IOException { + if (data != null) { + output.write(data); + } + } + + /** + * Writes chars from a String to bytes on an + * OutputStream using the default character encoding of the + * platform. + *

      + * This method uses {@link String#getBytes()}. + * + * @param data the String to write, null ignored + * @param output the OutputStream to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(String data, OutputStream output) + throws IOException { + if (data != null) { + output.write(data.getBytes()); + } + } + + /** + * Writes chars from a String to bytes on an + * OutputStream using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method uses {@link String#getBytes(String)}. + * + * @param data the String to write, null ignored + * @param output the OutputStream to write to + * @param encoding the encoding to use, null means platform default + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void write(String data, OutputStream output, String encoding) + throws IOException { + if (data != null) { + if (encoding == null) { + write(data, output); + } else { + output.write(data.getBytes(encoding)); + } + } + } + + // write StringBuffer + //----------------------------------------------------------------------- + /** + * Writes chars from a StringBuffer to a Writer. + * + * @param data the StringBuffer to write, null ignored + * @param output the Writer to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + * @deprecated replaced by write(CharSequence, Writer) + */ + @Deprecated + public static void write(StringBuffer data, Writer output) + throws IOException { + if (data != null) { + output.write(data.toString()); + } + } + + /** + * Writes chars from a StringBuffer to bytes on an + * OutputStream using the default character encoding of the + * platform. + *

      + * This method uses {@link String#getBytes()}. + * + * @param data the StringBuffer to write, null ignored + * @param output the OutputStream to write to + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + * @deprecated replaced by write(CharSequence, OutputStream) + */ + @Deprecated + public static void write(StringBuffer data, OutputStream output) + throws IOException { + if (data != null) { + output.write(data.toString().getBytes()); + } + } + + /** + * Writes chars from a StringBuffer to bytes on an + * OutputStream using the specified character encoding. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method uses {@link String#getBytes(String)}. + * + * @param data the StringBuffer to write, null ignored + * @param output the OutputStream to write to + * @param encoding the encoding to use, null means platform default + * @throws NullPointerException if output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + * @deprecated replaced by write(CharSequence, OutputStream, String) + */ + @Deprecated + public static void write(StringBuffer data, OutputStream output, + String encoding) throws IOException { + if (data != null) { + if (encoding == null) { + write(data, output); + } else { + output.write(data.toString().getBytes(encoding)); + } + } + } + + // writeLines + //----------------------------------------------------------------------- + /** + * Writes the toString() value of each item in a collection to + * an OutputStream line by line, using the default character + * encoding of the platform and the specified line ending. + * + * @param lines the lines to write, null entries produce blank lines + * @param lineEnding the line separator to use, null is system default + * @param output the OutputStream to write to, not null, not closed + * @throws NullPointerException if the output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void writeLines(Collection lines, String lineEnding, + OutputStream output) throws IOException { + if (lines == null) { + return; + } + if (lineEnding == null) { + lineEnding = LINE_SEPARATOR; + } + for (Object line : lines) { + if (line != null) { + output.write(line.toString().getBytes()); + } + output.write(lineEnding.getBytes()); + } + } + + /** + * Writes the toString() value of each item in a collection to + * an OutputStream line by line, using the specified character + * encoding and the specified line ending. + *

      + * Character encoding names can be found at + * IANA. + * + * @param lines the lines to write, null entries produce blank lines + * @param lineEnding the line separator to use, null is system default + * @param output the OutputStream to write to, not null, not closed + * @param encoding the encoding to use, null means platform default + * @throws NullPointerException if the output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void writeLines(Collection lines, String lineEnding, + OutputStream output, String encoding) throws IOException { + if (encoding == null) { + writeLines(lines, lineEnding, output); + } else { + if (lines == null) { + return; + } + if (lineEnding == null) { + lineEnding = LINE_SEPARATOR; + } + for (Object line : lines) { + if (line != null) { + output.write(line.toString().getBytes(encoding)); + } + output.write(lineEnding.getBytes(encoding)); + } + } + } + + /** + * Writes the toString() value of each item in a collection to + * a Writer line by line, using the specified line ending. + * + * @param lines the lines to write, null entries produce blank lines + * @param lineEnding the line separator to use, null is system default + * @param writer the Writer to write to, not null, not closed + * @throws NullPointerException if the input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void writeLines(Collection lines, String lineEnding, + Writer writer) throws IOException { + if (lines == null) { + return; + } + if (lineEnding == null) { + lineEnding = LINE_SEPARATOR; + } + for (Object line : lines) { + if (line != null) { + writer.write(line.toString()); + } + writer.write(lineEnding); + } + } + + // copy from File + //----------------------------------------------------------------------- + /** + * Copy bytes from one File to another File. + * Directory files are copied recursively. + *

      + * Large files (over 2GB) will return a bytes copied value of + * -1 after the copy has completed since the correct number of + * bytes cannot be returned as an int. For large files use the + * copyLarge(InputStream, OutputStream) method. + * + * @param input + * the File to read from + * @param output + * the File to write to + * @param forceOverwrite + * pass true to force existing files to be + * overwritten regardless; otherwise, a file will only be + * overwritten if it is older than the file being copied. + * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE + * @throws NullPointerException + * if the input or output is null + * @throws IOException + * if an I/O error occurs + * @since 1.1 + */ + public static int copy(File input, File output, boolean forceOverwrite) throws IOException { + long count = copyLarge(input, output, forceOverwrite); + if (count > Integer.MAX_VALUE) { + return -1; + } + return (int) count; + } + + // copy from InputStream + //----------------------------------------------------------------------- + /** + * Copy bytes from an InputStream to an + * OutputStream. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

      + * Large streams (over 2GB) will return a bytes copied value of + * -1 after the copy has completed since the correct + * number of bytes cannot be returned as an int. For large streams + * use the copyLarge(InputStream, OutputStream) method. + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static int copy(InputStream input, OutputStream output) throws IOException { + long count = copyLarge(input, output); + if (count > Integer.MAX_VALUE) { + return -1; + } + return (int) count; + } + + /** + * Copy bytes from one large (over 2GB) File to another + * File. Directory files are copied recursively. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

      + * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. + * + * @param input + * the File to read from + * @param output + * the File to write to + * @param forceOverwrite + * pass true to force existing files to be + * overwritten regardless; otherwise, a file will only be + * overwritten if it is older than the file being copied. + * @return the number of bytes copied + * @throws NullPointerException + * if the input or output is null + * @throws IOException + * if an I/O error occurs + * @since 1.3 + */ + public static long copyLarge(File input, File output, boolean forceOverwrite) throws IOException { + if (input.isDirectory()) { + if (!output.exists()) + output.mkdirs(); + else if (!output.isDirectory()) + throw new IOException(output.getCanonicalPath() + " already exists but is not a directory"); + long count = 0L; + for (File child : input.listFiles()) { + count += copyLarge(child, new File(output, child.getName()), forceOverwrite); + } + return count; + } else if (input.lastModified() > output.lastModified() || forceOverwrite) { + if (!output.getParentFile().exists()) + output.getParentFile().mkdirs(); + FileInputStream inStream = new FileInputStream(input); + FileOutputStream outStream = new FileOutputStream(output); + try { + return copyLarge(inStream, outStream); + } finally { + closeQuietly(inStream); + closeQuietly(outStream); + } + } else { + return input.length(); + } + } + + /** + * Copy bytes from a large (over 2GB) InputStream to an + * OutputStream. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

      + * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.3 + */ + public static long copyLarge(InputStream input, OutputStream output) + throws IOException { + return copyLarge(input, output, new byte[DEFAULT_BUFFER_SIZE]); + } + + /** + * Copy bytes from a large (over 2GB) InputStream to an + * OutputStream. + *

      + * This method uses the provided buffer, so there is no need to use a + * BufferedInputStream. + *

      + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @param buffer the buffer to use for the copy + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + public static long copyLarge(InputStream input, OutputStream output, byte[] buffer) + throws IOException { + long count = 0; + int n = 0; + while (EOF != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } + + /** + * Copy some or all bytes from a large (over 2GB) InputStream to an + * OutputStream, optionally skipping input bytes. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

      + * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @param inputOffset : number of bytes to skip from input before copying + * -ve values are ignored + * @param length : number of bytes to copy. -ve means all + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + public static long copyLarge(InputStream input, OutputStream output, long inputOffset, long length) + throws IOException { + return copyLarge(input, output, inputOffset, length, new byte[DEFAULT_BUFFER_SIZE]); + } + + /** + * Copy some or all bytes from a large (over 2GB) InputStream to an + * OutputStream, optionally skipping input bytes. + *

      + * This method uses the provided buffer, so there is no need to use a + * BufferedInputStream. + *

      + * + * @param input the InputStream to read from + * @param output the OutputStream to write to + * @param inputOffset : number of bytes to skip from input before copying + * -ve values are ignored + * @param length : number of bytes to copy. -ve means all + * @param buffer the buffer to use for the copy + * + * @return the number of bytes copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + public static long copyLarge(InputStream input, OutputStream output, + final long inputOffset, final long length, byte[] buffer) throws IOException { + if (inputOffset > 0) { + skipFully(input, inputOffset); + } + if (length == 0) { + return 0; + } + final int bufferLength = buffer.length; + int bytesToRead = bufferLength; + if (length > 0 && length < bufferLength) { + bytesToRead = (int) length; + } + int read; + long totalRead = 0; + while (bytesToRead > 0 && EOF != (read = input.read(buffer, 0, bytesToRead))) { + output.write(buffer, 0, read); + totalRead += read; + if (length > 0) { // only adjust length if not reading to the end + // Note the cast must work because buffer.length is an integer + bytesToRead = (int) Math.min(length - totalRead, bufferLength); + } + } + return totalRead; + } + + /** + * Copy bytes from an InputStream to chars on a + * Writer using the default character encoding of the platform. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

      + * This method uses {@link InputStreamReader}. + * + * @param input the InputStream to read from + * @param output the Writer to write to + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void copy(InputStream input, Writer output) + throws IOException { + InputStreamReader in = new InputStreamReader(input); + copy(in, output); + } + + /** + * Copy bytes from an InputStream to chars on a + * Writer using the specified character encoding. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedInputStream. + *

      + * Character encoding names can be found at + * IANA. + *

      + * This method uses {@link InputStreamReader}. + * + * @param input the InputStream to read from + * @param output the Writer to write to + * @param encoding the encoding to use, null means platform default + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void copy(InputStream input, Writer output, String encoding) + throws IOException { + if (encoding == null) { + copy(input, output); + } else { + InputStreamReader in = new InputStreamReader(input, encoding); + copy(in, output); + } + } + + // copy from Reader + //----------------------------------------------------------------------- + /** + * Copy chars from a Reader to a Writer. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + *

      + * Large streams (over 2GB) will return a chars copied value of + * -1 after the copy has completed since the correct + * number of chars cannot be returned as an int. For large streams + * use the copyLarge(Reader, Writer) method. + * + * @param input the Reader to read from + * @param output the Writer to write to + * @return the number of characters copied, or -1 if > Integer.MAX_VALUE + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static int copy(Reader input, Writer output) throws IOException { + long count = copyLarge(input, output); + if (count > Integer.MAX_VALUE) { + return -1; + } + return (int) count; + } + + /** + * Copy chars from a large (over 2GB) Reader to a Writer. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + *

      + * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. + * + * @param input the Reader to read from + * @param output the Writer to write to + * @return the number of characters copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.3 + */ + public static long copyLarge(Reader input, Writer output) throws IOException { + return copyLarge(input, output, new char[DEFAULT_BUFFER_SIZE]); + } + + /** + * Copy chars from a large (over 2GB) Reader to a Writer. + *

      + * This method uses the provided buffer, so there is no need to use a + * BufferedReader. + *

      + * + * @param input the Reader to read from + * @param output the Writer to write to + * @param buffer the buffer to be used for the copy + * @return the number of characters copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + public static long copyLarge(Reader input, Writer output, char [] buffer) throws IOException { + long count = 0; + int n = 0; + while (EOF != (n = input.read(buffer))) { + output.write(buffer, 0, n); + count += n; + } + return count; + } + + /** + * Copy some or all chars from a large (over 2GB) InputStream to an + * OutputStream, optionally skipping input chars. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + *

      + * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. + * + * @param input the Reader to read from + * @param output the Writer to write to + * @param inputOffset : number of chars to skip from input before copying + * -ve values are ignored + * @param length : number of chars to copy. -ve means all + * @return the number of chars copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + public static long copyLarge(Reader input, Writer output, final long inputOffset, final long length) + throws IOException { + return copyLarge(input, output, inputOffset, length, new char[DEFAULT_BUFFER_SIZE]); + } + + /** + * Copy some or all chars from a large (over 2GB) InputStream to an + * OutputStream, optionally skipping input chars. + *

      + * This method uses the provided buffer, so there is no need to use a + * BufferedReader. + *

      + * + * @param input the Reader to read from + * @param output the Writer to write to + * @param inputOffset : number of chars to skip from input before copying + * -ve values are ignored + * @param length : number of chars to copy. -ve means all + * @param buffer the buffer to be used for the copy + * @return the number of chars copied + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + public static long copyLarge(Reader input, Writer output, final long inputOffset, final long length, char [] buffer) + throws IOException { + if (inputOffset > 0) { + skipFully(input, inputOffset); + } + if (length == 0) { + return 0; + } + int bytesToRead = buffer.length; + if (length > 0 && length < buffer.length) { + bytesToRead = (int) length; + } + int read; + long totalRead = 0; + while (bytesToRead > 0 && EOF != (read = input.read(buffer, 0, bytesToRead))) { + output.write(buffer, 0, read); + totalRead += read; + if (length > 0) { // only adjust length if not reading to the end + // Note the cast must work because buffer.length is an integer + bytesToRead = (int) Math.min(length - totalRead, buffer.length); + } + } + return totalRead; + } + + /** + * Copy chars from a Reader to bytes on an + * OutputStream using the default character encoding of the + * platform, and calling flush. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + *

      + * Due to the implementation of OutputStreamWriter, this method performs a + * flush. + *

      + * This method uses {@link OutputStreamWriter}. + * + * @param input the Reader to read from + * @param output the OutputStream to write to + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void copy(Reader input, OutputStream output) + throws IOException { + OutputStreamWriter out = new OutputStreamWriter(output); + copy(input, out); + // XXX Unless anyone is planning on rewriting OutputStreamWriter, we + // have to flush here. + out.flush(); + } + + /** + * Copy chars from a Reader to bytes on an + * OutputStream using the specified character encoding, and + * calling flush. + *

      + * This method buffers the input internally, so there is no need to use a + * BufferedReader. + *

      + * Character encoding names can be found at + * IANA. + *

      + * Due to the implementation of OutputStreamWriter, this method performs a + * flush. + *

      + * This method uses {@link OutputStreamWriter}. + * + * @param input the Reader to read from + * @param output the OutputStream to write to + * @param encoding the encoding to use, null means platform default + * @throws NullPointerException if the input or output is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static void copy(Reader input, OutputStream output, String encoding) + throws IOException { + if (encoding == null) { + copy(input, output); + } else { + OutputStreamWriter out = new OutputStreamWriter(output, encoding); + copy(input, out); + // XXX Unless anyone is planning on rewriting OutputStreamWriter, + // we have to flush here. + out.flush(); + } + } + + // content equals + //----------------------------------------------------------------------- + /** + * Compare the contents of two Streams to determine if they are equal or + * not. + *

      + * This method buffers the input internally using + * BufferedInputStream if they are not already buffered. + * + * @param input1 the first stream + * @param input2 the second stream + * @return true if the content of the streams are equal or they both don't + * exist, false otherwise + * @throws NullPointerException if either input is null + * @throws IOException if an I/O error occurs + */ + public static boolean contentEquals(InputStream input1, InputStream input2) + throws IOException { + if (!(input1 instanceof BufferedInputStream)) { + input1 = new BufferedInputStream(input1); + } + if (!(input2 instanceof BufferedInputStream)) { + input2 = new BufferedInputStream(input2); + } + + int ch = input1.read(); + while (EOF != ch) { + int ch2 = input2.read(); + if (ch != ch2) { + return false; + } + ch = input1.read(); + } + + int ch2 = input2.read(); + return ch2 == EOF; + } + + /** + * Compare the contents of two Readers to determine if they are equal or + * not. + *

      + * This method buffers the input internally using + * BufferedReader if they are not already buffered. + * + * @param input1 the first reader + * @param input2 the second reader + * @return true if the content of the readers are equal or they both don't + * exist, false otherwise + * @throws NullPointerException if either input is null + * @throws IOException if an I/O error occurs + * @since 1.1 + */ + public static boolean contentEquals(Reader input1, Reader input2) + throws IOException { + + input1 = toBufferedReader(input1); + input2 = toBufferedReader(input2); + + int ch = input1.read(); + while (EOF != ch) { + int ch2 = input2.read(); + if (ch != ch2) { + return false; + } + ch = input1.read(); + } + + int ch2 = input2.read(); + return ch2 == EOF; + } + + /** + * Compare the contents of two Readers to determine if they are equal or + * not, ignoring EOL characters. + *

      + * This method buffers the input internally using + * BufferedReader if they are not already buffered. + * + * @param input1 the first reader + * @param input2 the second reader + * @return true if the content of the readers are equal (ignoring EOL differences), false otherwise + * @throws NullPointerException if either input is null + * @throws IOException if an I/O error occurs + * @since 2.2 + */ + public static boolean contentEqualsIgnoreEOL(Reader input1, Reader input2) + throws IOException { + BufferedReader br1 = toBufferedReader(input1); + BufferedReader br2 = toBufferedReader(input2); + + String line1 = br1.readLine(); + String line2 = br2.readLine(); + while (line1 != null && line2 != null && line1.equals(line2)) { + line1 = br1.readLine(); + line2 = br2.readLine(); + } + return line1 == null ? line2 == null ? true : false : line1.equals(line2); + } + + /** + * Skip bytes from an input byte stream. + * This implementation guarantees that it will read as many bytes + * as possible before giving up; this may not always be the case for + * subclasses of {@link Reader}. + * + * @param input byte stream to skip + * @param toSkip number of bytes to skip. + * @return number of bytes actually skipped. + * + * @see InputStream#skip(long) + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if toSkip is negative + * @since 2.0 + */ + public static long skip(InputStream input, long toSkip) throws IOException { + if (toSkip < 0) { + throw new IllegalArgumentException("Skip count must be non-negative, actual: " + toSkip); + } + /* + * N.B. no need to synchronize this because: - we don't care if the buffer is created multiple times (the data + * is ignored) - we always use the same size buffer, so if it it is recreated it will still be OK (if the buffer + * size were variable, we would need to synch. to ensure some other thread did not create a smaller one) + */ + if (SKIP_BYTE_BUFFER == null) { + SKIP_BYTE_BUFFER = new byte[SKIP_BUFFER_SIZE]; + } + long remain = toSkip; + while (remain > 0) { + long n = input.read(SKIP_BYTE_BUFFER, 0, (int) Math.min(remain, SKIP_BUFFER_SIZE)); + if (n < 0) { // EOF + break; + } + remain -= n; + } + return toSkip - remain; + } + + /** + * Skip characters from an input character stream. + * This implementation guarantees that it will read as many characters + * as possible before giving up; this may not always be the case for + * subclasses of {@link Reader}. + * + * @param input character stream to skip + * @param toSkip number of characters to skip. + * @return number of characters actually skipped. + * + * @see Reader#skip(long) + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if toSkip is negative + * @since 2.0 + */ + public static long skip(Reader input, long toSkip) throws IOException { + if (toSkip < 0) { + throw new IllegalArgumentException("Skip count must be non-negative, actual: " + toSkip); + } + /* + * N.B. no need to synchronize this because: - we don't care if the buffer is created multiple times (the data + * is ignored) - we always use the same size buffer, so if it it is recreated it will still be OK (if the buffer + * size were variable, we would need to synch. to ensure some other thread did not create a smaller one) + */ + if (SKIP_CHAR_BUFFER == null) { + SKIP_CHAR_BUFFER = new char[SKIP_BUFFER_SIZE]; + } + long remain = toSkip; + while (remain > 0) { + long n = input.read(SKIP_CHAR_BUFFER, 0, (int) Math.min(remain, SKIP_BUFFER_SIZE)); + if (n < 0) { // EOF + break; + } + remain -= n; + } + return toSkip - remain; + } + + /** + * Skip the requested number of bytes or fail if there are not enough left. + *

      + * This allows for the possibility that {@link InputStream#skip(long)} may + * not skip as many bytes as requested (most likely because of reaching EOF). + * + * @param input stream to skip + * @param toSkip the number of bytes to skip + * @see InputStream#skip(long) + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if toSkip is negative + * @throws EOFException if the number of bytes skipped was incorrect + * @since 2.0 + */ + public static void skipFully(InputStream input, long toSkip) throws IOException { + if (toSkip < 0) { + throw new IllegalArgumentException("Bytes to skip must not be negative: " + toSkip); + } + long skipped = skip(input, toSkip); + if (skipped != toSkip) { + throw new EOFException("Bytes to skip: " + toSkip + " actual: " + skipped); + } + } + + /** + * Skip the requested number of characters or fail if there are not enough left. + *

      + * This allows for the possibility that {@link Reader#skip(long)} may + * not skip as many characters as requested (most likely because of reaching EOF). + * + * @param input stream to skip + * @param toSkip the number of characters to skip + * @see Reader#skip(long) + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if toSkip is negative + * @throws EOFException if the number of characters skipped was incorrect + * @since 2.0 + */ + public static void skipFully(Reader input, long toSkip) throws IOException { + long skipped = skip(input, toSkip); + if (skipped != toSkip) { + throw new EOFException("Chars to skip: " + toSkip + " actual: " + skipped); + } + } + + + /** + * Read characters from an input character stream. + * This implementation guarantees that it will read as many characters + * as possible before giving up; this may not always be the case for + * subclasses of {@link Reader}. + * + * @param input where to read input from + * @param buffer destination + * @param offset inital offset into buffer + * @param length length to read, must be >= 0 + * @return actual length read; may be less than requested if EOF was reached + * @throws IOException if a read error occurs + * @since 2.2 + */ + public static int read(Reader input, char[] buffer, int offset, int length) throws IOException { + if (length < 0) { + throw new IllegalArgumentException("Length must not be negative: " + length); + } + int remaining = length; + while (remaining > 0) { + int location = length - remaining; + int count = input.read(buffer, offset + location, remaining); + if (EOF == count) { // EOF + break; + } + remaining -= count; + } + return length - remaining; + } + + /** + * Read characters from an input character stream. + * This implementation guarantees that it will read as many characters + * as possible before giving up; this may not always be the case for + * subclasses of {@link Reader}. + * + * @param input where to read input from + * @param buffer destination + * @return actual length read; may be less than requested if EOF was reached + * @throws IOException if a read error occurs + * @since 2.2 + */ + public static int read(Reader input, char[] buffer) throws IOException { + return read(input, buffer, 0, buffer.length); + } + + /** + * Read bytes from an input stream. + * This implementation guarantees that it will read as many bytes + * as possible before giving up; this may not always be the case for + * subclasses of {@link InputStream}. + * + * @param input where to read input from + * @param buffer destination + * @param offset inital offset into buffer + * @param length length to read, must be >= 0 + * @return actual length read; may be less than requested if EOF was reached + * @throws IOException if a read error occurs + * @since 2.2 + */ + public static int read(InputStream input, byte[] buffer, int offset, int length) throws IOException { + if (length < 0) { + throw new IllegalArgumentException("Length must not be negative: " + length); + } + int remaining = length; + while (remaining > 0) { + int location = length - remaining; + int count = input.read(buffer, offset + location, remaining); + if (EOF == count) { // EOF + break; + } + remaining -= count; + } + return length - remaining; + } + + /** + * Read bytes from an input stream. + * This implementation guarantees that it will read as many bytes + * as possible before giving up; this may not always be the case for + * subclasses of {@link InputStream}. + * + * @param input where to read input from + * @param buffer destination + * @return actual length read; may be less than requested if EOF was reached + * @throws IOException if a read error occurs + * @since 2.2 + */ + public static int read(InputStream input, byte[] buffer) throws IOException { + return read(input, buffer, 0, buffer.length); + } + + /** + * Read the requested number of characters or fail if there are not enough left. + *

      + * This allows for the possibility that {@link Reader#read(char[], int, int)} may + * not read as many characters as requested (most likely because of reaching EOF). + * + * @param input where to read input from + * @param buffer destination + * @param offset inital offset into buffer + * @param length length to read, must be >= 0 + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if length is negative + * @throws EOFException if the number of characters read was incorrect + * @since 2.2 + */ + public static void readFully(Reader input, char[] buffer, int offset, int length) throws IOException { + int actual = read(input, buffer, offset, length); + if (actual != length) { + throw new EOFException("Length to read: " + length + " actual: " + actual); + } + } + + /** + * Read the requested number of characters or fail if there are not enough left. + *

      + * This allows for the possibility that {@link Reader#read(char[], int, int)} may + * not read as many characters as requested (most likely because of reaching EOF). + * + * @param input where to read input from + * @param buffer destination + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if length is negative + * @throws EOFException if the number of characters read was incorrect + * @since 2.2 + */ + public static void readFully(Reader input, char[] buffer) throws IOException { + readFully(input, buffer, 0, buffer.length); + } + + /** + * Read the requested number of bytes or fail if there are not enough left. + *

      + * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may + * not read as many bytes as requested (most likely because of reaching EOF). + * + * @param input where to read input from + * @param buffer destination + * @param offset inital offset into buffer + * @param length length to read, must be >= 0 + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if length is negative + * @throws EOFException if the number of bytes read was incorrect + * @since 2.2 + */ + public static void readFully(InputStream input, byte[] buffer, int offset, int length) throws IOException { + int actual = read(input, buffer, offset, length); + if (actual != length) { + throw new EOFException("Length to read: " + length + " actual: " + actual); + } + } + + /** + * Read the requested number of bytes or fail if there are not enough left. + *

      + * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may + * not read as many bytes as requested (most likely because of reaching EOF). + * + * @param input where to read input from + * @param buffer destination + * + * @throws IOException if there is a problem reading the file + * @throws IllegalArgumentException if length is negative + * @throws EOFException if the number of bytes read was incorrect + * @since 2.2 + */ + public static void readFully(InputStream input, byte[] buffer) throws IOException { + readFully(input, buffer, 0, buffer.length); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/JsonHelper.java b/typescript.java-ts.core/src/main/java/ts/utils/JsonHelper.java new file mode 100644 index 000000000..59385f4b7 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/JsonHelper.java @@ -0,0 +1,31 @@ +package ts.utils; + +import com.eclipsesource.json.JsonArray; +import com.eclipsesource.json.JsonObject; +import com.eclipsesource.json.JsonValue; + +public class JsonHelper { + + public static JsonArray toJson(String[] arr) { + JsonArray json = new JsonArray(); + for (int i = 0; i < arr.length; i++) { + json.add(arr[i]); + } + return json; + } + + public static JsonArray getArray(JsonObject obj, String name) { + JsonValue value = obj.get(name); + return value != null ? value.asArray() : null; + } + + public static Integer getInteger(JsonObject obj, String name) { + JsonValue value = obj.get(name); + return value != null ? value.asInt() : null; + } + + public static Boolean getBoolean(JsonObject obj, String name) { + JsonValue value = obj.get(name); + return value != null ? value.asBoolean() : null; + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/ProcessHelper.java b/typescript.java-ts.core/src/main/java/ts/utils/ProcessHelper.java new file mode 100644 index 000000000..df55b9945 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/ProcessHelper.java @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2016-2017 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +import ts.OS; + +/** + * Helper for Process. + * + */ +public class ProcessHelper { + + private static final String PATH_ENV = "PATH"; + + /** + * Returns the given filename location. + * + * @param fileName + * @param os + * @param extension + * @return the given filename location + */ + public static File findLocation(String fileName, OS os, String extension) { + String fileNameWithExt = extension == null ? fileName : fileName + extension; + String path = System.getenv(PATH_ENV); + String[] paths = path.split("" + File.pathSeparatorChar, 0); + List directories = new ArrayList(); + for (String p : paths) { + directories.add(p); + } + + // ensure /usr/local/bin is included for OS X + if (os == OS.MacOS) { + directories.add("/usr/local/bin"); + } + + // search for filename in the PATH directories + for (String directory : directories) { + File file = new File(directory, fileNameWithExt); + + if (file.exists()) { + return file; + } + } + return which(fileName, os); + } + + /** + * Returns the given filename location by using command "which $filename". + * + * @param fileName + * file name to search. + * @param os + * the OS. + * @return the given filename location by using command "which $filename". + */ + public static File which(String fileName, OS os) { + String[] command = whichCommand(fileName, os); + BufferedReader reader = null; + try { + Process p = Runtime.getRuntime().exec(command); + reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + String foundFile = reader.readLine(); + if (StringUtils.isEmpty(foundFile)) { + return null; + } + File f = new File(foundFile); + return f.exists() ? f : null; + } catch (IOException e) { + return null; + } finally { + IOUtils.closeQuietly(reader); + } + } + + private static String[] whichCommand(String fileName, OS os) { + return getCommand("where " + fileName, os); + } + + public static String[] getCommand(String command, OS os) { + File defaultShell = defaultShell(os); + String image = defaultShell.isAbsolute() ? defaultShell.getAbsolutePath() : defaultShell.getPath(); + if (os == OS.Windows) { + return new String[] { image, "/c", command }; + } + return new String[] { image, "-c", command }; + } + + /** + * Returns the default shell to launch. Looks at the environment variable + * "SHELL" first before assuming some default default values. + * + * @return The default shell to launch. + */ + private static final File defaultShell(OS os) { + String shell = null; + if (os == OS.Windows) { + if (System.getenv("ComSpec") != null && !"".equals(System.getenv("ComSpec").trim())) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + shell = System.getenv("ComSpec").trim(); //$NON-NLS-1$ + } else { + shell = "cmd.exe"; //$NON-NLS-1$ + } + } + if (StringUtils.isEmpty(shell)) { + if (System.getenv("SHELL") != null && !"".equals(System.getenv("SHELL").trim())) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + shell = System.getenv("SHELL").trim(); //$NON-NLS-1$ + } else { + shell = "/bin/sh"; //$NON-NLS-1$ + } + } + return new File(shell); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/StringUtils.java b/typescript.java-ts.core/src/main/java/ts/utils/StringUtils.java new file mode 100644 index 000000000..1cdd2177d --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/StringUtils.java @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2015-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.utils; + +/** + * String utilities. + * + */ +public class StringUtils { + + public static final String[] EMPTY_STRING = new String[0]; + + /** + * Represents a failed index search. + */ + public static final int INDEX_NOT_FOUND = -1; + + private static final int NOT_FOUND = -1; + + public static int countMatches(final CharSequence str, final CharSequence sub) { + if (isEmpty(str) || isEmpty(sub)) { + return 0; + } + int count = 0; + int idx = 0; + while ((idx = indexOf(str, sub, idx)) != INDEX_NOT_FOUND) { + count++; + idx += sub.length(); + } + return count; + } + + static int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) { + return cs.toString().indexOf(searchChar.toString(), start); + } + + static int indexOf(final CharSequence cs, final int searchChar, int start) { + if (cs instanceof String) { + return ((String) cs).indexOf(searchChar, start); + } + final int sz = cs.length(); + if (start < 0) { + start = 0; + } + for (int i = start; i < sz; i++) { + if (cs.charAt(i) == searchChar) { + return i; + } + } + return NOT_FOUND; + } + + public static boolean isEmpty(final CharSequence cs) { + return cs == null || cs.length() == 0; + } + + public static String normalizeSpace(String s) { + if (s == null) { + return null; + } + int len = s.length(); + if (len < 1) { + return ""; + } + int st = 0; + int off = 0; /* avoid getfield opcode */ + char[] val = s.toCharArray(); /* avoid getfield opcode */ + int count = s.length(); + + boolean parse = true; + char c; + while (parse) { + c = val[off + st]; + parse = isParse(len, st, c); + if (parse) { + st++; + } + } + parse = true; + while ((st < len) && (val[off + len - 1] <= ' ')) { + c = val[off + len - 1]; + parse = isParse(len, st, c); + if (parse) { + len--; + } + } + return ((st > 0) || (len < count)) ? s.substring(st, len) : s; + } + + private static boolean isParse(int len, int st, char c) { + return (st < len) && (c == ' ' || c == '\r' || c == '\n' || c == '\t'); + } + +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/TypeScriptHelper.java b/typescript.java-ts.core/src/main/java/ts/utils/TypeScriptHelper.java new file mode 100644 index 000000000..d229d4802 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/TypeScriptHelper.java @@ -0,0 +1,72 @@ +package ts.utils; + +import java.util.List; + +import ts.client.completions.SymbolDisplayPart; + +public class TypeScriptHelper { + + /** + * Returns the TypeScript prefix completion for the given position of the + * given content. + * + * @param contents + * @param position + * @return the TypeScript prefix completion for the given position of the + * given content. + */ + public static String getPrefix(String contents, int position) { + StringBuilder prefix = null; + int i = position - 1; + while (i >= 0) { + char c = contents.charAt(i); + if (!Character.isJavaIdentifierPart(c)) { + break; + } else { + if (prefix == null) { + prefix = new StringBuilder(); + } + prefix.insert(0, c); + } + i--; + } + return prefix != null ? prefix.toString() : null; + } + + public static String text(List parts, boolean withPre) { + if (parts == null || parts.size() < 1) { + return null; + } + StringBuilder html = new StringBuilder(withPre ? "

      " : "");
      +		for (SymbolDisplayPart part : parts) {
      +			html.append(part.getText());
      +		}
      +		if (withPre) {
      +			html.append("
      "); + } + return html.toString(); + } + + public static String extractFunctionParameters(List parts) { + if (parts == null || parts.size() < 1) { + return null; + } + StringBuilder information = new StringBuilder(""); + boolean hasParam = false; + for (SymbolDisplayPart part : parts) { + if (part.isParameterName()) { + information.append(part.getText()); + hasParam = true; + } else if (hasParam) { + if (")".equals(part.getText())) { + // end of parameters declaration + break; + } else { + information.append(part.getText()); + } + } + } + information.append(""); + return information.toString(); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/VersionHelper.java b/typescript.java-ts.core/src/main/java/ts/utils/VersionHelper.java new file mode 100644 index 000000000..daf180396 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/VersionHelper.java @@ -0,0 +1,56 @@ +package ts.utils; + +public class VersionHelper { + + public static boolean canSupport(String version, String sinceVersion) { + if(version == null) { + return false; + } + if (sinceVersion == null) { + return true; + } + return versionCompare(version, sinceVersion) >= 0; + } + + /** + * Compares two version strings. + * + * Use this instead of String.compareTo() for a non-lexicographical + * comparison that works for version strings. e.g. "1.10".compareTo("1.6"). + * + * @note It does not work if "1.10" is supposed to be equal to "1.10.0". + * + * @param str1 + * a string of ordinal numbers separated by decimal points. + * @param str2 + * a string of ordinal numbers separated by decimal points. + * @return The result is a negative integer if str1 is _numerically_ less + * than str2. The result is a positive integer if str1 is + * _numerically_ greater than str2. The result is zero if the + * strings are _numerically_ equal. + */ + public static int versionCompare(String str1, String str2) { + String[] vals1 = str1.split("\\."); + String[] vals2 = str2.split("\\."); + int i = 0; + // set index to first non-equal ordinal or length of shortest version + // string + while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) { + i++; + } + // compare first non-equal ordinal number + if (i < vals1.length && i < vals2.length) { + String v = vals1[i]; + int index = v.indexOf('-'); + if (index > -1) { + // ex : 1-insiders + v = v.substring(0, index); + } + int diff = Integer.valueOf(v).compareTo(Integer.valueOf(vals2[i])); + return Integer.signum(diff); + } + // the strings are equal or one string is a substring of the other + // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4" + return Integer.signum(vals1.length - vals2.length); + } +} diff --git a/typescript.java-ts.core/src/main/java/ts/utils/ZipUtils.java b/typescript.java-ts.core/src/main/java/ts/utils/ZipUtils.java new file mode 100644 index 000000000..9ee737492 --- /dev/null +++ b/typescript.java-ts.core/src/main/java/ts/utils/ZipUtils.java @@ -0,0 +1,254 @@ +/** + * Copyright (c) 2013-2016 Angelo ZERR. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr - initial API and implementation + */ +package ts.utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.zip.GZIPInputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.tukaani.xz.XZInputStream; + +import ts.internal.io.tar.TarEntry; +import ts.internal.io.tar.TarException; +import ts.internal.io.tar.TarInputStream; + +/** + * Zip, tar.gz Utilities. + * + */ +public class ZipUtils { + + public static final String ZIP_EXTENSION = ".zip"; + public static final String TAR_GZ_EXTENSION = ".tar.gz"; + public static final String TAR_XZ_EXTENSION = ".tar.xz"; + private static final String BIN_FOLDER = "/bin"; + + private ZipUtils() { + } + + /** + * Returns true if the given file is a zip file and false otherwise. + * + * @param file + * @return true if the given file is a zip file and false otherwise. + */ + public static boolean isZipFile(File file) { + return file.isFile() && file.getName().toLowerCase().endsWith(ZIP_EXTENSION); + } + + /** + * Returns true if the given file is a tar.gz file and false otherwise. + * + * @param file + * @return true if the given file is a tar.gz file and false otherwise. + */ + public static boolean isTarGZFile(File file) { + return file.isFile() && file.getName().toLowerCase().endsWith(TAR_GZ_EXTENSION); + } + + /** + * Returns true if the given file is a tar.xz file and false otherwise. + * + * @param file + * @return true if the given file is a tar.xz file and false otherwise. + */ + public static boolean isTarXZFile(File file) { + return file.isFile() && file.getName().toLowerCase().endsWith(TAR_XZ_EXTENSION); + } + + /** + * Extract zip file to destination folder. + * + * @param file + * zip file to extract + * @param destination + * destination folder + */ + public static void extractZip(File file, File destination) throws IOException { + ZipInputStream in = null; + OutputStream out = null; + try { + // Open the ZIP file + in = new ZipInputStream(new FileInputStream(file)); + + // Get the first entry + ZipEntry entry = null; + + while ((entry = in.getNextEntry()) != null) { + String outFilename = entry.getName(); + + // Open the output file + File extracted = new File(destination, outFilename); + if (entry.isDirectory()) { + extracted.mkdirs(); + } else { + // Be sure that parent file exists + File baseDir = extracted.getParentFile(); + if (!baseDir.exists()) { + baseDir.mkdirs(); + } + + out = new FileOutputStream(extracted); + + // Transfer bytes from the ZIP file to the output file + byte[] buf = new byte[1024]; + int len; + + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + + // Close the stream + out.close(); + // Preserve original modification date + extracted.setLastModified(entry.getTime()); + if (extracted.getParent().contains(BIN_FOLDER)) { + extracted.setExecutable(true); + } + } + } + } finally { + // Close the stream + if (in != null) { + in.close(); + } + if (out != null) { + out.close(); + } + } + } + + /** + * Extract tar.gz file to destination folder. + * + * @param file + * zip file to extract + * @param destination + * destination folder + */ + public static void extractTarGZ(File file, File destination) throws IOException { + extractTar(file, destination, true); + } + + /** + * Extract tar.xz file to destination folder. + * + * @param file + * zip file to extract + * @param destination + * destination folder + */ + public static void extractTarXZ(File file, File destination) throws IOException { + extractTar(file, destination, false); + } + + /** + * Extract tar.gz/tar.xz file to destination folder. + * + * @param file + * zip file to extract + * @param destination + * destination folder + */ + private static void extractTar(File file, File destination, boolean tarGz) throws IOException { + TarInputStream in = null; + OutputStream out = null; + try { + // Open the ZIP file + in = new TarInputStream(tarGz ? new GZIPInputStream(new FileInputStream(file)) + : new XZInputStream(new FileInputStream(file))); + + // Get the first entry + TarEntry entry = null; + + while ((entry = in.getNextEntry()) != null) { + String outFilename = entry.getName(); + + switch (entry.getFileType()) { + case TarEntry.DIRECTORY: + File extractedDir = new File(destination, outFilename); + if (extractedDir.isDirectory()) { + extractedDir.mkdirs(); + } + break; + case TarEntry.FILE: + File extractedFile = new File(destination, outFilename); + // Be sure that parent file exists + File baseDir = extractedFile.getParentFile(); + if (!baseDir.exists()) { + baseDir.mkdirs(); + } + + out = new FileOutputStream(extractedFile); + + // Transfer bytes from the ZIP file to the output file + byte[] buf = new byte[1024]; + int len; + + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + + // Close the stream + out.close(); + // Preserve original modification date + extractedFile.setLastModified(entry.getTime()); + long mode = entry.getMode(); + if ((mode & 00100) > 0) { + // Preserve execute permissions + extractedFile.setExecutable(true, (mode & 00001) == 0); + } + break; + case TarEntry.LINK: + File linkFile = new File(destination, outFilename); + // Be sure that parent file exists + File linkBaseDir = linkFile.getParentFile(); + if (!linkBaseDir.exists()) { + linkBaseDir.mkdirs(); + } + Path target = Paths.get(entry.getLinkName()); + Files.createLink(linkFile.toPath(), target); + break; + case TarEntry.SYM_LINK: + File symLinkFile = new File(destination, outFilename); + // Be sure that parent file exists + File symLinkBaseDir = symLinkFile.getParentFile(); + if (!symLinkBaseDir.exists()) { + symLinkBaseDir.mkdirs(); + } + Path symTarget = Paths.get(entry.getLinkName()); + Files.createSymbolicLink(symLinkFile.toPath(), symTarget); + break; + } + } + } catch (TarException e) { + throw new IOException(e); + } finally { + // Close the stream + if (in != null) { + in.close(); + } + if (out != null) { + out.close(); + } + } + + } + +}