[OpenLayers-Commits] r12377 - in sandbox/jsdoc: lib/OpenLayers
tools tools/closure-compiler tools/closure-compiler/bin
tools/closure-library tools/closure-library/closure
tools/closure-library/closure/bin
tools/closure-library/closure/bin/build
commits-20090109 at openlayers.org
commits-20090109 at openlayers.org
Sat Sep 17 13:30:37 EDT 2011
Author: tschaub
Date: 2011-09-17 10:30:36 -0700 (Sat, 17 Sep 2011)
New Revision: 12377
Added:
sandbox/jsdoc/tools/NaturalDocs2JsDoc.py
sandbox/jsdoc/tools/NaturalDocsPreserve.py
sandbox/jsdoc/tools/closure-compiler/
sandbox/jsdoc/tools/closure-compiler/bin/
sandbox/jsdoc/tools/closure-compiler/bin/_where-is-the-compiler.txt
sandbox/jsdoc/tools/closure-library/
sandbox/jsdoc/tools/closure-library/closure/
sandbox/jsdoc/tools/closure-library/closure/bin/
sandbox/jsdoc/tools/closure-library/closure/bin/build/
sandbox/jsdoc/tools/closure-library/closure/bin/build/jscompiler.py
Modified:
sandbox/jsdoc/lib/OpenLayers/Events.js
sandbox/jsdoc/tools/mergejs.py
Log:
Adding stuff from patch for #3008.
Modified: sandbox/jsdoc/lib/OpenLayers/Events.js
===================================================================
--- sandbox/jsdoc/lib/OpenLayers/Events.js 2011-09-17 16:11:32 UTC (rev 12376)
+++ sandbox/jsdoc/lib/OpenLayers/Events.js 2011-09-17 17:30:36 UTC (rev 12377)
@@ -381,6 +381,10 @@
if (window.Event) {
OpenLayers.Util.applyDefaults(window.Event, OpenLayers.Event);
} else {
+ /**
+ * Silence Closure Compiler error: Variable Event first declared in externs.zip//w3c_event.js
+ * @suppress {duplicate}
+ */
var Event = OpenLayers.Event;
}
Added: sandbox/jsdoc/tools/NaturalDocs2JsDoc.py
===================================================================
--- sandbox/jsdoc/tools/NaturalDocs2JsDoc.py (rev 0)
+++ sandbox/jsdoc/tools/NaturalDocs2JsDoc.py 2011-09-17 17:30:36 UTC (rev 12377)
@@ -0,0 +1,383 @@
+#!/usr/bin/env python
+
+import re
+import os
+import sys
+
+# -----------------
+# Sintax: OpenLayers Natural Docs --> Closure Compiler jsDoc
+# -----------------
+
+# Translate comment blocks
+syntax ={
+ "public": { # No effect: should be studied
+ "keywords": ["APIFunction:", "APIMethod:"]
+ },
+ "private": { # No effect: should be studied
+ "keywords": ["Function:", "Method:"]
+ },
+ "jsDoc": { # See Format/WKT.js:260-349
+ "keywords": ["@param ", "@return ", "@returns "],
+ "keywordLineCnv": "cnvKeywordJsDoc"
+ },
+ "extends": {
+ "keywords": ["Inherits from: *$"],
+ "lineConv": "lineSuperClass",
+ "maxLines": 1, # Closure Compiler does not understand the multiple-inheritance.
+ "prefixLine": "@extends"
+ },
+ "constructor": {
+ "keywords": ["Constructor:"],
+ "prefixKeyword": "@constructor"
+ },
+ "const": {
+ "keywords": ["Constant:"],
+ "prefixKeyword": "@const",
+ "lineConv": "lineSingleDecl",
+ "prefixLine": "@type"
+ },
+ "namespace": {
+ "keywords": ["Namespace:"],
+ "prefixKeyword": "@type {Object}"
+ },
+ "var": {
+ "keywords": ["Property:", "APIProperty:"],
+ "lineConv": "lineSingleDecl",
+ "prefixLine": "@type",
+ "maxLines": 1, # forced end of block
+ "maxKeywords": 1 ## TODO:
+ ## A property can be a function with parameters
+ ## documented in other lines within the block,
+ ## this means stop working line by line to analyze
+ ## the whole block together. uff!
+ ## See APIProperty:onStart on Control/DragFeature.js
+ # On the other hand it is very rare case and there is few
+ # additional informations that can provide to the compiler.
+ },
+ "params": {
+ "keywords": ["Parameters: *$", "Parameter: *$"],
+ "lineConv": "lineParam",
+ "prefixLine": "@param"
+ },
+ "optionalParams": { # New block: To debate
+ "keywords": ["Optional Parameters: *$", "Optional Parameter: *$"],
+ "lineConv": "lineOptParam",
+ "prefixLine": "@param"
+ },
+ "optionsParam": { # Any "options" argument is forced to set optional.
+ "keywords": ["options - {Object}"],
+ "prefixKeyword": "@param {Object=} options",
+ "lineConv" : "lineOptParam", # Causes compiler warnings that allows
+ "prefixLine": "@param" # better verification of documentation.
+ # See below "optionsProperties"
+ },
+ "optionsProperties": { # The properties of the "options" are not translated into jsDoc
+ # It is necessary to complete the set of parameters
+ # for the compiler and also for the documentation
+ # generated by Natural Docs.
+ "keywords": [
+ "Options: *$",
+ "Allowed Options: *$",
+ "Valid Options: *$",
+ "Valid options properties: *$"]
+ },
+ "scope": { # New block: To debate
+ "keywords": ["Scope: *$"],
+ "lineConv": "lineSingleDecl",
+ "prefixLine": "@this"
+ },
+ "return": {
+ "keywords": ["Returns: *$", "Return: *$"],
+ "lineConv": "lineSingleDecl",
+ "maxLines": 1, # forced end of block
+ "prefixLine": "@return"
+ }
+}
+
+# Translate types
+typesOL = [
+ # For DOM types see Closure Compiler source in the folder: closure-compiler/externs
+ ("XMLNode", "Node"), # Closure said: "we put XMLNode properties on Node" (see: ie_dom.js)
+ ("DOMElement", "Element"),
+ ("HTMLDOMElement", "Element"), # Used in: Events.js
+ # js types
+ ("Number", "number"),
+ ("Integer", "number"),
+ ("int", "number"), # Used in: Events.js
+ ("Float", "number"),
+ ("String", "string"),
+ ("Boolean", "boolean"),
+ ("Function", "function(...[*])"),
+ # Composed types
+ (r"Array\((.*)\)", r"Array.<\1>"), # Array(...) to Array.<...>
+ (r"Array\[(.*)\]", r"Array.<\1>"), # Used in: Popup/Framed.js
+ (r"Array\<(.*)\>", r"Array.<\1>"), # Used in: Renderer/Elements.js:26
+ (r"\<(.*)>\((.*)\)", r"\1.<\2>") # Used in Tween.js:24
+]
+
+# -----------------
+# Detect "Natural Docs" comments.
+# -----------------
+M_CODE = 0
+M_COM2_BLOC = 1
+reStarCom2Bloc = re.compile(r"^ *\/\*\* *(?! )")
+reLineCom2 = re.compile(r"^ *\* *(?! )")
+reEndComBloc = re.compile(r"\*\/")
+reEndLine = re.compile(r"\n")
+reProblematicEndLine = re.compile(r"\\\n")
+
+def cnv4JsDoc (inputFilename, outputFilename):
+ print "Translating into jsDoc: ", outputFilename, " ",
+
+ if not os.path.isfile(inputFilename):
+ print "\nProcess aborted due to errors."
+ sys.exit('ERROR: Input file "%s" does not exist!' % inputFilename)
+
+ dirOut = os.path.dirname(outputFilename)
+ if dirOut == "":
+ print "\nProcess aborted due to errors."
+ sys.exit('ERROR: Output file "%s" without path!' % outputFilename)
+
+ if not os.path.exists(dirOut):
+ os.makedirs(dirOut)
+
+ fOut = open(outputFilename,"w")
+ fIn = open(inputFilename)
+
+ mode = M_CODE
+ previousProblematicEndLine = False
+ nat = Com2()
+ lineNumber = 0
+ for line in fIn:
+ lineNumber += 1
+ startCom2 = -1
+ endCom2 = -1
+ if mode == M_CODE and not previousProblematicEndLine:
+ oo = reStarCom2Bloc.search(line)
+ if oo:
+ startCom2 = oo.end()
+ mode = M_COM2_BLOC
+ nat.clearBlock()
+
+ # Com2 line?
+ if mode == M_COM2_BLOC:
+ previousProblematicEndLine = False
+ oo = reEndComBloc.search(line)
+ if oo:
+ endCom2 = oo.start()
+ mode = M_CODE
+
+ if startCom2 == -1:
+ oo = reLineCom2.search(line)
+ if oo:
+ startCom2 = oo.end()
+
+ if endCom2 == -1:
+ endCom2 = reEndLine.search(line).start()
+
+ if startCom2 >= 0 and startCom2 < endCom2:
+ # Com2 line? Yeah!
+ line = ( line[:startCom2] +
+ nat.toJsDoc(line[startCom2:endCom2]) +
+ line[endCom2:] )
+ fOut.write(line)
+ if mode == M_CODE:
+ if reProblematicEndLine.search(line):
+ previousProblematicEndLine = True
+ else:
+ previousProblematicEndLine = False
+
+ print " Done!"
+ fIn.close()
+ fOut.close()
+ return outputFilename
+
+# -----------------
+# Analyze comment blocks
+# -----------------
+class Com2:
+ def __init__(self):
+ self.clearBlock()
+
+ def clearBlock(self):
+ self.maxKeywords = sys.maxint
+ self.processedKeywords = 0
+ self.blockActive = True
+ self.clearKeyword()
+
+ def clearKeyword(self):
+ self.maxLines = sys.maxint
+ self.processedLines = 0
+ self.currentModeBlock = None
+ self.blockName = None
+
+ def toJsDoc(self, line):
+ if self.blockActive == False:
+ return line
+ for k, v in syntax.iteritems():
+ for j in v["keywords"]:
+ if re.match(j, line, flags=re.IGNORECASE):
+ # Close the previous keyword
+ if self.maxKeywords <= self.processedKeywords:
+ self.blockActive = False
+ return line
+ self.clearKeyword()
+
+ # Start keyword
+ self.blockName = k
+ self.currentModeBlock = v
+
+ if "keywordLineCnv" in self.currentModeBlock:
+ conv = self.currentModeBlock["keywordLineCnv"]
+ if conv == "cnvKeywordJsDoc":
+ line = self.cnvKeywordJsDoc(line)
+ # cnvKeywordType
+ if v.get("maxLines"):
+ self.maxLines = v.get("maxLines")
+ if v.get("maxKeywords"):
+ self.maxKeywords = v.get("maxKeywords")
+ if "prefixKeyword" in self.currentModeBlock:
+ line = self.currentModeBlock["prefixKeyword"] + " " + line
+ self.processedKeywords += 1
+ break
+ else:
+ continue
+ break
+ else:
+ if self.currentModeBlock and self.currentModeBlock.get("lineConv"):
+ conv = self.currentModeBlock.get("lineConv")
+ if conv == "lineParam":
+ line = self.cnvLineParam(line, "", "")
+ elif conv == "lineOptParam":
+ line = self.cnvLineParam(line, "", "|null|undefined=")
+ elif conv == "lineSingleDecl":
+ line = self.cnvLineSingleDecl(line)
+ elif conv == "lineSuperClass":
+ line = self.cnvLineSuperClass(line)
+
+ if self.maxLines <= self.processedLines:
+ self.clearKeyword() # forced end of block
+ return line
+
+ # Keyword line converters
+ def cnvKeywordJsDoc(self, subLine):
+ words = subLine.split(None,1)
+ if len(words) < 2:
+ return subLine
+
+ decl = self.cnvChkDeclaration(words[1])
+ if decl == None:
+ return subLine
+
+ return ( words[0] + " {" + decl[0] + "} " + " " + decl[1])
+
+ # Line converters
+ def cnvLineSuperClass(self, subLine):
+ superClass = subLine.replace("- <",
+ self.currentModeBlock.get("prefixLine") + " ")
+ if subLine == superClass:
+ return subLine
+
+ self.processedLines += 1
+ superClass = superClass.replace(">","")
+ return superClass
+
+ def cnvLineParam(self, subLine, start, end):
+ words = subLine.split(None,2)
+ if len(words) < 3:
+ return subLine
+
+ if words[1] != "-":
+ return subLine
+
+ decl = self.cnvChkDeclaration(words[2])
+ if decl == None:
+ return subLine
+
+ self.processedLines += 1
+ return (self.currentModeBlock.get("prefixLine") +
+ " {" + start + decl[0] + end + "} " +
+ words[0] + " "+ decl[1])
+
+ def cnvLineSingleDecl(self, subLine):
+ decl = self.cnvChkDeclaration(subLine)
+ if decl == None:
+ return subLine
+
+ self.processedLines += 1
+ return self.currentModeBlock.get("prefixLine") + " {" + decl[0] + "} " + decl[1]
+
+ # Type converter
+ def cnvChkDeclaration(self, subLine):
+ if subLine[0:1] != "{":
+ return None
+
+ declEnd = re.search(r"\}(\s|\n|$)", subLine)
+ if not declEnd:
+ return None
+
+ return [self.cnvTypeList(subLine[1:declEnd.start()]),
+ subLine[declEnd.start()+1:]]
+
+ def cnvTypeList(self, typeList):
+ repetitiveParameter = ""
+ if typeList[-4:] == " ...":
+ typeList = typeList[:-4]
+ repetitiveParameter = "..."
+
+ return repetitiveParameter + self.cnvTypeName(typeList)
+
+ def cnvTypeName(self, typeName):
+ # print "ini:", typeName
+ if typeName == "":
+ return "*" # Any type from declaration as {}
+
+ for p, r in typesOL:
+ if r.find(r"\2") > 0:
+ spl = re.split(p,typeName)
+ if len(spl) >= 4 and spl[1] != "" and spl[2] != "":
+ typeName = re.sub(p,r,typeName)
+ typeName = typeName.replace(spl[1], self.cnvTypeName(spl[1]))
+ typeName = typeName.replace(spl[2], self.cnvTypeName(spl[2]))
+ # print "/2:",typeName
+ return self.cnvTypeNameSplit(typeName)
+ elif r.find(r"\1") > 0:
+ spl = re.split(p,typeName)
+ if len(spl) >= 3 and spl[1] != "":
+ typeName = re.sub(p,r,typeName)
+ typeName = typeName.replace(spl[1], self.cnvTypeName(spl[1]))
+ # print "/1:",typeName
+ return self.cnvTypeNameSplit(typeName)
+ else:
+ if typeName.lower() == p.lower():
+ return r
+
+ return self.cnvTypeNameSplit(typeName)
+
+ def cnvTypeNameSplit(self, typeName):
+ # print "or:",typeName
+ typeName = typeName.replace(" or ","|")
+ typeName = typeName.replace("||","|") # Used in Event.js
+ typeName = typeName.replace(" ","")
+ types = typeName.split("|")
+ if len(types) > 1:
+ for i in range(len(types)):
+ types[i] = self.cnvTypeName(self.cnvTypeNameClear(types[i]))
+ # print types
+ return "|".join(types)
+ else:
+ # print typeName
+ return self.cnvTypeNameClear(typeName)
+
+ def cnvTypeNameClear(self, typeAux):
+ if typeAux[0:1] == "{" and typeAux[len(typeAux)-1:] == "}": # See Protocol.js:105
+ typeAux = typeAux[1:-1]
+ if typeAux[0:1] == "<" and typeAux[len(typeAux)-1:] == ">":
+ typeAux = typeAux[1:-1]
+ return typeAux
+
+# -----------------
+# main
+# -----------------
+if __name__ == '__main__':
+ cnv4JsDoc(sys.argv[1],sys.argv[2])
Added: sandbox/jsdoc/tools/NaturalDocsPreserve.py
===================================================================
--- sandbox/jsdoc/tools/NaturalDocsPreserve.py (rev 0)
+++ sandbox/jsdoc/tools/NaturalDocsPreserve.py 2011-09-17 17:30:36 UTC (rev 12377)
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+
+import re
+import os
+import sys
+
+# -----------------
+# Detect "Natural Docs" comments.
+# -----------------
+preserveText ="@preserve"
+endSeparatorText ="------------------------------"
+M_CODE = 0
+M_COM1_BLOC = 1
+M_COM2_BLOC = 2
+reStarTextComBloc = re.compile(r"^ *\/\*+ *(?! )")
+reStarCom2Bloc = re.compile(r"^ *\/\*\*")
+reStarCom1Bloc = re.compile(r"^ *\/\*")
+reEndComBloc = re.compile(r"\*\/")
+reEndSepComBloc = re.compile(r"\-{30} *\*\/")
+reEndLine = re.compile(r"\n")
+reProblematicEndLine = re.compile(r"\\\n")
+
+def preserveCom (inputFilename, outputFilename):
+ print "Preserving comments to: ", outputFilename, " ",
+
+ if not os.path.isfile(inputFilename):
+ print "\nProcess aborted due to errors."
+ sys.exit('ERROR: Input file "%s" does not exist!' % inputFilename)
+
+ dirOut = os.path.dirname(outputFilename)
+ if dirOut == "":
+ print "\nProcess aborted due to errors."
+ sys.exit('ERROR: Output file "%s" without path!' % outputFilename)
+
+ if not os.path.exists(dirOut):
+ os.makedirs(dirOut)
+ fOut = open(outputFilename,"w")
+ fIn = open(inputFilename)
+
+ mode = M_CODE
+ previousProblematicEndLine = False
+ lineNumber = 0
+ for line in fIn:
+ lineNumber += 1
+ startCom = -1
+ endCom = -1
+ if mode == M_CODE and not previousProblematicEndLine:
+ oo = reStarCom2Bloc.search(line)
+ if oo:
+ startCom = oo.end()
+ mode = M_COM2_BLOC
+ else:
+ oo = reStarCom1Bloc.search(line)
+ if oo:
+ startCom = oo.end()
+ mode = M_COM1_BLOC
+
+ if mode != M_CODE:
+ modeOld = mode
+ previousProblematicEndLine = False
+ oo = reEndComBloc.search(line)
+ if oo:
+ endCom = oo.start()
+ mode = M_CODE
+
+ if endCom == -1:
+ endCom = reEndLine.search(line).start()
+
+ if startCom >= 0 and startCom <= endCom: # first line
+ aux = preserveText
+ if modeOld == M_COM1_BLOC: # Set simple comment block to comment-2 block
+ aux = "*" + preserveText
+ startText = reStarTextComBloc.search(line).end()
+ if line[startText:startText+1] != "\n": # Add line if start block with text
+ aux += "\n"
+ line = line[:startCom] + aux + line[startCom:]
+ if mode == M_CODE: # last line
+ if not reEndSepComBloc.search(line): # add separator at last line of block if not found
+ endCom = reEndComBloc.search(line).start()
+ line = ( line[:endCom] +
+ endSeparatorText +
+ line[endCom:] )
+
+ fOut.write(line)
+ if mode == M_CODE:
+ if reProblematicEndLine.search(line):
+ previousProblematicEndLine = True
+ else:
+ previousProblematicEndLine = False
+
+ print "Done!"
+ fIn.close()
+ fOut.close()
+ return outputFilename
+
+# -----------------
+# main
+# -----------------
+if __name__ == '__main__':
+ preserveCom(sys.argv[1],sys.argv[2])
Added: sandbox/jsdoc/tools/closure-compiler/bin/_where-is-the-compiler.txt
===================================================================
--- sandbox/jsdoc/tools/closure-compiler/bin/_where-is-the-compiler.txt (rev 0)
+++ sandbox/jsdoc/tools/closure-compiler/bin/_where-is-the-compiler.txt 2011-09-17 17:30:36 UTC (rev 12377)
@@ -0,0 +1,2 @@
+Download the "compiler.jar" in this directory from:
+ http://code.google.com/p/closure-compiler/downloads/list
Added: sandbox/jsdoc/tools/closure-library/closure/bin/build/jscompiler.py
===================================================================
--- sandbox/jsdoc/tools/closure-library/closure/bin/build/jscompiler.py (rev 0)
+++ sandbox/jsdoc/tools/closure-library/closure/bin/build/jscompiler.py 2011-09-17 17:30:36 UTC (rev 12377)
@@ -0,0 +1,57 @@
+# Copyright 2010 The Closure Library Authors. All Rights Reserved.
+
+"""Utility to use the Closure Compiler CLI from Python."""
+
+import distutils.version
+import logging
+import re
+import subprocess
+
+
+# Pulls a version number from the first line of 'java -version'
+_VERSION_REGEX = re.compile('[\.0-9]+')
+
+
+def _GetJavaVersion():
+ """Returns the string for the current version of Java installed."""
+ proc = subprocess.Popen(['java', '-version'], stderr=subprocess.PIPE)
+ unused_stdoutdata, stderrdata = proc.communicate()
+ version_line = stderrdata.splitlines()[0]
+ return _VERSION_REGEX.search(version_line).group()
+
+
+def Compile(compiler_jar_path, source_paths, flags=None):
+ """Prepares command-line call to Closure Compiler.
+
+ Args:
+ compiler_jar_path: Path to the Closure compiler .jar file.
+ source_paths: Source paths to build, in order.
+ flags: A list of additional flags to pass on to Closure Compiler.
+
+ Returns:
+ The compiled source, as a string, or None if compilation failed.
+ """
+
+ # User friendly version check.
+ if not (distutils.version.LooseVersion(_GetJavaVersion()) >
+ distutils.version.LooseVersion('1.6')):
+ logging.error('Closure Compiler requires Java 1.6 or higher. '
+ 'Please visit http://www.java.com/getjava')
+ return
+
+ args = ['java', '-jar', compiler_jar_path]
+ for path in source_paths:
+ args += ['--js', path]
+
+ if flags:
+ args += flags
+
+ logging.info('Compiling with the following command: %s', ' '.join(args))
+
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE)
+ stdoutdata, unused_stderrdata = proc.communicate()
+
+ if proc.returncode != 0:
+ return
+
+ return stdoutdata
Modified: sandbox/jsdoc/tools/mergejs.py
===================================================================
--- sandbox/jsdoc/tools/mergejs.py 2011-09-17 16:11:32 UTC (rev 12376)
+++ sandbox/jsdoc/tools/mergejs.py 2011-09-17 17:30:36 UTC (rev 12377)
@@ -142,6 +142,12 @@
def run (sourceDirectory, outputFilename = None, configFile = None):
+ return getSortedFiles(sourceDirectory, outputFilename, configFile, False)
+
+def getNames (sourceDirectory, configFile = None):
+ return getSortedFiles(sourceDirectory, None, configFile, True)
+
+def getSortedFiles (sourceDirectory, outputFilename = None, configFile = None, onlyNames = False):
cfg = None
if configFile:
cfg = Config(configFile)
@@ -210,6 +216,8 @@
## Move forced first and last files to the required position
if cfg:
print "Re-ordering files..."
+ cfg.forceFirst = chkListFiles("first", sourceDirectory, cfg.forceFirst, files)
+ cfg.forceLast = chkListFiles("last", sourceDirectory, cfg.forceLast, files)
order = cfg.forceFirst + [item
for item in order
if ((item not in cfg.forceFirst) and
@@ -219,6 +227,14 @@
## Output the files in the determined order
result = []
+ if onlyNames:
+ for fp in order:
+ fExp = os.path.normpath(os.path.join(sourceDirectory, fp)).replace("\\","/")
+ print "To compile: ", fExp
+ result.append(fExp)
+ print "\nTotal files to compile: %d " % len(result)
+ return result
+
for fp in order:
f = files[fp]
print "Exporting: ", f.filepath
@@ -235,6 +251,18 @@
open(outputFilename, "w").write("".join(result))
return "".join(result)
+def chkListFiles (listName, sourceDirectory, listFiles, files):
+ finalList = []
+ for item in listFiles:
+ if item not in files:
+ fFull = os.path.join(sourceDirectory, item).strip()
+ if not os.path.isfile(fFull):
+ print "File does not exist: [{0}] {1}".format(listName, item)
+ continue
+ files[item] = SourceFile(item, open(fFull, "U").read())
+ finalList.append(item)
+ return finalList
+
if __name__ == "__main__":
import getopt
More information about the Commits
mailing list