885 lines
23 KiB
TypeScript
885 lines
23 KiB
TypeScript
|
/**
|
||
|
* libjass
|
||
|
*
|
||
|
* https://github.com/Arnavion/libjass
|
||
|
*
|
||
|
* Copyright 2013 Arnav Singh
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
import { FileTransform } from "async-build";
|
||
|
|
||
|
import * as AST from "./typescript/ast";
|
||
|
import { Compiler } from "./typescript/compiler";
|
||
|
import { walk } from "./typescript/walker";
|
||
|
|
||
|
function flatten<T>(arr: T[][]): T[] {
|
||
|
let result: T[] = [];
|
||
|
|
||
|
for (const a of arr) {
|
||
|
result = result.concat(a);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
const sorter = (() => {
|
||
|
function visibilitySorter(value1: { isPrivate?: boolean; isProtected?: boolean; }, value2: { isPrivate?: boolean; isProtected?: boolean; }) {
|
||
|
if (value1.isPrivate === value2.isPrivate && value1.isProtected === value2.isProtected) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (value1.isPrivate) {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (value2.isPrivate) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
if (value1.isProtected) {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (value2.isProtected) {
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const types = [AST.Property, AST.Function, AST.Interface, AST.Class, AST.Enum];
|
||
|
function typeSorter(value1: AST.ModuleMember | AST.NamespaceMember, value2: AST.ModuleMember | AST.NamespaceMember) {
|
||
|
let type1Index = -1;
|
||
|
let type2Index = -1;
|
||
|
|
||
|
types.every((type, index) => {
|
||
|
if (value1 instanceof type) {
|
||
|
type1Index = index;
|
||
|
}
|
||
|
if (value2 instanceof type) {
|
||
|
type2Index = index;
|
||
|
}
|
||
|
return (type1Index === -1) || (type2Index === -1);
|
||
|
});
|
||
|
|
||
|
return type1Index - type2Index;
|
||
|
}
|
||
|
|
||
|
function nameSorter(value1: { name: string }, value2: { name: string }) {
|
||
|
return value1.name.localeCompare(value2.name);
|
||
|
}
|
||
|
|
||
|
const sorters: ((value1: AST.ModuleMember, value2: AST.ModuleMember) => number)[] = [visibilitySorter, typeSorter, nameSorter];
|
||
|
|
||
|
return (value1: AST.ModuleMember, value2: AST.ModuleMember) => {
|
||
|
for (const sorter of sorters) {
|
||
|
const result = sorter(value1, value2);
|
||
|
|
||
|
if (result !== 0) {
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
};
|
||
|
})();
|
||
|
|
||
|
function indenter(indent: number) {
|
||
|
return (line: string) => ((line === "") ? line : (Array(indent + 1).join("\t") + line));
|
||
|
}
|
||
|
|
||
|
function sanitize(str: string) {
|
||
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||
|
}
|
||
|
|
||
|
function toVariableName(item: { name: string }) {
|
||
|
// TODO: Handle non-letters (are both their toLowerCase() and toUpperCase())
|
||
|
|
||
|
const name = item.name;
|
||
|
let result = "";
|
||
|
|
||
|
for (let i = 0; i < name.length; i++) {
|
||
|
if (name[i] === name[i].toLowerCase()) {
|
||
|
// This is lower case. Write it as lower case.
|
||
|
result += name[i];
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
// This is upper case.
|
||
|
|
||
|
if (i === 0) {
|
||
|
// This is the first character. Write it as lower case.
|
||
|
result += name[i].toLowerCase();
|
||
|
}
|
||
|
|
||
|
else if (name[i - 1] === name[i - 1].toUpperCase()) {
|
||
|
// The previous character was upper case.
|
||
|
|
||
|
if (i === name.length - 1) {
|
||
|
// This is the last character. Write it as lower case.
|
||
|
result += name[i].toLowerCase();
|
||
|
}
|
||
|
else if (name[i + 1] === name[i + 1].toLowerCase()) {
|
||
|
// The next character is lower case so this is the start of a new word. Write this one as upper case.
|
||
|
result += name[i];
|
||
|
}
|
||
|
else {
|
||
|
// The next character is upper case. Write this one as lower case.
|
||
|
result += name[i].toLowerCase();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else {
|
||
|
// Previous character was lower case so this is the start of a new word. Write this one as upper case.
|
||
|
result += name[i];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
function toUsageName(item: AST.Class | AST.Interface | AST.Function | AST.Property | AST.Enum): string {
|
||
|
if (item.parent instanceof AST.Module) {
|
||
|
return item.name;
|
||
|
}
|
||
|
|
||
|
if (item instanceof AST.Class || item instanceof AST.Interface || item instanceof AST.Enum) {
|
||
|
if (item.isPrivate) {
|
||
|
return item.name;
|
||
|
}
|
||
|
|
||
|
return item.fullName;
|
||
|
}
|
||
|
|
||
|
if (item.parent instanceof AST.Namespace) {
|
||
|
if ((item as AST.CanBePrivate).isPrivate) {
|
||
|
return item.name;
|
||
|
}
|
||
|
|
||
|
return item.fullName;
|
||
|
}
|
||
|
|
||
|
if ((item as AST.CanBeStatic).isStatic) {
|
||
|
return toUsageName(item.parent as AST.Class | AST.Interface) + '.' + item.name;
|
||
|
}
|
||
|
|
||
|
return toVariableName(item.parent) + '.' + item.name;
|
||
|
}
|
||
|
|
||
|
function toId(item: { fullName?: string; name: string; }): string {
|
||
|
return sanitize((item.fullName === undefined) ? item.name : item.fullName);
|
||
|
}
|
||
|
|
||
|
function toLink(item: AST.ModuleMember | AST.EnumMember | AST.TypeReference): string {
|
||
|
let result = `<a href="#${ toId(item) }">${ sanitize(item.name) }`;
|
||
|
|
||
|
if (AST.hasGenerics(item) && item.generics.length > 0) {
|
||
|
const generics = item.generics as (string | AST.TypeReference | AST.IntrinsicTypeReference)[];
|
||
|
result += sanitize(`.<${ generics.map(generic =>
|
||
|
(generic instanceof AST.TypeReference || generic instanceof AST.IntrinsicTypeReference) ? generic.name : generic
|
||
|
).join(', ') }>`);
|
||
|
}
|
||
|
|
||
|
result += '</a>';
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
function writeDescription(text: string): string {
|
||
|
let result = sanitize(text).replace(/\{@link ([^} ]+)\}/g, (substring, linkTarget) => `<a href="#${ linkTarget }">${ linkTarget }</a>`);
|
||
|
|
||
|
let inCodeBlock = false;
|
||
|
result = result.split("\n").map(line => {
|
||
|
if (line.substr(0, " ".length) === " ") {
|
||
|
line = line.substr(" ".length);
|
||
|
|
||
|
if (!inCodeBlock) {
|
||
|
inCodeBlock = true;
|
||
|
line = `<pre class="code"><code>${ line }`;
|
||
|
}
|
||
|
}
|
||
|
else if (line.length > 0 && inCodeBlock) {
|
||
|
inCodeBlock = false;
|
||
|
line = `</code></pre>${ line }`;
|
||
|
}
|
||
|
else if (line.length === 0 && !inCodeBlock) {
|
||
|
line = "</p><p>";
|
||
|
}
|
||
|
|
||
|
return line;
|
||
|
}).join("\n");
|
||
|
|
||
|
if (inCodeBlock) {
|
||
|
result += '</code></pre>';
|
||
|
}
|
||
|
|
||
|
result = `<p>${ result }</p>`.replace(/<p>\s*<\/p>/g, "").replace(/<p>\s+/g, "<p>").replace(/\s+<\/p>/g, "</p>");
|
||
|
|
||
|
if (result.substr("<p>".length).indexOf("<p>") === -1) {
|
||
|
result = result.substring("<p>".length, result.length - "</p>".length);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
function writeParameters(parameters: AST.Parameter[]): string[] {
|
||
|
if (parameters.length === 0) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
return [
|
||
|
'<dd class="parameters">',
|
||
|
' <dl>'
|
||
|
].concat(flatten(parameters.map(parameter => {
|
||
|
return [
|
||
|
` <dt class="parameter name">${ sanitize(parameter.name) }</dt>`,
|
||
|
` <dd class="parameter type">${ sanitize(parameter.type) }</dd>`,
|
||
|
` <dd class="parameter description">${ writeDescription(parameter.description) }</dd>`
|
||
|
].concat(writeParameters(parameter.subParameters).map(indenter(2)));
|
||
|
}))).concat([
|
||
|
' </dl>',
|
||
|
'</dd>'
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
function functionToHtml(func: AST.Function): string[] {
|
||
|
return [
|
||
|
`<dl id="${ toId(func) }" class="function${
|
||
|
func.isAbstract ? ' abstract' : '' }${
|
||
|
func.isPrivate ? ' private' : ''}${
|
||
|
func.isProtected ? ' protected' : ''}${
|
||
|
func.isStatic ? ' static' : ''}">`,
|
||
|
` <dt class="name">${ toLink(func) }</dt>`,
|
||
|
' <dd class="description">',
|
||
|
` ${ writeDescription(func.description) }`,
|
||
|
' </dd>',
|
||
|
` <dd class="usage"><fieldset><legend /><pre><code>${
|
||
|
sanitize(
|
||
|
`${ (func.returnType !== null) ? 'var result = ' : '' }${ toUsageName(func) }(${
|
||
|
func.parameters.map(parameter => parameter.name).join(', ') });`
|
||
|
) }</code></pre></fieldset></dd>`
|
||
|
].concat(writeParameters(func.parameters).map(indenter(1))).concat(
|
||
|
(func.returnType === null) ? [] : [
|
||
|
' <dt>Returns</dt>',
|
||
|
` <dd class="return type">${ sanitize(func.returnType.type) }</dd>`,
|
||
|
` <dd class="return description">${ writeDescription(func.returnType.description) }</dd>`
|
||
|
]
|
||
|
).concat([
|
||
|
'</dl>',
|
||
|
''
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
function interfaceToHtml(interfase: AST.Interface): string[] {
|
||
|
const members: AST.InterfaceMember[] = [];
|
||
|
Object.keys(interfase.members).forEach(memberName => members.push(interfase.members[memberName]));
|
||
|
|
||
|
members.sort(sorter);
|
||
|
|
||
|
return [
|
||
|
`<dl id="${ toId(interfase) }" class="interface${ interfase.isPrivate ? ' private' : '' }">`,
|
||
|
` <dt class="name">interface ${ toLink(interfase) }${ (interfase.baseTypes.length > 0) ? ` extends ${
|
||
|
interfase.baseTypes.map(baseType => baseType instanceof AST.TypeReference ? toLink(baseType) : baseType.name).join(', ')
|
||
|
}` : '' }</dt>`,
|
||
|
' <dd class="description">',
|
||
|
` ${ writeDescription(interfase.description) }`,
|
||
|
' </dd>',
|
||
|
' <dd class="members">'
|
||
|
].concat(flatten(members.map(member => {
|
||
|
if (member instanceof AST.Property) {
|
||
|
return propertyToHtml(member).map(indenter(2));
|
||
|
}
|
||
|
else if (member instanceof AST.Function) {
|
||
|
return functionToHtml(member).map(indenter(2));
|
||
|
}
|
||
|
else {
|
||
|
throw new Error(`Unrecognized member type: ${ (member as any).constructor.name }`);
|
||
|
}
|
||
|
}))).concat([
|
||
|
' </dd>',
|
||
|
'</dl>',
|
||
|
''
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
function classToHtml(clazz: AST.Class): string[] {
|
||
|
const members: AST.InterfaceMember[] = [];
|
||
|
Object.keys(clazz.members).forEach(memberName => members.push(clazz.members[memberName]));
|
||
|
|
||
|
members.sort(sorter);
|
||
|
|
||
|
return [
|
||
|
`<dl id="${ toId(clazz) }" class="clazz${
|
||
|
clazz.isAbstract ? ' abstract' : ''}${
|
||
|
clazz.isPrivate ? ' private' : ''}">`,
|
||
|
` <dt class="name">class ${ toLink(clazz) }${
|
||
|
(clazz.baseType !== null) ? ` extends ${ (clazz.baseType instanceof AST.TypeReference) ? toLink(clazz.baseType) : clazz.baseType.name }` : '' }${
|
||
|
(clazz.interfaces.length > 0) ? ` implements ${ clazz.interfaces.map(interfase => interfase instanceof AST.TypeReference ? toLink(interfase) : interfase.name).join(', ') }` : ''}</dt>`,
|
||
|
' <dd class="description">',
|
||
|
` ${ writeDescription(clazz.description) }`,
|
||
|
' </dd>',
|
||
|
` <dd class="usage"><fieldset><legend /><pre><code>${
|
||
|
sanitize(
|
||
|
`var ${ toVariableName(clazz) } = new ${ toUsageName(clazz) }(${
|
||
|
clazz.parameters.map(parameter => parameter.name).join(', ') });`
|
||
|
) }</code></pre></fieldset></dd>`
|
||
|
].concat(writeParameters(clazz.parameters).map(indenter(1))).concat([
|
||
|
' <dd class="members">'
|
||
|
]).concat(flatten(members.map(member => {
|
||
|
if (member instanceof AST.Property) {
|
||
|
return propertyToHtml(member).map(indenter(2));
|
||
|
}
|
||
|
else if (member instanceof AST.Function) {
|
||
|
return functionToHtml(member).map(indenter(2));
|
||
|
}
|
||
|
else {
|
||
|
throw new Error(`Unrecognized member type: ${ (member as any).constructor.name }`);
|
||
|
}
|
||
|
}))).concat([
|
||
|
' </dd>',
|
||
|
'</dl>',
|
||
|
''
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
function enumToHtml(enumType: AST.Enum): string[] {
|
||
|
return [
|
||
|
`<dl id="${ toId(enumType) }" class="enum${ enumType.isPrivate ? ' private' : '' }">`,
|
||
|
` <dt class="name">enum <a href="#${ sanitize(enumType.fullName) }">${ sanitize(enumType.name) }</a></dt>`,
|
||
|
' <dd class="description">',
|
||
|
` ${ writeDescription(enumType.description) }`,
|
||
|
' </dd>'
|
||
|
].concat([
|
||
|
' <dd class="members">'
|
||
|
]).concat(flatten(enumType.members.map(member => [
|
||
|
` <dl id="${ toId(member) }" class="member">`,
|
||
|
` <dt class="name">${ toLink(member) } = ${ member.value }</dt>`,
|
||
|
' <dd class="description">',
|
||
|
` ${ writeDescription(member.description) }`,
|
||
|
' </dd>',
|
||
|
' </dl>'
|
||
|
]))).concat([
|
||
|
' </dd>',
|
||
|
'</dl>',
|
||
|
''
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
function propertyToHtml(property: AST.Property): string[] {
|
||
|
return [
|
||
|
`<dl id="${ toId(property) }" class="property">`,
|
||
|
` <dt class="name">${ toLink(property) }</dt>`
|
||
|
].concat((property.getter === null) ? [] : [
|
||
|
` <dt class="getter${ property.getter.isPrivate ? ' private' : '' }">Getter</dt>`,
|
||
|
' <dd class="description">',
|
||
|
` ${ writeDescription(property.getter.description) }`,
|
||
|
' </dd>',
|
||
|
` <dd class="usage"><fieldset><legend /><pre><code>${ sanitize(`var result = ${ toUsageName(property) };`) }</code></pre></fieldset></dd>`,
|
||
|
` <dd class="return type">${ sanitize(property.getter.type) }</dd>`
|
||
|
]).concat((property.setter === null) ? [] : [
|
||
|
` <dt class="setter${ property.setter.isPrivate ? ' private' : '' }">Setter</dt>`,
|
||
|
' <dd class="description">',
|
||
|
` ${ writeDescription(property.setter.description) }`,
|
||
|
' </dd>',
|
||
|
` <dd class="usage"><fieldset><legend /><pre><code>${ sanitize(`${ toUsageName(property) } = value;`) }</code></pre></fieldset></dd>`
|
||
|
].concat(writeParameters([new AST.Parameter("value", "", property.setter.type)]).map(indenter(1)))).concat([
|
||
|
'</dl>',
|
||
|
''
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
export function build(outputFilePath: string, root: string, rootNamespaceName: string): FileTransform {
|
||
|
const compiler = new Compiler();
|
||
|
|
||
|
return new FileTransform(function (file): void {
|
||
|
// Compile
|
||
|
compiler.compile(file);
|
||
|
|
||
|
// Walk
|
||
|
const walkResult = walk(compiler, root, rootNamespaceName);
|
||
|
const namespaces = walkResult.namespaces;
|
||
|
const modules = walkResult.modules;
|
||
|
|
||
|
// Make HTML
|
||
|
|
||
|
const namespaceNames = Object.keys(namespaces)
|
||
|
.filter(namespaceName => namespaceName.substr(0, rootNamespaceName.length) === rootNamespaceName)
|
||
|
.sort((ns1, ns2) => ns1.localeCompare(ns2));
|
||
|
|
||
|
const moduleNames = Object.keys(modules).sort((ns1, ns2) => ns1.localeCompare(ns2)).filter(moduleName => Object.keys(modules[moduleName].members).length > 0);
|
||
|
|
||
|
this.push({
|
||
|
path: outputFilePath,
|
||
|
contents: Buffer.concat([new Buffer(
|
||
|
`<?xml version="1.0" encoding="utf-8" ?>
|
||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||
|
<head>
|
||
|
<title>${ rootNamespaceName } API Documentation</title>
|
||
|
<style type="text/css">
|
||
|
<![CDATA[
|
||
|
html, body, .navigation, .content {
|
||
|
height: 100%;
|
||
|
margin: 0;
|
||
|
}
|
||
|
|
||
|
.navigation, .content {
|
||
|
overflow-y: scroll;
|
||
|
}
|
||
|
|
||
|
.navigation {
|
||
|
float: left;
|
||
|
background-color: white;
|
||
|
padding: 0 20px;
|
||
|
margin-right: 20px;
|
||
|
}
|
||
|
|
||
|
.navigation .namespace, .navigation .module {
|
||
|
margin-top: 1em;
|
||
|
}
|
||
|
|
||
|
.navigation .elements {
|
||
|
margin: 0;
|
||
|
}
|
||
|
|
||
|
.content > section:not(:last-child) {
|
||
|
border-bottom: 1px solid black;
|
||
|
}
|
||
|
|
||
|
.clazz, .enum, .function, .interface, .property {
|
||
|
margin-left: 30px;
|
||
|
padding: 10px;
|
||
|
}
|
||
|
|
||
|
.getter, .setter {
|
||
|
font-size: large;
|
||
|
}
|
||
|
|
||
|
section > .clazz:nth-child(2n), section > .enum:nth-child(2n), section > .function:nth-child(2n), section > .interface:nth-child(2n), section > .property:nth-child(2n) {
|
||
|
background-color: rgb(221, 250, 238);
|
||
|
}
|
||
|
|
||
|
section > .clazz:nth-child(2n + 1), section > .enum:nth-child(2n + 1), section > .function:nth-child(2n + 1), section > .interface:nth-child(2n + 1), section > .property:nth-child(2n + 1) {
|
||
|
background-color: rgb(244, 250, 221);
|
||
|
}
|
||
|
|
||
|
.name {
|
||
|
font-size: x-large;
|
||
|
}
|
||
|
|
||
|
.usage {
|
||
|
font-size: large;
|
||
|
font-style: italic;
|
||
|
}
|
||
|
|
||
|
.usage legend:before {
|
||
|
content: "Usage";
|
||
|
}
|
||
|
|
||
|
.usage fieldset {
|
||
|
min-width: initial;
|
||
|
overflow-x: auto;
|
||
|
}
|
||
|
|
||
|
.usage pre {
|
||
|
margin: 0;
|
||
|
}
|
||
|
|
||
|
.clazz .function, .clazz .property, .interface .function, .interface .property, .enum .member {
|
||
|
background-color: rgb(250, 241, 221);
|
||
|
}
|
||
|
|
||
|
.parameter.name {
|
||
|
font-size: large;
|
||
|
}
|
||
|
|
||
|
.type {
|
||
|
font-style: italic;
|
||
|
}
|
||
|
|
||
|
.type:before {
|
||
|
content: "Type: ";
|
||
|
}
|
||
|
|
||
|
.abstract > .name:before {
|
||
|
content: "abstract ";
|
||
|
}
|
||
|
|
||
|
.clazz .private > .name:before {
|
||
|
content: "private ";
|
||
|
}
|
||
|
|
||
|
.clazz .protected > .name:before {
|
||
|
content: "protected ";
|
||
|
}
|
||
|
|
||
|
.static > .name:before {
|
||
|
content: "static ";
|
||
|
}
|
||
|
|
||
|
.abstract.private > .name:before {
|
||
|
content: "abstract private ";
|
||
|
}
|
||
|
|
||
|
.private.static > .name:before {
|
||
|
content: "static private ";
|
||
|
}
|
||
|
|
||
|
.abstract.protected > .name:before {
|
||
|
content: "abstract protected ";
|
||
|
}
|
||
|
|
||
|
.protected.static > .name:before {
|
||
|
content: "static protected ";
|
||
|
}
|
||
|
|
||
|
body:not(.show-private) .clazz .private, body:not(.show-private) .clazz .protected, body:not(.show-private) .module {
|
||
|
display: none;
|
||
|
}
|
||
|
|
||
|
.description .code {
|
||
|
margin-left: 30px;
|
||
|
}
|
||
|
]]>
|
||
|
</style>
|
||
|
<script>
|
||
|
<![CDATA[
|
||
|
addEventListener("DOMContentLoaded", function () {
|
||
|
document.querySelector("#show-private").addEventListener("change", function (event) {
|
||
|
document.body.className = (event.target.checked ? "show-private" : "");
|
||
|
}, false);
|
||
|
|
||
|
showPrivateIfNecessary();
|
||
|
}, false);
|
||
|
|
||
|
function showPrivateIfNecessary() {
|
||
|
var jumpToElement = document.querySelector("[id=\\"" + location.hash.substr(1) + "\\"]");
|
||
|
if (jumpToElement !== null && jumpToElement.offsetHeight === 0) {
|
||
|
document.querySelector("#show-private").click()
|
||
|
jumpToElement.scrollIntoView();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
addEventListener("hashchange", showPrivateIfNecessary, false);
|
||
|
]]>
|
||
|
</script>
|
||
|
</head>
|
||
|
<body>
|
||
|
<nav class="navigation">
|
||
|
<label><input type="checkbox" id="show-private" />Show private</label>
|
||
|
`
|
||
|
)].concat(namespaceNames.map(namespaceName => {
|
||
|
const namespace = namespaces[namespaceName];
|
||
|
|
||
|
const namespaceMembers: AST.NamespaceMember[] = [];
|
||
|
for (const memberName of Object.keys(namespace.members)) {
|
||
|
namespaceMembers.push(namespace.members[memberName]);
|
||
|
}
|
||
|
|
||
|
namespaceMembers.sort(sorter);
|
||
|
|
||
|
return Buffer.concat([new Buffer(
|
||
|
` <fieldset class="namespace">
|
||
|
<legend><a href="#${ sanitize(namespaceName) }">${ sanitize(namespaceName) }</a></legend>
|
||
|
<ul class="elements">
|
||
|
`
|
||
|
)].concat(namespaceMembers.map(member => new Buffer(
|
||
|
` <li><a href="#${ sanitize(member.fullName) }">${ sanitize(member.name) }</a></li>
|
||
|
`
|
||
|
))).concat([new Buffer(
|
||
|
` </ul>
|
||
|
</fieldset>
|
||
|
|
||
|
`
|
||
|
)]));
|
||
|
})).concat(moduleNames.map(moduleName => {
|
||
|
const module = modules[moduleName];
|
||
|
|
||
|
const moduleMembers: AST.ModuleMemberWithoutReference[] = [];
|
||
|
for (const memberName of Object.keys(module.members)) {
|
||
|
const member = module.members[memberName];
|
||
|
if ((member as AST.HasParent).parent === module) {
|
||
|
moduleMembers.push(member as AST.ModuleMemberWithoutReference);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (moduleMembers.length === 0) {
|
||
|
return new Buffer("");
|
||
|
}
|
||
|
|
||
|
moduleMembers.sort(sorter);
|
||
|
|
||
|
return Buffer.concat([new Buffer(
|
||
|
` <fieldset class="module">
|
||
|
<legend><a href="#${ sanitize(moduleName) }">${ sanitize(moduleName) }</a></legend>
|
||
|
<ul class="elements">
|
||
|
`
|
||
|
)].concat(moduleMembers.map(member => new Buffer(
|
||
|
` <li><a href="#${ sanitize(member.fullName) }">${ sanitize(member.name) }</a></li>
|
||
|
`
|
||
|
))).concat([new Buffer(
|
||
|
` </ul>
|
||
|
</fieldset>
|
||
|
|
||
|
`
|
||
|
)]));
|
||
|
})).concat([new Buffer(
|
||
|
` </nav>
|
||
|
|
||
|
<div class="content">
|
||
|
`
|
||
|
)]).concat(flatten(namespaceNames.map(namespaceName => {
|
||
|
const namespace = namespaces[namespaceName];
|
||
|
|
||
|
const namespaceMembers: AST.NamespaceMember[] = [];
|
||
|
for (const memberName of Object.keys(namespace.members)) {
|
||
|
namespaceMembers.push(namespace.members[memberName]);
|
||
|
}
|
||
|
|
||
|
namespaceMembers.sort(sorter);
|
||
|
|
||
|
const properties = namespaceMembers.filter(member => member instanceof AST.Property) as AST.Property[];
|
||
|
const functions = namespaceMembers.filter(member => member instanceof AST.Function) as AST.Function[];
|
||
|
const interfaces = namespaceMembers.filter(member => member instanceof AST.Interface) as AST.Interface[];
|
||
|
const classes = namespaceMembers.filter(member => member instanceof AST.Class) as AST.Class[];
|
||
|
const enums = namespaceMembers.filter(member => member instanceof AST.Enum) as AST.Enum[];
|
||
|
|
||
|
const result = [new Buffer(
|
||
|
` <section class="namespace">
|
||
|
<h1 id="${ sanitize(namespaceName) }">Namespace ${ sanitize(namespaceName) }</h1>
|
||
|
`
|
||
|
)];
|
||
|
|
||
|
if (properties.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Properties</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const property of properties) {
|
||
|
result.push(new Buffer(propertyToHtml(property).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (functions.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Free functions</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const func of functions) {
|
||
|
result.push(new Buffer(functionToHtml(func).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (interfaces.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Interfaces</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const interfase of interfaces) {
|
||
|
result.push(new Buffer(interfaceToHtml(interfase).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (classes.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Classes</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const clazz of classes) {
|
||
|
result.push(new Buffer(classToHtml(clazz).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (enums.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Enums</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const enumType of enums) {
|
||
|
result.push(new Buffer(enumToHtml(enumType).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
return result;
|
||
|
}))).concat(flatten(moduleNames.map(moduleName => {
|
||
|
const module = modules[moduleName];
|
||
|
|
||
|
const moduleMembers: AST.ModuleMember[] = [];
|
||
|
for (const memberName of Object.keys(module.members)) {
|
||
|
const member = module.members[memberName];
|
||
|
if ((member as AST.HasParent).parent === module) {
|
||
|
moduleMembers.push(member);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (moduleMembers.length === 0) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
moduleMembers.sort(sorter);
|
||
|
|
||
|
const properties = moduleMembers.filter(member => member instanceof AST.Property) as AST.Property[];
|
||
|
const functions = moduleMembers.filter(member => member instanceof AST.Function) as AST.Function[];
|
||
|
const interfaces = moduleMembers.filter(member => member instanceof AST.Interface) as AST.Interface[];
|
||
|
const classes = moduleMembers.filter(member => member instanceof AST.Class) as AST.Class[];
|
||
|
const enums = moduleMembers.filter(member => member instanceof AST.Enum) as AST.Enum[];
|
||
|
|
||
|
const result = [new Buffer(
|
||
|
` <section class="module">
|
||
|
<h1 id="${ sanitize(moduleName) }">Module ${ sanitize(moduleName) }</h1>
|
||
|
`
|
||
|
)];
|
||
|
|
||
|
if (properties.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Properties</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const property of properties) {
|
||
|
result.push(new Buffer(propertyToHtml(property).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (functions.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Free functions</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const func of functions) {
|
||
|
result.push(new Buffer(functionToHtml(func).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (interfaces.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Interfaces</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const interfase of interfaces) {
|
||
|
result.push(new Buffer(interfaceToHtml(interfase).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (classes.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Classes</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const clazz of classes) {
|
||
|
result.push(new Buffer(classToHtml(clazz).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
if (enums.length > 0) {
|
||
|
result.push(new Buffer(
|
||
|
` <section>
|
||
|
<h2>Enums</h2>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
for (const enumType of enums) {
|
||
|
result.push(new Buffer(enumToHtml(enumType).map(indenter(5)).join("\n")));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
}
|
||
|
|
||
|
result.push(new Buffer(
|
||
|
` </section>
|
||
|
`
|
||
|
));
|
||
|
|
||
|
return result;
|
||
|
}))).concat([new Buffer(
|
||
|
` </div>
|
||
|
</body>
|
||
|
</html>
|
||
|
`
|
||
|
)]))
|
||
|
});
|
||
|
});
|
||
|
}
|