OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
This commit is contained in:
45
.phpstan/Rules/FacadeRule.php
Normal file
45
.phpstan/Rules/FacadeRule.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Leanstan\Rules;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\StaticCall;
|
||||
use PHPStan\Analyser\Scope;
|
||||
use PHPStan\Rules\Rule;
|
||||
|
||||
class FacadeRule implements Rule
|
||||
{
|
||||
private const ALLOWED_FACADES = ['Cache', 'Log', 'parent', 'self'];
|
||||
|
||||
public function getNodeType(): string
|
||||
{
|
||||
return StaticCall::class;
|
||||
}
|
||||
|
||||
public function processNode(Node $node, Scope $scope): array
|
||||
{
|
||||
if (!$node instanceof StaticCall) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$node->class instanceof \PhpParser\Node\Name) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$className = $node->class->toString();
|
||||
|
||||
// Check if it's likely a facade
|
||||
$parts = $node->class->getParts();
|
||||
if (strpos($className, 'Illuminate\\Support\\Facades\\') === 0 || count($parts) === 1) {
|
||||
$facadeName = count($parts) === 1 ? $parts[0] : end($parts);
|
||||
|
||||
if (!in_array($facadeName, self::ALLOWED_FACADES)) {
|
||||
return [
|
||||
"Only Cache:: and Log:: facades are allowed. Consider using dependency injection or helpers instead of {$facadeName}::."
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
20
.phpstan/bootstrap.php
Normal file
20
.phpstan/bootstrap.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use Leantime\Core\Http\HttpKernel;
|
||||
|
||||
define('RESTRICTED', true);
|
||||
define('ROOT', __DIR__);
|
||||
define('APP_ROOT', dirname(__DIR__, 1));
|
||||
define('LEAN_CLI', false);
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
$app = require_once APP_ROOT . '/bootstrap/app.php';
|
||||
|
||||
$app->make(\Leantime\Core\Console\ConsoleKernel::class)->bootstrap();
|
||||
|
||||
// Register Leantime's CarbonImmutable date/time macros into Carbon's macro registry so
|
||||
// Carbon's official PHPStan MacroExtension (vendor/nesbot/carbon/extension.neon) can resolve
|
||||
// them (formatDateForUser, setToDbTimezone, ...). At runtime these are registered by the
|
||||
// Localization middleware; PHPStan never runs that middleware, so register them here.
|
||||
\Carbon\CarbonImmutable::mixin(new \Leantime\Core\Support\CarbonMacros);
|
||||
50
.phpstan/phpstan.neon
Normal file
50
.phpstan/phpstan.neon
Normal file
@@ -0,0 +1,50 @@
|
||||
includes:
|
||||
# Carbon's official PHPStan extension: resolves macros registered via mixin()/macro()
|
||||
# (including Leantime's date/time macros, registered in bootstrap.php) on all Carbon types.
|
||||
- ../vendor/nesbot/carbon/extension.neon
|
||||
|
||||
parameters:
|
||||
bootstrapFiles:
|
||||
- bootstrap.php
|
||||
level: 5
|
||||
inferPrivatePropertyTypeFromConstructor: true
|
||||
paths:
|
||||
- ../public
|
||||
- ../app
|
||||
- ../.phpstan/Rules
|
||||
excludePaths:
|
||||
- ../app/Plugins/*
|
||||
scanDirectories:
|
||||
- ../vendor
|
||||
- ../config
|
||||
stubFiles:
|
||||
# Declares Leantime's runtime-registered methods (Str/Carbon macros, Collection::countNested,
|
||||
# Event::discoverListeners) so vanilla PHPStan stops reporting them as undefined.
|
||||
- stubs/leantime-macros.stub
|
||||
# Declares concrete Laravel methods our code calls through looser contracts (no Larastan).
|
||||
- stubs/laravel-gaps.stub
|
||||
ignoreErrors:
|
||||
# Legacy templates receive their variables from the view layer ($tpl->assign / extract)
|
||||
# and blade files via compiled-in view data. PHPStan analyses them as plain PHP and so
|
||||
# cannot see those variables. This is a known limitation of the template pattern, not a
|
||||
# code defect. reportUnmatched is off because templates are mid-migration (paths come and
|
||||
# go) and app/Plugins is a private submodule absent in CI.
|
||||
-
|
||||
identifier: variable.undefined
|
||||
reportUnmatched: false
|
||||
paths:
|
||||
- ../app/Domain/*/Templates/*
|
||||
- ../app/Views/*
|
||||
- ../app/Plugins/*/Templates/*
|
||||
universalObjectCratesClasses:
|
||||
- Leantime\Core\Configuration\Environment
|
||||
earlyTerminatingMethodCalls:
|
||||
Leantime\Core\UI\Templates:
|
||||
- redirect
|
||||
- display
|
||||
- displayPartial
|
||||
# services:
|
||||
# -
|
||||
# class: Leanstan\Rules\FacadeRule
|
||||
# tags:
|
||||
# - phpstan.rules.rule
|
||||
108
.phpstan/stubs/laravel-gaps.stub
Normal file
108
.phpstan/stubs/laravel-gaps.stub
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHPStan stub: methods that exist on the CONCRETE Laravel classes our code uses at
|
||||
* runtime, but are not declared on the looser contracts/interfaces we type-hint against.
|
||||
*
|
||||
* Leantime intentionally does NOT use Larastan, so vanilla PHPStan only sees the contract
|
||||
* (e.g. ConnectionInterface) and reports the concrete method (e.g. getDriverName()) as
|
||||
* undefined — even though the runtime object (Illuminate\Database\Connection) always has it.
|
||||
*
|
||||
* These @method tags merge onto the real interfaces/classes; native members are unaffected.
|
||||
* Each entry is documented with the concrete class that actually provides the method.
|
||||
*/
|
||||
|
||||
namespace Illuminate\Database;
|
||||
|
||||
/**
|
||||
* Provided at runtime by the abstract Illuminate\Database\Connection that
|
||||
* DatabaseManager::connection() always returns.
|
||||
*
|
||||
* @method string getDriverName()
|
||||
* @method \PDO getPdo()
|
||||
* @method \Illuminate\Database\Query\Grammars\Grammar getQueryGrammar()
|
||||
*/
|
||||
interface ConnectionInterface {}
|
||||
|
||||
namespace Illuminate\Contracts\Cache;
|
||||
|
||||
/**
|
||||
* The concrete Illuminate\Cache\Repository (what Cache::store() returns) forwards lock() via
|
||||
* __call to its underlying store when that store is a LockProvider (Redis/File/Database/...).
|
||||
* StartSession::cache() is typed against this contract and uses it for session locking.
|
||||
*
|
||||
* @method \Illuminate\Cache\Lock lock(string $name, int $seconds = 0, ?string $owner = null)
|
||||
*/
|
||||
interface Repository {}
|
||||
|
||||
namespace Illuminate\Contracts\Filesystem;
|
||||
|
||||
/**
|
||||
* Provided by the concrete Illuminate\Filesystem\FilesystemAdapter (and the Cloud contract
|
||||
* for url()/temporaryUrl()). Storage::disk() returns that adapter.
|
||||
*
|
||||
* @method string url(string $path)
|
||||
* @method string temporaryUrl(string $path, \DateTimeInterface $expiration, array $options = [])
|
||||
* @method string|false mimeType(string $path)
|
||||
*/
|
||||
interface Filesystem {}
|
||||
|
||||
namespace Illuminate\Contracts\Foundation;
|
||||
|
||||
/**
|
||||
* Provided by Illuminate\Foundation\Application (which Leantime\Core\Application extends).
|
||||
*
|
||||
* @method void rebinding(string $abstract, \Closure $callback)
|
||||
* @method string getCachedConfigPath()
|
||||
* @method string detectEnvironment(\Closure $callback)
|
||||
*/
|
||||
interface Application {}
|
||||
|
||||
namespace Illuminate\Container;
|
||||
|
||||
/**
|
||||
* terminating() lives on Illuminate\Foundation\Application; the container instance Leantime
|
||||
* passes around is that application.
|
||||
*
|
||||
* @method void terminating(\Closure|string $callback)
|
||||
*/
|
||||
class Container {}
|
||||
|
||||
namespace Illuminate\Contracts\Auth;
|
||||
|
||||
/**
|
||||
* Provided by the concrete Illuminate\Auth\AuthManager bound to 'auth'.
|
||||
*
|
||||
* @method string getDefaultDriver()
|
||||
* @method \Illuminate\Contracts\Auth\Authenticatable|null user()
|
||||
*/
|
||||
interface Factory {}
|
||||
|
||||
/**
|
||||
* viaRemember()/getRecallerName()/logoutCurrentDevice() are provided by the concrete
|
||||
* session guard (Illuminate\Auth\SessionGuard) that AuthManager::guard() returns.
|
||||
*
|
||||
* @method bool viaRemember()
|
||||
* @method string getRecallerName()
|
||||
* @method void logoutCurrentDevice()
|
||||
*/
|
||||
interface Guard {}
|
||||
|
||||
namespace Illuminate\Support;
|
||||
|
||||
/**
|
||||
* addRealMinutes() is a Carbon magic method (Carbon 3 dropped its @method annotation but the
|
||||
* __call magic still resolves it). Used by StartSession exactly as upstream Laravel does.
|
||||
*
|
||||
* @method \Illuminate\Support\Carbon addRealMinutes(int $value = 1)
|
||||
*/
|
||||
class Carbon {}
|
||||
|
||||
namespace Laravel\Socialite\Contracts;
|
||||
|
||||
/**
|
||||
* setScopes() is provided by the concrete Laravel\Socialite\Two\AbstractProvider.
|
||||
*
|
||||
* @method \Laravel\Socialite\Contracts\Provider setScopes(array|string $scopes)
|
||||
*/
|
||||
interface Provider {}
|
||||
45
.phpstan/stubs/leantime-macros.stub
Normal file
45
.phpstan/stubs/leantime-macros.stub
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PHPStan stub: declares Leantime's custom runtime-registered methods that vanilla
|
||||
* PHPStan (no Larastan) cannot see. These are NOT real source definitions — they
|
||||
* only teach the analyzer that the methods exist with these signatures.
|
||||
*
|
||||
* - Str macros are registered via Str::mixin(...) in
|
||||
* app/Core/Support/LoadMacrosServiceProvider.php. Each mixin method returns a
|
||||
* closure; the closure's parameters are the real call signature (registration-time
|
||||
* params are baked in and declared here as optional so existing call sites pass).
|
||||
* - Collection::countNested is registered via Collection::macro(...) in the same provider.
|
||||
* - Event::discoverListeners() lives on Leantime\Core\Events\EventDispatcher, which is
|
||||
* bound to the 'events' container singleton (app/Core/Events/EventsServiceProvider.php).
|
||||
*
|
||||
* The @method tags merge onto the real classes; native methods are unaffected.
|
||||
*
|
||||
* NOTE: Leantime's CarbonImmutable macros (formatDateForUser, setToDbTimezone, ...) are NOT
|
||||
* stubbed here — stubbing Carbon\CarbonInterface would clobber Carbon's own @method API.
|
||||
* They are resolved by Carbon's official PHPStan MacroExtension instead (vendor extension.neon
|
||||
* included from phpstan.neon), fed by the mixin registration in .phpstan/bootstrap.php.
|
||||
*/
|
||||
|
||||
namespace Illuminate\Support;
|
||||
|
||||
/**
|
||||
* @method static string alphaNumeric(string $value, bool $removeSpaces = false)
|
||||
* @method static string beautifyFilename(string $filename)
|
||||
* @method static string sanitizeFilename(string $filename, bool $beautify = true)
|
||||
* @method static string sanitizeForLLM(string $value, bool $removeNewlines = false)
|
||||
* @method static string toMarkdown(mixed $data, int $headerLevel = 2)
|
||||
*/
|
||||
class Str {}
|
||||
|
||||
/**
|
||||
* @method int countNested(string $childrenKey = 'children')
|
||||
*/
|
||||
class Collection {}
|
||||
|
||||
namespace Illuminate\Support\Facades;
|
||||
|
||||
/**
|
||||
* @method static void discoverListeners()
|
||||
*/
|
||||
class Event {}
|
||||
Reference in New Issue
Block a user