serverFile function

String serverFile(
  1. ServerServer server,
  2. String formatter(
    1. Spec
    ), {
  3. required Options options,
})

Implementation

String serverFile(
  ServerServer server,
  String Function(Spec) formatter, {
  required Options options,
}) {
  final imports = [
    if (options.ignoreLints case final lints when lints.isNotEmpty)
      "// ignore_for_file: ${options.ignoreLints.join(', ')}\n",
    "import 'dart:io';",
    "import 'dart:async';",
    '',
    "import 'package:path/path.dart' as p;",
    for (final imprt in {
      if (server.context.mode.isDebug)
        'package:revali_construct/revali_construct.dart',
      'package:revali_router/revali_router.dart',
      ...server.packageImports(),
    })
      "import '$imprt';",
    '',
    for (final imprt in {...server.pathImports()}) "import '../../$imprt';",
  ];

  final app = server.app;
  if (app == null) {
    throw Exception('No app found');
  }

  final main = Method(
    (b) => b
      ..name = 'main'
      ..returns = refer('void')
      ..requiredParameters.add(
        Parameter(
          (b) => b
            ..name = 'args'
            ..type = refer('List<String>'),
        ),
      )
      ..body = Block.of([
        if (server.context.mode.isDebug)
          refer('hotReload').call([
            Method(
              (b) => b
                ..lambda = true
                ..body = refer(
                  'createServer',
                ).call([literalNull, refer('args')]).code,
            ).closure,
          ]).statement
        else
          refer('createServer').call([literalNull, refer('args')]).statement,
      ]),
  );

  final createServer = Method(
    (b) => b
      ..name = 'createServer'
      ..returns = TypeReference(
        (p) => p
          ..symbol = (Future).name
          ..types.add(refer((HttpServer).name)),
      )
      ..modifier = MethodModifier.async
      ..optionalParameters.addAll([
        Parameter(
          (e) => e
            ..name = 'providedServer'
            ..named = false
            ..type = refer('${(HttpServer).name}?'),
        ),
        Parameter(
          (e) => e
            ..name = 'rawArgs'
            ..named = false
            ..defaultTo = const Code('const []')
            ..type = refer('List<String>'),
        ),
      ])
      ..body = Block.of([
        declareFinal('args')
            .assign(
              refer((Args).name).newInstanceNamed('parse', [refer('rawArgs')]),
            )
            .statement,
        declareFinal(
          'app',
          type: refer((AppConfig).name),
        ).assign(createApp(app)).statement,
        refer('app')
            .property('runStartup')
            .call([
              Method(
                (b) => b
                  ..modifier = MethodModifier.async
                  ..body = Block.of([
                    declareFinal(
                      'server',
                      late: true,
                      type: refer('HttpServer'),
                    ).statement,
                    tryCatch(
                      refer('server')
                          .assign(
                            refer('providedServer').ifNullThen(
                              refer((HttpServer).name)
                                  .property(
                                    app.isSecure ? 'bindSecure' : 'bind',
                                  )
                                  .call(
                                    [
                                      refer('app').property('host'),
                                      refer('app').property('port'),
                                      if (app.isSecure)
                                        refer('app')
                                            .property('securityContext')
                                            .nullChecked,
                                    ],
                                    {
                                      if (app.isSecure)
                                        'requestClientCertificate': refer(
                                          'app',
                                        ).property('requestClientCertificate'),
                                      if (server.context.mode.isDebug)
                                        'shared': literalTrue,
                                    },
                                  )
                                  .awaited,
                            ),
                          )
                          .statement,
                      Block.of([
                        refer('print').call([
                          literalString(r'Failed to bind server:\n$e'),
                        ]).statement,
                        refer('exit').call([literalNum(1)]).statement,
                      ]),
                    ),
                    const Code('\n'),
                    ...createDependencyInjection(server),
                    const Code('\n'),
                    ...createRoutesVariable(server),
                    const Code('\n'),
                    Block.of([
                      const Code('if ('),
                      refer('app').property('prefix').code,
                      const Code(' case'),
                      declareFinal('prefix?').code,
                      const Code(' when '),
                      refer('prefix').property('isNotEmpty').code,
                      const Code(') {'),
                      refer('_routes')
                          .assign(
                            literalList([
                              refer((Route).name).newInstance(
                                [refer('prefix')],
                                {'routes': refer('_routes')},
                              ),
                            ]),
                          )
                          .statement,
                      const Code('}'),
                    ]),
                    const Code('\n'),
                    declareFinal('router')
                        .assign(
                          refer((Router).name).newInstance([], {
                            if (server.context.mode.isNotRelease)
                              'debug': literalTrue,
                            'routes': literalList([
                              refer('_routes').spread,
                              refer('public').spread,
                            ]),
                            if (app.observers.hasObservers)
                              'observers': literalList([
                                if (app.observers.types.expand((e) => e.types)
                                    case final observers
                                    when observers.isNotEmpty)
                                  for (final observer in observers)
                                    createClass(observer),
                                if (app.observers.mimics case final mimics
                                    when mimics.isNotEmpty)
                                  for (final type in mimics) createMimic(type),
                              ]),
                            'reflects': refer('reflects'),
                            'defaultResponses': refer(
                              'app',
                            ).property('defaultResponses'),
                            if (server.app case final app?
                                when app.globalRouteAnnotations.hasAnnotations)
                              'globalComponents':
                                  refer(
                                    (LifecycleComponentsImpl).name,
                                  ).newInstance([], {
                                    ...createModifierArgs(
                                      annotations: app.globalRouteAnnotations,
                                    ),
                                  }),
                          }),
                        )
                        .statement,
                    const Code('\n'),
                    refer('handleRequests')
                        .call([
                          refer('server'),
                          refer('router').property('handle'),
                          refer('router').property('responseHandler'),
                          refer('router').property('close'),
                        ])
                        .property('ignore')
                        .call([])
                        .statement,
                    const Code('\n'),
                    refer('app').property('onServerStarted').call([
                      refer('server'),
                    ]).statement,
                    const Code('\n'),
                    refer('server').returned.statement,
                  ]),
              ).closure,
            ])
            .returned
            .statement,
      ]),
  );

  final parts = <Spec>[main, createServer];

  final content = parts.map(formatter).join('\n');

  return '''
${imports.join('\n')}
$content''';
}