HomeForumSourceResearchGuide
Sign in to contribute to source.
Component .docgen by barry
expand copy to clipboardexpand
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)
						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
		
		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("
") fd.write(" --- extends:") fd.write(formatType(sf, id.extendsType.name)) fd.write("
") } //semantic variants? String implementations[] = new String[](csearch.getComponents(stringUtil.trim(includePackage)), csearch.getComponents("$(stringUtil.trim(includePackage)):*")) String svars[] = getSemanticVariants(implementations, stringUtil.trim(includePackage)) if (svars.arrayLength > 1 || (svars.arrayLength == 1 && svars[0].string != "<default>")) { fd.write("
") fd.write(" --- semantic variants:") for (int j = 0; j < svars.arrayLength; j++) { if (j > 0) fd.write(",") fd.write(" ") fd.write(svars[j].string) } fd.write("
") } //the overall interface description if (id.doc_description != null) { JSONElement doc = parser.parseDocument(id.doc_description) if (doc == null) out.println("invalid docstring '$(id.doc_description)' for interface $(id.name) defined in $(sf.path)") fd.write("
") fd.write(parser.getValue(doc, "description").value) fd.write("
") } else { if (SHOW_WARNINGS) out.println("[warning] 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("
") else fd.write("
") fd.write(formatType(sf, id.constants[j].type)) fd.write(" ") fd.write(id.constants[j].displayName) fd.write("
") } fd.write("
") } // - transfer fields if (id.transferFields.arrayLength > 0) { fd.write("
") fd.write("
") fd.write("Transfer fields") fd.write("
") for (int j = 0; j < id.transferFields.arrayLength; j++) { fd.write("
") fd.write(formatType(sf, id.transferFields[j].type)) fd.write(" ") fd.write(id.transferFields[j].displayName) fd.write("
") } fd.write("
") } // - event sources if (id.eventSources.arrayLength > 0) { fd.write("
") fd.write("
") fd.write("Events") fd.write("
") for (int j = 0; j < id.eventSources.arrayLength; j++) { fd.write("
") //fd.write(formatType(sf, id.eventSources[j].type)) //fd.write(" ") //fd.write(id.eventSources[j].displayName) //fd.write(id.eventSources[j].displayName) fd.write(formatEventHeader(sf, id.eventSources[j])) fd.write("
") } fd.write("
") } // - the list of functions as a summary (with hyperlinks to their descriptions) fd.write("
") fd.write("
") fd.write("Functions") fd.write("
") for (int j = 0; j < id.functions.arrayLength; j++) { bool deprecated = isDeprecated(id.functions[j].doc_description) if (deprecated) fd.write("
") else fd.write("
") fd.write(formatFunctionHeader(sf, id.functions[j])) fd.write("
") } fd.write("
") //the list of constants in detail if (id.constants.arrayLength > 0) { fd.write("
") fd.write("
") fd.write("Constants") fd.write("
") fd.write("
") for (int j = 0; j < id.constants.arrayLength; j++) { char desc[] = null if (id.constants[j].doc_description != null) { JSONElement doc = parser.parseDocument(id.constants[j].doc_description) if (parser.getValue(doc, "@description") != null) desc = parser.getValue(doc, "@description").value } else { if (SHOW_WARNINGS) out.println("[warning] element $(id.name).$(id.constants[j].name) has no documentation") } if (isDeprecated(id.constants[j].doc_description)) fd.write("
") else fd.write("
") fd.write("$(id.constants[j].name) ") fd.write("$desc") fd.write("
") } fd.write("
") fd.write("
") } //the list of transfer fields in detail if (id.transferFields.arrayLength > 0) { fd.write("
") fd.write("
") fd.write("Transfer fields") fd.write("
") fd.write("
") for (int j = 0; j < id.transferFields.arrayLength; j++) { char desc[] = null if (id.transferFields[j].doc_description != null) { JSONElement doc = parser.parseDocument(id.transferFields[j].doc_description) if (parser.getValue(doc, "@description") != null) desc = parser.getValue(doc, "@description").value } else { if (SHOW_WARNINGS) out.println("[warning] element $(id.name).$(id.transferFields[j].name) has no documentation") } fd.write("
") fd.write("$(id.transferFields[j].name) ") fd.write("$desc") fd.write("
") } fd.write("
") fd.write("
") } //the list of eventsource fields in detail if (id.eventSources.arrayLength > 0) { fd.write("
") fd.write("
") fd.write("Events") fd.write("
") fd.write("
") for (int j = 0; j < id.eventSources.arrayLength; j++) { char desc[] = null if (id.eventSources[j].doc_description != null) { JSONElement doc = parser.parseDocument(id.eventSources[j].doc_description) if (parser.getValue(doc, "@description") != null) desc = parser.getValue(doc, "@description").value } else { if (SHOW_WARNINGS) out.println("[warning] element $(id.name).$(id.eventSources[j].name) has no documentation") } fd.write("
") fd.write("$(id.eventSources[j].name) ") fd.write("$desc") fd.write("
") } fd.write("
") 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 fd.write("
") fd.write("
") fd.write(formatFunctionHeader(sf, id.functions[j])) fd.write("
") if (id.functions[j].doc_description != null) { JSONElement doc = parser.parseDocument(id.functions[j].doc_description) if (parser.getValue(doc, "@description") != null) { fd.write("
") fd.write(parser.getValue(doc, "@description").value) fd.write("
") } } else { if (SHOW_WARNINGS) out.println("[warning] 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("
") fd.write("$(id.functions[j].params[q].name) ") fd.write("$desc") fd.write("
") } } fd.write("
") //description of return value fd.write("
") char desc[] = null if (id.functions[j].doc_description != null) { JSONElement doc = parser.parseDocument(id.functions[j].doc_description) if (parser.getValue(doc, "@return") != null) desc = parser.getValue(doc, "@return").value } if (desc != null) { fd.write("
") fd.write("returns: ") fd.write("$desc") fd.write("
") } fd.write("
") 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] 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("
") fd.write(" --- extends:") fd.write(formatType(sf, td.extendsType.name)) fd.write("
") } //the overall type description if (td.doc_description != null) { JSONElement doc = parser.parseDocument(td.doc_description) JSONElement descEl = parser.getValue(doc, "description") if (descEl != null) { fd.write("
") fd.write(parser.getValue(doc, "description").value) fd.write("
") } else { if (SHOW_WARNINGS) out.println("[warning] type $(td.name) has no 'description' element in its summary documentation") } } else { if (SHOW_WARNINGS) out.println("[warning] 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) out.println("[warning] element $(td.name).$(td.constants[j].displayName) has no documentation") } fd.write("
") } fd.write("
") } if (td.fields.arrayLength > 0) { fd.write("
") fd.write("
") fd.write("Fields") fd.write("
") for (int j = 0; j < td.fields.arrayLength; j++) { char desc[] = null if (td.fields[j].doc_description != null) { JSONElement doc = parser.parseDocument(td.fields[j].doc_description) if (parser.getValue(doc, "@description") != null) desc = parser.getValue(doc, "@description").value } fd.write("
") fd.write("") fd.write(formatType(sf, td.fields[j].type)) fd.write(" ") fd.write(td.fields[j].displayName) fd.write("") if (desc != null) { fd.write(" $desc") } else { if (SHOW_WARNINGS) out.println("[warning] element $(td.name).$(td.fields[j].displayName) has no documentation") } fd.write("
") } fd.write("
") } fd.write("") fd.write("") fd.close() } } } } char[] getPrimaryType(SourceFile sf) { String tokens[] = stringUtil.explode(sf.path, "./\\") char name[] = tokens[tokens.arrayLength-2].string for (int i = 0; i < sf.types.arrayLength; i++) { if (sf.types[i].name == name) return name } return null } bool alphaGreater(char a[], char b[]) { a = stringUtil.lowercase(a) b = stringUtil.lowercase(b) for (int i = 0; i < a.arrayLength && i < b.arrayLength; i++) { if (a[i] > b[i]) return true else if (a[i] < b[i]) return false } if (a.arrayLength > b.arrayLength) return true return false } void sortTypes(PrimaryType types[]) { bool sorted = false while (!sorted) { sorted = true for (int i = 0; i < types.arrayLength - 1; i++) { if (alphaGreater(types[i].type, types[i+1].type)) { PrimaryType tmp = types[i] types[i] = types[i+1] types[i+1] = tmp sorted = false break } } } } void addPackageNode(PackageNode root, PrimaryType t, char package[]) { String parts[] = package.lsplit(".") char thisNode[] = null char nextNode[] = null if (parts != null && parts[0].string.arrayLength > 0) { //there's more to come... thisNode = parts[0].string nextNode = parts[1].string } else { //it's the last one thisNode = package } //insert this node, if it's new PackageNode subNode = null if (thisNode.arrayLength == 0) { subNode = root } else if ((subNode = root.members.findFirst(PackageNode.[path], new PackageNode(path = thisNode))) == null) { root.members = new PackageNode[](root.members, subNode = new PackageNode(PackageNode.T_PACKAGE, thisNode)) } //either recurse, or insert the actual type within this node if (nextNode != null) { addPackageNode(subNode, t, nextNode) } else { subNode.members = new PackageNode[](subNode.members, new PackageNode(PackageNode.T_TYPE, t.type, t.htmlFile)) } } void createPath(char path[]) { String parts[] = path.explode("/") char partial[] = parts[0].string if (!fileSystem.exists(partial)) { fileSystem.createDirectory(partial) } for (int i = 1; i < parts.arrayLength; i++) { partial = new char[](partial, "/", parts[i].string) if (!fileSystem.exists(partial)) { fileSystem.createDirectory(partial) } } } bool validPacdoc(char path[]) { if (!fileSystem.exists("$path/index.md")) return false return true } void parsePackageDocs(char srcDir[], char destDir[], char cssRelative[]) { //ensure that destDir exists createPath(destDir) //parse all .md files FileEntry files[] = fileSystem.getDirectoryContents(srcDir) for (int i = 0; i < files.arrayLength; i++) { if (files[i].name.endsWith(".md")) { File fd = new File("$(srcDir)/$(files[i].name)", File.READ) char doc[] = fd.read(fd.getSize()) fd.close() MDElement mdDoc = mdParser.parse(doc) char html[] = mdHTML.process(mdDoc, "docMainColumn", codeStyling, true, false, "docNavColumn") char plainName[] = files[i].name.rsplit(".")[0].string fd = new File("$(destDir)/$(plainName).html", File.CREATE) fd.write("") fd.write("") fd.write("") fd.write("Package documentation") fd.write("") fd.write(html) fd.write("") fd.close() } else { //just copy the file fileSystem.copy("$(srcDir)/$(files[i].name)", "$(destDir)/$(files[i].name)") } } } char[] getBasePath(char path[]) { String parts[] = path.explode("/") path = null for (int i = 1; i < parts.arrayLength; i++) { path = "../$path" } return path } int writePackageTree(File fd, PackageNode n, bool isRoot, int nestingLevel, int uid, char path[]) { //sort and write the top-level, then write every other level as hidden with js-unhides int uidAdd = 0 n.members = n.members.sort(PackageNode.[path], true) for (int i = 0; i < n.members.arrayLength; i++) { if (n.members[i].type == PackageNode.T_PACKAGE) { char doclink[] = null //check for a pacdoc directory, and generate package-level documentation if present (parse all .md files to html and copy all other files over) if (fileSystem.exists("$path/$(n.members[i].path)/$(PACDOC_DIR)")) { out.println("> parsing package documentation for $path/$(n.members[i].path)") if (validPacdoc("$path/$(n.members[i].path)/$(PACDOC_DIR)")) { parsePackageDocs("$path/$(n.members[i].path)/$(PACDOC_DIR)", "$OUTPUT_DIR/pacdoc/$path/$(n.members[i].path)/", getBasePath("pacdoc/$path/$(n.members[i].path)/")) doclink = "doc" } else { out.println("warning: pacdoc structure in $path/$(n.members[i].path)/$(PACDOC_DIR) is not valid, skipping this folder") } } fd.write("
") fd.write("$(n.members[i].path) $doclink") fd.write("
") fd.write("
") int increment = writePackageTree(fd, n.members[i], false, nestingLevel + 1, uid+1, "$path/$(n.members[i].path)") fd.write("
") uidAdd += increment + 1 uid += increment + 1 } } for (int i = 0; i < n.members.arrayLength; i++) { if (n.members[i].type == PackageNode.T_TYPE) { fd.write("
") fd.write("$(n.members[i].path)") 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("
[flat] [package]
") for (int i = 0; i < types.arrayLength; i++) { fd.write("
") if (duplicateNames.findFirst(PrimaryType.[type], types[i]) != null) fd.write("$(types[i].type) [$(types[i].package)]") else fd.write("$(types[i].type)") fd.write("
") addPackageNode(pkgTree, types[i], types[i].package) } ref = new File("$dana_home/components/resources-ext/doc/index_b.html", File.READ) fd.write(ref.read(ref.getSize())) ref.close() fd.write("") ref = new File("$dana_home/components/resources-ext/doc/index_c.html", File.READ) fd.write(ref.read(ref.getSize())) ref.close() fd.close() //now read the package tree to build the package index page fd = new File("$OUTPUT_DIR/$(packageIndex).html", File.CREATE) if (fd != null) { ref = new File("$dana_home/components/resources-ext/doc/index_a.html", File.READ) fd.write(ref.read(ref.getSize())) ref.close() fd.write("") fd.write("
[flat] [package]
") if (fileSystem.exists("$(PACDOC_DIR)")) { out.println("> parsing package documentation for .") //parse all md files to html, and copy all other files over to our docs if (validPacdoc("$(PACDOC_DIR)")) parsePackageDocs("$(PACDOC_DIR)", "$OUTPUT_DIR/pacdoc/_root/", getBasePath("/pacdoc/./_root/")) else out.println("warning: pacdoc structure in ./$(PACDOC_DIR) is not valid, skipping this folder") } writePackageTree(fd, pkgTree, true, 0, 0, ".") ref = new File("$dana_home/components/resources-ext/doc/index_b.html", File.READ) fd.write(ref.read(ref.getSize())) ref.close() fd.write("") ref = new File("$dana_home/components/resources-ext/doc/index_c.html", File.READ) fd.write(ref.read(ref.getSize())) ref.close() fd.close() } //copy in the CSS file fd = new File("$OUTPUT_DIR/doc.css", File.WRITE) ref = new File("$dana_home/components/resources-ext/doc/doc.css", File.READ) fd.write(ref.read(ref.getSize())) ref.close() fd.close() fd = new File("$OUTPUT_DIR/files/doc.css", File.WRITE) ref = new File("$dana_home/components/resources-ext/doc/doc.css", File.READ) fd.write(ref.read(ref.getSize())) ref.close() fd.close() } } } void scanDirectory(TypeParser docBuilder, char path[]) { FileEntry files[] = fileSystem.getDirectoryContents(path) for (int i = 0; i < files.arrayLength; i++) { char filePath[] = new char[](path, "/", files[i].name) if (fileSystem.getInfo(filePath).type == FileInfo.TYPE_FILE) { out.println("Parsing $filePath") File fd = new File(filePath, File.READ) char content[] = fd.read(fd.getSize()) fd.close() docBuilder.parseFile(content, filePath) } else { scanDirectory(docBuilder, filePath) } } } int App:main(AppParam params[]) { TypeParser docBuilder = new TypeParser() bool writeIndex = false ParamParser pp = new ParamParser(params, new String[](new String("-df"), new String("-dp"))) char flatIndex[] = "index" char packageIndex[] = "index_pkg" if (pp.hasSwitch("-dp")) { flatIndex = "index_flat" packageIndex = "index" } if (pp.getFreeValues().arrayLength > 0) { out.println("Parsing $(pp.getFreeValues()[0].string)") File fd = new File(pp.getFreeValues()[0].string, File.READ) char content[] = fd.read(fd.getSize()) fd.close() docBuilder.parseFile(content, pp.getFreeValues()[0].string) } else { if (fileSystem.exists("resources") && fileSystem.getInfo("resources").type == FileInfo.TYPE_DIR) { scanDirectory(docBuilder, "resources") writeIndex = true } } ParsedFiles p = docBuilder.getParsedFiles() writeDocs(p, writeIndex, flatIndex, packageIndex) return 0 } }
Linked auxiliary files
doc/index_c.html
doc/index_a.html
doc/index_b.html
doc/doc.css
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n .docgen -m "reason for update" -u yourUsername
Version 1 (this version) by barry
Notes for this version: Standard Library Initialisation