├── .gitignore ├── Makefile.in ├── README.md ├── configure ├── libs └── compiler.jar └── src ├── META-INF └── MANIFEST.MF ├── com ├── anychart │ └── gjstags │ │ ├── CommandLineRunner.java │ │ ├── builder │ │ ├── CTagsBuilder.java │ │ ├── CTagsEntry.java │ │ └── ITopLevelInfoProvider.java │ │ ├── ctags │ │ ├── CTag.java │ │ └── CTagsFile.java │ │ └── utils │ │ └── SourceCodeTraversal.java └── google │ └── javascript │ └── jscomp │ └── PublicNodeUtil.java └── gjstags /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | *.iml 4 | out/ 5 | Makefile 6 | bin/ 7 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | PREFIX=@prefix@ 2 | JAVAC=@javac@ 3 | JAR=@jar@ 4 | 5 | compile: 6 | mkdir -p classes 7 | mkdir -p bin 8 | $(JAVAC) -sourcepath src -classpath libs/compiler.jar -d classes src/com/anychart/gjstags/CommandLineRunner.java 9 | $(JAR) cvfm bin/gjstags.jar src/META-INF/MANIFEST.MF -C classes . 10 | rm -rf classes 11 | 12 | install: 13 | cp bin/gjstags $(PREFIX)/bin/gjstags 14 | cp bin/gjstags.jar $(PREFIX)/bin/gjstags.jar 15 | cp libs/compiler.jar $(PREFIX)/bin/compiler.jar 16 | chmod go+x $(PREFIX)/bin/gjstags 17 | chmod go+r $(PREFIX)/bin/gjstags.jar 18 | chmod go+r $(PREFIX)/bin/compiler.jar 19 | 20 | clean: 21 | rm -rf bin/* 22 | rm -rf classes/* 23 | rm -f Makefile 24 | rm -f $(PREFIX)/bin/gjstags 25 | rm -f $(PREFIX)/bin/gjstags.jar 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gjstags 2 | CTags generator for JavaScript. 3 | Licensed under Apache License 2.0. Based on Google Closure Compiler. 4 | Works under Mac OS X or Linux. 5 | 6 | ## Installation 7 | ### Cloning source: 8 | ``` 9 | git clone git://github.com/AnyChart/gjstags.git 10 | ``` 11 | ### Building: 12 | ``` 13 | ./configure 14 | make 15 | make install 16 | ``` 17 | 18 | #### ./configure arguments: 19 | `--prefix path` /usr/local by default 20 | `--with-javac javac` javac by default 21 | `--with-jar jar-path` jar by default 22 | 23 | 24 | ## Usage 25 | ``` 26 | gjstags [options] file(s) 27 | ``` 28 | see `gjstags --help` for more details. 29 | 30 | ## Uninstall 31 | ``` 32 | make clean 33 | ``` -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Copyright 2011 AnyChart.Com Team 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | 17 | PREFIX=/usr/local 18 | JAVAC=javac 19 | JAR=jar 20 | 21 | options=$@ 22 | arguments=$options 23 | index=0 24 | for argument in $options 25 | do 26 | # Incrementing index 27 | index=`expr $index + 1` 28 | 29 | # The conditions 30 | case $argument in 31 | --prefix) PREFIX=${arguments[index]} ;; 32 | --with-javac) JAVAC=${arguments[index]} ;; 33 | --with-jar) JAR=${arguments[index]} ;; 34 | esac 35 | done 36 | 37 | sed "\ 38 | s/@prefix@/$(echo $PREFIX | sed -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/&/\\\&/g')/g;\ 39 | s/@javac@/$(echo $JAVAC | sed -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/&/\\\&/g')/g;\ 40 | s/@jar@/$(echo $JAR | sed -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/&/\\\&/g')/g" Makefile.in > Makefile 41 | 42 | rm -rf bin 43 | mkdir bin 44 | sed s/@path@/$(echo $PREFIX | sed -e 's/\\/\\\\/g' -e 's/\//\\\//g' -e 's/&/\\\&/g')\\/bin/g src/gjstags > bin/gjstags 45 | chmod +x bin/gjstags 46 | -------------------------------------------------------------------------------- /libs/compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnyChart/gjstags/4a761962074be38c657fc4c42ab5f7806a34431a/libs/compiler.jar -------------------------------------------------------------------------------- /src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: com.anychart.gjstags.CommandLineRunner 3 | Class-Path: compiler.jar 4 | -------------------------------------------------------------------------------- /src/com/anychart/gjstags/CommandLineRunner.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 AnyChart.Com Team 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.anychart.gjstags; 17 | 18 | import com.anychart.gjstags.builder.CTagsBuilder; 19 | import com.anychart.gjstags.ctags.CTagsFile; 20 | 21 | import java.io.File; 22 | import java.io.IOException; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | * @author Aleksandr Batsuev (alex@batsuev.com) 28 | */ 29 | public class CommandLineRunner { 30 | 31 | public static final String VERSION = "1.2"; 32 | 33 | private static final String ERROR_NO_OUTPUT = "Error: No output file specified"; 34 | private static final String ERROR_NO_INPUT = "Error: No valid inputs specified"; 35 | 36 | private static final String LICENSE = "Copyright 2011 AnyChart.Com Team\n" + 37 | "\n" + 38 | "Licensed under the Apache License, Version 2.0 (the \"License\");\n" + 39 | "you may not use this file except in compliance with the License.\n" + 40 | "You may obtain a copy of the License at\n" + 41 | "\n" + 42 | " http://www.apache.org/licenses/LICENSE-2.0\n" + 43 | "\n" + 44 | "Unless required by applicable law or agreed to in writing, software\n" + 45 | "distributed under the License is distributed on an \"AS IS\" BASIS,\n" + 46 | "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + 47 | "See the License for the specific language governing permissions and\n" + 48 | "limitations under the License.\n"; 49 | 50 | private static final String HELP = "gjstags " + VERSION + ", Copyright (C) 2011 AnyChart.Com Team\n" + 51 | "Author: Aleksandr Batsuev (alex@batsuev.com)\n" + 52 | "\n" + 53 | "Usage: gjstags [options] [file(s)]\n" + 54 | "\n" + 55 | "Options:\n" + 56 | " -a Append the tags to an existing tag file. Disabled by default. \n" + 57 | " -f \n" + 58 | " Write tags to specified file. 'tags' by default.\n" + 59 | " -o Alias for -f\n" + 60 | " -r Find source files recursively.\n" + 61 | " -R alias for -r\n" + 62 | " -b base dir\n" + 63 | " --recursive Alias for -r\n" + 64 | " --basedir Alias for -b\n" + 65 | " --version Show version info.\n" + 66 | " --license Show license.\n" + 67 | " --help Show this help.\n"; 68 | 69 | public static void main(String[] args) throws IOException { 70 | 71 | if (args.length == 0) { 72 | System.out.print(HELP); 73 | return; 74 | } 75 | 76 | boolean isRecursive = false; 77 | String outputFile = "tags"; 78 | boolean appendTags = false; 79 | List inputs = new ArrayList(); 80 | String baseDir = null; 81 | 82 | for (int i = 0; i < args.length; i++) { 83 | String arg = args[i]; 84 | if (arg.equals("--help")) { 85 | System.out.print(HELP); 86 | return; 87 | } else if (arg.equals("--version")) { 88 | System.out.println("gjstags " + VERSION + ", Copyright (C) 2011 AnyChart.Com Team\n"); 89 | return; 90 | } else if (arg.equals("--license")) { 91 | System.out.print(LICENSE); 92 | } else if (arg.equals("-R") || arg.equals("-r") || arg.equals("--recursive")) { 93 | isRecursive = true; 94 | } else if (arg.equals("-f") || arg.equals("-o")) { 95 | if (i == (args.length - 1)) { 96 | System.out.println(ERROR_NO_OUTPUT); 97 | return; 98 | } 99 | outputFile = args[++i]; 100 | } else if (arg.equals("-a")) { 101 | appendTags = true; 102 | } else if (arg.equals("-b") || arg.equals("--basedir")) { 103 | if (i < (args.length - 1)) { 104 | baseDir = args[++i]; 105 | } 106 | } else { 107 | inputs.add(arg); 108 | } 109 | } 110 | 111 | ArrayList realInputFiles = new ArrayList(); 112 | 113 | if (isRecursive) { 114 | for (String input : inputs) { 115 | File f = new File(input); 116 | if (f.isDirectory()) { 117 | realInputFiles.addAll(getJSFilesFromDir(input)); 118 | } else if (f.isFile()) { 119 | realInputFiles.add(input); 120 | } 121 | } 122 | }else { 123 | for (String input : inputs) { 124 | File f = new File(input); 125 | if (f.isFile() && f.exists()) { 126 | realInputFiles.add(input); 127 | } 128 | } 129 | } 130 | 131 | if (realInputFiles.size() == 0) { 132 | System.out.println(ERROR_NO_INPUT); 133 | return; 134 | } 135 | 136 | 137 | CTagsBuilder cTagsBuilder = new CTagsBuilder(); 138 | cTagsBuilder.initAST(realInputFiles.toArray(new String[realInputFiles.size()])); 139 | cTagsBuilder.parseCTags(baseDir); 140 | 141 | CTagsFile file; 142 | if (appendTags && new File(outputFile).exists()) { 143 | file = CTagsFile.fromFile(outputFile); 144 | } else { 145 | file = new CTagsFile(); 146 | } 147 | 148 | file.update(cTagsBuilder.getTags()); 149 | file.write(outputFile); 150 | } 151 | 152 | private static List getJSFilesFromDir(String path) { 153 | List res = new ArrayList(); 154 | File dir = new File(path); 155 | for (File child : dir.listFiles()) { 156 | if (child.isDirectory()) { 157 | res.addAll(getJSFilesFromDir(child.getPath())); 158 | } else if (child.isFile()) { 159 | String childPath = child.getPath(); 160 | if (!childPath.contains(".")) continue; 161 | int index = childPath.lastIndexOf("."); 162 | String extension = childPath.substring(index); 163 | if (extension.toLowerCase().equals(".js")) { 164 | res.add(childPath); 165 | } 166 | } 167 | } 168 | return res; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/com/anychart/gjstags/builder/CTagsBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 AnyChart.Com Team 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.anychart.gjstags.builder; 17 | 18 | import com.anychart.gjstags.utils.SourceCodeTraversal; 19 | import com.google.common.collect.Lists; 20 | import com.google.javascript.jscomp.Compiler; 21 | import com.google.javascript.jscomp.*; 22 | import com.google.javascript.rhino.JSDocInfo; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import java.util.Map; 27 | 28 | /** 29 | * @author Aleksandr Batsuev (alex@batsuev.com) 30 | */ 31 | public class CTagsBuilder implements ITopLevelInfoProvider { 32 | 33 | private static Compiler compiler; 34 | private static CompilerOptions compilerOptions; 35 | 36 | private static void initCompiler() { 37 | compiler = new Compiler(); 38 | compilerOptions = new CompilerOptions(); 39 | compilerOptions.ideMode = true; 40 | compilerOptions.variableRenaming = VariableRenamingPolicy.OFF; 41 | } 42 | 43 | private SourceCodeTraversal sourceCodeTraversal; 44 | 45 | public CTagsBuilder() { 46 | if (CTagsBuilder.compiler == null) 47 | CTagsBuilder.initCompiler(); 48 | } 49 | 50 | public void initAST(String[] paths) { 51 | List sourceFiles = new ArrayList(); 52 | for (String path : paths) 53 | sourceFiles.add(JSSourceFile.fromFile(path)); 54 | 55 | compiler.compile(Lists.newArrayList(), sourceFiles, compilerOptions); 56 | 57 | sourceCodeTraversal = new SourceCodeTraversal(); 58 | NodeTraversal.traverse(compiler, compiler.getRoot(), sourceCodeTraversal); 59 | } 60 | 61 | private List tags; 62 | 63 | public CTagsEntry[] getTags() { 64 | return this.tags.toArray(new CTagsEntry[this.tags.size()]); 65 | } 66 | 67 | public void parseCTags(String baseDir) { 68 | this.classes = new ArrayList(); 69 | this.interfaces = new ArrayList(); 70 | this.enums = new ArrayList(); 71 | 72 | Map entries = sourceCodeTraversal.getEntries(); 73 | 74 | this.tags = new ArrayList(); 75 | 76 | //first of all - extract classes, enums, interfaces and generate ctags for them 77 | for (Map.Entry entry : entries.entrySet()) { 78 | this.checkTopLevelEntry(this.tags, entry.getKey(), entry.getValue()); 79 | } 80 | 81 | for (Map.Entry entry : entries.entrySet()) { 82 | if (entry.getValue().getValue() == null) continue; 83 | CTagsEntry.generateFromEntry(this.tags, this, entry.getKey(), entry.getValue(), baseDir); 84 | } 85 | } 86 | 87 | private List classes; 88 | private List interfaces; 89 | private List enums; 90 | 91 | public boolean isClass(String name) { 92 | return classes != null && classes.contains(name); 93 | } 94 | 95 | public boolean isInterface(String name) { 96 | return interfaces != null && interfaces.contains(name); 97 | } 98 | 99 | public boolean isEnum(String name) { 100 | return enums != null && enums.contains(name); 101 | } 102 | 103 | private void checkTopLevelEntry(List tags, String key, SourceCodeTraversal.SourceCodeEntry entry) { 104 | if (entry.getValue() == null || entry.getJsDocInfo() == null) return; 105 | 106 | JSDocInfo info = entry.getJsDocInfo(); 107 | 108 | if (info.isConstructor()) { 109 | classes.add(key); 110 | } else if (info.isInterface()) { 111 | interfaces.add(key); 112 | } else if (info.hasEnumParameterType()) { 113 | enums.add(key); 114 | } 115 | 116 | CTagsEntry.generateFromTopLevelEntry(tags, key, entry); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/com/anychart/gjstags/builder/CTagsEntry.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 AnyChart.Com Team 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.anychart.gjstags.builder; 17 | 18 | import com.anychart.gjstags.ctags.CTag; 19 | import com.anychart.gjstags.utils.SourceCodeTraversal; 20 | import com.google.javascript.jscomp.NodeUtil; 21 | import com.google.javascript.rhino.JSDocInfo; 22 | import com.google.javascript.rhino.Token; 23 | 24 | import java.io.File; 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | /** 29 | * @author Aleksandr Batsuev (alex@batsuev.com) 30 | */ 31 | public class CTagsEntry extends CTag { 32 | 33 | public enum CTagsEntryKind { 34 | CLASS, 35 | INTERFACE, 36 | ENUM, 37 | METHOD, 38 | PROPERTY, 39 | STATIC_METHOD, 40 | STATIC_PROPERTY, 41 | ENUM_ENTRY, 42 | DEFINE; 43 | 44 | public String toString() { 45 | switch (this) { 46 | case CLASS: 47 | return "c"; 48 | case INTERFACE: 49 | return "i"; 50 | case ENUM: 51 | return "g"; 52 | case METHOD: 53 | return "m"; 54 | case PROPERTY: 55 | return "f"; 56 | case STATIC_PROPERTY: 57 | return "f"; 58 | case STATIC_METHOD: 59 | return "p"; 60 | case ENUM_ENTRY: 61 | return "e"; 62 | case DEFINE: 63 | return "d"; 64 | } 65 | return null; 66 | } 67 | } 68 | 69 | private String packageName; 70 | private CTagsEntryKind kind; 71 | private String className; 72 | private String enumName; 73 | 74 | public String getMeta() { 75 | String meta = ";\""; 76 | if (this.kind != null) meta += "\tkind:" + this.kind.toString(); 77 | if (this.packageName != null) meta += "\tpackage:" + this.packageName; 78 | if (this.className != null) meta += "\tclass:" + this.className; 79 | if (this.enumName != null) meta += "\tenum:" + this.enumName; 80 | return meta; 81 | } 82 | 83 | public static void generateFromEntry(List tags, ITopLevelInfoProvider infoProvider, String name, SourceCodeTraversal.SourceCodeEntry entry, String baseDir) { 84 | 85 | CTagsEntryKind kind; 86 | String className = null; 87 | String enumName = null; 88 | String packageName = null; 89 | 90 | String fileName = NodeUtil.getSourceName(entry.getValue()); 91 | if (baseDir != null) { 92 | String absPath = new File(fileName).getAbsolutePath(); 93 | String absBaseDir = new File(baseDir).getAbsolutePath(); 94 | if (absPath.contains(absBaseDir)) { 95 | fileName = absPath.substring(absPath.indexOf(absBaseDir) + absBaseDir.length()+1); 96 | } 97 | } 98 | 99 | int lineNumber = entry.getValue().getLineno(); 100 | 101 | //class or interface method/prop 102 | if (name.contains(".prototype.") || name.contains(".__OBJLIT__.")) { 103 | if (name.contains(".prototype.")) { 104 | className = name.substring(0, name.indexOf(".prototype.")); 105 | } else { 106 | className = name.substring(0, name.indexOf(".__OBJLIT__.")); 107 | } 108 | packageName = getPackage(className); 109 | 110 | if (entry.getValue().getType() == Token.FUNCTION) 111 | kind = CTagsEntryKind.METHOD; 112 | else 113 | kind = CTagsEntryKind.PROPERTY; 114 | 115 | } else { 116 | JSDocInfo info = entry.getJsDocInfo(); 117 | if (info != null && 118 | (info.isConstructor() || 119 | info.isInterface() || 120 | info.hasEnumParameterType())) 121 | return; 122 | 123 | String containerName = getPackage(name); 124 | 125 | //enum entry 126 | if (infoProvider.isEnum(containerName)) { 127 | kind = CTagsEntryKind.ENUM_ENTRY; 128 | enumName = containerName; 129 | //class entry 130 | } else if (infoProvider.isClass(containerName)) { 131 | className = containerName; 132 | if (entry.getValue().getType() == Token.FUNCTION) 133 | kind = CTagsEntryKind.STATIC_METHOD; 134 | else 135 | kind = CTagsEntryKind.STATIC_PROPERTY; 136 | } else if (info != null && info.isDefine()) { 137 | kind = CTagsEntryKind.DEFINE; 138 | } else { 139 | //package static method or prop 140 | if (entry.getValue().getType() == Token.FUNCTION) 141 | kind = CTagsEntryKind.STATIC_METHOD; 142 | else 143 | kind = CTagsEntryKind.STATIC_PROPERTY; 144 | packageName = containerName; 145 | } 146 | } 147 | 148 | for (String tagName : getNameVariations(name)) { 149 | CTagsEntry tag = new CTagsEntry(); 150 | tag.file = fileName; 151 | tag.address = String.valueOf(lineNumber); 152 | tag.packageName = packageName; 153 | tag.className = className; 154 | tag.enumName = enumName; 155 | tag.kind = kind; 156 | tag.name = tagName; 157 | tags.add(tag); 158 | } 159 | } 160 | 161 | public static void generateFromTopLevelEntry(List tags, String name, SourceCodeTraversal.SourceCodeEntry entry) { 162 | JSDocInfo info = entry.getJsDocInfo(); 163 | if (info == null || entry.getValue() == null) return; 164 | 165 | CTagsEntryKind kind = null; 166 | if (info.isConstructor()) 167 | kind = CTagsEntryKind.CLASS; 168 | else if (info.isInterface()) 169 | kind = CTagsEntryKind.INTERFACE; 170 | else if (info.hasEnumParameterType()) 171 | kind = CTagsEntryKind.ENUM; 172 | 173 | if (kind == null) return; 174 | 175 | String fileName = NodeUtil.getSourceName(entry.getValue()); 176 | int lineNumber = entry.getValue().getLineno(); 177 | String packageName = getPackage(name); 178 | 179 | for (String tagName : getNameVariations(name)) { 180 | CTagsEntry tag = new CTagsEntry(); 181 | tag.file = fileName; 182 | tag.address = String.valueOf(lineNumber); 183 | tag.packageName = packageName; 184 | tag.kind = kind; 185 | tag.name = tagName; 186 | tags.add(tag); 187 | } 188 | } 189 | 190 | private static String getPackage(String name) { 191 | if (name.contains(".")) 192 | return name.substring(0, name.lastIndexOf(".")); 193 | return ""; 194 | } 195 | 196 | private static List getNameVariations(String name) { 197 | List res = new ArrayList(); 198 | 199 | name = name.replace("prototype.", ""); 200 | name = name.replace("__OBJDEF__.", ""); 201 | 202 | res.add(name); 203 | 204 | if (!name.contains(".")) return res; 205 | 206 | String packageName = name; 207 | int index = packageName.indexOf("."); 208 | while (packageName.contains(".")) { 209 | packageName = packageName.substring(index + 1); 210 | index = packageName.indexOf("."); 211 | if (!packageName.startsWith("prototype.") && 212 | !packageName.startsWith("__OBJDEF__.")) res.add(packageName); 213 | } 214 | 215 | return res; 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/com/anychart/gjstags/builder/ITopLevelInfoProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 AnyChart.Com Team 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.anychart.gjstags.builder; 17 | 18 | /** 19 | * @author Aleksandr Batsuev (alex@batsuev.com) 20 | */ 21 | public interface ITopLevelInfoProvider { 22 | public boolean isClass(String name); 23 | 24 | public boolean isInterface(String name); 25 | 26 | public boolean isEnum(String name); 27 | } 28 | -------------------------------------------------------------------------------- /src/com/anychart/gjstags/ctags/CTag.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 AnyChart.Com Team 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.anychart.gjstags.ctags; 17 | 18 | import java.io.Writer; 19 | import java.io.IOException; 20 | 21 | /** 22 | * @author Aleksandr Batsuev (alex@batsuev.com) 23 | */ 24 | public class CTag { 25 | protected String name; 26 | protected String file; 27 | protected String address; 28 | protected String meta; 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | 34 | public String getFile() { 35 | return file; 36 | } 37 | 38 | public String getAddress() { 39 | return address; 40 | } 41 | 42 | public String getMeta() { 43 | return meta; 44 | } 45 | 46 | public String getCTagString() { 47 | return this.getName() + "\t" + this.getFile() + "\t" + this.getAddress() + this.getMeta() + "\n"; 48 | } 49 | 50 | public void writeCTagString(Writer writer) throws IOException { 51 | writer.write(this.getName()); 52 | writer.write('\t'); 53 | writer.write(this.getFile()); 54 | writer.write('\t'); 55 | writer.write(this.getAddress()); 56 | writer.write(this.getMeta()); 57 | writer.write('\n'); 58 | } 59 | 60 | public static CTag fromString(String line) { 61 | 62 | String tag = line; 63 | String meta = ""; 64 | if (tag.contains(";\"\t")) { 65 | tag = line.substring(0, tag.indexOf(";\"\t")); 66 | meta = line.substring(tag.indexOf(";\"\t")); 67 | } 68 | 69 | String[] entries = tag.split("\t"); 70 | if (entries.length == 0) return null; 71 | String name = entries[0]; 72 | if (name.startsWith("!")) return null; 73 | String fileName = entries[1]; 74 | String address = entries[2]; 75 | 76 | CTag res = new CTag(); 77 | res.name = name; 78 | res.file = fileName; 79 | res.address = address; 80 | res.meta = meta; 81 | return res; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/com/anychart/gjstags/ctags/CTagsFile.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 AnyChart.Com Team 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.anychart.gjstags.ctags; 17 | 18 | import com.anychart.gjstags.CommandLineRunner; 19 | 20 | import java.io.BufferedReader; 21 | import java.io.BufferedWriter; 22 | import java.io.FileReader; 23 | import java.io.FileWriter; 24 | import java.io.IOException; 25 | import java.util.ArrayList; 26 | import java.util.Collections; 27 | import java.util.List; 28 | 29 | /** 30 | * @author Aleksandr Batsuev (alex@batsuev.com) 31 | */ 32 | public class CTagsFile { 33 | 34 | private static final String HEADER = 35 | "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/\n" + 36 | "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/\n" + 37 | "!_TAG_PROGRAM_AUTHOR\tAnyChart.Com Team\n" + 38 | "!_TAG_PROGRAM_NAME\tgjstags\t//\n" + 39 | "!_TAG_PROGRAM_URL\thttps://github.com/AnyChart/gjstags\t/official site/\n" + 40 | "!_TAG_PROGRAM_VERSION\t"+ CommandLineRunner.VERSION+"\t//\n"; 41 | 42 | private List entries; 43 | 44 | public CTagsFile() { 45 | this.entries = new ArrayList(); 46 | } 47 | 48 | public void update(CTag[] newEntries) { 49 | //remove all old entries with specific file names 50 | for (CTag tag : newEntries) { 51 | String fileName = tag.getFile(); 52 | for (CTag currentTag : this.entries) { 53 | if (currentTag.getFile().equals(fileName)) { 54 | this.entries.remove(currentTag); 55 | } 56 | } 57 | } 58 | 59 | Collections.addAll(this.entries, newEntries); 60 | } 61 | 62 | public void write(String fileName) throws IOException { 63 | BufferedWriter writer = new BufferedWriter(new FileWriter(fileName)); 64 | writer.write(HEADER); 65 | for (CTag tag : this.entries) { 66 | tag.writeCTagString(writer); 67 | } 68 | writer.close(); 69 | } 70 | 71 | public static CTagsFile fromFile(String fileName) throws IOException { 72 | CTagsFile file = new CTagsFile(); 73 | BufferedReader reader = new BufferedReader(new FileReader(fileName)); 74 | String line = reader.readLine(); 75 | while (line != null) { 76 | CTag tag = CTag.fromString(line); 77 | if (tag != null) 78 | file.entries.add(tag); 79 | line = reader.readLine(); 80 | } 81 | return file; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/com/anychart/gjstags/utils/SourceCodeTraversal.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 AnyChart.Com Team 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.anychart.gjstags.utils; 17 | 18 | import com.google.javascript.jscomp.Compiler; 19 | import com.google.javascript.jscomp.NodeTraversal; 20 | import com.google.javascript.jscomp.PublicNodeUtil; 21 | import com.google.javascript.rhino.JSDocInfo; 22 | import com.google.javascript.rhino.Node; 23 | import com.google.javascript.rhino.Token; 24 | 25 | import java.util.ArrayList; 26 | import java.util.HashMap; 27 | import java.util.List; 28 | import java.util.Map; 29 | 30 | /** 31 | * @author Aleksandr Batsuev (alex@batsuev.com) 32 | */ 33 | public class SourceCodeTraversal extends NodeTraversal.AbstractShallowCallback { 34 | 35 | private Compiler compiler; 36 | 37 | public Compiler getCompiler() { 38 | return this.compiler; 39 | } 40 | 41 | private Map entries; 42 | 43 | public Map getEntries() { 44 | return this.entries; 45 | } 46 | 47 | public List getEntries(String prefix) { 48 | List entries = new ArrayList(); 49 | 50 | for (SourceCodeEntry entry : this.entries.values()) { 51 | if (entry.getName().startsWith(prefix) && !entry.getName().equals(prefix)) 52 | entries.add(entry); 53 | } 54 | 55 | return entries; 56 | } 57 | 58 | private List classInheritanceInfos; 59 | 60 | public List getClassInheritanceInfos() { 61 | return this.classInheritanceInfos; 62 | } 63 | 64 | public SourceCodeTraversal() { 65 | this.entries = new HashMap(); 66 | this.classInheritanceInfos = new ArrayList(); 67 | } 68 | 69 | public void visit(NodeTraversal nodeTraversal, Node node, Node parent) { 70 | if (node.getType() != Token.SCRIPT) return; 71 | this.compiler = (Compiler) nodeTraversal.getCompiler(); 72 | 73 | for (Node child : node.children()) { 74 | if (child.getBooleanProp(Node.IS_NAMESPACE)) continue; 75 | 76 | switch (child.getType()) { 77 | case Token.VAR: 78 | this.visitVar(nodeTraversal, child, node); 79 | break; 80 | case Token.EXPR_RESULT: 81 | if (child.getFirstChild() == null) continue; 82 | if (child.getFirstChild().getType() == Token.ASSIGN) { 83 | this.visitAssign(nodeTraversal, child.getFirstChild(), child); 84 | } else if (child.getFirstChild().getType() == Token.CALL) { 85 | if (child.getFirstChild().getFirstChild().getType() == Token.GETPROP && 86 | child.getFirstChild().getFirstChild().isQualifiedName() && 87 | child.getFirstChild().getFirstChild().getQualifiedName().equals("goog.inherits")) { 88 | 89 | String className = child.getFirstChild().getChildAtIndex(1).getQualifiedName(); 90 | String baseClassName = child.getFirstChild().getLastChild().getQualifiedName(); 91 | 92 | classInheritanceInfos.add(new InheritanceInfo(baseClassName, className)); 93 | } 94 | } 95 | break; 96 | } 97 | } 98 | } 99 | 100 | private void visitAssign(NodeTraversal nodeTraversal, Node node, Node parent) { 101 | String name = node.getFirstChild().getQualifiedName(); 102 | if (name == null) return; 103 | Node assignValue = node.getLastChild(); 104 | this.visitValue(name, assignValue, node.getJSDocInfo()); 105 | } 106 | 107 | private void visitVar(NodeTraversal nodeTraversal, Node node, Node parent) { 108 | String name = node.getFirstChild().getString(); 109 | if (name == null) return; 110 | 111 | Node varValue = node.getFirstChild().getFirstChild(); 112 | this.visitValue(name, varValue, node.getJSDocInfo()); 113 | } 114 | 115 | private void visitValue(String name, Node valueNode, JSDocInfo info) { 116 | SourceCodeEntry entry = new SourceCodeEntry(name, valueNode, info); 117 | if (this.entries.containsKey(name)) 118 | this.entries.remove(this.entries.get(name)); 119 | 120 | this.entries.put(name, entry); 121 | 122 | if (valueNode != null) { 123 | if (valueNode.getType() == Token.OBJECTLIT) { 124 | if (name.contains(".DEFAULT_TEMPLATE")) return; //anychart-specific gag - ignore templates json 125 | 126 | for (Node child : valueNode.children()) { 127 | String childName = PublicNodeUtil.getObjectLitKeyName(child); 128 | this.visitValue(name + "." + childName, child.getFirstChild(), child.getJSDocInfo()); 129 | } 130 | } else if (valueNode.getType() == Token.FUNCTION) { 131 | Node body = PublicNodeUtil.getFunctionBody(valueNode); 132 | this.visitFunctionBody(name, body); 133 | } 134 | } 135 | } 136 | 137 | private void visitValueFromFunction(String functionName, String propName, Node valueNode, JSDocInfo info) { 138 | if (functionName.contains(".prototype.")) return; //ignore fields from prototype functions bodies 139 | propName = functionName + ".__OBJDEF__." + propName.substring("this.".length()); 140 | this.visitValue(propName, valueNode, info); 141 | } 142 | 143 | private void visitFunctionBody(String name, Node body) { 144 | if (name.contains(".__OBJDEF__.")) return; 145 | if (name.contains(".prototype.")) return; 146 | 147 | for (Node child : body.children()) { 148 | if (child.getType() != Token.EXPR_RESULT) continue; 149 | if (child.getFirstChild() == null) continue; 150 | if (child.getFirstChild().getType() != Token.ASSIGN) continue; 151 | if (!child.getFirstChild().getFirstChild().isQualifiedName()) continue; 152 | String targetName = child.getFirstChild().getFirstChild().getQualifiedName(); 153 | if (targetName.startsWith("this.")) { 154 | this.visitValueFromFunction(name, targetName, child.getFirstChild().getLastChild(), child.getJSDocInfo()); 155 | } 156 | } 157 | } 158 | 159 | public class SourceCodeEntry implements Comparable { 160 | private String name; 161 | private Node value; 162 | private JSDocInfo jsDocInfo; 163 | 164 | public String getName() { 165 | return this.name; 166 | } 167 | 168 | public Node getValue() { 169 | return this.value; 170 | } 171 | 172 | public JSDocInfo getJsDocInfo() { 173 | return this.jsDocInfo; 174 | } 175 | 176 | public SourceCodeEntry(String name, Node value, JSDocInfo jsDocInfo) { 177 | this.name = name; 178 | this.value = value; 179 | this.jsDocInfo = jsDocInfo; 180 | } 181 | 182 | public int compareTo(SourceCodeEntry sourceCodeEntry) { 183 | return sourceCodeEntry.name.compareTo(this.name); 184 | } 185 | } 186 | 187 | private class InheritanceInfo { 188 | private String baseName; 189 | 190 | public String getBaseName() { 191 | return this.baseName; 192 | } 193 | 194 | private String name; 195 | 196 | public String getName() { 197 | return this.name; 198 | } 199 | 200 | public InheritanceInfo(String baseName, String name) { 201 | this.baseName = baseName; 202 | this.name = name; 203 | } 204 | } 205 | } -------------------------------------------------------------------------------- /src/com/google/javascript/jscomp/PublicNodeUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 AnyChart.Com Team 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.google.javascript.jscomp; 17 | 18 | import com.google.javascript.rhino.Node; 19 | 20 | /** 21 | * @author Aleksandr Batsuev (alex@batsuev.com) 22 | * Proxy for com.google.javascript.jscomp.NodeUtil 23 | */ 24 | public class PublicNodeUtil { 25 | 26 | public static String getObjectLitKeyName(Node node) { 27 | return NodeUtil.getObjectLitKeyName(node); 28 | } 29 | 30 | public static Node getFunctionBody(Node node) { 31 | return NodeUtil.getFunctionBody(node); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/gjstags: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright 2011 AnyChart.Com Team 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | exec java -jar @path@/gjstags.jar $@ 17 | --------------------------------------------------------------------------------