Example #1
0
def generate_documentation(scheme_file):
    """Generates the documentation HTML files from from scheme.tl to /methods and /constructors, etc."""
    original_paths = {
        'css': 'css/docs.css',
        'arrow': 'img/arrow.svg',
        'index_all': 'index.html',
        'index_types': 'types/index.html',
        'index_methods': 'methods/index.html',
        'index_constructors': 'constructors/index.html'
    }
    tlobjects = tuple(TLParser.parse_file(scheme_file))

    print('Generating constructors and functions documentation...')

    # Save 'Type: [Constructors]' for use in both:
    # * Seeing the return type or constructors belonging to the same type.
    # * Generating the types documentation, showing available constructors.
    # TODO Tried using 'defaultdict(list)' with strange results, make it work.
    tltypes = {}
    tlfunctions = {}
    for tlobject in tlobjects:
        # Select to which dictionary we want to store this type
        dictionary = tlfunctions if tlobject.is_function else tltypes

        if tlobject.result in dictionary:
            dictionary[tlobject.result].append(tlobject)
        else:
            dictionary[tlobject.result] = [tlobject]

    for tltype, constructors in tltypes.items():
        tltypes[tltype] = list(sorted(constructors, key=lambda c: c.name))

    for tlobject in tlobjects:
        filename = get_create_path_for(tlobject)

        # Determine the relative paths for this file
        paths = get_relative_paths(original_paths, relative_to=filename)

        with DocsWriter(filename,
                        type_to_path_function=get_path_for_type) as docs:
            docs.write_head(title=get_class_name(tlobject),
                            relative_css_path=paths['css'])

            # Create the menu (path to the current TLObject)
            docs.set_menu_separator(paths['arrow'])
            build_menu(docs, filename, relative_main_index=paths['index_all'])

            # Create the page title
            docs.write_title(get_class_name(tlobject))

            # Write the code definition for this TLObject
            docs.write_code(tlobject)
            docs.write_copy_button('Copy import to the clipboard',
                                   get_import_code(tlobject))

            # Write the return type (or constructors belonging to the same type)
            docs.write_title(
                'Returns' if tlobject.is_function else 'Belongs to', level=3)

            generic_arg = next(
                (arg.name for arg in tlobject.args if arg.generic_definition),
                None)

            if tlobject.result == generic_arg:
                # We assume it's a function returning a generic type
                generic_arg = next(
                    (arg.name for arg in tlobject.args if arg.is_generic))
                docs.write_text('This function returns the result of whatever '
                                'the result from invoking the request passed '
                                'through <i>{}</i> is.'.format(generic_arg))
            else:
                if re.search('^vector<', tlobject.result, re.IGNORECASE):
                    docs.write_text(
                        'A list of the following type is returned.')
                    _, inner = tlobject.result.split('<')
                    inner = inner.strip('>')
                else:
                    inner = tlobject.result

                docs.begin_table(column_count=1)
                docs.add_row(inner,
                             link=get_path_for_type(inner,
                                                    relative_to=filename))
                docs.end_table()

                constructors = tltypes.get(inner, [])
                if not constructors:
                    docs.write_text('This type has no instances available.')
                elif len(constructors) == 1:
                    docs.write_text('This type can only be an instance of:')
                else:
                    docs.write_text('This type can be an instance of either:')

                docs.begin_table(column_count=2)
                for constructor in constructors:
                    link = get_create_path_for(constructor)
                    link = get_relative_path(link, relative_to=filename)
                    docs.add_row(get_class_name(constructor), link=link)
                docs.end_table()

            # Return (or similar types) written. Now parameters/members
            docs.write_title(
                'Parameters' if tlobject.is_function else 'Members', level=3)

            # Sort the arguments in the same way they're sorted on the generated code (flags go last)
            args = [
                a for a in tlobject.sorted_args()
                if not a.flag_indicator and not a.generic_definition
            ]

            if args:
                # Writing parameters
                docs.begin_table(column_count=3)

                for arg in args:
                    # Name row
                    docs.add_row(arg.name, bold=True)

                    # Type row
                    if arg.is_generic:
                        docs.add_row('!' + arg.type, align='center')
                    else:
                        docs.add_row(arg.type,
                                     link=get_path_for_type(
                                         arg.type, relative_to=filename),
                                     align='center')

                    # Create a description for this argument
                    description = ''
                    if arg.can_be_inferred:
                        description += 'If left to None, it will be inferred automatically. '
                    if arg.is_vector:
                        description += 'A list must be supplied for this argument. '
                    if arg.is_generic:
                        description += 'A different MTProtoRequest must be supplied for this argument. '
                    if arg.is_flag:
                        description += 'This argument can be omitted. '

                    docs.add_row(description.strip())

                docs.end_table()
            else:
                if tlobject.is_function:
                    docs.write_text('This request takes no input parameters.')
                else:
                    docs.write_text('This type has no members.')

            docs.end_body()

    # Find all the available types (which are not the same as the constructors)
    # Each type has a list of constructors associated to it, so it should be a map
    print('Generating types documentation...')
    for tltype, constructors in tltypes.items():
        filename = get_path_for_type(tltype)
        out_dir = os.path.dirname(filename)
        os.makedirs(out_dir, exist_ok=True)

        # Since we don't have access to the full TLObject, split the type into namespace.name
        if '.' in tltype:
            namespace, name = tltype.split('.')
        else:
            namespace, name = None, tltype

        # Determine the relative paths for this file
        paths = get_relative_paths(original_paths, relative_to=out_dir)

        with DocsWriter(filename,
                        type_to_path_function=get_path_for_type) as docs:
            docs.write_head(title=get_class_name(name),
                            relative_css_path=paths['css'])

            docs.set_menu_separator(paths['arrow'])
            build_menu(docs, filename, relative_main_index=paths['index_all'])

            # Main file title
            docs.write_title(get_class_name(name))

            # List available constructors for this type
            docs.write_title('Available constructors', level=3)
            if not constructors:
                docs.write_text('This type has no constructors available.')
            elif len(constructors) == 1:
                docs.write_text('This type has one constructor available.')
            else:
                docs.write_text('This type has %d constructors available.' %
                                len(constructors))

            docs.begin_table(2)
            for constructor in constructors:
                # Constructor full name
                link = get_create_path_for(constructor)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(constructor), link=link)
            docs.end_table()

            # List all the methods which return this type
            docs.write_title('Methods returning this type', level=3)
            functions = tlfunctions.get(tltype, [])
            if not functions:
                docs.write_text('No method returns this type.')
            elif len(functions) == 1:
                docs.write_text('Only the following method returns this type.')
            else:
                docs.write_text(
                    'The following %d methods return this type as a result.' %
                    len(functions))

            docs.begin_table(2)
            for func in functions:
                link = get_create_path_for(func)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(func), link=link)
            docs.end_table()

            # List every other type which has this type as a member
            docs.write_title('Other types containing this type', level=3)
            other_types = sorted(
                (t
                 for t in tlobjects if any(tltype == a.type for a in t.args)),
                key=lambda t: t.name)

            if not other_types:
                docs.write_text('No other types have a member of this type.')
            elif len(other_types) == 1:
                docs.write_text(
                    'You can find this type as a member of this other type.')
            else:
                docs.write_text('You can find this type as a member of any of '
                                'the following %d types.' % len(other_types))

            docs.begin_table(2)
            for ot in other_types:
                link = get_create_path_for(ot)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(ot), link=link)
            docs.end_table()
            docs.end_body()

    # After everything's been written, generate an index.html file for every folder.
    # This will be done automatically and not taking into account any additional
    # information that we have available, simply a file listing all the others
    # accessible by clicking on their title
    print('Generating indices...')
    for folder in ['types', 'methods', 'constructors']:
        generate_index(folder, original_paths)

    # Write the final core index, the main index for the rest of files
    layer = TLParser.find_layer(scheme_file)
    types = set()
    methods = []
    for tlobject in tlobjects:
        if tlobject.is_function:
            methods.append(tlobject)

        types.add(tlobject.result)

    types = sorted(types)
    methods = sorted(methods, key=lambda m: m.name)

    request_names = ', '.join('"' + get_class_name(m) + '"' for m in methods)
    type_names = ', '.join('"' + get_class_name(t) + '"' for t in types)

    request_urls = ', '.join('"' + get_create_path_for(m) + '"'
                             for m in methods)
    type_urls = ', '.join('"' + get_path_for_type(t) + '"' for t in types)

    replace_dict = {
        'type_count': len(types),
        'method_count': len(methods),
        'constructor_count': len(tlobjects) - len(methods),
        'layer': layer,
        'request_names': request_names,
        'type_names': type_names,
        'request_urls': request_urls,
        'type_urls': type_urls
    }

    with open('../res/core.html') as infile:
        with open(original_paths['index_all'], 'w') as outfile:
            text = infile.read()
            for key, value in replace_dict.items():
                text = text.replace('{' + key + '}', str(value))

            outfile.write(text)

    # Everything done
    print('Documentation generated.')
Example #2
0
def generate_documentation(scheme_file):
    """Generates the documentation HTML files from from scheme.tl to
       /methods and /constructors, etc.
    """
    original_paths = {
        'css': 'css/docs.css',
        'arrow': 'img/arrow.svg',
        'search.js': 'js/search.js',
        '404': '404.html',
        'index_all': 'index.html',
        'index_types': 'types/index.html',
        'index_methods': 'methods/index.html',
        'index_constructors': 'constructors/index.html'
    }
    tlobjects = tuple(TLParser.parse_file(scheme_file))

    print('Generating constructors and functions documentation...')

    # Save 'Type: [Constructors]' for use in both:
    # * Seeing the return type or constructors belonging to the same type.
    # * Generating the types documentation, showing available constructors.
    # TODO Tried using 'defaultdict(list)' with strange results, make it work.
    tltypes = {}
    tlfunctions = {}
    for tlobject in tlobjects:
        # Select to which dictionary we want to store this type
        dictionary = tlfunctions if tlobject.is_function else tltypes

        if tlobject.result in dictionary:
            dictionary[tlobject.result].append(tlobject)
        else:
            dictionary[tlobject.result] = [tlobject]

    for tltype, constructors in tltypes.items():
        tltypes[tltype] = list(sorted(constructors, key=lambda c: c.name))

    for tlobject in tlobjects:
        filename = get_create_path_for(tlobject)

        # Determine the relative paths for this file
        paths = get_relative_paths(original_paths, relative_to=filename)

        with DocsWriter(filename, type_to_path_function=get_path_for_type) \
                as docs:
            docs.write_head(title=get_class_name(tlobject),
                            relative_css_path=paths['css'])

            # Create the menu (path to the current TLObject)
            docs.set_menu_separator(paths['arrow'])
            build_menu(docs, filename, relative_main_index=paths['index_all'])

            # Create the page title
            docs.write_title(get_class_name(tlobject))

            # Write the code definition for this TLObject
            docs.write_code(tlobject)
            docs.write_copy_button('Copy import to the clipboard',
                                   get_import_code(tlobject))

            # Write the return type (or constructors belonging to the same type)
            docs.write_title(
                'Returns' if tlobject.is_function else 'Belongs to', level=3)

            generic_arg = next(
                (arg.name for arg in tlobject.args if arg.generic_definition),
                None)

            if tlobject.result == generic_arg:
                # We assume it's a function returning a generic type
                generic_arg = next(
                    (arg.name for arg in tlobject.args if arg.is_generic))
                docs.write_text('This function returns the result of whatever '
                                'the result from invoking the request passed '
                                'through <i>{}</i> is.'.format(generic_arg))
            else:
                if re.search('^vector<', tlobject.result, re.IGNORECASE):
                    docs.write_text(
                        'A list of the following type is returned.')
                    _, inner = tlobject.result.split('<')
                    inner = inner.strip('>')
                else:
                    inner = tlobject.result

                docs.begin_table(column_count=1)
                docs.add_row(inner,
                             link=get_path_for_type(inner,
                                                    relative_to=filename))
                docs.end_table()

                constructors = tltypes.get(inner, [])
                if not constructors:
                    docs.write_text('This type has no instances available.')
                elif len(constructors) == 1:
                    docs.write_text('This type can only be an instance of:')
                else:
                    docs.write_text('This type can be an instance of either:')

                docs.begin_table(column_count=2)
                for constructor in constructors:
                    link = get_create_path_for(constructor)
                    link = get_relative_path(link, relative_to=filename)
                    docs.add_row(get_class_name(constructor), link=link)
                docs.end_table()

            # Return (or similar types) written. Now parameters/members
            docs.write_title(
                'Parameters' if tlobject.is_function else 'Members', level=3)

            # Sort the arguments in the same way they're sorted
            # on the generated code (flags go last)
            args = [
                a for a in tlobject.sorted_args()
                if not a.flag_indicator and not a.generic_definition
            ]

            if args:
                # Writing parameters
                docs.begin_table(column_count=3)

                for arg in args:
                    # Name row
                    docs.add_row(arg.name, bold=True)

                    # Type row
                    if arg.is_generic:
                        docs.add_row('!' + arg.type, align='center')
                    else:
                        docs.add_row(arg.type,
                                     align='center',
                                     link=get_path_for_type(
                                         arg.type, relative_to=filename))

                    # Add a description for this argument
                    docs.add_row(get_description(arg))

                docs.end_table()
            else:
                if tlobject.is_function:
                    docs.write_text('This request takes no input parameters.')
                else:
                    docs.write_text('This type has no members.')

            # TODO Bit hacky, make everything like this? (prepending '../')
            depth = '../' * (2 if tlobject.namespace else 1)
            docs.add_script(src='prependPath = "{}";'.format(depth))
            docs.add_script(relative_src=paths['search.js'])
            docs.end_body()

    # Find all the available types (which are not the same as the constructors)
    # Each type has a list of constructors associated to it, hence is a map
    print('Generating types documentation...')
    for tltype, constructors in tltypes.items():
        filename = get_path_for_type(tltype)
        out_dir = os.path.dirname(filename)
        if out_dir:
            os.makedirs(out_dir, exist_ok=True)

        # Since we don't have access to the full TLObject, split the type
        if '.' in tltype:
            namespace, name = tltype.split('.')
        else:
            namespace, name = None, tltype

        # Determine the relative paths for this file
        paths = get_relative_paths(original_paths, relative_to=out_dir)

        with DocsWriter(filename, type_to_path_function=get_path_for_type) \
                as docs:
            docs.write_head(title=get_class_name(name),
                            relative_css_path=paths['css'])

            docs.set_menu_separator(paths['arrow'])
            build_menu(docs, filename, relative_main_index=paths['index_all'])

            # Main file title
            docs.write_title(get_class_name(name))

            # List available constructors for this type
            docs.write_title('Available constructors', level=3)
            if not constructors:
                docs.write_text('This type has no constructors available.')
            elif len(constructors) == 1:
                docs.write_text('This type has one constructor available.')
            else:
                docs.write_text('This type has %d constructors available.' %
                                len(constructors))

            docs.begin_table(2)
            for constructor in constructors:
                # Constructor full name
                link = get_create_path_for(constructor)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(constructor), link=link)
            docs.end_table()

            # List all the methods which return this type
            docs.write_title('Methods returning this type', level=3)
            functions = tlfunctions.get(tltype, [])
            if not functions:
                docs.write_text('No method returns this type.')
            elif len(functions) == 1:
                docs.write_text('Only the following method returns this type.')
            else:
                docs.write_text(
                    'The following %d methods return this type as a result.' %
                    len(functions))

            docs.begin_table(2)
            for func in functions:
                link = get_create_path_for(func)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(func), link=link)
            docs.end_table()

            # List all the methods which take this type as input
            docs.write_title('Methods accepting this type as input', level=3)
            other_methods = sorted(
                (t
                 for t in tlobjects if any(tltype == a.type
                                           for a in t.args) and t.is_function),
                key=lambda t: t.name)
            if not other_methods:
                docs.write_text(
                    'No methods accept this type as an input parameter.')
            elif len(other_methods) == 1:
                docs.write_text(
                    'Only this method has a parameter with this type.')
            else:
                docs.write_text(
                    'The following %d methods accept this type as an input '
                    'parameter.' % len(other_methods))

            docs.begin_table(2)
            for ot in other_methods:
                link = get_create_path_for(ot)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(ot), link=link)
            docs.end_table()

            # List every other type which has this type as a member
            docs.write_title('Other types containing this type', level=3)
            other_types = sorted(
                (t for t in tlobjects
                 if any(tltype == a.type
                        for a in t.args) and not t.is_function),
                key=lambda t: t.name)

            if not other_types:
                docs.write_text('No other types have a member of this type.')
            elif len(other_types) == 1:
                docs.write_text(
                    'You can find this type as a member of this other type.')
            else:
                docs.write_text('You can find this type as a member of any of '
                                'the following %d types.' % len(other_types))

            docs.begin_table(2)
            for ot in other_types:
                link = get_create_path_for(ot)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(ot), link=link)
            docs.end_table()
            docs.end_body()

    # After everything's been written, generate an index.html per folder.
    # This will be done automatically and not taking into account any extra
    # information that we have available, simply a file listing all the others
    # accessible by clicking on their title
    print('Generating indices...')
    for folder in ['types', 'methods', 'constructors']:
        generate_index(folder, original_paths)

    # Write the final core index, the main index for the rest of files
    layer = TLParser.find_layer(scheme_file)
    types = set()
    methods = []
    constructors = []
    for tlobject in tlobjects:
        if tlobject.is_function:
            methods.append(tlobject)
        else:
            constructors.append(tlobject)

        if not is_core_type(tlobject.result):
            if re.search('^vector<', tlobject.result, re.IGNORECASE):
                types.add(tlobject.result.split('<')[1].strip('>'))
            else:
                types.add(tlobject.result)

    types = sorted(types)
    methods = sorted(methods, key=lambda m: m.name)
    constructors = sorted(constructors, key=lambda c: c.name)

    def fmt(xs):
        ys = {x: get_class_name(x) for x in xs}  # cache TLObject: display
        zs = {}  # create a dict to hold those which have duplicated keys
        for y in ys.values():
            zs[y] = y in zs
        return ', '.join(
            '"{}.{}"'.format(x.namespace, ys[x]) if zs[ys[x]]
            and getattr(x, 'namespace', None) else '"{}"'.format(ys[x])
            for x in xs)

    request_names = fmt(methods)
    type_names = fmt(types)
    constructor_names = fmt(constructors)

    def fmt(xs, formatter):
        return ', '.join('"{}"'.format(formatter(x)) for x in xs)

    request_urls = fmt(methods, get_create_path_for)
    type_urls = fmt(types, get_path_for_type)
    constructor_urls = fmt(constructors, get_create_path_for)

    shutil.copy('../res/404.html', original_paths['404'])
    copy_replace(
        '../res/core.html', original_paths['index_all'], {
            '{type_count}': len(types),
            '{method_count}': len(methods),
            '{constructor_count}': len(tlobjects) - len(methods),
            '{layer}': layer,
        })
    os.makedirs(os.path.abspath(
        os.path.join(original_paths['search.js'], os.path.pardir)),
                exist_ok=True)
    copy_replace(
        '../res/js/search.js', original_paths['search.js'], {
            '{request_names}': request_names,
            '{type_names}': type_names,
            '{constructor_names}': constructor_names,
            '{request_urls}': request_urls,
            '{type_urls}': type_urls,
            '{constructor_urls}': constructor_urls
        })

    # Everything done
    print('Documentation generated.')
Example #3
0
def generate_documentation(scheme_file):
    """Generates the documentation HTML files from from scheme.tl to /methods and /constructors, etc."""
    original_paths = {
        'css': 'css/docs.css',
        'arrow': 'img/arrow.svg',
        'index_all': 'index.html',
        'index_types': 'types/index.html',
        'index_methods': 'methods/index.html',
        'index_constructors': 'constructors/index.html'
    }

    tlobjects = tuple(TLParser.parse_file(scheme_file))

    print('Generating constructors and functions documentation...')
    for tlobject in tlobjects:
        filename = get_create_path_for(tlobject)

        # Determine the relative paths for this file
        paths = get_relative_paths(original_paths, relative_to=filename)

        with DocsWriter(filename,
                        type_to_path_function=get_path_for_type) as docs:
            docs.write_head(title=get_class_name(tlobject),
                            relative_css_path=paths['css'])

            # Create the menu (path to the current TLObject)
            docs.set_menu_separator(paths['arrow'])
            build_menu(docs, filename, relative_main_index=paths['index_all'])

            # Create the page title
            docs.write_title(get_class_name(tlobject))

            # Write the code definition for this TLObject
            docs.write_code(tlobject)

            docs.write_title(
                'Parameters' if tlobject.is_function else 'Members', level=3)

            # Sort the arguments in the same way they're sorted on the generated code (flags go last)
            args = sorted([
                a for a in tlobject.args
                if not a.flag_indicator and not a.generic_definition
            ],
                          key=lambda a: a.is_flag)
            if args:
                # Writing parameters
                docs.begin_table(column_count=3)

                for arg in args:
                    # Name row
                    docs.add_row(arg.name, bold=True)

                    # Type row
                    if arg.is_generic:
                        docs.add_row('!' + arg.type, align='center')
                    else:
                        docs.add_row(arg.type,
                                     link=get_path_for_type(
                                         arg.type, relative_to=filename),
                                     align='center')

                    # Create a description for this argument
                    description = ''
                    if arg.is_vector:
                        description += 'A list must be supplied for this argument. '
                    if arg.is_generic:
                        description += 'A different MTProtoRequest must be supplied for this argument. '
                    if arg.is_flag:
                        description += 'This argument can be omitted. '

                    docs.add_row(description.strip())

                docs.end_table()
            else:
                if tlobject.is_function:
                    docs.write_text('This request takes no input parameters.')
                else:
                    docs.write_text('This type has no members.')

            docs.end_body()

    # Find all the available types (which are not the same as the constructors)
    # Each type has a list of constructors associated to it, so it should be a map
    print('Generating types documentation...')
    tltypes = {}
    tlfunctions = {}
    for tlobject in tlobjects:
        # Select to which dictionary we want to store this type
        dictionary = tlfunctions if tlobject.is_function else tltypes

        if tlobject.result in dictionary:
            dictionary[tlobject.result].append(tlobject)
        else:
            dictionary[tlobject.result] = [tlobject]

    for tltype, constructors in tltypes.items():
        filename = get_path_for_type(tltype)
        out_dir = os.path.dirname(filename)
        os.makedirs(out_dir, exist_ok=True)

        # Since we don't have access to the full TLObject, split the type into namespace.name
        if '.' in tltype:
            namespace, name = tltype.split('.')
        else:
            namespace, name = None, tltype

        # Determine the relative paths for this file
        paths = get_relative_paths(original_paths, relative_to=out_dir)

        with DocsWriter(filename,
                        type_to_path_function=get_path_for_type) as docs:
            docs.write_head(title=get_class_name(name),
                            relative_css_path=paths['css'])

            docs.set_menu_separator(paths['arrow'])
            build_menu(docs, filename, relative_main_index=paths['index_all'])

            # Main file title
            docs.write_title(get_class_name(name))

            docs.write_title('Available constructors', level=3)
            if not constructors:
                docs.write_text('This type has no constructors available.')
            elif len(constructors) == 1:
                docs.write_text('This type has one constructor available.')
            else:
                docs.write_text('This type has %d constructors available.' %
                                len(constructors))

            docs.begin_table(2)
            for constructor in constructors:
                # Constructor full name
                link = get_create_path_for(constructor)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(constructor), link=link)
            docs.end_table()

            docs.write_title('Methods returning this type', level=3)
            functions = tlfunctions.get(tltype, [])
            if not functions:
                docs.write_text('No method returns this type.')
            elif len(functions) == 1:
                docs.write_text('Only the following method returns this type.')
            else:
                docs.write_text(
                    'The following %d methods return this type as a result.' %
                    len(functions))

            docs.begin_table(2)
            for func in functions:
                link = get_create_path_for(func)
                link = get_relative_path(link, relative_to=filename)
                docs.add_row(get_class_name(func), link=link)
            docs.end_table()
            docs.end_body()

    # After everything's been written, generate an index.html file for every folder.
    # This will be done automatically and not taking into account any additional
    # information that we have available, simply a file listing all the others
    # accessible by clicking on their title
    print('Generating indices...')
    for folder in ['types', 'methods', 'constructors']:
        generate_index(folder, original_paths)

    # Write the final core index, the main index for the rest of files
    layer = TLParser.find_layer(scheme_file)
    types = set()
    methods = []
    for tlobject in tlobjects:
        if tlobject.is_function:
            methods.append(tlobject)

        types.add(tlobject.result)

    types = sorted(types)
    methods = sorted(methods, key=lambda m: m.name)

    request_names = ', '.join('"' + get_class_name(m) + '"' for m in methods)
    type_names = ', '.join('"' + get_class_name(t) + '"' for t in types)

    request_urls = ', '.join('"' + get_create_path_for(m) + '"'
                             for m in methods)
    type_urls = ', '.join('"' + get_path_for_type(t) + '"' for t in types)

    replace_dict = {
        'type_count': len(types),
        'method_count': len(methods),
        'constructor_count': len(tlobjects) - len(methods),
        'layer': layer,
        'request_names': request_names,
        'type_names': type_names,
        'request_urls': request_urls,
        'type_urls': type_urls
    }

    with open('../res/core.html') as infile:
        with open(original_paths['index_all'], 'w') as outfile:
            text = infile.read()
            for key, value in replace_dict.items():
                text = text.replace('{' + key + '}', str(value))

            outfile.write(text)

    # Everything done
    print('Documentation generated.')