Initial commit: WordPress wp-content (themes, plugins, languages)

- Theme: momentry (custom theme with REST API routes)
- Plugins: code-snippets (contains all API proxies)
- Languages: zh_TW translations
- Excludes: cache, backups, uploads, logs
This commit is contained in:
OpenCode
2026-05-29 19:07:56 +08:00
commit 09ef1f000f
6521 changed files with 867163 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
class ArrayUtil
{
public static function flattenMap(callable $callable, array $array): array
{
$map = array_map($callable, $array);
return static::flatten($map);
}
/**
* Flatten array by one level.
*
* @param array $array
*
* @return array
*/
public static function flatten(array $array): array
{
$result = [];
foreach ($array as $item) {
if (is_array($item)) {
$result = array_merge($result, array_values($item));
} else {
$result[] = $item;
}
}
return $result;
}
}

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
class Config implements ConfigInterface
{
/**
* @var string
*/
protected $packageDir;
/**
* @var array
*/
private $config;
public function __construct(string $packageDir, array $config)
{
$this->packageDir = StringUtil::addTrailingSlash($packageDir);
$this->config = $config;
}
/**
* @return string[]
*/
public function getAutoloads(): array
{
return array_map(function (string $autoload): string {
return $this->packageDir . $autoload;
}, array_unique($this->getAutoloadPaths()));
}
/**
* @return string[]
*/
private function getAutoloadPaths(): array
{
$autoloads = $this->get('autoload');
unset($autoloads['exclude-from-classmap']);
return ArrayUtil::flattenMap(function ($autoloadConfig): array {
return $this->normalizeAutoload($autoloadConfig);
}, $autoloads);
}
protected function get(string $key): array
{
return $this->config[$key] ?? [];
}
/**
* @param $autoloadConfigs
*
* @return string[]
*/
private function normalizeAutoload($autoloadConfigs): array
{
if (! is_array($autoloadConfigs)) {
return [$autoloadConfigs];
}
return ArrayUtil::flattenMap(function ($autoloadConfig): array {
return $this->normalizeAutoload($autoloadConfig);
}, $autoloadConfigs);
}
public function getPackageDir(): string
{
return $this->packageDir;
}
/**
* @return string[]
*/
public function getRequires(): array
{
return array_keys($this->get('require'));
}
}

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
class ConfigCollection implements ConfigCollectionInterface
{
/**
* @var ConfigInterface[]
*/
private $configs = [];
/**
* @param ConfigInterface $config
*
* @return void
*/
public function add(ConfigInterface $config)
{
$this->configs[$config->getPackageDir()] = $config;
}
/**
* @return string[]
*/
public function getAutoloads(): array
{
$autoloads = ArrayUtil::flattenMap(function (ConfigInterface $config) {
return $config->getAutoloads();
}, $this->all());
return array_unique($autoloads);
}
/**
* @return ConfigInterface[]
*/
public function all(): array
{
return $this->configs;
}
}

View File

@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
class ConfigCollectionFactory
{
public static function forProject(
ProjectConfigInterface $projectConfig,
Filesystem $filesystem
): ConfigCollectionInterface {
return static::addRequiredPackageConfigsRecursively(
new ConfigCollection(),
$projectConfig,
$projectConfig,
$filesystem
);
}
private static function addRequiredPackageConfigsRecursively(
ConfigCollectionInterface $configCollection,
ProjectConfigInterface $projectConfig,
ConfigInterface $config,
Filesystem $filesystem
): ConfigCollectionInterface {
$filteredRequires = static::getFilteredPackages($projectConfig, $config);
foreach ($filteredRequires as $package) {
$packageConfig = ConfigFactory::build(
$projectConfig->getVendorDir() . $package . '/composer.json',
$filesystem
);
$configCollection->add($packageConfig);
static::addRequiredPackageConfigsRecursively(
$configCollection,
$projectConfig,
$packageConfig,
$filesystem
);
}
return $configCollection;
}
/**
* @param ProjectConfigInterface $projectConfig
* @param ConfigInterface $config
*
* @return string[]
*/
private static function getFilteredPackages(ProjectConfigInterface $projectConfig, ConfigInterface $config): array
{
$requiredPackages = array_filter($config->getRequires(), function (string $package) {
return (false !== strpos($package, '/'));
});
$nonComposerPackages = array_filter($requiredPackages, function (string $package) {
return (false === strpos($package, 'composer/'));
});
return array_filter($nonComposerPackages, function (string $package) use ($projectConfig) {
return ! in_array($package, $projectConfig->getExcludes(), true);
});
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
interface ConfigCollectionInterface
{
/**
* @param ConfigInterface $config
*
* @return void
*/
public function add(ConfigInterface $config);
/**
* @return ConfigInterface[]
*/
public function all(): array;
/**
* @return string[]
*/
public function getAutoloads(): array;
}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
class ConfigFactory
{
public static function build(string $path, Filesystem $filesystem): Config
{
return new Config(
$filesystem->dirname($path),
json_decode(
$filesystem->get($path),
true
)
);
}
public static function buildProjectConfig(string $path, Filesystem $filesystem): ProjectConfig
{
return new ProjectConfig(
$filesystem->dirname($path),
json_decode(
$filesystem->get($path),
true
)
);
}
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
interface ConfigInterface
{
/**
* @return string[]
*/
public function getAutoloads(): array;
public function getPackageDir(): string;
/**
* @return string[]
*/
public function getRequires(): array;
}

View File

@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RuntimeException;
class Filesystem implements FilesystemInterface
{
/**
* @param string $path
*
* @return \SplFileInfo[]
* @throws \UnexpectedValueException
*/
public function allFiles(string $path): array
{
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS)
);
return iterator_to_array($iterator);
}
/**
* Extract the parent directory from a file path.
*
* @param string $path
*
* @return string
*/
public function dirname(string $path): string
{
return pathinfo($path, PATHINFO_DIRNAME);
}
/**
* Get the contents of a file.
*
* @param string $path
*
* @return string
* @throws \RuntimeException
*/
public function get(string $path): string
{
if (! $this->isFile($path)) {
throw new RuntimeException('File does not exist at path ' . $path);
}
return file_get_contents($path);
}
/**
* Determine if the given path is a file.
*
* @param string $path
*
* @return bool
*/
public function isFile(string $path): bool
{
return is_file($path);
}
/**
* Determine if the given path is a directory.
*
* @param string $path
*
* @return bool
*/
public function isDir(string $path): bool
{
return is_dir($path);
}
/**
* Write the contents of a file.
*
* @param string $path
* @param string $contents
*
* @return int|false
*/
public function put(string $path, string $contents)
{
return file_put_contents($path, $contents);
}
}

View File

@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
interface FilesystemInterface
{
/**
* @param string $path
*
* @return \SplFileInfo[]
*/
public function allFiles(string $path): array;
/**
* Extract the parent directory from a file path.
*
* @param string $path
*
* @return string
*/
public function dirname(string $path): string;
/**
* Get the contents of a file.
*
* @param string $path
*
* @return string
*/
public function get(string $path): string;
/**
* Determine if the given path is a file.
*
* @param string $path
*
* @return bool
*/
public function isFile(string $path): bool;
/**
* Determine if the given path is a directory.
*
* @param string $path
*
* @return bool
*/
public function isDir(string $path);
/**
* Write the contents of a file.
*
* @param string $path
* @param string $contents
*
* @return mixed
*/
public function put(string $path, string $contents);
}

View File

@@ -0,0 +1,135 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
class Imposter implements ImposterInterface
{
/**
* @var string[]
*/
private $autoloads;
/**
* @var string[]
*/
private $invalidAutoloads;
/**
* @var ConfigCollectionInterface
*/
private $configCollection;
/**
* @var TransformerInterface
*/
private $transformer;
/**
* @var FilesystemInterface
*/
private $filesystem;
/**
* Imposter constructor.
*
* @param ConfigCollectionInterface $configCollection
* @param TransformerInterface $transformer
* @param FilesystemInterface $filesystem
*/
public function __construct(
ConfigCollectionInterface $configCollection,
TransformerInterface $transformer,
FilesystemInterface $filesystem
) {
$this->configCollection = $configCollection;
$this->transformer = $transformer;
$this->filesystem = $filesystem;
}
/**
* @return ConfigCollectionInterface
*/
public function getConfigCollection(): ConfigCollectionInterface
{
return $this->configCollection;
}
/**
* @return TransformerInterface
*/
public function getTransformer(): TransformerInterface
{
return $this->transformer;
}
/**
* Transform all autoload files.
*
* @return void
*/
public function run()
{
$autoloads = $this->getAutoloads();
array_walk($autoloads, [$this, 'transform']);
}
/**
* Get all valid (exist) autoload paths.
*
* @return string[]
*/
public function getAutoloads(): array
{
if ($this->autoloads === null) {
$this->setAutoloads();
}
return $this->autoloads;
}
/**
* Get all autoload paths which defined in composer.json but not exist.
*
* @return string[]
*/
public function getInvalidAutoloads(): array
{
if ($this->invalidAutoloads === null) {
$this->setAutoloads();
}
return $this->invalidAutoloads;
}
protected function setAutoloads(): void
{
$this->autoloads = [];
$this->invalidAutoloads = [];
$autoloads = $this->configCollection->getAutoloads();
foreach ($autoloads as $autoload) {
$isValid = $this->filesystem->isFile($autoload) || $this->filesystem->isDir($autoload);
if ($isValid) {
$this->autoloads[] = $autoload;
} else {
$this->invalidAutoloads[] = $autoload;
}
}
}
/**
* Transform a file or directory recursively.
*
* @param string $target Path to the target file or directory.
*
* @return void
*/
public function transform(string $target)
{
$this->transformer->transform($target);
}
}

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
class ImposterFactory
{
/**
* @param string $projectPath
* @param string[] $extraExcludes
*
* @return Imposter
*/
public static function forProject(string $projectPath, array $extraExcludes = []): Imposter
{
$filesystem = new Filesystem();
$projectConfig = ConfigFactory::buildProjectConfig($projectPath . '/composer.json', $filesystem);
$projectConfig->setExtraExcludes($extraExcludes);
$transformer = new Transformer($projectConfig->getImposterNamespace(), $filesystem);
$configCollection = ConfigCollectionFactory::forProject(
$projectConfig,
$filesystem
);
return new Imposter($configCollection, $transformer, $filesystem);
}
}

View File

@@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
interface ImposterInterface
{
/**
* Get all valid (exist) autoload paths.
*
* @return string[]
*/
public function getAutoloads(): array;
/**
* Get all invalid (not exist) autoload paths.
*
* @return string[]
*/
public function getInvalidAutoloads(): array;
/**
* Transform all autoload files.
*
* @return void
*/
public function run();
/**
* Transform a file or directory recursively.
*
* @param string $target Path to the target file or directory.
*
* @return void
*/
public function transform(string $target);
}

View File

@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
use UnexpectedValueException;
class ProjectConfig extends Config implements ProjectConfigInterface
{
/**
* @var string[]
*/
protected const DEFAULT_EXCLUDES = ['typisttech/imposter'];
/**
* @var string[]
*/
private $extraExcludes = [];
/**
* @return string[]
*/
public function getExcludes(): array
{
$extra = $this->get('extra');
$excludes = $extra['imposter']['excludes'] ?? [];
return array_merge(static::DEFAULT_EXCLUDES, $excludes, $this->extraExcludes);
}
public function getImposterNamespace(): string
{
$extra = $this->get('extra');
if (empty($extra['imposter']['namespace'])) {
throw new UnexpectedValueException('Imposter namespace is empty');
}
return $extra['imposter']['namespace'];
}
public function getVendorDir(): string
{
$config = $this->get('config');
$vendorDir = $config['vendor-dir'] ?? 'vendor';
return StringUtil::addTrailingSlash($this->packageDir . $vendorDir);
}
/**
* @param string[] $extraExcludes
*
* @return void
*/
public function setExtraExcludes(array $extraExcludes)
{
$this->extraExcludes = $extraExcludes;
}
}

View File

@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
interface ProjectConfigInterface extends ConfigInterface
{
/**
* @return string[]
*/
public function getExcludes(): array;
public function getImposterNamespace(): string;
public function getVendorDir(): string;
/**
* @param string[] $extraExcludes
*
* @return void
*/
public function setExtraExcludes(array $extraExcludes);
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
class StringUtil
{
public static function addTrailingSlash(string $string): string
{
return rtrim($string, '/\\') . '/';
}
public static function ensureDoubleBackwardSlash(string $string): string
{
$parts = explode('\\', $string);
$nonEmptyParts = array_filter($parts, function ($part) {
return ! empty($part);
});
return implode('\\\\', $nonEmptyParts) . '\\\\';
}
}

View File

@@ -0,0 +1,166 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
use SplFileInfo;
class Transformer implements TransformerInterface
{
/**
* @var FilesystemInterface
*/
private $filesystem;
/**
* @var string
*/
private $namespacePrefix;
/**
* Transformer constructor.
*
* @param string $namespacePrefix
* @param FilesystemInterface $filesystem
*/
public function __construct(string $namespacePrefix, FilesystemInterface $filesystem)
{
$this->namespacePrefix = StringUtil::ensureDoubleBackwardSlash($namespacePrefix);
$this->filesystem = $filesystem;
}
/**
* Transform a file or directory recursively.
*
* @todo Skip non-php files.
*
* @param string $target Path to the target file or directory.
*
* @return void
*/
public function transform(string $target)
{
if ($this->filesystem->isFile($target)) {
$this->doTransform($target);
return;
}
$files = $this->filesystem->allFiles($target);
array_walk($files, function (SplFileInfo $file) {
$this->doTransform($file->getRealPath());
});
}
/**
* @param string $targetFile
*
* @return void
*/
private function doTransform(string $targetFile)
{
$this->prefixNamespace($targetFile);
$this->prefixUseConst($targetFile);
$this->prefixUseFunction($targetFile);
$this->prefixUse($targetFile);
}
/**
* Prefix namespace at the given path.
*
* @param string $targetFile
*
* @return void
*/
private function prefixNamespace(string $targetFile)
{
$pattern = sprintf(
'/(\s+)%1$s\\s+(?!(%2$s)|(Composer(\\\\|;)))/',
'namespace',
$this->namespacePrefix
);
$replacement = sprintf('%1$s %2$s', '${1}namespace', $this->namespacePrefix);
$this->replace($pattern, $replacement, $targetFile);
}
/**
* Replace string in the given file.
*
* @param string $pattern
* @param string $replacement
* @param string $targetFile
*
* @return void
*/
private function replace(string $pattern, string $replacement, string $targetFile)
{
$this->filesystem->put(
$targetFile,
preg_replace(
$pattern,
$replacement,
$this->filesystem->get($targetFile)
)
);
}
/**
* Prefix `use const` keywords at the given path.
*
* @param string $targetFile
*
* @return void
*/
private function prefixUseConst(string $targetFile)
{
$pattern = sprintf(
'/%1$s\\s+(?!(%2$s)|(\\\\(?!.*\\\\.*))|(Composer(\\\\|;)|(?!.*\\\\.*)))/',
'use const',
$this->namespacePrefix
);
$replacement = sprintf('%1$s %2$s', 'use const', $this->namespacePrefix);
$this->replace($pattern, $replacement, $targetFile);
}
/**
* Prefix `use function` keywords at the given path.
*
* @param string $targetFile
*
* @return void
*/
private function prefixUseFunction(string $targetFile)
{
$pattern = sprintf(
'/%1$s\\s+(?!(%2$s)|(\\\\(?!.*\\\\.*))|(Composer(\\\\|;)|(?!.*\\\\.*)))/',
'use function',
$this->namespacePrefix
);
$replacement = sprintf('%1$s %2$s', 'use function', $this->namespacePrefix);
$this->replace($pattern, $replacement, $targetFile);
}
/**
* Prefix `use` keywords at the given path.
*
* @param string $targetFile
*
* @return void
*/
private function prefixUse(string $targetFile)
{
$pattern = sprintf(
'/%1$s\\s+(?!(const)|(function)|(%2$s)|(\\\\(?!.*\\\\.*))|(Composer(\\\\|;)|(?!.*\\\\.*)))/',
'use',
$this->namespacePrefix
);
$replacement = sprintf('%1$s %2$s', 'use', $this->namespacePrefix);
$this->replace($pattern, $replacement, $targetFile);
}
}

View File

@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace TypistTech\Imposter;
interface TransformerInterface
{
/**
* Transform a file or directory recursively.
*
* @param string $target Path to the target file or directory.
*
* @return void
*/
public function transform(string $target);
}