diff --git a/build/doc.ts b/build/doc.ts index a1df648..f5a1606 100644 --- a/build/doc.ts +++ b/build/doc.ts @@ -18,17 +18,14 @@ * limitations under the License. */ -import * as fs from "fs"; -import * as path from "path"; - -import { File, FileTransform } from "async-build"; +import { FileTransform } from "async-build"; import * as AST from "./typescript/ast"; import { Compiler } from "./typescript/compiler"; import { walk } from "./typescript/walker"; function flatten(arr: T[][]): T[] { - var result: T[] = []; + let result: T[] = []; for (const a of arr) { result = result.concat(a); @@ -37,7 +34,7 @@ function flatten(arr: T[][]): T[] { return result; } -var sorter = (() => { +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; @@ -62,10 +59,10 @@ var sorter = (() => { return 0; } - var types = [AST.Property, AST.Function, AST.Interface, AST.Class, AST.Enum]; + const types = [AST.Property, AST.Function, AST.Interface, AST.Class, AST.Enum]; function typeSorter(value1: AST.ModuleMember | AST.NamespaceMember, value2: AST.ModuleMember | AST.NamespaceMember) { - var type1Index = -1; - var type2Index = -1; + let type1Index = -1; + let type2Index = -1; types.every((type, index) => { if (value1 instanceof type) { @@ -84,11 +81,11 @@ var sorter = (() => { return value1.name.localeCompare(value2.name); } - var sorters: ((value1: AST.ModuleMember, value2: AST.ModuleMember) => number)[] = [visibilitySorter, typeSorter, nameSorter]; + const sorters: ((value1: AST.ModuleMember, value2: AST.ModuleMember) => number)[] = [visibilitySorter, typeSorter, nameSorter]; return (value1: AST.ModuleMember, value2: AST.ModuleMember) => { - for (var i = 0; i < sorters.length; i++) { - var result = sorters[i](value1, value2); + for (const sorter of sorters) { + const result = sorter(value1, value2); if (result !== 0) { return result; @@ -110,10 +107,10 @@ function sanitize(str: string) { function toVariableName(item: { name: string }) { // TODO: Handle non-letters (are both their toLowerCase() and toUpperCase()) - var name = item.name; - var result = ""; + const name = item.name; + let result = ""; - for (var i = 0; i < name.length; i++) { + 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]; @@ -168,15 +165,15 @@ function toUsageName(item: AST.Class | AST.Interface | AST.Function | AST.Proper } if (item.parent instanceof AST.Namespace) { - if ((item).isPrivate) { + if ((item as AST.CanBePrivate).isPrivate) { return item.name; } return item.fullName; } - if ((item).isStatic) { - return toUsageName(item.parent) + '.' + item.name; + if ((item as AST.CanBeStatic).isStatic) { + return toUsageName(item.parent as AST.Class | AST.Interface) + '.' + item.name; } return toVariableName(item.parent) + '.' + item.name; @@ -187,13 +184,12 @@ function toId(item: { fullName?: string; name: string; }): string { } function toLink(item: AST.ModuleMember | AST.EnumMember | AST.TypeReference): string { - var result = `${ sanitize(item.name) }`; + let result = `${ sanitize(item.name) }`; - var itemWithGenerics = item; - if (itemWithGenerics.generics !== undefined && itemWithGenerics.generics.length > 0) { - var generics = <(string | AST.TypeReference | AST.IntrinsicTypeReference)[]>itemWithGenerics.generics; + 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 + (generic instanceof AST.TypeReference || generic instanceof AST.IntrinsicTypeReference) ? generic.name : generic ).join(', ') }>`); } @@ -203,9 +199,9 @@ function toLink(item: AST.ModuleMember | AST.EnumMember | AST.TypeReference): st } function writeDescription(text: string): string { - var result = sanitize(text).replace(/\{@link ([^} ]+)\}/g, (substring, linkTarget) => `${ linkTarget }`); + let result = sanitize(text).replace(/\{@link ([^} ]+)\}/g, (substring, linkTarget) => `${ linkTarget }`); - var inCodeBlock = false; + let inCodeBlock = false; result = result.split("\n").map(line => { if (line.substr(0, " ".length) === " ") { line = line.substr(" ".length); @@ -288,7 +284,7 @@ function functionToHtml(func: AST.Function): string[] { } function interfaceToHtml(interfase: AST.Interface): string[] { - var members: AST.InterfaceMember[] = []; + const members: AST.InterfaceMember[] = []; Object.keys(interfase.members).forEach(memberName => members.push(interfase.members[memberName])); members.sort(sorter); @@ -310,7 +306,7 @@ function interfaceToHtml(interfase: AST.Interface): string[] { return functionToHtml(member).map(indenter(2)); } else { - throw new Error(`Unrecognized member type: ${ (member.constructor).name }`); + throw new Error(`Unrecognized member type: ${ (member as any).constructor.name }`); } }))).concat([ ' ', @@ -320,7 +316,7 @@ function interfaceToHtml(interfase: AST.Interface): string[] { } function classToHtml(clazz: AST.Class): string[] { - var members: AST.InterfaceMember[] = []; + const members: AST.InterfaceMember[] = []; Object.keys(clazz.members).forEach(memberName => members.push(clazz.members[memberName])); members.sort(sorter); @@ -330,7 +326,7 @@ function classToHtml(clazz: AST.Class): string[] { clazz.isAbstract ? ' abstract' : ''}${ clazz.isPrivate ? ' private' : ''}">`, `
class ${ toLink(clazz) }${ - (clazz.baseType !== null) ? ` extends ${ (clazz.baseType instanceof AST.TypeReference) ? toLink(clazz.baseType) : clazz.baseType.name }` : '' }${ + (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(', ') }` : ''}
`, '
', ` ${ writeDescription(clazz.description) }`, @@ -350,7 +346,7 @@ function classToHtml(clazz: AST.Class): string[] { return functionToHtml(member).map(indenter(2)); } else { - throw new Error(`Unrecognized member type: ${ (member.constructor).name }`); + throw new Error(`Unrecognized member type: ${ (member as any).constructor.name }`); } }))).concat([ '
', @@ -406,30 +402,26 @@ function propertyToHtml(property: AST.Property): string[] { } export function build(outputFilePath: string, root: string, rootNamespaceName: string): FileTransform { - var compiler = new Compiler(); - - return new FileTransform(function (file: File): void { - var self: FileTransform = this; + const compiler = new Compiler(); + return new FileTransform(function (file): void { // Compile compiler.compile(file); // Walk - var walkResult = walk(compiler, root, rootNamespaceName); - var namespaces = walkResult.namespaces; - var modules = walkResult.modules; + const walkResult = walk(compiler, root, rootNamespaceName); + const namespaces = walkResult.namespaces; + const modules = walkResult.modules; // Make HTML - var namespaceNames = Object.keys(namespaces) + const namespaceNames = Object.keys(namespaces) .filter(namespaceName => namespaceName.substr(0, rootNamespaceName.length) === rootNamespaceName) .sort((ns1, ns2) => ns1.localeCompare(ns2)); - var moduleNames = Object.keys(modules).sort((ns1, ns2) => ns1.localeCompare(ns2)); - - moduleNames = moduleNames.filter(moduleName => Object.keys(modules[moduleName].members).length > 0); + const moduleNames = Object.keys(modules).sort((ns1, ns2) => ns1.localeCompare(ns2)).filter(moduleName => Object.keys(modules[moduleName].members).length > 0); - self.push({ + this.push({ path: outputFilePath, contents: Buffer.concat([new Buffer( ` @@ -589,9 +581,9 @@ export function build(outputFilePath: string, root: string, rootNamespaceName: s ` )].concat(namespaceNames.map(namespaceName => { - var namespace = namespaces[namespaceName]; + const namespace = namespaces[namespaceName]; - var namespaceMembers: AST.NamespaceMember[] = []; + const namespaceMembers: AST.NamespaceMember[] = []; for (const memberName of Object.keys(namespace.members)) { namespaceMembers.push(namespace.members[memberName]); } @@ -613,13 +605,13 @@ export function build(outputFilePath: string, root: string, rootNamespaceName: s ` )])); })).concat(moduleNames.map(moduleName => { - var module = modules[moduleName]; + const module = modules[moduleName]; - var moduleMembers: AST.ModuleMemberWithoutReference[] = []; + const moduleMembers: AST.ModuleMemberWithoutReference[] = []; for (const memberName of Object.keys(module.members)) { - var member = module.members[memberName]; - if ((member).parent === module) { - moduleMembers.push(member); + const member = module.members[memberName]; + if ((member as AST.HasParent).parent === module) { + moduleMembers.push(member as AST.ModuleMemberWithoutReference); } } @@ -649,22 +641,22 @@ export function build(outputFilePath: string, root: string, rootNamespaceName: s
` )]).concat(flatten(namespaceNames.map(namespaceName => { - var namespace = namespaces[namespaceName]; + const namespace = namespaces[namespaceName]; - var namespaceMembers: AST.NamespaceMember[] = []; + const namespaceMembers: AST.NamespaceMember[] = []; for (const memberName of Object.keys(namespace.members)) { namespaceMembers.push(namespace.members[memberName]); } namespaceMembers.sort(sorter); - var properties = namespaceMembers.filter(member => member instanceof AST.Property); - var functions = namespaceMembers.filter(member => member instanceof AST.Function); - var interfaces = namespaceMembers.filter(member => member instanceof AST.Interface); - var classes = namespaceMembers.filter(member => member instanceof AST.Class); - var enums = namespaceMembers.filter(member => member instanceof AST.Enum); + 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[]; - var result = [new Buffer( + const result = [new Buffer( `

Namespace ${ sanitize(namespaceName) }

` @@ -762,13 +754,13 @@ export function build(outputFilePath: string, root: string, rootNamespaceName: s return result; }))).concat(flatten(moduleNames.map(moduleName => { - var module = modules[moduleName]; + const module = modules[moduleName]; - var moduleMembers: AST.ModuleMember[] = []; + const moduleMembers: AST.ModuleMember[] = []; for (const memberName of Object.keys(module.members)) { - var member = module.members[memberName]; - if ((member).parent === module) { - moduleMembers.push(member); + const member = module.members[memberName]; + if ((member as AST.HasParent).parent === module) { + moduleMembers.push(member); } } @@ -778,13 +770,13 @@ export function build(outputFilePath: string, root: string, rootNamespaceName: s moduleMembers.sort(sorter); - var properties = moduleMembers.filter(member => member instanceof AST.Property); - var functions = moduleMembers.filter(member => member instanceof AST.Function); - var interfaces = moduleMembers.filter(member => member instanceof AST.Interface); - var classes = moduleMembers.filter(member => member instanceof AST.Class); - var enums = moduleMembers.filter(member => member instanceof AST.Enum); + 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[]; - var result = [new Buffer( + const result = [new Buffer( `

Module ${ sanitize(moduleName) }

` diff --git a/build/tsconfig.json b/build/tsconfig.json new file mode 100644 index 0000000..5394740 --- /dev/null +++ b/build/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noUnusedLocals": true, + "noUnusedParameters": false, + "strictNullChecks": false, + + "target": "es5", + "module": "commonjs", + "moduleResolution": "classic", + "noImplicitUseStrict": false, + "types": [] + }, + + "files": [ + "./typescript/index.ts", + "./doc.ts", + "./node.d.ts", + "./typescript/typescript.d.ts", + "../node_modules/async-build/typings.d.ts" + ] +} diff --git a/build/typescript/ast.ts b/build/typescript/ast.ts index dffad89..c90a89c 100644 --- a/build/typescript/ast.ts +++ b/build/typescript/ast.ts @@ -18,7 +18,7 @@ * limitations under the License. */ -import * as ts from "typescript"; +import ts = require("typescript"); export class HasParent { public parent: HasParent = null; @@ -30,7 +30,7 @@ export class HasParent { return this.name; } - var parent = this.parent; + const parent = this.parent; if (parent instanceof Namespace) { return parent.getMemberFullName(this); } @@ -188,7 +188,17 @@ export class UnresolvedType { } export type HasStringGenerics = Class | Interface | Function; + +export function hasStringGenerics(item: NamespaceMember): item is HasStringGenerics { + return (item as HasGenerics).generics !== undefined; +} + export type HasGenerics = HasStringGenerics | TypeReference; + +export function hasGenerics(item: ModuleMember | EnumMember | TypeReference): item is HasGenerics { + return (item as HasGenerics).generics !== undefined; +} + export type CanBePrivate = Class | Interface | Function | Getter | Setter | Enum | Reference; export type CanBeProtected = Function; export type CanBeStatic = Function; diff --git a/build/typescript/compiler.ts b/build/typescript/compiler.ts index 6206915..86ff04c 100644 --- a/build/typescript/compiler.ts +++ b/build/typescript/compiler.ts @@ -18,33 +18,52 @@ * limitations under the License. */ -import * as fs from "fs"; -import * as path from "path"; -import * as ts from "typescript"; +import path = require("path"); +import ts = require("typescript"); -import { File, FileTransform, FileWatcher } from "async-build"; +import { File, FileTransform } from "async-build"; import * as AST from "./ast"; import { walk } from "./walker"; -export interface StreamingCompilerHost extends ts.CompilerHost, ts.ParseConfigHost { +export interface StreamingCompilerHost extends ts.CompilerHost { setOutputStream(outputStream: FileTransform): void; } +function createCompilerHost(options: ts.CompilerOptions): StreamingCompilerHost { + const host = ts.createCompilerHost(options) as StreamingCompilerHost; + + let _outputStream: FileTransform = null; + host.setOutputStream = outputStream => _outputStream = outputStream; + + host.writeFile = (fileName, data, writeByteOrderMark, onError?, sourceFiles?): void => { + _outputStream.push({ + path: fileName, + contents: new Buffer(data) + }); + }; + + host.useCaseSensitiveFileNames = () => true; + + host.getNewLine = () => "\n"; + + return host; +} + export class Compiler { private _projectRoot: string = null; + private _host: StreamingCompilerHost; private _program: ts.Program = null; - constructor(private _host: StreamingCompilerHost = new CompilerHost()) { } - compile(projectConfigFile: File) { this._projectRoot = path.dirname(projectConfigFile.path); - var projectConfig = ts.parseJsonConfigFileContent(JSON.parse(projectConfigFile.contents.toString()), this._host, this._projectRoot); + const projectConfig = ts.parseJsonConfigFileContent(JSON.parse(projectConfigFile.contents.toString()), ts.sys, this._projectRoot); + this._host = createCompilerHost(projectConfig.options); this._program = ts.createProgram(projectConfig.fileNames, projectConfig.options, this._host); - var syntacticDiagnostics = this._program.getSyntacticDiagnostics(); + const syntacticDiagnostics = this._program.getSyntacticDiagnostics(); if (syntacticDiagnostics.length > 0) { this._reportDiagnostics(syntacticDiagnostics); throw new Error("There were one or more syntactic diagnostics."); @@ -56,13 +75,13 @@ export class Compiler { throw new Error("There were one or more options diagnostics."); } - var globalDiagnostics = this._program.getGlobalDiagnostics(); + const globalDiagnostics = this._program.getGlobalDiagnostics(); if (globalDiagnostics.length > 0) { this._reportDiagnostics(globalDiagnostics); throw new Error("There were one or more global diagnostics."); } - var semanticDiagnostics = this._program.getSemanticDiagnostics(); + const semanticDiagnostics = this._program.getSemanticDiagnostics(); if (semanticDiagnostics.length > 0) { this._reportDiagnostics(semanticDiagnostics); throw new Error("There were one or more semantic diagnostics."); @@ -72,7 +91,7 @@ export class Compiler { writeFiles(outputStream: FileTransform) { this._host.setOutputStream(outputStream); - var emitDiagnostics = this._program.emit().diagnostics; + const emitDiagnostics = this._program.emit().diagnostics; if (emitDiagnostics.length > 0) { this._reportDiagnostics(emitDiagnostics); throw new Error("There were one or more emit diagnostics."); @@ -93,10 +112,10 @@ export class Compiler { private _reportDiagnostics(diagnostics: ts.Diagnostic[]) { for (const diagnostic of diagnostics) { - var message = ""; + let message = ""; if (diagnostic.file) { - var location = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start); + const location = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start); message = `${ diagnostic.file.fileName }(${ location.line + 1 },${ location.character }): `; } @@ -110,168 +129,23 @@ export class Compiler { }; } -const typeScriptModulePath = path.dirname(require.resolve("typescript")); - -class CompilerHost implements StreamingCompilerHost { - protected _sourceFiles = Object.create(null); - - private _outputStream: FileTransform = null; - - setOutputStream(outputStream: FileTransform): void { - this._outputStream = outputStream; - } - - // ts.ModuleResolutionHost members - - fileExists(fileName: string): boolean { - return fs.existsSync(fileName); - } - - readFile(fileName: string): string { - if (!this.fileExists(fileName)) { - return undefined; - } - - return fs.readFileSync(fileName, { encoding: "utf8" }); - } - - // ts.CompilerHost members - - getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError: (message: string) => void): ts.SourceFile { - if (fileName in this._sourceFiles) { - return this._sourceFiles[fileName]; - } - - try { - var text = fs.readFileSync(fileName, { encoding: "utf8" }); - var result = ts.createSourceFile(fileName, text, ts.ScriptTarget.ES5); - this._sourceFiles[fileName] = result; - } - catch (ex) { - if (onError) { - onError(ex.message); - } - } - - return result; - } - - getDefaultLibFileName(): string { - return path.join(typeScriptModulePath, "lib.dom.d.ts"); - } - - writeFile(fileName: string, data: string, writeByteOrderMark: boolean, onError: (message?: string) => void): void { - this._outputStream.push({ - path: fileName, - contents: new Buffer(data) - }); - } - - getCurrentDirectory(): string { - return path.resolve("."); - } - - getCanonicalFileName(fileName: string): string { - return ts.normalizeSlashes(path.resolve(fileName)); - } - - useCaseSensitiveFileNames(): boolean { - return true; - } - - getNewLine(): string { - return "\n"; - } - - // ts.ParseConfigHost members - - readDirectory(rootDir: string, extension: string, exclude: string[]): string[] { - return ts.sys.readDirectory(rootDir, extension, exclude).map(fileName => this.getCanonicalFileName(fileName)); - } -} - -class WatchCompilerHost extends CompilerHost { - private _fileWatcher = new FileWatcher(fileNames => this._onFilesChanged(fileNames)); - - private _filesChangedSinceLast: string[] = []; - - constructor(private _onChangeCallback: () => void) { - super(); - } - - getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, onError: (message: string) => void): ts.SourceFile { - var result = super.getSourceFile(fileName, languageVersion, onError); - if (result !== undefined) { - this._fileWatcher.watchFile(fileName); - } - - return result; - }; - - private _onFilesChanged(fileNames: string[]) { - for (const fileName of fileNames) { - delete this._sourceFiles[fileName]; - } - - this._onChangeCallback(); - } -} - export function build(root: string, rootNamespaceName: string): FileTransform { - var compiler = new Compiler(); - - return new FileTransform(function (projectConfigFile: File): void { - var self: FileTransform = this; + const compiler = new Compiler(); + return new FileTransform(function (projectConfigFile): void { console.log("Compiling " + projectConfigFile.path + "..."); compiler.compile(projectConfigFile); - var walkResult = walk(compiler, root, rootNamespaceName); + const walkResult = walk(compiler, root, rootNamespaceName); addJSDocComments(walkResult.modules); - compiler.writeFiles(self); + compiler.writeFiles(this); console.log("Compile succeeded."); }); } -export function watch(root: string, rootNamespaceName: string): FileTransform { - return new FileTransform(function (projectConfigFile: File): void { - var self: FileTransform = this; - - function compile() { - console.log("Compiling " + projectConfigFile.path + "..."); - - compiler.compile(projectConfigFile); - - compiler.writeFiles(self); - - console.log("Compile succeeded."); - - self.push({ - path: "END", - contents: "" - }); - }; - - var compilerHost = new WatchCompilerHost(() => { - try { - compile(); - } - catch (ex) { - console.error("Compile failed." + ex.stack); - } - }); - - var compiler = new Compiler(compilerHost); - - compile(); - - console.log("Listening for changes..."); - }, callback => { }); -} - function addJSDocComments(modules: { [name: string]: AST.Module }): void { function visitor(current: AST.Module | AST.ModuleMember | AST.InterfaceMember) { if (current instanceof AST.Module) { @@ -282,18 +156,18 @@ function addJSDocComments(modules: { [name: string]: AST.Module }): void { return; } - var newComments: string[] = []; + const newComments: string[] = []; if (current instanceof AST.Class) { newComments.push("@constructor"); if (current.baseType !== null) { - var baseType = current.baseType; + const baseType = current.baseType; newComments.push( "@extends {" + baseType.fullName + ( (baseType instanceof AST.TypeReference && baseType.generics.length) > 0 ? - (".<" + (baseType).generics.map(generic => generic.fullName).join(", ") + ">") : + (".<" + (baseType as AST.TypeReference).generics.map(generic => generic.fullName).join(", ") + ">") : "" ) + "}" @@ -323,37 +197,37 @@ function addJSDocComments(modules: { [name: string]: AST.Module }): void { return; } - if ((current).parent instanceof AST.Namespace) { - newComments.push("@memberOf " + (current).parent.fullName); + if (current.parent instanceof AST.Namespace) { + newComments.push("@memberOf " + current.parent.fullName); } - if ((current).generics !== undefined && (current).generics.length > 0) { - newComments.push("@template " + (current).generics.join(", ")); + if (AST.hasStringGenerics(current) && current.generics.length > 0) { + newComments.push("@template " + current.generics.join(", ")); } - if ((current).isPrivate) { + if ((current as AST.CanBePrivate).isPrivate) { newComments.push("@private"); } - if ((current).isProtected) { + if ((current as AST.CanBeProtected).isProtected) { newComments.push("@protected"); } - if ((current).isStatic) { + if ((current as AST.CanBeStatic).isStatic) { newComments.push("@static"); } if (newComments.length > 0) { if (current instanceof AST.Property) { - var nodes: ts.Node[] = []; + const nodes: ts.Node[] = []; if (current.getter !== null) { nodes.push(current.getter.astNode); } if (current.setter !== null && nodes[0] !== current.setter.astNode) { nodes.push(current.setter.astNode); } for (const node of nodes) { - (node)["typescript-new-comment"] = newComments; + (node as any)["typescript-new-comment"] = newComments; } } else { - ((current).astNode)["typescript-new-comment"] = newComments; + (current.astNode as any)["typescript-new-comment"] = newComments; } } } @@ -405,6 +279,7 @@ class FakeSourceFile { var fakeSourceFiles: { [name: string]: FakeSourceFile } = Object.create(null); export const oldGetLeadingCommentRangesOfNodeFromText: typeof ts.getLeadingCommentRangesOfNodeFromText = ts.getLeadingCommentRangesOfNodeFromText.bind(ts); + ts.getLeadingCommentRangesOfNodeFromText = (node: ts.Node, text: string) => { const originalComments = oldGetLeadingCommentRangesOfNodeFromText(node, text); diff --git a/build/typescript/extras.d.ts b/build/typescript/extras.d.ts index b7b4d9e..acd6eb8 100644 --- a/build/typescript/extras.d.ts +++ b/build/typescript/extras.d.ts @@ -1,22 +1,22 @@ declare namespace ts { - export interface EmitTextWriter { } + interface EmitTextWriter { } - export interface IntrinsicType extends Type { + interface IntrinsicType extends Type { intrinsicName: string; } - export interface SourceFile { + interface SourceFile { lineMap: number[]; } - export function forEachValue(map: Map, callback: (value: T) => U): U; - export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration): ExpressionWithTypeArguments; - export function getClassImplementsHeritageClauseElements(node: ClassDeclaration): NodeArray; - export function getInterfaceBaseTypeNodes(node: InterfaceDeclaration): NodeArray; - export function getLeadingCommentRangesOfNodeFromText(node: Node, text: string): CommentRange[]; - export function getLineStarts(sourceFile: SourceFile): number[]; - export function getSourceFileOfNode(node: Node): SourceFile; - export function getTextOfNode(node: Node, includeTrivia?: boolean): string; - export function normalizeSlashes(path: string): string; - export function writeCommentRange(text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string): void; + function forEachProperty(map: Map, callback: (value: T, key: string) => U): U; + function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration): ExpressionWithTypeArguments; + function getClassImplementsHeritageClauseElements(node: ClassLikeDeclaration): ExpressionWithTypeArguments[]; + function getInterfaceBaseTypeNodes(node: InterfaceDeclaration): ExpressionWithTypeArguments[]; + function getLeadingCommentRangesOfNodeFromText(node: Node, text: string): CommentRange[]; + function getLineStarts(sourceFile: SourceFile): number[]; + function getSourceFileOfNode(node: Node): SourceFile; + function getTextOfNode(node: Node, includeTrivia?: boolean): string; + function normalizeSlashes(path: string): string; + function writeCommentRange(text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string): void; } diff --git a/build/typescript/index.ts b/build/typescript/index.ts index 21fe2cd..4518681 100644 --- a/build/typescript/index.ts +++ b/build/typescript/index.ts @@ -18,4 +18,4 @@ * limitations under the License. */ -export { build, watch } from "./compiler"; +export { build } from "./compiler"; diff --git a/build/typescript/walker.ts b/build/typescript/walker.ts index acb063b..e8877ea 100644 --- a/build/typescript/walker.ts +++ b/build/typescript/walker.ts @@ -18,13 +18,17 @@ * limitations under the License. */ -import * as path from "path"; -import * as ts from "typescript"; +import path = require("path"); +import ts = require("typescript"); import { Compiler, oldGetLeadingCommentRangesOfNodeFromText } from "./compiler"; import * as AST from "./ast"; +function hasModifier(node: ts.Node, flags: ts.NodeFlags): boolean { + return (node.flags & flags) !== 0; +} + interface JSDoc { description: string; isAbstract: boolean; @@ -68,13 +72,13 @@ class Walker { } walk(sourceFile: ts.SourceFile): void { - var moduleName = this._moduleNameFromFileName(sourceFile.fileName); + const moduleName = this._moduleNameFromFileName(sourceFile.fileName); if (!(moduleName in this.modules)) { this.modules[moduleName] = new AST.Module(moduleName); } - var module = this._scope.enter(this.modules[moduleName]); + const module = this._scope.enter(this.modules[moduleName]); this._currentSourceFile = sourceFile; for (const statement of sourceFile.statements) { @@ -87,31 +91,31 @@ class Walker { private _walk(node: ts.Node, parent: AST.Module): void { switch (node.kind) { case ts.SyntaxKind.VariableStatement: - this._visitVariableStatement(node, parent); + this._visitVariableStatement(node as ts.VariableStatement, parent); break; case ts.SyntaxKind.FunctionDeclaration: - this._visitFunctionDeclaration(node, parent); + this._visitFunctionDeclaration(node as ts.FunctionDeclaration, parent); break; case ts.SyntaxKind.ClassDeclaration: - this._visitClassDeclaration(node, parent); + this._visitClassDeclaration(node as ts.ClassDeclaration, parent); break; case ts.SyntaxKind.InterfaceDeclaration: - this._visitInterfaceDeclaration(node, parent); + this._visitInterfaceDeclaration(node as ts.InterfaceDeclaration, parent); break; case ts.SyntaxKind.EnumDeclaration: - this._visitEnumDeclaration(node, parent); + this._visitEnumDeclaration(node as ts.EnumDeclaration, parent); break; case ts.SyntaxKind.ImportDeclaration: - this._visitImportDeclaration(node, parent); + this._visitImportDeclaration(node as ts.ImportDeclaration, parent); break; case ts.SyntaxKind.ExportDeclaration: - this._visitExportDeclaration(node, parent); + this._visitExportDeclaration(node as ts.ExportDeclaration, parent); break; case ts.SyntaxKind.ExpressionStatement: @@ -121,7 +125,7 @@ class Walker { break; default: - console.error(node.kind, (ts).SyntaxKind[node.kind], node); + console.error(node.kind, ts.SyntaxKind[node.kind], node); throw new Error("Unrecognized node."); } } @@ -130,20 +134,20 @@ class Walker { switch (node.kind) { case ts.SyntaxKind.PropertySignature: case ts.SyntaxKind.PropertyDeclaration: - this._visitProperty(node, clazz); + this._visitProperty(node as ts.PropertyDeclaration, clazz); break; case ts.SyntaxKind.MethodSignature: case ts.SyntaxKind.MethodDeclaration: - this._visitMethod(node, clazz); + this._visitMethod(node as ts.MethodDeclaration, clazz); break; case ts.SyntaxKind.GetAccessor: - this._visitGetAccessor(node, clazz); + this._visitGetAccessor(node as ts.AccessorDeclaration, clazz); break; case ts.SyntaxKind.SetAccessor: - this._visitSetAccessor(node, clazz); + this._visitSetAccessor(node as ts.AccessorDeclaration, clazz); break; case ts.SyntaxKind.TypeParameter: @@ -152,7 +156,7 @@ class Walker { break; default: - console.error(node.kind, (ts).SyntaxKind[node.kind], node); + console.error(node.kind, ts.SyntaxKind[node.kind], node); throw new Error("Unrecognized node."); } } @@ -161,12 +165,12 @@ class Walker { switch (node.kind) { case ts.SyntaxKind.PropertySignature: case ts.SyntaxKind.PropertyDeclaration: - this._visitProperty(node, interfase); + this._visitProperty(node as ts.PropertyDeclaration, interfase); break; case ts.SyntaxKind.MethodSignature: case ts.SyntaxKind.MethodDeclaration: - this._visitMethod(node, interfase); + this._visitMethod(node as ts.MethodDeclaration, interfase); break; case ts.SyntaxKind.TypeParameter: @@ -176,24 +180,24 @@ class Walker { break; default: - console.error(node.kind, (ts).SyntaxKind[node.kind], node); + console.error(node.kind, ts.SyntaxKind[node.kind], node); throw new Error("Unrecognized node."); } } private _visitProperty(node: ts.PropertyDeclaration, parent: AST.Class | AST.Interface) { - if ((node.flags & ts.NodeFlags.Private) === ts.NodeFlags.Private) { + if (hasModifier(node, ts.NodeFlags.Private)) { return; } - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); if (jsDoc.typeAnnotation === null) { this._notifyIncorrectJsDoc(`Field ${ ts.getTextOfNode(node.name) } has no @type annotation.`); jsDoc.typeAnnotation = "*"; } - var property = this._scope.enter(new AST.Property(ts.getTextOfNode(node.name))); + const property = this._scope.enter(new AST.Property(ts.getTextOfNode(node.name))); parent.members[property.name] = property; property.getter = new AST.Getter(node, jsDoc.description, jsDoc.typeAnnotation, false); property.setter = new AST.Setter(node, jsDoc.description, jsDoc.typeAnnotation, false); @@ -201,9 +205,9 @@ class Walker { } private _visitMethod(node: ts.MethodDeclaration, parent: AST.Class | AST.Interface) { - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); - var parameters = this._connectParameters(node.parameters, jsDoc.parameters, + const parameters = this._connectParameters(node.parameters, jsDoc.parameters, parameterName => `Could not find @param annotation for ${ parameterName } on method ${ ts.getTextOfNode(node.name) }` ); @@ -212,25 +216,25 @@ class Walker { jsDoc.returnType = new AST.ReturnType("", "*"); } - var isPrivate = (node.flags & ts.NodeFlags.Private) === ts.NodeFlags.Private; - var isProtected = (node.flags & ts.NodeFlags.Protected) === ts.NodeFlags.Protected; - var isStatic = (node.flags & ts.NodeFlags.Static) === ts.NodeFlags.Static; + const isPrivate = hasModifier(node, ts.NodeFlags.Private); + const isProtected = hasModifier(node, ts.NodeFlags.Protected); + const isStatic = hasModifier(node, ts.NodeFlags.Static); - var generics = this._getGenericsOfSignatureDeclaration(node); + const generics = this._getGenericsOfSignatureDeclaration(node); - var method = this._scope.enter(new AST.Function(ts.getTextOfNode(node.name), node, jsDoc.description, generics, parameters, jsDoc.returnType, jsDoc.isAbstract, isPrivate, isProtected, isStatic)); + const method = this._scope.enter(new AST.Function(ts.getTextOfNode(node.name), node, jsDoc.description, generics, parameters, jsDoc.returnType, jsDoc.isAbstract, isPrivate, isProtected, isStatic)); parent.members[method.name] = method; this._scope.leave(); } private _visitGetAccessor(node: ts.AccessorDeclaration, clazz: AST.Class): void { - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); - var name = ts.getTextOfNode(node.name); + const name = ts.getTextOfNode(node.name); - var isPrivate = (node.flags & ts.NodeFlags.Private) === ts.NodeFlags.Private; + const isPrivate = hasModifier(node, ts.NodeFlags.Private); - var property = clazz.members[name]; + let property = clazz.members[name] as AST.Property; if (property === undefined) { this._scope.enter(property = new AST.Property(name)); @@ -247,13 +251,13 @@ class Walker { } private _visitSetAccessor(node: ts.AccessorDeclaration, clazz: AST.Class): void { - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); - var name = ts.getTextOfNode(node.name); + const name = ts.getTextOfNode(node.name); - var isPrivate = (node.flags & ts.NodeFlags.Private) === ts.NodeFlags.Private; + const isPrivate = hasModifier(node, ts.NodeFlags.Private); - var property = clazz.members[name]; + let property = clazz.members[name] as AST.Property; if (property === undefined) { this._scope.enter(property = new AST.Property(name)); @@ -274,17 +278,17 @@ class Walker { return; } - var declaration = node.declarationList.declarations[0]; - if ((declaration.flags & ts.NodeFlags.Ambient) === ts.NodeFlags.Ambient) { + const declaration = node.declarationList.declarations[0]; + if (hasModifier(declaration, ts.NodeFlags.Ambient)) { return; } - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); if (jsDoc.typeAnnotation === null) { return; } - var property = this._scope.enter(new AST.Property(ts.getTextOfNode(declaration.name))); + const property = this._scope.enter(new AST.Property(ts.getTextOfNode(declaration.name))); property.getter = new AST.Getter(node, jsDoc.description, jsDoc.typeAnnotation, false); parent.members[property.name] = property; @@ -293,13 +297,13 @@ class Walker { } private _visitFunctionDeclaration(node: ts.FunctionDeclaration, parent: AST.Module): void { - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); - var isPrivate = (node.flags & ts.NodeFlags.Export) !== ts.NodeFlags.Export; + const isPrivate = !hasModifier(node, ts.NodeFlags.Export); - var generics = this._getGenericsOfSignatureDeclaration(node); + const generics = this._getGenericsOfSignatureDeclaration(node); - var parameters = this._connectParameters(node.parameters, jsDoc.parameters, + const parameters = this._connectParameters(node.parameters, jsDoc.parameters, parameterName => `Could not find @param annotation for ${ parameterName } on function ${ node.name.text }` ); @@ -312,7 +316,7 @@ class Walker { jsDoc.returnType = new AST.ReturnType("", "*"); } - var freeFunction = this._scope.enter(new AST.Function(node.name.text, node, jsDoc.description, generics, parameters, jsDoc.returnType, jsDoc.isAbstract, isPrivate, false, false)); + const freeFunction = this._scope.enter(new AST.Function(node.name.text, node, jsDoc.description, generics, parameters, jsDoc.returnType, jsDoc.isAbstract, isPrivate, false, false)); parent.members[freeFunction.name] = freeFunction; @@ -320,32 +324,32 @@ class Walker { } private _visitClassDeclaration(node: ts.ClassDeclaration, parent: AST.Module): void { - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); + + const type = this._typeChecker.getTypeAtLocation(node) as ts.InterfaceType; - var baseTypeHeritageClauseElement = ts.getClassExtendsHeritageClauseElement(node) || null; - var baseType: AST.UnresolvedType = null; + const generics = this._getGenericsOfInterfaceType(type); + + const baseTypeHeritageClauseElement = ts.getClassExtendsHeritageClauseElement(node) || null; + let baseType: AST.UnresolvedType = null; if (baseTypeHeritageClauseElement !== null) { baseType = new AST.UnresolvedType( this._typeChecker.getTypeAtLocation(baseTypeHeritageClauseElement).symbol, - this._getGenericsOfTypeReferenceNode(baseTypeHeritageClauseElement) + this._getGenericsOfTypeReferenceNode(baseTypeHeritageClauseElement, generics) ); } - var interfaces = (ts.getClassImplementsHeritageClauseElements(node) || []).map(type => new AST.UnresolvedType( + const interfaces = (ts.getClassImplementsHeritageClauseElements(node) || []).map(type => new AST.UnresolvedType( this._typeChecker.getTypeAtLocation(type).symbol, - this._getGenericsOfTypeReferenceNode(type) + this._getGenericsOfTypeReferenceNode(type, generics) )); - var isPrivate = (node.flags & ts.NodeFlags.Export) !== ts.NodeFlags.Export; - - var type = this._typeChecker.getTypeAtLocation(node); + const isPrivate = !hasModifier(node, ts.NodeFlags.Export); - var generics = this._getGenericsOfInterfaceType(type); - - var parameters: AST.Parameter[] = []; + let parameters: AST.Parameter[] = []; if (type.symbol.members["__constructor"] !== undefined) { - parameters = this._connectParameters((type.symbol.members["__constructor"].declarations[0]).parameters, jsDoc.parameters, + parameters = this._connectParameters((type.symbol.members["__constructor"].declarations[0] as ts.ConstructorDeclaration).parameters, jsDoc.parameters, parameterName => `Could not find @param annotation for ${ parameterName } on constructor in class ${ node.name.text }` ); } @@ -353,11 +357,11 @@ class Walker { this._notifyIncorrectJsDoc("There are @param annotations on this class but it has no constructors."); } - var clazz = this._scope.enter(new AST.Class(node.name.text, node, jsDoc.description, generics, parameters, baseType, interfaces, jsDoc.isAbstract, isPrivate)); + const clazz = this._scope.enter(new AST.Class(node.name.text, node, jsDoc.description, generics, parameters, baseType, interfaces, jsDoc.isAbstract, isPrivate)); parent.members[clazz.name] = clazz; - ts.forEachValue(type.symbol.exports, symbol => { + ts.forEachProperty(type.symbol.exports, symbol => { if (symbol.name === "prototype") { return; } @@ -367,7 +371,7 @@ class Walker { } }); - ts.forEachValue(type.symbol.members, symbol => { + ts.forEachProperty(type.symbol.members, symbol => { for (const declaration of symbol.declarations) { this._walkClassMember(declaration, clazz); } @@ -377,28 +381,28 @@ class Walker { } private _visitInterfaceDeclaration(node: ts.InterfaceDeclaration, parent: AST.Module): void { - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); + + const type = this._typeChecker.getTypeAtLocation(node) as ts.InterfaceType; - var baseTypes = (ts.getInterfaceBaseTypeNodes(node) || []).map(type => new AST.UnresolvedType( + const generics = this._getGenericsOfInterfaceType(type); + + const baseTypes = (ts.getInterfaceBaseTypeNodes(node) || []).map(type => new AST.UnresolvedType( this._typeChecker.getTypeAtLocation(type).symbol, - this._getGenericsOfTypeReferenceNode(type) + this._getGenericsOfTypeReferenceNode(type, generics) )); - var existingInterfaceType = parent.members[node.name.text]; + const existingInterfaceType = parent.members[node.name.text]; if (existingInterfaceType !== undefined) { return; } - var isPrivate = (node.flags & ts.NodeFlags.Export) !== ts.NodeFlags.Export; - - var type = this._typeChecker.getTypeAtLocation(node); + const isPrivate = !hasModifier(node, ts.NodeFlags.Export); - var generics = this._getGenericsOfInterfaceType(type); - - var interfase = this._scope.enter(new AST.Interface(node.name.text, node, jsDoc.description, generics, baseTypes, isPrivate)); + const interfase = this._scope.enter(new AST.Interface(node.name.text, node, jsDoc.description, generics, baseTypes, isPrivate)); parent.members[interfase.name] = interfase; - ts.forEachValue(type.symbol.members, symbol => { + ts.forEachProperty(type.symbol.members, symbol => { for (const declaration of symbol.declarations) { this._walkInterfaceMember(declaration, interfase); } @@ -408,33 +412,33 @@ class Walker { } private _visitEnumDeclaration(node: ts.EnumDeclaration, parent: AST.Module): void { - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); - var existingEnumType = parent.members[node.name.text]; + const existingEnumType = parent.members[node.name.text]; if (existingEnumType !== undefined) { return; } - var isPrivate = (node.flags & ts.NodeFlags.Export) !== ts.NodeFlags.Export; + const isPrivate = !hasModifier(node, ts.NodeFlags.Export); - var type = this._typeChecker.getTypeAtLocation(node); + const type = this._typeChecker.getTypeAtLocation(node); - var enumType = this._scope.enter(new AST.Enum(node.name.text, node, jsDoc.description, isPrivate)); + const enumType = this._scope.enter(new AST.Enum(node.name.text, node, jsDoc.description, isPrivate)); parent.members[enumType.name] = enumType; - ts.forEachValue(type.symbol.exports, symbol => { - this._visitEnumMember(symbol.declarations[0], enumType); + ts.forEachProperty(type.symbol.exports, symbol => { + this._visitEnumMember(symbol.declarations[0] as ts.EnumMember, enumType); }); this._scope.leave(); } private _visitEnumMember(node: ts.EnumMember, parent: AST.Enum): void { - var jsDoc = this._parseJSDoc(node); + const jsDoc = this._parseJSDoc(node); - var value = (node.initializer === undefined) ? null : parseInt((node.initializer).text); + const value = (node.initializer === undefined) ? null : parseInt((node.initializer as ts.LiteralExpression).text); - var enumMember = this._scope.enter(new AST.EnumMember(ts.getTextOfNode(node.name), (jsDoc === null) ? "" : jsDoc.description, value)); + const enumMember = this._scope.enter(new AST.EnumMember(ts.getTextOfNode(node.name), (jsDoc === null) ? "" : jsDoc.description, value)); parent.members.push(enumMember); @@ -451,16 +455,16 @@ class Walker { throw new Error("Default import is not supported."); } - var moduleName = this._resolve((node.moduleSpecifier).text, parent); + const moduleName = this._resolve((node.moduleSpecifier as ts.LiteralExpression).text, parent); - if ((node.importClause.namedBindings).name !== undefined) { + if ((node.importClause.namedBindings as ts.NamespaceImport).name !== undefined) { // import * as foo from "baz"; - parent.members[(node.importClause.namedBindings).name.text] = new AST.Reference(moduleName, "*", true); + parent.members[(node.importClause.namedBindings as ts.NamespaceImport).name.text] = new AST.Reference(moduleName, "*", true); } - else if ((node.importClause.namedBindings).elements !== undefined) { + else if ((node.importClause.namedBindings as ts.NamedImports).elements !== undefined) { // import { foo, bar } from "baz"; - for (const element of (node.importClause.namedBindings).elements) { - var importedName = element.propertyName && element.propertyName.text || element.name.text; + for (const element of (node.importClause.namedBindings as ts.NamedImports).elements) { + const importedName = element.propertyName && element.propertyName.text || element.name.text; parent.members[element.name.text] = new AST.Reference(moduleName, importedName, true); } } @@ -472,22 +476,22 @@ class Walker { private _visitExportDeclaration(node: ts.ExportDeclaration, parent: AST.Module): void { if (node.moduleSpecifier !== undefined) { // export { foo } from "bar"; - var moduleName = this._resolve((node.moduleSpecifier).text, parent); + const moduleName = this._resolve((node.moduleSpecifier as ts.LiteralExpression).text, parent); for (const element of node.exportClause.elements) { - var importedName = element.propertyName && element.propertyName.text || element.name.text; + const importedName = element.propertyName && element.propertyName.text || element.name.text; parent.members[element.name.text] = new AST.Reference(moduleName, importedName, false); } } else { // export { foo }; for (const element of node.exportClause.elements) { - (parent.members[element.name.text]).isPrivate = false; + (parent.members[element.name.text] as AST.CanBePrivate).isPrivate = false; } } } private _resolve(relativeModuleName: string, currentModule: AST.Module): string { - var result = ts.normalizeSlashes(path.join(currentModule.name, `../${ relativeModuleName }`)); + let result = ts.normalizeSlashes(path.join(currentModule.name, `../${ relativeModuleName }`)); if (result[0] !== ".") { result = `./${ result }`; @@ -497,7 +501,7 @@ class Walker { } private _parseJSDoc(node: ts.Node): JSDoc { - var comments = oldGetLeadingCommentRangesOfNodeFromText(node, this._currentSourceFile.text); + let comments = oldGetLeadingCommentRangesOfNodeFromText(node, this._currentSourceFile.text); if (comments === undefined) { comments = []; @@ -507,41 +511,41 @@ class Walker { comments = [comments[comments.length - 1]]; } - var comment = + const comment = (comments.length === 0) ? "" : this._currentSourceFile.text.substring(comments[0].pos, comments[0].end); - var commentStartIndex = comment.indexOf("/**"); - var commentEndIndex = comment.lastIndexOf("*/"); + const commentStartIndex = comment.indexOf("/**"); + const commentEndIndex = comment.lastIndexOf("*/"); - var lines = + const lines = (commentStartIndex === -1 || commentEndIndex === -1) ? [] : comment.substring(commentStartIndex + 2, commentEndIndex).split("\n").map(line => { - var match = line.match(/^[ \t]*\* (.*)/); + const match = line.match(/^[ \t]*\* (.*)/); if (match === null) { return ""; } return match[1]; }); - var rootDescription = ""; + let rootDescription = ""; - var parameters: { [name: string]: AST.Parameter } = Object.create(null); + const parameters: { [name: string]: AST.Parameter } = Object.create(null); - var typeAnnotation: string = null; + let typeAnnotation: string = null; - var returnType: AST.ReturnType = null; + let returnType: AST.ReturnType = null; - var isAbstract = false; + let isAbstract = false; - var lastRead: { description: string } = null; + let lastRead: { description: string } = null; for (const line of lines) { - var firstWordMatch = line.match(/^\s*(\S+)(\s*)/); - var firstWord = (firstWordMatch !== null) ? firstWordMatch[1] : ""; - var remainingLine = (firstWordMatch !== null) ? line.substring(firstWordMatch[0].length) : ""; + const firstWordMatch = line.match(/^\s*(\S+)(\s*)/); + const firstWord = (firstWordMatch !== null) ? firstWordMatch[1] : ""; + let remainingLine = (firstWordMatch !== null) ? line.substring(firstWordMatch[0].length) : ""; if (firstWord[0] === "@") { lastRead = null; @@ -552,30 +556,33 @@ class Walker { isAbstract = true; break; - case "@param": - var type: string; + case "@param": { + let type: string; [type, remainingLine] = this._readType(remainingLine); - var [, name, description] = remainingLine.match(/(\S+)\s*(.*)/); + const [, name, description] = remainingLine.match(/(\S+)\s*(.*)/); - var subParameterMatch = name.match(/^(?:(.+)\.([^\.]+))|(?:(.+)\[("[^\[\]"]+")\])$/); + const subParameterMatch = name.match(/^(?:(.+)\.([^\.]+))|(?:(.+)\[("[^\[\]"]+")\])$/); if (subParameterMatch === null) { parameters[name] = lastRead = new AST.Parameter(name, description, type); } else { - var parentName = subParameterMatch[1] || subParameterMatch[3]; - var childName = subParameterMatch[2] || subParameterMatch[4]; - var parentParameter = parameters[parentName]; + const parentName = subParameterMatch[1] || subParameterMatch[3]; + const childName = subParameterMatch[2] || subParameterMatch[4]; + const parentParameter = parameters[parentName]; parentParameter.subParameters.push(lastRead = new AST.Parameter(childName, description, type)); } + break; + } - case "@return": - var [type, description] = this._readType(remainingLine); + case "@return": { + const [type, description] = this._readType(remainingLine); returnType = lastRead = new AST.ReturnType(description, type); break; + } case "@type": [typeAnnotation] = this._readType(remainingLine); @@ -606,9 +613,9 @@ class Walker { return ["*", remainingLine]; } - var index = -1; - var numberOfUnterminatedBraces = 0; - for (var i = 0; i < remainingLine.length; i++) { + let index = -1; + let numberOfUnterminatedBraces = 0; + for (let i = 0; i < remainingLine.length; i++) { if (remainingLine[i] === "{") { numberOfUnterminatedBraces++; } @@ -626,7 +633,7 @@ class Walker { throw new Error("Unterminated type specifier."); } - var type = remainingLine.substr(1, index - 1); + const type = remainingLine.substr(1, index - 1); remainingLine = remainingLine.substr(index + 1).replace(/^\s+/, ""); return [type, remainingLine]; @@ -640,16 +647,24 @@ class Walker { return signatureDeclaration.typeParameters.map(typeParameter => typeParameter.name.text); } - private _getGenericsOfTypeReferenceNode(typeReferenceNode: ts.ExpressionWithTypeArguments): (AST.UnresolvedType | AST.IntrinsicTypeReference)[] { + private _getGenericsOfTypeReferenceNode(typeReferenceNode: ts.ExpressionWithTypeArguments, intrinsicGenerics: string[]): (AST.UnresolvedType | AST.IntrinsicTypeReference)[] { if (typeReferenceNode.typeArguments === undefined) { return []; } - var typeReference = this._typeChecker.getTypeAtLocation(typeReferenceNode); + const typeReference = this._typeChecker.getTypeAtLocation(typeReferenceNode) as ts.TypeReference; return typeReference.typeArguments.map(typeArgument => { - if ((typeArgument).intrinsicName !== undefined) { - return new AST.IntrinsicTypeReference((typeArgument).intrinsicName); + if ((typeArgument as ts.IntrinsicType).intrinsicName !== undefined) { + return new AST.IntrinsicTypeReference((typeArgument as ts.IntrinsicType).intrinsicName); + } + + if (typeArgument.flags & ts.TypeFlags.TypeParameter) { + if (intrinsicGenerics.indexOf(typeArgument.symbol.name) !== -1) { + return new AST.IntrinsicTypeReference(typeArgument.symbol.name); + } + + throw new Error(`Unbound type parameter ${ typeArgument.symbol.name }`); } return new AST.UnresolvedType(typeArgument.symbol, []); @@ -668,12 +683,12 @@ class Walker { private _connectParameters(astParameters: ts.ParameterDeclaration[], jsDocParameters: { [name: string]: AST.Parameter }, onMissingMessageCallback: (parameterName: string) => string) { return astParameters.map(parameter => { - var parameterName = (parameter.name).text; + let parameterName = (parameter.name as ts.Identifier).text; if (parameterName[0] === "_") { parameterName = parameterName.substr(1); } - var jsDocParameter = jsDocParameters[parameterName]; + let jsDocParameter = jsDocParameters[parameterName]; if (jsDocParameter === undefined) { this._notifyIncorrectJsDoc(onMissingMessageCallback.call(this, parameterName)); @@ -685,8 +700,8 @@ class Walker { } private _notifyIncorrectJsDoc(message: string): void { - var fileName = path.basename(this._currentSourceFile.fileName); - if (fileName === "lib.core.d.ts" || fileName === "lib.dom.d.ts") { + const fileName = path.basename(this._currentSourceFile.fileName); + if (fileName === "lib.es5.d.ts" || fileName === "lib.dom.d.ts") { return; } @@ -695,17 +710,17 @@ class Walker { link(rootNamespaceName: string): void { for (const moduleName of Object.keys(this.modules)) { - var module = this.modules[moduleName]; + const module = this.modules[moduleName]; for (const memberName of Object.keys(module.members)) { - var member = module.members[memberName]; + const member = module.members[memberName]; if (member instanceof AST.Class) { if (member.unresolvedBaseType instanceof AST.UnresolvedType) { - member.baseType = this._resolveTypeReference(member.unresolvedBaseType); + member.baseType = this._resolveTypeReference(member.unresolvedBaseType); } else { - member.baseType = member.unresolvedBaseType; + member.baseType = member.unresolvedBaseType; } member.interfaces = member.unresolvedInterfaces.map(interfase => { @@ -713,7 +728,7 @@ class Walker { return this._resolveTypeReference(interfase); } - return interfase; + return interfase; }); } @@ -723,12 +738,12 @@ class Walker { return this._resolveTypeReference(baseType); } - return baseType; + return baseType; }); } else if (member instanceof AST.Enum) { - var value = 0; + let value = 0; for (const enumMember of member.members) { if (enumMember.value === null) { enumMember.value = value; @@ -750,17 +765,17 @@ class Walker { private _moduleToNamespace(module: AST.Module): void { for (const memberName of Object.keys(module.members)) { - var member = module.members[memberName]; + let member = module.members[memberName]; if (member instanceof AST.Reference) { - if ((member).isPrivate) { + if (member.isPrivate) { continue; } if (member.name === "*") { - var newNamespace = this._scope.enter(new AST.Namespace(memberName)); + const newNamespace = this._scope.enter(new AST.Namespace(memberName)); - var existingNamespace = this.namespaces[newNamespace.fullName]; + const existingNamespace = this.namespaces[newNamespace.fullName]; if (existingNamespace !== undefined) { this._scope.leave(); this._scope.enter(existingNamespace); @@ -769,10 +784,10 @@ class Walker { this.namespaces[newNamespace.fullName] = newNamespace; } - var referencedModuleName = (member).moduleName; - var referencedModule = this.modules[referencedModuleName]; + let referencedModuleName = member.moduleName; + let referencedModule = this.modules[referencedModuleName]; if (referencedModule === undefined && ((referencedModuleName + "/index") in this.modules)) { - (member).moduleName = referencedModuleName = referencedModuleName + "/index"; + member.moduleName = referencedModuleName = referencedModuleName + "/index"; referencedModule = this.modules[referencedModuleName]; } this._moduleToNamespace(referencedModule); @@ -781,56 +796,56 @@ class Walker { } else { while (member instanceof AST.Reference) { - member = this.modules[(member).moduleName].members[member.name]; + member = this.modules[member.moduleName].members[member.name]; } - this._scope.enter(member); + this._scope.enter(member); this._scope.leave(); - (this._scope.current).members[member.name] = member; + (this._scope.current as AST.Namespace).members[member.name] = member; } } - else if (!(member).isPrivate) { - this._scope.enter(member); + else if (!(member as AST.CanBePrivate).isPrivate) { + this._scope.enter(member); this._scope.leave(); - (this._scope.current).members[member.name] = member; + (this._scope.current as AST.Namespace).members[member.name] = member; } } } private _resolveTypeReference(unresolvedType: AST.UnresolvedType): AST.TypeReference { - var node: ts.Node = unresolvedType.symbol.declarations[0]; + let node: ts.Node = unresolvedType.symbol.declarations[0]; while (node.kind !== ts.SyntaxKind.SourceFile) { node = node.parent; } - var sourceFile = node; + const sourceFile = node as ts.SourceFile; - var moduleName = this._moduleNameFromFileName(sourceFile.fileName); - var module = this.modules[moduleName]; + const moduleName = this._moduleNameFromFileName(sourceFile.fileName); + const module = this.modules[moduleName]; - var result = module.members[unresolvedType.symbol.name]; + let result = module.members[unresolvedType.symbol.name]; if (result === undefined) { throw new Error(`Type ${ unresolvedType.symbol.name } could not be resolved.`); } while (result instanceof AST.Reference) { - result = this.modules[(result).moduleName].members[result.name]; + result = this.modules[result.moduleName].members[result.name]; } - var resultGenerics = unresolvedType.generics.map(generic => { + const resultGenerics = unresolvedType.generics.map(generic => { if (generic instanceof AST.UnresolvedType) { return this._resolveTypeReference(generic); } - return generic; + return generic; }); - return new AST.TypeReference(result, resultGenerics); + return new AST.TypeReference(result, resultGenerics); } private _moduleNameFromFileName(fileName: string): string { - var result = ts.normalizeSlashes(path.relative(this._compiler.projectRoot, fileName)); + let result = ts.normalizeSlashes(path.relative(this._compiler.projectRoot, fileName)); result = result.substr(0, result.length - ".ts".length); @@ -843,16 +858,14 @@ class Walker { } export function walk(compiler: Compiler, root: string, rootNamespaceName: string) { - var sourceFiles = compiler.sourceFiles; - var rootFileName = ts.normalizeSlashes(path.resolve(root)); - var rootSourceFile = sourceFiles.filter(sourceFile => sourceFile.fileName === rootFileName)[0]; + const sourceFiles = compiler.sourceFiles; - var walker = new Walker(compiler); + const walker = new Walker(compiler); // Walk for (const sourceFile of sourceFiles) { if ( - path.basename(sourceFile.fileName) === "lib.core.d.ts" || + path.basename(sourceFile.fileName) === "lib.es5.d.ts" || path.basename(sourceFile.fileName) === "lib.dom.d.ts" || sourceFile.fileName.substr(-"references.d.ts".length) === "references.d.ts" ) { diff --git a/package.json b/package.json index e13a2d0..abdc03c 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "main": "lib/libjass.js", "scripts": { "prepublish": "node ./build.js clean default", - "build": "tsc ./build/typescript/index.ts ./build/doc.ts ./build/node.d.ts ./build/typescript/typescript.d.ts ./node_modules/async-build/typings.d.ts -m commonjs -t es5 -noImplicitAny --moduleResolution classic", + "build": "tsc -p ./build/tsconfig.json", "test": "node ./build.js test", "test-lib": "intern-client config=tests/intern reporters=Pretty", "test-minified": "intern-client config=tests/intern reporters=Pretty minified=true", @@ -26,12 +26,12 @@ }, "devDependencies": { "async": "1.x >=1.4", - "async-build": "0.3.0", + "async-build": "0.3.1", "intern": "3.x >=3.2.0", "npm": "3.x", - "pngjs": "2.3.1", + "pngjs": "3.x", "sax": "1.x", - "typescript": "1.8.10", + "typescript": "2.0.10", "uglify-js": "2.x >=2.4.24" }, "private": true diff --git a/src/index.ts b/src/index.ts index 3ea7631..d0e2b43 100644 --- a/src/index.ts +++ b/src/index.ts @@ -67,27 +67,27 @@ export { version } from "./version"; export function configure(newConfig: { debugMode?: boolean, verboseMode?: boolean, - Set?: typeof set.Set, - Map?: typeof map.Map, - Promise?: typeof promise.Promise, + Set?: typeof set.Set | null, + Map?: typeof map.Map | null, + Promise?: typeof promise.Promise | null, }): void { - if ("debugMode" in newConfig) { + if (typeof newConfig.debugMode === "boolean") { settings.setDebugMode(newConfig.debugMode); } - if ("verboseMode" in newConfig) { + if (typeof newConfig.verboseMode === "boolean") { settings.setVerboseMode(newConfig.verboseMode); } - if ("Set" in newConfig) { + if (typeof newConfig.Set === "function" || newConfig.Set === null) { set.setImplementation(newConfig.Set); } - if ("Map" in newConfig) { + if (typeof newConfig.Map === "function" || newConfig.Map === null) { map.setImplementation(newConfig.Map); } - if ("Promise" in newConfig) { + if (typeof newConfig.Promise === "function" || newConfig.Promise === null) { promise.setImplementation(newConfig.Promise); } } diff --git a/src/parser/misc.ts b/src/parser/misc.ts index ff9612b..cf475b2 100644 --- a/src/parser/misc.ts +++ b/src/parser/misc.ts @@ -28,7 +28,7 @@ import { Map } from "../utility/map"; * @param {string} line * @return {Property} */ -export function parseLineIntoProperty(line: string): Property { +export function parseLineIntoProperty(line: string): Property | null { const colonPos = line.indexOf(":"); if (colonPos === -1) { return null; @@ -47,7 +47,7 @@ export function parseLineIntoProperty(line: string): Property { * @param {!Array.} formatSpecifier * @return {TypedTemplate} */ -export function parseLineIntoTypedTemplate(line: string, formatSpecifier: string[]): TypedTemplate { +export function parseLineIntoTypedTemplate(line: string, formatSpecifier: string[]): TypedTemplate | null { const property = parseLineIntoProperty(line); if (property === null) { return null; diff --git a/src/parser/parse.ts b/src/parser/parse.ts index a2d56e6..ec7a2f8 100644 --- a/src/parser/parse.ts +++ b/src/parser/parse.ts @@ -71,7 +71,7 @@ class ParserRun { /** * @type {ParseNode} */ - get result(): ParseNode { + get result(): ParseNode | null { return this._result; } @@ -124,7 +124,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_enclosedTags(parent: ParseNode): ParseNode { + parse_enclosedTags(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); current.value = []; @@ -135,7 +135,7 @@ class ParserRun { } for (let next = this._peek(); this._haveMore() && next !== "}"; next = this._peek()) { - let childNode: ParseNode = null; + let childNode: ParseNode | null = null; if (this.read(current, "\\") !== null) { childNode = @@ -237,7 +237,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_newline(parent: ParseNode): ParseNode { + parse_newline(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "\\N") === null) { @@ -254,7 +254,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_hardspace(parent: ParseNode): ParseNode { + parse_hardspace(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "\\h") === null) { @@ -301,7 +301,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_a(parent: ParseNode): ParseNode { + parse_tag_a(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "a") === null) { @@ -339,8 +339,8 @@ class ParserRun { const valueNode = new ParseNode(current, next); - let value: number; - switch (valueNode.value) { + let value: number = -1; + switch ((valueNode.value)) { case "1": value = 1; break; @@ -387,7 +387,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_alpha(parent: ParseNode): ParseNode { + parse_tag_alpha(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -395,7 +395,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_an(parent: ParseNode): ParseNode { + parse_tag_an(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "an") === null) { @@ -421,7 +421,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_b(parent: ParseNode): ParseNode { + parse_tag_b(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "b") === null) { @@ -429,7 +429,7 @@ class ParserRun { return null; } - let valueNode: ParseNode = null; + let valueNode: ParseNode | null = null; let next = this._peek(); @@ -459,7 +459,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_be(parent: ParseNode): ParseNode { + parse_tag_be(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -467,7 +467,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_blur(parent: ParseNode): ParseNode { + parse_tag_blur(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -475,7 +475,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_bord(parent: ParseNode): ParseNode { + parse_tag_bord(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -483,7 +483,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_c(parent: ParseNode): ParseNode { + parse_tag_c(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -491,7 +491,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_clip(parent: ParseNode): ParseNode { + parse_tag_clip(parent: ParseNode): ParseNode | null { return this._parse_tag_clip_or_iclip("clip", parent); } @@ -499,7 +499,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fad(parent: ParseNode): ParseNode { + parse_tag_fad(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "fad") === null) { @@ -543,7 +543,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fade(parent: ParseNode): ParseNode { + parse_tag_fade(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "fade") === null) { @@ -646,7 +646,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fax(parent: ParseNode): ParseNode { + parse_tag_fax(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -654,7 +654,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fay(parent: ParseNode): ParseNode { + parse_tag_fay(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -662,7 +662,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fn(parent: ParseNode): ParseNode { + parse_tag_fn(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "fn") === null) { @@ -690,7 +690,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fr(parent: ParseNode): ParseNode { + parse_tag_fr(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -698,7 +698,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_frx(parent: ParseNode): ParseNode { + parse_tag_frx(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -706,7 +706,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fry(parent: ParseNode): ParseNode { + parse_tag_fry(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -714,7 +714,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_frz(parent: ParseNode): ParseNode { + parse_tag_frz(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -722,7 +722,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fs(parent: ParseNode): ParseNode { + parse_tag_fs(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -730,7 +730,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fsplus(parent: ParseNode): ParseNode { + parse_tag_fsplus(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "fs+") === null) { @@ -754,7 +754,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fsminus(parent: ParseNode): ParseNode { + parse_tag_fsminus(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "fs-") === null) { @@ -778,7 +778,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fscx(parent: ParseNode): ParseNode { + parse_tag_fscx(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "fscx") === null) { @@ -802,7 +802,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fscy(parent: ParseNode): ParseNode { + parse_tag_fscy(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "fscy") === null) { @@ -826,7 +826,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_fsp(parent: ParseNode): ParseNode { + parse_tag_fsp(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -834,7 +834,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_i(parent: ParseNode): ParseNode { + parse_tag_i(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -842,7 +842,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_iclip(parent: ParseNode): ParseNode { + parse_tag_iclip(parent: ParseNode): ParseNode | null { return this._parse_tag_clip_or_iclip("iclip", parent); } @@ -850,7 +850,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_k(parent: ParseNode): ParseNode { + parse_tag_k(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "k") === null) { @@ -874,7 +874,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_K(parent: ParseNode): ParseNode { + parse_tag_K(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "K") === null) { @@ -898,7 +898,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_kf(parent: ParseNode): ParseNode { + parse_tag_kf(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "kf") === null) { @@ -922,7 +922,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_ko(parent: ParseNode): ParseNode { + parse_tag_ko(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "ko") === null) { @@ -946,7 +946,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_move(parent: ParseNode): ParseNode { + parse_tag_move(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "move") === null) { @@ -998,8 +998,8 @@ class ParserRun { return null; } - let t1Node: ParseNode = null; - let t2Node: ParseNode = null; + let t1Node: ParseNode | null = null; + let t2Node: ParseNode | null = null; if (this.read(current, ",") !== null) { t1Node = this.parse_decimal(current); @@ -1037,7 +1037,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_org(parent: ParseNode): ParseNode { + parse_tag_org(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "org") === null) { @@ -1081,7 +1081,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_p(parent: ParseNode): ParseNode { + parse_tag_p(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1089,7 +1089,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_pbo(parent: ParseNode): ParseNode { + parse_tag_pbo(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1097,7 +1097,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_pos(parent: ParseNode): ParseNode { + parse_tag_pos(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "pos") === null) { @@ -1141,7 +1141,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_q(parent: ParseNode): ParseNode { + parse_tag_q(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "q") === null) { @@ -1167,7 +1167,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_r(parent: ParseNode): ParseNode { + parse_tag_r(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "r") === null) { @@ -1195,7 +1195,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_s(parent: ParseNode): ParseNode { + parse_tag_s(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1203,7 +1203,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_shad(parent: ParseNode): ParseNode { + parse_tag_shad(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1211,7 +1211,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_t(parent: ParseNode): ParseNode { + parse_tag_t(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, "t") === null) { @@ -1224,9 +1224,9 @@ class ParserRun { return null; } - let startNode: ParseNode = null; - let endNode: ParseNode = null; - let accelNode: ParseNode = null; + let startNode: ParseNode | null = null; + let endNode: ParseNode | null = null; + let accelNode: ParseNode | null = null; const firstNode = this.parse_decimal(current); if (firstNode !== null) { @@ -1268,7 +1268,7 @@ class ParserRun { const transformTags: parts.Part[] = []; for (let next = this._peek(); this._haveMore() && next !== ")" && next !== "}"; next = this._peek()) { - let childNode: ParseNode = null; + let childNode: ParseNode | null = null; if (this.read(current, "\\") !== null) { childNode = @@ -1354,7 +1354,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_u(parent: ParseNode): ParseNode { + parse_tag_u(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1362,7 +1362,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_xbord(parent: ParseNode): ParseNode { + parse_tag_xbord(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1370,7 +1370,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_xshad(parent: ParseNode): ParseNode { + parse_tag_xshad(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1378,7 +1378,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_ybord(parent: ParseNode): ParseNode { + parse_tag_ybord(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1386,7 +1386,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_yshad(parent: ParseNode): ParseNode { + parse_tag_yshad(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1394,7 +1394,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_1a(parent: ParseNode): ParseNode { + parse_tag_1a(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1402,7 +1402,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_1c(parent: ParseNode): ParseNode { + parse_tag_1c(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1410,7 +1410,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_2a(parent: ParseNode): ParseNode { + parse_tag_2a(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1418,7 +1418,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_2c(parent: ParseNode): ParseNode { + parse_tag_2c(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1426,7 +1426,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_3a(parent: ParseNode): ParseNode { + parse_tag_3a(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1434,7 +1434,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_3c(parent: ParseNode): ParseNode { + parse_tag_3c(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1442,7 +1442,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_4a(parent: ParseNode): ParseNode { + parse_tag_4a(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1450,7 +1450,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_tag_4c(parent: ParseNode): ParseNode { + parse_tag_4c(parent: ParseNode): ParseNode | null { throw new Error("Method not implemented."); } @@ -1461,7 +1461,7 @@ class ParserRun { parse_drawingInstructions(parent: ParseNode): ParseNode { const current = new ParseNode(parent); - let currentType: string = null; + let currentType: string | null = null; const numberParts: ParseNode[] = []; current.value = []; @@ -1518,7 +1518,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_decimalInt32(parent: ParseNode): ParseNode { + parse_decimalInt32(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); const isNegative = this.read(current, "-") !== null; @@ -1550,7 +1550,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_hexInt32(parent: ParseNode): ParseNode { + parse_hexInt32(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); const isNegative = this.read(current, "-") !== null; @@ -1590,7 +1590,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_decimalOrHexInt32(parent: ParseNode): ParseNode { + parse_decimalOrHexInt32(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); const valueNode = @@ -1612,7 +1612,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_decimal(parent: ParseNode): ParseNode { + parse_decimal(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); const negative = (this.read(current, "-") !== null); @@ -1637,12 +1637,12 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_unsignedDecimal(parent: ParseNode): ParseNode { + parse_unsignedDecimal(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); const characteristicNode = new ParseNode(current, ""); - let mantissaNode: ParseNode = null; + let mantissaNode: ParseNode | null = null; for (let next = this._peek(); this._haveMore() && next >= "0" && next <= "9"; next = this._peek()) { characteristicNode.value += next; @@ -1675,7 +1675,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_enableDisable(parent: ParseNode): ParseNode { + parse_enableDisable(parent: ParseNode): ParseNode | null { const next = this._peek(); if (next === "0" || next === "1") { @@ -1692,7 +1692,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_color(parent: ParseNode): ParseNode { + parse_color(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); while (this.read(current, "&") !== null || this.read(current, "H") !== null) { } @@ -1720,7 +1720,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_alpha(parent: ParseNode): ParseNode { + parse_alpha(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); while (this.read(current, "&") !== null || this.read(current, "H") !== null) { } @@ -1744,7 +1744,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - parse_colorWithAlpha(parent: ParseNode): ParseNode { + parse_colorWithAlpha(parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); const valueNode = this.parse_decimalOrHexInt32(current); @@ -1770,7 +1770,7 @@ class ParserRun { * @param {string} next * @return {ParseNode} */ - read(parent: ParseNode, next: string): ParseNode { + read(parent: ParseNode, next: string): ParseNode | null { if (this._peek(next.length) !== next) { return null; } @@ -1801,7 +1801,7 @@ class ParserRun { * @param {!ParseNode} parent * @return {ParseNode} */ - private _parse_tag_clip_or_iclip(tagName: "clip" | "iclip", parent: ParseNode): ParseNode { + private _parse_tag_clip_or_iclip(tagName: "clip" | "iclip", parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); if (this.read(current, tagName) === null) { @@ -1814,12 +1814,12 @@ class ParserRun { return null; } - let x1Node: ParseNode = null; - let x2Node: ParseNode = null; - let y1Node: ParseNode = null; - let y2Node: ParseNode = null; - let scaleNode: ParseNode = null; - let commandsNode: ParseNode = null; + let x1Node: ParseNode | null = null; + let x2Node: ParseNode | null = null; + let y1Node: ParseNode | null = null; + let y2Node: ParseNode | null = null; + let scaleNode: ParseNode | null = null; + let commandsNode: ParseNode | null = null; const firstNode = this.parse_decimal(current); @@ -1895,19 +1895,18 @@ class ParserRun { function makeTagParserFunction( tagName: string, tagConstructor: { new (value: any): parts.Part }, - valueParser: (current: ParseNode) => ParseNode, + valueParser: (current: ParseNode) => ParseNode | null, required: boolean ): void { - (ParserRun.prototype as any)[`parse_tag_${ tagName }`] = function (parent: ParseNode): ParseNode { - const self = this as ParserRun; + (ParserRun.prototype as any)[`parse_tag_${ tagName }`] = function (this: ParserRun, parent: ParseNode): ParseNode | null { const current = new ParseNode(parent); - if (self.read(current, tagName) === null) { + if (this.read(current, tagName) === null) { parent.pop(); return null; } - const valueNode = valueParser.call(self, current); + const valueNode: ParseNode | null = valueParser.call(this, current); if (valueNode !== null) { current.value = new tagConstructor(valueNode.value); @@ -1975,7 +1974,7 @@ class ParseNode { private _end: number; private _value: any; - constructor(private _parent: ParseNode, value: any = null) { + constructor(private _parent: ParseNode | null, value: any = null) { if (_parent !== null) { _parent.children.push(this); } @@ -2007,7 +2006,7 @@ class ParseNode { /** * @type {ParseNode} */ - get parent(): ParseNode { + get parent(): ParseNode | null { return this._parent; } diff --git a/src/parser/stream-parsers.ts b/src/parser/stream-parsers.ts index 0d0d0b7..bb5c5c0 100644 --- a/src/parser/stream-parsers.ts +++ b/src/parser/stream-parsers.ts @@ -21,13 +21,13 @@ import { debugMode } from "../settings"; import { ASS } from "../types/ass"; -import { Style } from "../types/style"; -import { Dialogue } from "../types/dialogue"; import { Attachment, AttachmentType } from "../types/attachment"; +import { Dialogue } from "../types/dialogue"; +import { Style } from "../types/style"; import { Map } from "../utility/map"; -import { Promise, DeferredPromise } from "../utility/promise"; +import { DeferredPromise, Promise } from "../utility/promise"; import { parseLineIntoProperty } from "./misc"; import { Stream } from "./streams"; @@ -54,7 +54,7 @@ export class StreamParser { private _shouldSwallowBom: boolean = true; private _currentSection: Section = Section.ScriptInfo; - private _currentAttachment: Attachment = null; + private _currentAttachment: Attachment | null = null; constructor(private _stream: Stream) { this._stream.nextLine().then(line => this._onNextLine(line), reason => { @@ -118,7 +118,7 @@ export class StreamParser { /** * @param {string} line */ - private _onNextLine(line: string): void { + private _onNextLine(line: string | null): void { if (line === null) { this.currentSection = Section.EOF; return; @@ -290,10 +290,10 @@ export class SrtStreamParser { private _shouldSwallowBom: boolean = true; - private _currentDialogueNumber: string = null; - private _currentDialogueStart: string = null; - private _currentDialogueEnd: string = null; - private _currentDialogueText: string = null; + private _currentDialogueNumber: string | null = null; + private _currentDialogueStart: string | null = null; + private _currentDialogueEnd: string | null = null; + private _currentDialogueText: string | null = null; constructor(private _stream: Stream) { this._stream.nextLine().then(line => this._onNextLine(line), reason => { @@ -319,7 +319,7 @@ export class SrtStreamParser { /** * @param {string} line */ - private _onNextLine(line: string): void { + private _onNextLine(line: string | null): void { if (line === null) { if (this._currentDialogueNumber !== null && this._currentDialogueStart !== null && this._currentDialogueEnd !== null && this._currentDialogueText !== null) { this._ass.dialogues.push(new Dialogue(new Map([ diff --git a/src/parser/streams.ts b/src/parser/streams.ts index eda7bcf..d22059e 100644 --- a/src/parser/streams.ts +++ b/src/parser/streams.ts @@ -18,7 +18,7 @@ * limitations under the License. */ -import { Promise, DeferredPromise } from "../utility/promise"; +import { DeferredPromise, Promise } from "../utility/promise"; export interface ReadableStream { /** @@ -65,7 +65,7 @@ export interface Stream { /** * @return {!Promise.} A promise that will be resolved with the next line, or null if the stream is exhausted. */ - nextLine(): Promise; + nextLine(): Promise; } /** @@ -81,8 +81,8 @@ export class StringStream implements Stream { /** * @return {!Promise.} A promise that will be resolved with the next line, or null if the string has been completely read. */ - nextLine(): Promise { - let result: Promise; + nextLine(): Promise { + let result: Promise; if (this._readTill < this._str.length) { const nextNewLinePos = this._str.indexOf("\n", this._readTill); @@ -96,7 +96,7 @@ export class StringStream implements Stream { } } else { - result = Promise.resolve(null); + result = Promise.resolve(null); } return result; @@ -111,8 +111,8 @@ export class StringStream implements Stream { */ export class XhrStream implements Stream { private _readTill: number = 0; - private _pendingDeferred: DeferredPromise = null; - private _failedError: ErrorEvent = null; + private _pendingDeferred: DeferredPromise | null = null; + private _failedError: ErrorEvent | null = null; constructor(private _xhr: XMLHttpRequest) { _xhr.addEventListener("progress", () => this._onXhrProgress(), false); @@ -181,7 +181,7 @@ export class XhrStream implements Stream { */ private _tryResolveNextLine(): void { if (this._failedError !== null) { - this._pendingDeferred.reject(this._failedError); + this._pendingDeferred!.reject(this._failedError); return; } @@ -189,23 +189,23 @@ export class XhrStream implements Stream { const nextNewLinePos = response.indexOf("\n", this._readTill); if (nextNewLinePos !== -1) { - this._pendingDeferred.resolve(response.substring(this._readTill, nextNewLinePos)); + this._pendingDeferred!.resolve(response.substring(this._readTill, nextNewLinePos)); this._readTill = nextNewLinePos + 1; this._pendingDeferred = null; } else if (this._xhr.readyState === XMLHttpRequest.DONE) { if (this._failedError !== null) { - this._pendingDeferred.reject(this._failedError); + this._pendingDeferred!.reject(this._failedError); } // No more data. This is the last line. else if (this._readTill < response.length) { - this._pendingDeferred.resolve(response.substr(this._readTill)); + this._pendingDeferred!.resolve(response.substr(this._readTill)); this._readTill = response.length; } else { - this._pendingDeferred.resolve(null); + this._pendingDeferred!.resolve(null); } this._pendingDeferred = null; @@ -223,11 +223,11 @@ export class BrowserReadableStream implements Stream { private _reader: ReadableStreamReader; private _decoder: TextDecoder; private _buffer: string = ""; - private _pendingDeferred: DeferredPromise = null; + private _pendingDeferred: DeferredPromise | null = null; constructor(stream: ReadableStream, encoding: string) { this._reader = stream.getReader(); - this._decoder = new global.TextDecoder(encoding, { ignoreBOM: true }); + this._decoder = new global.TextDecoder!(encoding, { ignoreBOM: true }); } /** @@ -250,7 +250,7 @@ export class BrowserReadableStream implements Stream { private _tryResolveNextLine(): void { const nextNewLinePos = this._buffer.indexOf("\n"); if (nextNewLinePos !== -1) { - this._pendingDeferred.resolve(this._buffer.substr(0, nextNewLinePos)); + this._pendingDeferred!.resolve(this._buffer.substr(0, nextNewLinePos)); this._buffer = this._buffer.substr(nextNewLinePos + 1); this._pendingDeferred = null; } @@ -266,10 +266,10 @@ export class BrowserReadableStream implements Stream { else { // No more data. if (this._buffer.length === 0) { - this._pendingDeferred.resolve(null); + this._pendingDeferred!.resolve(null); } else { - this._pendingDeferred.resolve(this._buffer); + this._pendingDeferred!.resolve(this._buffer); this._buffer = ""; } diff --git a/src/parser/ttf.ts b/src/parser/ttf.ts index 51e37da..bdeaf3d 100644 --- a/src/parser/ttf.ts +++ b/src/parser/ttf.ts @@ -37,19 +37,22 @@ const fieldDecorators = new Map void>() @struct class OffsetTable { + /** @type {function(!{ dataView: DataView, position: number }): OffsetTable} */ + static read: (reader: DataReader) => OffsetTable; + /** @type {number} */ @field(DataType.Uint16) majorVersion: number; /** @type {number} */ @field(DataType.Uint16) minorVersion: number; /** @type {number} */ @field(DataType.Uint16) numTables: number; /** @type {number} */ @field(DataType.Uint16) searchRange: number; /** @type {number} */ @field(DataType.Uint16) entrySelector: number; /** @type {number} */ @field(DataType.Uint16) rangeShift: number; - - /** @type {function(!{ dataView: DataView, position: number }): OffsetTable} */ - static read: (reader: DataReader) => OffsetTable; } @struct class TableRecord { + /** @type {function(!{ dataView: DataView, position: number }): TableRecord} */ + static read: (reader: DataReader) => TableRecord; + /** @type {string} */ @field(DataType.Char) c1: string; /** @type {string} */ @field(DataType.Char) c2: string; /** @type {string} */ @field(DataType.Char) c3: string; @@ -57,32 +60,29 @@ class TableRecord { /** @type {number} */ @field(DataType.Uint32) checksum: number; /** @type {number} */ @field(DataType.Uint32) offset: number; /** @type {number} */ @field(DataType.Uint32) length: number; - - /** @type {function(!{ dataView: DataView, position: number }): TableRecord} */ - static read: (reader: DataReader) => TableRecord; } @struct class NameTableHeader { + /** @type {function(!{ dataView: DataView, position: number }): NameTableHeader} */ + static read: (reader: DataReader) => NameTableHeader; + /** @type {number} */ @field(DataType.Uint16) formatSelector: number; /** @type {number} */ @field(DataType.Uint16) count: number; /** @type {number} */ @field(DataType.Uint16) stringOffset: number; - - /** @type {function(!{ dataView: DataView, position: number }): NameTableHeader} */ - static read: (reader: DataReader) => NameTableHeader; } @struct class NameRecord { + /** @type {function(!{ dataView: DataView, position: number }): NameRecord} */ + static read: (reader: DataReader) => NameRecord; + /** @type {number} */ @field(DataType.Uint16) platformId: number; /** @type {number} */ @field(DataType.Uint16) encodingId: number; /** @type {number} */ @field(DataType.Uint16) languageId: number; /** @type {number} */ @field(DataType.Uint16) nameId: number; /** @type {number} */ @field(DataType.Uint16) length: number; /** @type {number} */ @field(DataType.Uint16) offset: number; - - /** @type {function(!{ dataView: DataView, position: number }): NameRecord} */ - static read: (reader: DataReader) => NameRecord; } /** @@ -103,7 +103,7 @@ export function getTtfNames(attachment: Attachment): Set { const reader = { dataView: new DataView(bytes.buffer), position: 0 }; const offsetTable = OffsetTable.read(reader); - let nameTableRecord: TableRecord = null; + let nameTableRecord: TableRecord | null = null; for (let i = 0; i < offsetTable.numTables; i++) { const tableRecord = TableRecord.read(reader); if (tableRecord.c1 + tableRecord.c2 + tableRecord.c3 + tableRecord.c4 === "name") { diff --git a/src/parts/index.ts b/src/parts/index.ts index 68684d1..90cced1 100644 --- a/src/parts/index.ts +++ b/src/parts/index.ts @@ -186,14 +186,14 @@ export class Italic { * @param {?boolean|?number} value {\b1} -> true, {\b0} -> false, {\b###} -> weight of the bold (number), {\b} -> null */ export class Bold { - constructor(private _value: boolean | number) { } + constructor(private _value: boolean | number | null) { } /** * The value of this bold tag. * * @type {?boolean|?number} */ - get value(): boolean | number { + get value(): boolean | number | null { return this._value; } } @@ -384,14 +384,14 @@ export class GaussianBlur { * @param {?string} value {\fn###} -> name (string), {\fn} -> null */ export class FontName { - constructor(private _value: string) { } + constructor(private _value: string | null) { } /** * The value of this font name tag. * * @type {?string} */ - get value(): string { + get value(): string | null { return this._value; } } @@ -456,14 +456,14 @@ export class FontSizeMinus { * @param {?number} value {\fscx###} -> scale (number), {\fscx} -> null */ export class FontScaleX { - constructor(private _value: number) { } + constructor(private _value: number | null) { } /** * The value of this horizontal font scaling tag. * * @type {?number} */ - get value(): number { + get value(): number | null { return this._value; } } @@ -474,14 +474,14 @@ export class FontScaleX { * @param {?number} value {\fscy###} -> scale (number), {\fscy} -> null */ export class FontScaleY { - constructor(private _value: number) { } + constructor(private _value: number | null) { } /** * The value of this vertical font scaling tag. * * @type {?number} */ - get value(): number { + get value(): number | null { return this._value; } } @@ -852,14 +852,14 @@ export class WrappingStyle { * @param {?string} value {\r###} -> style name (string), {\r} -> null */ export class Reset { - constructor(private _value: string) { } + constructor(private _value: string | null) { } /** * The value of this style reset tag. * * @type {?string} */ - get value(): string { + get value(): string | null { return this._value; } } @@ -903,7 +903,7 @@ export class Position { * @param {?number} t2 */ export class Move { - constructor(private _x1: number, private _y1: number, private _x2: number, private _y2: number, private _t1: number, private _t2: number) { } + constructor(private _x1: number, private _y1: number, private _x2: number, private _y2: number, private _t1: number | null, private _t2: number | null) { } /** * The starting x value of this move tag. @@ -946,7 +946,7 @@ export class Move { * * @type {?number} */ - get t1(): number { + get t1(): number | null { return this._t1; } @@ -955,7 +955,7 @@ export class Move { * * @type {?number} */ - get t2(): number { + get t2(): number | null { return this._t2; } } @@ -1106,14 +1106,14 @@ export class ComplexFade { * @param {!Array.} tags */ export class Transform { - constructor(private _start: number, private _end: number, private _accel: number, private _tags: Part[]) { } + constructor(private _start: number | null, private _end: number | null, private _accel: number | null, private _tags: Part[]) { } /** * The starting time of this transform tag. * * @type {?number} */ - get start(): number { + get start(): number | null { return this._start; } @@ -1122,7 +1122,7 @@ export class Transform { * * @type {?number} */ - get end(): number { + get end(): number | null { return this._end; } @@ -1131,7 +1131,7 @@ export class Transform { * * @type {?number} */ - get accel(): number { + get accel(): number | null { return this._accel; } @@ -1295,14 +1295,14 @@ export class DrawingInstructions { } } -const addToString = function (ctor: Function, ctorName: string) { +const addToString = function (ctor: Function, ctorName: string): void { if (!ctor.prototype.hasOwnProperty("toString")) { const propertyNames = Object.getOwnPropertyNames(ctor.prototype).filter(property => property !== "constructor"); - ctor.prototype.toString = function () { + ctor.prototype.toString = function (this: any): string { return ( ctorName + " { " + - propertyNames.map(name => `${ name }: ${ (this as any)[name] }`).join(", ") + + propertyNames.map(name => `${ name }: ${ this[name] }`).join(", ") + ((propertyNames.length > 0) ? " " : "") + "}" ); diff --git a/src/renderers/clocks/auto.ts b/src/renderers/clocks/auto.ts index 78fbe80..361d1f2 100644 --- a/src/renderers/clocks/auto.ts +++ b/src/renderers/clocks/auto.ts @@ -41,10 +41,10 @@ import { ManualClock } from "./manual"; export class AutoClock implements Clock { private _manualClock: ManualClock = new ManualClock(); - private _nextAnimationFrameRequestId: number = null; + private _nextAnimationFrameRequestId: number | null = null; - private _lastKnownExternalTime: number = null; - private _lastKnownExternalTimeObtainedAt: number = null; + private _lastKnownExternalTime: number | null = null; + private _lastKnownExternalTimeObtainedAt: number = 0; constructor(private _getCurrentTime: () => number, private _autoPauseAfter: number) { } @@ -213,7 +213,7 @@ export class AutoClock implements Clock { if (!this._manualClock.paused) { if (this._lastKnownExternalTime !== null && currentExternalTime === this._lastKnownExternalTime) { if (timeStamp - this._lastKnownExternalTimeObtainedAt > this._autoPauseAfter) { - this._lastKnownExternalTimeObtainedAt = null; + this._lastKnownExternalTimeObtainedAt = 0; this._manualClock.seek(currentExternalTime); } else { diff --git a/src/renderers/clocks/manual.ts b/src/renderers/clocks/manual.ts index 320b240..354a6cc 100644 --- a/src/renderers/clocks/manual.ts +++ b/src/renderers/clocks/manual.ts @@ -18,8 +18,8 @@ * limitations under the License. */ -import { mixin } from "../../utility/mixin"; import { Map } from "../../utility/map"; +import { mixin } from "../../utility/mixin"; import { Clock, ClockEvent, EventSource } from "./base"; diff --git a/src/renderers/default.ts b/src/renderers/default.ts index a6ff038..c96f92f 100644 --- a/src/renderers/default.ts +++ b/src/renderers/default.ts @@ -35,7 +35,7 @@ export class DefaultRenderer extends WebRenderer { constructor(private _video: HTMLVideoElement, ass: ASS, settings?: RendererSettings) { super(ass, new VideoClock(_video), document.createElement("div"), settings); - this._video.parentElement.replaceChild(this.libjassSubsWrapper, this._video); + this._video.parentElement!.replaceChild(this.libjassSubsWrapper, this._video); this.libjassSubsWrapper.insertBefore(this._video, this.libjassSubsWrapper.firstElementChild); } diff --git a/src/renderers/null.ts b/src/renderers/null.ts index e61828f..a5a76e6 100644 --- a/src/renderers/null.ts +++ b/src/renderers/null.ts @@ -18,15 +18,15 @@ * limitations under the License. */ -import { Clock, ClockEvent } from "./clocks/base"; - -import { RendererSettings } from "./settings"; - import { debugMode, verboseMode } from "../settings"; import { ASS } from "../types/ass"; import { Dialogue } from "../types/dialogue"; +import { Clock, ClockEvent } from "./clocks/base"; + +import { RendererSettings } from "./settings"; + /** * A renderer implementation that doesn't output anything. * @@ -35,7 +35,7 @@ import { Dialogue } from "../types/dialogue"; * @param {libjass.renderers.RendererSettings} settings */ export class NullRenderer { - private static _lastRendererId = -1; + private static _lastRendererId: number = -1; private _id: number; diff --git a/src/renderers/references.d.ts b/src/renderers/references.d.ts new file mode 100644 index 0000000..0844b39 --- /dev/null +++ b/src/renderers/references.d.ts @@ -0,0 +1,28 @@ +/** + * 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. + */ + +interface Array { + /** + * Returns the elements of an array that meet the condition specified in a callback function. + * @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array. + * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value. + */ + filter(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; +} diff --git a/src/renderers/settings.ts b/src/renderers/settings.ts index e06126a..85cee53 100644 --- a/src/renderers/settings.ts +++ b/src/renderers/settings.ts @@ -25,6 +25,77 @@ import { Map } from "../utility/map"; * Settings for the renderer. */ export class RendererSettings { + /** + * A convenience method to create a font map from a