Upstream dedoc/scramble state of the touched files before c327325c7c
This commit is contained in:
1 parent
e6f2982a99
commit
185af03608
1 file changed
+421
@@ -0,0 +1,421 @@
|
||||
<?php
|
||||
|
||||
namespace Dedoc\Scramble;
|
||||
|
||||
use Dedoc\Scramble\Configuration\GeneratorConfigCollection;
|
||||
use Dedoc\Scramble\Configuration\OperationTransformers;
|
||||
use Dedoc\Scramble\Configuration\ParametersExtractors;
|
||||
use Dedoc\Scramble\Console\Commands\AnalyzeDocumentation;
|
||||
use Dedoc\Scramble\Console\Commands\CacheDocumentation;
|
||||
use Dedoc\Scramble\Console\Commands\ClearDocumentationCache;
|
||||
use Dedoc\Scramble\Console\Commands\ExportDocumentation;
|
||||
use Dedoc\Scramble\Contracts\RouteProvider as RouteProviderContract;
|
||||
use Dedoc\Scramble\DocumentTransformers\AddDocumentTags;
|
||||
use Dedoc\Scramble\DocumentTransformers\CleanupUnusedResponseReferencesTransformer;
|
||||
use Dedoc\Scramble\Extensions\ExceptionToResponseExtension;
|
||||
use Dedoc\Scramble\Extensions\OperationExtension;
|
||||
use Dedoc\Scramble\Extensions\TypeToSchemaExtension;
|
||||
use Dedoc\Scramble\Http\Middleware\RestrictedDocsAccess;
|
||||
use Dedoc\Scramble\Infer\Definition\FunctionLikeDefinition;
|
||||
use Dedoc\Scramble\Infer\Extensions\ExtensionsBroker;
|
||||
use Dedoc\Scramble\Infer\Extensions\IndexBuildingBroker;
|
||||
use Dedoc\Scramble\Infer\Extensions\InferExtension;
|
||||
use Dedoc\Scramble\Infer\Scope\Index;
|
||||
use Dedoc\Scramble\Infer\Scope\LazyShallowReflectionIndex;
|
||||
use Dedoc\Scramble\Infer\Services\FileParser;
|
||||
use Dedoc\Scramble\Support\DevTools;
|
||||
use Dedoc\Scramble\Support\ExceptionToResponseExtensions\AuthenticationExceptionToResponseExtension;
|
||||
use Dedoc\Scramble\Support\ExceptionToResponseExtensions\AuthorizationExceptionToResponseExtension;
|
||||
use Dedoc\Scramble\Support\ExceptionToResponseExtensions\HttpExceptionToResponseExtension;
|
||||
use Dedoc\Scramble\Support\ExceptionToResponseExtensions\NotFoundExceptionToResponseExtension;
|
||||
use Dedoc\Scramble\Support\ExceptionToResponseExtensions\ValidationExceptionToResponseExtension;
|
||||
use Dedoc\Scramble\Support\Generator\TypeTransformer;
|
||||
use Dedoc\Scramble\Support\IndexBuilders\IndexBuilder;
|
||||
use Dedoc\Scramble\Support\IndexBuilders\PaginatorsCandidatesBuilder;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AbortHelpersExceptionInfer;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterAnonymousResourceCollectionDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterCursorPaginatorDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterEloquentBuilderDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterEloquentCollectionDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterEloquentRelationDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterJsonApiResourceDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterJsonResourceDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterLengthAwarePaginatorDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterModelDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterPaginatorDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterResourceCollectionDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\AfterResponseDefinitionCreatedExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\ArrayMergeReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\ArrStaticMethodReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\EloquentBuilderExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\FacadeStaticMethodReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\JsonApiResourceCollectionMethodReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\JsonApiResourceMethodReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\JsonResourceExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\JsonResponseMethodReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\ModelExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\PaginateMethodsReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\PossibleExceptionInfer;
|
||||
use Dedoc\Scramble\Support\InferExtensions\RequestExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\ResourceCollectionTypeInfer;
|
||||
use Dedoc\Scramble\Support\InferExtensions\ResourceResponseMethodReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\ResponseFactoryTypeInfer;
|
||||
use Dedoc\Scramble\Support\InferExtensions\ShallowFunctionDefinition;
|
||||
use Dedoc\Scramble\Support\InferExtensions\StorageResponseTypeInfer;
|
||||
use Dedoc\Scramble\Support\InferExtensions\TransformsToResourceCollectionExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\TranslationReturnTypeExtension;
|
||||
use Dedoc\Scramble\Support\InferExtensions\TypeTraceInfer;
|
||||
use Dedoc\Scramble\Support\InferExtensions\ValidatorTypeInfer;
|
||||
use Dedoc\Scramble\Support\ProNudge\Extensions\LaravelDataRequestBodyNudgeExtractor;
|
||||
use Dedoc\Scramble\Support\ProNudge\Extensions\LaravelDataReturnTypeNudgeExtension;
|
||||
use Dedoc\Scramble\Support\ProNudge\Extensions\QueryBuilderUsageNudgeExtension;
|
||||
use Dedoc\Scramble\Support\RouteProviders\RouteProvider;
|
||||
use Dedoc\Scramble\Support\Type\FunctionType;
|
||||
use Dedoc\Scramble\Support\Type\TemplateType;
|
||||
use Dedoc\Scramble\Support\Type\VoidType;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\ArrayableToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\BinaryFileResponseToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\CarbonInterfaceToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\CollectionToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\CursorPaginatorTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\EloquentCollectionToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\EnumToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\JsonApiAnonymousCollectionTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\JsonApiPaginatedResourceResponseToSchemaExtension;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\JsonApiResourceResponseToSchemaExtension;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\JsonApiResourceTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\JsonResourceTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\LengthAwarePaginatorTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\PaginatedResourceResponseTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\PaginatorTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\PlainObjectToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\ResourceCollectionTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\ResourceResponseTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\ResponsableTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\ResponseTypeToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\StreamedResponseToSchema;
|
||||
use Dedoc\Scramble\Support\TypeToSchemaExtensions\VoidTypeToSchema;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Routing\Router;
|
||||
use PhpParser\ParserFactory;
|
||||
use PhpParser\PrettyPrinter;
|
||||
use Spatie\LaravelPackageTools\Package;
|
||||
use Spatie\LaravelPackageTools\PackageServiceProvider;
|
||||
|
||||
class ScrambleServiceProvider extends PackageServiceProvider
|
||||
{
|
||||
/** @var array<class-string, class-string> */
|
||||
public $bindings = [
|
||||
RouteProviderContract::class => RouteProvider::class,
|
||||
];
|
||||
|
||||
public $singletons = [
|
||||
PrettyPrinter::class => PrettyPrinter\Standard::class,
|
||||
GeneratorConfigCollection::class => GeneratorConfigCollection::class,
|
||||
CacheableGenerator::class => CacheableGenerator::class,
|
||||
];
|
||||
|
||||
public function configurePackage(Package $package): void
|
||||
{
|
||||
$package
|
||||
->name('scramble')
|
||||
->hasConfigFile()
|
||||
->hasCommand(ExportDocumentation::class)
|
||||
->hasCommand(AnalyzeDocumentation::class)
|
||||
->hasCommand(CacheDocumentation::class)
|
||||
->hasCommand(ClearDocumentationCache::class)
|
||||
->hasViews('scramble');
|
||||
|
||||
$this->app->singleton(FileParser::class, function () {
|
||||
return new FileParser(
|
||||
(new ParserFactory)->createForHostVersion()
|
||||
);
|
||||
});
|
||||
|
||||
$this->app->singleton(LazyShallowReflectionIndex::class, function () {
|
||||
return new LazyShallowReflectionIndex(
|
||||
// Abort helpers are handled in the extension and these definitions are needed to avoid leaking the
|
||||
// annotated exceptions to the caller's definitions.
|
||||
functions: [
|
||||
'abort' => $abortType = new FunctionLikeDefinition(type: new FunctionType('abort', returnType: new VoidType)),
|
||||
'abort_if' => $abortType,
|
||||
'abort_unless' => $abortType,
|
||||
'throw_if' => $throwType = new FunctionLikeDefinition(type: new FunctionType('throw_if', returnType: new VoidType)),
|
||||
'throw_unless' => $throwType,
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
$this->app->singleton(Index::class, function () {
|
||||
$index = new Index;
|
||||
foreach ((require __DIR__.'/../dictionaries/classMap.php') ?: [] as $className => $serializedClassDefinition) {
|
||||
$index->classesDefinitions[$className] = unserialize($serializedClassDefinition);
|
||||
}
|
||||
|
||||
$templates = [$tValue = new TemplateType('TValue')];
|
||||
$index->functionsDefinitions['tap'] = new ShallowFunctionDefinition(
|
||||
type: tap(new FunctionType(
|
||||
name: 'tap',
|
||||
arguments: [
|
||||
'value' => $tValue,
|
||||
],
|
||||
returnType: $tValue,
|
||||
), function (FunctionType $type) use ($templates) {
|
||||
$type->templates = $templates;
|
||||
})
|
||||
);
|
||||
|
||||
return $index;
|
||||
});
|
||||
|
||||
$this->app->singleton(Infer::class);
|
||||
|
||||
$this->app->when(ExtensionsBroker::class)
|
||||
->needs('$extensions')
|
||||
->give(function ($app) {
|
||||
$extensions = array_merge(config('scramble.extensions', []), Scramble::$extensions);
|
||||
|
||||
$inferExtensionsClasses = array_values(array_filter(
|
||||
$extensions,
|
||||
fn ($e) => is_a($e, InferExtension::class, true),
|
||||
));
|
||||
|
||||
$inferExtensionsClasses = array_merge($inferExtensionsClasses, [
|
||||
JsonApiResourceMethodReturnTypeExtension::class,
|
||||
JsonApiResourceCollectionMethodReturnTypeExtension::class,
|
||||
AfterJsonApiResourceDefinitionCreatedExtension::class,
|
||||
AfterEloquentBuilderDefinitionCreatedExtension::class,
|
||||
AfterEloquentRelationDefinitionCreatedExtension::class,
|
||||
AfterModelDefinitionCreatedExtension::class,
|
||||
AfterEloquentCollectionDefinitionCreatedExtension::class,
|
||||
JsonResourceExtension::class,
|
||||
ResourceResponseMethodReturnTypeExtension::class,
|
||||
JsonResponseMethodReturnTypeExtension::class,
|
||||
ModelExtension::class,
|
||||
TransformsToResourceCollectionExtension::class,
|
||||
EloquentBuilderExtension::class,
|
||||
RequestExtension::class,
|
||||
AfterJsonResourceDefinitionCreatedExtension::class,
|
||||
AfterLengthAwarePaginatorDefinitionCreatedExtension::class,
|
||||
AfterPaginatorDefinitionCreatedExtension::class,
|
||||
AfterCursorPaginatorDefinitionCreatedExtension::class,
|
||||
AfterResourceCollectionDefinitionCreatedExtension::class,
|
||||
AfterAnonymousResourceCollectionDefinitionCreatedExtension::class,
|
||||
AfterResponseDefinitionCreatedExtension::class,
|
||||
]);
|
||||
|
||||
return array_merge(
|
||||
[
|
||||
new PossibleExceptionInfer,
|
||||
new AbortHelpersExceptionInfer,
|
||||
|
||||
new PaginateMethodsReturnTypeExtension,
|
||||
new FacadeStaticMethodReturnTypeExtension,
|
||||
new ArrStaticMethodReturnTypeExtension,
|
||||
|
||||
new ValidatorTypeInfer,
|
||||
new ResourceCollectionTypeInfer,
|
||||
new ResponseFactoryTypeInfer,
|
||||
new StorageResponseTypeInfer,
|
||||
|
||||
new ArrayMergeReturnTypeExtension,
|
||||
new TranslationReturnTypeExtension,
|
||||
|
||||
/* Keep this extension last, so the trace info is preserved. */
|
||||
new TypeTraceInfer,
|
||||
],
|
||||
array_map(function ($class) {
|
||||
return app($class);
|
||||
}, $inferExtensionsClasses)
|
||||
);
|
||||
});
|
||||
|
||||
$this->app->when(IndexBuildingBroker::class)
|
||||
->needs('$indexBuilders')
|
||||
->give(function () {
|
||||
$extensions = array_merge(config('scramble.extensions', []), Scramble::$extensions);
|
||||
|
||||
$indexBuilders = array_values(array_filter(
|
||||
$extensions,
|
||||
fn ($e) => is_a($e, IndexBuilder::class, true),
|
||||
));
|
||||
|
||||
return array_map(function ($class) {
|
||||
return app($class);
|
||||
}, array_merge([PaginatorsCandidatesBuilder::class], $indexBuilders));
|
||||
});
|
||||
|
||||
$this->app->bind(TypeTransformer::class, function (Application $application, array $parameters) {
|
||||
$extensions = array_merge(config('scramble.extensions', []), Scramble::$extensions);
|
||||
|
||||
$typesToSchemaExtensions = array_values(array_filter(
|
||||
$extensions,
|
||||
fn ($e) => is_a($e, TypeToSchemaExtension::class, true),
|
||||
));
|
||||
|
||||
$exceptionToResponseExtensions = array_values(array_filter(
|
||||
$extensions,
|
||||
fn ($e) => is_a($e, ExceptionToResponseExtension::class, true),
|
||||
));
|
||||
|
||||
return new TypeTransformer(
|
||||
$parameters['infer'] ?? $application->make(Infer::class),
|
||||
$parameters['context'],
|
||||
typeToSchemaExtensionsClasses: $parameters['typeToSchemaExtensions'] ?? array_merge([
|
||||
PlainObjectToSchema::class,
|
||||
ResponsableTypeToSchema::class,
|
||||
ArrayableToSchema::class,
|
||||
EnumToSchema::class,
|
||||
JsonResourceTypeToSchema::class,
|
||||
JsonApiResourceTypeToSchema::class,
|
||||
CollectionToSchema::class,
|
||||
EloquentCollectionToSchema::class,
|
||||
ResourceCollectionTypeToSchema::class,
|
||||
CursorPaginatorTypeToSchema::class,
|
||||
PaginatorTypeToSchema::class,
|
||||
LengthAwarePaginatorTypeToSchema::class,
|
||||
ResponseTypeToSchema::class,
|
||||
BinaryFileResponseToSchema::class,
|
||||
StreamedResponseToSchema::class,
|
||||
ResourceResponseTypeToSchema::class,
|
||||
PaginatedResourceResponseTypeToSchema::class,
|
||||
JsonApiAnonymousCollectionTypeToSchema::class,
|
||||
JsonApiResourceResponseToSchemaExtension::class,
|
||||
JsonApiPaginatedResourceResponseToSchemaExtension::class,
|
||||
CarbonInterfaceToSchema::class,
|
||||
VoidTypeToSchema::class,
|
||||
], $typesToSchemaExtensions),
|
||||
exceptionToResponseExtensionsClasses: $parameters['exceptionToResponseExtensions'] ?? array_merge([
|
||||
ValidationExceptionToResponseExtension::class,
|
||||
AuthorizationExceptionToResponseExtension::class,
|
||||
AuthenticationExceptionToResponseExtension::class,
|
||||
HttpExceptionToResponseExtension::class,
|
||||
NotFoundExceptionToResponseExtension::class,
|
||||
], $exceptionToResponseExtensions),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public function bootingPackage()
|
||||
{
|
||||
Scramble::configure()
|
||||
->useConfig(config('scramble'))
|
||||
->withOperationTransformers(function (OperationTransformers $transformers) {
|
||||
$extensions = array_merge(config('scramble.extensions', []), Scramble::$extensions);
|
||||
|
||||
$operationExtensions = array_values(array_filter(
|
||||
$extensions,
|
||||
fn ($e) => is_a($e, OperationExtension::class, true),
|
||||
));
|
||||
|
||||
$transformers->append($operationExtensions);
|
||||
})
|
||||
->withDocumentTransformers([
|
||||
AddDocumentTags::class,
|
||||
CleanupUnusedResponseReferencesTransformer::class,
|
||||
]);
|
||||
|
||||
Scramble::infer()
|
||||
->configure()
|
||||
->buildDefinitionsUsingAstFor([
|
||||
Attribute::class,
|
||||
]);
|
||||
|
||||
if (Scramble::$defaultRoutesIgnored) {
|
||||
Scramble::configure()->expose(false);
|
||||
}
|
||||
|
||||
$this->registerProNudge();
|
||||
|
||||
$this->app->booted(function () {
|
||||
$this->registerRoutes();
|
||||
});
|
||||
}
|
||||
|
||||
private function registerProNudge(): void
|
||||
{
|
||||
if (class_exists('Dedoc\ScramblePro\ScrambleProServiceProvider')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Scramble::configure()
|
||||
->withOperationTransformers([
|
||||
LaravelDataReturnTypeNudgeExtension::class,
|
||||
QueryBuilderUsageNudgeExtension::class,
|
||||
])
|
||||
->withParametersExtractors(function (ParametersExtractors $extractors) {
|
||||
$extractors->append(LaravelDataRequestBodyNudgeExtractor::class);
|
||||
});
|
||||
}
|
||||
|
||||
private function registerRoutes(): void
|
||||
{
|
||||
$this->registerDevToolsAssetsRoute();
|
||||
|
||||
foreach (Scramble::getConfigurationsInstance()->all() as $api => $generatorConfig) {
|
||||
/** @var Router $router */
|
||||
$router = $this->app->get(Router::class);
|
||||
|
||||
if ($generatorConfig->uiRoute) {
|
||||
$cb = is_callable($generatorConfig->uiRoute)
|
||||
? $generatorConfig->uiRoute
|
||||
: fn ($router, $action) => $router->get($generatorConfig->uiRoute, $action);
|
||||
|
||||
$cb($router, function (CacheableGenerator $generator) use ($api) {
|
||||
$config = Scramble::getGeneratorConfig($api);
|
||||
$result = $generator->generate($config);
|
||||
|
||||
return view($config->renderer()->view, [
|
||||
/*
|
||||
* `spec` here is for backward compatibility in case there is a
|
||||
* stale published view that expects it to exist, will be removed in 1.0
|
||||
*/
|
||||
'spec' => $result->spec($config->openApiVersion()),
|
||||
'config' => $config,
|
||||
'result' => $result,
|
||||
]);
|
||||
})->middleware($generatorConfig->get('middleware', [RestrictedDocsAccess::class]));
|
||||
}
|
||||
|
||||
if ($generatorConfig->documentRoute) {
|
||||
$cb = is_callable($generatorConfig->documentRoute)
|
||||
? $generatorConfig->documentRoute
|
||||
: fn ($router, $action) => $router->get($generatorConfig->documentRoute, $action);
|
||||
|
||||
$cb($router, function (CacheableGenerator $generator) use ($api) {
|
||||
$config = Scramble::getGeneratorConfig($api);
|
||||
|
||||
return response()->json($generator($config), options: JSON_PRETTY_PRINT);
|
||||
})->middleware($generatorConfig->get('middleware', [RestrictedDocsAccess::class]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function registerDevToolsAssetsRoute(): void
|
||||
{
|
||||
if (! DevTools::enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var Router $router */
|
||||
$router = $this->app->get(Router::class);
|
||||
$middleware = array_values(array_filter(
|
||||
(array) config('scramble.middleware', [RestrictedDocsAccess::class]),
|
||||
fn ($middleware) => is_string($middleware),
|
||||
));
|
||||
|
||||
$router->get('_scramble/dev-tools/devtools.js', function () {
|
||||
$path = DevTools::assetPath();
|
||||
|
||||
abort_unless(is_file($path), 404);
|
||||
|
||||
return response()->file($path, [
|
||||
'Cache-Control' => 'no-store',
|
||||
'Content-Type' => 'text/javascript; charset=UTF-8',
|
||||
]);
|
||||
})
|
||||
->name('scramble.dev-tools.asset')
|
||||
->middleware($middleware);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user