APISchema

 view release on metacpan or  search on metacpan

lib/APISchema/Generator/Markdown.pm  view on Meta::CPAN

package APISchema::Generator::Markdown;
use strict;
use warnings;

# lib
use APISchema::Generator::Markdown::Formatter;
use APISchema::Generator::Markdown::ExampleFormatter;
use APISchema::Generator::Markdown::ResourceResolver;

# cpan
use Text::MicroTemplate::DataSection qw();

sub new {
    my ($class) = @_;

    my $renderer = Text::MicroTemplate::DataSection->new(
        escape_func => undef
    );
    bless {
        renderer => $renderer,
        map {
            ( $_ => $renderer->build_file($_) );
        } qw(index toc route resource request response
             request_example response_example),
    }, $class;
}

sub resolve_encoding ($) {
    my ($resources) = @_;
    $resources = { body => $resources } unless ref $resources;
    my $encoding = $resources->{encoding} // { '' => 'auto' };
    $encoding = { '' => $encoding } unless ref $encoding;
    return { %$resources, encoding => $encoding };
}

sub format_schema {
    my ($self, $schema) = @_;

    my $renderer = $self->{renderer};
    my $routes = $schema->get_routes;
    my $resources = $schema->get_resources;

    my $root = $schema->get_resource_root;
    my $resolver = APISchema::Generator::Markdown::ResourceResolver->new(
        schema => $root,
    );
    return $self->{index}->(
        $renderer,
        $schema,
        $self->{toc}->(
            $renderer,
            $routes,
            $resources,
        ),
        join('', map {
            my $route = $_;
            my $req = resolve_encoding($route->request_resource);
            my $request_resource = $route->canonical_request_resource($root);

            my $codes = $route->responsible_codes;
            my $default_code = $route->default_responsible_code;
            my $response_resource = $route->canonical_response_resource($root, [
                $default_code
            ]);

            my $res = $_->response_resource;
            $res = $_->responsible_code_is_specified
                ? { map { $_ => resolve_encoding($res->{$_}) } @$codes }
                : { '' => resolve_encoding($res) };

            $self->{route}->(
                $renderer,
                $route,
                {
                    req =>  $self->{request_example}->(
                        $renderer,
                        $route,
                        APISchema::Generator::Markdown::ExampleFormatter->new(
                            resolver => $resolver,
                            spec     => $request_resource,
                        ),
                    ),
                    res => $self->{response_example}->(
                        $renderer,
                        $route,
                        $default_code,
                        APISchema::Generator::Markdown::ExampleFormatter->new(
                            resolver => $resolver,
                            spec     => $response_resource,
                        ),
                    ),
                },
                {
                    req => $self->{request}->($renderer, $route, $req),
                    res => join("\n", map {
                        $self->{response}->($renderer, $route, $_, $res->{$_});
                    } sort keys %$res),
                },
            );
        } @$routes),
        join('', map {
            my $properties = $resolver->properties($_->definition);
            $self->{resource}->($renderer, $resolver, $_, [ map { +{
                path => $_,
                definition => $properties->{$_},
            } } sort keys %$properties ]);
        } grep {
            ( $_->definition->{type} // '' ) ne 'hidden';
        } @$resources),
    );
}

1;
__DATA__
@@ index
? my ($schema, $toc_text, $routes_text, $resources_text) = @_;
# <?= $schema->title || '' ?>

?= $schema->description || ''

?= $toc_text

## <a name="routes"></a> Routes

?= $routes_text

## <a name="resources"></a> Resources

?= $resources_text

----------------------------------------------------------------
Generated by <?= __PACKAGE__ ?>

@@ toc
? my ($routes, $resources) = @_;

- [Routes](#routes)
? for (@$routes) {
    - [<?= $_->title ?>](#<?= anchor(route => $_->title) ?>) - <?= methods($_->method) ?> <?= $_->route ?>
? }
- [Resources](#resources)
? for (@$resources) {
?   next if ( $_->definition->{type} // '' ) eq 'hidden';
    - [<?= $_->title ?>](#<?= anchor(resource => $_->title) ?>)
? }

@@ route
? my ($route, $example, $text) = @_;
### <a name="<?= anchor(route => $route) ?>"></a> <?= $route->title ?>

?= $example->{req}
?= $example->{res}
?= $route->description || ''

?= $text->{req}

?= $text->{res}

@@ request_example
? my ($route, $example) = @_;
```
<?= method($route->method) ?> <?= $route->route ?><?= $example->parameter ?>
<?= $example->header_and_body ?>



( run in 0.667 second using v1.01-cache-2.11-cpan-39bf76dae61 )