[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\ntrim_trailing_whitespace = true\n\n[*.md]\ntrim_trailing_whitespace = false\n\n[*.{yml,yaml}]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto\n\n/tests export-ignore\n/.editorconfig export-ignore\n/.gitattributes export-ignore\n/.github export-ignore\n/.gitignore export-ignore\n/.github export-ignore\n/Makefile export-ignore\n/phpstan-baseline.neon export-ignore\n/phpstan.neon.dist export-ignore\n/phpunit.xml.dist export-ignore\n/README.md export-ignore\n/UPGRADING.md export-ignore\n/vendor-bin export-ignore\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# CONTRIBUTOR COVENANT CODE OF CONDUCT\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual identity\nand orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the\n  overall community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or\n  advances of any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email\n  address, without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at\nhello@gjcampbell.co.uk.\nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series\nof actions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or\npermanent ban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior,  harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within\nthe community.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][Mozilla CoC].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n[https://www.contributor-covenant.org/faq][FAQ]. Translations are available\nat [https://www.contributor-covenant.org/translations][translations].\n\n[homepage]: https://www.contributor-covenant.org\n[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html\n[Mozilla CoC]: https://github.com/mozilla/diversity\n[FAQ]: https://www.contributor-covenant.org/faq\n[translations]: https://www.contributor-covenant.org/translations\n"
  },
  {
    "path": ".github/CONTRIBUTING.md",
    "content": "# CONTRIBUTION GUIDELINES\n\nContributions are **welcome** and will be fully **credited**.\n\nWe accept contributions via pull requests on Github. Please review these guidelines before continuing.\n\n## Guidelines\n\n* Please follow the [PSR-12 Coding Style Guide](https://www.php-fig.org/psr/psr-12/).\n* Ensure that the current tests pass, and if you've added something new, add the tests where relevant.\n* Send a coherent commit history, making sure each individual commit in your pull request is meaningful.\n* You may need to [rebase](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) to avoid merge conflicts.\n* If you are changing or adding to the behaviour or public api, you may need to update the docs.\n* Please remember that we follow [SemVer](https://semver.org/).\n\n## Running Tests\n\nFirst, install the dependencies using [Composer](https://getcomposer.org/):\n\n```bash\n$ make install\n```\n\nThen run [PHPUnit](https://phpunit.de/) and the static analyzers:\n\n```bash\n$ make test\n```\n\nThese will also be automatically run by [GitHub Actions](https://github.com/features/actions) against pull requests.\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "github: GrahamCampbell\ntidelift: \"packagist/vlucas/phpdotenv\"\n"
  },
  {
    "path": ".github/SECURITY.md",
    "content": "# SECURITY POLICY\n\n## Supported Versions\n\nAfter each new major release, the previous release will be supported for no\nless than 2 years, unless explicitly stated otherwise. This may mean that there\nare multiple supported versions at any given time.\n\n## Reporting a Vulnerability\n\nIf you discover a security vulnerability within this package, please send an\nemail to security@tidelift.com. All security vulnerabilities will be promptly\naddressed. Please do not disclose security-related issues publicly until a fix\nhas been announced.\n"
  },
  {
    "path": ".github/workflows/static.yml",
    "content": "name: Static Analysis\n\non:\n  push:\n  pull_request:\n\njobs:\n  phpstan:\n    name: PHPStan\n    runs-on: ubuntu-24.04\n\n    steps:\n      - name: Checkout code\n        uses: actions/checkout@v6\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: '8.5'\n          tools: composer:v2\n          coverage: none\n        env:\n          update: true\n\n      - name: Install Dependencies\n        uses: nick-fields/retry@v3\n        with:\n          timeout_minutes: 5\n          max_attempts: 5\n          command: composer update --no-interaction --no-progress\n\n      - name: Install PHPStan\n        uses: nick-fields/retry@v3\n        with:\n          timeout_minutes: 5\n          max_attempts: 5\n          command: composer bin phpstan update --no-interaction --no-progress\n\n      - name: Execute PHPStan\n        run: vendor/bin/phpstan analyze --no-progress\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Tests\n\non:\n  push:\n  pull_request:\n\njobs:\n  latest:\n    name: PHP ${{ matrix.php }} Latest\n    runs-on: ubuntu-24.04\n\n    strategy:\n      matrix:\n        php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']\n\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@v6\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          tools: composer:v2\n          coverage: none\n\n      - name: Setup Problem Matchers\n        run: echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"\n\n      - name: Install Latest Dependencies\n        uses: nick-fields/retry@v3\n        with:\n          timeout_minutes: 5\n          max_attempts: 5\n          command: composer update --no-interaction --no-progress\n\n      - name: Execute PHPUnit\n        run: vendor/bin/phpunit\n\n  lowest:\n    name: PHP ${{ matrix.php }} Lowest\n    runs-on: ubuntu-24.04\n\n    strategy:\n      matrix:\n        php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5']\n\n    steps:\n      - name: Checkout Code\n        uses: actions/checkout@v6\n\n      - name: Setup PHP\n        uses: shivammathur/setup-php@v2\n        with:\n          php-version: ${{ matrix.php }}\n          tools: composer:v2\n          coverage: none\n\n      - name: Setup Problem Matchers\n        run: echo \"::add-matcher::${{ runner.tool_cache }}/phpunit.json\"\n\n      - name: Install Lowest Dependencies\n        uses: nick-fields/retry@v3\n        with:\n          timeout_minutes: 5\n          max_attempts: 5\n          command: composer update --prefer-lowest --prefer-stable --no-interaction --no-progress\n\n      - name: Execute PHPUnit\n        run: vendor/bin/phpunit\n"
  },
  {
    "path": ".gitignore",
    "content": ".phpunit.result.cache\ncomposer.lock\nphpstan.neon\nphpstan.tests.neon\nphpunit.xml\nvendor\n"
  },
  {
    "path": "LICENSE",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2014, Graham Campbell.\nCopyright (c) 2013, Vance Lucas.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "Makefile",
    "content": "install:\n\t@docker run -it -w /data -v ${PWD}:/data:delegated -v ~/.composer:/root/.composer:delegated --entrypoint composer --rm registry.gitlab.com/grahamcampbell/php:8.5-base update\n\t@docker run -it -w /data -v ${PWD}:/data:delegated -v ~/.composer:/root/.composer:delegated --entrypoint composer --rm registry.gitlab.com/grahamcampbell/php:8.5-base bin all update\n\nphpunit:\n\t@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpunit --rm registry.gitlab.com/grahamcampbell/php:8.5-cli\n\nphpstan-analyze:\n\t@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpstan --rm registry.gitlab.com/grahamcampbell/php:8.5-cli analyze\n\nphpstan-baseline:\n\t@docker run -it -w /data -v ${PWD}:/data:delegated --entrypoint vendor/bin/phpstan --rm registry.gitlab.com/grahamcampbell/php:8.5-cli analyze --generate-baseline\n\ntest: phpunit phpstan-analyze\n\nclean:\n\t@rm -rf .phpunit.result.cache composer.lock vendor vendor-bin/*/composer.lock vendor-bin/*/vendor\n"
  },
  {
    "path": "README.md",
    "content": "PHP dotenv\n==========\n\nLoads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.\n\n![Banner](https://user-images.githubusercontent.com/2829600/71564012-31105580-2a91-11ea-9ad7-ef1278411b35.png)\n\n<p align=\"center\">\n<a href=\"LICENSE\"><img src=\"https://img.shields.io/badge/license-BSD%203--Clause-brightgreen.svg?style=flat-square\" alt=\"Software License\"></img></a>\n<a href=\"https://packagist.org/packages/vlucas/phpdotenv\"><img src=\"https://img.shields.io/packagist/dt/vlucas/phpdotenv.svg?style=flat-square\" alt=\"Total Downloads\"></img></a>\n<a href=\"https://github.com/vlucas/phpdotenv/releases\"><img src=\"https://img.shields.io/github/release/vlucas/phpdotenv.svg?style=flat-square\" alt=\"Latest Version\"></img></a>\n</p>\n\n<div align=\"center\">\n\n**Special thanks to [our sponsors](https://github.com/sponsors/GrahamCampbell)**\n\n<hr>\n</div>\n\n\n## Why .env?\n\n**You should never store sensitive credentials in your code**. Storing\n[configuration in the environment](https://www.12factor.net/config) is one of\nthe tenets of a [twelve-factor app](https://www.12factor.net/). Anything that\nis likely to change between deployment environments – such as database\ncredentials or credentials for 3rd party services – should be extracted from\nthe code into environment variables.\n\nBasically, a `.env` file is an easy way to load custom configuration variables\nthat your application needs without having to modify .htaccess files or\nApache/nginx virtual hosts. This means you won't have to edit any files outside\nthe project, and all the environment variables are always set no matter how you\nrun your project - Apache, Nginx, CLI, and even PHP's built-in webserver. It's\nWAY easier than all the other ways you know of to set environment variables,\nand you're going to love it!\n\n* NO editing virtual hosts in Apache or Nginx\n* NO adding `php_value` flags to .htaccess files\n* EASY portability and sharing of required ENV values\n* COMPATIBLE with PHP's built-in web server and CLI runner\n\nPHP dotenv is a PHP version of the original [Ruby\ndotenv](https://github.com/bkeepers/dotenv).\n\n\n## Installation\n\nInstallation is super-easy via [Composer](https://getcomposer.org/):\n\n```bash\n$ composer require vlucas/phpdotenv\n```\n\nor add it by hand to your `composer.json` file.\n\n\n## Upgrading\n\nWe follow [semantic versioning](https://semver.org/), which means breaking\nchanges may occur between major releases. We have upgrading guides available\nfor V2 to V3, V3 to V4 and V4 to V5 available [here](UPGRADING.md).\n\n\n## Usage\n\nThe `.env` file is generally kept out of version control since it can contain\nsensitive API keys and passwords. A separate `.env.example` file is created\nwith all the required environment variables defined except for the sensitive\nones, which are either user-supplied for their own development environments or\nare communicated elsewhere to project collaborators. The project collaborators\nthen independently copy the `.env.example` file to a local `.env` and ensure\nall the settings are correct for their local environment, filling in the secret\nkeys or providing their own values when necessary. In this usage, the `.env`\nfile should be added to the project's `.gitignore` file so that it will never\nbe committed by collaborators.  This usage ensures that no sensitive passwords\nor API keys will ever be in the version control history so there is less risk\nof a security breach, and production values will never have to be shared with\nall project collaborators.\n\nAdd your application configuration to a `.env` file in the root of your\nproject. **Make sure the `.env` file is added to your `.gitignore` so it is not\nchecked-in the code**\n\n```shell\nS3_BUCKET=\"dotenv\"\nSECRET_KEY=\"souper_seekret_key\"\n```\n\nNow create a file named `.env.example` and check this into the project. This\nshould have the ENV variables you need to have set, but the values should\neither be blank or filled with dummy data. The idea is to let people know what\nvariables are required, but not give them the sensitive production values.\n\n```shell\nS3_BUCKET=\"devbucket\"\nSECRET_KEY=\"abc123\"\n```\n\nYou can then load `.env` in your application with:\n\n```php\n$dotenv = Dotenv\\Dotenv::createImmutable(__DIR__);\n$dotenv->load();\n```\n\nTo suppress the exception that is thrown when there is no `.env` file, you can:\n\n```php\n$dotenv = Dotenv\\Dotenv::createImmutable(__DIR__);\n$dotenv->safeLoad();\n```\n\nOptionally you can pass in a filename as the second parameter, if you would\nlike to use something other than `.env`:\n\n```php\n$dotenv = Dotenv\\Dotenv::createImmutable(__DIR__, 'myconfig');\n$dotenv->load();\n```\n\nAll of the defined variables are now available in the `$_ENV` and `$_SERVER`\nsuper-globals.\n\n```php\n$s3_bucket = $_ENV['S3_BUCKET'];\n$s3_bucket = $_SERVER['S3_BUCKET'];\n```\n\n\n### Putenv and Getenv\n\nUsing `getenv()` and `putenv()` is strongly discouraged due to the fact that\nthese functions are not thread safe, however it is still possible to instruct\nPHP dotenv to use these functions. Instead of calling\n`Dotenv::createImmutable`, one can call `Dotenv::createUnsafeImmutable`, which\nwill add the `PutenvAdapter` behind the scenes. Your environment variables will\nnow be available using the `getenv` method, as well as the super-globals:\n\n```php\n$s3_bucket = getenv('S3_BUCKET');\n$s3_bucket = $_ENV['S3_BUCKET'];\n$s3_bucket = $_SERVER['S3_BUCKET'];\n```\n\n\n### Nesting Variables\n\nIt's possible to nest an environment variable within another, useful to cut\ndown on repetition.\n\nThis is done by wrapping an existing environment variable in `${…}` e.g.\n\n```shell\nBASE_DIR=\"/var/webroot/project-root\"\nCACHE_DIR=\"${BASE_DIR}/cache\"\nTMP_DIR=\"${BASE_DIR}/tmp\"\n```\n\n\n### Immutability and Repository Customization\n\nImmutability refers to if Dotenv is allowed to overwrite existing environment\nvariables. If you want Dotenv to overwrite existing environment variables,\nuse `createMutable` instead of `createImmutable`:\n\n```php\n$dotenv = Dotenv\\Dotenv::createMutable(__DIR__);\n$dotenv->load();\n```\n\nBehind the scenes, this is instructing the \"repository\" to allow immutability\nor not. By default, the repository is configured to allow overwriting existing\nvalues by default, which is relevant if one is calling the \"create\" method\nusing the `RepositoryBuilder` to construct a more custom repository:\n\n```php\n$repository = Dotenv\\Repository\\RepositoryBuilder::createWithNoAdapters()\n    ->addAdapter(Dotenv\\Repository\\Adapter\\EnvConstAdapter::class)\n    ->addWriter(Dotenv\\Repository\\Adapter\\PutenvAdapter::class)\n    ->immutable()\n    ->make();\n\n$dotenv = Dotenv\\Dotenv::create($repository, __DIR__);\n$dotenv->load();\n```\n\nThe above example will write loaded values to `$_ENV` and `putenv`, but when\ninterpolating environment variables, we'll only read from `$_ENV`. Moreover, it\nwill never replace any variables already set before loading the file.\n\nBy means of another example, one can also specify a set of variables to be\nallow listed. That is, only the variables in the allow list will be loaded:\n\n```php\n$repository = Dotenv\\Repository\\RepositoryBuilder::createWithDefaultAdapters()\n    ->allowList(['FOO', 'BAR'])\n    ->make();\n\n$dotenv = Dotenv\\Dotenv::create($repository, __DIR__);\n$dotenv->load();\n```\n\n\n### Requiring Variables to be Set\n\nPHP dotenv has built in validation functionality, including for enforcing the\npresence of an environment variable. This is particularly useful to let people\nknow any explicit required variables that your app will not work without.\n\nYou can use a single string:\n\n```php\n$dotenv->required('DATABASE_DSN');\n```\n\nOr an array of strings:\n\n```php\n$dotenv->required(['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS']);\n```\n\nIf any ENV vars are missing, Dotenv will throw a `RuntimeException` like this:\n\n```\nOne or more environment variables failed assertions: DATABASE_DSN is missing\n```\n\n\n### Empty Variables\n\nBeyond simply requiring a variable to be set, you might also need to ensure the\nvariable is not empty:\n\n```php\n$dotenv->required('DATABASE_DSN')->notEmpty();\n```\n\nIf the environment variable is empty, you'd get an Exception:\n\n```\nOne or more environment variables failed assertions: DATABASE_DSN is empty\n```\n\n\n### Integer Variables\n\nYou might also need to ensure that the variable is of an integer value. You may\ndo the following:\n\n```php\n$dotenv->required('FOO')->isInteger();\n```\n\nIf the environment variable is not an integer, you'd get an Exception:\n\n```\nOne or more environment variables failed assertions: FOO is not an integer.\n```\n\nOne may only want to enforce validation rules when a variable is set. We\nsupport this too:\n\n```php\n$dotenv->ifPresent('FOO')->isInteger();\n```\n\n\n### Boolean Variables\n\nYou may need to ensure a variable is in the form of a boolean, accepting\n\"true\", \"false\", \"On\", \"1\", \"Yes\", \"Off\", \"0\" and \"No\". You may do the\nfollowing:\n\n```php\n$dotenv->required('FOO')->isBoolean();\n```\n\nIf the environment variable is not a boolean, you'd get an Exception:\n\n```\nOne or more environment variables failed assertions: FOO is not a boolean.\n```\n\nSimilarly, one may write:\n\n```php\n$dotenv->ifPresent('FOO')->isBoolean();\n```\n\n\n### Allowed Values\n\nIt is also possible to define a set of values that your environment variable\nshould be. This is especially useful in situations where only a handful of\noptions or drivers are actually supported by your code:\n\n```php\n$dotenv->required('SESSION_STORE')->allowedValues(['Filesystem', 'Memcached']);\n```\n\nIf the environment variable wasn't in this list of allowed values, you'd get a\nsimilar Exception:\n\n```\nOne or more environment variables failed assertions: SESSION_STORE is not an allowed value.\n```\n\nIt is also possible to define a regex that your environment variable should be.\n```php\n$dotenv->required('FOO')->allowedRegexValues('([[:lower:]]{3})');\n```\n\n\n### Comments\n\nYou can comment your `.env` file using the `#` character. E.g.\n\n```shell\n# this is a comment\nVAR=\"value\" # comment\nVAR=value # comment\n```\n\n\n### Parsing Without Loading\n\nSometimes you just wanna parse the file and resolve the nested environment variables, by giving us a string, and have an array returned back to you. While this is already possible, it is a little fiddly, so we have provided a direct way to do this:\n\n```php\n// ['FOO' => 'Bar', 'BAZ' => 'Hello Bar']\nDotenv\\Dotenv::parse(\"FOO=Bar\\nBAZ=\\\"Hello \\${FOO}\\\"\");\n```\n\nThis is exactly the same as:\n\n```php\nDotenv\\Dotenv::createArrayBacked(__DIR__)->load();\n```\n\nonly, instead of providing the directory to find the file, you have directly provided the file contents.\n\n\n### Usage Notes\n\nWhen a new developer clones your codebase, they will have an additional\none-time step to manually copy the `.env.example` file to `.env` and fill-in\ntheir own values (or get any sensitive values from a project co-worker).\n\n\n### Troubleshooting\n\nIn certain server setups (most commonly found in shared hosting), PHP might deactivate superglobals like `$_ENV` or `$_SERVER`. If these variables are not set, review the `variables_order` in the `php.ini` file. See [php.net/manual/en/ini.core.php#ini.variables-order](https://www.php.net/manual/en/ini.core.php#ini.variables-order).\n\n## Security\n\nIf you discover a security vulnerability within this package, please send an email to security@tidelift.com. All security vulnerabilities will be promptly addressed. You may view our full security policy [here](https://github.com/vlucas/phpdotenv/security/policy).\n\n\n## License\n\nPHP dotenv is licensed under [The BSD 3-Clause License](LICENSE).\n\n\n## For Enterprise\n\nAvailable as part of the Tidelift Subscription\n\nThe maintainers of `vlucas/phpdotenv` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-vlucas-phpdotenv?utm_source=packagist-vlucas-phpdotenv&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)\n"
  },
  {
    "path": "UPGRADING.md",
    "content": "# Upgrading Guide\n\n## V5.5 to V5.6\n\nBumping the minimum required PHP version is not a breaking change, however it is notable. Since version 5.6.0, we now require PHP 7.2.5 or higher. Installation metrics show that for some time, PHP 7.1 has represented only around 0.1% of installs of V5.\n\nRelease notes for 5.6.0 are available [here](https://github.com/vlucas/phpdotenv/releases/tag/v5.6.0).\n\n## V4 to V5\n\n### Introduction\n\nVersion 5 bumps to PHP 7.1+, and adds some additional parameter typing. There have been some internal changes and refactorings too, but nothing that changes the overall feel and usage of the package. The Dotenv class itself is largely unchanged from V4.\n\nRelease notes for 5.0.0 are available [here](https://github.com/vlucas/phpdotenv/releases/tag/v5.0.0).\n\n### Details\n\n1. The `Dotenv\\Dotenv::createImmutable` and `Dotenv\\Dotenv::createMutable` methods no longer call will result in `getenv` and `putenv` being called. One should instead use `Dotenv\\Dotenv::createUnsafeImmutable` and `Dotenv\\Dotenv::createUnsafeMutable` methods, if one really needs these functions.\n2. The `Dotenv\\Dotenv` constructor has been modified to expect exactly 4 parameters: a store, a parser, a loader, and a repository. This likely won't affect many people, since it is more common to construct this class via the public static create methods. Those methods have not changed.\n3. Scalar typehints have been added to the public interface.\n4. The parser now returns a result type instead of raising an exception. This change is strictly internal, and most users won't notice a difference. The responsibility for raising an exception has simply been shifted up to the caller.\n5. Adapters have been refactored again, with changes to the repositories. In particular, the repository builder has been tweaked. It now expects to be explicitly told if you want to use the default adapters or not, and expects individual readers and writers to be added, one by one. Similar changes have been applied to the store factory. Moreover, the `ApacheAdapter` has been changed so that it behaves much like the other adapters. The old behaviour can be simulated by composing it with the new `ReplacingWriter` (see below). We will no longer include this adapter in our default setup, so that people can enable exactly what they need. Finally, by default, we will no longer be using the `PutenvAdapter`. It can be added, as required.\n6. Variable whitelisting has been replaced with allow listing, and the responsibility has moved from the loader to a new adapter `GuardedWriter`.\n7. The parser has been moved to its own namespace and parses entire files now. This change is expected to have little impact when upgrading. The `Lines` class has also moved to the parser namespace.\n8. The loader now only returns the variables that were actually loaded into the repository, and not all the variables from the file. Moreover, it now expects as input the result of running the new parser (an array of entries), rather than raw file content.\n\nThe changes listed in (4) mean that instead of:\n\n```php\n$repository = Dotenv\\Repository\\RepositoryBuilder::create()\n    ->withReaders([\n        new Dotenv\\Repository\\Adapter\\EnvConstAdapter(),\n    ])\n    ->withWriters([\n        new Dotenv\\Repository\\Adapter\\EnvConstAdapter(),\n        new Dotenv\\Repository\\Adapter\\PutenvAdapter(),\n    ])\n    ->make();\n```\n\none would now write:\n\n```php\n$repository = Dotenv\\Repository\\RepositoryBuilder::createWithNoAdapters()\n    ->addAdapter(Dotenv\\Repository\\Adapter\\EnvConstAdapter::class)\n    ->addWriter(Dotenv\\Repository\\Adapter\\PutenvAdapter::class)\n    ->make();\n```\n\nInstead of passing class names, one can also pass actual adapter instances. Note that it is not possible to directly construct any of the adapters. One has to go via their static `create` method which returns an optional. This is to strictly encapsulate the fact that not all adapters are capable of running on all systems, and so those that cannot be run, cannot be created. For example, the apache adapter can only be run within an apache web server context. Passing the class names as in the above example will handle this for you, by adding the adapter only if it can be created (the optional has a value set).\n\nTo add an apache environment variable writer that only writes to existing apache environment variables, as was the default in v4, one should do the following:\n\n```php\n$builder = Dotenv\\Repository\\RepositoryBuilder::createWithDefaultAdapters();\n\nDotenv\\Repository\\Adapter\\ApacheAdapter::create()->map(function ($adapter) {\n    return new Dotenv\\Repository\\Adapter\\ReplacingWriter($adapter, $adapter);\n})->map([$builder, 'addWriter'])->getOrElse($builder);\n\n$repository = $builder->make();\n```\n\nThe use of optionals handles the case where the apache environment functions are not available (such as in a CLI environment).\n\n## V4.0 to V4.1\n\n### Introduction\n\nVersion 4.1 is a minor release, and as such, there are no breaking changes. There is, however a deprecation to be noted.\n\n### Details\n\nThe `Dotenv\\Dotenv` constructor now expects either an array of file paths as the third parameter, or an instance of `Dotenv\\Store\\StoreInterface`. Passing an array is deprecated, and will be removed in V5.\n\n## V3 to V4\n\n### Introduction\n\nVersion 4 sees some refactoring, and support for escaping dollars in values (https://github.com/vlucas/phpdotenv/pull/380). It is no longer possible to change immutability on the fly, and the `Loader` no longer is responsible for tracking immutability. It is now the responsibility of \"repositories\" to track this. One must explicitly decide if they want (im)mutability when constructing an instance of `Dotenv\\Dotenv`.\n\nRelease notes for 4.0.0 are available [here](https://github.com/vlucas/phpdotenv/releases/tag/v4.0.0).\n\n### Details\n\nV4 has again changed the way you initialize the `Dotenv` class. If you want immutable loading of environment variables, then replace `Dotenv::create` with `Dotenv::createImmutable`, and if you want mutable loading, replace `Dotenv::create` with `Dotenv::createMutable` and `->overload()` with `->load()`. The `overload` method has been removed in favour of specifying mutability at object construction.\n\nThe behaviour when parsing single quoted strings has now changed, to mimic the behaviour of bash. It is no longer possible to escape characters in single quoted strings, and everything is treated literally. As soon as the first single quote character is read, after the initial one, then the variable is treated as ending immediately at that point. When parsing unquoted or double quoted strings, it is now possible to escape dollar signs, to forcefully avoid variable interpolation. Escaping dollars is not mandated, in the sense that if a dollar is present, and not following by variable interpolation syntax, this is allowed, and the dollar will be treated as a literal dollar. Finally, interpolation of variables is now performed right to left, instead of left to right, so it is possible to nest interpolations to allow using the value of a variable as the name of another for further interpolation.\n\nThe `getEnvironmentVariableNames` method is no longer available. This is because calls to `load()` (since v3.0.0) return an associative array of what was loaded, so `$dotenv->getEnvironmentVariableNames()` can be replaced with `array_keys($dotenv->load())`.\n\nThere have been various internal refactorings. Apart from what has already been mentioned, the only other changes likely to affect developers is:\n\n1. The `Dotenv\\Environment` namespace has been moved to `Dotenv\\Repository`, the `Dotenv\\Environment\\Adapter\\AdapterInterface` interface has been replaced by `Dotenv\\Repository\\Adapter\\ReaderInterface` and `Dotenv\\Repository\\Adapter\\WriterInterface`.\n2. The `Dotenv\\Environment\\DotenvFactory` has been (roughly) replaced by `Dotenv\\Repository\\RepositoryBuilder`, and `Dotenv\\Environment\\FactoryInterface` has been deleted.\n3. `Dotenv\\Environment\\AbstractVariables` has been replaced by `Dotenv\\Repository\\AbstractRepository`, `Dotenv\\Environment\\DotenvVariables` has been replaced by `Dotenv\\Repository\\AdapterRepository`, and `Dotenv\\Environment\\VariablesInterface` has been replaced by `Dotenv\\Repository\\RepositoryInterface`.\n4. The `Dotenv\\Loader` class has been moved to `Dotenv\\Loader\\Loader`, and now has a different public interface. It no longer expects any parameters at construction, and implements only the new interface `Dotenv\\Loader\\LoaderInterface`. Its responsibility has changed to purely taking raw env file content, and handing it off to the parser, dealing with variable interpolation, and sending off instructions to the repository to set variables. No longer can it be used as a way to read the environment by callers, and nor does it track immutability.\n5. The `Dotenv\\Parser` and `Dotenv\\Lines` classes have moved to `Dotenv\\Loader\\Parser` and `Dotenv\\Loader\\Lines`, respectively. `Dotenv\\Loader\\Parser::parse` now return has either `null` or `Dotenv\\Loader\\Value` objects as values, instead of `string`s. This is to support the new variable interpolation and dollar escaping features.\n6. The `Dotenv\\Validator` constructor has changed from `__construct(array $variables, Loader $loader, $required = true)` to `__construct(RepositoryInterface $repository, array $variables, $required = true)`.\n\nThe example at the bottom of the below upgrading guide, in V4 now looks like:\n\n```php\n<?php\n\nuse Dotenv\\Dotenv;\nuse Dotenv\\Repository\\Adapter\\EnvConstAdapter;\nuse Dotenv\\Repository\\Adapter\\ServerConstAdapter;\nuse Dotenv\\Repository\\RepositoryBuilder;\n\n$adapters = [\n\tnew EnvConstAdapter(),\n\tnew ServerConstAdapter(),\n];\n\n$repository = RepositoryBuilder::create()\n    ->withReaders($adapters)\n    ->withWriters($adapters)\n    ->immutable()\n    ->make();\n\nDotenv::create($repository, $path, null)->load();\n```\n\nSince v3.2.0, it was easily possible to read a file and process variable interpolations, without actually \"loading\" the variables. This is still possible in v4.0.0. Example code that does this is as follows:\n\n```php\n<?php\n\nuse Dotenv\\Repository\\Adapter\\ArrayAdapter;\nuse Dotenv\\Repository\\RepositoryBuilder;\nuse Dotenv\\Loader\\Loader;\n\n$adapters = [new ArrayAdapter()];\n\n$repository = RepositoryBuilder::create()\n    ->withReaders($adapters)\n    ->withWriters($adapters)\n    ->make();\n\n$variables = (new Loader())->load($repository, $content);\n```\n\nNotice, that compared to v3, the loader no longer expects file paths in the constructor. Reading of the files is now managed by the `Dotenv\\Dotenv` class. The loader is genuinely just loading the content into the repository.\n\nFinally, we note that the minimum supported version of PHP has increased to 5.5.9, up from 5.4.0 in V3 and 5.3.9 in V2.\n\n## V2 to V3\n\n### Introduction\n\nNew in Version 3 is first-class support for multiline variables ([#301](https://github.com/vlucas/phpdotenv/pull/301)) and much more flexibility in terms of which parts of the environment we try to read and modify ([#300](https://github.com/vlucas/phpdotenv/pull/300)). Consequently, you will need to replace any occurrences of `new Dotenv(...)` with `Dotenv::create(...)`, since our new native constructor takes a `Loader` instance now, so that it can be truly customized if required. Finally, one should note that the loader will no longer be trimming values ([#302](https://github.com/vlucas/phpdotenv/pull/302)), moreover `Loader::load()` and its callers now return an associative array of the variables loaded with their values, rather than an array of raw lines from the environment file ([#306](https://github.com/vlucas/phpdotenv/pull/306)).\n\nRelease notes for 3.0.0 are available [here](https://github.com/vlucas/phpdotenv/releases/tag/v3.0.0).\n\n### Details\n\nV3 has changed the way you initialize the `Dotenv` class. Consequently, you will need to replace any occurrences of new Dotenv(...) with Dotenv::create(...), since our new native constructor takes a `Loader` instance now.\n\n`Loader::load()` and its callers now return an associative array of the variables loaded with their values.\n\nValue parsing has been modified in the following ways:\n\n1. For unquoted strings, as soon as there's a hash, it's treated as a comment start.\n2. We're being stricter about invalid escape sequences within quoted strings.\n3. We're no longer trimming the parsed values of quoted strings.\n4. Multiline quoted values are now permitted, and will be parsed by V3.\n\n| input value | V2.5.2 | V2.6.1 | V3.3.1 |\n|-|-|-|-|\n| `foo#bar` | `foo#bar` | `foo#bar` | `foo` |\n| `foo # bar` | `foo` | `foo` | `foo` |\n| `\"iiiiviiiixiiiiviiii\\n\"` | silent failure | `iiiviiiixiiiiviiii\\n` | fails with invalid escape sequence exception |\n| `\"iiiiviiiixiiiiviiii\\\\n\"` | `iiiiviiiixiiiiviiii\\n` | `iiiiviiiixiiiiviiii\\n` | `iiiiviiiixiiiiviiii\\n` |\n| `\"foo\\\"bar\"` | `foo\"bar` | `foo\"bar` | `foo\"bar` |\n| `\"  foo \"` | `foo` with whitespace trimmed | `foo` with whitespace trimmed | `foo` with 2 spaces in front and one after |\n\nIn double quoted strings, double quotes and backslashes need escaping with a backslash, and in single quoted strings, single quote and backslashes need escaping with a backslash. In v2.5.2, forgetting an escape can lead to odd results due to the regex running out of stack, but this was fixed in 2.6 and 3.3, with 2.6 allowing you to continue after an unescaped backslash, but 3.3 not.\n\nIt's possible to use phpdotenv V3 in a threaded environment, instructing it to not call any functions that are not tread-safe:\n\n```php\n<?php\n\nuse Dotenv\\Dotenv;\nuse Dotenv\\Environment\\Adapter\\EnvConstAdapter;\nuse Dotenv\\Environment\\Adapter\\ServerConstAdapter;\nuse Dotenv\\Environment\\DotenvFactory;\n\n$factory = new DotenvFactory([new EnvConstAdapter(), new ServerConstAdapter()]);\n\nDotenv::create($path, null, $factory)->load();\n```\n\nFinally, we note that the minimum supported version of PHP has increased from 5.3.9 to 5.4.0.\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"vlucas/phpdotenv\",\n    \"description\": \"Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.\",\n    \"keywords\": [\"env\", \"dotenv\", \"environment\"],\n    \"license\": \"BSD-3-Clause\",\n    \"authors\": [\n        {\n            \"name\": \"Graham Campbell\",\n            \"email\": \"hello@gjcampbell.co.uk\",\n            \"homepage\": \"https://github.com/GrahamCampbell\"\n        },\n        {\n            \"name\": \"Vance Lucas\",\n            \"email\": \"vance@vancelucas.com\",\n            \"homepage\": \"https://github.com/vlucas\"\n        }\n    ],\n    \"require\": {\n        \"php\": \"^7.2.5 || ^8.0\",\n        \"ext-pcre\": \"*\",\n        \"graham-campbell/result-type\": \"^1.1.4\",\n        \"phpoption/phpoption\": \"^1.9.5\",\n        \"symfony/polyfill-ctype\": \"^1.26\",\n        \"symfony/polyfill-mbstring\": \"^1.26\",\n        \"symfony/polyfill-php80\": \"^1.26\"\n    },\n    \"require-dev\": {\n        \"ext-filter\": \"*\",\n        \"bamarni/composer-bin-plugin\": \"^1.8.2\",\n        \"phpunit/phpunit\":\"^8.5.34 || ^9.6.13 || ^10.4.2\"\n    },\n    \"autoload\": {\n        \"psr-4\": {\n            \"Dotenv\\\\\": \"src/\"\n        }\n    },\n    \"autoload-dev\": {\n        \"psr-4\": {\n            \"Dotenv\\\\Tests\\\\\": \"tests/Dotenv/\"\n        }\n    },\n    \"suggest\": {\n        \"ext-filter\": \"Required to use the boolean validator.\"\n    },\n    \"config\": {\n        \"allow-plugins\": {\n            \"bamarni/composer-bin-plugin\": true\n        },\n        \"preferred-install\": \"dist\"\n    },\n    \"extra\": {\n        \"bamarni-bin\": {\n            \"bin-links\": true,\n            \"forward-command\": false\n        },\n        \"branch-alias\": {\n            \"dev-master\": \"5.6-dev\"\n        }\n    }\n}\n"
  },
  {
    "path": "phpstan-baseline.neon",
    "content": "parameters:\n\tignoreErrors:\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<Dotenv\\\\Parser\\\\Value\\> is not subtype of type PhpOption\\\\Option\\<Dotenv\\\\Parser\\\\Value\\|null\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Parser/Entry.php\n\n\t\t-\n\t\t\tmessage: '#^Anonymous function should return GrahamCampbell\\\\ResultType\\\\Result\\<mixed, string\\> but returns GrahamCampbell\\\\ResultType\\\\Result\\<Dotenv\\\\Parser\\\\Entry, string\\>\\.$#'\n\t\t\tidentifier: return.type\n\t\t\tcount: 1\n\t\t\tpath: src/Parser/EntryParser.php\n\n\t\t-\n\t\t\tmessage: '#^Method Dotenv\\\\Parser\\\\EntryParser\\:\\:parse\\(\\) should return GrahamCampbell\\\\ResultType\\\\Result\\<Dotenv\\\\Parser\\\\Entry, string\\> but returns GrahamCampbell\\\\ResultType\\\\Result\\<mixed, string\\>\\.$#'\n\t\t\tidentifier: return.type\n\t\t\tcount: 1\n\t\t\tpath: src/Parser/EntryParser.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type GrahamCampbell\\\\ResultType\\\\Result\\<Dotenv\\\\Parser\\\\Value\\|null, string\\> is not subtype of type GrahamCampbell\\\\ResultType\\\\Result\\<Dotenv\\\\Parser\\\\Value, string\\>\\|GrahamCampbell\\\\ResultType\\\\Result\\<null, mixed\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Parser/EntryParser.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#2 \\$callback of function array_reduce expects callable\\(GrahamCampbell\\\\ResultType\\\\Result\\<array\\{Dotenv\\\\Parser\\\\Value, int\\}, mixed\\>\\|GrahamCampbell\\\\ResultType\\\\Result\\<array\\{mixed, int\\}, string\\>, string\\)\\: \\(GrahamCampbell\\\\ResultType\\\\Result\\<array\\{Dotenv\\\\Parser\\\\Value, int\\}, mixed\\>\\|GrahamCampbell\\\\ResultType\\\\Result\\<array\\{mixed, int\\}, string\\>\\), Closure\\(GrahamCampbell\\\\ResultType\\\\Result, string\\)\\: GrahamCampbell\\\\ResultType\\\\Result\\<array\\{Dotenv\\\\Parser\\\\Value, int\\}, string\\> given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 1\n\t\t\tpath: src/Parser/EntryParser.php\n\n\t\t-\n\t\t\tmessage: '#^Only booleans are allowed in a negated boolean, int\\|false given\\.$#'\n\t\t\tidentifier: booleanNot.exprNotBoolean\n\t\t\tcount: 1\n\t\t\tpath: src/Parser/Lexer.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#1 \\$pattern of function preg_match expects string, mixed given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 1\n\t\t\tpath: src/Parser/Lexer.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<Dotenv\\\\Repository\\\\Adapter\\\\AdapterInterface\\> is not subtype of type PhpOption\\\\Some\\<Dotenv\\\\Repository\\\\Adapter\\\\ApacheAdapter\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/ApacheAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<string\\> is not subtype of type PhpOption\\\\Option\\<string\\|false\\|null\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/ApacheAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<Dotenv\\\\Repository\\\\Adapter\\\\AdapterInterface\\> is not subtype of type PhpOption\\\\Some\\<Dotenv\\\\Repository\\\\Adapter\\\\ArrayAdapter\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/ArrayAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^Cannot cast mixed to string\\.$#'\n\t\t\tidentifier: cast.string\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/EnvConstAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<Dotenv\\\\Repository\\\\Adapter\\\\AdapterInterface\\> is not subtype of type PhpOption\\\\Some\\<Dotenv\\\\Repository\\\\Adapter\\\\EnvConstAdapter\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/EnvConstAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<Dotenv\\\\Repository\\\\Adapter\\\\AdapterInterface\\> is not subtype of type PhpOption\\\\Some\\<Dotenv\\\\Repository\\\\Adapter\\\\PutenvAdapter\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/PutenvAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<string\\> is not subtype of type PhpOption\\\\Option\\<string\\|false\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/PutenvAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^Cannot cast mixed to string\\.$#'\n\t\t\tidentifier: cast.string\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/ServerConstAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<Dotenv\\\\Repository\\\\Adapter\\\\AdapterInterface\\> is not subtype of type PhpOption\\\\Some\\<Dotenv\\\\Repository\\\\Adapter\\\\ServerConstAdapter\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/Adapter/ServerConstAdapter.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#1 \\$callable of method PhpOption\\\\Some\\<Dotenv\\\\Repository\\\\Adapter\\\\AdapterInterface\\|string\\>\\:\\:flatMap\\(\\) expects callable\\(Dotenv\\\\Repository\\\\Adapter\\\\AdapterInterface\\|string\\)\\: PhpOption\\\\Option\\<S\\>, Closure\\(mixed\\)\\: mixed given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/RepositoryBuilder.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#1 \\$callable of method PhpOption\\\\Some\\<Dotenv\\\\Repository\\\\Adapter\\\\ReaderInterface\\|string\\>\\:\\:flatMap\\(\\) expects callable\\(Dotenv\\\\Repository\\\\Adapter\\\\ReaderInterface\\|string\\)\\: PhpOption\\\\Option\\<S\\>, Closure\\(mixed\\)\\: mixed given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/RepositoryBuilder.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#1 \\$callable of method PhpOption\\\\Some\\<Dotenv\\\\Repository\\\\Adapter\\\\WriterInterface\\|string\\>\\:\\:flatMap\\(\\) expects callable\\(Dotenv\\\\Repository\\\\Adapter\\\\WriterInterface\\|string\\)\\: PhpOption\\\\Option\\<S\\>, Closure\\(mixed\\)\\: mixed given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 1\n\t\t\tpath: src/Repository/RepositoryBuilder.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#1 \\$readers of class Dotenv\\\\Repository\\\\RepositoryBuilder constructor expects array\\<Dotenv\\\\Repository\\\\Adapter\\\\ReaderInterface\\>, array\\<Dotenv\\\\Repository\\\\Adapter\\\\ReaderInterface\\|S\\> given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 2\n\t\t\tpath: src/Repository/RepositoryBuilder.php\n\n\t\t-\n\t\t\tmessage: '#^Parameter \\#2 \\$writers of class Dotenv\\\\Repository\\\\RepositoryBuilder constructor expects array\\<Dotenv\\\\Repository\\\\Adapter\\\\WriterInterface\\>, array\\<Dotenv\\\\Repository\\\\Adapter\\\\WriterInterface\\|S\\> given\\.$#'\n\t\t\tidentifier: argument.type\n\t\t\tcount: 2\n\t\t\tpath: src/Repository/RepositoryBuilder.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<string\\> is not subtype of type PhpOption\\\\Option\\<string\\|false\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Store/File/Reader.php\n\n\t\t-\n\t\t\tmessage: '#^Method Dotenv\\\\Util\\\\Regex\\:\\:occurrences\\(\\) should return GrahamCampbell\\\\ResultType\\\\Result\\<int, string\\> but returns GrahamCampbell\\\\ResultType\\\\Result\\<int\\<0, max\\>, string\\>\\.$#'\n\t\t\tidentifier: return.type\n\t\t\tcount: 1\n\t\t\tpath: src/Util/Regex.php\n\n\t\t-\n\t\t\tmessage: '#^Loose comparison via \"\\=\\=\" is not allowed\\.$#'\n\t\t\tidentifier: equal.notAllowed\n\t\t\tcount: 1\n\t\t\tpath: src/Util/Str.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type GrahamCampbell\\\\ResultType\\\\Result\\<string, string\\> is not subtype of type GrahamCampbell\\\\ResultType\\\\Result\\<mixed, non\\-falsy\\-string\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 2\n\t\t\tpath: src/Util/Str.php\n\n\t\t-\n\t\t\tmessage: '#^PHPDoc tag @var with type PhpOption\\\\Option\\<int\\> is not subtype of type PhpOption\\\\Option\\<int\\<0, max\\>\\|false\\>\\.$#'\n\t\t\tidentifier: varTag.type\n\t\t\tcount: 1\n\t\t\tpath: src/Util/Str.php\n"
  },
  {
    "path": "phpstan.neon.dist",
    "content": "includes:\n    - phpstan-baseline.neon\n\nparameters:\n    level: max\n    paths:\n        - src\n"
  },
  {
    "path": "phpunit.xml.dist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" backupGlobals=\"false\" beStrictAboutTestsThatDoNotTestAnything=\"true\" beStrictAboutOutputDuringTests=\"true\" bootstrap=\"vendor/autoload.php\" colors=\"true\" failOnRisky=\"true\" failOnWarning=\"true\" processIsolation=\"false\" stopOnError=\"false\" stopOnFailure=\"false\" xsi:noNamespaceSchemaLocation=\"https://schema.phpunit.de/10.4/phpunit.xsd\">\n  <testsuites>\n    <testsuite name=\"PHP Dotenv Test Suite\">\n      <directory suffix=\"Test.php\">./tests</directory>\n    </testsuite>\n  </testsuites>\n  <source>\n    <include>\n      <directory suffix=\".php\">./src</directory>\n    </include>\n  </source>\n</phpunit>\n"
  },
  {
    "path": "src/Dotenv.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv;\n\nuse Dotenv\\Exception\\InvalidPathException;\nuse Dotenv\\Loader\\Loader;\nuse Dotenv\\Loader\\LoaderInterface;\nuse Dotenv\\Parser\\Parser;\nuse Dotenv\\Parser\\ParserInterface;\nuse Dotenv\\Repository\\Adapter\\ArrayAdapter;\nuse Dotenv\\Repository\\Adapter\\PutenvAdapter;\nuse Dotenv\\Repository\\RepositoryBuilder;\nuse Dotenv\\Repository\\RepositoryInterface;\nuse Dotenv\\Store\\StoreBuilder;\nuse Dotenv\\Store\\StoreInterface;\nuse Dotenv\\Store\\StringStore;\n\nclass Dotenv\n{\n    /**\n     * The store instance.\n     *\n     * @var \\Dotenv\\Store\\StoreInterface\n     */\n    private $store;\n\n    /**\n     * The parser instance.\n     *\n     * @var \\Dotenv\\Parser\\ParserInterface\n     */\n    private $parser;\n\n    /**\n     * The loader instance.\n     *\n     * @var \\Dotenv\\Loader\\LoaderInterface\n     */\n    private $loader;\n\n    /**\n     * The repository instance.\n     *\n     * @var \\Dotenv\\Repository\\RepositoryInterface\n     */\n    private $repository;\n\n    /**\n     * Create a new dotenv instance.\n     *\n     * @param \\Dotenv\\Store\\StoreInterface           $store\n     * @param \\Dotenv\\Parser\\ParserInterface         $parser\n     * @param \\Dotenv\\Loader\\LoaderInterface         $loader\n     * @param \\Dotenv\\Repository\\RepositoryInterface $repository\n     *\n     * @return void\n     */\n    public function __construct(\n        StoreInterface $store,\n        ParserInterface $parser,\n        LoaderInterface $loader,\n        RepositoryInterface $repository\n    ) {\n        $this->store = $store;\n        $this->parser = $parser;\n        $this->loader = $loader;\n        $this->repository = $repository;\n    }\n\n    /**\n     * Create a new dotenv instance.\n     *\n     * @param \\Dotenv\\Repository\\RepositoryInterface $repository\n     * @param string|string[]                        $paths\n     * @param string|string[]|null                   $names\n     * @param bool                                   $shortCircuit\n     * @param string|null                            $fileEncoding\n     *\n     * @return \\Dotenv\\Dotenv\n     */\n    public static function create(RepositoryInterface $repository, $paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null)\n    {\n        $builder = $names === null ? StoreBuilder::createWithDefaultName() : StoreBuilder::createWithNoNames();\n\n        foreach ((array) $paths as $path) {\n            $builder = $builder->addPath($path);\n        }\n\n        foreach ((array) $names as $name) {\n            $builder = $builder->addName($name);\n        }\n\n        if ($shortCircuit) {\n            $builder = $builder->shortCircuit();\n        }\n\n        return new self($builder->fileEncoding($fileEncoding)->make(), new Parser(), new Loader(), $repository);\n    }\n\n    /**\n     * Create a new mutable dotenv instance with default repository.\n     *\n     * @param string|string[]      $paths\n     * @param string|string[]|null $names\n     * @param bool                 $shortCircuit\n     * @param string|null          $fileEncoding\n     *\n     * @return \\Dotenv\\Dotenv\n     */\n    public static function createMutable($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null)\n    {\n        $repository = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding);\n    }\n\n    /**\n     * Create a new mutable dotenv instance with default repository with the putenv adapter.\n     *\n     * @param string|string[]      $paths\n     * @param string|string[]|null $names\n     * @param bool                 $shortCircuit\n     * @param string|null          $fileEncoding\n     *\n     * @return \\Dotenv\\Dotenv\n     */\n    public static function createUnsafeMutable($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null)\n    {\n        $repository = RepositoryBuilder::createWithDefaultAdapters()\n            ->addAdapter(PutenvAdapter::class)\n            ->make();\n\n        return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding);\n    }\n\n    /**\n     * Create a new immutable dotenv instance with default repository.\n     *\n     * @param string|string[]      $paths\n     * @param string|string[]|null $names\n     * @param bool                 $shortCircuit\n     * @param string|null          $fileEncoding\n     *\n     * @return \\Dotenv\\Dotenv\n     */\n    public static function createImmutable($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null)\n    {\n        $repository = RepositoryBuilder::createWithDefaultAdapters()->immutable()->make();\n\n        return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding);\n    }\n\n    /**\n     * Create a new immutable dotenv instance with default repository with the putenv adapter.\n     *\n     * @param string|string[]      $paths\n     * @param string|string[]|null $names\n     * @param bool                 $shortCircuit\n     * @param string|null          $fileEncoding\n     *\n     * @return \\Dotenv\\Dotenv\n     */\n    public static function createUnsafeImmutable($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null)\n    {\n        $repository = RepositoryBuilder::createWithDefaultAdapters()\n            ->addAdapter(PutenvAdapter::class)\n            ->immutable()\n            ->make();\n\n        return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding);\n    }\n\n    /**\n     * Create a new dotenv instance with an array backed repository.\n     *\n     * @param string|string[]      $paths\n     * @param string|string[]|null $names\n     * @param bool                 $shortCircuit\n     * @param string|null          $fileEncoding\n     *\n     * @return \\Dotenv\\Dotenv\n     */\n    public static function createArrayBacked($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null)\n    {\n        $repository = RepositoryBuilder::createWithNoAdapters()->addAdapter(ArrayAdapter::class)->make();\n\n        return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding);\n    }\n\n    /**\n     * Parse the given content and resolve nested variables.\n     *\n     * This method behaves just like load(), only without mutating your actual\n     * environment. We do this by using an array backed repository.\n     *\n     * @param string $content\n     *\n     * @throws \\Dotenv\\Exception\\InvalidFileException\n     *\n     * @return array<string, string|null>\n     */\n    public static function parse(string $content)\n    {\n        $repository = RepositoryBuilder::createWithNoAdapters()->addAdapter(ArrayAdapter::class)->make();\n\n        $phpdotenv = new self(new StringStore($content), new Parser(), new Loader(), $repository);\n\n        return $phpdotenv->load();\n    }\n\n    /**\n     * Read and load environment file(s).\n     *\n     * @throws \\Dotenv\\Exception\\InvalidPathException|\\Dotenv\\Exception\\InvalidEncodingException|\\Dotenv\\Exception\\InvalidFileException\n     *\n     * @return array<string, string|null>\n     */\n    public function load()\n    {\n        $entries = $this->parser->parse($this->store->read());\n\n        return $this->loader->load($this->repository, $entries);\n    }\n\n    /**\n     * Read and load environment file(s), silently failing if no files can be read.\n     *\n     * @throws \\Dotenv\\Exception\\InvalidEncodingException|\\Dotenv\\Exception\\InvalidFileException\n     *\n     * @return array<string, string|null>\n     */\n    public function safeLoad()\n    {\n        try {\n            return $this->load();\n        } catch (InvalidPathException $e) {\n            // suppressing exception\n            return [];\n        }\n    }\n\n    /**\n     * Required ensures that the specified variables exist, and returns a new validator object.\n     *\n     * @param string|string[] $variables\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function required($variables)\n    {\n        return (new Validator($this->repository, (array) $variables))->required();\n    }\n\n    /**\n     * Returns a new validator object that won't check if the specified variables exist.\n     *\n     * @param string|string[] $variables\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function ifPresent($variables)\n    {\n        return new Validator($this->repository, (array) $variables);\n    }\n}\n"
  },
  {
    "path": "src/Exception/ExceptionInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Exception;\n\nuse Throwable;\n\ninterface ExceptionInterface extends Throwable\n{\n    //\n}\n"
  },
  {
    "path": "src/Exception/InvalidEncodingException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Exception;\n\nuse InvalidArgumentException;\n\nfinal class InvalidEncodingException extends InvalidArgumentException implements ExceptionInterface\n{\n    //\n}\n"
  },
  {
    "path": "src/Exception/InvalidFileException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Exception;\n\nuse InvalidArgumentException;\n\nfinal class InvalidFileException extends InvalidArgumentException implements ExceptionInterface\n{\n    //\n}\n"
  },
  {
    "path": "src/Exception/InvalidPathException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Exception;\n\nuse InvalidArgumentException;\n\nfinal class InvalidPathException extends InvalidArgumentException implements ExceptionInterface\n{\n    //\n}\n"
  },
  {
    "path": "src/Exception/ValidationException.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Exception;\n\nuse RuntimeException;\n\nfinal class ValidationException extends RuntimeException implements ExceptionInterface\n{\n    //\n}\n"
  },
  {
    "path": "src/Loader/Loader.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Loader;\n\nuse Dotenv\\Parser\\Entry;\nuse Dotenv\\Parser\\Value;\nuse Dotenv\\Repository\\RepositoryInterface;\n\nfinal class Loader implements LoaderInterface\n{\n    /**\n     * Load the given entries into the repository.\n     *\n     * We'll substitute any nested variables, and send each variable to the\n     * repository, with the effect of actually mutating the environment.\n     *\n     * @param \\Dotenv\\Repository\\RepositoryInterface $repository\n     * @param \\Dotenv\\Parser\\Entry[]                 $entries\n     *\n     * @return array<string, string|null>\n     */\n    public function load(RepositoryInterface $repository, array $entries)\n    {\n        /** @var array<string, string|null> */\n        return \\array_reduce($entries, static function (array $vars, Entry $entry) use ($repository) {\n            $name = $entry->getName();\n\n            $value = $entry->getValue()->map(static function (Value $value) use ($repository) {\n                return Resolver::resolve($repository, $value);\n            });\n\n            if ($value->isDefined()) {\n                $inner = $value->get();\n                if ($repository->set($name, $inner)) {\n                    return \\array_merge($vars, [$name => $inner]);\n                }\n            } else {\n                if ($repository->clear($name)) {\n                    return \\array_merge($vars, [$name => null]);\n                }\n            }\n\n            return $vars;\n        }, []);\n    }\n}\n"
  },
  {
    "path": "src/Loader/LoaderInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Loader;\n\nuse Dotenv\\Repository\\RepositoryInterface;\n\ninterface LoaderInterface\n{\n    /**\n     * Load the given entries into the repository.\n     *\n     * @param \\Dotenv\\Repository\\RepositoryInterface $repository\n     * @param \\Dotenv\\Parser\\Entry[]                 $entries\n     *\n     * @return array<string, string|null>\n     */\n    public function load(RepositoryInterface $repository, array $entries);\n}\n"
  },
  {
    "path": "src/Loader/Resolver.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Loader;\n\nuse Dotenv\\Parser\\Value;\nuse Dotenv\\Repository\\RepositoryInterface;\nuse Dotenv\\Util\\Regex;\nuse Dotenv\\Util\\Str;\nuse PhpOption\\Option;\n\nfinal class Resolver\n{\n    /**\n     * This class is a singleton.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Resolve the nested variables in the given value.\n     *\n     * Replaces ${varname} patterns in the allowed positions in the variable\n     * value by an existing environment variable.\n     *\n     * @param \\Dotenv\\Repository\\RepositoryInterface $repository\n     * @param \\Dotenv\\Parser\\Value                   $value\n     *\n     * @return string\n     */\n    public static function resolve(RepositoryInterface $repository, Value $value)\n    {\n        return \\array_reduce($value->getVars(), static function (string $s, int $i) use ($repository) {\n            return Str::substr($s, 0, $i).self::resolveVariable($repository, Str::substr($s, $i));\n        }, $value->getChars());\n    }\n\n    /**\n     * Resolve a single nested variable.\n     *\n     * @param \\Dotenv\\Repository\\RepositoryInterface $repository\n     * @param string                                 $str\n     *\n     * @return string\n     */\n    private static function resolveVariable(RepositoryInterface $repository, string $str)\n    {\n        return Regex::replaceCallback(\n            '/\\A\\${([a-zA-Z0-9_.]+)}/',\n            static function (array $matches) use ($repository) {\n                /** @var string */\n                return Option::fromValue($repository->get($matches[1]))->getOrElse($matches[0]);\n            },\n            $str,\n            1\n        )->success()->getOrElse($str);\n    }\n}\n"
  },
  {
    "path": "src/Parser/Entry.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Parser;\n\nuse PhpOption\\Option;\n\nfinal class Entry\n{\n    /**\n     * The entry name.\n     *\n     * @var string\n     */\n    private $name;\n\n    /**\n     * The entry value.\n     *\n     * @var \\Dotenv\\Parser\\Value|null\n     */\n    private $value;\n\n    /**\n     * Create a new entry instance.\n     *\n     * @param string                    $name\n     * @param \\Dotenv\\Parser\\Value|null $value\n     *\n     * @return void\n     */\n    public function __construct(string $name, ?Value $value = null)\n    {\n        $this->name = $name;\n        $this->value = $value;\n    }\n\n    /**\n     * Get the entry name.\n     *\n     * @return string\n     */\n    public function getName()\n    {\n        return $this->name;\n    }\n\n    /**\n     * Get the entry value.\n     *\n     * @return \\PhpOption\\Option<\\Dotenv\\Parser\\Value>\n     */\n    public function getValue()\n    {\n        /** @var \\PhpOption\\Option<\\Dotenv\\Parser\\Value> */\n        return Option::fromValue($this->value);\n    }\n}\n"
  },
  {
    "path": "src/Parser/EntryParser.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Parser;\n\nuse Dotenv\\Util\\Regex;\nuse Dotenv\\Util\\Str;\nuse GrahamCampbell\\ResultType\\Error;\nuse GrahamCampbell\\ResultType\\Result;\nuse GrahamCampbell\\ResultType\\Success;\n\nfinal class EntryParser\n{\n    private const INITIAL_STATE = 0;\n    private const UNQUOTED_STATE = 1;\n    private const SINGLE_QUOTED_STATE = 2;\n    private const DOUBLE_QUOTED_STATE = 3;\n    private const ESCAPE_SEQUENCE_STATE = 4;\n    private const WHITESPACE_STATE = 5;\n    private const COMMENT_STATE = 6;\n    private const REJECT_STATES = [self::SINGLE_QUOTED_STATE, self::DOUBLE_QUOTED_STATE, self::ESCAPE_SEQUENCE_STATE];\n\n    /**\n     * This class is a singleton.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Parse a raw entry into a proper entry.\n     *\n     * That is, turn a raw environment variable entry into a name and possibly\n     * a value. We wrap the answer in a result type.\n     *\n     * @param string $entry\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Entry, string>\n     */\n    public static function parse(string $entry)\n    {\n        return self::splitStringIntoParts($entry)->flatMap(static function (array $parts) {\n            [$name, $value] = $parts;\n\n            return self::parseName($name)->flatMap(static function (string $name) use ($value) {\n                /** @var Result<Value|null, string> */\n                $parsedValue = $value === null ? Success::create(null) : self::parseValue($value);\n\n                return $parsedValue->map(static function (?Value $value) use ($name) {\n                    return new Entry($name, $value);\n                });\n            });\n        });\n    }\n\n    /**\n     * Split the compound string into parts.\n     *\n     * @param string $line\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<array{string, string|null},string>\n     */\n    private static function splitStringIntoParts(string $line)\n    {\n        /** @var array{string, string|null} */\n        $result = Str::pos($line, '=')->map(static function () use ($line) {\n            return \\array_map('trim', \\explode('=', $line, 2));\n        })->getOrElse([$line, null]);\n\n        if ($result[0] === '') {\n            /** @var \\GrahamCampbell\\ResultType\\Result<array{string, string|null},string> */\n            return Error::create(self::getErrorMessage('an unexpected equals', $line));\n        }\n\n        /** @var \\GrahamCampbell\\ResultType\\Result<array{string, string|null},string> */\n        return Success::create($result);\n    }\n\n    /**\n     * Parse the given variable name.\n     *\n     * That is, strip the optional quotes and leading \"export\" from the\n     * variable name. We wrap the answer in a result type.\n     *\n     * @param string $name\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<string, string>\n     */\n    private static function parseName(string $name)\n    {\n        if (Str::len($name) > 8 && Str::substr($name, 0, 6) === 'export' && \\ctype_space(Str::substr($name, 6, 1))) {\n            $name = \\ltrim(Str::substr($name, 6));\n        }\n\n        if (self::isQuotedName($name)) {\n            $name = Str::substr($name, 1, -1);\n        }\n\n        if (!self::isValidName($name)) {\n            /** @var \\GrahamCampbell\\ResultType\\Result<string, string> */\n            return Error::create(self::getErrorMessage('an invalid name', $name));\n        }\n\n        /** @var \\GrahamCampbell\\ResultType\\Result<string, string> */\n        return Success::create($name);\n    }\n\n    /**\n     * Is the given variable name quoted?\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    private static function isQuotedName(string $name)\n    {\n        if (Str::len($name) < 3) {\n            return false;\n        }\n\n        $first = Str::substr($name, 0, 1);\n        $last = Str::substr($name, -1, 1);\n\n        return ($first === '\"' && $last === '\"') || ($first === '\\'' && $last === '\\'');\n    }\n\n    /**\n     * Is the given variable name valid?\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    private static function isValidName(string $name)\n    {\n        return Regex::matches('~(*UTF8)\\A[\\p{Ll}\\p{Lu}\\p{M}\\p{N}_.]+\\z~', $name)->success()->getOrElse(false);\n    }\n\n    /**\n     * Parse the given variable value.\n     *\n     * This has the effect of stripping quotes and comments, dealing with\n     * special characters, and locating nested variables, but not resolving\n     * them. Formally, we run a finite state automaton with an output tape: a\n     * transducer. We wrap the answer in a result type.\n     *\n     * @param string $value\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Value, string>\n     */\n    private static function parseValue(string $value)\n    {\n        if (\\trim($value) === '') {\n            /** @var \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Value, string> */\n            return Success::create(Value::blank());\n        }\n\n        return \\array_reduce(\\iterator_to_array(Lexer::lex($value)), static function (Result $data, string $token) {\n            return $data->flatMap(static function (array $data) use ($token) {\n                return self::processToken($data[1], $token)->map(static function (array $val) use ($data) {\n                    return [$data[0]->append($val[0], $val[1]), $val[2]];\n                });\n            });\n        }, Success::create([Value::blank(), self::INITIAL_STATE]))->flatMap(static function (array $result) {\n            if (in_array($result[1], self::REJECT_STATES, true)) {\n                /** @var \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Value, string> */\n                return Error::create('a missing closing quote');\n            }\n\n            /** @var \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Value, string> */\n            return Success::create($result[0]);\n        })->mapError(static function (string $err) use ($value) {\n            return self::getErrorMessage($err, $value);\n        });\n    }\n\n    /**\n     * Process the given token.\n     *\n     * @param int    $state\n     * @param string $token\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string>\n     */\n    private static function processToken(int $state, string $token)\n    {\n        switch ($state) {\n            case self::INITIAL_STATE:\n                if ($token === '\\'') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::SINGLE_QUOTED_STATE]);\n                } elseif ($token === '\"') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::DOUBLE_QUOTED_STATE]);\n                } elseif ($token === '#') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::COMMENT_STATE]);\n                } elseif ($token === '$') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, true, self::UNQUOTED_STATE]);\n                } else {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, false, self::UNQUOTED_STATE]);\n                }\n            case self::UNQUOTED_STATE:\n                if ($token === '#') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::COMMENT_STATE]);\n                } elseif (\\ctype_space($token)) {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::WHITESPACE_STATE]);\n                } elseif ($token === '$') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, true, self::UNQUOTED_STATE]);\n                } else {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, false, self::UNQUOTED_STATE]);\n                }\n            case self::SINGLE_QUOTED_STATE:\n                if ($token === '\\'') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::WHITESPACE_STATE]);\n                } else {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, false, self::SINGLE_QUOTED_STATE]);\n                }\n            case self::DOUBLE_QUOTED_STATE:\n                if ($token === '\"') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::WHITESPACE_STATE]);\n                } elseif ($token === '\\\\') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::ESCAPE_SEQUENCE_STATE]);\n                } elseif ($token === '$') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, true, self::DOUBLE_QUOTED_STATE]);\n                } else {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, false, self::DOUBLE_QUOTED_STATE]);\n                }\n            case self::ESCAPE_SEQUENCE_STATE:\n                if ($token === '\"' || $token === '\\\\') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, false, self::DOUBLE_QUOTED_STATE]);\n                } elseif ($token === '$') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create([$token, false, self::DOUBLE_QUOTED_STATE]);\n                } else {\n                    $first = Str::substr($token, 0, 1);\n                    if (\\in_array($first, ['f', 'n', 'r', 't', 'v'], true)) {\n                        /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                        return Success::create([\\stripcslashes('\\\\'.$first).Str::substr($token, 1), false, self::DOUBLE_QUOTED_STATE]);\n                    } else {\n                        /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                        return Error::create('an unexpected escape sequence');\n                    }\n                }\n            case self::WHITESPACE_STATE:\n                if ($token === '#') {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::COMMENT_STATE]);\n                } elseif (!\\ctype_space($token)) {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Error::create('unexpected whitespace');\n                } else {\n                    /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                    return Success::create(['', false, self::WHITESPACE_STATE]);\n                }\n            case self::COMMENT_STATE:\n                /** @var \\GrahamCampbell\\ResultType\\Result<array{string, bool, int}, string> */\n                return Success::create(['', false, self::COMMENT_STATE]);\n            default:\n                throw new \\Error('Parser entered invalid state.');\n        }\n    }\n\n    /**\n     * Generate a friendly error message.\n     *\n     * @param string $cause\n     * @param string $subject\n     *\n     * @return string\n     */\n    private static function getErrorMessage(string $cause, string $subject)\n    {\n        return \\sprintf(\n            'Encountered %s at [%s].',\n            $cause,\n            \\strtok($subject, \"\\n\")\n        );\n    }\n}\n"
  },
  {
    "path": "src/Parser/Lexer.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Parser;\n\nfinal class Lexer\n{\n    /**\n     * The regex for each type of token.\n     */\n    private const PATTERNS = [\n        '[\\r\\n]{1,1000}', '[^\\S\\r\\n]{1,1000}', '\\\\\\\\', '\\'', '\"', '\\\\#', '\\\\$', '([^(\\s\\\\\\\\\\'\"\\\\#\\\\$)]|\\\\(|\\\\)){1,1000}',\n    ];\n\n    /**\n     * This class is a singleton.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Convert content into a token stream.\n     *\n     * Multibyte string processing is not needed here, and nether is error\n     * handling, for performance reasons.\n     *\n     * @param string $content\n     *\n     * @return \\Generator<string>\n     */\n    public static function lex(string $content)\n    {\n        static $regex;\n\n        if ($regex === null) {\n            $regex = '(('.\\implode(')|(', self::PATTERNS).'))A';\n        }\n\n        $offset = 0;\n\n        while (isset($content[$offset])) {\n            if (!\\preg_match($regex, $content, $matches, 0, $offset)) {\n                throw new \\Error(\\sprintf('Lexer encountered unexpected character [%s].', $content[$offset]));\n            }\n\n            $offset += \\strlen($matches[0]);\n\n            yield $matches[0];\n        }\n    }\n}\n"
  },
  {
    "path": "src/Parser/Lines.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Parser;\n\nuse Dotenv\\Util\\Regex;\nuse Dotenv\\Util\\Str;\n\nfinal class Lines\n{\n    /**\n     * This class is a singleton.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Process the array of lines of environment variables.\n     *\n     * This will produce an array of raw entries, one per variable.\n     *\n     * @param string[] $lines\n     *\n     * @return string[]\n     */\n    public static function process(array $lines)\n    {\n        $output = [];\n        $multiline = false;\n        $multilineBuffer = [];\n\n        foreach ($lines as $line) {\n            [$multiline, $line, $multilineBuffer] = self::multilineProcess($multiline, $line, $multilineBuffer);\n\n            if (!$multiline && !self::isCommentOrWhitespace($line)) {\n                $output[] = $line;\n            }\n        }\n\n        return $output;\n    }\n\n    /**\n     * Used to make all multiline variable process.\n     *\n     * @param bool     $multiline\n     * @param string   $line\n     * @param string[] $buffer\n     *\n     * @return array{bool,string, string[]}\n     */\n    private static function multilineProcess(bool $multiline, string $line, array $buffer)\n    {\n        $startsOnCurrentLine = $multiline ? false : self::looksLikeMultilineStart($line);\n\n        // check if $line can be multiline variable\n        if ($startsOnCurrentLine) {\n            $multiline = true;\n        }\n\n        if ($multiline) {\n            \\array_push($buffer, $line);\n\n            if (self::looksLikeMultilineStop($line, $startsOnCurrentLine)) {\n                $multiline = false;\n                $line = \\implode(\"\\n\", $buffer);\n                $buffer = [];\n            }\n        }\n\n        return [$multiline, $line, $buffer];\n    }\n\n    /**\n     * Determine if the given line can be the start of a multiline variable.\n     *\n     * @param string $line\n     *\n     * @return bool\n     */\n    private static function looksLikeMultilineStart(string $line)\n    {\n        return Str::pos($line, '=\"')->map(static function () use ($line) {\n            return self::looksLikeMultilineStop($line, true) === false;\n        })->getOrElse(false);\n    }\n\n    /**\n     * Determine if the given line can be the start of a multiline variable.\n     *\n     * @param string $line\n     * @param bool   $started\n     *\n     * @return bool\n     */\n    private static function looksLikeMultilineStop(string $line, bool $started)\n    {\n        if ($line === '\"') {\n            return true;\n        }\n\n        return Regex::occurrences('/(?=([^\\\\\\\\]\"))/', \\str_replace('\\\\\\\\', '', $line))->map(static function (int $count) use ($started) {\n            return $started ? $count > 1 : $count >= 1;\n        })->success()->getOrElse(false);\n    }\n\n    /**\n     * Determine if the line in the file is a comment or whitespace.\n     *\n     * @param string $line\n     *\n     * @return bool\n     */\n    private static function isCommentOrWhitespace(string $line)\n    {\n        $line = \\trim($line);\n\n        return $line === '' || (isset($line[0]) && $line[0] === '#');\n    }\n}\n"
  },
  {
    "path": "src/Parser/Parser.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Parser;\n\nuse Dotenv\\Exception\\InvalidFileException;\nuse Dotenv\\Util\\Regex;\nuse GrahamCampbell\\ResultType\\Result;\nuse GrahamCampbell\\ResultType\\Success;\n\nfinal class Parser implements ParserInterface\n{\n    /**\n     * Parse content into an entry array.\n     *\n     * @param string $content\n     *\n     * @throws \\Dotenv\\Exception\\InvalidFileException\n     *\n     * @return \\Dotenv\\Parser\\Entry[]\n     */\n    public function parse(string $content)\n    {\n        return Regex::split(\"/(\\r\\n|\\n|\\r)/\", $content)->mapError(static function () {\n            return 'Could not split into separate lines.';\n        })->flatMap(static function (array $lines) {\n            return self::process(Lines::process($lines));\n        })->mapError(static function (string $error) {\n            throw new InvalidFileException(\\sprintf('Failed to parse dotenv file. %s', $error));\n        })->success()->get();\n    }\n\n    /**\n     * Convert the raw entries into proper entries.\n     *\n     * @param string[] $entries\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Entry[], string>\n     */\n    private static function process(array $entries)\n    {\n        /** @var \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Entry[], string> */\n        return \\array_reduce($entries, static function (Result $result, string $raw) {\n            return $result->flatMap(static function (array $entries) use ($raw) {\n                return EntryParser::parse($raw)->map(static function (Entry $entry) use ($entries) {\n                    /** @var \\Dotenv\\Parser\\Entry[] */\n                    return \\array_merge($entries, [$entry]);\n                });\n            });\n        }, Success::create([]));\n    }\n}\n"
  },
  {
    "path": "src/Parser/ParserInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Parser;\n\ninterface ParserInterface\n{\n    /**\n     * Parse content into an entry array.\n     *\n     * @param string $content\n     *\n     * @throws \\Dotenv\\Exception\\InvalidFileException\n     *\n     * @return \\Dotenv\\Parser\\Entry[]\n     */\n    public function parse(string $content);\n}\n"
  },
  {
    "path": "src/Parser/Value.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Parser;\n\nuse Dotenv\\Util\\Str;\n\nfinal class Value\n{\n    /**\n     * The string representation of the parsed value.\n     *\n     * @var string\n     */\n    private $chars;\n\n    /**\n     * The locations of the variables in the value.\n     *\n     * @var int[]\n     */\n    private $vars;\n\n    /**\n     * Internal constructor for a value.\n     *\n     * @param string $chars\n     * @param int[]  $vars\n     *\n     * @return void\n     */\n    private function __construct(string $chars, array $vars)\n    {\n        $this->chars = $chars;\n        $this->vars = $vars;\n    }\n\n    /**\n     * Create an empty value instance.\n     *\n     * @return \\Dotenv\\Parser\\Value\n     */\n    public static function blank()\n    {\n        return new self('', []);\n    }\n\n    /**\n     * Create a new value instance, appending the characters.\n     *\n     * @param string $chars\n     * @param bool   $var\n     *\n     * @return \\Dotenv\\Parser\\Value\n     */\n    public function append(string $chars, bool $var)\n    {\n        return new self(\n            $this->chars.$chars,\n            $var ? \\array_merge($this->vars, [Str::len($this->chars)]) : $this->vars\n        );\n    }\n\n    /**\n     * Get the string representation of the parsed value.\n     *\n     * @return string\n     */\n    public function getChars()\n    {\n        return $this->chars;\n    }\n\n    /**\n     * Get the locations of the variables in the value.\n     *\n     * @return int[]\n     */\n    public function getVars()\n    {\n        $vars = $this->vars;\n\n        \\rsort($vars);\n\n        return $vars;\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/AdapterInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\ninterface AdapterInterface extends ReaderInterface, WriterInterface\n{\n    /**\n     * Create a new instance of the adapter, if it is available.\n     *\n     * @return \\PhpOption\\Option<\\Dotenv\\Repository\\Adapter\\AdapterInterface>\n     */\n    public static function create();\n}\n"
  },
  {
    "path": "src/Repository/Adapter/ApacheAdapter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nuse PhpOption\\None;\nuse PhpOption\\Option;\nuse PhpOption\\Some;\n\nfinal class ApacheAdapter implements AdapterInterface\n{\n    /**\n     * Create a new apache adapter instance.\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Create a new instance of the adapter, if it is available.\n     *\n     * @return \\PhpOption\\Option<\\Dotenv\\Repository\\Adapter\\AdapterInterface>\n     */\n    public static function create()\n    {\n        if (self::isSupported()) {\n            /** @var \\PhpOption\\Option<AdapterInterface> */\n            return Some::create(new self());\n        }\n\n        return None::create();\n    }\n\n    /**\n     * Determines if the adapter is supported.\n     *\n     * This happens if PHP is running as an Apache module.\n     *\n     * @return bool\n     */\n    private static function isSupported()\n    {\n        return \\function_exists('apache_getenv') && \\function_exists('apache_setenv');\n    }\n\n    /**\n     * Read an environment variable, if it exists.\n     *\n     * @param non-empty-string $name\n     *\n     * @return \\PhpOption\\Option<string>\n     */\n    public function read(string $name)\n    {\n        /** @var \\PhpOption\\Option<string> */\n        return Option::fromValue(apache_getenv($name))->filter(static function ($value) {\n            return \\is_string($value) && $value !== '';\n        });\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        return apache_setenv($name, $value);\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        return apache_setenv($name, '');\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/ArrayAdapter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nuse PhpOption\\Option;\nuse PhpOption\\Some;\n\nfinal class ArrayAdapter implements AdapterInterface\n{\n    /**\n     * The variables and their values.\n     *\n     * @var array<string, string>\n     */\n    private $variables;\n\n    /**\n     * Create a new array adapter instance.\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        $this->variables = [];\n    }\n\n    /**\n     * Create a new instance of the adapter, if it is available.\n     *\n     * @return \\PhpOption\\Option<\\Dotenv\\Repository\\Adapter\\AdapterInterface>\n     */\n    public static function create()\n    {\n        /** @var \\PhpOption\\Option<AdapterInterface> */\n        return Some::create(new self());\n    }\n\n    /**\n     * Read an environment variable, if it exists.\n     *\n     * @param non-empty-string $name\n     *\n     * @return \\PhpOption\\Option<string>\n     */\n    public function read(string $name)\n    {\n        return Option::fromArraysValue($this->variables, $name);\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        $this->variables[$name] = $value;\n\n        return true;\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        unset($this->variables[$name]);\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/EnvConstAdapter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nuse PhpOption\\Option;\nuse PhpOption\\Some;\n\nfinal class EnvConstAdapter implements AdapterInterface\n{\n    /**\n     * Create a new env const adapter instance.\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Create a new instance of the adapter, if it is available.\n     *\n     * @return \\PhpOption\\Option<\\Dotenv\\Repository\\Adapter\\AdapterInterface>\n     */\n    public static function create()\n    {\n        /** @var \\PhpOption\\Option<AdapterInterface> */\n        return Some::create(new self());\n    }\n\n    /**\n     * Read an environment variable, if it exists.\n     *\n     * @param non-empty-string $name\n     *\n     * @return \\PhpOption\\Option<string>\n     */\n    public function read(string $name)\n    {\n        /** @var \\PhpOption\\Option<string> */\n        return Option::fromArraysValue($_ENV, $name)\n            ->filter(static function ($value) {\n                return \\is_scalar($value);\n            })\n            ->map(static function ($value) {\n                if ($value === false) {\n                    return 'false';\n                }\n\n                if ($value === true) {\n                    return 'true';\n                }\n\n                return (string) $value;\n            });\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        $_ENV[$name] = $value;\n\n        return true;\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        unset($_ENV[$name]);\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/GuardedWriter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nfinal class GuardedWriter implements WriterInterface\n{\n    /**\n     * The inner writer to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\WriterInterface\n     */\n    private $writer;\n\n    /**\n     * The variable name allow list.\n     *\n     * @var string[]\n     */\n    private $allowList;\n\n    /**\n     * Create a new guarded writer instance.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\WriterInterface $writer\n     * @param string[]                                   $allowList\n     *\n     * @return void\n     */\n    public function __construct(WriterInterface $writer, array $allowList)\n    {\n        $this->writer = $writer;\n        $this->allowList = $allowList;\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        // Don't set non-allowed variables\n        if (!$this->isAllowed($name)) {\n            return false;\n        }\n\n        // Set the value on the inner writer\n        return $this->writer->write($name, $value);\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        // Don't clear non-allowed variables\n        if (!$this->isAllowed($name)) {\n            return false;\n        }\n\n        // Set the value on the inner writer\n        return $this->writer->delete($name);\n    }\n\n    /**\n     * Determine if the given variable is allowed.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    private function isAllowed(string $name)\n    {\n        return \\in_array($name, $this->allowList, true);\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/ImmutableWriter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nfinal class ImmutableWriter implements WriterInterface\n{\n    /**\n     * The inner writer to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\WriterInterface\n     */\n    private $writer;\n\n    /**\n     * The inner reader to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\ReaderInterface\n     */\n    private $reader;\n\n    /**\n     * The record of loaded variables.\n     *\n     * @var array<string, string>\n     */\n    private $loaded;\n\n    /**\n     * Create a new immutable writer instance.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\WriterInterface $writer\n     * @param \\Dotenv\\Repository\\Adapter\\ReaderInterface $reader\n     *\n     * @return void\n     */\n    public function __construct(WriterInterface $writer, ReaderInterface $reader)\n    {\n        $this->writer = $writer;\n        $this->reader = $reader;\n        $this->loaded = [];\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        // Don't overwrite existing environment variables\n        // Ruby's dotenv does this with `ENV[key] ||= value`\n        if ($this->isExternallyDefined($name)) {\n            return false;\n        }\n\n        // Set the value on the inner writer\n        if (!$this->writer->write($name, $value)) {\n            return false;\n        }\n\n        // Record that we have loaded the variable\n        $this->loaded[$name] = '';\n\n        return true;\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        // Don't clear existing environment variables\n        if ($this->isExternallyDefined($name)) {\n            return false;\n        }\n\n        // Clear the value on the inner writer\n        if (!$this->writer->delete($name)) {\n            return false;\n        }\n\n        // Leave the variable as fair game\n        unset($this->loaded[$name]);\n\n        return true;\n    }\n\n    /**\n     * Determine if the given variable is externally defined.\n     *\n     * That is, is it an \"existing\" variable.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    private function isExternallyDefined(string $name)\n    {\n        return $this->reader->read($name)->isDefined() && !isset($this->loaded[$name]);\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/MultiReader.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nuse PhpOption\\None;\n\nfinal class MultiReader implements ReaderInterface\n{\n    /**\n     * The set of readers to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\ReaderInterface[]\n     */\n    private $readers;\n\n    /**\n     * Create a new multi-reader instance.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\ReaderInterface[] $readers\n     *\n     * @return void\n     */\n    public function __construct(array $readers)\n    {\n        $this->readers = $readers;\n    }\n\n    /**\n     * Read an environment variable, if it exists.\n     *\n     * @param non-empty-string $name\n     *\n     * @return \\PhpOption\\Option<string>\n     */\n    public function read(string $name)\n    {\n        foreach ($this->readers as $reader) {\n            $result = $reader->read($name);\n            if ($result->isDefined()) {\n                return $result;\n            }\n        }\n\n        return None::create();\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/MultiWriter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nfinal class MultiWriter implements WriterInterface\n{\n    /**\n     * The set of writers to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\WriterInterface[]\n     */\n    private $writers;\n\n    /**\n     * Create a new multi-writer instance.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\WriterInterface[] $writers\n     *\n     * @return void\n     */\n    public function __construct(array $writers)\n    {\n        $this->writers = $writers;\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        foreach ($this->writers as $writers) {\n            if (!$writers->write($name, $value)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        foreach ($this->writers as $writers) {\n            if (!$writers->delete($name)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/PutenvAdapter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nuse PhpOption\\None;\nuse PhpOption\\Option;\nuse PhpOption\\Some;\n\nfinal class PutenvAdapter implements AdapterInterface\n{\n    /**\n     * Create a new putenv adapter instance.\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Create a new instance of the adapter, if it is available.\n     *\n     * @return \\PhpOption\\Option<\\Dotenv\\Repository\\Adapter\\AdapterInterface>\n     */\n    public static function create()\n    {\n        if (self::isSupported()) {\n            /** @var \\PhpOption\\Option<AdapterInterface> */\n            return Some::create(new self());\n        }\n\n        return None::create();\n    }\n\n    /**\n     * Determines if the adapter is supported.\n     *\n     * @return bool\n     */\n    private static function isSupported()\n    {\n        return \\function_exists('getenv') && \\function_exists('putenv');\n    }\n\n    /**\n     * Read an environment variable, if it exists.\n     *\n     * @param non-empty-string $name\n     *\n     * @return \\PhpOption\\Option<string>\n     */\n    public function read(string $name)\n    {\n        /** @var \\PhpOption\\Option<string> */\n        return Option::fromValue(\\getenv($name), false)->filter(static function ($value) {\n            return \\is_string($value);\n        });\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        \\putenv(\"$name=$value\");\n\n        return true;\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        \\putenv($name);\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/ReaderInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\ninterface ReaderInterface\n{\n    /**\n     * Read an environment variable, if it exists.\n     *\n     * @param non-empty-string $name\n     *\n     * @return \\PhpOption\\Option<string>\n     */\n    public function read(string $name);\n}\n"
  },
  {
    "path": "src/Repository/Adapter/ReplacingWriter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nfinal class ReplacingWriter implements WriterInterface\n{\n    /**\n     * The inner writer to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\WriterInterface\n     */\n    private $writer;\n\n    /**\n     * The inner reader to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\ReaderInterface\n     */\n    private $reader;\n\n    /**\n     * The record of seen variables.\n     *\n     * @var array<string, string>\n     */\n    private $seen;\n\n    /**\n     * Create a new replacement writer instance.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\WriterInterface $writer\n     * @param \\Dotenv\\Repository\\Adapter\\ReaderInterface $reader\n     *\n     * @return void\n     */\n    public function __construct(WriterInterface $writer, ReaderInterface $reader)\n    {\n        $this->writer = $writer;\n        $this->reader = $reader;\n        $this->seen = [];\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        if ($this->exists($name)) {\n            return $this->writer->write($name, $value);\n        }\n\n        // succeed if nothing to do\n        return true;\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        if ($this->exists($name)) {\n            return $this->writer->delete($name);\n        }\n\n        // succeed if nothing to do\n        return true;\n    }\n\n    /**\n     * Does the given environment variable exist.\n     *\n     * Returns true if it currently exists, or existed at any point in the past\n     * that we are aware of.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    private function exists(string $name)\n    {\n        if (isset($this->seen[$name])) {\n            return true;\n        }\n\n        if ($this->reader->read($name)->isDefined()) {\n            $this->seen[$name] = '';\n\n            return true;\n        }\n\n        return false;\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/ServerConstAdapter.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\nuse PhpOption\\Option;\nuse PhpOption\\Some;\n\nfinal class ServerConstAdapter implements AdapterInterface\n{\n    /**\n     * Create a new server const adapter instance.\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Create a new instance of the adapter, if it is available.\n     *\n     * @return \\PhpOption\\Option<\\Dotenv\\Repository\\Adapter\\AdapterInterface>\n     */\n    public static function create()\n    {\n        /** @var \\PhpOption\\Option<AdapterInterface> */\n        return Some::create(new self());\n    }\n\n    /**\n     * Read an environment variable, if it exists.\n     *\n     * @param non-empty-string $name\n     *\n     * @return \\PhpOption\\Option<string>\n     */\n    public function read(string $name)\n    {\n        /** @var \\PhpOption\\Option<string> */\n        return Option::fromArraysValue($_SERVER, $name)\n            ->filter(static function ($value) {\n                return \\is_scalar($value);\n            })\n            ->map(static function ($value) {\n                if ($value === false) {\n                    return 'false';\n                }\n\n                if ($value === true) {\n                    return 'true';\n                }\n\n                return (string) $value;\n            });\n    }\n\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value)\n    {\n        $_SERVER[$name] = $value;\n\n        return true;\n    }\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name)\n    {\n        unset($_SERVER[$name]);\n\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/Repository/Adapter/WriterInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository\\Adapter;\n\ninterface WriterInterface\n{\n    /**\n     * Write to an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     * @param string           $value\n     *\n     * @return bool\n     */\n    public function write(string $name, string $value);\n\n    /**\n     * Delete an environment variable, if possible.\n     *\n     * @param non-empty-string $name\n     *\n     * @return bool\n     */\n    public function delete(string $name);\n}\n"
  },
  {
    "path": "src/Repository/AdapterRepository.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository;\n\nuse Dotenv\\Repository\\Adapter\\ReaderInterface;\nuse Dotenv\\Repository\\Adapter\\WriterInterface;\nuse InvalidArgumentException;\n\nfinal class AdapterRepository implements RepositoryInterface\n{\n    /**\n     * The reader to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\ReaderInterface\n     */\n    private $reader;\n\n    /**\n     * The writer to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\WriterInterface\n     */\n    private $writer;\n\n    /**\n     * Create a new adapter repository instance.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\ReaderInterface $reader\n     * @param \\Dotenv\\Repository\\Adapter\\WriterInterface $writer\n     *\n     * @return void\n     */\n    public function __construct(ReaderInterface $reader, WriterInterface $writer)\n    {\n        $this->reader = $reader;\n        $this->writer = $writer;\n    }\n\n    /**\n     * Determine if the given environment variable is defined.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public function has(string $name)\n    {\n        return '' !== $name && $this->reader->read($name)->isDefined();\n    }\n\n    /**\n     * Get an environment variable.\n     *\n     * @param string $name\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return string|null\n     */\n    public function get(string $name)\n    {\n        if ('' === $name) {\n            throw new InvalidArgumentException('Expected name to be a non-empty string.');\n        }\n\n        return $this->reader->read($name)->getOrElse(null);\n    }\n\n    /**\n     * Set an environment variable.\n     *\n     * @param string $name\n     * @param string $value\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return bool\n     */\n    public function set(string $name, string $value)\n    {\n        if ('' === $name) {\n            throw new InvalidArgumentException('Expected name to be a non-empty string.');\n        }\n\n        return $this->writer->write($name, $value);\n    }\n\n    /**\n     * Clear an environment variable.\n     *\n     * @param string $name\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return bool\n     */\n    public function clear(string $name)\n    {\n        if ('' === $name) {\n            throw new InvalidArgumentException('Expected name to be a non-empty string.');\n        }\n\n        return $this->writer->delete($name);\n    }\n}\n"
  },
  {
    "path": "src/Repository/RepositoryBuilder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository;\n\nuse Dotenv\\Repository\\Adapter\\AdapterInterface;\nuse Dotenv\\Repository\\Adapter\\EnvConstAdapter;\nuse Dotenv\\Repository\\Adapter\\GuardedWriter;\nuse Dotenv\\Repository\\Adapter\\ImmutableWriter;\nuse Dotenv\\Repository\\Adapter\\MultiReader;\nuse Dotenv\\Repository\\Adapter\\MultiWriter;\nuse Dotenv\\Repository\\Adapter\\ReaderInterface;\nuse Dotenv\\Repository\\Adapter\\ServerConstAdapter;\nuse Dotenv\\Repository\\Adapter\\WriterInterface;\nuse InvalidArgumentException;\nuse PhpOption\\Some;\nuse ReflectionClass;\n\nfinal class RepositoryBuilder\n{\n    /**\n     * The set of default adapters.\n     */\n    private const DEFAULT_ADAPTERS = [\n        ServerConstAdapter::class,\n        EnvConstAdapter::class,\n    ];\n\n    /**\n     * The set of readers to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\ReaderInterface[]\n     */\n    private $readers;\n\n    /**\n     * The set of writers to use.\n     *\n     * @var \\Dotenv\\Repository\\Adapter\\WriterInterface[]\n     */\n    private $writers;\n\n    /**\n     * Are we immutable?\n     *\n     * @var bool\n     */\n    private $immutable;\n\n    /**\n     * The variable name allow list.\n     *\n     * @var string[]|null\n     */\n    private $allowList;\n\n    /**\n     * Create a new repository builder instance.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\ReaderInterface[] $readers\n     * @param \\Dotenv\\Repository\\Adapter\\WriterInterface[] $writers\n     * @param bool                                         $immutable\n     * @param string[]|null                                $allowList\n     *\n     * @return void\n     */\n    private function __construct(array $readers = [], array $writers = [], bool $immutable = false, ?array $allowList = null)\n    {\n        $this->readers = $readers;\n        $this->writers = $writers;\n        $this->immutable = $immutable;\n        $this->allowList = $allowList;\n    }\n\n    /**\n     * Create a new repository builder instance with no adapters added.\n     *\n     * @return \\Dotenv\\Repository\\RepositoryBuilder\n     */\n    public static function createWithNoAdapters()\n    {\n        return new self();\n    }\n\n    /**\n     * Create a new repository builder instance with the default adapters added.\n     *\n     * @return \\Dotenv\\Repository\\RepositoryBuilder\n     */\n    public static function createWithDefaultAdapters()\n    {\n        $adapters = \\iterator_to_array(self::defaultAdapters());\n\n        return new self($adapters, $adapters);\n    }\n\n    /**\n     * Return the array of default adapters.\n     *\n     * @return \\Generator<\\Dotenv\\Repository\\Adapter\\AdapterInterface>\n     */\n    private static function defaultAdapters()\n    {\n        foreach (self::DEFAULT_ADAPTERS as $adapter) {\n            $instance = $adapter::create();\n            if ($instance->isDefined()) {\n                yield $instance->get();\n            }\n        }\n    }\n\n    /**\n     * Determine if the given name if of an adapterclass.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    private static function isAnAdapterClass(string $name)\n    {\n        if (!\\class_exists($name)) {\n            return false;\n        }\n\n        return (new ReflectionClass($name))->implementsInterface(AdapterInterface::class);\n    }\n\n    /**\n     * Creates a repository builder with the given reader added.\n     *\n     * Accepts either a reader instance, or a class-string for an adapter. If\n     * the adapter is not supported, then we silently skip adding it.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\ReaderInterface|string $reader\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return \\Dotenv\\Repository\\RepositoryBuilder\n     */\n    public function addReader($reader)\n    {\n        if (!(\\is_string($reader) && self::isAnAdapterClass($reader)) && !($reader instanceof ReaderInterface)) {\n            throw new InvalidArgumentException(\n                \\sprintf(\n                    'Expected either an instance of %s or a class-string implementing %s',\n                    ReaderInterface::class,\n                    AdapterInterface::class\n                )\n            );\n        }\n\n        $optional = Some::create($reader)->flatMap(static function ($reader) {\n            return \\is_string($reader) ? $reader::create() : Some::create($reader);\n        });\n\n        $readers = \\array_merge($this->readers, \\iterator_to_array($optional));\n\n        return new self($readers, $this->writers, $this->immutable, $this->allowList);\n    }\n\n    /**\n     * Creates a repository builder with the given writer added.\n     *\n     * Accepts either a writer instance, or a class-string for an adapter. If\n     * the adapter is not supported, then we silently skip adding it.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\WriterInterface|string $writer\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return \\Dotenv\\Repository\\RepositoryBuilder\n     */\n    public function addWriter($writer)\n    {\n        if (!(\\is_string($writer) && self::isAnAdapterClass($writer)) && !($writer instanceof WriterInterface)) {\n            throw new InvalidArgumentException(\n                \\sprintf(\n                    'Expected either an instance of %s or a class-string implementing %s',\n                    WriterInterface::class,\n                    AdapterInterface::class\n                )\n            );\n        }\n\n        $optional = Some::create($writer)->flatMap(static function ($writer) {\n            return \\is_string($writer) ? $writer::create() : Some::create($writer);\n        });\n\n        $writers = \\array_merge($this->writers, \\iterator_to_array($optional));\n\n        return new self($this->readers, $writers, $this->immutable, $this->allowList);\n    }\n\n    /**\n     * Creates a repository builder with the given adapter added.\n     *\n     * Accepts either an adapter instance, or a class-string for an adapter. If\n     * the adapter is not supported, then we silently skip adding it. We will\n     * add the adapter as both a reader and a writer.\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\WriterInterface|string $adapter\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return \\Dotenv\\Repository\\RepositoryBuilder\n     */\n    public function addAdapter($adapter)\n    {\n        if (!(\\is_string($adapter) && self::isAnAdapterClass($adapter)) && !($adapter instanceof AdapterInterface)) {\n            throw new InvalidArgumentException(\n                \\sprintf(\n                    'Expected either an instance of %s or a class-string implementing %s',\n                    WriterInterface::class,\n                    AdapterInterface::class\n                )\n            );\n        }\n\n        $optional = Some::create($adapter)->flatMap(static function ($adapter) {\n            return \\is_string($adapter) ? $adapter::create() : Some::create($adapter);\n        });\n\n        $readers = \\array_merge($this->readers, \\iterator_to_array($optional));\n        $writers = \\array_merge($this->writers, \\iterator_to_array($optional));\n\n        return new self($readers, $writers, $this->immutable, $this->allowList);\n    }\n\n    /**\n     * Creates a repository builder with mutability enabled.\n     *\n     * @return \\Dotenv\\Repository\\RepositoryBuilder\n     */\n    public function immutable()\n    {\n        return new self($this->readers, $this->writers, true, $this->allowList);\n    }\n\n    /**\n     * Creates a repository builder with the given allow list.\n     *\n     * @param string[]|null $allowList\n     *\n     * @return \\Dotenv\\Repository\\RepositoryBuilder\n     */\n    public function allowList(?array $allowList = null)\n    {\n        return new self($this->readers, $this->writers, $this->immutable, $allowList);\n    }\n\n    /**\n     * Creates a new repository instance.\n     *\n     * @return \\Dotenv\\Repository\\RepositoryInterface\n     */\n    public function make()\n    {\n        $reader = new MultiReader($this->readers);\n        $writer = new MultiWriter($this->writers);\n\n        if ($this->immutable) {\n            $writer = new ImmutableWriter($writer, $reader);\n        }\n\n        if ($this->allowList !== null) {\n            $writer = new GuardedWriter($writer, $this->allowList);\n        }\n\n        return new AdapterRepository($reader, $writer);\n    }\n}\n"
  },
  {
    "path": "src/Repository/RepositoryInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Repository;\n\ninterface RepositoryInterface\n{\n    /**\n     * Determine if the given environment variable is defined.\n     *\n     * @param string $name\n     *\n     * @return bool\n     */\n    public function has(string $name);\n\n    /**\n     * Get an environment variable.\n     *\n     * @param string $name\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return string|null\n     */\n    public function get(string $name);\n\n    /**\n     * Set an environment variable.\n     *\n     * @param string $name\n     * @param string $value\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return bool\n     */\n    public function set(string $name, string $value);\n\n    /**\n     * Clear an environment variable.\n     *\n     * @param string $name\n     *\n     * @throws \\InvalidArgumentException\n     *\n     * @return bool\n     */\n    public function clear(string $name);\n}\n"
  },
  {
    "path": "src/Store/File/Paths.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Store\\File;\n\n/**\n * @internal\n */\nfinal class Paths\n{\n    /**\n     * This class is a singleton.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Returns the full paths to the files.\n     *\n     * @param string[] $paths\n     * @param string[] $names\n     *\n     * @return string[]\n     */\n    public static function filePaths(array $paths, array $names)\n    {\n        $files = [];\n\n        foreach ($paths as $path) {\n            foreach ($names as $name) {\n                $files[] = \\rtrim($path, \\DIRECTORY_SEPARATOR).\\DIRECTORY_SEPARATOR.$name;\n            }\n        }\n\n        return $files;\n    }\n}\n"
  },
  {
    "path": "src/Store/File/Reader.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Store\\File;\n\nuse Dotenv\\Exception\\InvalidEncodingException;\nuse Dotenv\\Util\\Str;\nuse PhpOption\\Option;\n\n/**\n * @internal\n */\nfinal class Reader\n{\n    /**\n     * This class is a singleton.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Read the file(s), and return their raw content.\n     *\n     * We provide the file path as the key, and its content as the value. If\n     * short circuit mode is enabled, then the returned array with have length\n     * at most one. File paths that couldn't be read are omitted entirely.\n     *\n     * @param string[]    $filePaths\n     * @param bool        $shortCircuit\n     * @param string|null $fileEncoding\n     *\n     * @throws \\Dotenv\\Exception\\InvalidEncodingException\n     *\n     * @return array<string, string>\n     */\n    public static function read(array $filePaths, bool $shortCircuit = true, ?string $fileEncoding = null)\n    {\n        $output = [];\n\n        foreach ($filePaths as $filePath) {\n            $content = self::readFromFile($filePath, $fileEncoding);\n            if ($content->isDefined()) {\n                $output[$filePath] = $content->get();\n                if ($shortCircuit) {\n                    break;\n                }\n            }\n        }\n\n        return $output;\n    }\n\n    /**\n     * Read the given file.\n     *\n     * @param string      $path\n     * @param string|null $encoding\n     *\n     * @throws \\Dotenv\\Exception\\InvalidEncodingException\n     *\n     * @return \\PhpOption\\Option<string>\n     */\n    private static function readFromFile(string $path, ?string $encoding = null)\n    {\n        /** @var Option<string> */\n        $content = Option::fromValue(@\\file_get_contents($path), false);\n\n        return $content->flatMap(static function (string $content) use ($encoding) {\n            return Str::utf8($content, $encoding)->mapError(static function (string $error) {\n                throw new InvalidEncodingException($error);\n            })->success();\n        });\n    }\n}\n"
  },
  {
    "path": "src/Store/FileStore.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Store;\n\nuse Dotenv\\Exception\\InvalidPathException;\nuse Dotenv\\Store\\File\\Reader;\n\nfinal class FileStore implements StoreInterface\n{\n    /**\n     * The file paths.\n     *\n     * @var string[]\n     */\n    private $filePaths;\n\n    /**\n     * Should file loading short circuit?\n     *\n     * @var bool\n     */\n    private $shortCircuit;\n\n    /**\n     * The file encoding.\n     *\n     * @var string|null\n     */\n    private $fileEncoding;\n\n    /**\n     * Create a new file store instance.\n     *\n     * @param string[]    $filePaths\n     * @param bool        $shortCircuit\n     * @param string|null $fileEncoding\n     *\n     * @return void\n     */\n    public function __construct(array $filePaths, bool $shortCircuit, ?string $fileEncoding = null)\n    {\n        $this->filePaths = $filePaths;\n        $this->shortCircuit = $shortCircuit;\n        $this->fileEncoding = $fileEncoding;\n    }\n\n    /**\n     * Read the content of the environment file(s).\n     *\n     * @throws \\Dotenv\\Exception\\InvalidEncodingException|\\Dotenv\\Exception\\InvalidPathException\n     *\n     * @return string\n     */\n    public function read()\n    {\n        if ($this->filePaths === []) {\n            throw new InvalidPathException('At least one environment file path must be provided.');\n        }\n\n        $contents = Reader::read($this->filePaths, $this->shortCircuit, $this->fileEncoding);\n\n        if (\\count($contents) > 0) {\n            return \\implode(\"\\n\", $contents);\n        }\n\n        throw new InvalidPathException(\n            \\sprintf('Unable to read any of the environment file(s) at [%s].', \\implode(', ', $this->filePaths))\n        );\n    }\n}\n"
  },
  {
    "path": "src/Store/StoreBuilder.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Store;\n\nuse Dotenv\\Store\\File\\Paths;\n\nfinal class StoreBuilder\n{\n    /**\n     * The of default name.\n     */\n    private const DEFAULT_NAME = '.env';\n\n    /**\n     * The paths to search within.\n     *\n     * @var string[]\n     */\n    private $paths;\n\n    /**\n     * The file names to search for.\n     *\n     * @var string[]\n     */\n    private $names;\n\n    /**\n     * Should file loading short circuit?\n     *\n     * @var bool\n     */\n    private $shortCircuit;\n\n    /**\n     * The file encoding.\n     *\n     * @var string|null\n     */\n    private $fileEncoding;\n\n    /**\n     * Create a new store builder instance.\n     *\n     * @param string[]    $paths\n     * @param string[]    $names\n     * @param bool        $shortCircuit\n     * @param string|null $fileEncoding\n     *\n     * @return void\n     */\n    private function __construct(array $paths = [], array $names = [], bool $shortCircuit = false, ?string $fileEncoding = null)\n    {\n        $this->paths = $paths;\n        $this->names = $names;\n        $this->shortCircuit = $shortCircuit;\n        $this->fileEncoding = $fileEncoding;\n    }\n\n    /**\n     * Create a new store builder instance with no names.\n     *\n     * @return \\Dotenv\\Store\\StoreBuilder\n     */\n    public static function createWithNoNames()\n    {\n        return new self();\n    }\n\n    /**\n     * Create a new store builder instance with the default name.\n     *\n     * @return \\Dotenv\\Store\\StoreBuilder\n     */\n    public static function createWithDefaultName()\n    {\n        return new self([], [self::DEFAULT_NAME]);\n    }\n\n    /**\n     * Creates a store builder with the given path added.\n     *\n     * @param string $path\n     *\n     * @return \\Dotenv\\Store\\StoreBuilder\n     */\n    public function addPath(string $path)\n    {\n        return new self(\\array_merge($this->paths, [$path]), $this->names, $this->shortCircuit, $this->fileEncoding);\n    }\n\n    /**\n     * Creates a store builder with the given name added.\n     *\n     * @param string $name\n     *\n     * @return \\Dotenv\\Store\\StoreBuilder\n     */\n    public function addName(string $name)\n    {\n        return new self($this->paths, \\array_merge($this->names, [$name]), $this->shortCircuit, $this->fileEncoding);\n    }\n\n    /**\n     * Creates a store builder with short circuit mode enabled.\n     *\n     * @return \\Dotenv\\Store\\StoreBuilder\n     */\n    public function shortCircuit()\n    {\n        return new self($this->paths, $this->names, true, $this->fileEncoding);\n    }\n\n    /**\n     * Creates a store builder with the specified file encoding.\n     *\n     * @param string|null $fileEncoding\n     *\n     * @return \\Dotenv\\Store\\StoreBuilder\n     */\n    public function fileEncoding(?string $fileEncoding = null)\n    {\n        return new self($this->paths, $this->names, $this->shortCircuit, $fileEncoding);\n    }\n\n    /**\n     * Creates a new store instance.\n     *\n     * @return \\Dotenv\\Store\\StoreInterface\n     */\n    public function make()\n    {\n        return new FileStore(\n            Paths::filePaths($this->paths, $this->names),\n            $this->shortCircuit,\n            $this->fileEncoding\n        );\n    }\n}\n"
  },
  {
    "path": "src/Store/StoreInterface.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Store;\n\ninterface StoreInterface\n{\n    /**\n     * Read the content of the environment file(s).\n     *\n     * @throws \\Dotenv\\Exception\\InvalidEncodingException|\\Dotenv\\Exception\\InvalidPathException\n     *\n     * @return string\n     */\n    public function read();\n}\n"
  },
  {
    "path": "src/Store/StringStore.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Store;\n\nfinal class StringStore implements StoreInterface\n{\n    /**\n     * The file content.\n     *\n     * @var string\n     */\n    private $content;\n\n    /**\n     * Create a new string store instance.\n     *\n     * @param string $content\n     *\n     * @return void\n     */\n    public function __construct(string $content)\n    {\n        $this->content = $content;\n    }\n\n    /**\n     * Read the content of the environment file(s).\n     *\n     * @return string\n     */\n    public function read()\n    {\n        return $this->content;\n    }\n}\n"
  },
  {
    "path": "src/Util/Regex.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Util;\n\nuse GrahamCampbell\\ResultType\\Error;\nuse GrahamCampbell\\ResultType\\Success;\n\n/**\n * @internal\n */\nfinal class Regex\n{\n    /**\n     * This class is a singleton.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Perform a preg match, wrapping up the result.\n     *\n     * @param string $pattern\n     * @param string $subject\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<bool, string>\n     */\n    public static function matches(string $pattern, string $subject)\n    {\n        return self::pregAndWrap(static function (string $subject) use ($pattern) {\n            return @\\preg_match($pattern, $subject) === 1;\n        }, $subject);\n    }\n\n    /**\n     * Perform a preg match all, wrapping up the result.\n     *\n     * @param string $pattern\n     * @param string $subject\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<int, string>\n     */\n    public static function occurrences(string $pattern, string $subject)\n    {\n        return self::pregAndWrap(static function (string $subject) use ($pattern) {\n            return (int) @\\preg_match_all($pattern, $subject);\n        }, $subject);\n    }\n\n    /**\n     * Perform a preg replace callback, wrapping up the result.\n     *\n     * @param string                     $pattern\n     * @param callable(string[]): string $callback\n     * @param string                     $subject\n     * @param int|null                   $limit\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<string, string>\n     */\n    public static function replaceCallback(string $pattern, callable $callback, string $subject, ?int $limit = null)\n    {\n        return self::pregAndWrap(static function (string $subject) use ($pattern, $callback, $limit) {\n            return (string) @\\preg_replace_callback($pattern, $callback, $subject, $limit ?? -1);\n        }, $subject);\n    }\n\n    /**\n     * Perform a preg split, wrapping up the result.\n     *\n     * @param string $pattern\n     * @param string $subject\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<string[], string>\n     */\n    public static function split(string $pattern, string $subject)\n    {\n        return self::pregAndWrap(static function (string $subject) use ($pattern) {\n            /** @var string[] */\n            return (array) @\\preg_split($pattern, $subject);\n        }, $subject);\n    }\n\n    /**\n     * Perform a preg operation, wrapping up the result.\n     *\n     * @template V\n     *\n     * @param callable(string): V $operation\n     * @param string              $subject\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<V, string>\n     */\n    private static function pregAndWrap(callable $operation, string $subject)\n    {\n        $result = $operation($subject);\n\n        if (\\preg_last_error() !== \\PREG_NO_ERROR) {\n            /** @var \\GrahamCampbell\\ResultType\\Result<V,string> */\n            return Error::create(\\preg_last_error_msg());\n        }\n\n        /** @var \\GrahamCampbell\\ResultType\\Result<V,string> */\n        return Success::create($result);\n    }\n}\n"
  },
  {
    "path": "src/Util/Str.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Util;\n\nuse GrahamCampbell\\ResultType\\Error;\nuse GrahamCampbell\\ResultType\\Success;\nuse PhpOption\\Option;\n\n/**\n * @internal\n */\nfinal class Str\n{\n    /**\n     * This class is a singleton.\n     *\n     * @codeCoverageIgnore\n     *\n     * @return void\n     */\n    private function __construct()\n    {\n        //\n    }\n\n    /**\n     * Convert a string to UTF-8 from the given encoding.\n     *\n     * @param string      $input\n     * @param string|null $encoding\n     *\n     * @return \\GrahamCampbell\\ResultType\\Result<string, string>\n     */\n    public static function utf8(string $input, ?string $encoding = null)\n    {\n        if ($encoding !== null && !\\in_array($encoding, \\mb_list_encodings(), true)) {\n            /** @var \\GrahamCampbell\\ResultType\\Result<string, string> */\n            return Error::create(\n                \\sprintf('Illegal character encoding [%s] specified.', $encoding)\n            );\n        }\n\n        $converted = $encoding === null ?\n            @\\mb_convert_encoding($input, 'UTF-8') :\n            @\\mb_convert_encoding($input, 'UTF-8', $encoding);\n\n        if (!is_string($converted)) {\n            /** @var \\GrahamCampbell\\ResultType\\Result<string, string> */\n            return Error::create(\n                \\sprintf('Conversion from encoding [%s] failed.', $encoding ?? 'NULL')\n            );\n        }\n\n        /**\n         * this is for support UTF-8 with BOM encoding\n         * @see https://en.wikipedia.org/wiki/Byte_order_mark\n         * @see https://github.com/vlucas/phpdotenv/issues/500\n         */\n        if (\\substr($converted, 0, 3) == \"\\xEF\\xBB\\xBF\") {\n            $converted = \\substr($converted, 3);\n        }\n\n        /** @var \\GrahamCampbell\\ResultType\\Result<string, string> */\n        return Success::create($converted);\n    }\n\n    /**\n     * Search for a given substring of the input.\n     *\n     * @param string $haystack\n     * @param string $needle\n     *\n     * @return \\PhpOption\\Option<int>\n     */\n    public static function pos(string $haystack, string $needle)\n    {\n        /** @var \\PhpOption\\Option<int> */\n        return Option::fromValue(\\mb_strpos($haystack, $needle, 0, 'UTF-8'), false);\n    }\n\n    /**\n     * Grab the specified substring of the input.\n     *\n     * @param string   $input\n     * @param int      $start\n     * @param int|null $length\n     *\n     * @return string\n     */\n    public static function substr(string $input, int $start, ?int $length = null)\n    {\n        return \\mb_substr($input, $start, $length, 'UTF-8');\n    }\n\n    /**\n     * Compute the length of the given string.\n     *\n     * @param string $input\n     *\n     * @return int\n     */\n    public static function len(string $input)\n    {\n        return \\mb_strlen($input, 'UTF-8');\n    }\n}\n"
  },
  {
    "path": "src/Validator.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv;\n\nuse Dotenv\\Exception\\ValidationException;\nuse Dotenv\\Repository\\RepositoryInterface;\nuse Dotenv\\Util\\Regex;\nuse Dotenv\\Util\\Str;\n\nclass Validator\n{\n    /**\n     * The environment repository instance.\n     *\n     * @var \\Dotenv\\Repository\\RepositoryInterface\n     */\n    private $repository;\n\n    /**\n     * The variables to validate.\n     *\n     * @var string[]\n     */\n    private $variables;\n\n    /**\n     * Create a new validator instance.\n     *\n     * @param \\Dotenv\\Repository\\RepositoryInterface $repository\n     * @param string[]                               $variables\n     *\n     * @return void\n     */\n    public function __construct(RepositoryInterface $repository, array $variables)\n    {\n        $this->repository = $repository;\n        $this->variables = $variables;\n    }\n\n    /**\n     * Assert that each variable is present.\n     *\n     * @throws \\Dotenv\\Exception\\ValidationException\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function required()\n    {\n        return $this->assert(\n            static function (?string $value) {\n                return $value !== null;\n            },\n            'is missing'\n        );\n    }\n\n    /**\n     * Assert that each variable is not empty.\n     *\n     * @throws \\Dotenv\\Exception\\ValidationException\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function notEmpty()\n    {\n        return $this->assertNullable(\n            static function (string $value) {\n                return Str::len(\\trim($value)) > 0;\n            },\n            'is empty'\n        );\n    }\n\n    /**\n     * Assert that each specified variable is an integer.\n     *\n     * @throws \\Dotenv\\Exception\\ValidationException\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function isInteger()\n    {\n        return $this->assertNullable(\n            static function (string $value) {\n                return \\ctype_digit($value);\n            },\n            'is not an integer'\n        );\n    }\n\n    /**\n     * Assert that each specified variable is a boolean.\n     *\n     * @throws \\Dotenv\\Exception\\ValidationException\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function isBoolean()\n    {\n        return $this->assertNullable(\n            static function (string $value) {\n                if ($value === '') {\n                    return false;\n                }\n\n                return \\filter_var($value, \\FILTER_VALIDATE_BOOLEAN, \\FILTER_NULL_ON_FAILURE) !== null;\n            },\n            'is not a boolean'\n        );\n    }\n\n    /**\n     * Assert that each variable is amongst the given choices.\n     *\n     * @param string[] $choices\n     *\n     * @throws \\Dotenv\\Exception\\ValidationException\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function allowedValues(array $choices)\n    {\n        return $this->assertNullable(\n            static function (string $value) use ($choices) {\n                return \\in_array($value, $choices, true);\n            },\n            \\sprintf('is not one of [%s]', \\implode(', ', $choices))\n        );\n    }\n\n    /**\n     * Assert that each variable matches the given regular expression.\n     *\n     * @param string $regex\n     *\n     * @throws \\Dotenv\\Exception\\ValidationException\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function allowedRegexValues(string $regex)\n    {\n        return $this->assertNullable(\n            static function (string $value) use ($regex) {\n                return Regex::matches($regex, $value)->success()->getOrElse(false);\n            },\n            \\sprintf('does not match \"%s\"', $regex)\n        );\n    }\n\n    /**\n     * Assert that the callback returns true for each variable.\n     *\n     * @param callable(?string):bool $callback\n     * @param string                 $message\n     *\n     * @throws \\Dotenv\\Exception\\ValidationException\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function assert(callable $callback, string $message)\n    {\n        $failing = [];\n\n        foreach ($this->variables as $variable) {\n            if ($callback($this->repository->get($variable)) === false) {\n                $failing[] = \\sprintf('%s %s', $variable, $message);\n            }\n        }\n\n        if (\\count($failing) > 0) {\n            throw new ValidationException(\\sprintf(\n                'One or more environment variables failed assertions: %s.',\n                \\implode(', ', $failing)\n            ));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Assert that the callback returns true for each variable.\n     *\n     * Skip checking null variable values.\n     *\n     * @param callable(string):bool $callback\n     * @param string                $message\n     *\n     * @throws \\Dotenv\\Exception\\ValidationException\n     *\n     * @return \\Dotenv\\Validator\n     */\n    public function assertNullable(callable $callback, string $message)\n    {\n        return $this->assert(\n            static function (?string $value) use ($callback) {\n                if ($value === null) {\n                    return true;\n                }\n\n                return $callback($value);\n            },\n            $message\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/DotenvTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests;\n\nuse Dotenv\\Dotenv;\nuse Dotenv\\Exception\\InvalidEncodingException;\nuse Dotenv\\Exception\\InvalidPathException;\nuse Dotenv\\Loader\\Loader;\nuse Dotenv\\Parser\\Parser;\nuse Dotenv\\Repository\\RepositoryBuilder;\nuse Dotenv\\Store\\StoreBuilder;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class DotenvTest extends TestCase\n{\n    /**\n     * @var string\n     */\n    private static $folder;\n\n    /**\n     * @beforeClass\n     *\n     * @return void\n     */\n    public static function setFolder()\n    {\n        self::$folder = \\dirname(__DIR__).'/fixtures/env';\n    }\n\n    public function testDotenvThrowsExceptionIfUnableToLoadFile()\n    {\n        $dotenv = Dotenv::createMutable(__DIR__);\n\n        $this->expectException(InvalidPathException::class);\n        $this->expectExceptionMessage('Unable to read any of the environment file(s) at');\n\n        $dotenv->load();\n    }\n\n    public function testDotenvThrowsExceptionIfUnableToLoadFiles()\n    {\n        $dotenv = Dotenv::createMutable([__DIR__, __DIR__.'/foo/bar']);\n\n        $this->expectException(InvalidPathException::class);\n        $this->expectExceptionMessage('Unable to read any of the environment file(s) at');\n\n        $dotenv->load();\n    }\n\n    public function testDotenvThrowsExceptionWhenNoFiles()\n    {\n        $dotenv = Dotenv::createMutable([]);\n\n        $this->expectException(InvalidPathException::class);\n        $this->expectExceptionMessage('At least one environment file path must be provided.');\n\n        $dotenv->load();\n    }\n\n    public function testDotenvTriesPathsToLoad()\n    {\n        $dotenv = Dotenv::createMutable([__DIR__, self::$folder]);\n        self::assertCount(4, $dotenv->load());\n    }\n\n    public function testDotenvTriesPathsToLoadTwice()\n    {\n        $dotenv = Dotenv::createMutable([__DIR__, self::$folder]);\n        self::assertCount(4, $dotenv->load());\n\n        $dotenv = Dotenv::createImmutable([__DIR__, self::$folder]);\n        self::assertCount(0, $dotenv->load());\n    }\n\n    public function testDotenvTriesPathsToSafeLoad()\n    {\n        $dotenv = Dotenv::createMutable([__DIR__, self::$folder]);\n        self::assertCount(4, $dotenv->safeLoad());\n    }\n\n    public function testDotenvSkipsLoadingIfFileIsMissing()\n    {\n        $dotenv = Dotenv::createMutable(__DIR__);\n        self::assertSame([], $dotenv->safeLoad());\n    }\n\n    public function testDotenvLoadsEnvironmentVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder);\n        self::assertSame(\n            ['FOO' => 'bar', 'BAR' => 'baz', 'SPACED' => 'with spaces', 'NULL' => ''],\n            $dotenv->load()\n        );\n        self::assertSame('bar', $_SERVER['FOO']);\n        self::assertSame('baz', $_SERVER['BAR']);\n        self::assertSame('with spaces', $_SERVER['SPACED']);\n        self::assertEmpty($_SERVER['NULL']);\n    }\n\n    public function testDotenvLoadsEnvironmentVarsMultipleWithShortCircuitMode()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, ['.env', 'example.env']);\n\n        self::assertSame(\n            ['FOO' => 'bar', 'BAR' => 'baz', 'SPACED' => 'with spaces', 'NULL' => ''],\n            $dotenv->load()\n        );\n    }\n\n    public function testDotenvLoadsEnvironmentVarsMultipleWithoutShortCircuitMode()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, ['.env', 'example.env'], false);\n\n        self::assertSame(\n            ['FOO' => 'bar', 'BAR' => 'baz', 'SPACED' => 'with spaces', 'NULL' => '', 'EG' => 'example'],\n            $dotenv->load()\n        );\n    }\n\n    public function testCommentedDotenvLoadsEnvironmentVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'commented.env');\n        $dotenv->load();\n        self::assertSame('bar', $_SERVER['CFOO']);\n        self::assertFalse(isset($_SERVER['CBAR']));\n        self::assertFalse(isset($_SERVER['CZOO']));\n        self::assertSame('with spaces', $_SERVER['CSPACED']);\n        self::assertSame('a value with a # character', $_SERVER['CQUOTES']);\n        self::assertSame('a value with a # character & a quote \" character inside quotes', $_SERVER['CQUOTESWITHQUOTE']);\n        self::assertEmpty($_SERVER['CNULL']);\n        self::assertEmpty($_SERVER['EMPTY']);\n        self::assertEmpty($_SERVER['EMPTY2']);\n        self::assertSame('foo', $_SERVER['FOOO']);\n    }\n\n    public function testQuotedDotenvLoadsEnvironmentVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'quoted.env');\n        $dotenv->load();\n        self::assertSame('bar', $_SERVER['QFOO']);\n        self::assertSame('baz', $_SERVER['QBAR']);\n        self::assertSame('with spaces', $_SERVER['QSPACED']);\n        self::assertEmpty(\\getenv('QNULL'));\n\n        self::assertSame('pgsql:host=localhost;dbname=test', $_SERVER['QEQUALS']);\n        self::assertSame('test some escaped characters like a quote (\") or maybe a backslash (\\\\)', $_SERVER['QESCAPED']);\n        self::assertSame('iiiiviiiixiiiiviiii\\\\n', $_SERVER['QSLASH']);\n        self::assertSame('iiiiviiiixiiiiviiii\\\\\\\\n', $_SERVER['SQSLASH']);\n    }\n\n    public function testLargeDotenvLoadsEnvironmentVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'large.env');\n        $dotenv->load();\n        self::assertSame(2730, \\strlen($_SERVER['LARGE']));\n        self::assertSame(8192, \\strlen($_SERVER['HUGE']));\n    }\n\n    public function testDotenvLoadsMultibyteVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'multibyte.env');\n        $dotenv->load();\n        self::assertSame('Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě', $_SERVER['MB1']);\n        self::assertSame('行内支付', $_SERVER['MB2']);\n        self::assertSame('🚀', $_SERVER['APP_ENV']);\n    }\n\n    public function testDotenvLoadsMultibyteUTF8Vars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'multibyte.env', false, 'UTF-8');\n        $dotenv->load();\n        self::assertSame('Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě', $_SERVER['MB1']);\n        self::assertSame('行内支付', $_SERVER['MB2']);\n        self::assertSame('🚀', $_SERVER['APP_ENV']);\n    }\n\n    public function testDotenvLoadWithInvalidEncoding()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'multibyte.env', false, 'UTF-88');\n\n        $this->expectException(InvalidEncodingException::class);\n        $this->expectExceptionMessage('Illegal character encoding [UTF-88] specified.');\n\n        $dotenv->load();\n    }\n\n    public function testDotenvLoadsMultibyteWindowsVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'windows.env', false, 'Windows-1252');\n        $dotenv->load();\n        self::assertSame('ñá', $_SERVER['MBW']);\n    }\n\n    public function testMultipleDotenvLoadsEnvironmentVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'multiple.env');\n        $dotenv->load();\n        self::assertSame('bar', $_SERVER['MULTI1']);\n        self::assertSame('foo', $_SERVER['MULTI2']);\n    }\n\n    public function testExportedDotenvLoadsEnvironmentVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'exported.env');\n        $dotenv->load();\n        self::assertSame('bar', $_SERVER['EFOO']);\n        self::assertSame('baz', $_SERVER['EBAR']);\n        self::assertSame('with spaces', $_SERVER['ESPACED']);\n        self::assertSame('123', $_SERVER['EDQUOTED']);\n        self::assertSame('456', $_SERVER['ESQUOTED']);\n        self::assertEmpty($_SERVER['ENULL']);\n    }\n\n    public function testDotenvLoadsEnvGlobals()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder);\n        $dotenv->load();\n        self::assertSame('bar', $_SERVER['FOO']);\n        self::assertSame('baz', $_SERVER['BAR']);\n        self::assertSame('with spaces', $_SERVER['SPACED']);\n        self::assertEmpty($_SERVER['NULL']);\n    }\n\n    public function testDotenvLoadsServerGlobals()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder);\n        $dotenv->load();\n        self::assertSame('bar', $_ENV['FOO']);\n        self::assertSame('baz', $_ENV['BAR']);\n        self::assertSame('with spaces', $_ENV['SPACED']);\n        self::assertEmpty($_ENV['NULL']);\n    }\n\n    public function testDotenvNestedEnvironmentVars()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'nested.env');\n        $dotenv->load();\n        self::assertSame('{$NVAR1} {$NVAR2}', $_ENV['NVAR3']); // not resolved\n        self::assertSame('Hellō World!', $_ENV['NVAR4']);\n        self::assertSame('$NVAR1 {NVAR2}', $_ENV['NVAR5']); // not resolved\n        self::assertSame('Special Value', $_ENV['N.VAR6']); // new '.' (dot) in var name\n        self::assertSame('Special Value', $_ENV['NVAR7']);  // nested '.' (dot) variable\n        self::assertSame('', $_ENV['NVAR8']); // nested variable is empty string\n        self::assertSame('', $_ENV['NVAR9']); // nested variable is empty string\n        self::assertSame('${NVAR888}', $_ENV['NVAR10']); // nested variable is not set\n        self::assertSame('NVAR1', $_ENV['NVAR11']);\n        self::assertSame('Hellō', $_ENV['NVAR12']);\n        self::assertSame('${${NVAR11}}', $_ENV['NVAR13']); // single quotes\n        self::assertSame('${NVAR1} ${NVAR2}', $_ENV['NVAR14']); // single quotes\n        self::assertSame('${NVAR1} ${NVAR2}', $_ENV['NVAR15']); // escaped\n    }\n\n    public function testDotenvNullFileArgumentUsesDefault()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, null);\n        $dotenv->load();\n        self::assertSame('bar', $_SERVER['FOO']);\n    }\n\n    /**\n     * The fixture data has whitespace between the key and in the value string.\n     *\n     * Test that these keys are trimmed down.\n     */\n    public function testDotenvTrimmedKeys()\n    {\n        $dotenv = Dotenv::createMutable(self::$folder, 'quoted.env');\n        $dotenv->load();\n        self::assertSame('no space', $_SERVER['QWHITESPACE']);\n    }\n\n    public function testDotenvLoadDoesNotOverwriteEnv()\n    {\n        \\putenv('IMMUTABLE=true');\n        $dotenv = Dotenv::createImmutable(self::$folder, 'immutable.env');\n        $dotenv->load();\n        self::assertSame('true', \\getenv('IMMUTABLE'));\n    }\n\n    public function testDotenvLoadAfterOverload()\n    {\n        \\putenv('IMMUTABLE=true');\n        $dotenv = Dotenv::createUnsafeMutable(self::$folder, 'immutable.env');\n        $dotenv->load();\n        self::assertSame('false', \\getenv('IMMUTABLE'));\n    }\n\n    public function testDotenvOverloadAfterLoad()\n    {\n        \\putenv('IMMUTABLE=true');\n        $dotenv = Dotenv::createUnsafeImmutable(self::$folder, 'immutable.env');\n        $dotenv->load();\n        self::assertSame('true', \\getenv('IMMUTABLE'));\n    }\n\n    public function testDotenvOverloadDoesOverwriteEnv()\n    {\n        $dotenv = Dotenv::createUnsafeMutable(self::$folder, 'mutable.env');\n        $dotenv->load();\n        self::assertSame('true', \\getenv('MUTABLE'));\n    }\n\n    public function testDotenvAllowsSpecialCharacters()\n    {\n        $dotenv = Dotenv::createUnsafeMutable(self::$folder, 'specialchars.env');\n        $dotenv->load();\n        self::assertSame('$a6^C7k%zs+e^.jvjXk', \\getenv('SPVAR1'));\n        self::assertSame('?BUty3koaV3%GA*hMAwH}B', \\getenv('SPVAR2'));\n        self::assertSame('jdgEB4{QgEC]HL))&GcXxokB+wqoN+j>xkV7K?m$r', \\getenv('SPVAR3'));\n        self::assertSame('22222:22#2^{', \\getenv('SPVAR4'));\n        self::assertSame('test some escaped characters like a quote \" or maybe a backslash \\\\', \\getenv('SPVAR5'));\n        self::assertSame('secret!@', \\getenv('SPVAR6'));\n        self::assertSame('secret!@#', \\getenv('SPVAR7'));\n        self::assertSame('secret!@#', \\getenv('SPVAR8'));\n    }\n\n    public function testMultilineLoading()\n    {\n        $dotenv = Dotenv::createUnsafeMutable(self::$folder, 'multiline.env');\n        $dotenv->load();\n        self::assertSame(\"test\\n     test\\\"test\\\"\\n     test\", \\getenv('TEST'));\n        self::assertSame(\"test\\ntest\", \\getenv('TEST_ND'));\n        self::assertSame('test\\\\ntest', \\getenv('TEST_NS'));\n\n        self::assertSame('https://vision.googleapis.com/v1/images:annotate?key=', \\getenv('TEST_EQD'));\n        self::assertSame('https://vision.googleapis.com/v1/images:annotate?key=', \\getenv('TEST_EQS'));\n    }\n\n    public function testEmptyLoading()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'empty.env');\n        self::assertSame(['EMPTY_VAR' => null], $dotenv->load());\n    }\n\n    public function testUnicodeVarNames()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'unicodevarnames.env');\n        $dotenv->load();\n        self::assertSame('Skybert', $_SERVER['AlbertÅberg']);\n        self::assertSame('2022-04-01T00:00', $_SERVER['ДатаЗакрытияРасчетногоПериода']);\n    }\n\n    public function testDirectConstructor()\n    {\n        $repository = RepositoryBuilder::createWithDefaultAdapters()->make();\n        $store = StoreBuilder::createWithDefaultName()->addPath(self::$folder)->make();\n\n        $dotenv = new Dotenv($store, new Parser(), new Loader(), $repository);\n\n        self::assertSame([\n            'FOO'    => 'bar',\n            'BAR'    => 'baz',\n            'SPACED' => 'with spaces',\n            'NULL'   => '',\n        ], $dotenv->load());\n    }\n\n    public function testDotenvParseExample1()\n    {\n        $output = Dotenv::parse(\n            \"BASE_DIR=\\\"/var/webroot/project-root\\\"\\nCACHE_DIR=\\\"\\${BASE_DIR}/cache\\\"\\nTMP_DIR=\\\"\\${BASE_DIR}/tmp\\\"\\n\"\n        );\n\n        self::assertSame($output, [\n            'BASE_DIR'  => '/var/webroot/project-root',\n            'CACHE_DIR' => '/var/webroot/project-root/cache',\n            'TMP_DIR'   => '/var/webroot/project-root/tmp',\n        ]);\n    }\n\n    public function testDotenvParseExample2()\n    {\n        $output = Dotenv::parse(\"FOO=Bar\\nBAZ=\\\"Hello \\${FOO}\\\"\");\n\n        self::assertSame($output, ['FOO' => 'Bar', 'BAZ' => 'Hello Bar']);\n    }\n\n    public function testDotenvParseEmptyCase()\n    {\n        $output = Dotenv::parse('');\n\n        self::assertSame($output, []);\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Loader/LoaderTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Loader;\n\nuse Dotenv\\Exception\\InvalidFileException;\nuse Dotenv\\Loader\\Loader;\nuse Dotenv\\Loader\\LoaderInterface;\nuse Dotenv\\Parser\\Parser;\nuse Dotenv\\Repository\\Adapter\\ArrayAdapter;\nuse Dotenv\\Repository\\Adapter\\EnvConstAdapter;\nuse Dotenv\\Repository\\Adapter\\ServerConstAdapter;\nuse Dotenv\\Repository\\RepositoryBuilder;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class LoaderTest extends TestCase\n{\n    public function testParserInstanceOf()\n    {\n        self::assertInstanceOf(LoaderInterface::class, new Loader());\n    }\n\n    public function testLoaderWithNoReaders()\n    {\n        $repository = RepositoryBuilder::createWithNoAdapters()->addWriter(ArrayAdapter::class)->make();\n        $loader = new Loader();\n\n        $content = \"NVAR1=\\\"Hello\\\"\\nNVAR2=\\\"World!\\\"\\nNVAR3=\\\"{\\$NVAR1} {\\$NVAR2}\\\"\\nNVAR4=\\\"\\${NVAR1} \\${NVAR2}\\\"\";\n        $expected = ['NVAR1' => 'Hello', 'NVAR2' => 'World!', 'NVAR3' => '{$NVAR1} {$NVAR2}', 'NVAR4' => '${NVAR1} ${NVAR2}'];\n\n        self::assertSame($expected, $loader->load($repository, (new Parser())->parse($content)));\n    }\n\n    public function testLoaderWithAllowList()\n    {\n        $adapter = ArrayAdapter::create()->get();\n        $repository = RepositoryBuilder::createWithNoAdapters()->addReader($adapter)->addWriter($adapter)->allowList(['FOO'])->make();\n        $loader = new Loader();\n\n        self::assertSame(['FOO' => 'Hello'], $loader->load($repository, (new Parser())->parse(\"FOO=\\\"Hello\\\"\\nBAR=\\\"World!\\\"\\n\")));\n        self::assertTrue($adapter->read('FOO')->isDefined());\n        self::assertSame('Hello', $adapter->read('FOO')->get());\n        self::assertFalse($adapter->read('BAR')->isDefined());\n    }\n\n    public function testLoaderWithGarbage()\n    {\n        $adapter = ArrayAdapter::create()->get();\n        $repository = RepositoryBuilder::createWithNoAdapters()->make();\n        $loader = new Loader();\n\n        $this->expectException(InvalidFileException::class);\n        $this->expectExceptionMessage('Failed to parse dotenv file. Encountered unexpected whitespace at [\"\"\"].');\n\n        $loader->load($repository, (new Parser())->parse('FOO=\"\"\"'));\n    }\n\n    /**\n     * @return array<int,\\Dotenv\\Repository\\Adapter\\AdapterInterface|string>[]\n     */\n    public static function providesAdapters()\n    {\n        return [\n            [ArrayAdapter::create()->get()],\n            [EnvConstAdapter::class],\n            [ServerConstAdapter::class],\n        ];\n    }\n\n    /**\n     * @dataProvider providesAdapters\n     *\n     * @param \\Dotenv\\Repository\\Adapter\\AdapterInterface|string $adapter\n     */\n    public function testLoaderWithSpecificAdapter($adapter)\n    {\n        $repository = RepositoryBuilder::createWithNoAdapters()->addReader($adapter)->addWriter($adapter)->make();\n        $loader = new Loader();\n\n        $content = \"NVAR1=\\\"Hello\\\"\\nNVAR2=\\\"World!\\\"\\nNVAR3=\\\"{\\$NVAR1} {\\$NVAR2}\\\"\\nNVAR4=\\\"\\${NVAR1} \\${NVAR2}\\\"\";\n        $expected = ['NVAR1' => 'Hello', 'NVAR2' => 'World!', 'NVAR3' => '{$NVAR1} {$NVAR2}', 'NVAR4' => 'Hello World!'];\n\n        self::assertSame($expected, $loader->load($repository, (new Parser())->parse($content)));\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Parser/EntryParserTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Parser;\n\nuse Dotenv\\Parser\\Entry;\nuse Dotenv\\Parser\\EntryParser;\nuse Dotenv\\Parser\\Value;\nuse GrahamCampbell\\ResultType\\Result;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class EntryParserTest extends TestCase\n{\n    public function testBasicParse()\n    {\n        $result = EntryParser::parse('FOO=BAR');\n        $this->checkPositiveResult($result, 'FOO', 'BAR');\n    }\n\n    public function testNullParse()\n    {\n        $result = EntryParser::parse('FOO');\n        $this->checkEmptyResult($result, 'FOO');\n    }\n\n    public function testUnicodeNameParse()\n    {\n        $result = EntryParser::parse('FOOƱ=BAZ');\n        $this->checkPositiveResult($result, 'FOOƱ', 'BAZ');\n    }\n\n    public function testQuotesParse()\n    {\n        $result = EntryParser::parse(\"FOO=\\\"BAR  \\n\\\"\");\n        $this->checkPositiveResult($result, 'FOO', \"BAR  \\n\");\n    }\n\n    public function testNewlineParse()\n    {\n        $result = EntryParser::parse('FOO=\"\\n\"');\n        $this->checkPositiveResult($result, 'FOO', \"\\n\");\n    }\n\n    public function testTabParseDouble()\n    {\n        $result = EntryParser::parse('FOO=\"\\t\"');\n        $this->checkPositiveResult($result, 'FOO', \"\\t\");\n    }\n\n    public function testTabParseSingle()\n    {\n        $result = EntryParser::parse('FOO=\\'\\t\\'');\n        $this->checkPositiveResult($result, 'FOO', '\\t');\n    }\n\n    public function testNonEscapeParse1()\n    {\n        $result = EntryParser::parse('FOO=\\n\\v');\n        $this->checkPositiveResult($result, 'FOO', '\\n\\v');\n    }\n\n    public function testNonEscapeParse2()\n    {\n        $result = EntryParser::parse('FOO=\\q');\n        $this->checkPositiveResult($result, 'FOO', '\\q');\n    }\n\n    public function testBadEscapeParse()\n    {\n        $result = EntryParser::parse('FOO=\"\\q\"');\n        $this->checkErrorResult($result, 'Encountered an unexpected escape sequence at [\"\\q\"].');\n    }\n\n    public function testInlineVariable()\n    {\n        $result = EntryParser::parse('FOO=$BAR');\n        $this->checkPositiveResult($result, 'FOO', '$BAR', [0]);\n    }\n\n    public function testInlineVariableOffset()\n    {\n        $result = EntryParser::parse('FOO=AAA$BAR');\n        $this->checkPositiveResult($result, 'FOO', 'AAA$BAR', [3]);\n    }\n\n    public function testInlineVariables()\n    {\n        $result = EntryParser::parse('FOO=\"TEST $BAR $$BAZ\"');\n        $this->checkPositiveResult($result, 'FOO', 'TEST $BAR $$BAZ', [11, 10, 5]);\n    }\n\n    public function testNonInlineVariable()\n    {\n        $result = EntryParser::parse('FOO=\\'TEST $BAR $$BAZ\\'');\n        $this->checkPositiveResult($result, 'FOO', 'TEST $BAR $$BAZ');\n        self::assertTrue($result->success()->isDefined());\n    }\n\n    public function testWhitespaceParse()\n    {\n        $result = EntryParser::parse(\"FOO=\\\"\\n\\\"\");\n        $this->checkPositiveResult($result, 'FOO', \"\\n\");\n    }\n\n    public function testExportParse()\n    {\n        $result = EntryParser::parse('export FOO=\"bar baz\"');\n        $this->checkPositiveResult($result, 'FOO', 'bar baz');\n    }\n\n    public function testExportParseTab()\n    {\n        $result = EntryParser::parse(\"export\\t\\\"FOO\\\"='bar baz'\");\n        $this->checkPositiveResult($result, 'FOO', 'bar baz');\n    }\n\n    public function testExportParseFail()\n    {\n        $result = EntryParser::parse('export \"FOO=\"bar baz\"');\n        $this->checkErrorResult($result, 'Encountered an invalid name at [\"FOO].');\n    }\n\n    public function testClosingSlashParse()\n    {\n        $result = EntryParser::parse('SPVAR5=\"test some escaped characters like a quote \\\\\" or maybe a backslash \\\\\\\\\" # not escaped');\n        $this->checkPositiveResult($result, 'SPVAR5', 'test some escaped characters like a quote \" or maybe a backslash \\\\');\n    }\n\n    public function testParseInvalidSpaces()\n    {\n        $result = EntryParser::parse('FOO=bar baz');\n        $this->checkErrorResult($result, 'Encountered unexpected whitespace at [bar baz].');\n    }\n\n    public function testParseStrayEquals()\n    {\n        $result = EntryParser::parse('=');\n        $this->checkErrorResult($result, 'Encountered an unexpected equals at [=].');\n    }\n\n    public function testParseInvalidName()\n    {\n        $result = EntryParser::parse('FOO_ASD!=BAZ');\n        $this->checkErrorResult($result, 'Encountered an invalid name at [FOO_ASD!].');\n    }\n\n    public function testParserEscapingDouble()\n    {\n        $result = EntryParser::parse('FOO_BAD=\"iiiiviiiixiiiiviiii\\\\a\"');\n        $this->checkErrorResult($result, 'Encountered an unexpected escape sequence at [\"iiiiviiiixiiiiviiii\\a\"].');\n    }\n\n    public function testParserEscapingSingle()\n    {\n        $result = EntryParser::parse('FOO_BAD=\\'iiiiviiiixiiiiviiii\\\\a\\'');\n        $this->checkPositiveResult($result, 'FOO_BAD', 'iiiiviiiixiiiiviiii\\\\a');\n    }\n\n    public function testParserMissingClosingSingleQuote()\n    {\n        $result = EntryParser::parse('TEST=\\'erert');\n        $this->checkErrorResult($result, 'Encountered a missing closing quote at [\\'erert].');\n    }\n\n    public function testParserMissingClosingDoubleQuote()\n    {\n        $result = EntryParser::parse('TEST=\"erert');\n        $this->checkErrorResult($result, 'Encountered a missing closing quote at [\"erert].');\n    }\n\n    public function testParserMissingClosingQuotes()\n    {\n        $result = EntryParser::parse(\"TEST=\\\"erert\\nTEST='erert\\n\");\n        $this->checkErrorResult($result, 'Encountered a missing closing quote at [\"erert].');\n    }\n\n    public function testParserClosingQuoteWithEscape()\n    {\n        $result = EntryParser::parse('TEST=\"\\\\');\n        $this->checkErrorResult($result, 'Encountered a missing closing quote at [\"\\\\].');\n    }\n\n    /**\n     * @param \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Entry,string> $result\n     * @param string                                                         $name\n     * @param string                                                         $chars\n     * @param int[]                                                          $vars\n     *\n     * @return void\n     */\n    private function checkPositiveResult(Result $result, string $name, string $chars, array $vars = [])\n    {\n        self::assertTrue($result->success()->isDefined());\n\n        $entry = $result->success()->get();\n        self::assertInstanceOf(Entry::class, $entry);\n        self::assertSame($name, $entry->getName());\n        self::assertTrue($entry->getValue()->isDefined());\n\n        $value = $entry->getValue()->get();\n        self::assertInstanceOf(Value::class, $value);\n        self::assertSame($chars, $value->getChars());\n        self::assertSame($vars, $value->getVars());\n    }\n\n    /**\n     * @param \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Entry,string> $result\n     * @param string                                                         $name\n     *\n     * @return void\n     */\n    private function checkEmptyResult(Result $result, string $name)\n    {\n        self::assertTrue($result->success()->isDefined());\n\n        $entry = $result->success()->get();\n        self::assertInstanceOf(Entry::class, $entry);\n        self::assertSame('FOO', $entry->getName());\n        self::assertFalse($entry->getValue()->isDefined());\n    }\n\n    /**\n     * @param \\GrahamCampbell\\ResultType\\Result<\\Dotenv\\Parser\\Entry,string> $result\n     * @param string                                                         $error\n     *\n     * @return void\n     */\n    private function checkErrorResult(Result $result, string $error)\n    {\n        self::assertTrue($result->error()->isDefined());\n        self::assertSame($error, $result->error()->get());\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Parser/LexerTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Parser;\n\nuse Dotenv\\Parser\\Lexer;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class LexerTest extends TestCase\n{\n    /**\n     * @return array{string,string[]}[]\n     */\n    public static function provideLexCases()\n    {\n        return [\n            ['', []],\n            ['FOO', ['FOO']],\n            ['FOO bar', ['FOO', ' ', 'bar']],\n            ['FOO\\\\n()ab', ['FOO', '\\\\', 'n()ab']],\n            [\"FOO\\n\\n   A\", ['FOO', \"\\n\\n\", '   ', 'A']],\n            ['\"VA=L\"', ['\"', 'VA=L', '\"']],\n            ['\\' \\'', ['\\'', ' ', '\\'']],\n        ];\n    }\n\n    /**\n     * @dataProvider provideLexCases\n     *\n     * @param string   $input\n     * @param string[] $output\n     *\n     * @return void\n     */\n    public function testLex(string $input, array $output)\n    {\n        self::assertSame($output, \\iterator_to_array(Lexer::lex($input)));\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Parser/LinesTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Parser;\n\nuse Dotenv\\Parser\\Lines;\nuse Dotenv\\Util\\Regex;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class LinesTest extends TestCase\n{\n    public function testProcessBasic()\n    {\n        $content = \\file_get_contents(\\dirname(\\dirname(__DIR__)).'/fixtures/env/assertions.env');\n        self::assertIsString($content);\n        $result = Regex::split(\"/(\\r\\n|\\n|\\r)/\", $content);\n        self::assertTrue($result->success()->isDefined());\n\n        $expected = [\n            'ASSERTVAR1=val1',\n            'ASSERTVAR2=\"\"',\n            'ASSERTVAR3=\"val3   \"',\n            'ASSERTVAR4=\"0\" # empty looking value',\n            'ASSERTVAR5=\"#foo\"',\n            \"ASSERTVAR6=\\\"val1\\nval2\\\"\",\n            \"ASSERTVAR7=\\\"\\nval3\\\" #\",\n            \"ASSERTVAR8=\\\"val3\\n\\\"\",\n            \"ASSERTVAR9=\\\"\\n\\n\\\"\",\n        ];\n\n        self::assertSame($expected, Lines::process($result->success()->get()));\n    }\n\n    public function testProcessQuotes()\n    {\n        $content = \\file_get_contents(\\dirname(\\dirname(__DIR__)).'/fixtures/env/multiline.env');\n        self::assertIsString($content);\n        $result = Regex::split(\"/(\\r\\n|\\n|\\r)/\", $content);\n        self::assertTrue($result->success()->isDefined());\n\n        $expected = [\n            \"TEST=\\\"test\\n     test\\\\\\\"test\\\\\\\"\\n     test\\\"\",\n            'TEST_ND=\"test\\\\ntest\"',\n            'TEST_NS=\\'test\\\\ntest\\'',\n            'TEST_EQD=\"https://vision.googleapis.com/v1/images:annotate?key=\"',\n            'TEST_EQS=\\'https://vision.googleapis.com/v1/images:annotate?key=\\'',\n            \"BASE64_ENCODED_MULTILINE=\\\"qS1zCzMVVUJWQShokv6YVYi+ruKSC/bHV7GmEiyVkLaBWJHNVHCHsgTksEBsy8wJ\\nuwycAvR07ZyOJJed4XTRMKnKp1/v+6UATpWzkIjZXytK+pD+XlZimUHTx3uiDcmU\\njhQX1wWSxHDqrSWxeIJiTD+BuUyId8FzmXQ3TcBydJ474tmOU2F492ubk3LAiZ18\\nmhiRGoshXAOSbS/P3+RZi4bDeNE/No4=\\\"\",\n        ];\n\n        self::assertSame($expected, Lines::process($result->success()->get()));\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Parser/ParserTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Parser;\n\nuse Dotenv\\Exception\\InvalidFileException;\nuse Dotenv\\Parser\\Entry;\nuse Dotenv\\Parser\\Parser;\nuse Dotenv\\Parser\\ParserInterface;\nuse Dotenv\\Parser\\Value;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class ParserTest extends TestCase\n{\n    public function testParserInstanceOf()\n    {\n        self::assertInstanceOf(ParserInterface::class, new Parser());\n    }\n\n    public function testFullParse()\n    {\n        $result = (new Parser())->parse(\"FOO=BAR\\nFOO\\nFOO=\\\"BAR  \\n\\\"\\nFOO=\\\"\\\\n\\\"\");\n\n        self::assertIsArray($result);\n        self::assertCount(4, $result);\n\n        $this->checkPositiveEntry($result[0], 'FOO', 'BAR');\n        $this->checkEmptyEntry($result[1], 'FOO');\n        $this->checkPositiveEntry($result[2], 'FOO', \"BAR  \\n\");\n        $this->checkPositiveEntry($result[3], 'FOO', \"\\n\");\n    }\n\n    public function testBadEscapeParse()\n    {\n        $this->expectException(InvalidFileException::class);\n        $this->expectExceptionMessage('Failed to parse dotenv file. Encountered an unexpected escape sequence at [\"\\q\"].');\n\n        (new Parser())->parse('FOO=\"\\q\"');\n    }\n\n    public function testParseInvalidSpaces()\n    {\n        $this->expectException(InvalidFileException::class);\n        $this->expectExceptionMessage('Failed to parse dotenv file. Encountered unexpected whitespace at [bar baz].');\n\n        (new Parser())->parse(\"FOO=bar baz\\n\");\n    }\n\n    public function testParseStrayEquals()\n    {\n        $this->expectException(InvalidFileException::class);\n        $this->expectExceptionMessage('Failed to parse dotenv file. Encountered an unexpected equals at [=].');\n\n        (new Parser())->parse(\"=\\n\");\n    }\n\n    public function testParseInvalidName()\n    {\n        $this->expectException(InvalidFileException::class);\n        $this->expectExceptionMessage('Failed to parse dotenv file. Encountered an invalid name at [FOO_ASD!].');\n\n        (new Parser())->parse('FOO_ASD!=BAZ');\n    }\n\n    /**\n     * @param \\Dotenv\\Parser\\Entry $entry\n     * @param string               $name\n     * @param string               $chars\n     * @param int[]                $vars\n     *\n     * @return void\n     */\n    private function checkPositiveEntry(Entry $entry, string $name, string $chars, array $vars = [])\n    {\n        self::assertInstanceOf(Entry::class, $entry);\n        self::assertSame($name, $entry->getName());\n        self::assertTrue($entry->getValue()->isDefined());\n\n        $value = $entry->getValue()->get();\n        self::assertInstanceOf(Value::class, $value);\n        self::assertSame($chars, $value->getChars());\n        self::assertSame($vars, $value->getVars());\n    }\n\n    /**\n     * @param \\Dotenv\\Parser\\Entry $entry\n     * @param string               $name\n     *\n     * @return void\n     */\n    private function checkEmptyEntry(Entry $entry, string $name)\n    {\n        self::assertInstanceOf(Entry::class, $entry);\n        self::assertSame('FOO', $entry->getName());\n        self::assertFalse($entry->getValue()->isDefined());\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Repository/Adapter/ArrayAdapterTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Repository\\Adapter;\n\nuse Dotenv\\Repository\\Adapter\\ArrayAdapter;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class ArrayAdapterTest extends TestCase\n{\n    public function testGoodRead()\n    {\n        $adapter = self::createAdapter();\n        $adapter->write('CONST_TEST', 'foo bar baz');\n        $value = $adapter->read('CONST_TEST');\n        self::assertTrue($value->isDefined());\n        self::assertSame('foo bar baz', $value->get());\n    }\n\n    public function testUndefinedRead()\n    {\n        $adapter = self::createAdapter();\n        unset($_ENV['CONST_TEST']);\n        $value = $adapter->read('CONST_TEST');\n        self::assertFalse($value->isDefined());\n    }\n\n    public function testGoodWrite()\n    {\n        $adapter = self::createAdapter();\n        self::assertTrue($adapter->write('CONST_TEST', 'foo'));\n        self::assertSame('foo', $adapter->read('CONST_TEST')->get());\n    }\n\n    public function testEmptyWrite()\n    {\n        $adapter = self::createAdapter();\n        self::assertTrue($adapter->write('CONST_TEST', ''));\n        self::assertSame('', $adapter->read('CONST_TEST')->get());\n    }\n\n    public function testGoodDelete()\n    {\n        $adapter = self::createAdapter();\n        self::assertTrue($adapter->delete('CONST_TEST'));\n        self::assertFalse($adapter->read('CONST_TEST')->isDefined());\n    }\n\n    /**\n     * @return \\Dotenv\\Repository\\Adapter\\AdapterInterface\n     */\n    private static function createAdapter()\n    {\n        return ArrayAdapter::create()->get();\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Repository/Adapter/EnvConstAdapterTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Repository\\Adapter;\n\nuse Dotenv\\Repository\\Adapter\\EnvConstAdapter;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class EnvConstAdapterTest extends TestCase\n{\n    public function testGoodRead()\n    {\n        $_ENV['CONST_TEST'] = 'foo bar baz';\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertTrue($value->isDefined());\n        self::assertSame('foo bar baz', $value->get());\n    }\n\n    public function testFalseRead()\n    {\n        $_ENV['CONST_TEST'] = false;\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertTrue($value->isDefined());\n        self::assertSame('false', $value->get());\n    }\n\n    public function testTrueRead()\n    {\n        $_ENV['CONST_TEST'] = true;\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertTrue($value->isDefined());\n        self::assertSame('true', $value->get());\n    }\n\n    public function testBadTypeRead()\n    {\n        $_ENV['CONST_TEST'] = [123];\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertFalse($value->isDefined());\n    }\n\n    public function testUndefinedRead()\n    {\n        unset($_ENV['CONST_TEST']);\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertFalse($value->isDefined());\n    }\n\n    public function testGoodWrite()\n    {\n        self::assertTrue(self::createAdapter()->write('CONST_TEST', 'foo'));\n        self::assertSame('foo', $_ENV['CONST_TEST']);\n    }\n\n    public function testEmptyWrite()\n    {\n        self::assertTrue(self::createAdapter()->write('CONST_TEST', ''));\n        self::assertSame('', $_ENV['CONST_TEST']);\n    }\n\n    public function testGoodDelete()\n    {\n        self::assertTrue(self::createAdapter()->delete('CONST_TEST'));\n        self::assertFalse(isset($_ENV['CONST_TEST']));\n    }\n\n    /**\n     * @return \\Dotenv\\Repository\\Adapter\\AdapterInterface\n     */\n    private static function createAdapter()\n    {\n        return EnvConstAdapter::create()->get();\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Repository/Adapter/PutenvAdapterTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Repository\\Adapter;\n\nuse Dotenv\\Repository\\Adapter\\PutenvAdapter;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class PutenvAdapterTest extends TestCase\n{\n    public function testGoodRead()\n    {\n        \\putenv('CONST_TEST=foo bar baz');\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertTrue($value->isDefined());\n        self::assertSame('foo bar baz', $value->get());\n    }\n\n    public function testUndefinedRead()\n    {\n        \\putenv('CONST_TEST');\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertFalse($value->isDefined());\n    }\n\n    public function testGoodWrite()\n    {\n        self::assertTrue(self::createAdapter()->write('CONST_TEST', 'foo'));\n        self::assertSame('foo', \\getenv('CONST_TEST'));\n    }\n\n    public function testEmptyWrite()\n    {\n        self::assertTrue(self::createAdapter()->write('CONST_TEST', ''));\n        self::assertSame('', \\getenv('CONST_TEST'));\n    }\n\n    public function testGoodDelete()\n    {\n        self::assertTrue(self::createAdapter()->delete('CONST_TEST'));\n        self::assertFalse(\\getenv('CONST_TEST'));\n    }\n\n    /**\n     * @return \\Dotenv\\Repository\\Adapter\\AdapterInterface\n     */\n    private static function createAdapter()\n    {\n        return PutenvAdapter::create()->get();\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Repository/Adapter/ServerConstAdapterTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Repository\\Adapter;\n\nuse Dotenv\\Repository\\Adapter\\ServerConstAdapter;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class ServerConstAdapterTest extends TestCase\n{\n    public function testGoodRead()\n    {\n        $_SERVER['CONST_TEST'] = 'foo bar baz';\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertTrue($value->isDefined());\n        self::assertSame('foo bar baz', $value->get());\n    }\n\n    public function testFalseRead()\n    {\n        $_SERVER['CONST_TEST'] = false;\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertTrue($value->isDefined());\n        self::assertSame('false', $value->get());\n    }\n\n    public function testTrueRead()\n    {\n        $_SERVER['CONST_TEST'] = true;\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertTrue($value->isDefined());\n        self::assertSame('true', $value->get());\n    }\n\n    public function testBadTypeRead()\n    {\n        $_SERVER['CONST_TEST'] = [123];\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertFalse($value->isDefined());\n    }\n\n    public function testUndefinedRead()\n    {\n        unset($_SERVER['CONST_TEST']);\n        $value = self::createAdapter()->read('CONST_TEST');\n        self::assertFalse($value->isDefined());\n    }\n\n    public function testGoodWrite()\n    {\n        self::assertTrue(self::createAdapter()->write('CONST_TEST', 'foo'));\n        self::assertSame('foo', $_SERVER['CONST_TEST']);\n    }\n\n    public function testEmptyWrite()\n    {\n        self::assertTrue(self::createAdapter()->write('CONST_TEST', ''));\n        self::assertSame('', $_SERVER['CONST_TEST']);\n    }\n\n    public function testGoodDelete()\n    {\n        self::assertTrue(self::createAdapter()->delete('CONST_TEST'));\n        self::assertFalse(isset($_SERVER['CONST_TEST']));\n    }\n\n    /**\n     * @return \\Dotenv\\Repository\\Adapter\\AdapterInterface\n     */\n    private static function createAdapter()\n    {\n        return ServerConstAdapter::create()->get();\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Repository/RepositoryTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Repository;\n\nuse Dotenv\\Dotenv;\nuse Dotenv\\Repository\\Adapter\\ArrayAdapter;\nuse Dotenv\\Repository\\RepositoryBuilder;\nuse Dotenv\\Repository\\RepositoryInterface;\nuse InvalidArgumentException;\nuse PHPUnit\\Framework\\TestCase;\nuse TypeError;\n\nfinal class RepositoryTest extends TestCase\n{\n    /**\n     * @var array<string, string>|null\n     */\n    private $keyVal;\n\n    /**\n     * @before\n     *\n     * @return void\n     */\n    public function refreshKeyVal()\n    {\n        $this->keyVal(true);\n    }\n\n    /**\n     * @return void\n     */\n    private function load()\n    {\n        Dotenv::createMutable(\\dirname(\\dirname(__DIR__)).'/fixtures/env')->load();\n    }\n\n    /**\n     * Generates a new key/value pair or returns the previous one.\n     *\n     * Since most of our functionality revolves around setting/retrieving keys\n     * and values, we have this utility function to help generate new, unique\n     * key/value pairs.\n     *\n     * @param bool $reset\n     *\n     * @return array<string, string>\n     */\n    private function keyVal(bool $reset = false)\n    {\n        if (!isset($this->keyVal) || $reset) {\n            $this->keyVal = [\\uniqid() => \\uniqid()];\n        }\n\n        return $this->keyVal;\n    }\n\n    /**\n     * Returns the key from keyVal(), without reset.\n     *\n     * @return string\n     */\n    private function key()\n    {\n        $keyVal = $this->keyVal();\n\n        return (string) \\key($keyVal);\n    }\n\n    /**\n     * Returns the value from keyVal(), without reset.\n     *\n     * @return string\n     */\n    private function value()\n    {\n        $keyVal = $this->keyVal();\n\n        /** @var string */\n        return \\reset($keyVal);\n    }\n\n    public function testRepositoryInstanceOf()\n    {\n        self::assertInstanceOf(RepositoryInterface::class, RepositoryBuilder::createWithNoAdapters()->make());\n        self::assertInstanceOf(RepositoryInterface::class, RepositoryBuilder::createWithDefaultAdapters()->make());\n    }\n\n    public function testMutableLoaderClearsEnvironmentVars()\n    {\n        $repository = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        // Set an environment variable.\n        $repository->set($this->key(), $this->value());\n\n        // Clear the set environment variable.\n        $repository->clear($this->key());\n        self::assertNull($repository->get($this->key()));\n        self::assertFalse(\\getenv($this->key()));\n        self::assertFalse(isset($_ENV[$this->key()]));\n        self::assertFalse(isset($_SERVER[$this->key()]));\n    }\n\n    public function testImmutableLoaderCannotClearExistingEnvironmentVars()\n    {\n        $this->load();\n\n        $repository = RepositoryBuilder::createWithDefaultAdapters()->immutable()->make();\n\n        // Pre-set an environment variable.\n        RepositoryBuilder::createWithDefaultAdapters()->make()->set($this->key(), $this->value());\n\n        // Attempt to clear the environment variable, check that it fails.\n        $repository->clear($this->key());\n        self::assertSame($this->value(), $repository->get($this->key()));\n        self::assertTrue(isset($_ENV[$this->key()]));\n        self::assertTrue(isset($_SERVER[$this->key()]));\n    }\n\n    public function testImmutableLoaderCanClearSetEnvironmentVars()\n    {\n        $this->load();\n\n        $repository = RepositoryBuilder::createWithDefaultAdapters()->immutable()->make();\n\n        // Set an environment variable.\n        $repository->set($this->key(), $this->value());\n\n        // Attempt to clear the environment variable, check that it works.\n        $repository->clear($this->key());\n        self::assertNull($repository->get($this->key()));\n        self::assertFalse(\\getenv($this->key()));\n        self::assertFalse(isset($_ENV[$this->key()]));\n        self::assertFalse(isset($_SERVER[$this->key()]));\n    }\n\n    public function testCheckingWhetherVariableExists()\n    {\n        $this->load();\n\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        self::assertTrue($repo->has('FOO'));\n        self::assertFalse($repo->has('NON_EXISTING_VARIABLE'));\n    }\n\n    public function testHasWithBadVariable()\n    {\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        $this->expectException(TypeError::class);\n\n        $repo->has(null);\n    }\n\n    public function testGettingVariableByName()\n    {\n        $this->load();\n\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        self::assertSame('bar', $repo->get('FOO'));\n    }\n\n    public function testGettingNullVariable()\n    {\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        $this->expectException(TypeError::class);\n\n        $repo->get(null);\n    }\n\n    public function testGettingEmptyVariable()\n    {\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Expected name to be a non-empty string.');\n\n        $repo->get('');\n    }\n\n    public function testSettingVariable()\n    {\n        $this->load();\n\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        self::assertSame('bar', $repo->get('FOO'));\n        $repo->set('FOO', 'new');\n        self::assertSame('new', $repo->get('FOO'));\n    }\n\n    public function testSettingNullVariable()\n    {\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        $this->expectException(TypeError::class);\n\n        $repo->set(null, 'foo');\n    }\n\n    public function testSettingEmptyVariable()\n    {\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Expected name to be a non-empty string.');\n\n        $repo->set('', 'foo');\n    }\n\n    public function testClearingVariable()\n    {\n        $this->load();\n\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        self::assertTrue($repo->has('FOO'));\n        $repo->clear('FOO');\n        self::assertFalse($repo->has('FOO'));\n    }\n\n    public function testClearingVariableWithArrayAdapter()\n    {\n        $adapter = ArrayAdapter::create()->get();\n        $repo = RepositoryBuilder::createWithNoAdapters()->addReader($adapter)->addWriter($adapter)->make();\n\n        self::assertFalse($repo->has('FOO'));\n        $repo->set('FOO', 'BAR');\n        self::assertTrue($repo->has('FOO'));\n        $repo->clear('FOO');\n        self::assertFalse($repo->has('FOO'));\n    }\n\n    public function testClearingNullVariable()\n    {\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        $this->expectException(TypeError::class);\n\n        $repo->clear(null);\n    }\n\n    public function testClearingEmptyVariable()\n    {\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->make();\n\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Expected name to be a non-empty string.');\n\n        $repo->clear('');\n    }\n\n    public function testCannotSetVariableOnImmutableInstance()\n    {\n        $this->load();\n\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->immutable()->make();\n\n        self::assertSame('bar', $repo->get('FOO'));\n\n        $repo->set('FOO', 'new');\n\n        self::assertSame('bar', $repo->get('FOO'));\n    }\n\n    public function testCannotClearVariableOnImmutableInstance()\n    {\n        $this->load();\n\n        $repo = RepositoryBuilder::createWithDefaultAdapters()->immutable()->make();\n\n        $repo->clear('FOO');\n\n        self::assertTrue($repo->has('FOO'));\n    }\n\n    public function testBuildWithBadReader()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Expected either an instance of ');\n\n        RepositoryBuilder::createWithNoAdapters()->addReader('123');\n    }\n\n    public function testBuildWithBadWriter()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Expected either an instance of ');\n\n        RepositoryBuilder::createWithNoAdapters()->addWriter('123');\n    }\n\n    public function testBuildWithBadAdapter()\n    {\n        $this->expectException(InvalidArgumentException::class);\n        $this->expectExceptionMessage('Expected either an instance of ');\n\n        RepositoryBuilder::createWithNoAdapters()->addAdapter('');\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/Store/StoreTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests\\Store;\n\nuse Dotenv\\Exception\\InvalidEncodingException;\nuse Dotenv\\Store\\File\\Paths;\nuse Dotenv\\Store\\File\\Reader;\nuse Dotenv\\Store\\StoreBuilder;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class StoreTest extends TestCase\n{\n    /**\n     * @var string\n     */\n    private static $folder;\n\n    /**\n     * @beforeClass\n     *\n     * @return void\n     */\n    public static function setFolder()\n    {\n        self::$folder = \\dirname(\\dirname(__DIR__)).'/fixtures/env';\n    }\n\n    public function testBasicReadDirect()\n    {\n        self::assertSame(\n            [\n                self::$folder.\\DIRECTORY_SEPARATOR.'.env' => \"FOO=bar\\nBAR=baz\\nSPACED=\\\"with spaces\\\"\\n\\nNULL=\\n\",\n            ],\n            Reader::read(\n                Paths::filePaths([self::$folder], ['.env'])\n            )\n        );\n    }\n\n    public function testBasicRead()\n    {\n        $builder = StoreBuilder::createWithDefaultName()\n            ->addPath(self::$folder);\n\n        self::assertSame(\n            \"FOO=bar\\nBAR=baz\\nSPACED=\\\"with spaces\\\"\\n\\nNULL=\\n\",\n            $builder->make()->read()\n        );\n    }\n\n    public function testBasicReadWindowsEncoding()\n    {\n        $builder = StoreBuilder::createWithNoNames()\n            ->addPath(self::$folder)\n            ->addName('windows.env')\n            ->fileEncoding('Windows-1252');\n\n        self::assertSame(\n            \"MBW=\\\"ñá\\\"\\n\",\n            $builder->make()->read()\n        );\n    }\n\n    public function testBasicReadBadEncoding()\n    {\n        $builder = StoreBuilder::createWithNoNames()\n            ->addPath(self::$folder)\n            ->addName('windows.env')\n            ->fileEncoding('Windowss-1252');\n\n        $this->expectException(InvalidEncodingException::class);\n        $this->expectExceptionMessage('Illegal character encoding [Windowss-1252] specified.');\n\n        $builder->make()->read();\n    }\n\n    public function testFileReadMultipleShortCircuitModeDirect()\n    {\n        self::assertSame(\n            [\n                self::$folder.\\DIRECTORY_SEPARATOR.'.env' => \"FOO=bar\\nBAR=baz\\nSPACED=\\\"with spaces\\\"\\n\\nNULL=\\n\",\n            ],\n            Reader::read(\n                Paths::filePaths([self::$folder], ['.env', 'example.env'])\n            )\n        );\n    }\n\n    public function testFileReadMultipleShortCircuitMode()\n    {\n        $builder = StoreBuilder::createWithNoNames()\n            ->addPath(self::$folder)\n            ->addName('.env')\n            ->addName('example.env')\n            ->shortCircuit();\n\n        self::assertSame(\n            \"FOO=bar\\nBAR=baz\\nSPACED=\\\"with spaces\\\"\\n\\nNULL=\\n\",\n            $builder->make()->read()\n        );\n    }\n\n    public function testFileReadMultipleWithoutShortCircuitModeDirect()\n    {\n        self::assertSame(\n            [\n                self::$folder.\\DIRECTORY_SEPARATOR.'.env'        => \"FOO=bar\\nBAR=baz\\nSPACED=\\\"with spaces\\\"\\n\\nNULL=\\n\",\n                self::$folder.\\DIRECTORY_SEPARATOR.'example.env' => \"EG=\\\"example\\\"\\n\",\n            ],\n            Reader::read(\n                Paths::filePaths([self::$folder], ['.env', 'example.env']),\n                false\n            )\n        );\n    }\n\n    public function testFileReadMultipleWithoutShortCircuitMode()\n    {\n        $builder = StoreBuilder::createWithDefaultName()\n            ->addPath(self::$folder)\n            ->addName('example.env');\n\n        self::assertSame(\n            \"FOO=bar\\nBAR=baz\\nSPACED=\\\"with spaces\\\"\\n\\nNULL=\\n\\nEG=\\\"example\\\"\\n\",\n            $builder->make()->read()\n        );\n    }\n    public function testFileReadWithUtf8WithBomEncoding()\n    {\n        self::assertSame(\n            [\n                self::$folder.\\DIRECTORY_SEPARATOR.'utf8-with-bom-encoding.env' => \"FOO=bar\\nBAR=baz\\nSPACED=\\\"with spaces\\\"\\n\",\n            ],\n            Reader::read(\n                Paths::filePaths([self::$folder], ['utf8-with-bom-encoding.env'])\n            )\n        );\n    }\n}\n"
  },
  {
    "path": "tests/Dotenv/ValidatorTest.php",
    "content": "<?php\n\ndeclare(strict_types=1);\n\nnamespace Dotenv\\Tests;\n\nuse Dotenv\\Dotenv;\nuse Dotenv\\Exception\\ValidationException;\nuse Dotenv\\Repository\\Adapter\\ArrayAdapter;\nuse Dotenv\\Repository\\RepositoryBuilder;\nuse PHPUnit\\Framework\\TestCase;\n\nfinal class ValidatorTest extends TestCase\n{\n    /**\n     * @var string\n     */\n    private static $folder;\n\n    /**\n     * @beforeClass\n     *\n     * @return void\n     */\n    public static function setFolder()\n    {\n        self::$folder = \\dirname(__DIR__).'/fixtures/env';\n    }\n\n    /**\n     * @param string $name\n     *\n     * @return array{\\Dotenv\\Repository\\RepositoryInterface,\\Dotenv\\Dotenv}\n     */\n    public static function createArrayDotenv(string $name = '.env')\n    {\n        $repository = RepositoryBuilder::createWithNoAdapters()->addAdapter(ArrayAdapter::class)->make();\n\n        return [$repository, Dotenv::create($repository, self::$folder, $name)];\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testDotenvRequiredStringEnvironmentVars()\n    {\n        $dotenv = self::createArrayDotenv()[1];\n        $dotenv->load();\n        $dotenv->required('FOO');\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testDotenvAllowedValues()\n    {\n        $dotenv = self::createArrayDotenv()[1];\n        $dotenv->load();\n        $dotenv->required('FOO')->allowedValues(['bar', 'baz']);\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testDotenvAllowedValuesIfPresent()\n    {\n        $dotenv = self::createArrayDotenv()[1];\n        $dotenv->load();\n        $dotenv->ifPresent('FOO')->allowedValues(['bar', 'baz']);\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testDotenvAllowedValuesIfNotPresent()\n    {\n        $dotenv = self::createArrayDotenv()[1];\n        $dotenv->load();\n        $dotenv->ifPresent('FOOQWERTYOOOOOO')->allowedValues(['bar', 'baz']);\n    }\n\n    public function testDotenvProhibitedValues()\n    {\n        $dotenv = self::createArrayDotenv()[1];\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: FOO is not one of [buzz, buz].');\n\n        $dotenv->required('FOO')->allowedValues(['buzz', 'buz']);\n    }\n\n    public function testDotenvProhibitedValuesIfPresent()\n    {\n        $dotenv = self::createArrayDotenv()[1];\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: FOO is not one of [buzz, buz].');\n\n        $dotenv->ifPresent('FOO')->allowedValues(['buzz', 'buz']);\n    }\n\n    public function testDotenvRequiredThrowsRuntimeException()\n    {\n        [$repo, $dotenv] = self::createArrayDotenv();\n\n        $dotenv->load();\n\n        self::assertFalse($repo->has('FOOX'));\n        self::assertFalse($repo->has('NOPE'));\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: FOOX is missing, NOPE is missing.');\n\n        $dotenv->required(['FOOX', 'NOPE']);\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testDotenvRequiredArrayEnvironmentVars()\n    {\n        $dotenv = self::createArrayDotenv()[1];\n        $dotenv->load();\n        $dotenv->required(['FOO', 'BAR']);\n    }\n\n    public function testDotenvAssertions()\n    {\n        [$repo, $dotenv] = self::createArrayDotenv('assertions.env');\n\n        $dotenv->load();\n\n        self::assertSame('val1', $repo->get('ASSERTVAR1'));\n        self::assertSame('', $repo->get('ASSERTVAR2'));\n        self::assertSame('val3   ', $repo->get('ASSERTVAR3'));\n        self::assertSame('0', $repo->get('ASSERTVAR4'));\n        self::assertSame('#foo', $repo->get('ASSERTVAR5'));\n        self::assertSame(\"val1\\nval2\", $repo->get('ASSERTVAR6'));\n        self::assertSame(\"\\nval3\", $repo->get('ASSERTVAR7'));\n        self::assertSame(\"val3\\n\", $repo->get('ASSERTVAR8'));\n\n        $dotenv->required([\n            'ASSERTVAR1',\n            'ASSERTVAR2',\n            'ASSERTVAR3',\n            'ASSERTVAR4',\n            'ASSERTVAR5',\n            'ASSERTVAR6',\n            'ASSERTVAR7',\n            'ASSERTVAR8',\n            'ASSERTVAR9',\n        ]);\n\n        $dotenv->required([\n            'ASSERTVAR1',\n            'ASSERTVAR3',\n            'ASSERTVAR4',\n            'ASSERTVAR5',\n            'ASSERTVAR6',\n            'ASSERTVAR7',\n            'ASSERTVAR8',\n        ])->notEmpty();\n\n        $dotenv->required([\n            'ASSERTVAR1',\n            'ASSERTVAR4',\n            'ASSERTVAR5',\n        ])->notEmpty()->allowedValues(['0', 'val1', '#foo']);\n    }\n\n    public function testDotenvEmptyThrowsRuntimeException()\n    {\n        $dotenv = self::createArrayDotenv('assertions.env')[1];\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: ASSERTVAR2 is empty.');\n\n        $dotenv->required('ASSERTVAR2')->notEmpty();\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testDotenvEmptyWhenNotPresent()\n    {\n        $dotenv = self::createArrayDotenv('assertions.env')[1];\n        $dotenv->load();\n        $dotenv->ifPresent('ASSERTVAR2_NO_SUCH_VARIABLE')->notEmpty();\n    }\n\n    public function testDotenvStringOfSpacesConsideredEmpty()\n    {\n        $dotenv = self::createArrayDotenv('assertions.env')[1];\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: ASSERTVAR9 is empty.');\n\n        $dotenv->required('ASSERTVAR9')->notEmpty();\n    }\n\n    /**\n     * List of valid boolean values in fixtures/env/booleans.env.\n     *\n     * @return string[][]\n     */\n    public static function validBooleanValuesDataProvider()\n    {\n        return [\n            ['VALID_EXPLICIT_LOWERCASE_TRUE'],\n            ['VALID_EXPLICIT_LOWERCASE_FALSE'],\n            ['VALID_EXPLICIT_UPPERCASE_TRUE'],\n            ['VALID_EXPLICIT_UPPERCASE_FALSE'],\n            ['VALID_EXPLICIT_MIXEDCASE_TRUE'],\n            ['VALID_EXPLICIT_MIXEDCASE_FALSE'],\n\n            ['VALID_NUMBER_TRUE'],\n            ['VALID_NUMBER_FALSE'],\n\n            ['VALID_ONOFF_LOWERCASE_TRUE'],\n            ['VALID_ONOFF_LOWERCASE_FALSE'],\n            ['VALID_ONOFF_UPPERCASE_TRUE'],\n            ['VALID_ONOFF_UPPERCASE_FALSE'],\n            ['VALID_ONOFF_MIXEDCASE_TRUE'],\n            ['VALID_ONOFF_MIXEDCASE_FALSE'],\n\n            ['VALID_YESNO_LOWERCASE_TRUE'],\n            ['VALID_YESNO_LOWERCASE_FALSE'],\n            ['VALID_YESNO_UPPERCASE_TRUE'],\n            ['VALID_YESNO_UPPERCASE_FALSE'],\n            ['VALID_YESNO_MIXEDCASE_TRUE'],\n            ['VALID_YESNO_MIXEDCASE_FALSE'],\n        ];\n    }\n\n    /**\n     * @dataProvider validBooleanValuesDataProvider\n     * @doesNotPerformAssertions\n     */\n    public function testCanValidateBooleans(string $boolean)\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'booleans.env');\n        $dotenv->load();\n        $dotenv->required($boolean)->isBoolean();\n    }\n\n    /**\n     * @dataProvider validBooleanValuesDataProvider\n     * @doesNotPerformAssertions\n     */\n    public function testCanValidateBooleansIfPresent(string $boolean)\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'booleans.env');\n        $dotenv->load();\n        $dotenv->ifPresent($boolean)->isBoolean();\n    }\n\n    /**\n     * List of non-boolean values in fixtures/env/booleans.env.\n     *\n     * @return string[][]\n     */\n    public static function invalidBooleanValuesDataProvider()\n    {\n        return [\n            ['INVALID_SOMETHING'],\n            ['INVALID_EMPTY'],\n            ['INVALID_EMPTY_STRING'],\n            ['INVALID_NULL'],\n            ['INVALID_NUMBER_POSITIVE'],\n            ['INVALID_NUMBER_NEGATIVE'],\n            ['INVALID_MINUS'],\n            ['INVALID_TILDA'],\n            ['INVALID_EXCLAMATION'],\n        ];\n    }\n\n    /**\n     * @dataProvider invalidBooleanValuesDataProvider\n     */\n    public function testCanInvalidateNonBooleans(string $boolean)\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'booleans.env');\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: INVALID_');\n\n        $dotenv->required($boolean)->isBoolean();\n    }\n\n    /**\n     * @dataProvider invalidBooleanValuesDataProvider\n     */\n    public function testCanInvalidateNonBooleansIfPresent(string $boolean)\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'booleans.env');\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: INVALID_');\n\n        $dotenv->ifPresent($boolean)->isBoolean();\n    }\n\n    public function testCanInvalidateBooleanNonExist()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'booleans.env');\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: VAR_DOES_NOT_EXIST_234782462764');\n\n        $dotenv->required(['VAR_DOES_NOT_EXIST_234782462764'])->isBoolean();\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testIfPresentBooleanNonExist()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'booleans.env');\n        $dotenv->load();\n        $dotenv->ifPresent(['VAR_DOES_NOT_EXIST_234782462764'])->isBoolean();\n    }\n\n    /**\n     * List of valid integer values in fixtures/env/integers.env.\n     *\n     * @return string[][]\n     */\n    public static function validIntegerValuesDataProvider()\n    {\n        return [\n            ['VALID_ZERO'],\n            ['VALID_ONE'],\n            ['VALID_TWO'],\n            ['VALID_LARGE'],\n            ['VALID_HUGE'],\n        ];\n    }\n\n    /**\n     * @dataProvider validIntegerValuesDataProvider\n     * @doesNotPerformAssertions\n     */\n    public function testCanValidateIntegers(string $integer)\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'integers.env');\n        $dotenv->load();\n        $dotenv->required($integer)->isInteger();\n    }\n\n    /**\n     * @dataProvider validIntegerValuesDataProvider\n     * @doesNotPerformAssertions\n     */\n    public function testCanValidateIntegersIfPresent(string $integer)\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'integers.env');\n        $dotenv->load();\n        $dotenv->ifPresent($integer)->isInteger();\n    }\n\n    /**\n     * List of non-integer values in fixtures/env/integers.env.\n     *\n     * @return string[][]\n     */\n    public static function invalidIntegerValuesDataProvider()\n    {\n        return [\n            ['INVALID_SOMETHING'],\n            ['INVALID_EMPTY'],\n            ['INVALID_EMPTY_STRING'],\n            ['INVALID_NULL'],\n            ['INVALID_NEGATIVE'],\n            ['INVALID_MINUS'],\n            ['INVALID_TILDA'],\n            ['INVALID_EXCLAMATION'],\n            ['INVALID_SPACES'],\n            ['INVALID_COMMAS'],\n        ];\n    }\n\n    /**\n     * @dataProvider invalidIntegerValuesDataProvider\n     */\n    public function testCanInvalidateNonIntegers(string $integer)\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'integers.env');\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: INVALID_');\n\n        $dotenv->required($integer)->isInteger();\n    }\n\n    /**\n     * @dataProvider invalidIntegerValuesDataProvider\n     */\n    public function testCanInvalidateNonIntegersIfExist(string $integer)\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'integers.env');\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: INVALID_');\n\n        $dotenv->ifPresent($integer)->isInteger();\n    }\n\n    public function testCanInvalidateIntegerNonExist()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'integers.env');\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: VAR_DOES_NOT_EXIST_234782462764');\n\n        $dotenv->required(['VAR_DOES_NOT_EXIST_234782462764'])->isInteger();\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testIfPresentIntegerNonExist()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder, 'integers.env');\n        $dotenv->load();\n        $dotenv->ifPresent(['VAR_DOES_NOT_EXIST_234782462764'])->isInteger();\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testDotenvRegexMatchPass()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder);\n        $dotenv->load();\n        $dotenv->required('FOO')->allowedRegexValues('([[:lower:]]{3})');\n    }\n\n    public function testDotenvRegexMatchFail()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder);\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: FOO does not match \"/^([[:lower:]]{1})$/\".');\n\n        $dotenv->required('FOO')->allowedRegexValues('/^([[:lower:]]{1})$/');\n    }\n\n    public function testDotenvRegexMatchError()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder);\n        $dotenv->load();\n\n        $this->expectException(ValidationException::class);\n        $this->expectExceptionMessage('One or more environment variables failed assertions: FOO does not match \"/([[:lower:]{1{\".');\n\n        $dotenv->required('FOO')->allowedRegexValues('/([[:lower:]{1{');\n    }\n\n    /**\n     * @doesNotPerformAssertions\n     */\n    public function testDotenvRegexMatchNotPresent()\n    {\n        $dotenv = Dotenv::createImmutable(self::$folder);\n        $dotenv->load();\n        $dotenv->ifPresent('FOOOOOOOOOOO')->allowedRegexValues('([[:lower:]]{3})');\n    }\n}\n"
  },
  {
    "path": "tests/fixtures/env/assertions.env",
    "content": "ASSERTVAR1=val1\n\nASSERTVAR2=\"\"\n\nASSERTVAR3=\"val3   \"\nASSERTVAR4=\"0\" # empty looking value\nASSERTVAR5=\"#foo\"\nASSERTVAR6=\"val1\nval2\"\nASSERTVAR7=\"\nval3\" #\n\n\nASSERTVAR8=\"val3\n\"\nASSERTVAR9=\"\n\n\"\n"
  },
  {
    "path": "tests/fixtures/env/booleans.env",
    "content": "VALID_EXPLICIT_LOWERCASE_TRUE=true\nVALID_EXPLICIT_LOWERCASE_FALSE=false\nVALID_EXPLICIT_UPPERCASE_TRUE=TRUE\nVALID_EXPLICIT_UPPERCASE_FALSE=FALSE\nVALID_EXPLICIT_MIXEDCASE_TRUE=True\nVALID_EXPLICIT_MIXEDCASE_FALSE=False\n\nVALID_NUMBER_TRUE=1\nVALID_NUMBER_FALSE=0\n\nVALID_ONOFF_LOWERCASE_TRUE=on\nVALID_ONOFF_LOWERCASE_FALSE=off\nVALID_ONOFF_UPPERCASE_TRUE=ON\nVALID_ONOFF_UPPERCASE_FALSE=OFF\nVALID_ONOFF_MIXEDCASE_TRUE=On\nVALID_ONOFF_MIXEDCASE_FALSE=Off\n\nVALID_YESNO_LOWERCASE_TRUE=yes\nVALID_YESNO_LOWERCASE_FALSE=no\nVALID_YESNO_UPPERCASE_TRUE=YES\nVALID_YESNO_UPPERCASE_FALSE=NO\nVALID_YESNO_MIXEDCASE_TRUE=Yes\nVALID_YESNO_MIXEDCASE_FALSE=No\n\nINVALID_SOMETHING=something\nINVALID_EMPTY=\nINVALID_EMPTY_STRING=\"\"\nINVALID_NULL=null\nINVALID_NUMBER_POSITIVE=2\nINVALID_NUMBER_NEGATIVE=-2\nINVALID_MINUS=-\nINVALID_TILDA=~\nINVALID_EXCLAMATION=!\n"
  },
  {
    "path": "tests/fixtures/env/commented.env",
    "content": "# This is a comment\nCFOO=bar\n#CBAR=baz\n#CZOO=goo # a comment on a commented row\nCSPACED=\"with spaces\" # this is a comment\nCQUOTES=\"a value with a # character\" # this is a comment\nCQUOTESWITHQUOTE=\"a value with a # character & a quote \\\" character inside quotes\" # \" this is a comment\nEMPTY= # comment with empty variable\nEMPTY2=# comment with empty variable\nFOOO=foo# comment with no space\nBOOLEAN=yes # (yes, no)\n\nCNULL=\n\n## this is a comment ##\n"
  },
  {
    "path": "tests/fixtures/env/empty.env",
    "content": "EMPTY_VAR\n"
  },
  {
    "path": "tests/fixtures/env/example.env",
    "content": "EG=\"example\"\n"
  },
  {
    "path": "tests/fixtures/env/exported.env",
    "content": "export\tEFOO=\"bar\"\nexport EBAR = \"baz\"\nexport ESPACED=\"with spaces\"\nexport \"EDQUOTED\" = 123\nexport 'ESQUOTED' = 456\n\nexport    ENULL=\"\"\n"
  },
  {
    "path": "tests/fixtures/env/immutable.env",
    "content": "IMMUTABLE=false\n"
  },
  {
    "path": "tests/fixtures/env/integers.env",
    "content": "VALID_ZERO=0\nVALID_ONE=1\nVALID_TWO=2\n\nVALID_LARGE=99999999\nVALID_HUGE=99999999999999999999999999999999\n\nINVALID_SOMETHING=something\nINVALID_EMPTY=\nINVALID_EMPTY_STRING=\"\"\nINVALID_NULL=null\nINVALID_NEGATIVE=-2\nINVALID_MINUS=-\nINVALID_TILDA=~\nINVALID_EXCLAMATION=!\nINVALID_SPACES=\" 123\"\nINVALID_COMMAS=\"123,123\"\n"
  },
  {
    "path": "tests/fixtures/env/large.env",
    "content": "LARGE='111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'\nHUGE='AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'\n"
  },
  {
    "path": "tests/fixtures/env/multibyte.env",
    "content": "MB1=\"Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě\"\nMB2=行内支付\nAPP_ENV=🚀\n"
  },
  {
    "path": "tests/fixtures/env/multiline.env",
    "content": "TEST=\"test\n     test\\\"test\\\"\n     test\"\n\nTEST_ND=\"test\\ntest\"\nTEST_NS='test\\ntest'\n\nTEST_EQD=\"https://vision.googleapis.com/v1/images:annotate?key=\"\nTEST_EQS='https://vision.googleapis.com/v1/images:annotate?key='\n\nBASE64_ENCODED_MULTILINE=\"qS1zCzMVVUJWQShokv6YVYi+ruKSC/bHV7GmEiyVkLaBWJHNVHCHsgTksEBsy8wJ\nuwycAvR07ZyOJJed4XTRMKnKp1/v+6UATpWzkIjZXytK+pD+XlZimUHTx3uiDcmU\njhQX1wWSxHDqrSWxeIJiTD+BuUyId8FzmXQ3TcBydJ474tmOU2F492ubk3LAiZ18\nmhiRGoshXAOSbS/P3+RZi4bDeNE/No4=\"\n"
  },
  {
    "path": "tests/fixtures/env/multiple.env",
    "content": "MULTI1=foo\nMULTI2=${MULTI1}\nMULTI1=bar\n\n"
  },
  {
    "path": "tests/fixtures/env/mutable.env",
    "content": "MUTABLE=true"
  },
  {
    "path": "tests/fixtures/env/nested.env",
    "content": "NVAR1=\"Hellō\"\nNVAR2=\"World!\"\nNVAR3=\"{$NVAR1} {$NVAR2}\"\nNVAR4=\"${NVAR1} ${NVAR2}\"\nNVAR5=\"$NVAR1 {NVAR2}\"\nN.VAR6=\"Special Value\"\nNVAR7=\"${N.VAR6}\"\nNVAR8=\"\"\nNVAR9=\"${NVAR8}\"\nNVAR10=\"${NVAR888}\"\nNVAR11=\"NVAR1\"\nNVAR12=\"${${NVAR11}}\"\nNVAR13='${${NVAR11}}'\nNVAR14='${NVAR1} ${NVAR2}'\nNVAR15=\"\\${NVAR1} \\${NVAR2}\"\n"
  },
  {
    "path": "tests/fixtures/env/quoted.env",
    "content": "QFOO=\"bar\"\nQBAR=\"baz\"\nQSPACED=\"with spaces\"\nQEQUALS=\"pgsql:host=localhost;dbname=test\"\n\nQNULL=\"\"\nQWHITESPACE = \"no space\"\n\nQESCAPED=\"test some escaped characters like a quote (\\\") or maybe a backslash (\\\\)\"\nQSLASH=\"iiiiviiiixiiiiviiii\\\\n\"\nSQSLASH='iiiiviiiixiiiiviiii\\\\n'\n"
  },
  {
    "path": "tests/fixtures/env/specialchars.env",
    "content": "SPVAR1=\"$a6^C7k%zs+e^.jvjXk\"\nSPVAR2=\"?BUty3koaV3%GA*hMAwH}B\"\nSPVAR3=\"jdgEB4{QgEC]HL))&GcXxokB+wqoN+j>xkV7K?m$r\"\nSPVAR4=\"22222:22#2^{\"\nSPVAR5=\"test some escaped characters like a quote \\\" or maybe a backslash \\\\\" # not escaped\nSPVAR6=secret!@#\nSPVAR7='secret!@#'\nSPVAR8=\"secret!@#\"\n"
  },
  {
    "path": "tests/fixtures/env/unicodevarnames.env",
    "content": "AlbertÅberg=Skybert\nДатаЗакрытияРасчетногоПериода='2022-04-01T00:00'\n"
  },
  {
    "path": "tests/fixtures/env/utf8-with-bom-encoding.env",
    "content": "﻿FOO=bar\nBAR=baz\nSPACED=\"with spaces\"\n"
  },
  {
    "path": "tests/fixtures/env/windows.env",
    "content": "MBW=\"\"\n"
  },
  {
    "path": "vendor-bin/phpstan/composer.json",
    "content": "{\n    \"require\": {\n        \"php\": \"^8.5\",\n        \"phpstan/phpstan\": \"2.1.33\",\n        \"phpstan/extension-installer\": \"1.4.3\",\n        \"phpstan/phpstan-deprecation-rules\": \"2.0.3\",\n        \"phpstan/phpstan-strict-rules\": \"2.0.7\"\n    },\n    \"config\": {\n        \"preferred-install\": \"dist\",\n        \"allow-plugins\": {\n            \"phpstan/extension-installer\": true\n        }\n    }\n}\n"
  }
]