let visit = function()

in jsstub-generator/generate.ts [313:510]


let visit = function(sourceFile: ts.SourceFile, modulePrefix: string, iface: string) {
    return (node: ts.Node) => {
        switch (node.kind) {
            // Handle type aliases so that they can be resolved after parsing is done
            case ts.SyntaxKind.TypeAliasDeclaration:
                result.getModule(modulePrefix).aliases.set(
                    (node as ts.TypeAliasDeclaration).name.getText(),
                    (node as ts.TypeAliasDeclaration).type
                );
                break;
            // Handle variable declarations - they are assumed to be instances
            // declared at the module level
            case ts.SyntaxKind.VariableStatement:
                {
                    (<ts.VariableStatement>node).declarationList.declarations.forEach(decl => {
                        let declName = decl.name.getText();
                        if (declName !== '.prototype' && declName !== '.constructor') {
                            let propertySymbol = checker.getSymbolAtLocation(decl);
                            let propertydoc = '';
                            if (propertySymbol) {
                                propertydoc = ts.displayPartsToString(propertySymbol.getDocumentationComment(checker));
                            }

                            const propertyInfo = new MemberInfo(
                                false,
                                decl.type!,
                                propertydoc,
                                sourceFile.fileName
                            );

                            result.getModule(modulePrefix).variables.set(declName, propertyInfo);
                        };
                    });
                }
                break;
            // Handle function declarations - they are assumed to be unbound
            // functions declared at the module level
            case ts.SyntaxKind.FunctionDeclaration:
                if ((<ts.FunctionDeclaration>node).name) {
                    let functionName = propertyNameToString((<ts.FunctionDeclaration>node).name!);
                    let functionSymbol = ((node as any).symbol as ts.Symbol);

                    const parameters: { name: string, type: ts.TypeNode, doc: string, optional: boolean }[] = [];

                    for (const param of (<ts.MethodSignature>node).parameters) {
                        if (param.name.getText() == 'this') {
                            continue;
                        }
                        let paramSymbol = ((param as any).symbol) as ts.Symbol;
                        parameters.push({
                            name: param.name.getText(),
                            type: param.type!,
                            doc: ts.displayPartsToString(paramSymbol.getDocumentationComment(checker)),
                            optional: !!param.questionToken
                        });
                    }

                    const functionInfo = new MemberInfo(
                        true,
                        (<ts.PropertySignature>node).type!,
                        ts.displayPartsToString(functionSymbol.getDocumentationComment(checker)),
                        sourceFile.fileName,
                        parameters
                    );

                    result.getModule(modulePrefix).functions.set(functionName, functionInfo);
                }
                break;
            // Handle constructors
            case ts.SyntaxKind.ConstructSignature:
                const parameters: { name: string, type: ts.TypeNode, doc: string, optional: boolean }[] = [];

                for (const param of (<ts.ConstructSignatureDeclaration>node).parameters) {
                    if (param.name.getText() == 'this') {
                        continue;
                    }
                    let paramSymbol = ((param as any).symbol) as ts.Symbol;
                    parameters.push({
                        name: param.name.getText(),
                        type: param.type!,
                        doc: ts.displayPartsToString(paramSymbol.getDocumentationComment(checker)),
                        optional: !!param.questionToken
                    });
                }

                let ifaceBase = iface;
                if(iface.endsWith('Constructor')) {
                    ifaceBase = iface.substring(0, iface.length - 11);
                }

                const mi = new MemberInfo(
                    true,
                     (<ts.ConstructSignatureDeclaration>node).type!,
                     '',
                     sourceFile.fileName,
                     parameters
                );

                result.getModule(modulePrefix).getClass(ifaceBase).addFile(sourceFile.fileName);
                result.getModule(modulePrefix).getClass(ifaceBase).constructorInfo.push(mi);

                break;
            // Handle methods
            case ts.SyntaxKind.MethodSignature:
                let functionName = propertyNameToString((<ts.MethodSignature>node).name);
                if (functionName !== '.prototype' && functionName !== '.constructor') {
                    let functionSymbol = ((node as any).symbol as ts.Symbol);

                    const parameters: { name: string, type: ts.TypeNode, doc: string, optional: boolean }[] = [];

                    for (const param of (<ts.MethodSignature>node).parameters) {
                        if (param.name.getText() == 'this') {
                            continue;
                        }
                        let paramSymbol = ((param as any).symbol) as ts.Symbol;
                        parameters.push({
                            name: param.name.getText(),
                            type: param.type!,
                            doc: ts.displayPartsToString(paramSymbol.getDocumentationComment(checker)),
                            optional: !!param.questionToken
                        });
                    }

                    const functionInfo = new MemberInfo(
                        true,
                        (<ts.PropertySignature>node).type!,
                        ts.displayPartsToString(functionSymbol.getDocumentationComment(checker)),
                        sourceFile.fileName,
                        parameters
                    );

                    result.getModule(modulePrefix).getClass(iface).addFile(sourceFile.fileName);
                    result.getModule(modulePrefix).getClass(iface).properties.set(functionName, functionInfo);
                }
                break;
            // Handle properties
            case ts.SyntaxKind.PropertySignature:
                let propertyName = propertyNameToString((<ts.PropertySignature>node).name);
                if (propertyName !== '.prototype' && propertyName !== '.constructor') {
                    let propertySymbol = checker.getSymbolAtLocation(node);
                    let propertydoc = '';
                    if (propertySymbol) {
                        propertydoc = ts.displayPartsToString(propertySymbol.getDocumentationComment(checker));
                    }

                    const propertyInfo = new MemberInfo(
                        false,
                        (<ts.PropertySignature>node).type!,
                        propertydoc,
                        sourceFile.fileName
                    );

                    result.getModule(modulePrefix).getClass(iface).addFile(sourceFile.fileName);
                    result.getModule(modulePrefix).getClass(iface).properties.set(propertyName, propertyInfo);
                }
                break;
            // Handle module declarations - only handled to extract the name of the module
            case ts.SyntaxKind.ModuleDeclaration:
                let moduleName = (<ts.ModuleDeclaration>node).name.text;
                modulePrefix = moduleName;
                break;
            // Handle interface declaration
            case ts.SyntaxKind.InterfaceDeclaration:
                iface = (<ts.InterfaceDeclaration>node).name.text;
                break;

            default:
        }
        switch (node.kind) {
            // For modules decend into their children
            case ts.SyntaxKind.ModuleBlock:
                ts.forEachChild(node, visit(sourceFile, modulePrefix, iface));
                break;
            case ts.SyntaxKind.ModuleDeclaration:
                ts.forEachChild(node, visit(sourceFile, modulePrefix, iface));
                modulePrefix = '';
                break;
            // For interfaces decend into their children and extract the inheritence tree
            case ts.SyntaxKind.InterfaceDeclaration:
                ts.forEachChild(node, visit(sourceFile, modulePrefix, iface));
                const id = node as ts.InterfaceDeclaration;
                let idSymbol = ((id as any).symbol) as ts.Symbol;
                let idDoc = '';
                if (idSymbol) {
                    idDoc = ts.displayPartsToString(idSymbol.getDocumentationComment(checker));
                    result.getModule(modulePrefix).getClass(iface).doc = idDoc;
                }
                result.getModule(modulePrefix).getClass(iface).addFile(sourceFile.fileName);
                if (id.heritageClauses) {
                    id.heritageClauses.forEach(hc => {
                        hc.types.forEach(t => result.getModule(modulePrefix).getClass(iface).addInterits(t.expression.getText()));
                    });
                }
                iface = '';
                break;
        }
    }
};