data PrimaryType{
char type[]
char package[]
char htmlFile[]
}
data PackageNode {
const byte T_PACKAGE = 1
const byte T_TYPE = 2
byte type
char path[]
char htmlFile[]
PackageNode members[]
}
const char OUTPUT_DIR[] = "_docs"
const char PACDOC_DIR[] = "_xpacdoc"
const bool SHOW_WARNINGS = true
component provides App requires parsing.TypeParser, io.File, io.FileSystem fileSystem, data.json.JSONParser parser, data.StringUtil stringUtil, io.Output out, System system, composition.Search csearch, util.ObjectFile, data.query.Search dsearch, data.query.Sort sort, data.IntUtil iu, util.ParamParser, parsing.Markdown mdParser, parsing.MarkdownToHTML mdHTML {
String danaTokens[] = new String[](new String("."), new String(":"), new String("("), new String(")"), new String("["), new String("]"), new String("{"), new String("}"), new String("<"), new String(">"), new String(","), new String("+"), new String("-"), new String("/"), new String("*"), new String("%"), new String("&"), new String("|"), new String("!"), new String("~"), new String("^"), new String("="), new String(";"))
KeywordGroup keywordsA = new KeywordGroup("keywords_a", new String[](new String("component"), new String("interface"), new String("data"), new String("uses"), new String("provides"), new String("requires"), new String("extends"), new String("implementation"), new String("static"), new String("else"), new String("opt"), new String("transfer"), new String("store"), new String("const"), new String("native")))
KeywordGroup keywordsB = new KeywordGroup("keywords_b", new String[](new String("int"), new String("char"), new String("byte"), new String("bool"), new String("dec"), new String("true"), new String("false"), new String("null"), new String("void"), new String("super"), new String("clone"), new String("rclone"), new String("delink"), new String("from"), new String("if"), new String("else"), new String("while"), new String("for"), new String("break"), new String("mutex"), new String("fold"), new String("return"), new String("new"), new String("throw"), new String("typeof"), new String("this"), new String("asynch"), new String("eventsink"), new String("sinkevent"), new String("stopevent"), new String("event"), new String("emitevent")))
KeywordGroup keywordsC = new KeywordGroup("keywords_c", new String[](new String("implements"), new String("hastype"), new String("isset")))
MDCodeStyle codeStyling = new MDCodeStyle("dana", danaTokens, new String[](new String("/*"), new String("*/")), "//", new String[](new String("\""), new String("\"")), "src_comment", "src_string", new KeywordGroup[](keywordsA, keywordsB, keywordsC))
char[] getHTMLFileFor(char sourceFile[], char type[])
{
char path[] = stringUtil.subString(sourceFile, 0, stringUtil.rfind(sourceFile, "."))
path = stringUtil.implode(stringUtil.explode(path, "/\\"), "/")
//replace the start of the path (i.e. "resources") with "doc"
String tokens[] = clone stringUtil.explode(path, "/")
tokens[0] = new String("")
path = clone stringUtil.implode(tokens, ".")
path[0] = " "
path = stringUtil.ltrim(path)
char tpath[] = new char[](path, "_$type.html")
return tpath
}
char[] getPackageFor(char sourceFile[], char type[])
{
char path[] = stringUtil.subString(sourceFile, 0, stringUtil.rfind(sourceFile, "."))
path = stringUtil.implode(stringUtil.explode(path, "/\\"), "/")
//replace the start of the path (i.e. "resources") with "doc"
String tokens[] = clone stringUtil.explode(path, "/")
tokens[0] = new String("")
tokens[tokens.arrayLength-1] = new String("")
path = clone stringUtil.implode(tokens, ".")
path[0] = " "
path[path.arrayLength-1] = " "
path = stringUtil.trim(path)
return path
}
char[] getTypeSource(SourceFile sf, char type[])
{
//check types from sf
type = stringUtil.implode(stringUtil.explode(type, "[]"), "")
for (int i = 0; i < sf.types.arrayLength; i++)
{
if (sf.types[i].name == type)
{
return getHTMLFileFor(sf.path, type)
}
}
//now check all secondary files used by sf
for (int i = 0; i < sf.supportFiles.arrayLength; i++)
{
for (int j = 0; j < sf.supportFiles[i].types.arrayLength; j++)
{
if (sf.supportFiles[i].types[j].name == type)
{
return getHTMLFileFor(sf.supportFiles[i].path, type)
}
}
}
return null
}
char[] formatType(SourceFile sf, char type[], opt bool optional)
{
//check if the type is declared anywhere in sf or any secondary file; if so create a hyperlink to its doc file
char sfn[] = getTypeSource(sf, type)
if (sfn != null)
{
if (optional)
type = new char[]("$type")
else
type = new char[]("$type")
}
return type
}
char[] formatFunctionHeader(SourceFile sf, FunctionDef f)
{
char result[]
result = new char[](result, formatType(sf, f.returnType), " ", f.name)
result = new char[](result, "(")
bool optLatch = false
for (int q = 0; q < f.params.arrayLength; q++)
{
if (f.params[q].opt_param && !optLatch)
{
result = new char[](result, "optional ")
optLatch = true
}
if (f.params[q].scope_store)
result = new char[](result, "store", formatType(sf, f.params[q].type, optLatch), " ", f.params[q].displayName)
else
result = new char[](result, formatType(sf, f.params[q].type, optLatch), " ", f.params[q].displayName)
if (q + 1 < f.params.arrayLength) result = new char[](result, ", ")
}
if (optLatch) result = new char[](result, "")
result = new char[](result, ")")
return result
}
char[] formatEventHeader(SourceFile sf, EventSourceDef f)
{
char result[]
result = new char[](result, f.name)
result = new char[](result, "(")
for (int q = 0; q < f.params.arrayLength; q++)
{
result = new char[](result, formatType(sf, f.params[q].type), " ", f.params[q].displayName)
if (q + 1 < f.params.arrayLength) result = new char[](result, ", ")
}
result = new char[](result, ")")
return result
}
String[] getSemanticVariants(String components[], char searchPackage[])
{
String result[]
//read each component, and check for which variant of package it implements (if not default)
for (int i = 0; i < components.arrayLength; i++)
{
ObjectFile ow = new ObjectFile(components[i].string)
char intfData[] = ow.getInfoSection("DNIL", "json").content
JSONElement doc = parser.parseDocument(intfData)
JSONElement providedInterfaces = parser.getValue(doc, "providedInterfaces")
for (int k = 0; k < providedInterfaces.children.arrayLength; k++)
{
JSONElement pi = providedInterfaces.children[k]
char package[] = parser.getValue(pi, "package").value
if (package == searchPackage)
{
char semantic[] = "<default>"
if (parser.getValue(pi, "semantic") != null && parser.getValue(pi, "semantic").value.arrayLength != 0)
semantic = parser.getValue(pi, "semantic").value
if (dsearch.find(result, String.[string], new String(semantic)) == null)
{
result = new String[](result, new String(semantic))
}
}
}
}
return result
}
bool isDeprecated(char str[])
{
if (str != null)
{
JSONElement doc = parser.parseDocument(str)
if (parser.getValue(doc, "@deprecated") != null && parser.getValue(doc, "@deprecated").value == "true")
return true
}
return false
}
void writeFile(SourceFile sf)
{
//put "html" on the end
char path[] = stringUtil.subString(sf.path, 0, stringUtil.rfind(sf.path, "."))
path = stringUtil.implode(stringUtil.explode(path, "/\\"), "/")
//replace the start of the path (i.e. "resources") with "doc"
String tokens[] = clone stringUtil.explode(path, "/")
tokens[0] = new String(OUTPUT_DIR)
path = stringUtil.implode(tokens, "/")
//get the "include" package
tokens[0] = new String("")
char includePackage[] = clone stringUtil.implode(tokens, ".")
includePackage[0] = " "
//we write each type separately, and at the top of each HTML file indicate which resource file must be used
int dfID = 0
String warnings[] = null
for (int i = 0; i < sf.types.arrayLength; i++)
{
if (sf.types[i].class == TypeDef.INTERFACE)
{
InterfaceDef id = sf.types[i]
if (!isDeprecated(id.doc_description))
{
char tpath[] = new char[]("$OUTPUT_DIR/files/", getHTMLFileFor(sf.path, id.name))
if (fileSystem.exists(tpath))
fileSystem.delete(tpath)
File fd = new File(tpath, File.WRITE)
if (fd != null)
{
fd.write("")
fd.write("")
fd.write("")
fd.write("$(id.name)")
fd.write("")
fd.write("")
fd.write("
")
fd.write("Interface$(id.name)")
fd.write("
")
//what to include to use this type
fd.write("
")
fd.write("access this type via:$includePackage (provides, requires or uses)")
fd.write("
")
//extends?
if (id.extendsType != null)
{
fd.write("
")
}
else
{
if (SHOW_WARNINGS) warnings = new String[](warnings, new String("type $(id.name) has no summary documentation"))
}
//summary of the interface
// - constants
if (id.constants.arrayLength > 0)
{
fd.write("
")
fd.write("
")
fd.write("Constants")
fd.write("
")
for (int j = 0; j < id.constants.arrayLength; j++)
{
if (isDeprecated(id.constants[j].doc_description))
fd.write("
")
}
//the list of functions in detail, with parameter descriptions etc.
for (int j = 0; j < id.functions.arrayLength; j++)
{
bool deprecated = isDeprecated(id.functions[j].doc_description)
if (deprecated)
fd.write("
")
}
}
else
{
if (SHOW_WARNINGS) warnings = new String[](warnings, new String("element $(id.name).$(id.functions[j].name) has no documentation"))
}
//description of each parameter
fd.write("
")
for (int q = 0; q < id.functions[j].params.arrayLength; q++)
{
char desc[] = null
if (id.functions[j].doc_description != null)
{
JSONElement doc = parser.parseDocument(id.functions[j].doc_description)
if (parser.getValue(doc, id.functions[j].params[q].name) != null)
desc = parser.getValue(doc, id.functions[j].params[q].name).value
}
if (desc != null)
{
fd.write("
")
}
//TODO: a list of known implementations, with any documentation that those specific implementations have
// ...
fd.write("")
fd.write("")
fd.close()
}
}
}
}
for (int i = 0; i < sf.types.arrayLength; i++)
{
if (sf.types[i].class == TypeDef.DATA)
{
DataDef td = sf.types[i]
if (!isDeprecated(td.doc_description))
{
char tpath[] = new char[]("$OUTPUT_DIR/files/", getHTMLFileFor(sf.path, td.name))
if (fileSystem.exists(tpath))
fileSystem.delete(tpath)
File fd = new File(tpath, File.WRITE)
if (fd != null)
{
fd.write("")
fd.write("")
fd.write("")
fd.write("$(td.name)")
fd.write("")
fd.write("")
fd.write("
")
fd.write("Data type$(td.name)")
fd.write("
")
//what to include to use this type
fd.write("
")
fd.write("access this type via:$includePackage (uses)")
fd.write("
")
//extends?
if (td.extendsType != null)
{
fd.write("
")
}
else
{
if (SHOW_WARNINGS) warnings = new String[](warnings, new String("type $(td.name) has no 'description' element in its summary documentation"))
}
}
else
{
if (SHOW_WARNINGS) warnings = new String[](warnings, new String("type $(td.name) has no summary documentation"))
}
//the list of fields as a summary (with hyperlinks to their descriptions)
if (td.constants.arrayLength > 0)
{
fd.write("
")
fd.write("
")
fd.write("Constants")
fd.write("
")
for (int j = 0; j < td.constants.arrayLength; j++)
{
char desc[] = null
if (td.constants[j].doc_description != null)
{
JSONElement doc = parser.parseDocument(td.constants[j].doc_description)
if (parser.getValue(doc, "@description") != null)
desc = parser.getValue(doc, "@description").value
}
/*
if (isDeprecated(td.constants[j].doc_description))
fd.write("
")
else
fd.write("
")
*/
fd.write("
")
fd.write("")
fd.write(formatType(sf, td.constants[j].type))
fd.write(" ")
fd.write(td.constants[j].displayName)
fd.write("")
if (desc != null)
{
fd.write(" $desc")
}
else
{
if (SHOW_WARNINGS) warnings = new String[](warnings, new String("element $(td.name).$(td.constants[j].displayName) has no documentation"))
}
fd.write("
")
}
}
return uidAdd
}
void writeDocs(ParsedFiles p, bool writeIndex, char flatIndex[], char packageIndex[])
{
if (!fileSystem.exists(OUTPUT_DIR))
fileSystem.createDirectory(OUTPUT_DIR)
if (!fileSystem.exists("$OUTPUT_DIR/files"))
fileSystem.createDirectory("$OUTPUT_DIR/files")
out.println("Scanning components and generating pages")
//generate a set of HTML files for p.primaryFiles
for (int i = 0; i < p.primaryFiles.arrayLength; i++)
{
writeFile(p.primaryFiles[i])
}
if (writeIndex)
{
out.println("Generating index page")
//generate the index HTML file
File fd = new File("$OUTPUT_DIR/$(flatIndex).html", File.CREATE)
if (fd != null)
{
//build an alphabetically sorted list of primary types first, then write them
PrimaryType types[]
for (int i = 0; i < p.primaryFiles.arrayLength; i++)
{
char type[] = getPrimaryType(p.primaryFiles[i])
if (type != null)
{
char xf[] = getHTMLFileFor(p.primaryFiles[i].path, type)
//check the file exists (it won't do if it's a deprecated API)
if (fileSystem.exists("$OUTPUT_DIR/files/$xf"))
{
char pkg[] = getPackageFor(p.primaryFiles[i].path, type)
types = new PrimaryType[](types, new PrimaryType(type, pkg, xf))
}
}
}
char splashPage[] = ""
if (fileSystem.exists("$(PACDOC_DIR)") && validPacdoc("$(PACDOC_DIR)"))
{
//make this page the default for the content iframe
splashPage = "src = \"pacdoc/_root/index.html\""
}
//sort alphabetically
sortTypes(types)
PrimaryType duplicateNames[] = dsearch.findDuplicates(types, PrimaryType.[type])
PackageNode pkgTree = new PackageNode(PackageNode.T_PACKAGE, "")
char dana_home[] = system.getDanaHome()
File ref = new File("$dana_home/components/resources-ext/doc/index_a.html", File.READ)
fd.write(ref.read(ref.getSize()))
ref.close()
fd.write("