Full Code of BrianHenryIE/strauss for AI

master dd5fb996f5ac cached
223 files
2.0 MB
545.4k tokens
1480 symbols
1 requests
Download .txt
Showing preview only (2,181K chars total). Download the full file or copy to clipboard to get everything.
Repository: BrianHenryIE/strauss
Branch: master
Commit: dd5fb996f5ac
Files: 223
Total size: 2.0 MB

Directory structure:
gitextract_25c61qh9/

├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   └── bug_report.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── claude-code-review.yml
│       ├── claude.yml
│       ├── codecoverage.yml
│       ├── main.yml
│       ├── phpstan.yml
│       ├── release.yml
│       └── updateversionfromchangelog.yml
├── .gitignore
├── .phive/
│   └── phars.xml
├── .typos.toml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── bin/
│   └── strauss
├── bootstrap.php
├── composer.json
├── phive.phar.asc
├── phpcs.xml
├── phpstan-baseline.neon
├── phpstan.neon
├── phpunit.xml
├── scripts/
│   ├── createphar.sh
│   └── getbuiltinphp.php
├── src/
│   ├── Composer/
│   │   ├── ComposerPackage.php
│   │   ├── Extra/
│   │   │   ├── ReplaceConfigInterface.php
│   │   │   └── StraussConfig.php
│   │   └── ProjectComposerPackage.php
│   ├── Config/
│   │   ├── AliasesConfigInterface.php
│   │   ├── AutoloadConfigInterface.php
│   │   ├── AutoloadFilesEnumeratorConfigInterface.php
│   │   ├── ChangeEnumeratorConfigInterface.php
│   │   ├── CleanupConfigInterface.php
│   │   ├── CopierConfigInterface.php
│   │   ├── FileCopyScannerConfigInterface.php
│   │   ├── FileEnumeratorConfig.php
│   │   ├── FileSymbolScannerConfigInterface.php
│   │   ├── LicenserConfigInterface.php
│   │   ├── MarkSymbolsForRenamingConfigInterface.php
│   │   ├── OptimizeAutoloaderConfigInterface.php
│   │   └── PrefixerConfigInterface.php
│   ├── Console/
│   │   ├── Application.php
│   │   └── Commands/
│   │       ├── AbstractRenamespacerCommand.php
│   │       ├── DependenciesCommand.php
│   │       ├── IncludeAutoloaderCommand.php
│   │       └── ReplaceCommand.php
│   ├── Files/
│   │   ├── DiscoveredFiles.php
│   │   ├── File.php
│   │   ├── FileBase.php
│   │   ├── FileWithDependency.php
│   │   └── HasDependency.php
│   ├── Helpers/
│   │   ├── FileSystem.php
│   │   ├── FlysystemBackCompatInterface.php
│   │   ├── FlysystemBackCompatTrait.php
│   │   ├── InMemoryFilesystemAdapter.php
│   │   ├── Log/
│   │   │   ├── PadColonColumnsLogProcessor.php
│   │   │   └── RelativeFilepathLogProcessor.php
│   │   ├── NamespaceSort.php
│   │   ├── ReadOnlyFileSystem.php
│   │   └── StripFsRootPathNormalizer.php
│   ├── Pipeline/
│   │   ├── Aliases/
│   │   │   ├── Aliases.php
│   │   │   └── autoload_aliases.template.php
│   │   ├── Autoload/
│   │   │   ├── ComposerAutoloadGenerator.php
│   │   │   ├── DumpAutoload.php
│   │   │   └── VendorComposerAutoload.php
│   │   ├── Autoload.php
│   │   ├── AutoloadedFilesEnumerator.php
│   │   ├── ChangeEnumerator.php
│   │   ├── Cleanup/
│   │   │   ├── Cleanup.php
│   │   │   └── InstalledJson.php
│   │   ├── Copier.php
│   │   ├── DependenciesEnumerator.php
│   │   ├── FileCopyScanner.php
│   │   ├── FileEnumerator.php
│   │   ├── FileSymbol/
│   │   │   └── builtinsymbols.php
│   │   ├── FileSymbolScanner.php
│   │   ├── Licenser.php
│   │   ├── MarkSymbolsForRenaming.php
│   │   └── Prefixer.php
│   └── Types/
│       ├── AutoloadAliasInterface.php
│       ├── ClassSymbol.php
│       ├── ConstantSymbol.php
│       ├── DiscoveredSymbol.php
│       ├── DiscoveredSymbols.php
│       ├── FunctionSymbol.php
│       ├── InterfaceSymbol.php
│       ├── NamespaceSymbol.php
│       └── TraitSymbol.php
└── tests/
    ├── Integration/
    │   ├── Autoload/
    │   │   ├── DumpAutoloadFeatureTest.php
    │   │   └── VendorComposerAutoloadFeatureTest.php
    │   ├── ChangeEnumeratorIntegrationTest.php
    │   ├── Cleanup/
    │   │   ├── ExcludeFromCopyAutoloadIntegrationTest.php
    │   │   └── InstalledJsonIntegrationTest.php
    │   ├── CleanupIntegrationTest.php
    │   ├── CleanupSymlinkIntegrationTest.php
    │   ├── CopierFeatureTest.php
    │   ├── CopierIntegrationTest.php
    │   ├── DryRunFeatureTest.php
    │   ├── DumpAutoloadFeatureTest.php
    │   ├── ExcludeFromPrefixFeatureTest.php
    │   ├── FileCopyScannerIntegrationTest.php
    │   ├── FileEnumeratorIntegrationTest.php
    │   ├── Helpers/
    │   │   ├── FileSystemIntegrationTest.php
    │   │   ├── PadColonColumnsLogProcessorIntegrationTest.php
    │   │   └── ReadOnlyFileSystemIntegrationTest.php
    │   ├── OutputLevelFeatureTest.php
    │   ├── Pipeline/
    │   │   └── Aliases/
    │   │       └── AliasesFeatureTest.php
    │   ├── ReplaceCommandIntegrationTest.php
    │   ├── ReplacerIntegrationTest.php
    │   └── UpdateCallSitesIntegrationTest.php
    ├── IntegrationTestCase.php
    ├── Issues/
    │   ├── MozartIssue106Test.php
    │   ├── MozartIssue108Test.php
    │   ├── MozartIssue109Test.php
    │   ├── MozartIssue124Test.php
    │   ├── MozartIssue128Test.php
    │   ├── MozartIssue129Test.php
    │   ├── MozartIssue130Test.php
    │   ├── MozartIssue13Test.php
    │   ├── MozartIssue43Test.php
    │   ├── MozartIssue48Test.php
    │   ├── MozartIssue62Test.php
    │   ├── MozartIssue66Test.php
    │   ├── MozartIssue86Test.php
    │   ├── MozartIssue89Test.php
    │   ├── MozartIssue90Test.php
    │   ├── MozartIssue93Test.php
    │   ├── MozartIssue97Test.php
    │   ├── MozartIssue99Test.php
    │   ├── StraussIssue101Test.php
    │   ├── StraussIssue104Test.php
    │   ├── StraussIssue108Test.php
    │   ├── StraussIssue109Test.php
    │   ├── StraussIssue111Test.php
    │   ├── StraussIssue114Test.php
    │   ├── StraussIssue119Test.php
    │   ├── StraussIssue11Test.php
    │   ├── StraussIssue133Test.php
    │   ├── StraussIssue136Test.php
    │   ├── StraussIssue143Test.php
    │   ├── StraussIssue14Test.php
    │   ├── StraussIssue154Test.php
    │   ├── StraussIssue159Test.php
    │   ├── StraussIssue163Test.php
    │   ├── StraussIssue166Test.php
    │   ├── StraussIssue172Test.php
    │   ├── StraussIssue173Test.php
    │   ├── StraussIssue179Test.php
    │   ├── StraussIssue183Test.php
    │   ├── StraussIssue188Test.php
    │   ├── StraussIssue189Test.php
    │   ├── StraussIssue191Test.php
    │   ├── StraussIssue19Test.php
    │   ├── StraussIssue200Test.php
    │   ├── StraussIssue204Test.php
    │   ├── StraussIssue206Test.php
    │   ├── StraussIssue207Test.php
    │   ├── StraussIssue212Test.php
    │   ├── StraussIssue213Test.php
    │   ├── StraussIssue215Test.php
    │   ├── StraussIssue225Test.php
    │   ├── StraussIssue22Test.php
    │   ├── StraussIssue230Test.php
    │   ├── StraussIssue247Test.php
    │   ├── StraussIssue249Test.php
    │   ├── StraussIssue258Test.php
    │   ├── StraussIssue261Test.php
    │   ├── StraussIssue262Test.php
    │   ├── StraussIssue27Test.php
    │   ├── StraussIssue33Test.php
    │   ├── StraussIssue34Test.php
    │   ├── StraussIssue37Test.php
    │   ├── StraussIssue44Test.php
    │   ├── StraussIssue47Test.php
    │   ├── StraussIssue49Test.php
    │   ├── StraussIssue65Test.php
    │   ├── StraussIssue66Test.php
    │   ├── StraussIssue74Test.php
    │   ├── StraussIssue76Test.php
    │   ├── StraussIssue79Test.php
    │   ├── StraussIssue80Test.php
    │   ├── StraussIssue81Test.php
    │   ├── StraussIssue83Test.php
    │   ├── StraussIssue87Test.php
    │   ├── StraussIssue88Test.php
    │   ├── StraussIssue8Test.php
    │   ├── StraussIssue91Test.php
    │   ├── StraussIssue93Test.php
    │   └── data/
    │       └── Mpdf.php
    ├── TestCase.php
    └── Unit/
        ├── Composer/
        │   ├── ComposerPackageTest.php
        │   ├── Extra/
        │   │   └── StraussConfigTest.php
        │   ├── ProjectComposerPackageTest.php
        │   ├── composerpackage-test-easypost-php.json
        │   ├── composerpackage-test-libmergepdf.json
        │   ├── composerpackage-test-php-di.json
        │   ├── projectcomposerpackage-test-1.json
        │   └── projectcomposerpackage-test-getProjectPhpFiles.json
        ├── Console/
        │   ├── ApplicationTest.php
        │   └── Commands/
        │       └── DependenciesCommandTest.php
        ├── DiscoveredFilesTest.php
        ├── FileEnumeratorTest.php
        ├── Files/
        │   └── FileWithDependencyTest.php
        ├── Helpers/
        │   ├── FileSystemTest.php
        │   └── NamespaceSortTest.php
        ├── LicenserTest.php
        ├── Pipeline/
        │   ├── Aliases/
        │   │   └── AliasesTest.php
        │   ├── Autoload/
        │   │   ├── ComposerAutoloadGeneratorTest.php
        │   │   ├── DumpAutoloadTest.php
        │   │   └── VendorComposerAutoloadTest.php
        │   ├── AutoloadTest.php
        │   ├── ChangeEnumeratorTest.php
        │   ├── Cleanup/
        │   │   ├── CleanupTest.php
        │   │   └── InstalledJsonTest.php
        │   ├── CopierTest.php
        │   ├── FileCopyScannerTest.php
        │   ├── FileSymbolScannerTest.php
        │   └── MarkSymbolsForRenamingTest.php
        ├── PrefixerTest.php
        └── Types/
            ├── DiscoveredSymbolTest.php
            └── DiscoveredSymbolsTest.php

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
#
# Exclude these files from release archives.
# This will also make them unavailable when using Composer with `--prefer-dist`.
# https://blog.madewithlove.be/post/gitattributes/
#
/.gitattributes       export-ignore
/.gitignore           export-ignore
/.github              export-ignore
/.phive               export-ignore
/.typos.toml          export-ignore
/phive.phar.asc       export-ignore
/phpcs.xml            export-ignore
/phpstan.neon         export-ignore
/phpstanbootstrap.php export-ignore
/phpunit.xml          export-ignore
/scripts              export-ignore
/tests                export-ignore

#
# Auto detect text files and perform LF normalization
# https://pablorsk.medium.com/be-a-git-ninja-the-gitattributes-file-e58c07c9e915
#
* text=auto

*.php text


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''

---

A bug report generally means something is not being prefixed that should, or, less commonly, something is being prefixed that should not.

Please provide a minimal `composer.json` with the package that is affected and its precise version.

Please specify an affected file and state clearly the actual (problem) output and the expected output.


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:

  # Maintain dependencies for GitHub Actions
  - package-ecosystem: "github-actions"
    directory: "/"
    target-branch: "master"
    allow:
      - dependency-type: direct
    schedule:
      interval: "weekly"
    commit-message:
      prefix: "GitHub Actions"
      include: "scope"
    labels:
      - "dependencies"
      - "workflows"

  # Maintain dependencies for Composer
  - package-ecosystem: "composer"
    directory: "/"
    target-branch: "master"
    allow:
      - dependency-type: direct
    schedule:
      interval: "daily"
    versioning-strategy: increase
    commit-message:
      prefix: "Composer"
      prefix-development: "Composer Dev"
      include: "scope"
    labels:
      - "dependencies"
      - "php"


================================================
FILE: .github/workflows/claude-code-review.yml
================================================
name: Claude Code Review

on:
  pull_request_target:
    types: [opened, synchronize, ready_for_review, reopened]
    # Optional: Only run on specific file changes
    # paths:
    #   - "src/**/*.ts"
    #   - "src/**/*.tsx"
    #   - "src/**/*.js"
    #   - "src/**/*.jsx"
  workflow_dispatch:

jobs:
  claude-review:
#    # Only run for PRs from the same repo, not external forks
#    if: github.event.pull_request.head.repo.full_name == github.repository

    # Optional: Filter by PR author
    # if: |
    #   github.event.pull_request.user.login == 'external-contributor' ||
    #   github.event.pull_request.user.login == 'new-developer' ||
    #   github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'

    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write # Needed for leaving PR comments
      issues: read
      id-token: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          fetch-depth: 1

      - name: Run Claude Code Review
        id: claude-review
        uses: anthropics/claude-code-action@v1
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
          github_token: ${{ secrets.GITHUB_TOKEN }}
          additional_permissions: |
            actions: read
            pull-requests: write
          prompt: |
            REPO: ${{ github.repository }}
            PR NUMBER: ${{ github.event.pull_request.number }}

            Please review this pull request and provide feedback on:
            - Code quality and best practices
            - Potential bugs or issues
            - Performance considerations
            - Security concerns
            - Test coverage

            Be constructive and helpful in your feedback.

            Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.

          # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
          # or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
          claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
          # Re-use one comment for each updated Claude evaluation.
          use_sticky_comment: true
        env:
          # Fix: Either ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN is required when using direct Anthropic API. (although `claude_code_oauth_token` is set above)
          CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}


================================================
FILE: .github/workflows/claude.yml
================================================
name: Claude Code

on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
  issues:
    types: [opened, assigned]
  pull_request_review:
    types: [submitted]
  workflow_dispatch:

jobs:
  claude:
    if: |
      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
      (github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
      actions: read # Required for Claude to read CI results on PRs
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          fetch-depth: 1

      - name: Run Claude Code
        id: claude
        uses: anthropics/claude-code-action@v1
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

          # This is an optional setting that allows Claude to read CI results on PRs
          additional_permissions: |
            actions: read

          # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
          # prompt: 'Update the pull request description to include a summary of changes.'

          # Optional: Add claude_args to customize behavior and configuration
          # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
          # or https://code.claude.com/docs/en/cli-reference for available options
          # claude_args: '--allowed-tools Bash(gh pr:*)'



================================================
FILE: .github/workflows/codecoverage.yml
================================================
name: Code Coverage

# Runs PHPUnit with code coverage enabled, commits the html report to
# GitHub Pages, generates a README badge with the coverage percentage.
#
# Requires a gh-pages branch already created.
#
#  git checkout --orphan gh-pages
#  touch index.html
#  git add index.html
#  git commit -m 'Set up gh-pages branch' index.html
#  git push origin gh-pages
#
# @author BrianHenryIE

on:
  pull_request:
    types: [opened, synchronize, ready_for_review, reopened]
  push:
    branches:
      - master
    paths:
      - '**.php'
      - 'composer.json'
      - '.github/workflows/codecoverage.yml'
  workflow_dispatch:

concurrency:
  # Cancel previous runs of this workflow if they are testing the same branch
  group: ${{ github.workflow }}-${{ (github.event_name == 'pull_request' && github.head_ref) || github.sha }}
  cancel-in-progress: true

env:
  COVERAGE_PHP_VERSION: '7.4'

jobs:
  tests:
    runs-on: ubuntu-latest

    permissions:
      pull-requests: write # To add coverage comment
      contents: write # To commit coverage badge & report

    strategy:
      matrix:
        php: [ '7.4' ]

    steps:
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          tools: composer:v2, phive
          extensions: fileinfo, gd
          coverage: ${{ matrix.php == env.COVERAGE_PHP_VERSION && 'xdebug' || 'none' }}

      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          # Value already defaults to true, but `persist-credentials` is required to push new commits to the repository.
          persist-credentials: true

      - name: Checkout GitHub Pages branch for code coverage report
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }}
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: gh-pages
          path: gh-pages

      # TODO: merge master into this branch and run tests against what master will become, not just the isolated branch.
      # NB: how would that affect tj-actions/changed-files?

      - name: Install Phive tools
        if: ${{ github.event.pull_request.author_association == 'COLLABORATOR' || github.event.pull_request.author_association == 'OWNER' }} # secrets are not available to users without write access
        # Keys taken from `phive status`
        # `phive status | grep -oE '[A-F0-9]{16}' | tr '\n' ',' | sed 's/,$//'`
        # sed -i "s|^\s*phive install --trust-gpg-keys .*| phive install --trust-gpg-keys $(phive status | grep -oE '[A-F0-9]{16}' | paste -sd,)|" .github/workflows/phpstan.yml
        run: |
          phive install --trust-gpg-keys A9DB489A9190DE9B,4AA394086372C20A
          phive status
        env:
          # We need to be authenticated to skip GitHub rate limits
          # Generate a key at: https://github.com/settings/tokens, "classic"
          # Approve the 2FA notification on your phone (I presume/hope)
          # "Note" what it is for, I use ~PHIVE_GH_RATE_LIMIT_BRIANHENRY_EXPIRES_DEC182026 etc.
          # Choose "Expiration", "Custom"
          # For "Select Date", the Expiration date can only be set ~364 days ahead
          # No scopes are needed, scroll down and click "Generate Token"
          # Copied the displayed key
          # Visit https://github.com/your/repo/settings/secrets/actions
          # Click "New repository secret" and fill it in
          # Do the same at https://github.com/your/repo/settings/secrets/dependabot
          #
          # Fix for rate limited GitHub API requests. See https://github.com/phar-io/phive/issues/384#issuecomment-1337064012
          GITHUB_AUTH_TOKEN: ${{ secrets.PHIVE_GH_RATE_LIMIT_BRIANHENRY_EXPIRES_DEC182026 }}

      - name: Install Phive tools (unauthenticated)
        # secrets are not available to users without write access
        if: ${{ github.event.pull_request.author_association != 'COLLABORATOR' && github.event.pull_request.author_association != 'OWNER' }}
        run: |
          phive install --trust-gpg-keys A9DB489A9190DE9B,4AA394086372C20A
          phive status

      - name: Install PHP dependencies
        run: composer update --prefer-dist --verbose

      - name: Print composer.lock (for debug)
        run: cat composer.lock

      - name: Run tests without coverage
        if: ${{ matrix.php != env.COVERAGE_PHP_VERSION }}
        run: |
          vendor/bin/phpunit ./tests/Unit/ --debug

      - name: Run tests with coverage
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }} # We only need the coverage once
        run: XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --coverage-php gh-pages/${{ github.sha }}/phpunit/coveragephp.cov --coverage-clover tests/_output/clover.xml --coverage-html gh-pages/${{ github.sha }}/phpunit/html/ ./tests/Unit/ --debug


      # This makes the coverage percentage available in `{{ steps.coverage-percentage.outputs.coverage }}`.
      - name: Check test coverage
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }}
        uses: johanvanhelden/gha-clover-test-coverage-check@2543c79a701f179bd63aa14c16c6938c509b2cec # v1
        id: coverage-percentage
        with:
          percentage: 25
          exit: false
          filename: tests/_output/clover.xml
          rounded-precision: "0"

      - name: Generate the badge SVG image
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }}
        uses: emibcn/badge-action@v2
        id: badge
        with:
          label: 'PHPUnit'
          status: ${{ format('{0}%', steps.coverage-percentage.outputs.coverage-rounded) }}
          path: .github/coverage.svg
          color: ${{ steps.coverage.outputs.coverage >= 90 && 'green'
            || steps.coverage.outputs.coverage >= 80 && 'orange'
            || 'red' }}

      - name: Copy badge for PR comment display
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }}
        run: cp .github/coverage.svg gh-pages/${{ github.sha }}/phpunit/coverage.svg

      - name: Update root gh pages to redirect to commit for master
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION && github.ref == 'refs/heads/master' }}
        run: |
          echo '<script>window.location.href="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ github.sha }}/phpunit/html/index.html";</script><a href="https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ github.sha }}/phpunit/html/index.html">Coverage at ${{ github.sha }}</a>' > gh-pages/index.html

      # https://github.blog/news-insights/bypassing-jekyll-on-github-pages/
      # https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/about-github-pages-and-jekyll
      - name: Disable Jekyll for GitHub Pages
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION }}
        run: |
          if [ ! -f "gh-pages/.nojekyll" ]; then
            touch gh-pages/.nojekyll
          fi

      - name: Commit HTML code coverage + badge to gh-pages
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION && (github.event.pull_request.author_association == 'COLLABORATOR' || github.event.pull_request.author_association == 'OWNER') }}
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          repository: gh-pages
          branch: gh-pages
          commit_message: "🤖 Commit code coverage to gh-pages"

      - name: Commit code coverage badge to master/main
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION && github.ref == 'refs/heads/master' }}
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          file_pattern: .github/coverage.svg
          commit_message: "🤖 Commit code coverage badge"

      - name: Get changed files
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION && github.event_name == 'pull_request' }}
        id: changed-files
        uses: tj-actions/changed-files@v47
        with:
          separator: ','
          files: '**/**.php'

      - name: Generate markdown report
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION && github.event_name == 'pull_request' }} # We only need it added once
        run: |
          vendor/bin/php-codecoverage-markdown \
            --input-file gh-pages/${{ github.sha }}/phpunit/coveragephp.cov \
            --covered-files=${{ steps.changed-files.outputs.all_changed_files }} \
            --base-url ${{ format('https://{0}.github.io/{1}/{2}/phpunit/html/', github.repository_owner, github.event.repository.name, github.sha) }} \
            --output-file coverage-report.md

      - name: Add to the PR message
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION && github.event_name == 'pull_request' }}
        run: |
          echo "[![Project Code Coverage](https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ github.sha }}/phpunit/coverage.svg)](https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ github.sha }}/phpunit/html/index.html)" > coverage-comment-header.md
          echo "${{ format('[project coverage report {0}%](https://{1}.github.io/{2}/{3}/phpunit/html/) @ {4}', steps.coverage-percentage.outputs.coverage-rounded, github.repository_owner, github.event.repository.name, github.sha, github.sha) }}" >> coverage-comment-header.md
          echo "$(cat coverage-comment-header.md)" > coverage-comment.md
          echo "" >> coverage-comment.md
          echo "" >> coverage-comment.md
          echo "$(cat coverage-report.md)" >> coverage-comment.md

      - name: Add phpcov uncovered lines report to PR comment
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION && github.event_name == 'pull_request' }}
        continue-on-error: true # `phpcov` can fail if there are no uncovered lines
        run: |
          BRANCHED_COMMIT=$(git rev-list origin..HEAD | tail -n 1);
          echo "BRANCHED_COMMIT=$BRANCHED_COMMIT"
          git diff $BRANCHED_COMMIT...${{ github.event.pull_request.head.sha }} > branch.diff
          cat branch.diff
          OUTPUT=${vendor/bin/phpcov patch-coverage --path-prefix $(pwd) ./gh-pages/${{ github.event.pull_request.head.sha }}/phpunit/phpunit.cov branch.diff || true}
          echo $OUTPUT
          echo "" >> coverage-comment.md
          echo "$OUTPUT" >> coverage-comment.md

      - name: Comment on PR
        uses: mshick/add-pr-comment@v3
        if: ${{ matrix.php == env.COVERAGE_PHP_VERSION && github.event_name == 'pull_request' }} # We only need it added once
        with:
          message-id: coverage-report
          message-path: coverage-comment.md
        continue-on-error: true # When a PR is opened by a non-member, there are no write permissions (and no access to secrets), so this step will always fail.


================================================
FILE: .github/workflows/main.yml
================================================
name: Lint and test

on:
  push:
    branches:
      - master
      - main
    paths:
      - '**.php'
      - 'composer.json'
      - '.github/workflows/main.yml'
  pull_request:
    types: [opened, synchronize, ready_for_review, reopened]
    branches:
      - master
      - main
    paths:
      - '**.php'
      - 'composer.json'
      - '.github/workflows/main.yml'
  workflow_dispatch:

concurrency:
  # Cancel previous runs of this workflow if they are testing the same branch
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  tests:
    strategy:
      matrix:
        php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
        os: [ubuntu-latest]
#        os: [ubuntu-latest, windows-latest]
      fail-fast: false
    name: PHP tests ${{ matrix.php }} ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v6

      - name: Install PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php }}
          tools: composer:v2, phive
          extensions: fileinfo, gd, zip

      - name: Install Phive tools
        if: ${{ github.event.pull_request.author_association == 'COLLABORATOR' || github.event.pull_request.author_association == 'OWNER' }}
        # Keys taken from `phive status`
        # `phive status | grep -oE '[A-F0-9]{16}' | tr '\n' ',' | sed 's/,$//'`
        # sed -i "s|^\s*phive install --trust-gpg-keys .*| phive install --trust-gpg-keys $(phive status | grep -oE '[A-F0-9]{16}' | paste -sd,)|" .github/workflows/phpstan.yml
        run: |
          phive install --trust-gpg-keys A9DB489A9190DE9B,4AA394086372C20A
          phive status
        env:
          # We need to be authenticated to skip GitHub rate limits
          # Generate a key at: https://github.com/settings/tokens, "classic"
          # Approve the 2FA notification on your phone (I presume/hope)
          # "Note" what it is for, I use ~PHIVE_GH_RATE_LIMIT_BRIANHENRY_EXPIRES_DEC182026 etc.
          # Choose "Expiration", "Custom"
          # For "Select Date", the Expiration date can only be set ~364 days ahead
          # No scopes are needed, scroll down and click "Generate Token"
          # Copied the displayed key
          # Visit https://github.com/your/repo/settings/secrets/actions
          # Click "New repository secret" and fill it in
          # Do the same at https://github.com/your/repo/settings/secrets/dependabot
          #
          # Fix for rate limited GitHub API requests. See https://github.com/phar-io/phive/issues/384#issuecomment-1337064012
          GITHUB_AUTH_TOKEN: ${{ secrets.PHIVE_GH_RATE_LIMIT_BRIANHENRY_EXPIRES_DEC182026 }}

      - name: Install Phive tools (unauthenticated)
        # secrets are not available to users without write access
        if: ${{ github.event.pull_request.author_association != 'COLLABORATOR' && github.event.pull_request.author_association != 'OWNER' }}
        run: |
          phive install --trust-gpg-keys A9DB489A9190DE9B,4AA394086372C20A
          phive status

      - name: Setup problem matcher for PHPUnit
        run: |
          echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

      - name: Debugging
        run: |
          php --version
          php -m
          composer --version

      - name: Install dependencies
        run: composer install --prefer-dist --no-progress

      - name: Run previously workflows' failed tests first
        uses: BrianHenryIE/bh-phpunit-failed-tests-action@main
        with:
          phpunit-command: vendor/bin/phpunit
        env:
          RENAMESPACER_LOG: "debug"

      - name: Run tests
        run: vendor/bin/phpunit --order-by=random

      - name: Build phar
        run:
          ./scripts/createphar.sh

      - uses: actions/upload-artifact@v7
        if: ${{ matrix.php == '7.4' && github.event_name == 'pull_request' }}
        id: artifact-upload-step
        with:
          name: strauss.phar
          path: strauss.phar

      - name: Add phar to PR comment
        uses: mshick/add-pr-comment@v3
        if: ${{ matrix.php == '7.4' && github.event_name == 'pull_request' }}
        with:
          message-id: strauss-phar
          message: ${{ format('[strauss.phar.zip]({0}) @ {1} {2} `composer require brianhenryie/strauss:"dev-master#{1}" --dev`', steps.artifact-upload-step.outputs.artifact-url, github.event.pull_request.head.sha, '\n') }}
        continue-on-error: true

      - name: Run tests with strauss.phar
        run: vendor/bin/phpunit

  spelling:
    runs-on: ubuntu-latest
    name: Spelling
    steps:

      - uses: actions/checkout@v6

      - name: Search for misspellings
        uses: crate-ci/typos@master

  lint:
    runs-on: ubuntu-latest
    name: Lint project files
    steps:

      - uses: actions/checkout@v6

      - name: Install PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '7.4'
          tools: composer, cs2pr, phive
          extensions: fileinfo, gd

      - name: Install Phive tools
        if: ${{ github.event.pull_request.author_association == 'COLLABORATOR' || github.event.pull_request.author_association == 'OWNER' }} # secrets are not available to users without write access
        # Keys taken from `phive status`
        # `phive status | grep -oE '[A-F0-9]{16}' | tr '\n' ',' | sed 's/,$//'`
        # sed -i "s|^\s*phive install --trust-gpg-keys .*| phive install --trust-gpg-keys $(phive status | grep -oE '[A-F0-9]{16}' | paste -sd,)|" .github/workflows/phpstan.yml
        run: |
          phive install --trust-gpg-keys A9DB489A9190DE9B,4AA394086372C20A
          phive status
        env:
          # We need to be authenticated to skip GitHub rate limits
          # Generate a key at: https://github.com/settings/tokens, "classic"
          # Approve the 2FA notification on your phone (I presume/hope)
          # "Note" what it is for, I use ~PHIVE_GH_RATE_LIMIT_BRIANHENRY_EXPIRES_DEC182026 etc.
          # Choose "Expiration", "Custom"
          # For "Select Date", the Expiration date can only be set ~364 days ahead
          # No scopes are needed, scroll down and click "Generate Token"
          # Copied the displayed key
          # Visit https://github.com/your/repo/settings/secrets/actions
          # Click "New repository secret" and fill it in
          # Do the same at https://github.com/your/repo/settings/secrets/dependabot
          #
          # Fix for rate limited GitHub API requests. See https://github.com/phar-io/phive/issues/384#issuecomment-1337064012
          GITHUB_AUTH_TOKEN: ${{ secrets.PHIVE_GH_RATE_LIMIT_BRIANHENRY_EXPIRES_DEC182026 }}

      - name: Install Phive tools (unauthenticated)
        # secrets are not available to users without write access
        if: ${{ github.event.pull_request.author_association != 'COLLABORATOR' && github.event.pull_request.author_association != 'OWNER' }}
        run: |
          phive install --trust-gpg-keys A9DB489A9190DE9B,4AA394086372C20A
          phive status

      - name: Debugging
        run: |
          php --version
          php -m
          composer --version

      - name: Install dependencies
        run: composer install --prefer-dist --no-progress

      - name: Run validate
        run: |
          vendor/bin/phpcbf || true
          vendor/bin/phpcs -q -n --report=checkstyle | cs2pr

      - name: Commit PHPCBF changes
        if: ${{ github.ref == 'refs/heads/master' && github.event_name == 'push' }} # only commit on pushes to master
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          commit_message: "🤖 PHPCBF"


================================================
FILE: .github/workflows/phpstan.yml
================================================
name: PHPStan Analysis

on:
  pull_request:
    types: [opened, synchronize, ready_for_review, reopened]
#    branches: [ master ] # all PRs?
  push:
    branches:
      - master
  workflow_dispatch:

jobs:
  phpstan:
    runs-on: ubuntu-latest
    permissions:
      contents: write

    steps:
      - name: Checkout PR branch
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0 # needed for baseline comparison

      - name: Set up PHP
        uses: shivammathur/setup-php@ccf2c627fe61b1b4d924adfcbd19d661a18133a0 # v2.35.2
        with:
          php-version: 7.4
          tools: composer:v2, cs2pr
          extensions: fileinfo, gd
          coverage: none

      - name: Install Project Dependencies
        run: composer install

      - name: Run PHPStan (annotate all errors to max level)
        id: run-phpstan
        run: |
          vendor/bin/phpstan analyse --memory-limit=-1  --level max -vvv --error-format=checkstyle | cs2pr
        continue-on-error: true

      - name: Run PHPStan (fail if phpstan.neon level is not met) on PRs
        run: vendor/bin/phpstan analyse --memory-limit=-1 -vvv
        # TODO: fail _after_ the badge is updated
        continue-on-error: true

      - name: Get PhpStan level
        id: phpstan-level
        run: |
          # After adding the example commands at the top of the phpstan.neon file, which contain the word "level", we 
          # now have to use `tail`+`head` to skip the first few lines. (I'm sure there's a suitable regex, but this is 
          # easy to implement and follow)
          LEVEL=$(tail -n +3 phpstan.neon | head -n 10 | grep level | sed "s/[^0-9]*//")
          echo "level=$LEVEL" >> "$GITHUB_OUTPUT" 

      - name: Check success
        if: steps.run-phpstan.outcome == 'success'
        run: curl -o .github/phpstan.svg https://img.shields.io/badge/PHPStan-Level%20${{ steps.phpstan-level.outputs.level}}-2a5ea7.svg

      - name: Check failures
        if: steps.run-phpstan.outcome != 'success'
        run: curl -o .github/phpstan.svg https://img.shields.io/badge/PHPStan-Level%20${{ steps.phpstan-level.outputs.level}}❌-lightgrey.svg

      # This probably needs DEPLOY_KEY set for PRs and private repos
      - name: Commit README badge changes
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          file_pattern: ".github/phpstan.svg"
          commit_message: "🤖 PhpStan"


================================================
FILE: .github/workflows/release.yml
================================================
name: Build, tag and attach releases

on:
  release:
    types: [published]
  workflow_dispatch:

concurrency:
  # Cancel previous runs of this workflow if they are testing the same branch
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  create-phar:
    runs-on: ubuntu-latest
    name: Create Strauss phar on new release
    steps:
      - name: Resolve release tag
        id: resolve_release_tag
        uses: actions/github-script@v7
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          script: |
            let tagName = context.payload.release?.tag_name;

            if (!tagName) {
              try {
                const latestRelease = await github.rest.repos.getLatestRelease({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                });
                tagName = latestRelease.data.tag_name;
              } catch (error) {
                core.setFailed(`Unable to determine the latest published release tag: ${error.message}`);
                return;
              }
            }

            if (!tagName) {
              core.setFailed('Unable to determine a release tag for this workflow run.');
              return;
            }

            core.info(`Using release tag ${tagName}`);
            core.setOutput('tag', tagName);

      - name: Git checkout
        uses: actions/checkout@v6
        with:
          ref: ${{ steps.resolve_release_tag.outputs.tag }}

      - name: Install PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: 7.4
          tools: composer:v2
          extensions: fileinfo, gd

      - name: Install dependencies
        run: composer install --no-dev --prefer-dist --no-progress

      - name: "Edit `strauss/bin/strauss` to update the version number"
        env:
          CURRENT_RELEASE: ${{ steps.resolve_release_tag.outputs.tag }}
        run: |
          find bin -name 'strauss' -exec sed -i "s/}, '[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*');/}, '$CURRENT_RELEASE');/" {} +

      - name: Commit updated README.md
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          branch: master
          file_pattern: "bin/strauss"
          commit_message: "🤖 Update version number in bin"

      - name: Create .phar
        run: ./scripts/createphar.sh

      - name: Test run strauss
        run: php strauss.phar --version

      - name: Check version
        run: |
          TAG_NAME="${{ steps.resolve_release_tag.outputs.tag }}"
          CURRENT_VERSION="$(php strauss.phar --version | sed -e 's#^.\+ \([0-9.]\+\)$#\1#')"
          if [ "${TAG_NAME#v}" != "${CURRENT_VERSION}" ]; then
            echo "::error::Latest tag differs from current version"
            exit 10
          fi

      - name: Import GPG key
        uses: crazy-max/ghaction-import-gpg@v7
        with:
          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
          passphrase: ${{ secrets.PASSPHRASE }}

      # https://phar.io/howto/sign-and-upload-to-github.html
      # https://keys.openpgp.org/about/usage/
      # https://github.com/marketplace/actions/import-gpg
      # gpg --armor --export-secret-key BrianHenryIE@gmail.com | pbcopy
      # Specify exactly which key to export or it will export the first, expired key, and you will copy the wrong information to your secrets.
      # gpg --armor --export-secret-key BE6D3AB4AD637A11A26983AD3915D8F4028A0673 | pbcopy
      # TODO: command to pipe to gh CLI tool to set secret.
      - name: Check GPG key validity
        env:
          GPG_USER: ${{ secrets.GPG_USER }}
        run: |
          KEY_INFO="$(gpg --batch --list-secret-keys --with-colons "$GPG_USER" 2>/dev/null || true)"

          if [ -z "$KEY_INFO" ]; then
            echo "::error title=GPG key not available::Unable to find an imported secret GPG key for '$GPG_USER'."
            exit 1
          fi

          NOW="$(date +%s)"
          PARSED_KEY_INFO="$(printf '%s\n' "$KEY_INFO" | awk -F: -v now="$NOW" '
            $1=="sec" {
              total++;
              current_expiry=$7;
              current_valid=(current_expiry=="" || current_expiry=="0" || current_expiry>now);
              if (current_valid) {
                valid_total++;
              }
              next;
            }
            $1=="fpr" {
              if (current_valid && valid_fpr=="") {
                valid_fpr=$10;
                valid_expiry=current_expiry;
              }
              if (!current_valid && expired_fpr=="") {
                expired_fpr=$10;
                expired_expiry=current_expiry;
              }
              current_valid="";
              current_expiry="";
            }
            END {
              print "TOTAL_KEYS=" total+0;
              print "VALID_KEYS=" valid_total+0;
              print "KEY_FINGERPRINT=" valid_fpr;
              print "KEY_EXPIRY=" valid_expiry;
              print "EXPIRED_FINGERPRINT=" expired_fpr;
              print "EXPIRED_EXPIRY=" expired_expiry;
            }
          ')"

          TOTAL_KEYS="0"
          VALID_KEYS="0"
          KEY_FINGERPRINT=""
          KEY_EXPIRY=""
          EXPIRED_FINGERPRINT=""
          EXPIRED_EXPIRY=""
          while IFS='=' read -r PARSED_KEY PARSED_VALUE; do
            case "$PARSED_KEY" in
              TOTAL_KEYS) TOTAL_KEYS="$PARSED_VALUE" ;;
              VALID_KEYS) VALID_KEYS="$PARSED_VALUE" ;;
              KEY_FINGERPRINT) KEY_FINGERPRINT="$PARSED_VALUE" ;;
              KEY_EXPIRY) KEY_EXPIRY="$PARSED_VALUE" ;;
              EXPIRED_FINGERPRINT) EXPIRED_FINGERPRINT="$PARSED_VALUE" ;;
              EXPIRED_EXPIRY) EXPIRED_EXPIRY="$PARSED_VALUE" ;;
            esac
          done <<< "$PARSED_KEY_INFO"

          if [ "$TOTAL_KEYS" -eq 0 ]; then
            echo "::error title=GPG key not available::Unable to find an imported secret GPG key for '$GPG_USER'."
            exit 1
          fi

          if [ -z "$KEY_FINGERPRINT" ]; then
            if [ -n "$EXPIRED_EXPIRY" ] && [ "$EXPIRED_EXPIRY" != "0" ]; then
              EXPIRES_AT="$(date -u -d "@$EXPIRED_EXPIRY" '+%Y-%m-%d %H:%M:%S UTC')"
              echo "::error title=GPG key expired::Found $TOTAL_KEYS matching key(s) for '$GPG_USER', but all are expired (for example: $EXPIRED_FINGERPRINT expired on $EXPIRES_AT)."
            else
              echo "::error title=Unable to inspect imported GPG key::Found $TOTAL_KEYS matching key(s) for '$GPG_USER', but none could be validated for signing."
            fi
            echo "Rotate the signing key, update GPG_PRIVATE_KEY / GPG_USER / PASSPHRASE secrets, and rerun this workflow."
            echo "PHAR signing guide: https://phar.io/howto/sign-and-upload-to-github.html"
            echo "OpenPGP key publishing guide: https://keys.openpgp.org/about/usage/"
            exit 1
          fi

          if [ -n "$KEY_EXPIRY" ] && [ "$KEY_EXPIRY" != "0" ]; then
            if [ "$KEY_EXPIRY" -le "$NOW" ]; then
              EXPIRES_AT="$(date -u -d "@$KEY_EXPIRY" '+%Y-%m-%d %H:%M:%S UTC')"

              echo "::error title=GPG key expired::The imported GPG signing key $KEY_FINGERPRINT expired on $EXPIRES_AT."
              echo "Rotate the signing key, update GPG_PRIVATE_KEY / GPG_USER / PASSPHRASE secrets, and rerun this workflow."
              echo "PHAR signing guide: https://phar.io/howto/sign-and-upload-to-github.html"
              echo "OpenPGP key publishing guide: https://keys.openpgp.org/about/usage/"
              exit 1
            fi
          fi

          echo "SIGNING_KEY_FINGERPRINT=$KEY_FINGERPRINT" >> "$GITHUB_ENV"
          echo "Imported $TOTAL_KEYS matching key(s); using non-expired key $KEY_FINGERPRINT for signing."

      - name: Sign the PHAR
        run: |
          ls strauss.phar
          gpg --local-user ${{ secrets.GPG_USER }} \
              --batch \
              --yes \
              --passphrase="${{ secrets.PASSPHRASE }}" \
              --detach-sign \
              --output strauss.phar.asc \
              strauss.phar

      - uses: meeDamian/github-release@2.0
        with:
          tag: ${{ steps.resolve_release_tag.outputs.tag }}
          token: ${{ secrets.GITHUB_TOKEN }}
          files: |
            strauss.phar
            strauss.phar.asc
          gzip: false
          allow_override: true


================================================
FILE: .github/workflows/updateversionfromchangelog.yml
================================================
# When a new version number is added to the changelog, update the bin.

name: Update version from changelog

on:
  push:
    branches:
      - master
    paths:
      - 'CHANGELOG.md'

concurrency:
  # Cancel previous runs of this workflow if they are testing the same branch
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  update-version:
    runs-on: ubuntu-latest
    name: Create Strauss phar on new release
    steps:
      - name: Git checkout
        uses: actions/checkout@v6
        with:
          ref: master

      - name: "Edit `strauss/bin/strauss` to update the version number"
        run: |
          CURRENT_RELEASE=$(cat CHANGELOG.md | grep --max-count=1 -o '##.*' | awk '{print $2}')
          find bin -name 'strauss' -exec sed -i "s/}, '[[:digit:]]*\.[[:digit:]]*\.[[:digit:]]*');/}, '$CURRENT_RELEASE');/" {} +

      - name: Commit updated README.md
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          branch: master
          file_pattern: "bin/strauss"
          commit_message: "🤖 Update version number in bin"


================================================
FILE: .gitignore
================================================
.idea/
vendor/

.DS_Store
composer.lock
.phpunit.result.cache

*.phar

tests/_reports

temptestdir
build
scratch

# GitHub Actions
pcov.sh
xdebug.sh
7.4linux.sh
scripts/builtins.php
/tools

/teststempdir


================================================
FILE: .phive/phars.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="brianhenryie/php-diff-test" version="^0.8.1" installed="0.8.1" location="./tools/php-diff-test" copy="true"/>
  <phar name="phpcov" version="^10.0.1" installed="10.0.1" location="./tools/phpcov" copy="true"/>
</phive>


================================================
FILE: .typos.toml
================================================
[files]
extend-exclude = [
    ".git/",
    "tests/Issues/data/",
    "/src/Pipeline/FileSymbol/builtinsymbols.php",
]
ignore-hidden = false

[default]
extend-ignore-re = [
    "ComposerAutoloaderInit[0-9a-f]+",
]

[default.extend-identifiers]
# Typos
"Github" = "GitHub"
"Wordpress" = "WordPress"


================================================
FILE: CHANGELOG.md
================================================
# Change Log

## 0.27.2 April 2025

* Fix: over-eager cleanup – preserve vendor autoload entries for `exclude_from_copy` packages
* Fix: GPG key had expired causing release assets to be unavailable

## 0.27.1 April 2025

## 0.27.0 March 2025

## 0.26.5 February 2025

## 0.26.4 January 2025

## 0.26.3 December 2025

* Refactoring
* PHPStan fixes

## 0.26.2 November 2025

* Fix: namespaces not updated in non-autoloaded files

## 0.26.1 November 2025

* Fix: implicitly nullable warning
* Refactor: Split `exclude_from_prefixing` code from `AutoloadedFilesEnumerator` to `MarkSymbolsForRenaming` to fix bug
* Dev: Add scripts `analyze-changes`, `cs-changes-strict`...

## 0.26.0 November 2025

* Add: `include_root_autoload` option
* Fix: `preg_match(): Delimiter must not be alphanumeric or backslash for exclude regexp patterns`
* Fix: Mute "File does not exist" for directories (that don't matter)
* Fix: `vendor-prefixed/composer/autoload_classmap.php` for packages not directly included

## 0.25.0 November 2025

* Copy all files from packages (previously only copied autoloaded files)

## 0.24.1 August 2025

* Fix: inadvertently removing autoload keys from `installed.json` when `target_directory` is not `vendor-prefixed`
* Fix: double-prefixing case
* Fix: `exclude_from_prefix` config option not working correctly
* Fix: only update a _class extends_ namespace if it is global 
* Fix: log message replacement in `InstalledJson::cleanTargetDirInstalledJson()`
* Dependencies: use `conflict` to allow newer jsonmapper versions
* Release: update `.editorconfig` 
* Slightly better logging
* [...more](https://github.com/BrianHenryIE/strauss/compare/0.24.0...0.24.1)

## 0.24.0 July 2025

* Add: `functions_prefix` string|false config option
* Fix: Don't use the root `composer.json`'s autoload key when generating the `vendor-prefixed` autoloader

## 0.23.0 July 2025

* Add: use `COMPOSER=custom.json` environmental variable
* Fix: namespaced function aliasing
* Dependency: `simple-php-code-parser` `^0.15.3`

## 0.22.6 June 2025

* Fix: Use monolog (to avoid implementing `LoggerInterface`)
* Fix: prefixing of constants

## 0.22.5 June 2025

* Fix: Reliable prefixing of global functions
* Fix: FQDN namespaces not correctly prefxied
* Fix: Namespaces with no classes not in the direct namespace not working with psr-4
* Fix vendor autoloader dev entries when target is vendor

## 0.22.4 June 2025

* Require `simple-php-code-parser` `^0.15.1`

## 0.22.3 June 2025

* Filter 'implements' nodes on FullyQualified + add issue test
* Exclude directories from license copy step
* Add spelling to main workflow
* Use `"elazar/flystream": "^0.5.0|^1"`
* Fix spelling
* Filter `performReplacementsInProjectFiles()` to only PHP files
* Add `file_exists()` check in edited `vendor/autoload.php`
* Fix Double slashes when replacing namespace in use keywords inside classes
* Fix Fatal error: Uncaught Error: Failed opening required 'vendor_prefixed'
* Fix Command "include-autoloader" is not defined
* Fix/close Mockery
* Add `extends Composer\Autoload\AutoloadGenerator`
* Don't use dir as file

## 0.22.2 April 2025

* Fix: `psr-0` autoloaders were no longer autoloaded because the directory structure did not match
* Fix: `files` autoloaders failed when not unique (the whole point of this tool)
* Fix: spelling

## 0.22.1 April 2025

* Fix: jsonmapper latest version caused problems with PhpDoc

## 0.22.0 April 2025

* Add: `--info`, `--debug` and `--silent` verbosity levels
* Add: `--dry-run` which runs with `--debug` output but does not write files
* Add: `autoload_aliases.php` file for dev dependencies to load modified classes using their original fqdn
* Fix: relative namespaces
* Fix: allow vendor and target directories to be in parent directory of `composer.json`
* Fix: incorrectly updating call sites
* Dev: major refactor to use `thephpleague/Flysystem` and `elazar/flystream` for file operations
* Dev: print diff code coverage report on PRs
* Dev: skip / speed-up some tests
* Dev: improvements to tests' names and coverage reporting specificity 
* Docs: improve installation instructions in `README.md` 
* CI: Set up problem matcher for PHPUnit

## 0.21.1 January 2025

* Fix: global functions prefixed too liberally when defined as strings
* Add: include changelog in phar

## 0.21.0 January 2025

* Add: prefix global functions

## 0.20.1 December 2024

* Fix: `vendor-prefixed` subdirectories' permissions being copied as 0700 instead of 0755

## 0.20.0 November 2024

* Fix: `Generic<\namespaced\class-type>` not prefixed
* Add `strauss replace` command (e.g. if you fork a project and want to change its namespace)

## 0.19.5 October 2024

* Fix: `use GlobalClass as Alias;` not prefixed
* Add: `.gitattributes` file to exclude dev files from distribution
* CI: Fail releases if `bin/strauss` version number is out of sync
* Tests: Add first tests for `DiscoveredFiles.php`
* Improve `README.md`
* Fix: typos in code

## 0.19.4 October 2024

* Fix: out of sync version number in `bin/strauss`

## 0.19.3 October 2024

* Fix: handle `@` symbol for error suppression
* Fix: handle `preg_replace...` returning `null` in `Licenser`
* Fix: only search for symbols in PHP files

## 0.19.2 June 2024

* Fix: available CLI arguments were overwriting extra.strauss config
* Fix: updating `league/flysystem` changed the default directory permissions

## 0.19.1 April 2024

* Fix: was incorrectly deleting autoload keys from installed.json

## 0.19.0 April 2024

* Fix: check for array before loop
* Fix: filepaths on Windows (still work to do for Windows)
* Update: tidy `bin/strauss`
* Run tests with project classes + with built phar
* Allow `symfony/console` & `symfony/finder` `^7` for Laravel 11 compatibility
* Add: `scripts/createphar.sh`
* Lint: most PhpStan level 7

## 0.18.0 April 2024

* Add: GitHub Action to update bin version number from CHANGELOG.md
* Fix: casting a namespaced class to a string
* Fix: composer dump-autoload error after delete-vendor-files/delete-vendor-packages
* Fix: add missing built-in PHP interfaces to exclude rules
* Fix: Undefined offset when seeing namespace
* Refactoring for clarity and pending issues

## 0.14.0 07-March-2023

* Merge `in-situ` branch (bugs expected)
* Add: `delete_vendor_packages` option (`delete_vendor_files` is maybe deprecated now)
* Add: GPG .phar signing for Phive
* Breaking: Stop excluding `psr/*` from `file_patterns` prefixing


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) Coen Jacobs <coenjacobs@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
[![PHPUnit ](.github/coverage.svg)](https://brianhenryie.github.io/strauss/) [![PHPStan ](.github/phpstan.svg)](https://phpstan.org/)

# Strauss – PHP Namespace Renamer

A tool to prefix namespaces, classnames, and constants in PHP files to avoid autoloading collisions.

A fork of [Mozart](https://github.com/coenjacobs/mozart/) for [Composer](https://getcomposer.org/) for PHP.

Have you ever activated a WordPress plugin that has a conflict with another because the plugins use two different versions of the same PHP library? **Strauss is the solution to that problem** - it ensures that _your_ plugin's PHP dependencies are isolated and loaded from your plugin rather than loading from whichever plugin's autoloader registers & runs first.

> ⚠️ **Sponsorship**: It would be neat if you were to offer me a license to your plugin, or at least [post about where this is used](https://github.com/BrianHenryIE/strauss/discussions).

## Table of Contents

* [Installation](#installation)
    * [As a `.phar` file](#as-a-phar-file-recommended) (recommended)
    * [As a dev dependency via composer](#as-a-dev-dependency-via-composer-not-recommended)  (not recommended)
    * [Edit `composer.json` scripts](#edit-composerjson-scripts)
* [Usage](#usage)
* [Configuration](#configuration)
* [Autoloading](#autoloading)
* [Motivation & Comparison to Mozart](#motivation--comparison-to-mozart)
* [Alternatives](#alternatives)
* [Breaking Changes](#breaking-changes)
* [Acknowledgements](#acknowledgements)

## Installation

### As a `.phar` file (recommended)

There are a couple of small steps to make this possible.

#### Create a `bin/.gitkeep` file

This ensures that there is a `bin/` directory in the root of your project. This is where the `.phar` file will go.

```bash
mkdir bin
touch bin/.gitkeep
```

#### `.gitignore` the `.phar` file

Add the following to your `.gitignore`:

```bash
bin/strauss.phar
```

#### Edit `composer.json` `scripts

In your `composer.json`, add `strauss` to the `scripts` section:

```json
"scripts": {
    "prefix-namespaces": [
        "sh -c 'test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/latest/download/strauss.phar'",
        "@php bin/strauss.phar",
        "@composer dump-autoload"
    ],
    "post-install-cmd": [
        "@prefix-namespaces"
    ],
    "post-update-cmd": [
        "@prefix-namespaces"
    ],
    "post-autoload-dump": [
        "@php bin/strauss.phar include-autoloader"
    ]
}
```

This provides `composer strauss`, which does the following:

1. The `sh -c` command tests if `bin/strauss.phar` exists, and if not, downloads it from [releases](https://github.com/BrianHenryIE/strauss/releases).
2. Then `@php bin/strauss.phar` is run to prefix the namespaces.
3. Ensure that composer's autoload map is updated.

### As a dev dependency via composer (not recommended)

If you prefer to include Strauss as a dev dependency, you can still do so. You mileage may vary when you include it this way.

```
composer require --dev brianhenryie/strauss
```

#### Edit `composer.json` `scripts

```json
"scripts": {
    "prefix-namespaces": [
        "strauss",
        "@php composer dump-autoload"
    ],
    "post-install-cmd": [
        "@prefix-namespaces"
    ],
    "post-update-cmd": [
        "@prefix-namespaces"
    ],
    "post-autoload-dump": [
        "strauss include-autoloader"
    ]
}
```

## Usage

If you add Strauss to your `composer.json` as indicated in [Installation](#installation), it will run when you `composer install` or `composer update`. To run Strauss directly, simply use:

```bash
composer prefix-namespaces
```

To update the files that call the prefixed classes, you can use `--updateCallSites=true` which uses your autoload key, or `--updateCallSites=includes,templates` to explicitly specify the files and directories.

```bash
composer -- prefix-namespaces --updateCallSites=true
```

or

```bash
composer -- prefix-namespaces --updateCallSites=includes,templates
```

To try it out without making changes, you can use the `--dry-run` flag:

<details>

<summary>strauss --dry-run</summary>

![](.github/strauss.mp4)

</details>

Verbosity can be controlled with `--notice` (default), `--info`, `--debug` and `--silent`.

## Configuration

Strauss potentially requires zero configuration, but likely you'll want to customize a little, by adding in your `composer.json` an `extra/strauss` object. The following is the default config, where the `namespace_prefix` and `classmap_prefix` are determined from your `composer.json`'s `autoload` or `name` key and `packages` is determined from the `require` key:

```json
"extra": {
    "strauss": {
        "target_directory": "vendor-prefixed",
        "namespace_prefix": "BrianHenryIE\\My_Project\\",
        "classmap_prefix": "BrianHenryIE_My_Project_",
        "constant_prefix": "BHMP_",
        "packages": [
        ],
        "update_call_sites": false,
        "include_root_autoload": false,
        "optimize_autoloader": true,
        "override_autoload": {
        },
        "exclude_from_copy": {
            "packages": [
            ],
            "namespaces": [
            ],
            "file_patterns": [
            ]
        },
        "exclude_from_prefix": {
            "packages": [
            ],
            "namespaces": [
            ],
            "file_patterns": [
            ]
        },
        "exclude_constants": {
            "packages": [
            ],
            "namespaces": [
            ],
            "file_patterns": [
            ],
            "constants": [
            ]
        },
        "namespace_replacement_patterns" : {
        },
        "delete_vendor_packages": false,
        "delete_vendor_files": false
    }
},
```

The following configuration is inferred:

- `target_directory` defines the directory the files will be copied to, default `vendor-prefixed`
- `namespace_prefix` defines the default string to prefix each namespace with
- `classmap_prefix` defines the default string to prefix class names in the global namespace
- `packages` is the list of packages to process. If absent, all packages in the `require` key of your `composer.json` are included
- `classmap_output` is a `bool` to decide if Strauss will create `autoload-classmap.php` and `autoload.php`. If it is not set, it is `false` if `target_directory` is in your project's `autoload` key, `true` otherwise.

The following configuration is default:

- `delete_vendor_packages`: `false` a boolean flag to indicate if the packages' vendor directories should be deleted after being processed. It defaults to false, so any destructive change is opt-in.
- `delete_vendor_files`: `false` a boolean flag to indicate if files copied from the packages' vendor directories should be deleted after being processed. It defaults to false, so any destructive change is opt-in. This is maybe deprecated! Is there any use to this that is more appropriate than `delete_vendor_packages`?
- `include_modified_date` is a `bool` to decide if Strauss should include a date in the (phpdoc) header written to modified files. Defaults to `true`.
- `include_author` is a `bool` to decide if Strauss should include the author name in the (phpdoc) header written to modified files. Defaults to `true`.
- `update_call_sites`: `false`. This can be `true`, `false` or an `array` of directories/filepaths. When set to `true` it defaults to the directories and files in the project's `autoload` key. The PHP files and directories' PHP files will be updated where they call the prefixed classes.
- `include_root_autoload`: `false` is a boolean flag to indicate whether Strauss should include the root autoload section of your project when creating its autoloader. It is false by default. Enabling this option will allow you to require only the Strauss autoloader in your project. Note that conflicts may occur if your project enables this option, requires both the Composer and Strauss autoloaders, and uses `files` autoloading.
- `optimize_autoloader`: `true` is a boolean flag to indicate whether Strauss should force optimized/classmap-authoritative autoload generation. Set it to `false` to still regenerate autoload files without authoritative mode.

To disable optimized/classmap-authoritative Composer autoload generation:

```json
{
  "extra": {
    "strauss": {
      "optimize_autoloader": false
    }
  }
}
```

The remainder is empty:

- `constant_prefix` is for `define( "A_CONSTANT", value );` -> `define( "MY_PREFIX_A_CONSTANT", value );`. If it is empty, constants are not prefixed (this may change to an inferred value).
- `override_autoload` a dictionary, keyed with the package names, of autoload settings to replace those in the original packages' `composer.json` `autoload` property.
- `exclude_from_prefix` / [`file_patterns`](https://github.com/BrianHenryIE/strauss/blob/83484b79cfaa399bba55af0bf4569c24d6eb169d/src/ChangeEnumerator.php#L92-L96)
- `exclude_from_copy`
  - [`packages`](https://github.com/BrianHenryIE/strauss/blob/83484b79cfaa399bba55af0bf4569c24d6eb169d/src/FileEnumerator.php#L77-L79) array of package names to be skipped
  - [`namespaces`](https://github.com/BrianHenryIE/strauss/blob/83484b79cfaa399bba55af0bf4569c24d6eb169d/src/FileEnumerator.php#L95-L97) array of namespaces to skip (exact match from the package autoload keys)
  - [`file_patterns`](https://github.com/BrianHenryIE/strauss/blob/83484b79cfaa399bba55af0bf4569c24d6eb169d/src/FileEnumerator.php#L133-L137) array of regex patterns to check filenames against (including vendor relative path) where Strauss will skip that file if there is a match
- `exclude_from_prefix`
  - [`packages`](https://github.com/BrianHenryIE/strauss/blob/83484b79cfaa399bba55af0bf4569c24d6eb169d/src/ChangeEnumerator.php#L86-L90) array of package names to exclude from prefixing.
  - [`namespaces`](https://github.com/BrianHenryIE/strauss/blob/83484b79cfaa399bba55af0bf4569c24d6eb169d/src/ChangeEnumerator.php#L177-L181) array of exact match namespaces to exclude (i.e. not substring/parent namespaces)
- `exclude_constants` – same shape as `exclude_from_prefix`, but applies only to constants (e.g. from `define()` or `const`). Use to avoid prefixing runtime constants like `WP_PLUGIN_DIR`, `ABSPATH`.
  - `packages` array of package names whose constants are not prefixed
  - `namespaces` array of namespaces (prefix match) whose constants are not prefixed
  - `file_patterns` array of regex patterns for file paths
  - `constants` array of constant names to never prefix (e.g. `["WP_PLUGIN_DIR", "ABSPATH"]`)
- [`namespace_replacement_patterns`](https://github.com/BrianHenryIE/strauss/blob/83484b79cfaa399bba55af0bf4569c24d6eb169d/src/ChangeEnumerator.php#L183-L190) a dictionary to use in `preg_replace` instead of prefixing with `namespace_prefix`.

## Autoloading

Strauss uses Composer's own tools to generate a set of autoload files in the `target_directory` and creates an `autoload.php` alongside it, so in many projects autoloading is just a matter of:

```php
require_once __DIR__ . '/vendor-prefixed/autoload.php';
```

If you plan to continue using Composer's autoloader you probably want to turn on `delete_vendor_packages` or set `target_directory` to `vendor`.

You can use `strauss include-autoloader` to add a line to `vendor/autoload.php` which includes the autoloader for the new files.

If you don't plan to use Composer's autoloader, you may wish to enable `include_root_autoload` so that the Strauss autoloader includes the autoload for your project.

When `delete_vendor_packages` is enabled, `vendor/composer/autoload_aliases.php` is created to allow modified classes to be loaded with their old name during development. This file should not be included in your production code.

## Motivation & Comparison to Mozart

I was happy to make PRs to Mozart to fix bugs, but they weren't being reviewed and merged. At the time of writing, somewhere approaching 50% of Mozart's code [was written by me](https://github.com/coenjacobs/mozart/graphs/contributors) with an additional [nine open PRs](https://github.com/coenjacobs/mozart/pulls?q=is%3Apr+author%3ABrianHenryIE+) and the majority of issues' solutions [provided by me](https://github.com/coenjacobs/mozart/issues?q=is%3Aissue+). This fork is a means to merge all outstanding bugfixes I've written and make some more drastic changes I see as a better approach to the problem.

Benefits over Mozart:

* A single output directory whose structure matches source vendor directory structure (conceptually easier than Mozart's independent `classmap_directory` and `dep_directory`)
* A generated `autoload.php` to `include` in your project (analogous to Composer's `vendor/autoload.php`)
* Handles `files` autoloaders – and any autoloaders that Composer itself recognises, since Strauss uses Composer's own tooling to parse the packages
* Zero configuration – Strauss infers sensible defaults from your `composer.json`
* No destructive defaults – `delete_vendor_files` defaults to `false`, so any destruction is explicitly opt-in
* Licence files are included and PHP file headers are edited to adhere to licence requirements around modifications. My understanding is that re-distributing code that Mozart has handled is non-compliant with most open source licences – illegal!
* Extensively tested – PhpUnit tests have been written to validate that many of Mozart's bugs are not present in Strauss
* More configuration options – allowing exclusions in copying and editing files, and allowing specific/multiple namespace renaming
* Respects `composer.json` `vendor-dir` configuration
* Prefixes constants (`define`)
* Handles meta-packages and virtual-packages

Strauss will read the Mozart configuration from your `composer.json` to enable a seamless migration.

## Alternatives

I don't have a strong opinion on these. I began using Mozart because it was easy, then I adapted it to what I felt was most natural. I've never used these.

* [humbug/php-scoper](https://github.com/humbug/php-scoper)
* [TypistTech/imposter-plugin](https://github.com/TypistTech/imposter-plugin)
* [Automattic/jetpack-autoloader](https://github.com/Automattic/jetpack-autoloader)
* [tschallacka/wordpress-composer-plugin-builder](https://github.com/tschallacka/wordpress-composer-plugin-builder)
* [Interfacelab/namespacer](https://github.com/Interfacelab/namespacer)
* [PHP-Prefixer](https://github.com/PHP-Prefixer) SaaS!

### Interesting

* [composer-unused/composer-unused](https://github.com/composer-unused/composer-unused)
* [sdrobov/autopsr4](https://github.com/sdrobov/autopsr4)
* [jaem3l/unfuck](https://github.com/jaem3l/unfuck)
* [bamarni/composer-bin-plugin](https://github.com/bamarni/composer-bin-plugin)
* [phar-io/composer-distributor](https://github.com/phar-io/composer-distributor)

## Breaking Changes

* v0.25.0 – will copy all files from a package to the target directory
* v0.21.0 – will prefix global functions
* v0.16.0 – will no longer prefix PHP built-in classes seen in polyfill packages
* v0.14.0 – `psr/*` packages no longer excluded by default
* v0.12.0 – default output `target_directory` changes from `strauss` to `vendor-prefixed`

Please open issues to suggest possible breaking changes. I think we can probably move to 1.0.0 soon.

### Backward Compatibility Promise

This project will not increase its minimum required PHP version ahead of WordPress.

https://core.trac.wordpress.org/ticket/62622

## Changes before v1.0

* Comprehensive attribution of code forked from Mozart – changes have been drastic and `git blame` is now useless, so I intend to add more attributions
* More consistent naming. Are we prefixing or are we renaming?
* Further unit tests, particularly file-system related
* Regex patterns in config need to be validated
* Change the name? "Renamespacer"?

## Changes before v2.0

The correct approach to this problem is probably via [PHP-Parser](https://github.com/nikic/PHP-Parser/). At least all the tests will be useful.

## Acknowledgements

[Coen Jacobs](https://github.com/coenjacobs/) and all the [contributors to Mozart](https://github.com/coenjacobs/mozart/graphs/contributors), particularly those who wrote nice issues.


================================================
FILE: bin/strauss
================================================
#!/usr/bin/env php
<?php
call_user_func(function ($version) {
    $autoloaders = Phar::running() === ''
        ? [
            __DIR__ . '/../../autoload.php',     // Relative path from vendor/brianhenryie/strauss/bin/strauss to vendor/autoload.php.
            __DIR__ . '/../autoload.php',        // Relative path from vendor/bin/strauss to vendor/autoload.php.
            __DIR__ . '/../vendor/autoload.php', // Relative path from bin/strauss to vendor/autoload.php.
            getcwd() . '/vendor/autoload.php',
            getcwd() . '/../../autoload.php',
            __DIR__ . '/../../../autoload.php',  // I don't know if these last three are necessary.
        ]
        : [
            __DIR__ . '/../vendor/autoload.php', // Inside phar.
        ];

    foreach ($autoloaders as $autoloader) {
        if (!is_file($autoloader)) {
            continue;
        }
        require $autoloader;
        break;
    }

    if (!class_exists(BrianHenryIE\Strauss\Console\Application::class)) {
        fwrite(STDERR,
            'You must set up the project dependencies, run the following commands:' . PHP_EOL
            . 'curl -s https://getcomposer.org/installer | php' . PHP_EOL
            . 'php composer.phar install' . PHP_EOL
        );
        exit(1);
    }

    $app = new BrianHenryIE\Strauss\Console\Application($version);
    $app->run();
}, '0.27.2');


================================================
FILE: bootstrap.php
================================================
<?php
/**
 * When strauss is installed via Composer, this will help load the aliases file.
 *
 * When `composer install --no-dev` is run, Strauss won't be installed and this file won't exist to load
 * `autoload_aliases.php`. This is good – we don't want to load the aliases file in production or we end up
 * fixing the namespace collision issue for ourselves but preserving it for other packages.
 *
 * This file tries to read the project composer.json file to find the target directory. If it can't find it, it
 * assumes the default "vendor-prefixed".
 *
 * @package brianhenryie/strauss
 */

$autoloadAliasesFilepath = realpath(__DIR__ . '/../../composer/autoload_aliases.php');
if (file_exists($autoloadAliasesFilepath)) {
    $targetDirectoryFromComposerExtra = function () {
        $composerJsonFilepath = realpath(__DIR__ . '/../../../composer.json');
        if (file_exists($composerJsonFilepath)) {
            $composerJson = json_decode(file_get_contents($composerJsonFilepath), true);
            if (isset($composerJson['extra']['strauss']['target_directory'])
                &&
                is_dir(realpath(__DIR__ . '/../../../'.$composerJson['extra']['strauss']['target_directory']))
            ) {
                return $composerJson['extra']['strauss']['target_directory'];
            }
        }
        return null;
    };

    $autoloadTargetFilepath = sprintf(
        "%s/%s/autoload.php",
        getcwd(),
        $targetDirectoryFromComposerExtra() ?? "vendor-prefixed"
    );
    if ($autoloadTargetFilepath !== realpath(__DIR__ . '/../../autoload.php') && file_exists($autoloadTargetFilepath)) {
        require_once $autoloadTargetFilepath;
    }
    unset($autoloadTargetFilepath);

    require_once $autoloadAliasesFilepath;
}
unset($autoloadAliasesFilepath,);


================================================
FILE: composer.json
================================================
{
    "name": "brianhenryie/strauss",
    "description": "Prefixes dependencies namespaces so they are unique to your plugin",
    "authors": [
        {
            "name": "Brian Henry",
            "email": "BrianHenryIE@gmail.com"
        },
        {
            "name": "Coen Jacobs",
            "email": "coenjacobs@gmail.com"
        }
    ],
    "bin": ["bin/strauss"],
    "minimum-stability": "dev",
    "prefer-stable": true,
    "license": "MIT",
    "require": {
        "ext-json": "*",
        "brianhenryie/simple-php-code-parser": "^0.15.3",
        "composer-runtime-api": "^2.0",
        "composer/class-map-generator": "^1.6.0",
        "composer/composer": "^2.6.0",
        "elazar/flystream": "^0.5.0|^1",
        "json-mapper/json-mapper": "^2.0.0",
        "league/flysystem": "^2.1|^3.0",
        "league/flysystem-memory": "*",
        "monolog/monolog": "^2.10",
        "nikic/php-parser": "^5.4.0",
        "symfony/console": "^4|^5|^6|^7",
        "symfony/finder": "^4|^5|^6|^7"
    },
    "autoload": {
        "psr-4": {
            "BrianHenryIE\\Strauss\\": "src/"
        },
        "files": [
            "bootstrap.php"
        ]
    },
    "autoload-dev": {
        "psr-4": {
            "BrianHenryIE\\Strauss\\Tests\\": "tests/",
            "BrianHenryIE\\Strauss\\": [
                "tests/",
                "tests/Integration",
                "tests/Unit"
            ]
        },
        "classmap": [
            "tests"
        ]
    },
    "require-dev": {
        "php": "^7.4|^8.0",
        "brianhenryie/color-logger": "*",
        "brianhenryie/php-codecoverage-markdown": "^0.1.0",
        "clue/phar-composer": "^1.4",
        "jaschilz/php-coverage-badger": "^2.0",
        "mockery/mockery": "^1.6",
        "phpstan/extension-installer": "^1.4",
        "phpstan/phpstan": "^1.10",
        "phpstan/phpstan-mockery": "^1.1",
        "phpunit/phpcov": "*",
        "phpunit/phpunit": "^9|^10",
        "squizlabs/php_codesniffer": "^3.5"
    },
    "conflict": {
      "json-mapper/json-mapper": "2.23.0 | 2.24.0"
    },
    "scripts": {
        "post-install-cmd": [
        ],
        "post-update-cmd": [
        ],
        "analyze": [
          "phpstan analyse --memory-limit=-1 --verbose"
        ],
        "analyze-changes": [
          "updated_files=$(echo $(git diff --name-only `git merge-base origin/master HEAD` | grep php | tr '\\n' '\\0' | xargs -0 ls -1df 2>/dev/null)); if [ -n \"$updated_files\" ]; then phpstan analyse --memory-limit=-1 $updated_files --verbose || true; else echo \"No modified php files for phpstan.\"; fi;"
        ],
        "analyze-changes-strict": [
          "updated_files=$(echo $(git diff --name-only `git merge-base origin/master HEAD` | grep php | tr '\\n' '\\0' | xargs -0 ls -1df 2>/dev/null)); if [ -n \"$updated_files\" ]; then echo \"Found: $updated_files\"; phpstan analyse --memory-limit=-1 $updated_files --level max --verbose || true; else echo \"No modified php files for phpstan.\"; fi;"
        ],
        "cs": [
          "phpcs || true",
          "@analyze"
        ],
        "cs-fix": [
          "phpcbf || true",
          "phpcs || true",
          "@analyze"
        ],
        "cs-changes": [
          "updated_files=$(echo $(git diff --name-only `git merge-base origin/master HEAD` | grep php | tr '\\n' '\\0' | xargs -0 ls -1df 2>/dev/null)); if [ -n \"$updated_files\" ]; then phpcbf $updated_files || true; phpcs $updated_files || true; else echo \"No modified php files.\"; fi;",
          "@analyze-changes"
        ],
        "cs-changes-strict": [
          "updated_files=$(echo $(git diff --name-only `git merge-base origin/master HEAD` | grep php | tr '\\n' '\\0' | xargs -0 ls -1df 2>/dev/null)); if [ -n \"$updated_files\" ]; then phpcbf $updated_files || true; phpcs $updated_files || true; else echo \"No modified php files.\"; fi;",
          "@analyze-changes-strict"
        ],
        "install-phive-dependencies": [
            "if [ -z \"$(command -v phive)\" ]; then echo \"Phive is not installed. Run 'brew install gpg phive' or see https://phar.io/.\"; exit 1; fi;",
            "phive install"
        ],
        "test": [
            "Composer\\Config::disableProcessTimeout",
            "phpunit --stop-on-failure --order-by=random"
        ],
        "test-changes": [
            "if [ -z \"$(command -v ./tools/php-diff-test)\" ]; then echo \"Please install 'php-diff-test' with 'phive install'.\"; exit 1; fi;",
            "if [ \"$XDEBUG_MODE\" != \"coverage\" ]; then echo 'Run with XDEBUG_MODE=coverage composer test-changes'; exit 1; fi;",
            "phpunit --filter=\"$(./tools/php-diff-test filter --input-files tests/_reports/php.cov --granularity=line)\" --coverage-text;"
        ],
        "test-changes-report": [
            "if [ -z \"$(command -v ./tools/php-diff-test)\" ]; then echo \"Please install 'php-diff-test' with 'phive install'.\"; exit 1; fi;",
            "if [ -z \"$(command -v ./tools/phpcov)\" ]; then echo \"Please install 'phpcov' with 'phive install'.\"; exit 1; fi;",
            "if [ \"$XDEBUG_MODE\" != \"coverage\" ]; then echo 'Run with XDEBUG_MODE=coverage composer test-changes-report'; exit 1; fi;",
            "if [ -d \"tests/_reports/diff\" ]; then rm -rf tests/_reports/diff; fi;",
            "phpunit --filter=\"$(./tools/php-diff-test filter --input-files tests/_reports/php.cov --granularity file)\" --coverage-text --coverage-php tests/_reports/diff/php.cov -d memory_limit=-1;",
            "./tools/php-diff-test coverage --input-files tests/_reports/diff/php.cov --output-file tests/_reports/diff/php.cov;",
            "./tools/phpcov merge tests/_reports/diff --html tests/_reports/diff/html;",
            "open tests/_reports/diff/html/index.html"
        ],
        "test-coverage": [
            "Composer\\Config::disableProcessTimeout",
            "if [ \"$XDEBUG_MODE\" != \"coverage\" ]; then echo \"Run with 'XDEBUG_MODE=coverage composer test-coverage'\"; exit 1; fi;",
            "phpunit ./tests/Unit --coverage-text --coverage-clover tests/_reports/partial/unitclover.xml --coverage-php tests/_reports/partial/unitphp.cov -d memory_limit=-1 --order-by=random",
            "phpcov merge --clover tests/_reports/clover.xml --html tests/_reports/html tests/_reports/partial;",
            "php-coverage-badger tests/_reports/clover.xml .github/coverage.svg",
            "if [ $(command -v ./tools/phpcov) ]; then git diff master...head > /tmp/master.diff; ./tools/phpcov patch-coverage --path-prefix $(pwd) ./tests/_reports/php.cov /tmp/master.diff || true; fi;",
            "# Run 'open ./tests/_reports/html/index.html' to view report."
        ]
    },
    "scripts-descriptions": {
        "test-changes": "Run PHPUnit only on lines that have changed in master...HEAD",
        "test-changes-report": "Run PHPUnit only on files that have changed in master...HEAD and display the HTML report.",
        "test-coverage": "Run PHPUnit tests with coverage. Use 'XDEBUG_MODE=coverage composer test-coverage' to run, 'open ./tests/_reports/html/index.html' to view."
    },
    "replace":{
        "coenjacobs/mozart": "*"
    },
    "config": {
        "sort-packages": true,
        "allow-plugins": {
            "phpstan/extension-installer": true
        }
    }
}


================================================
FILE: phive.phar.asc
================================================
-----BEGIN PGP SIGNATURE-----

iQJBBAABCgArFiEEavclJwq4HgTXlEJUnYqYspstXXkFAmbHq+UNHHRlYW1AcGhh
ci5pbwAKCRCdipiymy1deRwWD/4oVUr8uQC5Zjr0rPEkJ5BwWRIpm5PZfhSP/jLC
vnL3TjtbLBy0/emJN69fUBa7oRYJX6x5Hil+P6i01COuLnvL+8ZItXT7ArYtgnJK
wo9+z/jQ+F5xGsBlWECdKGxt3RULpbjyss5mgPLY41WTX7Bts7uSCD9O2ur1hfjE
hJJjPnyhsX3zRS0rNe06SFovQYOItwKfucSjjOW04+XTdbol9Vayevi2M0ipaK16
8D8OquVxj4ZkXCaSQEz/2vQEb8sFJm4xAkaDNdpq2jSbDZ8Xmlklz39aBPu5TA0m
sol9fkAiRBF2ITtCdO61JLCv2Llt/IYSyu/ONYzvPD9FGD5OKkF/MV7yhf2bY8lA
1mzfY/UIzmiZ9Cy2p/SJFsi1Mc1xzex4PmOuwxULaRftKtztgLQMA9LvIJMDjpYu
Qr68SSIZ6pm3mzvmd7JUL0qgvDTWmKV1vIKSMMtXgqDkwuOcaLo+th7qxD5SpJhT
mAgnItWmtgRZolB+E2M2V4AMVNou4ydtQxSd4qD6fheXXNmED+2jayD5rSmPlnVm
oRMA1b1HIlz+zIZCYQo1XGrvkVxpfw0Zj4HfwObAnr+NE9JpH53OmZJ3vyqEwZhs
nkC1gip3cK3ZoajeSktK16TqZj9Bl5RDREvyFU2I0XKjxr+5QF5Y6oNEHCD0MH4M
2mGB3A==
=rU98
-----END PGP SIGNATURE-----


================================================
FILE: phpcs.xml
================================================
<?xml version="1.0"?>
<!--suppress XmlUnboundNsPrefix -->
<ruleset name="strauss">
    <description>Coding standard ruleset based on the PSR-2 coding standard.</description>
    <rule ref="PSR2">
        <exclude name="Generic.Files.LineLength.TooLong"/>
    </rule>
    <rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps">
        <exclude-pattern>*/tests/*</exclude-pattern>
    </rule>
    <file>./src</file>
    <file>./tests</file>
    <exclude-pattern>/tests/_reports/</exclude-pattern>
    <exclude-pattern>/tests/Issues/data</exclude-pattern>
</ruleset>

================================================
FILE: phpstan-baseline.neon
================================================
parameters:
	ignoreErrors:
		-
			message: "#^Parameter \\#1 \\$namespacePrefix of method BrianHenryIE\\\\Strauss\\\\Composer\\\\Extra\\\\StraussConfig\\:\\:setNamespacePrefix\\(\\) expects string, string\\|null given\\.$#"
			count: 3
			path: src/Composer/Extra/StraussConfig.php

		-
			message: "#^Parameter \\#1 \\$string of function rtrim expects string, string\\|null given\\.$#"
			count: 2
			path: src/Composer/Extra/StraussConfig.php

		-
			message: "#^Parameter \\#1 \\$string of function strtolower expects string, string\\|null given\\.$#"
			count: 1
			path: src/Composer/Extra/StraussConfig.php

		-
			message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#"
			count: 1
			path: src/Composer/Extra/StraussConfig.php

		-
			message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#"
			count: 5
			path: src/Composer/Extra/StraussConfig.php

		-
			message: "#^Cannot call method getOriginalSymbol\\(\\) on BrianHenryIE\\\\Strauss\\\\Types\\\\NamespaceSymbol\\|null\\.$#"
			count: 1
			path: src/Pipeline/Aliases/Aliases.php

		-
			message: "#^Cannot call method getReplacement\\(\\) on BrianHenryIE\\\\Strauss\\\\Types\\\\NamespaceSymbol\\|null\\.$#"
			count: 1
			path: src/Pipeline/Aliases/Aliases.php

		-
			message: "#^Cannot call method isChangedNamespace\\(\\) on BrianHenryIE\\\\Strauss\\\\Types\\\\NamespaceSymbol\\|null\\.$#"
			count: 2
			path: src/Pipeline/Aliases/Aliases.php

		-
			message: "#^Parameter \\#1 \\$namespace of method BrianHenryIE\\\\Strauss\\\\Types\\\\DiscoveredSymbols\\:\\:getNamespaceSymbolByString\\(\\) expects string, string\\|null given\\.$#"
			count: 2
			path: src/Pipeline/Aliases/Aliases.php

		-
			message: "#^Parameter \\#1 \\$search of function str_replace expects array\\|string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Aliases/Aliases.php

		-
			message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Aliases/Aliases.php

		-
			message: "#^Parameter \\#2 \\$string of function explode expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Aliases/Aliases.php

		-
			message: "#^Parameter \\#1 \\$projectUniqueString of class BrianHenryIE\\\\Strauss\\\\Pipeline\\\\Autoload\\\\ComposerAutoloadGenerator constructor expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Autoload/DumpAutoload.php

		-
			message: "#^Parameter \\#2 \\$contents of method BrianHenryIE\\\\Strauss\\\\Helpers\\\\FileSystem\\:\\:write\\(\\) expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Autoload/DumpAutoload.php

		-
			message: "#^Cannot access offset 'dev' on mixed\\.$#"
			count: 1
			path: src/Pipeline/Autoload/VendorComposerAutoload.php

		-
			message: "#^Parameter \\#1 \\$nodes of method PhpParser\\\\NodeTraverser\\:\\:traverse\\(\\) expects array\\<PhpParser\\\\Node\\>, array\\<PhpParser\\\\Node\\\\Stmt\\>\\|null given\\.$#"
			count: 2
			path: src/Pipeline/Autoload/VendorComposerAutoload.php

		-
			message: "#^Parameter \\#1 \\$value of class PhpParser\\\\Node\\\\Scalar\\\\String_ constructor expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Autoload/VendorComposerAutoload.php

		-
			message: "#^Parameter \\#1 \\$fromAbsoluteDirectory of method BrianHenryIE\\\\Strauss\\\\Helpers\\\\FileSystem\\:\\:getRelativePath\\(\\) expects string, string\\|null given\\.$#"
			count: 2
			path: src/Pipeline/AutoloadedFilesEnumerator.php

		-
			message: "#^Method BrianHenryIE\\\\Strauss\\\\Pipeline\\\\ChangeEnumerator\\:\\:determineNamespaceReplacement\\(\\) should return string but returns string\\|null\\.$#"
			count: 1
			path: src/Pipeline/ChangeEnumerator.php

		-
			message: "#^Parameter \\#1 \\$replacement of method BrianHenryIE\\\\Strauss\\\\Types\\\\DiscoveredSymbol\\:\\:setReplacement\\(\\) expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/ChangeEnumerator.php

		-
			message: "#^Parameter \\#1 \\$str of function preg_quote expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/ChangeEnumerator.php

		-
			message: "#^Parameter \\#2 \\$needle of function str_starts_with expects string, string\\|null given\\.$#"
			count: 2
			path: src/Pipeline/ChangeEnumerator.php

		-
			message: "#^Parameter \\#1 \\$location of method BrianHenryIE\\\\Strauss\\\\Helpers\\\\FileSystem\\:\\:deleteDirectory\\(\\) expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Cleanup/Cleanup.php

		-
			message: "#^Parameter \\#1 \\$path of function dirname expects string, string\\|null given\\.$#"
			count: 3
			path: src/Pipeline/Cleanup/Cleanup.php

		-
			message: "#^Parameter \\#2 \\$subDir of method BrianHenryIE\\\\Strauss\\\\Helpers\\\\FileSystem\\:\\:isSubDirOf\\(\\) expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Cleanup/Cleanup.php

		-
			message: "#^Parameter \\#2 \\$needle of function strpos expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/FileEnumerator.php

		-
			message: "#^Cannot access property \\$name on PhpParser\\\\Node\\\\Name\\|null\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Method BrianHenryIE\\\\Strauss\\\\Pipeline\\\\Prefixer\\:\\:getModifiedFiles\\(\\) should return array\\<string, BrianHenryIE\\\\Strauss\\\\Composer\\\\ComposerPackage\\> but returns array\\<string, BrianHenryIE\\\\Strauss\\\\Composer\\\\ComposerPackage\\|null\\>\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Method BrianHenryIE\\\\Strauss\\\\Pipeline\\\\Prefixer\\:\\:replaceGlobalClassInsideNamedNamespace\\(\\) should return string but returns string\\|null\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Method BrianHenryIE\\\\Strauss\\\\Pipeline\\\\Prefixer\\:\\:replaceNamespace\\(\\) should return string but returns string\\|null\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Parameter \\#1 \\$nodes of method PhpParser\\\\NodeFinder\\:\\:find\\(\\) expects array\\<PhpParser\\\\Node\\>\\|PhpParser\\\\Node, array\\<PhpParser\\\\Node\\\\Stmt\\>\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Parameter \\#1 \\$nodes of method PhpParser\\\\NodeFinder\\:\\:findInstanceOf\\(\\) expects array\\<PhpParser\\\\Node\\>\\|PhpParser\\\\Node, array\\<PhpParser\\\\Node\\\\Stmt\\>\\|null given\\.$#"
			count: 2
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Parameter \\#1 \\$nodes of method PhpParser\\\\NodeTraverser\\:\\:traverse\\(\\) expects array\\<PhpParser\\\\Node\\>, array\\<PhpParser\\\\Node\\\\Stmt\\>\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Parameter \\#1 \\$text of class PhpParser\\\\Comment\\\\Doc constructor expects string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Parameter \\#3 \\$subject of function preg_replace expects array\\|string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php

		-
			message: "#^Parameter \\#3 \\$subject of function preg_replace_callback expects array\\|string, string\\|null given\\.$#"
			count: 1
			path: src/Pipeline/Prefixer.php


================================================
FILE: phpstan.neon
================================================
# phpstan analyse --memory-limit=-1 --level 8 --verbose
# phpstan analyse --memory-limit=-1 --level max --generate-baseline

includes:
    - phpstan-baseline.neon

parameters:

    level: 7

    reportUnmatchedIgnoredErrors: false

    paths:
        - src
        - bin/strauss

    ignoreErrors:
        -
            message: '#Property.*excludePackages is unused#'
            path: src/Composer/Extra/StraussConfig.php
        - '#Cannot call method .* on Psr\\Log\\LoggerInterface\|null#'
        - '#.*expects Psr\\Log\\LoggerInterface, Psr\\Log\\LoggerInterface\|null given#'

        -   # Allow type errors in test assertions to just throw.
            message: '#Parameter .* of .*method PHPUnit\\Framework\\Assert::.* expects .* given.#'
            path: tests
        -   # Allow skipping tests
            identifier: deadCode.unreachable
            path: tests


================================================
FILE: phpunit.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" backupStaticAttributes="false" bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
  <coverage>
    <include>
      <directory suffix=".php">src/</directory>
      <file>bootstrap.php</file>
    </include>
    <exclude>
      <file>src/Pipeline/FileSymbol/builtinsymbols.php</file>
    </exclude>
  </coverage>
  <testsuites>
    <testsuite name="all">
      <directory>./tests/</directory>
    </testsuite>
  </testsuites>
</phpunit>


================================================
FILE: scripts/createphar.sh
================================================
#!/bin/bash

# chmod +x scripts/createphar.sh
# ./scripts/createphar.sh

rm -rf build
composer install --no-dev
wget -O phar-composer.phar https://github.com/clue/phar-composer/releases/download/v1.4.0/phar-composer-1.4.0.phar
mkdir build
cp -R vendor build/vendor
cp -R src build/src
cp -R bin build/bin
cp composer.json build
cp bootstrap.php build
cp CHANGELOG.md build
php -d phar.readonly=off phar-composer.phar build ./build/

rm phar-composer.phar
rm -rf build
composer install

php strauss.phar --version

================================================
FILE: scripts/getbuiltinphp.php
================================================
<?php
/**
 * Get all built-in PHP classes, interfaces, traits.
 *
 * TODO: consider using JetBrains/phpstorm-stubs or PhpStan stubs to build the list of built-in classes, interfaces, traits.
 */

$outputFile = __DIR__ . '/builtins.php';

$builtins = file_exists($outputFile) ? require $outputFile : [];

$currentPhpVersion = implode(
    '.',
    array_slice(
        explode('.', phpversion()),
        0,
        2
    )
);

if (!isset($builtins[$currentPhpVersion])) {
    $builtins[$currentPhpVersion] = [
        'classes' => [],
        'interfaces' => [],
        'traits' => [],
        'functions' => [],
    ];
}

$classes = array_filter(
    get_declared_classes(),
    function (string $className): bool {
        $reflector = new \ReflectionClass($className);
        return empty($reflector->getFileName());
    }
);

$interfaces = array_filter(
    get_declared_interfaces(),
    function (string $interfaceName): bool {
        $reflector = new \ReflectionClass($interfaceName);
        return empty($reflector->getFileName());
    }
);

$traits = array_filter(
    get_declared_traits(),
    function (string $traitName): bool {
        $reflector = new \ReflectionClass($traitName);
        return empty($reflector->getFileName());
    }
);

$functions = array_filter(
    get_defined_functions()['internal'],
    function ($functionName): bool {
        $reflector = new \ReflectionFunction($functionName);
        return empty($reflector->getFileName());
    }
);


// Remove classes, interfaces, traits that are built-in in this PHP version from future versions.
foreach ($builtins as $phpVersion => $builtinsArray) {
    if (version_compare($phpVersion, $currentPhpVersion, '>')) {
        $builtins[$phpVersion]['classes'] = array_diff($builtinsArray['classes'], $classes);
        $builtins[$phpVersion]['interfaces'] = array_diff($builtinsArray['interfaces'], $interfaces);
        $builtins[$phpVersion]['traits'] = array_diff($builtinsArray['traits'], $traits);
        $builtins[$phpVersion]['functions'] = array_diff($builtinsArray['functions'], $functions);
    }
}

// Remove from this PHP version's built-ins list classes, interfaces, traits that exist in older versions.
foreach ($builtins as $phpVersion => $builtinsArray) {
    if (version_compare($phpVersion, $currentPhpVersion, '<')) {
        $classes = array_diff($classes, $builtinsArray['classes']);
        $interfaces = array_diff($interfaces, $builtinsArray['interfaces']);
        $traits = array_diff($traits, $builtinsArray['traits']);
        $functions = array_diff($functions, $builtinsArray['functions']);
    }
}

$builtins[$currentPhpVersion]['classes'] = array_unique(array_merge($builtins[$currentPhpVersion]['classes'], $classes));
$builtins[$currentPhpVersion]['interfaces'] = array_unique(array_merge($builtins[$currentPhpVersion]['interfaces'], $interfaces));
$builtins[$currentPhpVersion]['traits'] = array_unique(array_merge($builtins[$currentPhpVersion]['traits'], $traits));
$builtins[$currentPhpVersion]['functions'] = array_unique(array_merge($builtins[$currentPhpVersion]['functions'], $functions));

foreach ($builtins as $phpVersion => $builtinsArray) {
    asort($builtins[$currentPhpVersion]['classes']);
    asort($builtins[$currentPhpVersion]['interfaces']);
    asort($builtins[$currentPhpVersion]['traits']);
    asort($builtins[$currentPhpVersion]['functions']);
}


$outputText = '<?php' . PHP_EOL . 'return ' . var_export($builtins, true) . ';';

$outputText = preg_replace('/\d+\s=>\s/', '', $outputText);

file_put_contents($outputFile, $outputText);


================================================
FILE: src/Composer/ComposerPackage.php
================================================
<?php
/**
 * Object for getting typed values from composer.json.
 *
 * Use this for dependencies. Use ProjectComposerPackage for the primary composer.json.
 */

namespace BrianHenryIE\Strauss\Composer;

use BrianHenryIE\Strauss\Files\FileWithDependency;
use BrianHenryIE\Strauss\Helpers\FileSystem;
use Composer\Composer;
use Composer\Factory;
use Composer\IO\NullIO;
use Composer\Util\Platform;
use Exception;

/**
 * @phpstan-type AutoloadKeyArray array{files?:array<string>, "classmap"?:array<string>, "psr-4"?:array<string,string|array<string>>, "exclude_from_classmap"?:array<string>}
 * @phpstan-type ComposerConfigArray array{vendor-dir?:string}
 * @phpstan-type ComposerJsonArray array{name?:string, type?:string, license?:string, require?:array<string,string>, autoload?:AutoloadKeyArray, config?:ComposerConfigArray, repositories?:array<mixed>, provide?:array<string,string>}
 * @see \Composer\Config::merge()
 */
class ComposerPackage
{
    /**
     * The composer.json file as parsed by Composer.
     *
     * @see Factory::create
     *
     * @var Composer
     */
    protected Composer $composer;

    /**
     * The name of the project in composer.json.
     *
     * e.g. brianhenryie/my-project
     *
     * @var string
     */
    protected string $packageName;

    /**
     * Virtual packages and meta packages do not have a composer.json.
     * Some packages are installed in a different directory name than their package name.
     *
     * @var ?string
     */
    protected ?string $relativePath = null;

    /**
     * Packages can be symlinked from outside the current project directory.
     *
     * TODO: When could a package _not_ have an absolute path? Virtual packages, ext-*...
     */
    protected ?string $packageAbsolutePath = null;

    /**
     * The discovered files, classmap, psr0 and psr4 autoload keys discovered (as parsed by Composer).
     *
     * @var AutoloadKeyArray
     */
    protected array $autoload = [];

    /**
     * The names in the composer.json's "requires" field (without versions).
     *
     * @var string[]
     */
    protected array $requiresNames = [];

    protected string $license;

    /**
     * Should the package be copied to the vendor-prefixed/target directory? Default: true.
     */
    protected bool $isCopy = true;
    /**
     * Has the package been copied to the vendor-prefixed/target directory? False until the package is copied.
     */
    protected bool $didCopy = false;
    /**
     * Should the package be deleted from the vendor directory? Default: false.
     */
    protected bool $isDelete = false;
    /**
     * Has the package been deleted from the vendor directory? False until the package is deleted.
     */
    protected bool $didDelete = false;

    /**
     * List of files found in the package directory.
     *
     * @var FileWithDependency[]
     */
    protected array $files;

    /**
     * @param string $absolutePath The absolute path to composer.json
     * @param ?array{files?:array<string>, classmap?:array<string>, psr?:array<string,string|array<string>>} $overrideAutoload Optional configuration to replace the package's own autoload definition with
     *                                    another which Strauss can use.
     * @return ComposerPackage
     * @throws Exception
     */
    public static function fromFile(string $absolutePath, ?array $overrideAutoload = null): ComposerPackage
    {
        $composer = Factory::create(new NullIO(), $absolutePath, true);

        return new ComposerPackage($composer, $overrideAutoload);
    }

    /**
     * This is used for virtual packages, which don't have a composer.json.
     *
     * @param ComposerJsonArray $jsonArray composer.json decoded to array
     * @param ?AutoloadKeyArray $overrideAutoload New autoload rules to replace the existing ones.
     * @throws Exception
     */
    public static function fromComposerJsonArray(array $jsonArray, ?array $overrideAutoload = null): ComposerPackage
    {
        $factory = new Factory();
        $io = new NullIO();
        $composer = $factory->createComposer($io, $jsonArray, true);

        return new ComposerPackage($composer, $overrideAutoload);
    }

    /**
     * Create a PHP object to represent a composer package.
     *
     * @param Composer $composer
     * @param ?AutoloadKeyArray $overrideAutoload Optional configuration to replace the package's own autoload definition with another which Strauss can use.
     * @throws Exception
     */
    public function __construct(Composer $composer, ?array $overrideAutoload = null)
    {
        $this->composer = $composer;

        $this->packageName = $composer->getPackage()->getName();

        $composerJsonFileAbsolute = $composer->getConfig()->getConfigSource()->getName();

        $pathNormalizer = FileSystem::makePathNormalizer(getcwd());
        
        $fsComposerAbsoluteDirectoryPath = realpath(dirname($composerJsonFileAbsolute));
        if (false !== $fsComposerAbsoluteDirectoryPath) {
            $fsComposerAbsoluteDirectoryPath = FileSystem::normalizeDirSeparator($fsComposerAbsoluteDirectoryPath);
            $this->packageAbsolutePath = $fsComposerAbsoluteDirectoryPath;
        }
        $fsComposerAbsoluteDirectoryPath = $fsComposerAbsoluteDirectoryPath ?: FileSystem::normalizeDirSeparator(dirname($composerJsonFileAbsolute));

        $fsCurrentWorkingDirectory = getcwd();
        if ($fsCurrentWorkingDirectory === false) {
            /**
             * @see Platform::getCwd()
             */
            throw new Exception('Could not determine working directory. Please comment out ~'.__LINE__.' in ' . __FILE__.' and see does it work regardless.');
        }
        $fsCurrentWorkingDirectory = FileSystem::normalizeDirSeparator($fsCurrentWorkingDirectory);

        /** @var string $vendorAbsoluteDirectoryPath */
        $vendorAbsoluteDirectoryPath = $this->composer->getConfig()->get('vendor-dir');
        if (file_exists($vendorAbsoluteDirectoryPath . '/' . $this->packageName)) {
            $this->relativePath = $this->packageName;
            $this->packageAbsolutePath = $pathNormalizer->normalizePath(realpath($vendorAbsoluteDirectoryPath . '/' . $this->packageName));
        // If the package is symlinked, the path will be outside the working directory.
        } elseif (0 !== strpos($fsComposerAbsoluteDirectoryPath, $fsCurrentWorkingDirectory) && 1 === preg_match('/.*[\/\\\\]([^\/\\\\]*[\/\\\\][^\/\\\\]*)[\/\\\\][^\/\\\\]*/', $vendorAbsoluteDirectoryPath, $output_array)) {
            $this->relativePath = $output_array[1];
        } elseif (1 === preg_match('/.*[\/\\\\]([^\/\\\\]+[\/\\\\][^\/\\\\]+)[\/\\\\]composer.json/', $composerJsonFileAbsolute, $output_array)) {
        // Not every package gets installed to a folder matching its name (crewlabs/unsplash).
            $this->relativePath = $output_array[1];
        }

        if (!is_null($overrideAutoload)) {
            $composer->getPackage()->setAutoload($overrideAutoload);
        }

        $this->autoload = $composer->getPackage()->getAutoload();

        foreach ($composer->getPackage()->getRequires() as $_name => $packageLink) {
            $this->requiresNames[] = $packageLink->getTarget();
        }

        // Try to get the license from the package's composer.json, assume proprietary (all rights reserved!).
        $this->license = !empty($composer->getPackage()->getLicense())
            ? implode(',', $composer->getPackage()->getLicense())
            : 'proprietary?';
    }

    /**
     * Composer package project name.
     *
     * vendor/project-name
     *
     * @return string
     */
    public function getPackageName(): string
    {
        return $this->packageName;
    }

    /**
     * Is this relative to vendor?
     */
    public function getRelativePath(): ?string
    {
        return is_null($this->relativePath) ? null : FileSystem::normalizeDirSeparator($this->relativePath);
    }


    /**
     * No leading or tailing slash
     */
    public function getPackageAbsolutePath(): ?string
    {
        return !empty($this->packageAbsolutePath) ? trim($this->packageAbsolutePath, '\\/') : null;
    }

    /**
     *
     * e.g. ['psr-4' => [ 'BrianHenryIE\Project' => 'src' ]]
     * e.g. ['psr-4' => [ 'BrianHenryIE\Project' => ['src','lib] ]]
     * e.g. ['classmap' => [ 'src', 'lib' ]]
     * e.g. ['files' => [ 'lib', 'functions.php' ]]
     *
     * @return AutoloadKeyArray
     */
    public function getAutoload(): array
    {
        return $this->autoload;
    }

    /**
     * The names of the packages in the composer.json's "requires" field (without version).
     *
     * Excludes PHP, ext-*, since we won't be copying or prefixing them.
     *
     * @return string[]
     */
    public function getRequiresNames(): array
    {
        // Unset PHP, ext-*.
        $removePhpExt = function ($element) {
            return !( 0 === strpos($element, 'ext') || 'php' === $element );
        };

        return array_filter($this->requiresNames, $removePhpExt);
    }

    public function getLicense():string
    {
        return $this->license;
    }

    /**
     * Should the file be copied? (defaults to yes)
     */
    public function setCopy(bool $isCopy): void
    {
        $this->isCopy = $isCopy;
    }

    /**
     * Should the file be copied? (defaults to yes)
     */
    public function isCopy(): bool
    {
        return $this->isCopy;
    }

    /**
     * Has the file been copied? (defaults to no)
     */
    public function setDidCopy(bool $didCopy): void
    {
        $this->didCopy = $didCopy;
    }

    /**
     * Has the file been copied? (defaults to no)
     */
    public function didCopy(): bool
    {
        return $this->didCopy;
    }

    /**
     * Should the file be deleted? (defaults to no)
     */
    public function setDelete(bool $isDelete): void
    {
        $this->isDelete = $isDelete;
    }

    /**
     * Should the file be deleted? (defaults to no)
     */
    public function isDoDelete(): bool
    {
        return $this->isDelete;
    }

    /**
     * Has the file been deleted? (defaults to no)
     */
    public function setDidDelete(bool $didDelete): void
    {
        $this->didDelete = $didDelete;
    }

    /**
     * Has the file been deleted? (defaults to no)
     */
    public function didDelete(): bool
    {
        return $this->didDelete;
    }

    public function addFile(FileWithDependency $file): void
    {
        $this->files[$file->getPackageRelativePath()] = $file;
    }

    public function getFile(string $path): ?FileWithDependency
    {
        return $this->files[$path] ?? null;
    }
}


================================================
FILE: src/Composer/Extra/ReplaceConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Composer\Extra;

use BrianHenryIE\Strauss\Config\AutoloadFilesEnumeratorConfigInterface;
use BrianHenryIE\Strauss\Config\ChangeEnumeratorConfigInterface;
use BrianHenryIE\Strauss\Config\FileEnumeratorConfig;
use BrianHenryIE\Strauss\Config\FileSymbolScannerConfigInterface;
use BrianHenryIE\Strauss\Config\LicenserConfigInterface;
use BrianHenryIE\Strauss\Config\PrefixerConfigInterface;

interface ReplaceConfigInterface extends
    FileEnumeratorConfig,
    FileSymbolScannerConfigInterface,
    AutoloadFilesEnumeratorConfigInterface,
    ChangeEnumeratorConfigInterface,
    PrefixerConfigInterface,
    LicenserConfigInterface
{

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromPrefixing(): array;

    /**
     * @return array<string,string>
     */
    public function getNamespaceReplacementPatterns(): array;

    public function isIncludeModifiedDate(): bool;

    public function isIncludeAuthor(): bool;

    /**
     * @return string[]|null
     */
    public function getUpdateCallSites(): ?array;
}


================================================
FILE: src/Composer/Extra/StraussConfig.php
================================================
<?php
/**
 * The extra/strauss key in composer.json.
 */

namespace BrianHenryIE\Strauss\Composer\Extra;

use BrianHenryIE\Strauss\Composer\ComposerPackage;
use BrianHenryIE\Strauss\Config\AliasesConfigInterface;
use BrianHenryIE\Strauss\Config\AutoloadConfigInterface;
use BrianHenryIE\Strauss\Config\AutoloadFilesEnumeratorConfigInterface;
use BrianHenryIE\Strauss\Config\ChangeEnumeratorConfigInterface;
use BrianHenryIE\Strauss\Config\CleanupConfigInterface;
use BrianHenryIE\Strauss\Config\CopierConfigInterface;
use BrianHenryIE\Strauss\Config\MarkSymbolsForRenamingConfigInterface;
use BrianHenryIE\Strauss\Config\FileCopyScannerConfigInterface;
use BrianHenryIE\Strauss\Config\FileEnumeratorConfig;
use BrianHenryIE\Strauss\Config\FileSymbolScannerConfigInterface;
use BrianHenryIE\Strauss\Config\OptimizeAutoloaderConfigInterface;
use BrianHenryIE\Strauss\Config\PrefixerConfigInterface;
use BrianHenryIE\Strauss\Console\Commands\DependenciesCommand;
use BrianHenryIE\Strauss\Helpers\FileSystem;
use BrianHenryIE\Strauss\Pipeline\Autoload\DumpAutoload;
use Composer\Composer;
use Exception;
use InvalidArgumentException;
use JsonMapper\Enums\TextNotation;
use JsonMapper\JsonMapperFactory;
use JsonMapper\Middleware\CaseConversion;
use JsonMapper\Middleware\Rename\Rename;
use Symfony\Component\Console\Input\InputInterface;

class StraussConfig implements
    AliasesConfigInterface,
    AutoloadConfigInterface,
    AutoloadFilesEnumeratorConfigInterface,
    ChangeEnumeratorConfigInterface,
    CleanupConfigInterface,
    CopierConfigInterface,
    MarkSymbolsForRenamingConfigInterface,
    FileSymbolScannerConfigInterface,
    FileEnumeratorConfig,
    FileCopyScannerConfigInterface,
    OptimizeAutoloaderConfigInterface,
    PrefixerConfigInterface,
    ReplaceConfigInterface
{
    /**
     * The directory containing `composer.json`. Probably `cwd()`.
     */
    protected string $projectDirectory;

    /**
     * The output directory.
     */
    protected string $targetDirectory = 'vendor-prefixed';

    /**
     * The vendor directory.
     *
     * Probably 'vendor/'
     */
    protected string $relativeVendorDirectory = 'vendor';

    /**
     * `namespacePrefix` is the prefix to be given to any namespaces.
     * Presumably this will take the form `My_Project_Namespace\dep_directory`.
     *
     * @link https://www.php-fig.org/psr/psr-4/
     */
    protected ?string $namespacePrefix = null;

    /**
     *
     */
    protected ?string $classmapPrefix = null;

    /**
     * Null to disable. Otherwise, suggested it is all lowercase with a trailing underscore.
     *
     * @var string|bool|null
     */
    protected $functionsPrefix;

    /**
     * @var ?string
     */
    protected ?string $constantsPrefix = null;

    /**
     * Should replacements be performed in project files?
     *
     * When null, files in the project's `autoload` key are scanned and changes which have been performed on the
     * vendor packages are reflected in the project files.
     *
     * When an array of relative file paths are provided, the files in those directories are updated.
     *
     * An empty array disables updating project files.
     *
     * @var ?string[]
     */
    protected ?array $updateCallSites = array();

    /**
     * Packages to copy and (maybe) prefix.
     *
     * If this is empty, the "requires" list in the project composer.json is used.
     *
     * @var string[]
     */
    protected array $packages = [];

    /**
     * @var array<string,ComposerPackage>
     */
    protected array $packagesToCopy = [];

    /**
     *
     * @var array<string,ComposerPackage>
     */
    protected array $packagesToPrefix = [];

    /**
     * Back-compatibility with Mozart.
     *
     * @var string[]
     */
    private array $excludePackages;

    /**
     * 'exclude_from_copy' in composer/extra config.
     *
     * @var array{packages: string[], namespaces: string[], file_patterns: string[]}
     */
    protected array $excludeFromCopy = array('file_patterns'=>array(),'namespaces'=>array(),'packages'=>array());

    /**
     * @var array{packages: string[], namespaces: string[], file_patterns: string[]}
     */
    protected array $excludeFromPrefix = array('file_patterns'=>array(),'namespaces'=>array(),'packages'=>array());

    /**
     * Exclude constants from prefixing only (same shape as exclude_from_prefix).
     *
     * @var array{packages: string[], namespaces: string[], file_patterns: string[], constants: string[]}
     */
    protected array $excludeConstants = array('file_patterns'=>array(),'namespaces'=>array(),'packages'=>array(),'constants'=>array());

    /**
     * An array of autoload keys to replace packages' existing autoload key.
     *
     * e.g. when
     * * A package has no autoloader
     * * A package specified both a PSR-4 and a classmap but only needs one
     * ...
     *
     * @var array<string, array{files?:array<string>,classmap?:array<string>,"psr-4":array<string|array<string>>}>|array{} $overrideAutoload
     */
    protected array $overrideAutoload = [];

    /**
     * After completing prefixing should the source files be deleted?
     * This does not affect symlinked directories.
     */
    protected bool $deleteVendorFiles = false;

    /**
     * After completing prefixing should the source packages be deleted?
     * This does not affect symlinked directories.
     */
    protected bool $deleteVendorPackages = false;

    protected bool $classmapOutput;

    /**
     * A dictionary of regex captures => regex replacements.
     *
     * E.g. used to avoid repetition of the plugin vendor name in namespaces.
     * `"~BrianHenryIE\\\\(.*)~" : "BrianHenryIE\\WC_Cash_App_Gateway\\\\$1"`.
     *
     * @var array<string, string> $namespaceReplacementPatterns
     */
    protected array $namespaceReplacementPatterns = array();

    /**
     * Should a modified date be included in the header for modified files?
     */
    protected bool $includeModifiedDate = true;

    /**
     * Should the author name be included in the header for modified files?
     */
    protected bool $includeAuthor = true;

    /**
     * Should the changes be printed to console rather than files modified?
     */
    protected bool $dryRun = false;

    /**
     * Should the root autoload be included when generating the strauss autoloader?
     */
    protected bool $includeRootAutoload = false;

    /**
     * Should Composer autoload generation be optimized and classmap authoritative?
     */
    protected bool $optimizeAutoloader = true;

    /**
     * Read any existing Mozart config.
     * Overwrite it with any Strauss config.
     * Provide sensible defaults.
     *
     * @param ?Composer $composer
     *
     * @throws Exception
     */
    public function __construct(?Composer $composer = null)
    {

        $configExtraSettings = null;

        // Backwards compatibility with Mozart.
        if (isset($composer, $composer->getPackage()->getExtra()['mozart'])) {
            $configExtraSettings = (object)$composer->getPackage()->getExtra()['mozart'];

            // Default setting for Mozart.
            $this->setDeleteVendorFiles(true);
        }

        if (isset($composer, $composer->getPackage()->getExtra()['strauss'])) {
            $configExtraSettings = (object)$composer->getPackage()->getExtra()['strauss'];
        }

        if (!is_null($configExtraSettings)) {
            $mapper = (new JsonMapperFactory())->bestFit();

            $rename = new Rename();
            $rename->addMapping(StraussConfig::class, 'dep_directory', 'targetDirectory');
            $rename->addMapping(StraussConfig::class, 'dep_namespace', 'namespacePrefix');

            $rename->addMapping(StraussConfig::class, 'exclude_packages', 'excludePackages');
            $rename->addMapping(StraussConfig::class, 'delete_vendor_files', 'deleteVendorFiles');
            $rename->addMapping(StraussConfig::class, 'delete_vendor_packages', 'deleteVendorPackages');

            $rename->addMapping(StraussConfig::class, 'exclude_prefix_packages', 'excludePackagesFromPrefixing');

            $rename->addMapping(StraussConfig::class, 'include_root_autoload', 'includeRootAutoload');

            $rename->addMapping(StraussConfig::class, 'function_prefix', 'functionsPrefix');

            $rename->addMapping(StraussConfig::class, 'constant_prefix', 'constantsPrefix');

            $mapper->unshift($rename);
            $mapper->push(new CaseConversion(TextNotation::UNDERSCORE(), TextNotation::CAMEL_CASE()));

            $mapper->mapObject($configExtraSettings, $this);
        }

        // Defaults.
        // * Use PSR-4 autoloader key
        // * Use PSR-0 autoloader key
        // * Use the package name
        if (! isset($this->namespacePrefix)) {
            if (isset($composer, $composer->getPackage()->getAutoload()['psr-4']) && !empty($composer->getPackage()->getAutoload()['psr-4'])) {
                $this->setNamespacePrefix(array_key_first($composer->getPackage()->getAutoload()['psr-4']));
            } elseif (isset($composer, $composer->getPackage()->getAutoload()['psr-0']) && !empty($composer->getPackage()->getAutoload()['psr-0'])) {
                $this->setNamespacePrefix(array_key_first($composer->getPackage()->getAutoload()['psr-0']));
            } elseif (isset($composer) && '__root__' !== $composer->getPackage()->getName()) {
                $packageName = $composer->getPackage()->getName();
                // Replace all non-word characters with underscores.
                $namespacePrefix = preg_replace('/[^\w\/]+/', '_', $packageName) ?? $packageName;
                $namespacePrefix = str_replace('/', '\\', $namespacePrefix) . '\\';
                $namespacePrefix = preg_replace_callback('/(?<=^|_|\\\\)[a-z]/', function ($match) {
                    return strtoupper($match[0]);
                }, $namespacePrefix) ?? $namespacePrefix;
                $this->setNamespacePrefix($namespacePrefix);
            } elseif (isset($this->classmapPrefix) && !empty($this->getClassmapPrefix())) {
                $namespacePrefix = rtrim($this->getClassmapPrefix(), '_');
                $this->setNamespacePrefix($namespacePrefix);
            }
        }

        if (! isset($this->classmapPrefix)) {
            if (isset($composer, $composer->getPackage()->getAutoload()['psr-4'])) {
                $autoloadKey = array_key_first($composer->getPackage()->getAutoload()['psr-4']);
                $classmapPrefix = str_replace("\\", "_", $autoloadKey);
                $this->setClassmapPrefix($classmapPrefix);
            } elseif (isset($composer, $composer->getPackage()->getAutoload()['psr-0'])) {
                $autoloadKey = array_key_first($composer->getPackage()->getAutoload()['psr-0']);
                $classmapPrefix = str_replace("\\", "_", $autoloadKey);
                $this->setClassmapPrefix($classmapPrefix);
            } elseif (isset($composer) && '__root__' !== $composer->getPackage()->getName()) {
                $packageName = $composer->getPackage()->getName();
                $classmapPrefix = preg_replace('/[^\w\/]+/', '_', $packageName);
                $classmapPrefix = str_replace('/', '\\', $classmapPrefix);
                // Uppercase the first letter of each word.
                $classmapPrefix = preg_replace_callback('/(?<=^|_|\\\\)[a-z]/', function ($match) {
                    return strtoupper($match[0]);
                }, $classmapPrefix);
                $classmapPrefix = str_replace("\\", "_", $classmapPrefix);
                $this->setClassmapPrefix($classmapPrefix);
            } elseif (isset($this->namespacePrefix)) {
                $classmapPrefix = preg_replace('/[^\w\/]+/', '_', $this->getNamespacePrefix()) ?? str_replace('\\', '_', $this->getNamespacePrefix());
                $classmapPrefix = rtrim($classmapPrefix, '_') . '_';
                $this->setClassmapPrefix($classmapPrefix);
            }
        }

//        if (!isset($this->namespacePrefix) || !isset($this->classmapPrefix)) {
//            throw new Exception('Prefix not set. Please set `namespace_prefix`, `classmap_prefix` in composer.json/extra/strauss.');
//        }

        if (isset($composer) && empty($this->packages)) {
            $this->packages = array_map(function (\Composer\Package\Link $element) {
                return $element->getTarget();
            }, $composer->getPackage()->getRequires());
        }

        // If the bool flag for classmapOutput wasn't set in the JSON config.
        if (!isset($this->classmapOutput)) {
            $this->classmapOutput = true;
            // Check each autoloader.
            if (isset($composer)) {
                foreach ($composer->getPackage()->getAutoload() as $autoload) {
                    // To see if one of its paths.
                    foreach ($autoload as $entry) {
                        $paths = (array) $entry;
                        foreach ($paths as $path) {
                            // Matches the target directory.
                            if (trim($path, '\\/') === $this->getAbsoluteTargetDirectory()) {
                                $this->classmapOutput = false;
                                break 3;
                            }
                        }
                    }
                }
            }
        }

        // TODO: Throw an exception if any regex patterns in config are invalid.
        // https://stackoverflow.com/questions/4440626/how-can-i-validate-regex
        // preg_match('~Valid(Regular)Expression~', null) === false);

        if (isset($configExtraSettings, $configExtraSettings->updateCallSites)) {
            if (true === $configExtraSettings->updateCallSites) {
                $this->updateCallSites = null;
            } elseif (false === $configExtraSettings->updateCallSites) {
                $this->updateCallSites = array();
            } elseif (is_array($configExtraSettings->updateCallSites)) {
                $this->updateCallSites = $configExtraSettings->updateCallSites;
            } else {
                // uh oh.
            }
        }
    }

    /**
     * `target_directory` will always be returned without a leading nor trailing slash.
     */
    public function getAbsoluteTargetDirectory(): string
    {
        return FileSystem::normalizeDirSeparator(
            trim($this->getProjectDirectory(), '\\/') . '/' . trim($this->targetDirectory, '\\/')
        );
    }

    public function isTargetDirectoryVendor(): bool
    {
        return $this->getAbsoluteVendorDirectory() === $this->getAbsoluteTargetDirectory();
    }

    /**
     * Default 'vendor-prefixed'. No leading or trailing slash.
     */
    public function getRelativeTargetDirectory(): string
    {
        return FileSystem::normalizeDirSeparator(
            trim($this->targetDirectory, '\\/')
        );
    }

    /**
     * @param string $targetDirectory
     */
    public function setTargetDirectory(string $targetDirectory): void
    {
        $this->targetDirectory = $targetDirectory;
    }

    /**
     * No leading or trailing slash.
     */
    public function getAbsoluteVendorDirectory(): string
    {
        return trim($this->getProjectDirectory() . '/' . $this->relativeVendorDirectory, '\\/');
    }

    /**
     * @param string $relativeVendorDirectory
     */
    public function setRelativeVendorDirectory(string $relativeVendorDirectory): void
    {
        $this->relativeVendorDirectory = $relativeVendorDirectory;
    }

    /**
     * With no trailing slash and no leading slash.
     */
    public function getNamespacePrefix(): ?string
    {
        return !isset($this->namespacePrefix) ? null : trim($this->namespacePrefix, '\\');
    }

    /**
     * @param string $namespacePrefix
     */
    public function setNamespacePrefix(string $namespacePrefix): void
    {
        $this->namespacePrefix = $namespacePrefix;
    }

    /**
     * @return string
     */
    public function getClassmapPrefix(): ?string
    {
        return $this->classmapPrefix;
    }

    /**
     * @param string $classmapPrefix
     */
    public function setClassmapPrefix(string $classmapPrefix): void
    {
        $this->classmapPrefix = $classmapPrefix;
    }

    public function getFunctionsPrefix(): ?string
    {
        if (!isset($this->functionsPrefix) && !is_null($this->getClassmapPrefix())) {
            return strtolower($this->getClassmapPrefix());
        }
        if (empty($this->functionsPrefix)) {
            return null;
        }
        if (is_string($this->functionsPrefix)) {
            return $this->functionsPrefix;
        }
        return null;
    }

    /**
     * @param string|bool|null $functionsPrefix
     */
    public function setFunctionsPrefix($functionsPrefix): void
    {
        $this->functionsPrefix = $functionsPrefix;
    }

    /**
     * @return string
     */
    public function getConstantsPrefix(): ?string
    {
        return $this->constantsPrefix;
    }

    /**
     * @param string $constantsPrefix
     */
    public function setConstantsPrefix(string $constantsPrefix): void
    {
        $this->constantsPrefix = $constantsPrefix;
    }

    /**
     * List of files and directories to update call sites in. Empty to disable. Null infers from the project's autoload key.
     *
     * @return string[]|null
     */
    public function getUpdateCallSites(): ?array
    {
        return $this->updateCallSites;
    }

    /**
     * @param string[]|array{0:bool}|null $updateCallSites
     * @throws InvalidArgumentException
     */
    public function setUpdateCallSites($updateCallSites): void
    {
        if (is_array($updateCallSites) && count($updateCallSites) === 1 && $updateCallSites[0] === true) {
            // Setting `null` instructs Strauss to update call sites in the project's autoload key.
            $this->updateCallSites = null;
            return;
        } elseif (is_array($updateCallSites) && count($updateCallSites) === 1 && $updateCallSites[0] === false) {
            $this->updateCallSites = array();
            return;
        } elseif (is_array($updateCallSites) && isset($updateCallSites[0]) && !is_bool($updateCallSites[0])) {
            $this->updateCallSites = array_filter(
                $updateCallSites,
                'is_string'
            );
            return;
        }
        throw new InvalidArgumentException('Unexpected value for updateCallSites');
    }

    /**
     * @param array{packages?:array<string>, namespaces?:array<string>, file_patterns?:array<string>} $excludeFromCopy
     */
    public function setExcludeFromCopy(array $excludeFromCopy): void
    {
        foreach (array( 'packages', 'namespaces', 'file_patterns' ) as $key) {
            if (isset($excludeFromCopy[$key])) {
                $this->excludeFromCopy[$key] = $excludeFromCopy[$key];
            }
        }
    }

    /**
     * @return string[]
     */
    public function getExcludePackagesFromCopy(): array
    {
        return $this->excludeFromCopy['packages'] ?? array();
    }

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromCopy(): array
    {
        return $this->excludeFromCopy['namespaces'] ?? array();
    }

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromCopy(): array
    {
        return $this->excludeFromCopy['file_patterns'] ?? array();
    }

    /**
     * @param array{packages?:array<string>, namespaces?:array<string>, file_patterns?:array<string>} $excludeFromPrefix
     */
    public function setExcludeFromPrefix(array $excludeFromPrefix): void
    {
        if (isset($excludeFromPrefix['packages'])) {
            $this->excludeFromPrefix['packages'] = $excludeFromPrefix['packages'];
        }
        if (isset($excludeFromPrefix['namespaces'])) {
            $this->excludeFromPrefix['namespaces'] = $excludeFromPrefix['namespaces'];
        }
        if (isset($excludeFromPrefix['file_patterns'])) {
            $this->excludeFromPrefix['file_patterns'] = $excludeFromPrefix['file_patterns'];
        }
    }

    /**
     * When prefixing, do not prefix these packages (which have been copied).
     *
     * @return string[]
     */
    public function getExcludePackagesFromPrefixing(): array
    {
        return $this->excludeFromPrefix['packages'] ?? [];
    }

    /**
     * @param string[] $excludePackagesFromPrefixing
     */
    public function setExcludePackagesFromPrefixing(array $excludePackagesFromPrefixing): void
    {
        $this->excludeFromPrefix['packages'] = $excludePackagesFromPrefixing;
    }

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromPrefixing(): array
    {
        return array_map(
            fn(string $packageName) => trim($packageName, '\\/'),
            $this->excludeFromPrefix['namespaces'] ?? []
        );
    }

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromPrefixing(): array
    {
        return $this->excludeFromPrefix['file_patterns'] ?? array();
    }

    /**
     * @param array{packages?:array<string>, namespaces?:array<string>, file_patterns?:array<string>, constants?:array<string>} $excludeConstants
     */
    public function setExcludeConstants(array $excludeConstants): void
    {
        if (isset($excludeConstants['packages'])) {
            $this->excludeConstants['packages'] = $excludeConstants['packages'];
        }
        if (isset($excludeConstants['namespaces'])) {
            $this->excludeConstants['namespaces'] = $excludeConstants['namespaces'];
        }
        if (isset($excludeConstants['file_patterns'])) {
            $this->excludeConstants['file_patterns'] = $excludeConstants['file_patterns'];
        }
        if (isset($excludeConstants['constants'])) {
            $this->excludeConstants['constants'] = $excludeConstants['constants'];
        }
    }

    /**
     * @return string[]
     */
    public function getExcludePackagesFromConstantPrefixing(): array
    {
        return $this->excludeConstants['packages'] ?? [];
    }

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromConstantPrefixing(): array
    {
        return array_map(
            fn(string $ns) => trim($ns, '\\/'),
            $this->excludeConstants['namespaces'] ?? []
        );
    }

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromConstantPrefixing(): array
    {
        return $this->excludeConstants['file_patterns'] ?? [];
    }

    /**
     * @return string[]
     */
    public function getExcludeConstantNames(): array
    {
        return $this->excludeConstants['constants'] ?? [];
    }

    /**
     * @return array{}|array<string, array{files?:array<string>,classmap?:array<string>,"psr-4":array<string|array<string>>}> $overrideAutoload Dictionary of package name: autoload rules.
     */
    public function getOverrideAutoload(): array
    {
        return $this->overrideAutoload;
    }

    /**
     * @param array<string, array{files?:array<string>,classmap?:array<string>,"psr-4":array<string|array<string>>}> $overrideAutoload Dictionary of package name: autoload rules.
     */
    public function setOverrideAutoload(array $overrideAutoload): void
    {
        $this->overrideAutoload = $overrideAutoload;
    }

    /**
     * @return bool
     */
    public function isDeleteVendorFiles(): bool
    {
        return $this->deleteVendorFiles;
    }

    /**
     * @return bool
     */
    public function isDeleteVendorPackages(): bool
    {
        return $this->deleteVendorPackages;
    }

    /**
     * @param bool $deleteVendorFiles
     */
    public function setDeleteVendorFiles(bool $deleteVendorFiles): void
    {
        $this->deleteVendorFiles = $deleteVendorFiles;
    }

    /**
     * @param bool $deleteVendorPackages
     */
    public function setDeleteVendorPackages(bool $deleteVendorPackages): void
    {
        $this->deleteVendorPackages = $deleteVendorPackages;
    }

    /**
     * @return string[]
     */
    public function getPackages(): array
    {
        return $this->packages;
    }

    /**
     * @param string[] $packages
     */
    public function setPackages(array $packages): void
    {
        $this->packages = $packages;
    }

    /**
     * @used-by DumpAutoload::createInstalledVersionsFiles()
     * @return array<string,ComposerPackage>
     */
    public function getPackagesToCopy(): array
    {
        return $this->packagesToCopy;
    }

    /**
     * @used-by DependenciesCommand::buildDependencyList()
     *
     * @param array<string,ComposerPackage> $packagesToCopy
     */
    public function setPackagesToCopy(array $packagesToCopy): void
    {
        $this->packagesToCopy = $packagesToCopy;
    }

    /**
     * @return array<string,ComposerPackage>
     */
    public function getPackagesToPrefix(): array
    {
        return $this->packagesToPrefix;
    }

    /**
     * @param array<string,ComposerPackage> $packagesToPrefix
     */
    public function setPackagesToPrefix(array $packagesToPrefix): void
    {
        $this->packagesToPrefix = $packagesToPrefix;
    }
    /**
     * TODO: Can we name this `isClassmapOutputEnabled`?
     */
    public function isClassmapOutput(): bool
    {
        return $this->classmapOutput;
    }

    /**
     * @param bool $classmapOutput
     */
    public function setClassmapOutput(bool $classmapOutput): void
    {
        $this->classmapOutput = $classmapOutput;
    }

    /**
     * Backwards compatibility with Mozart.
     *
     * @param string[] $excludePackages
     */
    public function setExcludePackages(array $excludePackages): void
    {
        $this->excludeFromPrefix['packages'] = $excludePackages;
    }

    /**
     * @return array<string,string>
     */
    public function getNamespaceReplacementPatterns(): array
    {
        return $this->namespaceReplacementPatterns;
    }

    /**
     * @param array<string,string> $namespaceReplacementPatterns
     */
    public function setNamespaceReplacementPatterns(array $namespaceReplacementPatterns): void
    {
        $this->namespaceReplacementPatterns = $namespaceReplacementPatterns;
    }

    /**
     * @return bool
     */
    public function isIncludeModifiedDate(): bool
    {
        return $this->includeModifiedDate;
    }

    /**
     * @param bool $includeModifiedDate
     */
    public function setIncludeModifiedDate(bool $includeModifiedDate): void
    {
        $this->includeModifiedDate = $includeModifiedDate;
    }


    /**
     * @return bool
     */
    public function isIncludeAuthor(): bool
    {
        return $this->includeAuthor;
    }

    /**
     * @param bool $includeAuthor
     */
    public function setIncludeAuthor(bool $includeAuthor): void
    {
        $this->includeAuthor = $includeAuthor;
    }

    /**
     * Should expected changes be printed to console rather than files modified?
     */
    public function isDryRun(): bool
    {
        return $this->dryRun;
    }

    /**
     * Disable making changes to files; output changes to console instead.
     */
    public function setDryRun(bool $dryRun): void
    {
        $this->dryRun = $dryRun;
    }

    /**
     * Should the root autoload be included when generating the strauss autoloader?
     */
    public function isIncludeRootAutoload(): bool
    {
        return $this->includeRootAutoload;
    }

    public function isOptimizeAutoloader(): bool
    {
        return $this->optimizeAutoloader;
    }

    /**
     * @param bool $includeRootAutoload Include the project root autoload in the strauss autoloader.
     */
    public function setIncludeRootAutoload(bool $includeRootAutoload): void
    {
        $this->includeRootAutoload = $includeRootAutoload;
    }

    public function setOptimizeAutoloader(bool $optimizeAutoloader): void
    {
        $this->optimizeAutoloader = $optimizeAutoloader;
    }

    /**
     * @param InputInterface $input To access the command line options.
     */
    public function updateFromCli(InputInterface $input): void
    {

        // strauss --updateCallSites=false (default)
        // strauss --updateCallSites=true
        // strauss --updateCallSites=src,input,extra

        if ($input->hasOption('updateCallSites') && $input->getOption('updateCallSites') !== null) {
            $updateCallSitesInput = $input->getOption('updateCallSites');

            if ('false' === $updateCallSitesInput) {
                $this->updateCallSites = array();
            } elseif ('true' === $updateCallSitesInput) {
                $this->updateCallSites = null;
            } elseif (is_string($updateCallSitesInput)) {
                $this->updateCallSites = explode(',', $updateCallSitesInput);
            }
        }

        if ($input->hasOption('deleteVendorPackages')  && $input->getOption('deleteVendorPackages') !== false) {
            $isDeleteVendorPackagesCommandLine = $input->getOption('deleteVendorPackages') === 'true'
                || $input->getOption('deleteVendorPackages') === null;
            $this->setDeleteVendorPackages($isDeleteVendorPackagesCommandLine);
        } elseif ($input->hasOption('delete_vendor_packages') && $input->getOption('delete_vendor_packages') !== false) {
            $isDeleteVendorPackagesCommandLine = $input->getOption('delete_vendor_packages') === 'true'
                || $input->getOption('delete_vendor_packages') === null;
            $this->setDeleteVendorPackages($isDeleteVendorPackagesCommandLine);
        }

        if ($input->hasOption('dry-run') && $input->getOption('dry-run') !== false) {
            // If we're here, the parameter was passed in the CLI command.
            $this->dryRun = empty($input->getOption('dry-run')) || (bool)filter_var($input->getOption('dry-run'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        }
    }

    /**
     * Should we create the `autoload_aliases.php` file in `vendor/composer`?
     *
     * TODO:
     * [x] YES when we are deleting vendor packages or files
     * [ ] NO when we are running composer install `--no-dev`
     * [ ] SOMETIMES: see https://github.com/BrianHenryIE/strauss/issues/144
     * [ ] Add `aliases` to `extra` in `composer.json`
     * [ ] Add `--aliases=true` CLI option
     */
    public function isCreateAliases(): bool
    {
        return $this->deleteVendorPackages || $this->deleteVendorFiles || trim($this->targetDirectory, '\\/') === 'vendor';
    }

    public function getProjectDirectory(): string
    {
        $projectDirectory = rtrim(FileSystem::normalizeDirSeparator($this->projectDirectory ?? getcwd()), '\\/');

        return $this->isDryRun()
            ? 'mem://' . ltrim($projectDirectory, '/')
            : $projectDirectory;
    }
}


================================================
FILE: src/Composer/ProjectComposerPackage.php
================================================
<?php
/**
 * Extends ComposerPackage to return the typed Strauss config.
 */

namespace BrianHenryIE\Strauss\Composer;

use BrianHenryIE\Strauss\Composer\Extra\StraussConfig;
use BrianHenryIE\Strauss\Helpers\FileSystem;
use Composer\Factory;
use Composer\IO\NullIO;

class ProjectComposerPackage extends ComposerPackage
{
    protected string $author;

    protected string $relativeVendorDirectory;

    /**
     * @param string $absolutePathFile
     * @param ?array{files?:array<string>,classmap?:array<string>,"psr-4"?:array<string,string|array<string>>} $overrideAutoload
     */
    public function __construct(string $absolutePathFile, ?array $overrideAutoload = null)
    {
        $composer = Factory::create(new NullIO(), $absolutePathFile, true);

        parent::__construct($composer, $overrideAutoload);

        $authors = $this->composer->getPackage()->getAuthors();
        if (empty($authors) || !isset($authors[0]['name'])) {
            $this->author = explode("/", $this->packageName, 2)[0];
        } else {
            $this->author = $authors[0]['name'];
        }

        /** @var ?string $projectVendorAbsoluteDirectoryPath */
        $projectVendorAbsoluteDirectoryPath = $this->composer->getConfig()->get('vendor-dir');
        $this->relativeVendorDirectory = is_string($projectVendorAbsoluteDirectoryPath) && !empty($projectVendorAbsoluteDirectoryPath)
            ? ltrim(str_replace(
                FileSystem::normalizeDirSeparator(dirname($absolutePathFile)),
                '',
                FileSystem::normalizeDirSeparator($projectVendorAbsoluteDirectoryPath)
            ), '\\/')
            :  'vendor';
    }

    /**
     * @return StraussConfig
     * @throws \Exception
     */
    public function getStraussConfig(): StraussConfig
    {
        $config = new StraussConfig($this->composer);
        $config->setRelativeVendorDirectory($this->getRelativeVendorDirectory());
        return $config;
    }


    public function getAuthor(): string
    {
        return $this->author;
    }

    /**
     * Relative vendor directory with trailing slash.
     *
     * No leading or trailing slash
     */
    public function getRelativeVendorDirectory(): string
    {
        return trim($this->relativeVendorDirectory, '\\/');
    }

    /**
     * Get all values in the autoload key as a flattened array.
     *
     * @return string[]
     */
    public function getFlatAutoloadKey(): array
    {
        $autoload = $this->getAutoload();
        $values = [];
        array_walk_recursive(
            $autoload,
            function ($value, $key) use (&$values) {
                $values[] = $value;
            }
        );
        return $values;
    }
}


================================================
FILE: src/Config/AliasesConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface AliasesConfigInterface
{

    /**
     * The directory where the source files are located.
     *
     * absolute? relative?
     */
    public function getAbsoluteVendorDirectory(): string;

    /**
     * The directory where Strauss copied the files to.
     * absolute? relative?
     */
    public function getAbsoluteTargetDirectory(): string;

    public function isDryRun(): bool;

    public function isCreateAliases(): bool;

    public function getNamespacePrefix(): ?string;
}


================================================
FILE: src/Config/AutoloadConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

use BrianHenryIE\Strauss\Composer\ComposerPackage;

interface AutoloadConfigInterface
{

    /**
     * The directory where the source files are located.
     *
     * absolute? relative?
     */
    public function getAbsoluteVendorDirectory(): string;

    /**
     * The directory where Strauss copied the files to.
     * absolute.
     */
    public function getAbsoluteTargetDirectory(): string;

    public function getRelativeTargetDirectory(): string;

    public function isTargetDirectoryVendor(): bool;

    /**
     * The directory containing `composer.json`.
     */
    public function getProjectDirectory(): string;

    public function isClassmapOutput(): bool;

    public function isDryRun(): bool;

    public function isIncludeRootAutoload(): bool;

    public function getNamespacePrefix(): ?string;

    /**
     * @return array<string,ComposerPackage>
     */
    public function getPackagesToCopy(): array;

    /**
     * @return array<string,ComposerPackage>
     */
    public function getPackagesToPrefix(): array;
}


================================================
FILE: src/Config/AutoloadFilesEnumeratorConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface AutoloadFilesEnumeratorConfigInterface
{
    public function getAbsoluteVendorDirectory(): string;

    /**
     * @return string[]
     */
    public function getExcludePackagesFromPrefixing(): array;

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromPrefixing(): array;

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromPrefixing(): array;
   /**
     * @return string[]
     */
    public function getExcludePackagesFromCopy(): array;

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromCopy(): array;

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromCopy(): array;
}


================================================
FILE: src/Config/ChangeEnumeratorConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

use BrianHenryIE\Strauss\Composer\ComposerPackage;

interface ChangeEnumeratorConfigInterface
{
    /**
     * @return string[]
     */
    public function getExcludePackagesFromPrefixing(): array;

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromPrefixing(): array;

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromPrefixing(): array;

    /**
     * @return array<string, string>
     */
    public function getNamespaceReplacementPatterns(): array;

    public function getNamespacePrefix(): ?string;

    public function getClassmapPrefix(): ?string;

    /**
     * @return array<string,ComposerPackage>
     */
    public function getPackagesToPrefix(): array;

    /**
     * The prefix to use for global functions. Null if none should be used.
     */
    public function getFunctionsPrefix(): ?string;
}


================================================
FILE: src/Config/CleanupConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface CleanupConfigInterface
{
    public function getAbsoluteVendorDirectory(): string;

    public function isTargetDirectoryVendor(): bool;

    public function isDeleteVendorFiles(): bool;

    public function isDeleteVendorPackages(): bool;

    public function getAbsoluteTargetDirectory(): string;

    public function isDryRun(): bool;

    /**
     * The directory containing `composer.json`.
     */
    public function getProjectDirectory(): string;

    /**
     * Packages to exclude from copying (and therefore from deletion).
     *
     * @return string[]
     */
    public function getExcludePackagesFromCopy(): array;
}


================================================
FILE: src/Config/CopierConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface CopierConfigInterface
{

    public function getAbsoluteTargetDirectory(): string;
}


================================================
FILE: src/Config/FileCopyScannerConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface FileCopyScannerConfigInterface
{

    public function getAbsoluteVendorDirectory(): string;

    public function isTargetDirectoryVendor(): bool;

    /**
     * @return string[]
     */
    public function getExcludePackagesFromCopy(): array;

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromCopy(): array;

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromCopy(): array;

    public function isDeleteVendorFiles(): bool;

    public function getAbsoluteTargetDirectory(): string;
}


================================================
FILE: src/Config/FileEnumeratorConfig.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface FileEnumeratorConfig
{

    public function getAbsoluteVendorDirectory(): string;

    public function getAbsoluteTargetDirectory(): string;

    public function getRelativeTargetDirectory(): string;

    /** @return string[] */
    public function getExcludeNamespacesFromCopy(): array;

    /** @return string[] */
    public function getExcludePackagesFromCopy(): array;

    /** @return string[] */
    public function getExcludeFilePatternsFromCopy(): array;
}


================================================
FILE: src/Config/FileSymbolScannerConfigInterface.php
================================================
<?php
/**
 * @see \BrianHenryIE\Strauss\Composer\Extra\StraussConfig
 */

namespace BrianHenryIE\Strauss\Config;

use BrianHenryIE\Strauss\Composer\ComposerPackage;

interface FileSymbolScannerConfigInterface
{
    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromPrefixing(): array;

    /**
     * @return array<string,ComposerPackage>
     */
    public function getPackagesToPrefix(): array;

    /**
     * Just for shortening paths to relative paths for logging.
     */
    public function getProjectDirectory(): string;
}


================================================
FILE: src/Config/LicenserConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface LicenserConfigInterface
{
    public function isIncludeModifiedDate(): bool;

    public function isIncludeAuthor(): bool;

    /**
     * The directory where Strauss copied the files to.
     * absolute.
     */
    public function getAbsoluteTargetDirectory(): string;

    /**
     * The directory where the source files are located.
     *
     * absolute.
     */
    public function getAbsoluteVendorDirectory(): string;
}


================================================
FILE: src/Config/MarkSymbolsForRenamingConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface MarkSymbolsForRenamingConfigInterface
{
    public function getAbsoluteVendorDirectory(): string;

    public function getAbsoluteTargetDirectory(): string;

    public function isTargetDirectoryVendor(): bool;

    /**
     * @return string[]
     */
    public function getExcludePackagesFromPrefixing(): array;

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromPrefixing(): array;

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromPrefixing(): array;

   /**
     * @return string[]
     */
    public function getExcludePackagesFromCopy(): array;

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromCopy(): array;

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromCopy(): array;

    /**
     * Config: extra.strauss.exclude_constants – applied only to constants.
     *
     * @return string[]
     */
    public function getExcludePackagesFromConstantPrefixing(): array;

    /**
     * @return string[]
     */
    public function getExcludeNamespacesFromConstantPrefixing(): array;

    /**
     * @return string[]
     */
    public function getExcludeFilePatternsFromConstantPrefixing(): array;

    /**
     * Explicit constant names to never prefix (e.g. WP_PLUGIN_DIR, ABSPATH).
     *
     * @return string[]
     */
    public function getExcludeConstantNames(): array;
}


================================================
FILE: src/Config/OptimizeAutoloaderConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface OptimizeAutoloaderConfigInterface
{
    public function isOptimizeAutoloader(): bool;
}


================================================
FILE: src/Config/PrefixerConfigInterface.php
================================================
<?php

namespace BrianHenryIE\Strauss\Config;

interface PrefixerConfigInterface
{
    public function getAbsoluteVendorDirectory(): string;

    public function getAbsoluteTargetDirectory(): string;

    public function isTargetDirectoryVendor(): bool;

    public function getNamespacePrefix(): ?string;

    public function getClassmapPrefix(): ?string;

    public function getConstantsPrefix(): ?string;

    /** @return string[] */
    public function getExcludePackagesFromPrefixing(): array;

    /** @return string[] */
    public function getExcludeNamespacesFromPrefixing(): array;

    /** @return string[] */
    public function getExcludeFilePatternsFromPrefixing(): array;
}


================================================
FILE: src/Console/Application.php
================================================
<?php

namespace BrianHenryIE\Strauss\Console;

use BrianHenryIE\Strauss\Console\Commands\DependenciesCommand;
use BrianHenryIE\Strauss\Console\Commands\IncludeAutoloaderCommand;
use BrianHenryIE\Strauss\Console\Commands\ReplaceCommand;
use Symfony\Component\Console\Application as BaseApplication;

class Application extends BaseApplication
{
    /**
     * @param string $version
     */
    public function __construct(string $version)
    {
        parent::__construct('strauss', $version);

        $composeCommand = new DependenciesCommand();
        $this->add($composeCommand);

        $replaceCommand = new ReplaceCommand();
        $this->add($replaceCommand);

        $this->add(new IncludeAutoloaderCommand());

        $this->setDefaultCommand('dependencies');
    }
}


================================================
FILE: src/Console/Commands/AbstractRenamespacerCommand.php
================================================
<?php
/**
 * Log level, filesystem
 */

namespace BrianHenryIE\Strauss\Console\Commands;

use BrianHenryIE\Strauss\Composer\Extra\StraussConfig;
use BrianHenryIE\Strauss\Composer\ProjectComposerPackage;
use BrianHenryIE\Strauss\Helpers\FileSystem;
use BrianHenryIE\Strauss\Helpers\Log\PadColonColumnsLogProcessor;
use BrianHenryIE\Strauss\Helpers\Log\RelativeFilepathLogProcessor;
use BrianHenryIE\Strauss\Helpers\ReadOnlyFileSystem;
use Composer\InstalledVersions;
use Elazar\Flystream\FilesystemRegistry;
use Monolog\Handler\PsrHandler;
use Monolog\Logger;
use Monolog\Processor\PsrLogMessageProcessor;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use League\Flysystem\Config;
use League\Flysystem\Local\LocalFilesystemAdapter;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Psr\Log\NullLogger;
use Symfony\Component\Console\Logger\ConsoleLogger;

abstract class AbstractRenamespacerCommand extends Command
{
    use LoggerAwareTrait;

    /** No trailing slash */
    protected string $workingDir;

    /** @var FileSystem */
    protected Filesystem $filesystem;
    protected ProjectComposerPackage $projectComposerPackage;

    protected StraussConfig $config;

    /**
     * Set name and description, call parent class to add dry-run, verbosity options.
     *
     * @used-by \Symfony\Component\Console\Command\Command::__construct
     * @override {@see \Symfony\Component\Console\Command\Command::configure()} empty method.
     *
     * @return void
     */
    protected function configure()
    {
        $this->addOption(
            'dry-run',
            null,
            InputOption::VALUE_OPTIONAL,
            'Do not actually make any changes',
            false
        );

        $this->addOption(
            'info',
            null,
            InputOption::VALUE_OPTIONAL,
            'output level',
            false
        );

        $this->addOption(
            'debug',
            null,
            InputOption::VALUE_OPTIONAL,
            'output level',
            false
        );

        /** @var string $installedSymfonyVersion */
        $installedSymfonyVersion = InstalledVersions::getVersion('symfony/console');

        if (version_compare($installedSymfonyVersion, '7.2', '<')) {
            $this->addOption(
                'silent',
                's',
                InputOption::VALUE_OPTIONAL,
                'output level',
                false
            );
        }
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        if (!isset($this->config)) {
            $this->config = $this->createConfig($input);
        }

        if ($this->config->isDryRun()) {
            $this->filesystem =
                new FileSystem(
                    new ReadOnlyFileSystem(
                        $this->filesystem,
                        Filesystem::makePathNormalizer($this->workingDir)
                    ),
                    $this->workingDir
                );

            /** @var FilesystemRegistry $registry */
            $registry = \Elazar\Flystream\ServiceLocator::get(\Elazar\Flystream\FilesystemRegistry::class);

            // Register a file stream mem:// to handle file operations by third party libraries.
            // This exception handling probably doesn't matter in real life but does in unit tests.
            try {
                $registry->get('mem');
            } catch (\Exception $e) {
                $registry->register('mem', $this->filesystem);
            }
        }

        $logger = new Logger('logger');
        $logger->pushProcessor(new PsrLogMessageProcessor());
        $logger->pushProcessor(new RelativeFilepathLogProcessor($this->filesystem));
        $logger->pushProcessor(new PadColonColumnsLogProcessor());
        $logger->pushHandler(new PsrHandler($this->getLogger($input, $output)));
        $this->setLogger($logger);

        return Command::SUCCESS;
    }

    /**
     * Symfony hook that runs before execute(). Sets working directory, filesystem and logger.
     */
    protected function initialize(InputInterface $input, OutputInterface $output): void
    {
        $this->workingDir = getcwd() . '';

        if (!isset($this->filesystem)) {
            $localFilesystemAdapter = new LocalFilesystemAdapter(
                FileSystem::getFsRoot($this->workingDir),
                null,
                LOCK_EX,
                LocalFilesystemAdapter::SKIP_LINKS
            );

            $this->filesystem = new FileSystem(
                new \League\Flysystem\Filesystem(
                    $localFilesystemAdapter,
                    [
                        Config::OPTION_DIRECTORY_VISIBILITY => 'public',
                    ],
                    Filesystem::makePathNormalizer($this->workingDir)
                ),
                $this->workingDir
            );
        }

        if (method_exists($this, 'setLogger')) {
            $this->setLogger($this->getLogger($input, $output));
        }
    }

    /**
     * Build a logger honoring optional --info/--debug/--silent flags if present.
     */
    protected function getLogger(InputInterface $input, OutputInterface $output): LoggerInterface
    {
        // If a subclass has a config and it is a dry-run, increase verbosity
        $isDryRun = property_exists($this, 'config') && isset($this->config) && method_exists($this->config, 'isDryRun') && $this->config->isDryRun();

        // Who would want to dry-run without output?
        if (!$isDryRun && $input->hasOption('silent') && $input->getOption('silent') !== false) {
            return new NullLogger();
        }

        $logLevel = [LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL];

        if ($input->hasOption('info') && $input->getOption('info') !== false) {
            $logLevel[LogLevel::INFO] = OutputInterface::VERBOSITY_NORMAL;
        }

        if ($isDryRun || ($input->hasOption('debug') && $input->getOption('debug') !== false)) {
            $logLevel[LogLevel::INFO] = OutputInterface::VERBOSITY_NORMAL;
            $logLevel[LogLevel::DEBUG] = OutputInterface::VERBOSITY_NORMAL;
        }

        return new ConsoleLogger($output, $logLevel);
    }


    protected function createConfig(InputInterface $input): StraussConfig
    {
        return new StraussConfig();
    }
}


================================================
FILE: src/Console/Commands/DependenciesCommand.php
================================================
<?php

namespace BrianHenryIE\Strauss\Console\Commands;

use BrianHenryIE\Strauss\Composer\ComposerPackage;
use BrianHenryIE\Strauss\Composer\ProjectComposerPackage;
use BrianHenryIE\Strauss\Files\DiscoveredFiles;
use BrianHenryIE\Strauss\Files\File;
use BrianHenryIE\Strauss\Pipeline\Aliases\Aliases;
use BrianHenryIE\Strauss\Pipeline\Autoload;
use BrianHenryIE\Strauss\Pipeline\Autoload\VendorComposerAutoload;
use BrianHenryIE\Strauss\Pipeline\AutoloadedFilesEnumerator;
use BrianHenryIE\Strauss\Pipeline\ChangeEnumerator;
use BrianHenryIE\Strauss\Pipeline\Cleanup\Cleanup;
use BrianHenryIE\Strauss\Pipeline\Cleanup\InstalledJson;
use BrianHenryIE\Strauss\Pipeline\Copier;
use BrianHenryIE\Strauss\Pipeline\DependenciesEnumerator;
use BrianHenryIE\Strauss\Pipeline\FileCopyScanner;
use BrianHenryIE\Strauss\Pipeline\FileEnumerator;
use BrianHenryIE\Strauss\Pipeline\FileSymbolScanner;
use BrianHenryIE\Strauss\Pipeline\Licenser;
use BrianHenryIE\Strauss\Pipeline\MarkSymbolsForRenaming;
use BrianHenryIE\Strauss\Pipeline\Prefixer;
use BrianHenryIE\Strauss\Types\DiscoveredSymbols;
use BrianHenryIE\Strauss\Types\NamespaceSymbol;
use Composer\Factory;
use Exception;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class DependenciesCommand extends AbstractRenamespacerCommand
{
    /** @var Prefixer */
    protected Prefixer $replacer;

    protected DependenciesEnumerator $dependenciesEnumerator;

    /** @var array<string,ComposerPackage> */
    protected array $flatDependencyTree = [];

    /**
     * ArrayAccess of \BrianHenryIE\Strauss\File objects indexed by their path relative to the output target directory.
     *
     * Each object contains the file's relative and absolute paths, the package and autoloaders it came from,
     * and flags indicating should it / has it been copied / deleted etc.
     *
     */
    protected DiscoveredFiles $discoveredFiles;
    protected DiscoveredSymbols $discoveredSymbols;

    /**
     * Set name and description, add CLI arguments, call parent class to add dry-run, verbosity options.
     *
     * @used-by \Symfony\Component\Console\Command\Command::__construct
     * @override {@see \Symfony\Component\Console\Command\Command::configure()} empty method.
     *
     * @return void
     */
    protected function configure()
    {
        $this->setName('dependencies');
        $this->setDescription("Copy composer's `require` and prefix their namespace and classnames.");
        $this->setHelp('');

        $this->addOption(
            'updateCallSites',
            null,
            InputArgument::OPTIONAL,
            'Should replacements also be performed in project files? true|list,of,paths|false'
        );

        $this->addOption(
            'deleteVendorPackages',
            null,
            4,
            'Should original packages be deleted after copying? true|false',
            false
        );
        // Is there a nicer way to add aliases?
        $this->addOption(
            'delete_vendor_packages',
            null,
            4,
            '',
            false
        );

        parent::configure();
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     *
     * @return int
     * @see Command::execute()
     *
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        try {
            $this->logger->notice('Starting... '/** version */); // + PHP version

            $this->loadProjectComposerPackage();
            $this->loadConfigFromComposerJson();
            $this->updateConfigFromCli($input);

            parent::execute($input, $output);

            $this->buildDependencyList();

            $this->enumerateFiles();

            $this->discoveredSymbols = new DiscoveredSymbols();

            $this->enumeratePsr4Namespaces();
            $this->enumerateAutoloadedFiles();
            $this->scanFilesForSymbols();
            $this->analyseFilesToCopy();
            $this->markSymbolsForRenaming();
            $this->determineChanges();
            $this->copyFiles();

            $this->performReplacements();

            $this->performReplacementsInProjectFiles();

            $this->addLicenses();

            $this->cleanUp();

            $this->generateAutoloader();

            // After files have been deleted, we may need aliases.
            $this->generateAliasesFile();

            $this->logger->notice('Done');
        } catch (Exception $e) {
            $this->logger->error($e->getMessage());
            return Command::FAILURE;
        }

        return Command::SUCCESS;
    }

    /**
     * Load the project's composer package using the current working directory.
     *
     * @throws Exception
     */
    protected function loadProjectComposerPackage(): void
    {
        $this->logger->notice('Loading package...');

        $composerFilePath = $this->filesystem->makeAbsolute(
            $this->filesystem->normalizePath(
                $this->workingDir . '/' . Factory::getComposerFile()
            )
        );
        $defaultComposerFilePath = $this->filesystem->makeAbsolute($this->workingDir . '/composer.json');
        if ($composerFilePath !== $defaultComposerFilePath) {
            $this->logger->info('Using: ' . $composerFilePath);
        }

        $this->projectComposerPackage = new ProjectComposerPackage($composerFilePath);

        // TODO: Print the config that Strauss is using.
        // Maybe even highlight what is default config and what is custom config.
    }

    /**
     * Load Strauss config from the project's composer.json.
     */
    protected function loadConfigFromComposerJson(): void
    {
        $this->logger->notice('Loading composer.json config...');

        $this->config = $this->projectComposerPackage->getStraussConfig();
    }

    protected function updateConfigFromCli(InputInterface $input): void
    {
        $this->logger->notice('Loading cli config...');

        $this->config->updateFromCli($input);
    }

    /**
     * 2. Built flat list of packages and dependencies.
     *
     * 2.1 Initiate getting dependencies for the project composer.json.
     *
     * @see DependenciesCommand::flatDependencyTree
     */
    protected function buildDependencyList(): void
    {
        $this->logger->notice('Building dependency list...');

        $this->dependenciesEnumerator = new DependenciesEnumerator(
            $this->config,
            $this->filesystem,
            $this->logger
        );
        $this->flatDependencyTree = $this->dependenciesEnumerator->getAllDependencies();

        $this->config->setPackagesToCopy(
            array_filter($this->flatDependencyTree, function ($dependency) {
                return !in_array($dependency, $this->config->getExcludePackagesFromCopy());
            },
            ARRAY_FILTER_USE_KEY)
        );

        $this->config->setPackagesToPrefix(
            array_filter($this->flatDependencyTree, function ($dependency) {
                return !in_array($dependency, $this->config->getExcludePackagesFromPrefixing());
            },
            ARRAY_FILTER_USE_KEY)
        );

        foreach ($this->flatDependencyTree as $dependency) {
            // Sort of duplicating the logic above.
            $dependency->setCopy(
                !in_array($dependency->getPackageName(), $this->config->getExcludePackagesFromCopy())
            );

            if ($this->config->isDeleteVendorPackages()) {
                $dependency->setDelete(true);
            }
        }

        // TODO: Print the dependency tree that Strauss has determined.
    }


    protected function enumerateFiles(): void
    {
        $this->logger->notice('Enumerating files...');

        $fileEnumerator = new FileEnumerator(
            $this->config,
            $this->filesystem,
            $this->logger
        );

        $this->discoveredFiles = $fileEnumerator->compileFileListForDependencies($this->flatDependencyTree);
    }

    /**
     * TODO: currently this must run after ::determineChanges() so the discoveredSymbols object exists,
     * but logically it should run first.
     */
    protected function enumeratePsr4Namespaces(): void
    {
        foreach ($this->config->getPackagesToPrefix() as $package) {
            $autoloadKey = $package->getAutoload();
            if (! isset($autoloadKey['psr-4'])) {
                continue;
            }

            $psr4autoloadKey = $autoloadKey['psr-4'];
            $namespaces = array_keys($psr4autoloadKey);

            $file = new File($package->getPackageAbsolutePath() . '/composer.json', '/../composer.json');

            foreach ($namespaces as $namespace) {
                // TODO: log.
                $symbol = new NamespaceSymbol(
                    trim($namespace, '\\'),
                    $file,
                    '\\',
                    $package
                );
                // TODO: respect all config options.
//              $symbol->setReplacement($this->config->getNamespacePrefix() . '\\' . trim($namespace, '\\'));
                $this->discoveredSymbols->add($symbol);
            }
        }
    }

    protected function enumerateAutoloadedFiles(): void
    {
        $this->logger->notice('Enumerating autoload files...');

        $autoloadFilesEnumerator = new AutoloadedFilesEnumerator(
            $this->config,
            $this->filesystem,
            $this->logger
        );
        $autoloadFilesEnumerator->scanForAutoloadedFiles($this->flatDependencyTree);
    }

    protected function scanFilesForSymbols(): void
    {
        $this->logger->notice('Scanning files...');

        $fileSymbolScanner = new FileSymbolScanner(
            $this->config,
            $this->discoveredSymbols,
            $this->filesystem,
            $this->logger
        );

        $fileSymbolScanner->findInFiles($this->discoveredFiles);
    }

    protected function markSymbolsForRenaming(): void
    {

        $markSymbolsForRenaming = new MarkSymbolsForRenaming(
            $this->config,
            $this->filesystem,
            $this->logger
        );

        $markSymbolsForRenaming->scanSymbols($this->discoveredSymbols);
    }

    protected function determineChanges(): void
    {
        $this->logger->notice('Determining changes...');

        $changeEnumerator = new ChangeEnumerator(
            $this->config,
            $this->logger
        );
        $changeEnumerator->determineReplacements($this->discoveredSymbols);
    }

    protected function analyseFilesToCopy(): void
    {
        (new FileCopyScanner($this->config, $this->filesystem, $this->logger))->scanFiles($this->discoveredFiles);
    }

    protected function copyFiles(): void
    {

        if ($this->config->isTargetDirectoryVendor()) {
            // Nothing to do.
            return;
        }

        $this->logger->notice('Copying files...');

        $copier = new Copier(
            $this->discoveredFiles,
            $this->config,
            $this->filesystem,
            $this->logger
        );


        $copier->prepareTarget();
        $copier->copy();

        foreach ($this->flatDependencyTree as $package) {
            if ($package->isCopy()) {
                $package->setDidCopy(true);
            }
        }

        $installedJson = new InstalledJson(
            $this->config,
            $this->filesystem,
            $this->logger
        );
        $installedJson->copyInstalledJson();
    }


    // 5. Update namespaces and class names.
    // Replace references to updated namespaces and classnames throughout the dependencies.
    protected function performReplacements(): void
    {
        $this->logger->notice('Performing replacements...');

        $this->replacer = new Prefixer(
            $this->config,
            $this->filesystem,
            $this->logger
        );

        $this->replacer->replaceInFiles(
            $this->discoveredSymbols,
            $this->discoveredFiles->getFiles()
        );
    }

    protected function performReplacementsInProjectFiles(): void
    {
        // TODO: this doesn't do tests?!
        $relativeCallSitePaths =
            $this->config->getUpdateCallSites()
            ?? $this->projectComposerPackage->getFlatAutoloadKey();

        if (empty($relativeCallSitePaths)) {
            return;
        }

        $callSitePaths = array_map(
            fn($path) => $this->workingDir . '/' . $path,
            $relativeCallSitePaths
        );

        $projectReplace = new Prefixer(
            $this->config,
            $this->filesystem,
            $this->logger
        );

        $fileEnumerator = new FileEnumerator(
            $this->config,
            $this->filesystem,
            $this->logger
        );

        $projectFiles = $fileEnumerator->compileFileListForPaths($callSitePaths);

        $phpFiles = array_filter(
            $projectFiles->getFiles(),
            fn($file) => $file->isPhpFile()
        );

        $phpFilesAbsolutePaths = array_map(
            fn($file) => $file->getSourcePath(),
            $phpFiles
        );

        // TODO: Warn when a file that was specified is not found
        // $this->logger->warning('Expected file not found from project autoload: ' . $absolutePath);

        $projectReplace->replaceInProjectFiles($this->discoveredSymbols, $phpFilesAbsolutePaths);
    }

    protected function addLicenses(): void
    {
        $this->logger->notice('Adding licenses...');

        $author = $this->projectComposerPackage->getAuthor();

        $dependencies = $this->flatDependencyTree;

        $licenser = new Licenser(
            $this->config,
            $dependencies,
            $author,
            $this->filesystem,
            $this->logger
        );

        $licenser->copyLicenses();

        $modifiedFiles = $this->replacer->getModifiedFiles();
        $licenser->addInformationToUpdatedFiles($modifiedFiles);
    }

    /**
     * 6. Generate autoloader.
     */
    protected function generateAutoloader(): void
    {
        if (isset($this->projectComposerPackage->getAutoload()['classmap'])
            && in_array(
                $this->config->getAbsoluteTargetDirectory(),
                array_map(
                    fn(string $entry) => trim($entry, '\\/'),
                    $this->projectComposerPackage->getAutoload()['classmap']
                ),
                true
            )
        ) {
            $this->logger->notice('Skipping autoloader generation as target directory is in Composer classmap. Run `composer dump-autoload`.');
            return;
        }

        $this->logger->notice('Generating autoloader...');

        $allFilesAutoloaders = $this->dependenciesEnumerator->getAllFilesAutoloaders();
        $filesAutoloaders = array();
        foreach ($allFilesAutoloaders as $packageName => $packageFilesAutoloader) {
            if (in_array($packageName, $this->config->getExcludePackagesFromCopy())) {
                continue;
            }
            $filesAutoloaders[$packageName] = $packageFilesAutoloader;
        }

        $classmap = new Autoload(
            $this->config,
            $filesAutoloaders,
            $this->filesystem,
            $this->logger
        );

        $classmap->generate($this->flatDependencyTree, $this->discoveredSymbols);
    }

    /**
     * When namespaces are prefixed which are used by both require and require-dev dependencies,
     * the require-dev dependencies need class aliases specified to point to the new class names/namespaces.
     */
    protected function generateAliasesFile(): void
    {
        if (!$this->config->isCreateAliases()) {
            return;
        }

        $this->logger->notice('Generating aliases file...');

        $aliases = new Aliases(
            $this->config,
            $this->filesystem,
            $this->logger
        );
        $aliases->writeAliasesFileForSymbols($this->discoveredSymbols);

        $vendorComposerAutoload = new VendorComposerAutoload(
            $this->config,
            $this->filesystem,
            $this->logger
        );
        $vendorComposerAutoload->addAliasesFileToComposer();
        $vendorComposerAutoload->addVendorPrefixedAutoloadToVendorAutoload();
    }

    /**
     * 7.
     * Delete source files if desired.
     * Delete empty directories in destination.
     */
    protected function cleanUp(): void
    {

        $this->logger->notice('Cleaning up...');

        $cleanup = new Cleanup(
            $this->config,
            $this->filesystem,
            $this->logger
        );

        // This will check the config to check should it delete or not.
        $cleanup->deleteFiles($this->flatDependencyTree, $this->discoveredFiles);

        $cleanup->cleanupVendorInstalledJson($this->flatDependencyTree, $this->discoveredSymbols);
        if ($this->config->isDeleteVendorFiles() || $this->config->isDeleteVendorPackages()) {
            // Rebuild the autoloader after cleanup.
            // This is needed because cleanup may have deleted files that were in the autoloader.
            $cleanup->rebuildVendorAutoloader();
        }
    }
}


================================================
FILE: src/Console/Commands/IncludeAutoloaderCommand.php
================================================
<?php
/**
 * Adds ~`require_once 'autoload_aliases.php'` to `vendor/autoload.php`.
 *
 * During development, when running Strauss as a phar, i.e. outside Composer's autoloading, we need to ensure the
 * `autoload_aliases.php` file is loaded. This is injected into Composer's `vendor/autoload.php` when it is first
 * generated, but when `composer dump-autoload` is run, the change is lost. This command is intended to be run in
 * `post-dump-autoload` scripts in `composer.json` to ensure the aliases are loaded.
 *
 * This command DOES NOT generate the `autoload_aliases.php` files. It only inserts the `require` statement into
 * `vendor/autoload.php`.
 *
 * @package brianhenryie/strauss
 */

namespace BrianHenryIE\Strauss\Console\Commands;

use BrianHenryIE\Strauss\Composer\ProjectComposerPackage;
use BrianHenryIE\Strauss\Pipeline\Autoload\VendorComposerAutoload;
use Composer\Factory;
use Exception;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class IncludeAutoloaderCommand extends AbstractRenamespacerCommand
{
    use LoggerAwareTrait;

    /**
     * Set name and description, add CLI arguments, call parent class to add dry-run, verbosity options.
     *
     * @used-by \Symfony\Component\Console\Command\Command::__construct
     * @override {@see \Symfony\Component\Console\Command\Command::configure()} empty method.
     *
     * @return void
     */
    protected function configure()
    {
        $this->setName('include-autoloader');
        $this->setDescription("Adds `require autoload_aliases.php` and `require vendor-prefixed/autoload.php` to `vendor/autoload.php`.");

        parent::configure();
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     *
     * @see Command::execute()
     *
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        try {
            // Pipeline
            $this->loadProjectComposerPackage();
            $this->loadConfigFromComposerJson();

            parent::execute($input, $output);

            // TODO: check for `--no-dev` somewhere.

            $vendorComposerAutoload = new VendorComposerAutoload(
                $this->config,
                $this->filesystem,
                $this->logger
            );

            $vendorComposerAutoload->addAliasesFileToComposer();
            $vendorComposerAutoload->addVendorPrefixedAutoloadToVendorAutoload();
        } catch (Exception $e) {
            $this->logger->error($e->getMessage());

            return Command::FAILURE;
        }

        return Command::SUCCESS;
    }


    /**
     * 1. Load the composer.json.
     *
     * @throws Exception
     */
    protected function loadProjectComposerPackage(): void
    {
        $this->logger->notice('Loading package...');

        $this->projectComposerPackage = new ProjectComposerPackage($this->workingDir . '/' . Factory::getComposerFile());
    }

    protected function loadConfigFromComposerJson(): void
    {
        $this->logger->notice('Loading composer.json config...');

        $this->config = $this->projectComposerPackage->getStraussConfig();
    }
}


================================================
FILE: src/Console/Commands/ReplaceCommand.php
================================================
<?php
/**
 * Rename a namespace in files. (in-place renaming)
 *
 * strauss replace --from "YourCompany\\Project" --to "BrianHenryIE\\MyProject" --paths "includes,my-plugin.php"
 */

namespace BrianHenryIE\Strauss\Console\Commands;

use BrianHenryIE\Strauss\Composer\ComposerPackage;
use BrianHenryIE\Strauss\Composer\Extra\ReplaceConfigInterface;
use BrianHenryIE\Strauss\Files\DiscoveredFiles;
use BrianHenryIE\Strauss\Pipeline\AutoloadedFilesEnumerator;
use BrianHenryIE\Strauss\Pipeline\ChangeEnumerator;
use BrianHenryIE\Strauss\Pipeline\FileEnumerator;
use BrianHenryIE\Strauss\Pipeline\FileSymbolScanner;
use BrianHenryIE\Strauss\Pipeline\Licenser;
use BrianHenryIE\Strauss\Pipeline\MarkSymbolsForRenaming;
use BrianHenryIE\Strauss\Pipeline\Prefixer;
use BrianHenryIE\Strauss\Types\DiscoveredSymbols;
use Exception;
use Psr\Log\LoggerAwareTrait;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class ReplaceCommand extends AbstractRenamespacerCommand
{
    use LoggerAwareTrait;

    /** @var Prefixer */
    protected Prefixer $replacer;

    /** @var ComposerPackage[] */
    protected array $flatDependencyTree = [];

    /**
     * ArrayAccess of \BrianHenryIE\Strauss\File objects indexed by their path relative to the output target directory.
     *
     * Each object contains the file's relative and absolute paths, the package and autoloaders it came from,
     * and flags indicating should it / has it been copied / deleted etc.
     *
     */
    protected DiscoveredFiles $discoveredFiles;
    protected DiscoveredSymbols $discoveredSymbols;

    protected function getConfig(): ReplaceConfigInterface
    {
        return $this->config;
    }

    /**
     * Set name and description, add CLI arguments, call parent class to add dry-run, verbosity options.
     *
     * @used-by \Symfony\Component\Console\Command\Command::__construct
     * @override {@see \Symfony\Component\Console\Command\Command::configure()} empty method.
     *
     * @return void
     */
    protected function configure()
    {
        $this->setName('replace');
        $this->setDescription("Rename a namespace in files.");
        $this->setHelp('');

        $this->addOption(
            'from',
            null,
            InputArgument::OPTIONAL,
            'Original namespace'
        );

        $this->addOption(
            'to',
            null,
            InputArgument::OPTIONAL,
            'New namespace'
        );

        $this->addOption(
            'paths',
            null,
            InputArgument::OPTIONAL,
            'Comma separated list of files and directories to update. Default is the current working directory.',
            getcwd()
        );

        parent::configure();
    }

    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     *
     * @see Command::execute()
     *
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        try {
            // TODO: where?!
            parent::execute($input, $output);

            $this->updateConfigFromCli($input);
            // Pipeline

            $config = $this->getConfig();

            $this->discoveredSymbols = new DiscoveredSymbols();

            $this->enumerateFiles($config);

            $this->determineChanges($config);

            $this->performReplacements($config);

            $this->performReplacementsInProjectFiles($config);

            $this->addLicenses($config);
        } catch (Exception $e) {
            $this->logger->error($e->getMessage());

            return 1;
        }

        return Command::SUCCESS;
    }


    protected function updateConfigFromCli(InputInterface $input): void
    {
        $this->logger->notice('Loading cli config...');

        /** @var string $inputFrom */
        $inputFrom = $input->getOption('from');

        /** @var string $inputTo */
        $inputTo = $input->getOption('to');

        // TODO: validate input exists.

        // TODO:
        $this->config->setNamespaceReplacementPatterns([$inputFrom => $inputTo]);

        /** @var string $inputPaths */
        $inputPaths = $input->getOption('paths');
        $paths = explode(',', $inputPaths);

        $this->config->setUpdateCallSites($paths);
    }


    protected function enumerateFiles(ReplaceConfigInterface $config): void
    {
        $this->logger->info('Enumerating files...');
        $relativeUpdateCallSites = $config->getUpdateCallSites() ?? [];
        $updateCallSites = array_map(
            fn($path) => false !== strpos($path, $this->workingDir) ? $path : $this->workingDir . '/'.$path,
            $relativeUpdateCallSites
        );
        $fileEnumerator = new FileEnumerator($config, $this->filesystem, $this->logger);
        $this->discoveredFiles = $fileEnumerator->compileFileListForPaths($updateCallSites);
    }

    // 4. Determine namespace and classname changes
    protected function determineChanges(ReplaceConfigInterface $config): void
    {
        $this->logger->info('Determining changes...');

        $fileScanner = new FileSymbolScanner(
            $config,
            $this->discoveredSymbols,
            $this->filesystem
        );

        $fileScanner->findInFiles($this->discoveredFiles);

        $autoloadFilesEnumerator = new AutoloadedFilesEnumerator(
            $config,
            $this->filesystem,
            $this->logger
        );
        $autoloadFilesEnumerator->scanForAutoloadedFiles($this->flatDependencyTree);

        $markSymbolsForRenaming = new MarkSymbolsForRenaming(
            $this->config,
            $this->filesystem,
            $this->logger
        );
        $markSymbolsForRenaming->scanSymbols($this->discoveredSymbols);

        $changeEnumerator = new ChangeEnumerator(
            $config,
            $this->logger
        );
        $changeEnumerator->determineReplacements($this->discoveredSymbols);
    }

    // 5. Update namespaces and class names.
    // Replace references to updated namespaces and classnames throughout the dependencies.
    protected function performReplacements(ReplaceConfigInterface $config): void
    {
        $this->logger->info('Performing replacements...');

        $this->replacer = new Prefixer($config, $this->filesystem, $this->logger);

        $this->replacer->replaceInFiles($this->discoveredSymbols, $this->discoveredFiles->getFiles());
    }

    protected function performReplacementsInProjectFiles(ReplaceConfigInterface $config): void
    {

        $relativeCallSitePaths = $this->config->getUpdateCallSites();

        if (empty($relativeCallSitePaths)) {
            return;
        }

        $callSitePaths = array_map(
            fn($path) => false !== strpos($path, $this->workingDir) ? $path : $this->workingDir . '/'. $path,
            $relativeCallSitePaths
        );

        $projectReplace = new Prefixer($config, $this->filesystem, $this->logger);

        $fileEnumerator = new FileEnumerator(
            $config,
            $this->filesystem,
            $this->logger
        );

        $phpFilePaths = $fileEnumerator->compileFileListForPaths($callSitePaths);

        // TODO: Warn when a file that was specified is not found (during config validation).
        // $this->logger->warning('Expected file not found from project autoload: ' . $absolutePath);

        $phpFilesAbsolutePaths = array_map(
            fn($file) => $file->getSourcePath(),
            $phpFilePaths->getFiles()
        );

        $projectReplace->replaceInProjectFiles($this->discoveredSymbols, $phpFilesAbsolutePaths);
    }


    protected function addLicenses(ReplaceConfigInterface $config): void
    {
        $this->logger->info('Adding licenses...');

        $username = trim(shell_exec('git config user.name') ?: '');
        $email = trim(shell_exec('git config user.email') ?: '');

        if (!empty($username) && !empty($email)) {
            // e.g. "Brian Henry <BrianHenryIE@gmail.com>".
            $author = $username . ' <' . $email . '>';
        } else {
            // e.g. "brianhenry".
            $author = get_current_user();
        }

        // TODO: Update to use DiscoveredFiles
        $dependencies = $this->flatDependencyTree;
        $licenser = new Licenser($config, $dependencies, $author, $this->filesystem, $this->logger);

        $licenser->copyLicenses();

        $modifiedFiles = $this->replacer->getModifiedFiles();
        $licenser->addInformationToUpdatedFiles($modifiedFiles);
    }
}


================================================
FILE: src/Files/DiscoveredFiles.php
================================================
<?php

namespace BrianHenryIE\Strauss\Files;

class DiscoveredFiles
{
    /** @var array<string,FileBase|File|FileWithDependency> */
    protected array $files = [];

    public function add(FileBase $file): void
    {
        $this->files[$file->getSourcePath()] = $file;
    }

    /**
     * @return array<string,FileBase|File|FileWithDependency>
     */
    public function getFiles(): array
    {
        return $this->files;
    }

    /**
     * Fetch/check if a file exists in the discovered files.
     *
     * @param string $sourceAbsolutePath Full path to the file.
     */
    public function getFile(string $sourceAbsolutePath): ?FileBase
    {
        return $this->files[$sourceAbsolutePath] ?? null;
    }

    public function sort(): void
    {
        ksort($this->files);
    }
}


================================================
FILE: src/Files/File.php
================================================
<?php
/**
 * A file without a dependency means the project src files and the vendor/composer autoload files.
 */

namespace BrianHenryIE\Strauss\Files;

use BrianHenryIE\Strauss\Types\DiscoveredSymbol;

class File implements FileBase
{
    /**
     * @var string The absolute path to the file on disk.
     */
    protected string $sourceAbsolutePath;

    protected string $vendorRelativePath;

    /**
     * Should this file be copied to the target directory?
     */
    protected bool $doCopy = true;

    protected bool $isAutoloaded = false;

    /**
     * Should this file be deleted from the source directory?
     *
     * `null` means defer to the package's `isDelete` setting.
     */
    protected ?bool $doDelete = false;

    /** @var DiscoveredSymbol[] */
    protected array $discoveredSymbols = [];

    protected string $absoluteTargetPath;

    protected bool $didDelete = false;

    protected bool $doPrefix = false;

    public function __construct(string $sourceAbsolutePath, string $vendorRelativePath)
    {
        $this->sourceAbsolutePath = $sourceAbsolutePath;
        $this->vendorRelativePath = $vendorRelativePath;
    }

    public function getSourcePath(): string
    {
        return $this->sourceAbsolutePath;
    }

    public function isPhpFile(): bool
    {
        return substr($this->sourceAbsolutePath, -4) === '.php';
    }

    /**
     * Some combination of file copy exclusions and vendor-dir == target-dir
     *
     * @param bool $doCopy
     *
     * @return void
     */
    public function setDoCopy(bool $doCopy): void
    {
        $this->doCopy = $doCopy;
    }
    public function isDoCopy(): bool
    {
        return $this->doCopy;
    }

    public function setIsAutoloaded(bool $isAutoloaded): void
    {
        $this->isAutoloaded = $isAutoloaded;
    }

    public function isAutoloaded(): bool
    {
        return $this->isAutoloaded;
    }

    /**
     * Should symbols discovered in this file be prefixed. (i.e. class definitions etc., not usages)
     */
    public function setDoPrefix(bool $doPrefix): void
    {
        $this->doPrefix = $doPrefix;
    }

    /**
     * Is this correct? Is there ever a time that NO changes should be made to a file? I.e. another file would have its
     * namespace changed and it needs to be updated throughout.
     *
     * Is this really a Symbol level function?
     */
    public function isDoPrefix(): bool
    {
        return $this->doPrefix;
    }

    /**
     * Used to mark files that are symlinked as not-to-be-deleted.
     *
     * @param bool $doDelete
     */
    public function setDoDelete(bool $doDelete): void
    {
        $this->doDelete = $doDelete;
    }

    /**
     * Should file be deleted?
     *
     * NB: Also respect the "delete_vendor_files"|"delete_vendor_packages" settings.
     */
    public function isDoDelete(): bool
    {
        return (bool) $this->doDelete;
    }

    public function setDidDelete(bool $didDelete): void
    {
        $this->didDelete = $didDelete;
    }

    public function getDidDelete(): bool
    {
        return $this->didDelete;
    }

    public function addDiscoveredSymbol(DiscoveredSymbol $symbol): void
    {
        $this->discoveredSymbols[$symbol->getOriginalSymbol()] = $symbol;
    }

    /**
     * @return array<string, DiscoveredSymbol> The discovered symbols in the file, indexed by their original string name.
     */
    public function getDiscoveredSymbols(): array
    {
        return $this->discoveredSymbols;
    }

    public function setAbsoluteTargetPath(string $absoluteTargetPath): void
    {
        $this->absoluteTargetPath = $absoluteTargetPath;
    }

    /**
     * The target path to (maybe) copy the file to, and the target path to perform replacements in (which may be the
     * original path).
     */
    public function getAbsoluteTargetPath(): string
    {
        // TODO: Maybe this is a mistake and should better be an exception.
        return isset($this->absoluteTargetPath) ? $this->absoluteTargetPath : $this->sourceAbsolutePath;
    }

    protected bool $didUpdate = false;

    public function setDidUpdate(): void
    {
        $this->didUpdate = true;
    }

    public function getDidUpdate(): bool
    {
        return $this->didUpdate;
    }

    public function getVendorRelativePath(): string
    {
        return $this->vendorRelativePath;
    }
}


================================================
FILE: src/Files/FileBase.php
================================================
<?php

namespace BrianHenryIE\Strauss\Files;

use BrianHenryIE\Strauss\Types\DiscoveredSymbol;

interface FileBase
{

    public function getSourcePath(): string;

    public function getAbsoluteTargetPath(): string;

    public function setAbsoluteTargetPath(string $absoluteTargetPath): void;

    public function getVendorRelativePath(): string;

    public function isPhpFile(): bool;

    public function isAutoloaded(): bool;

    public function setDoCopy(bool $doCopy): void;

    public function isDoCopy(): bool;

    public function setDoPrefix(bool $doPrefix): void;

    public function isDoPrefix(): bool;

    /**
     * Used to mark files that are symlinked as not-to-be-deleted.
     *
     * @param bool $doDelete
     *
     * @return void
     */
    public function setDoDelete(bool $doDelete): void;

    /**
     * Should file be deleted?
     *
     * NB: Also respect the "delete_vendor_files"|"delete_vendor_packages" settings.
     */
    public function isDoDelete(): bool;

    public function setDidDelete(bool $didDelete): void;

    public function getDidDelete(): bool;

    public function setDidUpdate(): void;

    public function addDiscoveredSymbol(DiscoveredSymbol $symbol): void;

    /**
     * @return array<string, DiscoveredSymbol> The discovered symbols in the file, indexed by their original string name.
     */
    public function getDiscoveredSymbols(): array;
}


================================================
FILE: src/Files/FileWithDependency.php
================================================
<?php

namespace BrianHenryIE\Strauss\Files;

use BrianHenryIE\Strauss\Composer\ComposerPackage;
use BrianHenryIE\Strauss\Helpers\FileSystem;

class FileWithDependency extends File implements HasDependency
{

    /**
     * @var string The path to the file relative to the package root.
     */
    protected string $vendorRelativePath;

    protected string $packageRelativePath;

    /**
     * The project dependency that this file belongs to.
     */
    protected ComposerPackage $dependency;

    /**
     * @var string[] The autoloader types that this file is included in.
     */
    protected array $autoloaderTypes = [];

    public function __construct(ComposerPackage $dependency, string $vendorRelativePath, string $sourceAbsolutePath)
    {
        parent::__construct($sourceAbsolutePath, $vendorRelativePath);

        /** @var string $packageAbsolutePath */
        $packageAbsolutePath = $dependency->getPackageAbsolutePath();

        $this->vendorRelativePath = ltrim($vendorRelativePath, '/\\');
        $this->packageRelativePath = str_replace(
            FileSystem::normalizeDirSeparator($packageAbsolutePath),
            '',
            FileSystem::normalizeDirSeparator($sourceAbsolutePath)
        );

        $this->dependency         = $dependency;

        // Set this to null so we query the package's `isDelete` setting.
        $this->doDelete = null;

        $this->dependency->addFile($this);
    }

    public function getDependency(): ComposerPackage
    {
        return $this->dependency;
    }

    /**
     * The target path to (maybe) copy the file to, and the target path to perform replacements in (which may be the
     * original path).
     */

    /**
     * Record the autoloader it is found in. Which could be all of them.
     */
    public function addAutoloader(string $autoloaderType): void
    {
        $this->autoloaderTypes = array_unique(array_merge($this->autoloaderTypes, array($autoloaderType)));
    }

    public function isFilesAutoloaderFile(): bool
    {
        return in_array('files', $this->autoloaderTypes, true);
    }

    public function getPackageRelativePath(): string
    {
        return trim($this->packageRelativePath, '\\/');
    }

    public function isDoDelete(): bool
    {
        return $this->doDelete ?? $this->dependency->isDoDelete();
    }
}


================================================
FILE: src/Files/HasDependency.php
================================================
<?php

namespace BrianHenryIE\Strauss\Files;

use BrianHenryIE\Strauss\Composer\ComposerPackage;

interface HasDependency
{

    public function getDependency(): ComposerPackage;

    /**
     * Record the autoloader it is found in. Which could be all of them.
     */
    public function addAutoloader(string $autoloaderType): void;

    public function isFilesAutoloaderFile(): bool;
}


================================================
FILE: src/Helpers/FileSystem.php
================================================
<?php
/**
 * This class extends Flysystem's Filesystem class to add some additional functionality, particularly around
 * symlinks which are not supported by Flysystem.
 *
 * TODO: Delete and modify operations on files in symlinked directories should fail with a warning.
 *
 * @see https://github.com/thephpleague/flysystem/issues/599
 */

namespace BrianHenryIE\Strauss\Helpers;

use Elazar\Flystream\StripProtocolPathNormalizer;
use Exception;
use League\Flysystem\DirectoryListing;
use League\Flysystem\FileAttributes;
use League\Flysystem\FilesystemException;
use League\Flysystem\FilesystemOperator;
use League\Flysystem\FilesystemReader;
use League\Flysystem\PathNormalizer;
use League\Flysystem\PathPrefixer;
use League\Flysystem\StorageAttributes;

class FileSystem implements FilesystemOperator, FlysystemBackCompatInterface, PathNormalizer
{
    use FlysystemBackCompatTrait;

    protected FilesystemOperator $flysystem;

    protected PathNormalizer $normalizer;

    protected PathPrefixer $pathPrefixer;

    /** No trailing slash */
    protected string $workingDir;

    /**
     * TODO: maybe restrict the constructor to only accept a LocalFilesystemAdapter.
     *
     * TODO: Check are any of these methods unused
     *
     * @param FilesystemOperator $flysystem
     * @param string $workingDir
     * @param ?string $flysystemRoot In practice we always use the root of the drive which can be inferred from workingDir but that's not strictly required.
     */
    public function __construct(
        FilesystemOperator $flysystem,
        string $workingDir,
        ?string $flysystemRoot = null
    ) {
        $this->flysystem = $flysystem;

        $this->normalizer = self::makePathNormalizer($workingDir);

        $this->workingDir = $workingDir;

        $this->pathPrefixer = new PathPrefixer(
            $flysystemRoot ?? self::getFsRoot($workingDir),
            DIRECTORY_SEPARATOR
        );
    }

    public static function getFsRoot(?string $path = null): string
    {
        if (1 === preg_match('/^([a-zA-Z]+:[\\\\\/]|\/)/', $path ?? getcwd(), $output_array)) {
            return strtoupper($output_array[1]);
        }
        return '/';
    }

    public static function makePathNormalizer(string $workingDir): PathNormalizer
    {
        return new StripProtocolPathNormalizer(
            [
                'mem',
            ],
            new StripFsRootPathNormalizer(
                [
                    FileSystem::getFsRoot($workingDir),
                    Filesystem::getFsRoot(),
                    Filesystem::normalizeDirSeparator(FileSystem::getFsRoot()),
                    'c:\\',
                    'c:/',
                ]
            )
        );
    }

    /**
     * Normalize directory separators to forward slashes.
     *
     * PHP native functions (realpath, getcwd, dirname) return backslashes on Windows,
     * but Flysystem always uses forward slashes. This method ensures consistency.
     *
     * Accepts null to preserve original str_replace() behavior where null is treated as empty string.
     *
     * @param string|false|null $path
     */
    public static function normalizeDirSeparator($path, $slashTo = '/'): string
    {
        $slashFrom = $slashTo === '/' ? '\\' : '/';

        return str_replace($slashFrom, $slashTo, $path ?: '');
    }

    /**
     * @param string[] $fileAndDirPaths
     *
     * @return string[]
     * @throws FilesystemException
     */
    public function findAllFilesAbsolutePaths(array $fileAndDirPaths, bool $excludeDirectories = false): array
    {
        $files = [];

        foreach ($fileAndDirPaths as $path) {
            if (!$this->directoryExists($path)) {
                $files[] = $path;
                continue;
            }

            $directoryListing = $this->listContents(
                $path,
                FilesystemReader::LIST_DEEP
            );

            /** @var FileAttributes[] $fileAttributesArray */
            $fileAttributesArray = $directoryListing->toArray();


            $f = array_map(
                fn(StorageAttributes $attributes): string => $this->makeAbsolute($attributes->path()),
                $fileAttributesArray
            );

            if ($excludeDirectories) {
                $f = array_filter($f, fn($path) => !$this->directoryExists($path));
            }

            $files = array_merge($files, $f);
        }

        return $files;
    }

    /**
     * @throws FilesystemException
     */
    public function getAttributes(string $absolutePath): ?StorageAttributes
    {
        // TODO: check if `realpath()` is a bad idea here.
        $fileDirectory = realpath(dirname($absolutePath)) ?: dirname($absolutePath);

        $absolutePath = $this->normalizePath($absolutePath);

        // Unsupported symbolic link encountered at location //home
        // \League\Flysystem\SymbolicLinkEncountered
        $dirList = $this->listContents($fileDirectory)->toArray();
        foreach ($dirList as $file) { // TODO: use the generator.
            if ($file->path() === $absolutePath) {
                return $file;
            }
        }

        return null;
    }

    /**
     * @throws FilesystemException
     */
    public function exists(string $location): bool
    {
        return $this->fileExists($location)
               || $this->directoryExists($location)
               || false !== realpath($this->pathPrefixer->prefixPath($this->normalizePath($location)));
    }

    public function fileExists(string $location): bool
    {
        return $this->flysystem->fileExists(
            $this->normalizePath($location)
        );
    }

    public function read(string $location): string
    {
        return $this->flysystem->read(
            $this->normalizePath($location)
        );
    }

    public function readStream(string $location)
    {
        return $this->flysystem->readStream(
            $this->normalizePath($location)
        );
    }

    public function listContents(string $location, bool $deep = self::LIST_SHALLOW): DirectoryListing
    {
        return $this->flysystem->listContents(
            $this->normalizePath($location),
            $deep
        );
    }

    publi
Download .txt
gitextract_25c61qh9/

├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   └── bug_report.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── claude-code-review.yml
│       ├── claude.yml
│       ├── codecoverage.yml
│       ├── main.yml
│       ├── phpstan.yml
│       ├── release.yml
│       └── updateversionfromchangelog.yml
├── .gitignore
├── .phive/
│   └── phars.xml
├── .typos.toml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── bin/
│   └── strauss
├── bootstrap.php
├── composer.json
├── phive.phar.asc
├── phpcs.xml
├── phpstan-baseline.neon
├── phpstan.neon
├── phpunit.xml
├── scripts/
│   ├── createphar.sh
│   └── getbuiltinphp.php
├── src/
│   ├── Composer/
│   │   ├── ComposerPackage.php
│   │   ├── Extra/
│   │   │   ├── ReplaceConfigInterface.php
│   │   │   └── StraussConfig.php
│   │   └── ProjectComposerPackage.php
│   ├── Config/
│   │   ├── AliasesConfigInterface.php
│   │   ├── AutoloadConfigInterface.php
│   │   ├── AutoloadFilesEnumeratorConfigInterface.php
│   │   ├── ChangeEnumeratorConfigInterface.php
│   │   ├── CleanupConfigInterface.php
│   │   ├── CopierConfigInterface.php
│   │   ├── FileCopyScannerConfigInterface.php
│   │   ├── FileEnumeratorConfig.php
│   │   ├── FileSymbolScannerConfigInterface.php
│   │   ├── LicenserConfigInterface.php
│   │   ├── MarkSymbolsForRenamingConfigInterface.php
│   │   ├── OptimizeAutoloaderConfigInterface.php
│   │   └── PrefixerConfigInterface.php
│   ├── Console/
│   │   ├── Application.php
│   │   └── Commands/
│   │       ├── AbstractRenamespacerCommand.php
│   │       ├── DependenciesCommand.php
│   │       ├── IncludeAutoloaderCommand.php
│   │       └── ReplaceCommand.php
│   ├── Files/
│   │   ├── DiscoveredFiles.php
│   │   ├── File.php
│   │   ├── FileBase.php
│   │   ├── FileWithDependency.php
│   │   └── HasDependency.php
│   ├── Helpers/
│   │   ├── FileSystem.php
│   │   ├── FlysystemBackCompatInterface.php
│   │   ├── FlysystemBackCompatTrait.php
│   │   ├── InMemoryFilesystemAdapter.php
│   │   ├── Log/
│   │   │   ├── PadColonColumnsLogProcessor.php
│   │   │   └── RelativeFilepathLogProcessor.php
│   │   ├── NamespaceSort.php
│   │   ├── ReadOnlyFileSystem.php
│   │   └── StripFsRootPathNormalizer.php
│   ├── Pipeline/
│   │   ├── Aliases/
│   │   │   ├── Aliases.php
│   │   │   └── autoload_aliases.template.php
│   │   ├── Autoload/
│   │   │   ├── ComposerAutoloadGenerator.php
│   │   │   ├── DumpAutoload.php
│   │   │   └── VendorComposerAutoload.php
│   │   ├── Autoload.php
│   │   ├── AutoloadedFilesEnumerator.php
│   │   ├── ChangeEnumerator.php
│   │   ├── Cleanup/
│   │   │   ├── Cleanup.php
│   │   │   └── InstalledJson.php
│   │   ├── Copier.php
│   │   ├── DependenciesEnumerator.php
│   │   ├── FileCopyScanner.php
│   │   ├── FileEnumerator.php
│   │   ├── FileSymbol/
│   │   │   └── builtinsymbols.php
│   │   ├── FileSymbolScanner.php
│   │   ├── Licenser.php
│   │   ├── MarkSymbolsForRenaming.php
│   │   └── Prefixer.php
│   └── Types/
│       ├── AutoloadAliasInterface.php
│       ├── ClassSymbol.php
│       ├── ConstantSymbol.php
│       ├── DiscoveredSymbol.php
│       ├── DiscoveredSymbols.php
│       ├── FunctionSymbol.php
│       ├── InterfaceSymbol.php
│       ├── NamespaceSymbol.php
│       └── TraitSymbol.php
└── tests/
    ├── Integration/
    │   ├── Autoload/
    │   │   ├── DumpAutoloadFeatureTest.php
    │   │   └── VendorComposerAutoloadFeatureTest.php
    │   ├── ChangeEnumeratorIntegrationTest.php
    │   ├── Cleanup/
    │   │   ├── ExcludeFromCopyAutoloadIntegrationTest.php
    │   │   └── InstalledJsonIntegrationTest.php
    │   ├── CleanupIntegrationTest.php
    │   ├── CleanupSymlinkIntegrationTest.php
    │   ├── CopierFeatureTest.php
    │   ├── CopierIntegrationTest.php
    │   ├── DryRunFeatureTest.php
    │   ├── DumpAutoloadFeatureTest.php
    │   ├── ExcludeFromPrefixFeatureTest.php
    │   ├── FileCopyScannerIntegrationTest.php
    │   ├── FileEnumeratorIntegrationTest.php
    │   ├── Helpers/
    │   │   ├── FileSystemIntegrationTest.php
    │   │   ├── PadColonColumnsLogProcessorIntegrationTest.php
    │   │   └── ReadOnlyFileSystemIntegrationTest.php
    │   ├── OutputLevelFeatureTest.php
    │   ├── Pipeline/
    │   │   └── Aliases/
    │   │       └── AliasesFeatureTest.php
    │   ├── ReplaceCommandIntegrationTest.php
    │   ├── ReplacerIntegrationTest.php
    │   └── UpdateCallSitesIntegrationTest.php
    ├── IntegrationTestCase.php
    ├── Issues/
    │   ├── MozartIssue106Test.php
    │   ├── MozartIssue108Test.php
    │   ├── MozartIssue109Test.php
    │   ├── MozartIssue124Test.php
    │   ├── MozartIssue128Test.php
    │   ├── MozartIssue129Test.php
    │   ├── MozartIssue130Test.php
    │   ├── MozartIssue13Test.php
    │   ├── MozartIssue43Test.php
    │   ├── MozartIssue48Test.php
    │   ├── MozartIssue62Test.php
    │   ├── MozartIssue66Test.php
    │   ├── MozartIssue86Test.php
    │   ├── MozartIssue89Test.php
    │   ├── MozartIssue90Test.php
    │   ├── MozartIssue93Test.php
    │   ├── MozartIssue97Test.php
    │   ├── MozartIssue99Test.php
    │   ├── StraussIssue101Test.php
    │   ├── StraussIssue104Test.php
    │   ├── StraussIssue108Test.php
    │   ├── StraussIssue109Test.php
    │   ├── StraussIssue111Test.php
    │   ├── StraussIssue114Test.php
    │   ├── StraussIssue119Test.php
    │   ├── StraussIssue11Test.php
    │   ├── StraussIssue133Test.php
    │   ├── StraussIssue136Test.php
    │   ├── StraussIssue143Test.php
    │   ├── StraussIssue14Test.php
    │   ├── StraussIssue154Test.php
    │   ├── StraussIssue159Test.php
    │   ├── StraussIssue163Test.php
    │   ├── StraussIssue166Test.php
    │   ├── StraussIssue172Test.php
    │   ├── StraussIssue173Test.php
    │   ├── StraussIssue179Test.php
    │   ├── StraussIssue183Test.php
    │   ├── StraussIssue188Test.php
    │   ├── StraussIssue189Test.php
    │   ├── StraussIssue191Test.php
    │   ├── StraussIssue19Test.php
    │   ├── StraussIssue200Test.php
    │   ├── StraussIssue204Test.php
    │   ├── StraussIssue206Test.php
    │   ├── StraussIssue207Test.php
    │   ├── StraussIssue212Test.php
    │   ├── StraussIssue213Test.php
    │   ├── StraussIssue215Test.php
    │   ├── StraussIssue225Test.php
    │   ├── StraussIssue22Test.php
    │   ├── StraussIssue230Test.php
    │   ├── StraussIssue247Test.php
    │   ├── StraussIssue249Test.php
    │   ├── StraussIssue258Test.php
    │   ├── StraussIssue261Test.php
    │   ├── StraussIssue262Test.php
    │   ├── StraussIssue27Test.php
    │   ├── StraussIssue33Test.php
    │   ├── StraussIssue34Test.php
    │   ├── StraussIssue37Test.php
    │   ├── StraussIssue44Test.php
    │   ├── StraussIssue47Test.php
    │   ├── StraussIssue49Test.php
    │   ├── StraussIssue65Test.php
    │   ├── StraussIssue66Test.php
    │   ├── StraussIssue74Test.php
    │   ├── StraussIssue76Test.php
    │   ├── StraussIssue79Test.php
    │   ├── StraussIssue80Test.php
    │   ├── StraussIssue81Test.php
    │   ├── StraussIssue83Test.php
    │   ├── StraussIssue87Test.php
    │   ├── StraussIssue88Test.php
    │   ├── StraussIssue8Test.php
    │   ├── StraussIssue91Test.php
    │   ├── StraussIssue93Test.php
    │   └── data/
    │       └── Mpdf.php
    ├── TestCase.php
    └── Unit/
        ├── Composer/
        │   ├── ComposerPackageTest.php
        │   ├── Extra/
        │   │   └── StraussConfigTest.php
        │   ├── ProjectComposerPackageTest.php
        │   ├── composerpackage-test-easypost-php.json
        │   ├── composerpackage-test-libmergepdf.json
        │   ├── composerpackage-test-php-di.json
        │   ├── projectcomposerpackage-test-1.json
        │   └── projectcomposerpackage-test-getProjectPhpFiles.json
        ├── Console/
        │   ├── ApplicationTest.php
        │   └── Commands/
        │       └── DependenciesCommandTest.php
        ├── DiscoveredFilesTest.php
        ├── FileEnumeratorTest.php
        ├── Files/
        │   └── FileWithDependencyTest.php
        ├── Helpers/
        │   ├── FileSystemTest.php
        │   └── NamespaceSortTest.php
        ├── LicenserTest.php
        ├── Pipeline/
        │   ├── Aliases/
        │   │   └── AliasesTest.php
        │   ├── Autoload/
        │   │   ├── ComposerAutoloadGeneratorTest.php
        │   │   ├── DumpAutoloadTest.php
        │   │   └── VendorComposerAutoloadTest.php
        │   ├── AutoloadTest.php
        │   ├── ChangeEnumeratorTest.php
        │   ├── Cleanup/
        │   │   ├── CleanupTest.php
        │   │   └── InstalledJsonTest.php
        │   ├── CopierTest.php
        │   ├── FileCopyScannerTest.php
        │   ├── FileSymbolScannerTest.php
        │   └── MarkSymbolsForRenamingTest.php
        ├── PrefixerTest.php
        └── Types/
            ├── DiscoveredSymbolTest.php
            └── DiscoveredSymbolsTest.php
Download .txt
SYMBOL INDEX (1480 symbols across 191 files)

FILE: src/Composer/ComposerPackage.php
  class ComposerPackage (line 24) | class ComposerPackage
    method fromFile (line 106) | public static function fromFile(string $absolutePath, ?array $override...
    method fromComposerJsonArray (line 120) | public static function fromComposerJsonArray(array $jsonArray, ?array ...
    method __construct (line 136) | public function __construct(Composer $composer, ?array $overrideAutolo...
    method getPackageName (line 198) | public function getPackageName(): string
    method getRelativePath (line 206) | public function getRelativePath(): ?string
    method getPackageAbsolutePath (line 215) | public function getPackageAbsolutePath(): ?string
    method getAutoload (line 229) | public function getAutoload(): array
    method getRequiresNames (line 241) | public function getRequiresNames(): array
    method getLicense (line 251) | public function getLicense():string
    method setCopy (line 259) | public function setCopy(bool $isCopy): void
    method isCopy (line 267) | public function isCopy(): bool
    method setDidCopy (line 275) | public function setDidCopy(bool $didCopy): void
    method didCopy (line 283) | public function didCopy(): bool
    method setDelete (line 291) | public function setDelete(bool $isDelete): void
    method isDoDelete (line 299) | public function isDoDelete(): bool
    method setDidDelete (line 307) | public function setDidDelete(bool $didDelete): void
    method didDelete (line 315) | public function didDelete(): bool
    method addFile (line 320) | public function addFile(FileWithDependency $file): void
    method getFile (line 325) | public function getFile(string $path): ?FileWithDependency

FILE: src/Composer/Extra/ReplaceConfigInterface.php
  type ReplaceConfigInterface (line 12) | interface ReplaceConfigInterface extends
    method getExcludeFilePatternsFromPrefixing (line 24) | public function getExcludeFilePatternsFromPrefixing(): array;
    method getNamespaceReplacementPatterns (line 29) | public function getNamespaceReplacementPatterns(): array;
    method isIncludeModifiedDate (line 31) | public function isIncludeModifiedDate(): bool;
    method isIncludeAuthor (line 33) | public function isIncludeAuthor(): bool;
    method getUpdateCallSites (line 38) | public function getUpdateCallSites(): ?array;

FILE: src/Composer/Extra/StraussConfig.php
  class StraussConfig (line 33) | class StraussConfig implements
    method __construct (line 220) | public function __construct(?Composer $composer = null)
    method getAbsoluteTargetDirectory (line 363) | public function getAbsoluteTargetDirectory(): string
    method isTargetDirectoryVendor (line 370) | public function isTargetDirectoryVendor(): bool
    method getRelativeTargetDirectory (line 378) | public function getRelativeTargetDirectory(): string
    method setTargetDirectory (line 388) | public function setTargetDirectory(string $targetDirectory): void
    method getAbsoluteVendorDirectory (line 396) | public function getAbsoluteVendorDirectory(): string
    method setRelativeVendorDirectory (line 404) | public function setRelativeVendorDirectory(string $relativeVendorDirec...
    method getNamespacePrefix (line 412) | public function getNamespacePrefix(): ?string
    method setNamespacePrefix (line 420) | public function setNamespacePrefix(string $namespacePrefix): void
    method getClassmapPrefix (line 428) | public function getClassmapPrefix(): ?string
    method setClassmapPrefix (line 436) | public function setClassmapPrefix(string $classmapPrefix): void
    method getFunctionsPrefix (line 441) | public function getFunctionsPrefix(): ?string
    method setFunctionsPrefix (line 458) | public function setFunctionsPrefix($functionsPrefix): void
    method getConstantsPrefix (line 466) | public function getConstantsPrefix(): ?string
    method setConstantsPrefix (line 474) | public function setConstantsPrefix(string $constantsPrefix): void
    method getUpdateCallSites (line 484) | public function getUpdateCallSites(): ?array
    method setUpdateCallSites (line 493) | public function setUpdateCallSites($updateCallSites): void
    method setExcludeFromCopy (line 515) | public function setExcludeFromCopy(array $excludeFromCopy): void
    method getExcludePackagesFromCopy (line 527) | public function getExcludePackagesFromCopy(): array
    method getExcludeNamespacesFromCopy (line 535) | public function getExcludeNamespacesFromCopy(): array
    method getExcludeFilePatternsFromCopy (line 543) | public function getExcludeFilePatternsFromCopy(): array
    method setExcludeFromPrefix (line 551) | public function setExcludeFromPrefix(array $excludeFromPrefix): void
    method getExcludePackagesFromPrefixing (line 569) | public function getExcludePackagesFromPrefixing(): array
    method setExcludePackagesFromPrefixing (line 577) | public function setExcludePackagesFromPrefixing(array $excludePackages...
    method getExcludeNamespacesFromPrefixing (line 585) | public function getExcludeNamespacesFromPrefixing(): array
    method getExcludeFilePatternsFromPrefixing (line 596) | public function getExcludeFilePatternsFromPrefixing(): array
    method setExcludeConstants (line 604) | public function setExcludeConstants(array $excludeConstants): void
    method getExcludePackagesFromConstantPrefixing (line 623) | public function getExcludePackagesFromConstantPrefixing(): array
    method getExcludeNamespacesFromConstantPrefixing (line 631) | public function getExcludeNamespacesFromConstantPrefixing(): array
    method getExcludeFilePatternsFromConstantPrefixing (line 642) | public function getExcludeFilePatternsFromConstantPrefixing(): array
    method getExcludeConstantNames (line 650) | public function getExcludeConstantNames(): array
    method getOverrideAutoload (line 658) | public function getOverrideAutoload(): array
    method setOverrideAutoload (line 666) | public function setOverrideAutoload(array $overrideAutoload): void
    method isDeleteVendorFiles (line 674) | public function isDeleteVendorFiles(): bool
    method isDeleteVendorPackages (line 682) | public function isDeleteVendorPackages(): bool
    method setDeleteVendorFiles (line 690) | public function setDeleteVendorFiles(bool $deleteVendorFiles): void
    method setDeleteVendorPackages (line 698) | public function setDeleteVendorPackages(bool $deleteVendorPackages): void
    method getPackages (line 706) | public function getPackages(): array
    method setPackages (line 714) | public function setPackages(array $packages): void
    method getPackagesToCopy (line 723) | public function getPackagesToCopy(): array
    method setPackagesToCopy (line 733) | public function setPackagesToCopy(array $packagesToCopy): void
    method getPackagesToPrefix (line 741) | public function getPackagesToPrefix(): array
    method setPackagesToPrefix (line 749) | public function setPackagesToPrefix(array $packagesToPrefix): void
    method isClassmapOutput (line 756) | public function isClassmapOutput(): bool
    method setClassmapOutput (line 764) | public function setClassmapOutput(bool $classmapOutput): void
    method setExcludePackages (line 774) | public function setExcludePackages(array $excludePackages): void
    method getNamespaceReplacementPatterns (line 782) | public function getNamespaceReplacementPatterns(): array
    method setNamespaceReplacementPatterns (line 790) | public function setNamespaceReplacementPatterns(array $namespaceReplac...
    method isIncludeModifiedDate (line 798) | public function isIncludeModifiedDate(): bool
    method setIncludeModifiedDate (line 806) | public function setIncludeModifiedDate(bool $includeModifiedDate): void
    method isIncludeAuthor (line 815) | public function isIncludeAuthor(): bool
    method setIncludeAuthor (line 823) | public function setIncludeAuthor(bool $includeAuthor): void
    method isDryRun (line 831) | public function isDryRun(): bool
    method setDryRun (line 839) | public function setDryRun(bool $dryRun): void
    method isIncludeRootAutoload (line 847) | public function isIncludeRootAutoload(): bool
    method isOptimizeAutoloader (line 852) | public function isOptimizeAutoloader(): bool
    method setIncludeRootAutoload (line 860) | public function setIncludeRootAutoload(bool $includeRootAutoload): void
    method setOptimizeAutoloader (line 865) | public function setOptimizeAutoloader(bool $optimizeAutoloader): void
    method updateFromCli (line 873) | public function updateFromCli(InputInterface $input): void
    method isCreateAliases (line 918) | public function isCreateAliases(): bool
    method getProjectDirectory (line 923) | public function getProjectDirectory(): string

FILE: src/Composer/ProjectComposerPackage.php
  class ProjectComposerPackage (line 13) | class ProjectComposerPackage extends ComposerPackage
    method __construct (line 23) | public function __construct(string $absolutePathFile, ?array $override...
    method getStraussConfig (line 51) | public function getStraussConfig(): StraussConfig
    method getAuthor (line 59) | public function getAuthor(): string
    method getRelativeVendorDirectory (line 69) | public function getRelativeVendorDirectory(): string
    method getFlatAutoloadKey (line 79) | public function getFlatAutoloadKey(): array

FILE: src/Config/AliasesConfigInterface.php
  type AliasesConfigInterface (line 5) | interface AliasesConfigInterface
    method getAbsoluteVendorDirectory (line 13) | public function getAbsoluteVendorDirectory(): string;
    method getAbsoluteTargetDirectory (line 19) | public function getAbsoluteTargetDirectory(): string;
    method isDryRun (line 21) | public function isDryRun(): bool;
    method isCreateAliases (line 23) | public function isCreateAliases(): bool;
    method getNamespacePrefix (line 25) | public function getNamespacePrefix(): ?string;

FILE: src/Config/AutoloadConfigInterface.php
  type AutoloadConfigInterface (line 7) | interface AutoloadConfigInterface
    method getAbsoluteVendorDirectory (line 15) | public function getAbsoluteVendorDirectory(): string;
    method getAbsoluteTargetDirectory (line 21) | public function getAbsoluteTargetDirectory(): string;
    method getRelativeTargetDirectory (line 23) | public function getRelativeTargetDirectory(): string;
    method isTargetDirectoryVendor (line 25) | public function isTargetDirectoryVendor(): bool;
    method getProjectDirectory (line 30) | public function getProjectDirectory(): string;
    method isClassmapOutput (line 32) | public function isClassmapOutput(): bool;
    method isDryRun (line 34) | public function isDryRun(): bool;
    method isIncludeRootAutoload (line 36) | public function isIncludeRootAutoload(): bool;
    method getNamespacePrefix (line 38) | public function getNamespacePrefix(): ?string;
    method getPackagesToCopy (line 43) | public function getPackagesToCopy(): array;
    method getPackagesToPrefix (line 48) | public function getPackagesToPrefix(): array;

FILE: src/Config/AutoloadFilesEnumeratorConfigInterface.php
  type AutoloadFilesEnumeratorConfigInterface (line 5) | interface AutoloadFilesEnumeratorConfigInterface
    method getAbsoluteVendorDirectory (line 7) | public function getAbsoluteVendorDirectory(): string;
    method getExcludePackagesFromPrefixing (line 12) | public function getExcludePackagesFromPrefixing(): array;
    method getExcludeFilePatternsFromPrefixing (line 17) | public function getExcludeFilePatternsFromPrefixing(): array;
    method getExcludeNamespacesFromPrefixing (line 22) | public function getExcludeNamespacesFromPrefixing(): array;
    method getExcludePackagesFromCopy (line 26) | public function getExcludePackagesFromCopy(): array;
    method getExcludeFilePatternsFromCopy (line 31) | public function getExcludeFilePatternsFromCopy(): array;
    method getExcludeNamespacesFromCopy (line 36) | public function getExcludeNamespacesFromCopy(): array;

FILE: src/Config/ChangeEnumeratorConfigInterface.php
  type ChangeEnumeratorConfigInterface (line 7) | interface ChangeEnumeratorConfigInterface
    method getExcludePackagesFromPrefixing (line 12) | public function getExcludePackagesFromPrefixing(): array;
    method getExcludeFilePatternsFromPrefixing (line 17) | public function getExcludeFilePatternsFromPrefixing(): array;
    method getExcludeNamespacesFromPrefixing (line 22) | public function getExcludeNamespacesFromPrefixing(): array;
    method getNamespaceReplacementPatterns (line 27) | public function getNamespaceReplacementPatterns(): array;
    method getNamespacePrefix (line 29) | public function getNamespacePrefix(): ?string;
    method getClassmapPrefix (line 31) | public function getClassmapPrefix(): ?string;
    method getPackagesToPrefix (line 36) | public function getPackagesToPrefix(): array;
    method getFunctionsPrefix (line 41) | public function getFunctionsPrefix(): ?string;

FILE: src/Config/CleanupConfigInterface.php
  type CleanupConfigInterface (line 5) | interface CleanupConfigInterface
    method getAbsoluteVendorDirectory (line 7) | public function getAbsoluteVendorDirectory(): string;
    method isTargetDirectoryVendor (line 9) | public function isTargetDirectoryVendor(): bool;
    method isDeleteVendorFiles (line 11) | public function isDeleteVendorFiles(): bool;
    method isDeleteVendorPackages (line 13) | public function isDeleteVendorPackages(): bool;
    method getAbsoluteTargetDirectory (line 15) | public function getAbsoluteTargetDirectory(): string;
    method isDryRun (line 17) | public function isDryRun(): bool;
    method getProjectDirectory (line 22) | public function getProjectDirectory(): string;
    method getExcludePackagesFromCopy (line 29) | public function getExcludePackagesFromCopy(): array;

FILE: src/Config/CopierConfigInterface.php
  type CopierConfigInterface (line 5) | interface CopierConfigInterface
    method getAbsoluteTargetDirectory (line 8) | public function getAbsoluteTargetDirectory(): string;

FILE: src/Config/FileCopyScannerConfigInterface.php
  type FileCopyScannerConfigInterface (line 5) | interface FileCopyScannerConfigInterface
    method getAbsoluteVendorDirectory (line 8) | public function getAbsoluteVendorDirectory(): string;
    method isTargetDirectoryVendor (line 10) | public function isTargetDirectoryVendor(): bool;
    method getExcludePackagesFromCopy (line 15) | public function getExcludePackagesFromCopy(): array;
    method getExcludeNamespacesFromCopy (line 20) | public function getExcludeNamespacesFromCopy(): array;
    method getExcludeFilePatternsFromCopy (line 25) | public function getExcludeFilePatternsFromCopy(): array;
    method isDeleteVendorFiles (line 27) | public function isDeleteVendorFiles(): bool;
    method getAbsoluteTargetDirectory (line 29) | public function getAbsoluteTargetDirectory(): string;

FILE: src/Config/FileEnumeratorConfig.php
  type FileEnumeratorConfig (line 5) | interface FileEnumeratorConfig
    method getAbsoluteVendorDirectory (line 8) | public function getAbsoluteVendorDirectory(): string;
    method getAbsoluteTargetDirectory (line 10) | public function getAbsoluteTargetDirectory(): string;
    method getRelativeTargetDirectory (line 12) | public function getRelativeTargetDirectory(): string;
    method getExcludeNamespacesFromCopy (line 15) | public function getExcludeNamespacesFromCopy(): array;
    method getExcludePackagesFromCopy (line 18) | public function getExcludePackagesFromCopy(): array;
    method getExcludeFilePatternsFromCopy (line 21) | public function getExcludeFilePatternsFromCopy(): array;

FILE: src/Config/FileSymbolScannerConfigInterface.php
  type FileSymbolScannerConfigInterface (line 10) | interface FileSymbolScannerConfigInterface
    method getExcludeNamespacesFromPrefixing (line 15) | public function getExcludeNamespacesFromPrefixing(): array;
    method getPackagesToPrefix (line 20) | public function getPackagesToPrefix(): array;
    method getProjectDirectory (line 25) | public function getProjectDirectory(): string;

FILE: src/Config/LicenserConfigInterface.php
  type LicenserConfigInterface (line 5) | interface LicenserConfigInterface
    method isIncludeModifiedDate (line 7) | public function isIncludeModifiedDate(): bool;
    method isIncludeAuthor (line 9) | public function isIncludeAuthor(): bool;
    method getAbsoluteTargetDirectory (line 15) | public function getAbsoluteTargetDirectory(): string;
    method getAbsoluteVendorDirectory (line 22) | public function getAbsoluteVendorDirectory(): string;

FILE: src/Config/MarkSymbolsForRenamingConfigInterface.php
  type MarkSymbolsForRenamingConfigInterface (line 5) | interface MarkSymbolsForRenamingConfigInterface
    method getAbsoluteVendorDirectory (line 7) | public function getAbsoluteVendorDirectory(): string;
    method getAbsoluteTargetDirectory (line 9) | public function getAbsoluteTargetDirectory(): string;
    method isTargetDirectoryVendor (line 11) | public function isTargetDirectoryVendor(): bool;
    method getExcludePackagesFromPrefixing (line 16) | public function getExcludePackagesFromPrefixing(): array;
    method getExcludeFilePatternsFromPrefixing (line 21) | public function getExcludeFilePatternsFromPrefixing(): array;
    method getExcludeNamespacesFromPrefixing (line 26) | public function getExcludeNamespacesFromPrefixing(): array;
    method getExcludePackagesFromCopy (line 31) | public function getExcludePackagesFromCopy(): array;
    method getExcludeFilePatternsFromCopy (line 36) | public function getExcludeFilePatternsFromCopy(): array;
    method getExcludeNamespacesFromCopy (line 41) | public function getExcludeNamespacesFromCopy(): array;
    method getExcludePackagesFromConstantPrefixing (line 48) | public function getExcludePackagesFromConstantPrefixing(): array;
    method getExcludeNamespacesFromConstantPrefixing (line 53) | public function getExcludeNamespacesFromConstantPrefixing(): array;
    method getExcludeFilePatternsFromConstantPrefixing (line 58) | public function getExcludeFilePatternsFromConstantPrefixing(): array;
    method getExcludeConstantNames (line 65) | public function getExcludeConstantNames(): array;

FILE: src/Config/OptimizeAutoloaderConfigInterface.php
  type OptimizeAutoloaderConfigInterface (line 5) | interface OptimizeAutoloaderConfigInterface
    method isOptimizeAutoloader (line 7) | public function isOptimizeAutoloader(): bool;

FILE: src/Config/PrefixerConfigInterface.php
  type PrefixerConfigInterface (line 5) | interface PrefixerConfigInterface
    method getAbsoluteVendorDirectory (line 7) | public function getAbsoluteVendorDirectory(): string;
    method getAbsoluteTargetDirectory (line 9) | public function getAbsoluteTargetDirectory(): string;
    method isTargetDirectoryVendor (line 11) | public function isTargetDirectoryVendor(): bool;
    method getNamespacePrefix (line 13) | public function getNamespacePrefix(): ?string;
    method getClassmapPrefix (line 15) | public function getClassmapPrefix(): ?string;
    method getConstantsPrefix (line 17) | public function getConstantsPrefix(): ?string;
    method getExcludePackagesFromPrefixing (line 20) | public function getExcludePackagesFromPrefixing(): array;
    method getExcludeNamespacesFromPrefixing (line 23) | public function getExcludeNamespacesFromPrefixing(): array;
    method getExcludeFilePatternsFromPrefixing (line 26) | public function getExcludeFilePatternsFromPrefixing(): array;

FILE: src/Console/Application.php
  class Application (line 10) | class Application extends BaseApplication
    method __construct (line 15) | public function __construct(string $version)

FILE: src/Console/Commands/AbstractRenamespacerCommand.php
  class AbstractRenamespacerCommand (line 31) | abstract class AbstractRenamespacerCommand extends Command
    method configure (line 52) | protected function configure()
    method execute (line 92) | protected function execute(InputInterface $input, OutputInterface $out...
    method initialize (line 133) | protected function initialize(InputInterface $input, OutputInterface $...
    method getLogger (line 165) | protected function getLogger(InputInterface $input, OutputInterface $o...
    method createConfig (line 190) | protected function createConfig(InputInterface $input): StraussConfig

FILE: src/Console/Commands/DependenciesCommand.php
  class DependenciesCommand (line 33) | class DependenciesCommand extends AbstractRenamespacerCommand
    method configure (line 61) | protected function configure()
    method execute (line 101) | protected function execute(InputInterface $input, OutputInterface $out...
    method loadProjectComposerPackage (line 153) | protected function loadProjectComposerPackage(): void
    method loadConfigFromComposerJson (line 176) | protected function loadConfigFromComposerJson(): void
    method updateConfigFromCli (line 183) | protected function updateConfigFromCli(InputInterface $input): void
    method buildDependencyList (line 197) | protected function buildDependencyList(): void
    method enumerateFiles (line 237) | protected function enumerateFiles(): void
    method enumeratePsr4Namespaces (line 254) | protected function enumeratePsr4Namespaces(): void
    method enumerateAutoloadedFiles (line 282) | protected function enumerateAutoloadedFiles(): void
    method scanFilesForSymbols (line 294) | protected function scanFilesForSymbols(): void
    method markSymbolsForRenaming (line 308) | protected function markSymbolsForRenaming(): void
    method determineChanges (line 320) | protected function determineChanges(): void
    method analyseFilesToCopy (line 331) | protected function analyseFilesToCopy(): void
    method copyFiles (line 336) | protected function copyFiles(): void
    method performReplacements (line 374) | protected function performReplacements(): void
    method performReplacementsInProjectFiles (line 390) | protected function performReplacementsInProjectFiles(): void
    method addLicenses (line 436) | protected function addLicenses(): void
    method generateAutoloader (line 461) | protected function generateAutoloader(): void
    method generateAliasesFile (line 502) | protected function generateAliasesFile(): void
    method cleanUp (line 531) | protected function cleanUp(): void

FILE: src/Console/Commands/IncludeAutoloaderCommand.php
  class IncludeAutoloaderCommand (line 27) | class IncludeAutoloaderCommand extends AbstractRenamespacerCommand
    method configure (line 39) | protected function configure()
    method execute (line 54) | protected function execute(InputInterface $input, OutputInterface $out...
    method loadProjectComposerPackage (line 88) | protected function loadProjectComposerPackage(): void
    method loadConfigFromComposerJson (line 95) | protected function loadConfigFromComposerJson(): void

FILE: src/Console/Commands/ReplaceCommand.php
  class ReplaceCommand (line 28) | class ReplaceCommand extends AbstractRenamespacerCommand
    method getConfig (line 48) | protected function getConfig(): ReplaceConfigInterface
    method configure (line 61) | protected function configure()
    method execute (line 99) | protected function execute(InputInterface $input, OutputInterface $out...
    method updateConfigFromCli (line 131) | protected function updateConfigFromCli(InputInterface $input): void
    method enumerateFiles (line 154) | protected function enumerateFiles(ReplaceConfigInterface $config): void
    method determineChanges (line 167) | protected function determineChanges(ReplaceConfigInterface $config): void
    method performReplacements (line 202) | protected function performReplacements(ReplaceConfigInterface $config)...
    method performReplacementsInProjectFiles (line 211) | protected function performReplacementsInProjectFiles(ReplaceConfigInte...
    method addLicenses (line 247) | protected function addLicenses(ReplaceConfigInterface $config): void

FILE: src/Files/DiscoveredFiles.php
  class DiscoveredFiles (line 5) | class DiscoveredFiles
    method add (line 10) | public function add(FileBase $file): void
    method getFiles (line 18) | public function getFiles(): array
    method getFile (line 28) | public function getFile(string $sourceAbsolutePath): ?FileBase
    method sort (line 33) | public function sort(): void

FILE: src/Files/File.php
  class File (line 10) | class File implements FileBase
    method __construct (line 42) | public function __construct(string $sourceAbsolutePath, string $vendor...
    method getSourcePath (line 48) | public function getSourcePath(): string
    method isPhpFile (line 53) | public function isPhpFile(): bool
    method setDoCopy (line 65) | public function setDoCopy(bool $doCopy): void
    method isDoCopy (line 69) | public function isDoCopy(): bool
    method setIsAutoloaded (line 74) | public function setIsAutoloaded(bool $isAutoloaded): void
    method isAutoloaded (line 79) | public function isAutoloaded(): bool
    method setDoPrefix (line 87) | public function setDoPrefix(bool $doPrefix): void
    method isDoPrefix (line 98) | public function isDoPrefix(): bool
    method setDoDelete (line 108) | public function setDoDelete(bool $doDelete): void
    method isDoDelete (line 118) | public function isDoDelete(): bool
    method setDidDelete (line 123) | public function setDidDelete(bool $didDelete): void
    method getDidDelete (line 128) | public function getDidDelete(): bool
    method addDiscoveredSymbol (line 133) | public function addDiscoveredSymbol(DiscoveredSymbol $symbol): void
    method getDiscoveredSymbols (line 141) | public function getDiscoveredSymbols(): array
    method setAbsoluteTargetPath (line 146) | public function setAbsoluteTargetPath(string $absoluteTargetPath): void
    method getAbsoluteTargetPath (line 155) | public function getAbsoluteTargetPath(): string
    method setDidUpdate (line 163) | public function setDidUpdate(): void
    method getDidUpdate (line 168) | public function getDidUpdate(): bool
    method getVendorRelativePath (line 173) | public function getVendorRelativePath(): string

FILE: src/Files/FileBase.php
  type FileBase (line 7) | interface FileBase
    method getSourcePath (line 10) | public function getSourcePath(): string;
    method getAbsoluteTargetPath (line 12) | public function getAbsoluteTargetPath(): string;
    method setAbsoluteTargetPath (line 14) | public function setAbsoluteTargetPath(string $absoluteTargetPath): void;
    method getVendorRelativePath (line 16) | public function getVendorRelativePath(): string;
    method isPhpFile (line 18) | public function isPhpFile(): bool;
    method isAutoloaded (line 20) | public function isAutoloaded(): bool;
    method setDoCopy (line 22) | public function setDoCopy(bool $doCopy): void;
    method isDoCopy (line 24) | public function isDoCopy(): bool;
    method setDoPrefix (line 26) | public function setDoPrefix(bool $doPrefix): void;
    method isDoPrefix (line 28) | public function isDoPrefix(): bool;
    method setDoDelete (line 37) | public function setDoDelete(bool $doDelete): void;
    method isDoDelete (line 44) | public function isDoDelete(): bool;
    method setDidDelete (line 46) | public function setDidDelete(bool $didDelete): void;
    method getDidDelete (line 48) | public function getDidDelete(): bool;
    method setDidUpdate (line 50) | public function setDidUpdate(): void;
    method addDiscoveredSymbol (line 52) | public function addDiscoveredSymbol(DiscoveredSymbol $symbol): void;
    method getDiscoveredSymbols (line 57) | public function getDiscoveredSymbols(): array;

FILE: src/Files/FileWithDependency.php
  class FileWithDependency (line 8) | class FileWithDependency extends File implements HasDependency
    method __construct (line 28) | public function __construct(ComposerPackage $dependency, string $vendo...
    method getDependency (line 50) | public function getDependency(): ComposerPackage
    method addAutoloader (line 63) | public function addAutoloader(string $autoloaderType): void
    method isFilesAutoloaderFile (line 68) | public function isFilesAutoloaderFile(): bool
    method getPackageRelativePath (line 73) | public function getPackageRelativePath(): string
    method isDoDelete (line 78) | public function isDoDelete(): bool

FILE: src/Files/HasDependency.php
  type HasDependency (line 7) | interface HasDependency
    method getDependency (line 10) | public function getDependency(): ComposerPackage;
    method addAutoloader (line 15) | public function addAutoloader(string $autoloaderType): void;
    method isFilesAutoloaderFile (line 17) | public function isFilesAutoloaderFile(): bool;

FILE: src/Helpers/FileSystem.php
  class FileSystem (line 24) | class FileSystem implements FilesystemOperator, FlysystemBackCompatInter...
    method __construct (line 46) | public function __construct(
    method getFsRoot (line 63) | public static function getFsRoot(?string $path = null): string
    method makePathNormalizer (line 71) | public static function makePathNormalizer(string $workingDir): PathNor...
    method normalizeDirSeparator (line 99) | public static function normalizeDirSeparator($path, $slashTo = '/'): s...
    method findAllFilesAbsolutePaths (line 112) | public function findAllFilesAbsolutePaths(array $fileAndDirPaths, bool...
    method getAttributes (line 149) | public function getAttributes(string $absolutePath): ?StorageAttributes
    method exists (line 171) | public function exists(string $location): bool
    method fileExists (line 178) | public function fileExists(string $location): bool
    method read (line 185) | public function read(string $location): string
    method readStream (line 192) | public function readStream(string $location)
    method listContents (line 199) | public function listContents(string $location, bool $deep = self::LIST...
    method lastModified (line 207) | public function lastModified(string $path): int
    method fileSize (line 214) | public function fileSize(string $path): int
    method mimeType (line 221) | public function mimeType(string $path): string
    method visibility (line 228) | public function visibility(string $path): string
    method write (line 239) | public function write(string $location, string $contents, array $confi...
    method writeStream (line 252) | public function writeStream(string $location, $contents, array $config...
    method setVisibility (line 261) | public function setVisibility(string $path, string $visibility): void
    method delete (line 269) | public function delete(string $location): void
    method deleteDirectory (line 276) | public function deleteDirectory(string $location): void
    method createDirectory (line 287) | public function createDirectory(string $location, array $config = []):...
    method move (line 299) | public function move(string $source, string $destination, array $confi...
    method copy (line 312) | public function copy(string $source, string $destination, array $confi...
    method getRelativePath (line 330) | public function getRelativePath(string $fromAbsoluteDirectory, string ...
    method getProjectRelativePath (line 356) | public function getProjectRelativePath(string $absolutePath): string
    method isSymlinked (line 373) | public function isSymlinked(string $path): bool
    method isSubDirOf (line 399) | public function isSubDirOf(string $dir, string $subDir): bool
    method normalizePath (line 407) | public function normalizePath(string $path): string
    method makeAbsolute (line 421) | public function makeAbsolute(string $path): string
    method isDirectoryEmpty (line 443) | public function isDirectoryEmpty(string $dirPath): bool

FILE: src/Helpers/FlysystemBackCompatInterface.php
  type FlysystemBackCompatInterface (line 10) | interface FlysystemBackCompatInterface extends FilesystemOperator
    method directoryExists (line 12) | public function directoryExists(string $location): bool;
    method has (line 13) | public function has(string $location): bool;

FILE: src/Helpers/FlysystemBackCompatTrait.php
  type FlysystemBackCompatTrait (line 12) | trait FlysystemBackCompatTrait
    method directoryExists (line 17) | public function directoryExists(string $location): bool
    method has (line 40) | public function has(string $location): bool

FILE: src/Helpers/InMemoryFilesystemAdapter.php
  class InMemoryFilesystemAdapter (line 9) | class InMemoryFilesystemAdapter extends LeagueInMemoryFilesystemAdapter
    method visibility (line 12) | public function visibility(string $path): FileAttributes
    method lastModified (line 28) | public function lastModified(string $path): FileAttributes
    method copy (line 38) | public function copy(string $source, string $destination, Config $conf...
    method write (line 45) | public function write(string $path, string $contents, Config $config):...
    method createDirectories (line 55) | protected function createDirectories(string $path, Config $config): void

FILE: src/Helpers/Log/PadColonColumnsLogProcessor.php
  class PadColonColumnsLogProcessor (line 18) | class PadColonColumnsLogProcessor implements ProcessorInterface
    method __invoke (line 27) | public function __invoke(array $record): array
    method pad (line 49) | private function pad(string $text, int $padLength): string

FILE: src/Helpers/Log/RelativeFilepathLogProcessor.php
  class RelativeFilepathLogProcessor (line 13) | class RelativeFilepathLogProcessor implements ProcessorInterface
    method __construct (line 17) | public function __construct(
    method __invoke (line 28) | public function __invoke(array $record): array

FILE: src/Helpers/NamespaceSort.php
  class NamespaceSort (line 8) | class NamespaceSort
    method __construct (line 16) | public function __construct(bool $order = self::SHORTEST)
    method __invoke (line 21) | public function __invoke(string $a, string $b): int
    method sort (line 31) | protected function sort(string $a, string $b): int

FILE: src/Helpers/ReadOnlyFileSystem.php
  class ReadOnlyFileSystem (line 27) | class ReadOnlyFileSystem implements FilesystemOperator, FlysystemBackCom...
    method __construct (line 36) | public function __construct(FilesystemOperator $filesystem, ?PathNorma...
    method fileExists (line 46) | public function fileExists(string $location): bool
    method write (line 61) | public function write(string $location, string $contents, array $confi...
    method writeStream (line 78) | public function writeStream(string $location, $contents, $config = [])...
    method rewindStream (line 93) | private function rewindStream($resource): void
    method read (line 100) | public function read(string $location): string
    method readStream (line 113) | public function readStream(string $location)
    method delete (line 126) | public function delete(string $location): void
    method deleteDirectory (line 139) | public function deleteDirectory(string $location): void
    method createDirectory (line 151) | public function createDirectory(string $location, array $config = []):...
    method listContents (line 160) | public function listContents(string $location, bool $deep = self::LIST...
    method move (line 191) | public function move(string $source, string $destination, array $confi...
    method copy (line 201) | public function copy(string $source, string $destination, $config = nu...
    method getAttributes (line 227) | private function getAttributes(string $path): StorageAttributes
    method lastModified (line 241) | public function lastModified(string $path): int
    method fileSize (line 247) | public function fileSize(string $path): int
    method mimeType (line 266) | public function mimeType(string $path): string
    method setVisibility (line 271) | public function setVisibility(string $path, string $visibility): void
    method visibility (line 276) | public function visibility(string $path): string
    method directoryExists (line 299) | public function directoryExists(string $location): bool
    method directoryExistsIn (line 318) | protected function directoryExistsIn(string $location, $filesystem): bool
    method has (line 342) | public function has(string $location): bool

FILE: src/Helpers/StripFsRootPathNormalizer.php
  class StripFsRootPathNormalizer (line 8) | class StripFsRootPathNormalizer implements PathNormalizer
    method __construct (line 20) | public function __construct(
    method normalizePath (line 31) | public function normalizePath(string $path): string

FILE: src/Pipeline/Aliases/Aliases.php
  class Aliases (line 32) | class Aliases
    method __construct (line 40) | public function __construct(
    method getTemplate (line 56) | protected function getTemplate(array $aliasesArray, ?string $autoloadA...
    method writeAliasesFileForSymbols (line 92) | public function writeAliasesFileForSymbols(DiscoveredSymbols $symbols)...
    method getAliasFilepath (line 106) | protected function getAliasFilepath(): string
    method getModifiedSymbols (line 114) | protected function getModifiedSymbols(DiscoveredSymbols $symbols): Dis...
    method registerAutoloader (line 137) | protected function registerAutoloader(array $classmap): void
    method buildStringOfAliases (line 157) | protected function buildStringOfAliases(DiscoveredSymbols $modifiedSym...
    method getAliasesArray (line 174) | protected function getAliasesArray(DiscoveredSymbols $symbols): array
    method getFunctionAliasesString (line 191) | protected function getFunctionAliasesString(DiscoveredSymbols $discove...
    method aliasedFunctionTemplate (line 314) | protected function aliasedFunctionTemplate(

FILE: src/Pipeline/Aliases/autoload_aliases.template.php
  class AliasAutoloader (line 17) | class AliasAutoloader
    method __construct (line 26) | public function __construct()
    method autoload (line 34) | public function autoload($class): void
    method load (line 67) | private function load(string $includeFile): void
    method classTemplate (line 77) | private function classTemplate(array $class): string
    method interfaceTemplate (line 102) | private function interfaceTemplate(array $interface): string
    method traitTemplate (line 120) | private function traitTemplate(array $trait): string

FILE: src/Pipeline/Autoload.php
  class Autoload (line 24) | class Autoload
    method __construct (line 49) | public function __construct(
    method generate (line 67) | public function generate(array $flatDependencyTree, DiscoveredSymbols ...

FILE: src/Pipeline/Autoload/ComposerAutoloadGenerator.php
  class ComposerAutoloadGenerator (line 28) | class ComposerAutoloadGenerator extends AutoloadGenerator
    method __construct (line 42) | public function __construct(
    method getFileIdentifier (line 65) | protected function getFileIdentifier(PackageInterface $package, string...

FILE: src/Pipeline/Autoload/DumpAutoload.php
  class DumpAutoload (line 28) | class DumpAutoload
    method __construct (line 40) | public function __construct(
    method generatedPrefixedAutoloader (line 59) | public function generatedPrefixedAutoloader(): void
    method generatedMainAutoloader (line 74) | protected function generatedMainAutoloader(): void
    method isOptimizeAutoloaderEnabled (line 186) | protected function isOptimizeAutoloaderEnabled(): bool
    method createInstalledVersionsFiles (line 203) | protected function createInstalledVersionsFiles(): void
    method prefixNewAutoloader (line 235) | protected function prefixNewAutoloader(): void
    method getSuffix (line 293) | protected function getSuffix(): ?string

FILE: src/Pipeline/Autoload/VendorComposerAutoload.php
  class VendorComposerAutoload (line 25) | class VendorComposerAutoload
    method __construct (line 33) | public function __construct(
    method addVendorPrefixedAutoloadToVendorAutoload (line 46) | public function addVendorPrefixedAutoloadToVendorAutoload(): void
    method addAliasesFileToComposer (line 86) | public function addAliasesFileToComposer(): void
    method isComposerInstalled (line 127) | protected function isComposerInstalled(): bool
    method isComposerNoDev (line 154) | protected function isComposerNoDev(): bool
    method addAliasesFileToComposerAutoload (line 166) | protected function addAliasesFileToComposerAutoload(string $code): string
    method addVendorPrefixedAutoloadToComposerAutoload (line 250) | protected function addVendorPrefixedAutoloadToComposerAutoload(string ...

FILE: src/Pipeline/AutoloadedFilesEnumerator.php
  class AutoloadedFilesEnumerator (line 16) | class AutoloadedFilesEnumerator
    method __construct (line 23) | public function __construct(
    method scanForAutoloadedFiles (line 36) | public function scanForAutoloadedFiles(array $dependencies): void
    method scanPackage (line 47) | protected function scanPackage(ComposerPackage $dependency): void

FILE: src/Pipeline/ChangeEnumerator.php
  class ChangeEnumerator (line 17) | class ChangeEnumerator
    method __construct (line 23) | public function __construct(
    method determineReplacements (line 31) | public function determineReplacements(DiscoveredSymbols $discoveredSym...
    method determineNamespaceReplacement (line 156) | protected function determineNamespaceReplacement(string $originalNames...

FILE: src/Pipeline/Cleanup/Cleanup.php
  class Cleanup (line 30) | class Cleanup
    method __construct (line 41) | public function __construct(
    method deleteFiles (line 63) | public function deleteFiles(array $flatDependencyTree, DiscoveredFiles...
    method cleanupVendorInstalledJson (line 87) | public function cleanupVendorInstalledJson(array $flatDependencyTree, ...
    method rebuildVendorAutoloader (line 122) | public function rebuildVendorAutoloader(): void
    method isOptimizeAutoloaderEnabled (line 178) | protected function isOptimizeAutoloaderEnabled(): bool
    method deleteEmptyDirectories (line 189) | protected function deleteEmptyDirectories(array $files): void
    method doIsDeleteVendorPackages (line 255) | protected function doIsDeleteVendorPackages(array $flatDependencyTree,...
    method doIsDeleteVendorFiles (line 338) | public function doIsDeleteVendorFiles(array $files): void

FILE: src/Pipeline/Cleanup/InstalledJson.php
  class InstalledJson (line 46) | class InstalledJson
    method __construct (line 54) | public function __construct(
    method copyInstalledJson (line 68) | public function copyInstalledJson(): void
    method getJsonFile (line 98) | protected function getJsonFile(string $vendorDir): JsonFile
    method updatePackagePaths (line 129) | protected function updatePackagePaths(array $installedJsonArray, array...
    method pathExistsInPackage (line 175) | protected function pathExistsInPackage(string $vendorDir, array $packa...
    method removeMissingAutoloadKeyPaths (line 189) | protected function removeMissingAutoloadKeyPaths(array $installedJsonA...
    method removeMovedPackagesAutoloadKeyFromVendorDirInstalledJson (line 283) | protected function removeMovedPackagesAutoloadKeyFromVendorDirInstalle...
    method removeMovedPackagesAutoloadKeyFromTargetDirInstalledJson (line 317) | protected function removeMovedPackagesAutoloadKeyFromTargetDirInstalle...
    method updateNamespaces (line 358) | protected function updateNamespaces(array $installedJsonArray, Discove...
    method cleanTargetDirInstalledJson (line 468) | public function cleanTargetDirInstalledJson(array $flatDependencyTree,...
    method cleanupVendorInstalledJson (line 542) | public function cleanupVendorInstalledJson(array $flatDependencyTree, ...
    method reindexPackagesList (line 583) | private function reindexPackagesList(array $installedJsonArray): array

FILE: src/Pipeline/Copier.php
  class Copier (line 24) | class Copier
    method __construct (line 42) | public function __construct(
    method prepareTarget (line 60) | public function prepareTarget(): void
    method copy (line 85) | public function copy(): void

FILE: src/Pipeline/DependenciesEnumerator.php
  class DependenciesEnumerator (line 23) | class DependenciesEnumerator
    method __construct (line 60) | public function __construct(
    method getAllDependencies (line 79) | public function getAllDependencies(): array
    method recursiveGetAllDependencies (line 92) | protected function recursiveGetAllDependencies(array $requiredPackageN...
    method getAllFilesAutoloaders (line 211) | public function getAllFilesAutoloaders(): array
    method removeVirtualPackagesFilter (line 225) | protected function removeVirtualPackagesFilter(string $requiredPackage...

FILE: src/Pipeline/FileCopyScanner.php
  class FileCopyScanner (line 32) | class FileCopyScanner
    method __construct (line 40) | public function __construct(
    method scanFiles (line 51) | public function scanFiles(DiscoveredFiles $files): void
    method isPackageExcluded (line 113) | protected function isPackageExcluded(ComposerPackage $package): bool
    method isNamespaceExcluded (line 125) | protected function isNamespaceExcluded(FileBase $file): bool
    method isFilePathExcluded (line 153) | protected function isFilePathExcluded(FileBase $file): bool
    method preparePattern (line 167) | private function preparePattern(string $pattern): string

FILE: src/Pipeline/FileEnumerator.php
  class FileEnumerator (line 18) | class FileEnumerator
    method __construct (line 31) | public function __construct(
    method compileFileListForDependencies (line 49) | public function compileFileListForDependencies(array $dependencies): D...
    method compileFileListForPaths (line 66) | public function compileFileListForPaths(array $paths, ?ComposerPackage...
    method addFile (line 87) | protected function addFile(

FILE: src/Pipeline/FileSymbolScanner.php
  class FileSymbolScanner (line 36) | class FileSymbolScanner
    method __construct (line 57) | public function __construct(
    method add (line 72) | protected function add(DiscoveredSymbol $symbol): void
    method findInFiles (line 96) | public function findInFiles(DiscoveredFiles $files): DiscoveredSymbols
    method find (line 126) | protected function find(string $contents, FileBase $file, ?ComposerPac...
    method splitByNamespace (line 187) | protected function splitByNamespace(string $contents):array
    method addDiscoveredClassChange (line 235) | protected function addDiscoveredClassChange(
    method addDiscoveredNamespaceChange (line 252) | protected function addDiscoveredNamespaceChange(string $namespace, Fil...
    method getBuiltIns (line 288) | protected function getBuiltIns(): array
    method loadBuiltIns (line 300) | protected function loadBuiltIns(): void

FILE: src/Pipeline/Licenser.php
  class Licenser (line 30) | class Licenser
    method __construct (line 65) | public function __construct(
    method copyLicenses (line 88) | public function copyLicenses(): void
    method findLicenseFiles (line 138) | public function findLicenseFiles(): void
    method getDiscoveredLicenseFiles (line 177) | public function getDiscoveredLicenseFiles(): array
    method addInformationToUpdatedFiles (line 188) | public function addInformationToUpdatedFiles(array $modifiedFiles): void
    method addChangeDeclarationToPhpString (line 235) | public function addChangeDeclarationToPhpString(

FILE: src/Pipeline/MarkSymbolsForRenaming.php
  class MarkSymbolsForRenaming (line 22) | class MarkSymbolsForRenaming
    method __construct (line 30) | public function __construct(
    method scanSymbols (line 40) | public function scanSymbols(DiscoveredSymbols $symbols): void
    method fileIsAutoloaded (line 87) | protected function fileIsAutoloaded(DiscoveredSymbol $symbol): bool
    method excludeFromPrefix (line 109) | protected function excludeFromPrefix(DiscoveredSymbol $symbol): bool
    method isSymbolFoundInFileThatIsNotCopied (line 123) | protected function isSymbolFoundInFileThatIsNotCopied(DiscoveredSymbol...
    method isSymbolFoundInFileThatIsCopied (line 136) | protected function isSymbolFoundInFileThatIsCopied(DiscoveredSymbol $s...
    method isExcludeFromCopyPackage (line 152) | protected function isExcludeFromCopyPackage(?string $packageName): bool
    method isExcludeFromPrefixPackage (line 160) | protected function isExcludeFromPrefixPackage(?string $packageName): bool
    method isExcludeFromPrefixNamespace (line 180) | protected function isExcludeFromPrefixNamespace(?string $namespace): bool
    method isExcludedFromPrefixFilePattern (line 202) | protected function isExcludedFromPrefixFilePattern(array $files): bool
    method isExcludeConstants (line 224) | protected function isExcludeConstants(ConstantSymbol $symbol): bool
    method isExcludeConstantsPackage (line 232) | protected function isExcludeConstantsPackage(?string $packageName): bool
    method isExcludeConstantsNamespace (line 240) | protected function isExcludeConstantsNamespace(?string $namespace): bool
    method isExcludedConstantsFilePattern (line 256) | protected function isExcludedConstantsFilePattern(array $files): bool
    method isExcludeConstantName (line 274) | protected function isExcludeConstantName(string $constantName): bool
    method preparePattern (line 282) | private function preparePattern(string $pattern): string

FILE: src/Pipeline/Prefixer.php
  class Prefixer (line 33) | class Prefixer
    method __construct (line 48) | public function __construct(
    method replaceInFiles (line 69) | public function replaceInFiles(DiscoveredSymbols $discoveredSymbols, a...
    method replaceInProjectFiles (line 121) | public function replaceInProjectFiles(DiscoveredSymbols $discoveredSym...
    method replaceInString (line 160) | public function replaceInString(DiscoveredSymbols $discoveredSymbols, ...
    method replaceConstFetchNamespaces (line 205) | protected function replaceConstFetchNamespaces(DiscoveredSymbols $symb...
    method replaceNamespace (line 266) | public function replaceNamespace(string $contents, string $originalNam...
    method replaceClassname (line 364) | public function replaceClassname(string $contents, string $originalCla...
    method replaceGlobalClassInsideNamedNamespace (line 428) | protected function replaceGlobalClassInsideNamedNamespace(
    method checkPregError (line 472) | protected function checkPregError(): void
    method replaceConstants (line 487) | protected function replaceConstants(string $contents, array $originalC...
    method replaceConstant (line 497) | protected function replaceConstant(string $contents, string $originalC...
    method replaceFunctions (line 502) | protected function replaceFunctions(string $contents, FunctionSymbol $...
    method getModifiedFiles (line 590) | public function getModifiedFiles(): array
    method prepareRelativeNamespaces (line 607) | protected function prepareRelativeNamespaces(string $phpFileContent, a...

FILE: src/Types/AutoloadAliasInterface.php
  type AutoloadAliasInterface (line 16) | interface AutoloadAliasInterface
    method getAutoloadAliasArray (line 21) | public function getAutoloadAliasArray(): array;

FILE: src/Types/ClassSymbol.php
  class ClassSymbol (line 10) | class ClassSymbol extends DiscoveredSymbol implements AutoloadAliasInter...
    method __construct (line 28) | public function __construct(
    method getExtends (line 43) | public function getExtends(): ?string
    method getInterfaces (line 51) | public function getInterfaces(): array
    method isAbstract (line 56) | public function isAbstract(): bool
    method getOriginalSymbolStripPrefix (line 61) | public function getOriginalSymbolStripPrefix(string $class_prefix): st...
    method getAutoloadAliasArray (line 78) | public function getAutoloadAliasArray(): array

FILE: src/Types/ConstantSymbol.php
  class ConstantSymbol (line 5) | class ConstantSymbol extends DiscoveredSymbol

FILE: src/Types/DiscoveredSymbol.php
  class DiscoveredSymbol (line 12) | abstract class DiscoveredSymbol
    method __construct (line 31) | public function __construct(
    method getOriginalSymbol (line 46) | public function getOriginalSymbol(): string
    method getSourceFiles (line 54) | public function getSourceFiles(): array
    method addSourceFile (line 62) | public function addSourceFile(FileBase $sourceFile): void
    method getReplacement (line 67) | public function getReplacement(): string
    method setReplacement (line 74) | public function setReplacement(string $replacement): void
    method getNamespace (line 79) | public function getNamespace(): ?string
    method getOriginalLocalName (line 84) | public function getOriginalLocalName(): string
    method setDoRename (line 89) | public function setDoRename(bool $doRename): void
    method isDoRename (line 94) | public function isDoRename(): bool
    method getPackage (line 99) | public function getPackage(): ?ComposerPackage
    method getPackageName (line 104) | public function getPackageName(): ?string

FILE: src/Types/DiscoveredSymbols.php
  class DiscoveredSymbols (line 11) | class DiscoveredSymbols
    method __construct (line 34) | public function __construct()
    method add (line 45) | public function add(DiscoveredSymbol $symbol): void
    method getSymbols (line 74) | public function getSymbols(): array
    method getConstants (line 87) | public function getConstants(): array
    method getNamespaces (line 95) | public function getNamespaces(): array
    method getNamespace (line 100) | public function getNamespace(string $namespace): ?NamespaceSymbol
    method getGlobalClasses (line 108) | public function getGlobalClasses(): array
    method getGlobalClassChanges (line 119) | public function getGlobalClassChanges(): array
    method getAllClasses (line 130) | public function getAllClasses(): array
    method getDiscoveredNamespaces (line 140) | public function getDiscoveredNamespaces(?string $namespacePrefix = '')...
    method getDiscoveredNamespaceChanges (line 162) | public function getDiscoveredNamespaceChanges(?string $namespacePrefix...
    method getDiscoveredClasses (line 173) | public function getDiscoveredClasses(?string $classmapPrefix = ''): array
    method getDiscoveredConstants (line 188) | public function getDiscoveredConstants(?string $constantsPrefix = ''):...
    method getDiscoveredConstantChanges (line 203) | public function getDiscoveredConstantChanges(?string $constantsPrefix ...
    method getDiscoveredFunctions (line 220) | public function getDiscoveredFunctions(): array
    method getDiscoveredFunctionChanges (line 228) | public function getDiscoveredFunctionChanges(): array
    method getAll (line 239) | public function getAll(): array
    method getDiscoveredTraits (line 247) | public function getDiscoveredTraits(): array
    method getDiscoveredInterfaces (line 255) | public function getDiscoveredInterfaces(): array
    method getClassmapSymbols (line 265) | public function getClassmapSymbols(): array
    method getNamespaceSymbolByString (line 274) | public function getNamespaceSymbolByString(string $namespace): ?Namesp...

FILE: src/Types/FunctionSymbol.php
  class FunctionSymbol (line 5) | class FunctionSymbol extends DiscoveredSymbol

FILE: src/Types/InterfaceSymbol.php
  class InterfaceSymbol (line 11) | class InterfaceSymbol extends DiscoveredSymbol implements AutoloadAliasI...
    method __construct (line 25) | public function __construct(
    method getExtends (line 40) | public function getExtends(): array
    method getAutoloadAliasArray (line 48) | public function getAutoloadAliasArray(): array

FILE: src/Types/NamespaceSymbol.php
  class NamespaceSymbol (line 8) | class NamespaceSymbol extends DiscoveredSymbol
    method isChangedNamespace (line 10) | public function isChangedNamespace(): bool

FILE: src/Types/TraitSymbol.php
  class TraitSymbol (line 11) | class TraitSymbol extends DiscoveredSymbol implements AutoloadAliasInter...
    method __construct (line 25) | public function __construct(
    method getUses (line 40) | public function getUses(): array
    method getAutoloadAliasArray (line 48) | public function getAutoloadAliasArray(): array

FILE: tests/Integration/Autoload/DumpAutoloadFeatureTest.php
  class DumpAutoloadFeatureTest (line 20) | class DumpAutoloadFeatureTest extends IntegrationTestCase
    method test_optimize_autoloader_for_prefixed_autoload_real (line 25) | public function test_optimize_autoloader_for_prefixed_autoload_real(st...
    method provider_optimize_autoloader_for_prefixed_autoload_real (line 70) | public static function provider_optimize_autoloader_for_prefixed_autol...
    method test_fix_double_loading_of_files_autoloaders (line 120) | public function test_fix_double_loading_of_files_autoloaders(string $c...
    method provider_fix_double_loading_of_files_autoloaders (line 152) | public static function provider_fix_double_loading_of_files_autoloader...
    method test_option_include_root_autoload (line 212) | public function test_option_include_root_autoload(string $composerJson...
    method provider_option_include_root_autoload (line 253) | public static function provider_option_include_root_autoload(): array
    method test_check_prefixed_autoloader_indirect (line 337) | public function test_check_prefixed_autoloader_indirect(): void

FILE: tests/Integration/Autoload/VendorComposerAutoloadFeatureTest.php
  class VendorComposerAutoloadFeatureTest (line 13) | class VendorComposerAutoloadFeatureTest extends IntegrationTestCase
    method testHappyPath (line 16) | public function testHappyPath(): void
    method testInstallNoDev (line 50) | public function testInstallNoDev(): void
    method testRepeatedlyRunningOnlyAddsAutoloadOnce (line 83) | public function testRepeatedlyRunningOnlyAddsAutoloadOnce(): void
    method testRepeatedlyRunningOnlyAddsAutoloadAliasesOnce (line 129) | public function testRepeatedlyRunningOnlyAddsAutoloadAliasesOnce(): void
    method test_does_not_edit_autoloader_namespaces_when_not_deleting_files (line 171) | public function test_does_not_edit_autoloader_namespaces_when_not_dele...
    method test_does_edit_autoloader_namespaces_when_deleting_files (line 212) | public function test_does_edit_autoloader_namespaces_when_deleting_fil...
    method test_does_edit_autoloader_namespaces_when_target_is_vendor (line 254) | public function test_does_edit_autoloader_namespaces_when_target_is_ve...

FILE: tests/Integration/ChangeEnumeratorIntegrationTest.php
  class ChangeEnumeratorIntegrationTest (line 10) | class ChangeEnumeratorIntegrationTest extends IntegrationTestCase
    method testPrepareTarget (line 16) | public function testPrepareTarget(): void
    method testNamespaceInTwoPackagesExclude (line 50) | public function testNamespaceInTwoPackagesExclude(): void

FILE: tests/Integration/Cleanup/ExcludeFromCopyAutoloadIntegrationTest.php
  class ExcludeFromCopyAutoloadIntegrationTest (line 13) | class ExcludeFromCopyAutoloadIntegrationTest extends IntegrationTestCase
    method test_excluded_package_remains_in_vendor_autoload_after_parent_package_is_deleted (line 15) | public function test_excluded_package_remains_in_vendor_autoload_after...
    method test_rebuild_vendor_autoloader_keeps_orphaned_excluded_package_autoloads (line 49) | public function test_rebuild_vendor_autoloader_keeps_orphaned_excluded...
    method createLocalPathRepositoryFixture (line 72) | private function createLocalPathRepositoryFixture(): void
    method composerInstall (line 163) | private function composerInstall(): void
    method runStraussInSubprocess (line 169) | private function runStraussInSubprocess(?string &$allOutput = null): int
    method removePackageFromVendorInstalledJson (line 181) | private function removePackageFromVendorInstalledJson(string $packageN...
    method extractPackageNamesFromInstalledJson (line 202) | private function extractPackageNamesFromInstalledJson(string $installe...
    method assertPreservedPackageIsRuntimeAutoloadable (line 216) | private function assertPreservedPackageIsRuntimeAutoloadable(): void
    method writeJsonFile (line 237) | private function writeJsonFile(string $path, array $contents): void
    method writeFile (line 245) | private function writeFile(string $path, string $contents): void
    method readFile (line 255) | private function readFile(string $path): string

FILE: tests/Integration/Cleanup/InstalledJsonIntegrationTest.php
  class InstalledJsonIntegrationTest (line 10) | class InstalledJsonIntegrationTest extends IntegrationTestCase
    method testVendorInstalledJsonPackagesRemainAListAfterDeletedPackagesAreRemoved (line 12) | public function testVendorInstalledJsonPackagesRemainAListAfterDeleted...
    method testTargetInstalledJsonPackagesRemainAListAfterNonStraussPackagesAreRemoved (line 30) | public function testTargetInstalledJsonPackagesRemainAListAfterNonStra...
    method testComposerDumpAutoloadOnTargetDirectory (line 58) | public function testComposerDumpAutoloadOnTargetDirectory(): void
    method testComposerDumpAutoloadOnTargetDirectoryIsVendorDir (line 95) | public function testComposerDumpAutoloadOnTargetDirectoryIsVendorDir()...
    method testComposerDumpAutoloadWithDeleteFalse (line 127) | public function testComposerDumpAutoloadWithDeleteFalse(): void
    method testPackageWithEmptyPsr4Namespace (line 170) | public function testPackageWithEmptyPsr4Namespace(): void
    method createDeletedParentWithExcludedDependencyFixture (line 250) | private function createDeletedParentWithExcludedDependencyFixture(): void
    method createTargetPackageRemovalFixture (line 299) | private function createTargetPackageRemovalFixture(): void
    method pathRepository (line 346) | private function pathRepository(string $path): array
    method writePackage (line 360) | private function writePackage(string $path, string $name, array $requi...
    method writeJsonFile (line 390) | private function writeJsonFile(string $path, array $contents): void
    method writeFile (line 398) | private function writeFile(string $path, string $contents): void
    method assertInstalledJsonPackagesIsList (line 411) | private function assertInstalledJsonPackagesIsList(string $installedJs...

FILE: tests/Integration/CleanupIntegrationTest.php
  class CleanupIntegrationTest (line 16) | class CleanupIntegrationTest extends IntegrationTestCase
    method test_optimize_autoloader_for_vendor_autoload_real (line 21) | public function test_optimize_autoloader_for_vendor_autoload_real(stri...
    method provider_optimize_autoloader_for_vendor_autoload_real (line 49) | public static function provider_optimize_autoloader_for_vendor_autoloa...
    method testFilesAutoloaderCleaned (line 91) | public function testFilesAutoloaderCleaned(): void
    method testExcludedPackagesNotDeletedWhenDeleteVendorPackagesEnabled (line 149) | public function testExcludedPackagesNotDeletedWhenDeleteVendorPackages...
    method extractPackageNamesFromInstalledJson (line 207) | private function extractPackageNamesFromInstalledJson(string $installe...

FILE: tests/Integration/CleanupSymlinkIntegrationTest.php
  class CleanupSymlinkIntegrationTest (line 10) | final class CleanupSymlinkIntegrationTest extends IntegrationTestCase
    method testEnsureNoRemovalOfSymlinks (line 15) | public function testEnsureNoRemovalOfSymlinks(): void
    method packageComposerFile (line 67) | private function packageComposerFile(): string
    method symlinkedComposerFile (line 96) | private function symlinkedComposerFile(): string
    method symlinkedPhpFile (line 110) | private function symlinkedPhpFile(): string

FILE: tests/Integration/CopierFeatureTest.php
  class CopierFeatureTest (line 30) | class CopierFeatureTest extends IntegrationTestCase
    method test_default_copy_behavior_with_vendor_prefixed_target (line 40) | public function test_default_copy_behavior_with_vendor_prefixed_target...
    method test_custom_target_directory (line 85) | public function test_custom_target_directory(): void
    method test_target_directory_same_as_vendor_directory (line 134) | public function test_target_directory_same_as_vendor_directory(): void
    method test_exclude_packages_from_copy (line 180) | public function test_exclude_packages_from_copy(): void
    method test_exclude_namespaces_from_copy (line 230) | public function test_exclude_namespaces_from_copy(): void
    method test_exclude_file_patterns_from_copy (line 277) | public function test_exclude_file_patterns_from_copy(): void
    method test_exclude_with_inverted_regex_pattern (line 325) | public function test_exclude_with_inverted_regex_pattern(): void
    method test_combined_exclusions_from_copy (line 372) | public function test_combined_exclusions_from_copy(): void
    method test_excluded_files_not_prefixed (line 424) | public function test_excluded_files_not_prefixed(): void
    method test_target_directory_creation (line 471) | public function test_target_directory_creation(): void
    method test_existing_target_files_overwritten (line 517) | public function test_existing_target_files_overwritten(): void
    method test_missing_source_files_handled_gracefully (line 571) | public function test_missing_source_files_handled_gracefully(): void
    method test_directory_and_file_copying (line 621) | public function test_directory_and_file_copying(): void
    method test_symlink_files_copying (line 677) | public function test_symlink_files_copying(): void
    method test_absolute_vs_relative_target_paths (line 697) | public function test_absolute_vs_relative_target_paths(): void
    method test_empty_exclude_configuration (line 767) | public function test_empty_exclude_configuration(): void
    method test_invalid_regex_pattern_handling (line 811) | public function test_invalid_regex_pattern_handling(): void
    method test_case_sensitivity_in_namespace_exclusions (line 859) | public function test_case_sensitivity_in_namespace_exclusions(): void
    method test_files_autoloader_copying (line 904) | public function test_files_autoloader_copying(): void

FILE: tests/Integration/CopierIntegrationTest.php
  class CopierIntegrationTest (line 20) | class CopierIntegrationTest extends IntegrationTestCase
    method testPrepareTarget (line 23) | public function testPrepareTarget(): void
    method testsCopy (line 90) | public function testsCopy(): void
    method createComposer (line 161) | protected function createComposer(): void
    method it_creates_absent_dirs (line 199) | public function it_creates_absent_dirs(): void
    method it_is_unpertrubed_by_existing_dirs (line 226) | public function it_is_unpertrubed_by_existing_dirs(): void
    method it_deletes_subdirs_for_packages_about_to_be_moved (line 261) | public function it_deletes_subdirs_for_packages_about_to_be_moved(): void

FILE: tests/Integration/DryRunFeatureTest.php
  class DryRunFeatureTest (line 12) | class DryRunFeatureTest extends IntegrationTestCase
    method test_not_enabled (line 19) | public function test_not_enabled(): void
    method getDirectoryMd5s (line 26) | protected function getDirectoryMd5s(string $directory): array
    method assertEqualsDirectoryHashes (line 44) | protected function assertEqualsDirectoryHashes(array $hashesBefore, ar...
    method test_happy_path (line 62) | public function test_happy_path(): void
    method test_cli_argument (line 103) | public function test_cli_argument(): void
    method test_cli_argument_overrides_composer_json (line 144) | public function test_cli_argument_overrides_composer_json(): void
    method testGenerateAutoload (line 186) | public function testGenerateAutoload():void
    method test_composer_files_not_modified (line 227) | public function test_composer_files_not_modified(): void

FILE: tests/Integration/DumpAutoloadFeatureTest.php
  class DumpAutoloadFeatureTest (line 13) | class DumpAutoloadFeatureTest extends IntegrationTestCase
    method testDumpAutoload (line 18) | public function testDumpAutoload(): void

FILE: tests/Integration/ExcludeFromPrefixFeatureTest.php
  class ExcludeFromPrefixFeatureTest (line 8) | class ExcludeFromPrefixFeatureTest extends IntegrationTestCase
    method test_exclude_from_prefix_file_patterns (line 11) | public function test_exclude_from_prefix_file_patterns(): void
    method test_namespace_excluded (line 51) | public function test_namespace_excluded(): void

FILE: tests/Integration/FileCopyScannerIntegrationTest.php
  class FileCopyScannerIntegrationTest (line 21) | class FileCopyScannerIntegrationTest extends IntegrationTestCase
    method test_find_namespace_and_global_classes (line 27) | public function test_find_namespace_and_global_classes(): void
    method test_exclude_copy_file_patterns (line 118) | public function test_exclude_copy_file_patterns(): void

FILE: tests/Integration/FileEnumeratorIntegrationTest.php
  class FileEnumeratorIntegrationTest (line 17) | class FileEnumeratorIntegrationTest extends IntegrationTestCase
    method testBuildFileList (line 20) | public function testBuildFileList(): void
    method test_exclude_from_classmap (line 79) | public function test_exclude_from_classmap(): void

FILE: tests/Integration/Helpers/FileSystemIntegrationTest.php
  class FileSystemIntegrationTest (line 11) | class FileSystemIntegrationTest extends IntegrationTestCase
    method test_is_dir (line 16) | public function test_is_dir(): void
    method test_find_all_files_absolute_paths (line 31) | public function test_find_all_files_absolute_paths(): void

FILE: tests/Integration/Helpers/PadColonColumnsLogProcessorIntegrationTest.php
  class PadColonColumnsLogProcessorIntegrationTest (line 11) | class PadColonColumnsLogProcessorIntegrationTest extends TestCase
    method testHappyPath (line 13) | public function testHappyPath(): void

FILE: tests/Integration/Helpers/ReadOnlyFileSystemIntegrationTest.php
  class ReadOnlyFileSystemIntegrationTest (line 12) | class ReadOnlyFileSystemIntegrationTest extends IntegrationTestCase
    method test_write (line 22) | public function test_write(): void
    method test_file_exists_true (line 43) | public function test_file_exists_true(): void
    method test_file_exists_false (line 62) | public function test_file_exists_false(): void
    method test_dry_run_deleted_file_throws_exception_on_read (line 78) | public function test_dry_run_deleted_file_throws_exception_on_read(): ...
    method testListContentsDeleteFile (line 100) | public function testListContentsDeleteFile(): void
    method testListContentsAddFile (line 126) | public function testListContentsAddFile(): void
    method test_copy (line 148) | public function test_copy():void
    method testDirectoryExists (line 169) | public function testDirectoryExists(): void
    method testDirectoryExistsDelete (line 183) | public function testDirectoryExistsDelete(): void
    method testDirectoryExistsPhantomDir (line 210) | public function testDirectoryExistsPhantomDir(): void

FILE: tests/Integration/OutputLevelFeatureTest.php
  class OutputLevelFeatureTest (line 13) | class OutputLevelFeatureTest extends IntegrationTestCase
    method setUp (line 15) | public function setUp(): void
    method test_silent_output_level (line 44) | public function test_silent_output_level(): void
    method test_normal_output_level (line 53) | public function test_normal_output_level(): void
    method test_info_output_level (line 63) | public function test_info_output_level(): void
    method test_debug_output_level (line 74) | public function test_debug_output_level(): void
    method test_dry_run_output_level (line 85) | public function test_dry_run_output_level(): void

FILE: tests/Integration/Pipeline/Aliases/AliasesFeatureTest.php
  class AliasesFeatureTest (line 10) | class AliasesFeatureTest extends IntegrationTestCase
    method test_happy_path (line 24) | public function test_happy_path(): void
    method test_namespaced_files_alias (line 74) | public function test_namespaced_files_alias(): void
    method test_non_namespaced_files_alias (line 107) | public function test_non_namespaced_files_alias(): void
    method test_disabled_function_renaming (line 145) | public function test_disabled_function_renaming(): void
    method test_double_prefixing (line 194) | public function test_double_prefixing(): void

FILE: tests/Integration/ReplaceCommandIntegrationTest.php
  class ReplaceCommandIntegrationTest (line 18) | class ReplaceCommandIntegrationTest extends IntegrationTestCase
    method test_rename_namespace (line 20) | public function test_rename_namespace(): void

FILE: tests/Integration/ReplacerIntegrationTest.php
  class ReplacerIntegrationTest (line 12) | class ReplacerIntegrationTest extends IntegrationTestCase
    method testReplaceNamespace (line 15) | public function testReplaceNamespace(): void
    method testReplaceClass (line 68) | public function testReplaceClass(): void
    method testSimpleReplacementPatterns (line 101) | public function testSimpleReplacementPatterns(): void
    method testExaggeratedReplacementPatterns (line 136) | public function testExaggeratedReplacementPatterns(): void
    method testRidiculousReplacementPatterns (line 171) | public function testRidiculousReplacementPatterns(): void
    method testSimpleReplacement (line 209) | public function testSimpleReplacement(): void
    method test_replace_classname_is_namespace_name (line 247) | public function test_replace_classname_is_namespace_name(): void

FILE: tests/Integration/UpdateCallSitesIntegrationTest.php
  class UpdateCallSitesIntegrationTest (line 10) | class UpdateCallSitesIntegrationTest extends IntegrationTestCase
    method test_updateCallSites_functions (line 17) | public function test_updateCallSites_functions(): void

FILE: tests/IntegrationTestCase.php
  class IntegrationTestCase (line 26) | class IntegrationTestCase extends TestCase
    method setUp (line 35) | public function setUp(): void
    method isPhpStormRunning (line 73) | protected function isPhpStormRunning(): bool
    method runStrauss (line 85) | protected function runStrauss(?string &$allOutput = null, string $para...
    method tearDown (line 152) | public function tearDown(): void
    method deleteDir (line 174) | protected function deleteDir($dir)
    method markTestSkippedOnPhpVersionBelow (line 230) | public function markTestSkippedOnPhpVersionBelow(string $php_version, ...
    method markTestSkippedOnPhpVersionEqualOrBelow (line 234) | public function markTestSkippedOnPhpVersionEqualOrBelow(string $php_ve...
    method markTestSkippedOnPhpVersionAbove (line 238) | public function markTestSkippedOnPhpVersionAbove(string $php_version, ...
    method markTestSkippedOnPhpVersionEqualOrAbove (line 242) | public function markTestSkippedOnPhpVersionEqualOrAbove(string $php_ve...
    method markTestSkippedOnPhpVersion (line 249) | public function markTestSkippedOnPhpVersion(string $php_version, strin...
    method assertFileNotExistsInFileSystem (line 265) | protected function assertFileNotExistsInFileSystem(string $filePath, ?...
    method assertFileExistsInFileSystem (line 275) | protected function assertFileExistsInFileSystem(string $filePath, ?Fil...
    method assertDirectoryNotExistsInFileSystem (line 289) | protected function assertDirectoryNotExistsInFileSystem(string $direct...
    method assertDirectoryExistsInFileSystem (line 299) | protected function assertDirectoryExistsInFileSystem(string $directory...
    method getParentDirectoryAssertFailureMessagePart (line 320) | protected function getParentDirectoryAssertFailureMessagePart(string $...

FILE: tests/Issues/MozartIssue106Test.php
  class MozartIssue106Test (line 14) | class MozartIssue106Test extends IntegrationTestCase
    method test_only_prefix_classmap_classes_once (line 22) | public function test_only_prefix_classmap_classes_once(): void

FILE: tests/Issues/MozartIssue108Test.php
  class MozartIssue108Test (line 24) | class MozartIssue108Test extends IntegrationTestCase
    method test_woocommerce_actionscheduler (line 30) | public function test_woocommerce_actionscheduler(): void

FILE: tests/Issues/MozartIssue109Test.php
  class MozartIssue109Test (line 18) | class MozartIssue109Test extends IntegrationTestCase
    method testTheOutputDoesNotPrefixComments (line 21) | public function testTheOutputDoesNotPrefixComments(): void

FILE: tests/Issues/MozartIssue124Test.php
  class MozartIssue124Test (line 15) | class MozartIssue124Test extends IntegrationTestCase
    method test_it_does_not_make_classname_replacement_inside_namespaced_file (line 29) | public function test_it_does_not_make_classname_replacement_inside_nam...
    method test_it_does_not_prefix_function_argument_types_whose_classname_matches_the_namespace (line 77) | public function test_it_does_not_prefix_function_argument_types_whose_...
    method testItDoesPrefixNamespacedExtends (line 122) | public function testItDoesPrefixNamespacedExtends(): void

FILE: tests/Issues/MozartIssue128Test.php
  class MozartIssue128Test (line 14) | class MozartIssue128Test extends IntegrationTestCase
    method test_fpdf (line 20) | public function test_fpdf(): void

FILE: tests/Issues/MozartIssue129Test.php
  class MozartIssue129Test (line 27) | class MozartIssue129Test extends TestCase
    method test_test (line 35) | public function test_test($phpString, $expected)
    method pairTestDataProvider (line 50) | public static function pairTestDataProvider()

FILE: tests/Issues/MozartIssue130Test.php
  class MozartIssue130Test (line 20) | class MozartIssue130Test extends IntegrationTestCase
    method test_config_copied (line 26) | public function test_config_copied(): void

FILE: tests/Issues/MozartIssue13Test.php
  class MozartIssue13Test (line 17) | class MozartIssue13Test extends IntegrationTestCase
    method testPaypalStringReplacement (line 25) | public function testPaypalStringReplacement(): void

FILE: tests/Issues/MozartIssue43Test.php
  class MozartIssue43Test (line 18) | class MozartIssue43Test extends IntegrationTestCase
    method testAwsSdkSucceeds (line 27) | public function testAwsSdkSucceeds(): void

FILE: tests/Issues/MozartIssue48Test.php
  class MozartIssue48Test (line 17) | class MozartIssue48Test extends IntegrationTestCase
    method testRubixTensorBothPathsPersist (line 26) | public function testRubixTensorBothPathsPersist(): void

FILE: tests/Issues/MozartIssue62Test.php
  class MozartIssue62Test (line 28) | class MozartIssue62Test extends IntegrationTestCase
    method testGuzzleNamespaceIsPrefixedInS3Client (line 34) | public function testGuzzleNamespaceIsPrefixedInS3Client(): void

FILE: tests/Issues/MozartIssue66Test.php
  class MozartIssue66Test (line 18) | class MozartIssue66Test extends IntegrationTestCase
    method testFilesAutoloaderIsUsed (line 34) | public function testFilesAutoloaderIsUsed(): void

FILE: tests/Issues/MozartIssue86Test.php
  class MozartIssue86Test (line 15) | class MozartIssue86Test extends IntegrationTestCase
    method test_do_not_parse_comments_to_classnames (line 23) | public function test_do_not_parse_comments_to_classnames(): void
    method test_do_not_parse_comments_to_classnames_wp_dependency_installer (line 73) | public function test_do_not_parse_comments_to_classnames_wp_dependency...

FILE: tests/Issues/MozartIssue89Test.php
  class MozartIssue89Test (line 18) | class MozartIssue89Test extends IntegrationTestCase
    method it_moves_each_file_once_per_namespace (line 57) | public function it_moves_each_file_once_per_namespace()

FILE: tests/Issues/MozartIssue90Test.php
  class MozartIssue90Test (line 15) | class MozartIssue90Test extends IntegrationTestCase
    method testLibpdfmergeSucceeds (line 23) | public function testLibpdfmergeSucceeds(): void

FILE: tests/Issues/MozartIssue93Test.php
  class MozartIssue93Test (line 14) | class MozartIssue93Test extends IntegrationTestCase
    method test_it_does_not_make_classname_replacement_inside_namespaced_file (line 25) | public function test_it_does_not_make_classname_replacement_inside_nam...

FILE: tests/Issues/MozartIssue97Test.php
  class MozartIssue97Test (line 15) | class MozartIssue97Test extends IntegrationTestCase
    method testCrewlabsUnsplashSucceeds (line 24) | public function testCrewlabsUnsplashSucceeds(): void

FILE: tests/Issues/MozartIssue99Test.php
  class MozartIssue99Test (line 21) | class MozartIssue99Test extends IntegrationTestCase
    method test_mustache (line 27) | public function test_mustache(): void

FILE: tests/Issues/StraussIssue101Test.php
  class StraussIssue101Test (line 16) | class StraussIssue101Test extends IntegrationTestCase
    method test_does_not_delete_autoload_keys (line 18) | public function test_does_not_delete_autoload_keys(): void

FILE: tests/Issues/StraussIssue104Test.php
  class StraussIssue104Test (line 16) | class StraussIssue104Test extends IntegrationTestCase
    method test_correct_directory_permission (line 18) | public function test_correct_directory_permission(): void

FILE: tests/Issues/StraussIssue108Test.php
  class StraussIssue108Test (line 18) | class StraussIssue108Test extends IntegrationTestCase
    method test_a (line 20) | public function test_a(): void

FILE: tests/Issues/StraussIssue109Test.php
  class StraussIssue109Test (line 16) | class StraussIssue109Test extends IntegrationTestCase
    method test_absent_cli_argument_parsing_does_not_overwrite_config (line 18) | public function test_absent_cli_argument_parsing_does_not_overwrite_co...

FILE: tests/Issues/StraussIssue111Test.php
  class StraussIssue111Test (line 16) | class StraussIssue111Test extends IntegrationTestCase
    method test_phpdoc (line 18) | public function test_phpdoc(): void

FILE: tests/Issues/StraussIssue114Test.php
  class StraussIssue114Test (line 16) | class StraussIssue114Test extends IntegrationTestCase
    method test_muted_errors (line 18) | public function test_muted_errors(): void

FILE: tests/Issues/StraussIssue119Test.php
  class StraussIssue119Test (line 17) | class StraussIssue119Test extends IntegrationTestCase
    method test_incorrectly_prefixing_class (line 19) | public function test_incorrectly_prefixing_class(): void

FILE: tests/Issues/StraussIssue11Test.php
  class StraussIssue11Test (line 21) | class StraussIssue11Test extends IntegrationTestCase
    method test_migrate_mozart_config (line 27) | public function test_migrate_mozart_config(): void
    method test_carbon_fields (line 79) | public function test_carbon_fields(): void
    method test_static_namespace (line 137) | public function test_static_namespace(): void

FILE: tests/Issues/StraussIssue133Test.php
  class StraussIssue133Test (line 16) | class StraussIssue133Test extends IntegrationTestCase
    method test_unable_to_read_file (line 23) | public function test_unable_to_read_file(): void

FILE: tests/Issues/StraussIssue136Test.php
  class StraussIssue136Test (line 16) | class StraussIssue136Test extends IntegrationTestCase
    method test_does_not_update_source_files_unless_requested (line 21) | public function test_does_not_update_source_files_unless_requested(): ...

FILE: tests/Issues/StraussIssue143Test.php
  class StraussIssue143Test (line 17) | class StraussIssue143Test extends IntegrationTestCase
    method test_composer_in_sibling_dir (line 19) | public function test_composer_in_sibling_dir(): void
    method test_composer_in_sibling_dir_delete_packages (line 85) | public function test_composer_in_sibling_dir_delete_packages(): void
    method test_silent_option_symfony_72 (line 129) | public function test_silent_option_symfony_72(): void

FILE: tests/Issues/StraussIssue14Test.php
  class StraussIssue14Test (line 14) | class StraussIssue14Test extends IntegrationTestCase
    method test_guzzle_http_is_prefixed (line 22) | public function test_guzzle_http_is_prefixed(): void
    method testFilesAutoloaderIsGenerated (line 56) | public function testFilesAutoloaderIsGenerated(): void

FILE: tests/Issues/StraussIssue154Test.php
  class StraussIssue154Test (line 14) | class StraussIssue154Test extends IntegrationTestCase
    method test_relative_namespaces (line 16) | public function test_relative_namespaces(): void
    method test_use (line 56) | public function test_use(): void
    method test_parameter (line 96) | public function test_parameter(): void
    method test_constant (line 136) | public function test_constant(): void
    method test_class_prefix (line 176) | public function test_class_prefix(): void
    method test_multiple_namespaces (line 215) | public function test_multiple_namespaces(): void
    method test_return_type (line 253) | public function test_return_type(): void
    method test_phpdoc (line 289) | public function test_phpdoc(): void
    method test_static_property (line 325) | public function test_static_property(): void
    method test_constructor_parameter (line 361) | public function test_constructor_parameter(): void
    method test_exception_type (line 397) | public function test_exception_type(): void
    method test_instanceof (line 432) | public function test_instanceof(): void

FILE: tests/Issues/StraussIssue159Test.php
  class StraussIssue159Test (line 16) | class StraussIssue159Test extends IntegrationTestCase
    method test_autoloader_does_not_include_platform_check (line 18) | public function test_autoloader_does_not_include_platform_check(): void

FILE: tests/Issues/StraussIssue163Test.php
  class StraussIssue163Test (line 13) | class StraussIssue163Test extends IntegrationTestCase
    method test_multiple_autoloaders_breaks_autoloading (line 18) | public function test_multiple_autoloaders_breaks_autoloading(): void

FILE: tests/Issues/StraussIssue166Test.php
  class StraussIssue166Test (line 16) | class StraussIssue166Test extends IntegrationTestCase
    method test_namespaced_trait (line 18) | public function test_namespaced_trait(): void

FILE: tests/Issues/StraussIssue172Test.php
  class StraussIssue172Test (line 16) | class StraussIssue172Test extends IntegrationTestCase
    method test_issue_172 (line 18) | public function test_issue_172(): void

FILE: tests/Issues/StraussIssue173Test.php
  class StraussIssue173Test (line 15) | class StraussIssue173Test extends IntegrationTestCase
    method test_issue_173 (line 17) | public function test_issue_173(): void

FILE: tests/Issues/StraussIssue179Test.php
  class StraussIssue179Test (line 15) | class StraussIssue179Test extends IntegrationTestCase
    method test_issue_179 (line 17) | public function test_issue_179(): void

FILE: tests/Issues/StraussIssue183Test.php
  class StraussIssue183Test (line 16) | class StraussIssue183Test extends IntegrationTestCase
    method bootstrapDataProvider (line 19) | public static function bootstrapDataProvider(): array
    method test_bootstrap (line 30) | public function test_bootstrap(string $targetDirectoryJsonLine)
    method test_allow_url_include (line 79) | public function test_allow_url_include(): void

FILE: tests/Issues/StraussIssue188Test.php
  class StraussIssue188Test (line 16) | class StraussIssue188Test extends IntegrationTestCase
    method test_issue_188_implements (line 18) | public function test_issue_188_implements(): void
    method test_issue_188_extends (line 49) | public function test_issue_188_extends(): void

FILE: tests/Issues/StraussIssue189Test.php
  class StraussIssue189Test (line 15) | class StraussIssue189Test extends IntegrationTestCase
    method test_prefix_namespace (line 17) | public function test_prefix_namespace(): void

FILE: tests/Issues/StraussIssue191Test.php
  class StraussIssue191Test (line 18) | class StraussIssue191Test extends IntegrationTestCase
    method test_fatal (line 20) | public function test_fatal(): void

FILE: tests/Issues/StraussIssue19Test.php
  class StraussIssue19Test (line 14) | class StraussIssue19Test extends IntegrationTestCase
    method testObjectIsNotPrefixed (line 22) | public function testObjectIsNotPrefixed(): void

FILE: tests/Issues/StraussIssue200Test.php
  class StraussIssue200Test (line 14) | class StraussIssue200Test extends IntegrationTestCase
    method test_does_not_remove_vendor_autoload_dev_entries (line 16) | public function test_does_not_remove_vendor_autoload_dev_entries(): void

FILE: tests/Issues/StraussIssue204Test.php
  class StraussIssue204Test (line 14) | class StraussIssue204Test extends IntegrationTestCase
    method test_allow_specifying_alternative_composerjson (line 16) | public function test_allow_specifying_alternative_composerjson(): void

FILE: tests/Issues/StraussIssue206Test.php
  class StraussIssue206Test (line 14) | class StraussIssue206Test extends IntegrationTestCase
    method test_cleans_installedjson_autoloadfiles_on_vendor_delete_packages (line 16) | public function test_cleans_installedjson_autoloadfiles_on_vendor_dele...

FILE: tests/Issues/StraussIssue207Test.php
  class StraussIssue207Test (line 18) | class StraussIssue207Test extends IntegrationTestCase
    method test_fremius_files_are_copied (line 20) | public function test_fremius_files_are_copied(): void
    method test_action_scheduler_files_are_copied (line 53) | public function test_action_scheduler_files_are_copied(): void
    method test_plugin_update_checker_files_are_copied (line 83) | public function test_plugin_update_checker_files_are_copied(): void
    method test_abilities_api_files_are_copied (line 115) | public function test_abilities_api_files_are_copied(): void

FILE: tests/Issues/StraussIssue212Test.php
  class StraussIssue212Test (line 16) | class StraussIssue212Test extends IntegrationTestCase
    method test_symfony_polyfill_php83 (line 18) | public function test_symfony_polyfill_php83(): void

FILE: tests/Issues/StraussIssue213Test.php
  class StraussIssue213Test (line 14) | class StraussIssue213Test extends IntegrationTestCase
    method test_cleans_installedjson_autoloadfiles_on_vendor_delete_packages_with_unusual_path (line 19) | public function test_cleans_installedjson_autoloadfiles_on_vendor_dele...

FILE: tests/Issues/StraussIssue215Test.php
  class StraussIssue215Test (line 17) | class StraussIssue215Test extends IntegrationTestCase
    method test_all_files_are_copied (line 19) | public function test_all_files_are_copied(): void

FILE: tests/Issues/StraussIssue225Test.php
  class StraussIssue225Test (line 15) | class StraussIssue225Test extends IntegrationTestCase
    method test_non_autoloaded_template_file_has_namespace_updated (line 18) | public function test_non_autoloaded_template_file_has_namespace_update...

FILE: tests/Issues/StraussIssue22Test.php
  class StraussIssue22Test (line 16) | class StraussIssue22Test extends IntegrationTestCase
    method test_virtual_package (line 31) | public function test_virtual_package(): void
    method test_meta_package (line 81) | public function test_meta_package(): void

FILE: tests/Issues/StraussIssue230Test.php
  class StraussIssue230Test (line 18) | class StraussIssue230Test extends IntegrationTestCase
    method test_return_type_double_prefixed (line 21) | public function test_return_type_double_prefixed(): void

FILE: tests/Issues/StraussIssue247Test.php
  class StraussIssue247Test (line 16) | class StraussIssue247Test extends IntegrationTestCase
    method test_return_type_double_prefixed (line 19) | public function test_return_type_double_prefixed(): void

FILE: tests/Issues/StraussIssue249Test.php
  class StraussIssue249Test (line 16) | class StraussIssue249Test extends IntegrationTestCase
    method test_return_type_double_prefixed (line 19) | public function test_return_type_double_prefixed(): void
    method extractPackageNamesFromInstalledJson (line 64) | private function extractPackageNamesFromInstalledJson(string $installe...

FILE: tests/Issues/StraussIssue258Test.php
  class StraussIssue258Test (line 15) | class StraussIssue258Test extends IntegrationTestCase
    method test_class_name_double_prefixed (line 18) | public function test_class_name_double_prefixed(): void

FILE: tests/Issues/StraussIssue261Test.php
  class StraussIssue261Test (line 16) | class StraussIssue261Test extends IntegrationTestCase
    method test_skip_missing_dir (line 19) | public function test_skip_missing_dir(): void

FILE: tests/Issues/StraussIssue262Test.php
  class StraussIssue262Test (line 15) | class StraussIssue262Test extends IntegrationTestCase
    method test_do_not_remove_symlink_exclude_from_copy (line 18) | public function test_do_not_remove_symlink_exclude_from_copy(): void

FILE: tests/Issues/StraussIssue27Test.php
  class StraussIssue27Test (line 16) | class StraussIssue27Test extends IntegrationTestCase
    method test_virtual_package (line 21) | public function test_virtual_package(): void

FILE: tests/Issues/StraussIssue33Test.php
  class StraussIssue33Test (line 16) | class StraussIssue33Test extends IntegrationTestCase
    method test_backtrack_limit_exhausted (line 21) | public function test_backtrack_limit_exhausted(): void
    method test_unit_backtrack_limit_exhausted (line 62) | public function test_unit_backtrack_limit_exhausted(): void

FILE: tests/Issues/StraussIssue34Test.php
  class StraussIssue34Test (line 16) | class StraussIssue34Test extends IntegrationTestCase
    method test_no_double_prefix_after_second_run (line 19) | public function test_no_double_prefix_after_second_run(): void

FILE: tests/Issues/StraussIssue37Test.php
  class StraussIssue37Test (line 15) | class StraussIssue37Test extends IntegrationTestCase
    method test_can_handle_psr_namespace_with_path_array (line 20) | public function test_can_handle_psr_namespace_with_path_array(): void

FILE: tests/Issues/StraussIssue44Test.php
  class StraussIssue44Test (line 14) | class StraussIssue44Test extends IntegrationTestCase
    method testStaticIsNotPrefixed (line 22) | public function testStaticIsNotPrefixed(): void

FILE: tests/Issues/StraussIssue47Test.php
  class StraussIssue47Test (line 20) | class StraussIssue47Test extends IntegrationTestCase
    method test_double_namespace (line 26) | public function test_double_namespace(): void
    method test_double_namespace_dont_copy_dependencies (line 87) | public function test_double_namespace_dont_copy_dependencies(): void
    method test_double_namespace_only_file_copied (line 173) | public function test_double_namespace_only_file_copied(): void

FILE: tests/Issues/StraussIssue49Test.php
  class StraussIssue49Test (line 14) | class StraussIssue49Test extends IntegrationTestCase
    method test_local_symlinked_repositories_fail (line 19) | public function test_local_symlinked_repositories_fail(): void

FILE: tests/Issues/StraussIssue65Test.php
  class StraussIssue65Test (line 14) | class StraussIssue65Test extends IntegrationTestCase
    method test_aws_prefixed_functions (line 20) | public function test_aws_prefixed_functions(): void

FILE: tests/Issues/StraussIssue66Test.php
  class StraussIssue66Test (line 16) | class StraussIssue66Test extends IntegrationTestCase
    method test_wp_graphql_prefix_main_class (line 21) | public function test_wp_graphql_prefix_main_class(): void

FILE: tests/Issues/StraussIssue74Test.php
  class StraussIssue74Test (line 16) | class StraussIssue74Test extends IntegrationTestCase
    method test_prefix_global_function (line 19) | public function test_prefix_global_function(): void
    method test_twig (line 56) | public function test_twig(): void

FILE: tests/Issues/StraussIssue76Test.php
  class StraussIssue76Test (line 16) | class StraussIssue76Test extends IntegrationTestCase
    method test_psr4_array (line 20) | public function test_psr4_array(): void

FILE: tests/Issues/StraussIssue79Test.php
  class StraussIssue79Test (line 18) | class StraussIssue79Test extends IntegrationTestCase
    method test_issue_79 (line 20) | public function test_issue_79(): void

FILE: tests/Issues/StraussIssue80Test.php
  class StraussIssue80Test (line 16) | class StraussIssue80Test extends IntegrationTestCase
    method test_issue_80 (line 21) | public function test_issue_80(): void
    method test_google_api_single_backslash_in_string (line 56) | public function test_google_api_single_backslash_in_string(): void

FILE: tests/Issues/StraussIssue81Test.php
  class StraussIssue81Test (line 16) | class StraussIssue81Test extends IntegrationTestCase
    method test_aliased_class (line 22) | public function test_aliased_class(): void
    method test_snake_case_cli_argument_supersedes_configured_option_false_to_true (line 96) | public function test_snake_case_cli_argument_supersedes_configured_opt...
    method test_snake_case_cli_argument_supersedes_configured_option_false_to_flag (line 127) | public function test_snake_case_cli_argument_supersedes_configured_opt...
    method test_snake_case_cli_argument_supersedes_configured_option_true_to_false (line 158) | public function test_snake_case_cli_argument_supersedes_configured_opt...
    method test_camel_case_cli_argument_supersedes_configured_option_false_to_true (line 189) | public function test_camel_case_cli_argument_supersedes_configured_opt...
    method test_camel_case_cli_argument_supersedes_configured_option_false_to_flag (line 219) | public function test_camel_case_cli_argument_supersedes_configured_opt...
    method test_camel_case_cli_argument_supersedes_configured_option_true_to_false (line 250) | public function test_camel_case_cli_argument_supersedes_configured_opt...

FILE: tests/Issues/StraussIssue83Test.php
  class StraussIssue83Test (line 16) | class StraussIssue83Test extends IntegrationTestCase
    method test_issue_83 (line 19) | public function test_issue_83(): void

FILE: tests/Issues/StraussIssue87Test.php
  class StraussIssue87Test (line 16) | class StraussIssue87Test extends IntegrationTestCase
    method test_autoload_classmap (line 18) | public function test_autoload_classmap(): void

FILE: tests/Issues/StraussIssue88Test.php
  class StraussIssue88Test (line 16) | class StraussIssue88Test extends IntegrationTestCase
    method test_returned_casted_function_call (line 18) | public function test_returned_casted_function_call(): void

FILE: tests/Issues/StraussIssue8Test.php
  class StraussIssue8Test (line 15) | class StraussIssue8Test extends IntegrationTestCase
    method test_delete_vendor_files (line 23) | public function test_delete_vendor_files(): void

FILE: tests/Issues/StraussIssue91Test.php
  class StraussIssue91Test (line 16) | class StraussIssue91Test extends IntegrationTestCase
    method test_issue_91 (line 18) | public function test_issue_91(): void

FILE: tests/Issues/StraussIssue93Test.php
  class StraussIssue93Test (line 16) | class StraussIssue93Test extends IntegrationTestCase
    method test_removes_entries_from_installed_json (line 18) | public function test_removes_entries_from_installed_json(): void

FILE: tests/Issues/data/Mpdf.php
  class Mpdf (line 28) | class Mpdf implements \Psr\Log\LoggerAwareInterface
    method __construct (line 1032) | public function __construct(array $config = [])
    method cleanup (line 1550) | public function cleanup()
    method setLogger (line 1569) | public function setLogger(LoggerInterface $logger)
    method initConfig (line 1582) | private function initConfig(array $config)
    method initConstructorParams (line 1595) | private function initConstructorParams(array $config)
    method initFontConfig (line 1620) | private function initFontConfig(array $config)
    method _setPageSize (line 1632) | function _setPageSize($format, &$orientation)
    method RestrictUnicodeFonts (line 1686) | function RestrictUnicodeFonts($res)
    method setMBencoding (line 1700) | function setMBencoding($enc)
    method SetMargins (line 1708) | function SetMargins($left, $right, $top)
    method ResetMargins (line 1716) | function ResetMargins()
    method SetLeftMargin (line 1745) | function SetLeftMargin($margin)
    method SetTopMargin (line 1754) | function SetTopMargin($margin)
    method SetRightMargin (line 1760) | function SetRightMargin($margin)
    method SetAutoPageBreak (line 1766) | function SetAutoPageBreak($auto, $margin = 0)
    method SetDisplayMode (line 1774) | function SetDisplayMode($zoom, $layout = 'continuous')
    method SetCompression (line 1793) | function SetCompression($compress)
    method SetTitle (line 1803) | function SetTitle($title)
    method SetSubject (line 1809) | function SetSubject($subject)
    method SetAuthor (line 1815) | function SetAuthor($author)
    method SetKeywords (line 1821) | function SetKeywords($keywords)
    method SetCreator (line 1827) | function SetCreator($creator)
    method AddCustomProperty (line 1833) | function AddCustomProperty($key, $value)
    method SetAssociatedFiles (line 1861) | function SetAssociatedFiles(array $files)
    method SetAdditionalXmpRdf (line 1866) | function SetAdditionalXmpRdf($s)
    method SetAnchor2Bookmark (line 1871) | function SetAnchor2Bookmark($x)
    method AliasNbPages (line 1876) | public function AliasNbPages($alias = '{nb}')
    method AliasNbPageGroups (line 1882) | public function AliasNbPageGroups($alias = '{nbpg}')
    method SetAlpha (line 1888) | function SetAlpha($alpha, $bm = 'Normal', $return = false, $mode = 'B')
    method AddExtGState (line 1917) | function AddExtGState($parms)
    method SetVisibility (line 1940) | function SetVisibility($v)
    method Open (line 1967) | function Open()
    method Close (line 1980) | function Close()
    method _resizeBackgroundImage (line 2053) | function _resizeBackgroundImage($imw, $imh, $cw, $ch, $resize, $repx, ...
    method SetBackground (line 2148) | function SetBackground(&$properties, &$maxwidth)
    method PrintBodyBackgrounds (line 2243) | function PrintBodyBackgrounds()
    method _setClippingPath (line 2299) | function _setClippingPath($clx, $cly, $clw, $clh)
    method PrintPageBackgrounds (line 2311) | function PrintPageBackgrounds($adjustmenty = 0)
    method PrintTableBackgrounds (line 2578) | function PrintTableBackgrounds($adjustmenty = 0)
    method BeginLayer (line 2757) | function BeginLayer($id)
    method EndLayer (line 2780) | function EndLayer()
    method AddPageByArray (line 2788) | function AddPageByArray($a)
    method _preForcedPagebreak (line 2820) | function _preForcedPagebreak($pagebreaktype)
    method _postForcedPagebreak (line 2855) | function _postForcedPagebreak($pagebreaktype, $startpage, $save_blk, $...
    method AddPage (line 2903) | function AddPage(
    method PageNo (line 3325) | function PageNo()
    method AddSpotColorsFromFile (line 3330) | function AddSpotColorsFromFile($file)
    method AddSpotColor (line 3346) | function AddSpotColor($name, $c, $m, $y, $k)
    method SetColor (line 3356) | function SetColor($col, $type = '')
    method SetDColor (line 3380) | function SetDColor($col, $return = false)
    method SetFColor (line 3396) | function SetFColor($col, $return = false)
    method SetTColor (line 3413) | function SetTColor($col, $return = false)
    method SetDrawColor (line 3426) | function SetDrawColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
    method SetFillColor (line 3441) | function SetFillColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
    method SetTextColor (line 3456) | function SetTextColor($r, $g = -1, $b = -1, $col4 = -1, $return = false)
    method _getCharWidth (line 3471) | function _getCharWidth(&$cw, $u, $isdef = true)
    method _charDefined (line 3492) | function _charDefined(&$cw, $u)
    method GetCharWidthCore (line 3505) | function GetCharWidthCore($c)
    method GetCharWidthNonCore (line 3536) | function GetCharWidthNonCore($c, $addSubset = true)
    method GetCharWidth (line 3597) | function GetCharWidth($c, $addSubset = true)
    method GetStringWidth (line 3606) | function GetStringWidth($s, $addSubset = true, $OTLdata = false, $text...
    method SetLineWidth (line 3745) | function SetLineWidth($width)
    method Line (line 3756) | function Line($x1, $y1, $x2, $y2)
    method Arrow (line 3762) | function Arrow($x1, $y1, $x2, $y2, $headsize = 3, $fill = 'B', $angle ...
    method Rect (line 3794) | function Rect($x, $y, $w, $h, $style = '')
    method AddFontDirectory (line 3807) | function AddFontDirectory($directory)
    method AddFont (line 3813) | function AddFont($family, $style = '')
    method SetFont (line 4020) | function SetFont($family, $style = '', $size = 0, $write = true, $forc...
    method SetFontSize (line 4284) | function SetFontSize($size, $write = true)
    method AddLink (line 4303) | function AddLink()
    method SetLink (line 4311) | function SetLink($link, $y = 0, $page = -1)
    method Link (line 4323) | function Link($x, $y, $w, $h, $link)
    method Text (line 4348) | function Text($x, $y, $txt, $OTLdata = [], $textvar = 0, $aixextra = '...
    method WriteText (line 4483) | function WriteText($x, $y, $txt)
    method WriteCell (line 4524) | function WriteCell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align...
    method ResetSpacing (line 4566) | function ResetSpacing()
    method SetSpacing (line 4578) | function SetSpacing($cs, $ws)
    method GetJspacing (line 4601) | function GetJspacing($nc, $ns, $w, $inclCursive, &$cOTLdata)
    method Cell (line 4734) | function Cell($w, $h = 0, $txt = '', $border = 0, $ln = 0, $align = ''...
    method applyGPOSpdf (line 5418) | function applyGPOSpdf($txt, $aix, $x, $y, $OTLdata, $textvar = 0)
    method _kern (line 5768) | function _kern($txt, $mode, $aix, $x, $y)
    method MultiCell (line 5833) | function MultiCell(
    method Write (line 6222) | function Write($h, $txt, $currentx = 0, $link = '', $directionality = ...
    method saveInlineProperties (line 6236) | function saveInlineProperties()
    method restoreInlineProperties (line 6266) | function restoreInlineProperties(&$saved)
    method GetFirstBlockFill (line 6322) | function GetFirstBlockFill()
    method saveFont (line 6339) | function saveFont()
    method restoreFont (line 6365) | function restoreFont(&$saved, $write = true)
    method newFlowingBlock (line 6404) | function newFlowingBlock($w, $h, $a = '', $is_table = false, $blocksta...
    method finishFlowingBlock (line 6436) | function finishFlowingBlock($endofblock = false, $next = '')
    method printobjectbuffer (line 7095) | function printobjectbuffer($is_table = false, $blockdir = false)
    method _printListBullet (line 7667) | function _printListBullet($x, $y, $size, $type, $color)
    method _moveToPrevChar (line 7689) | function _moveToPrevChar(&$contentctr, &$charctr, $content)
    method _getPrevChar (line 7713) | function _getPrevChar($contentctr, $charctr, $content)
    method WriteFlowingBlock (line 7736) | function WriteFlowingBlock($s, $sOTLdata)
    method _advanceFloatMargins (line 8760) | function _advanceFloatMargins()
    method _SetTextRendering (line 8806) | function _SetTextRendering($mode)
    method SetTextOutline (line 8818) | function SetTextOutline($params = [])
    method Image (line 8840) | function Image($file, $x, $y, $w = 0, $h = 0, $type = '', $link = '', ...
    method _getObjAttr (line 9074) | function _getObjAttr($t)
    method inlineObject (line 9085) | function inlineObject($type, $x, $y, $objattr, $Lmargin, $widthUsed, $...
    method SetLineJoin (line 9312) | function SetLineJoin($mode = 0)
    method SetLineCap (line 9321) | function SetLineCap($mode = 2)
    method SetDash (line 9330) | function SetDash($black = false, $white = false)
    method SetDisplayPreferences (line 9345) | function SetDisplayPreferences($preferences)
    method Ln (line 9352) | function Ln($h = '', $collapsible = 0)
    method DivLn (line 9374) | function DivLn($h, $level = -3, $move_y = true, $collapsible = false, ...
    method SetX (line 9450) | function SetX($x)
    method SetY (line 9460) | function SetY($y)
    method SetXY (line 9471) | function SetXY($x, $y)
    method Output (line 9478) | function Output($name = '', $dest = '')
    method _dochecks (line 9633) | function _dochecks()
    method _puthtmlheaders (line 9662) | function _puthtmlheaders()
    method Annotation (line 9871) | function Annotation($text, $x = 0, $y = 0, $icon = 'Note', $author = '...
    method _enddoc (line 9941) | function _enddoc()
    method _beginpage (line 10064) | function _beginpage(
    method _setAutoHeaderHeight (line 10398) | function _setAutoHeaderHeight(&$htmlh)
    method _setAutoFooterHeight (line 10425) | function _setAutoFooterHeight(&$htmlf)
    method _endpage (line 10453) | function _endpage()
    method _dounderline (line 10467) | function _dounderline($x, $y, $txt, $OTLdata = false, $textvar = 0)
    method watermark (line 10481) | function watermark($texte, $angle = 45, $fontsize = 96, $alpha = 0.2)
    method watermarkImg (line 10566) | function watermarkImg($src, $alpha = 0.2)
    method Rotate (line 10587) | function Rotate($angle, $x = -1, $y = -1)
    method CircularText (line 10609) | function CircularText($x, $y, $r, $text, $align = 'top', $fontfamily =...
    method RoundedRect (line 10619) | function RoundedRect($x, $y, $w, $h, $r, $style = '')
    method _Arc (line 10656) | function _Arc($x1, $y1, $x2, $y2, $x3, $y3)
    method Shaded_box (line 10667) | function Shaded_box($text, $font = '', $fontstyle = 'B', $szfont = '',...
    method UTF8StringToArray (line 10678) | function UTF8StringToArray($str, $addSubset = true)
    method UTF8toSubset (line 10707) | function UTF8toSubset($str)
    method AddCIDFont (line 10769) | function AddCIDFont($family, $style, $name, &$cw, $CMap, $registry, $d...
    method AddCJKFont (line 10786) | function AddCJKFont($family)
    method AddBig5Font (line 10803) | function AddBig5Font()
    method AddGBFont (line 10826) | function AddGBFont()
    method AddSJISFont (line 10850) | function AddSJISFont()
    method AddUHCFont (line 10874) | function AddUHCFont()
    method SetDefaultFont (line 10908) | function SetDefaultFont($font)
    method SetDefaultFontSize (line 10932) | function SetDefaultFontSize($fontsize)
    method SetDefaultBodyCSS (line 10941) | function SetDefaultBodyCSS($prop, $val)
    method SetDirectionality (line 10949) | function SetDirectionality($dir = 'ltr')
    method fixLineheight (line 10976) | function fixLineheight($v)
    method _getNormalLineheight (line 10992) | function _getNormalLineheight($desc = false)
    method SetLineHeight (line 11011) | function SetLineHeight($FontPt = '', $lh = '')
    method _computeLineheight (line 11020) | function _computeLineheight($lh, $fs = '')
    method _setLineYpos (line 11041) | function _setLineYpos(&$fontsize, &$fontdesc, &$CSSlineheight, $blockY...
    method _setInlineBlockHeights (line 11115) | function _setInlineBlockHeights(&$lineBox, &$stackHeight, &$content, &...
    method SetBasePath (line 11405) | function SetBasePath($str = '')
    method GetFullPath (line 11452) | public function GetFullPath(&$path, $basepath = '')
    method docPageNum (line 11525) | function docPageNum($num = 0, $extras = false)
    method docPageNumTotal (line 11574) | function docPageNumTotal($num = 0, $extras = false)
    method _getStyledNumber (line 11627) | function _getStyledNumber($ppgno, $type, $listmarker = false)
    method docPageSettings (line 11679) | function docPageSettings($num = 0)
    method RestartDocTemplate (line 11724) | function RestartDocTemplate()
    method Header (line 11730) | function Header($content = '')
    method TableHeaderFooter (line 11744) | function TableHeaderFooter($content = '', $tablestartpage = '', $table...
    method SetHTMLHeader (line 12257) | function SetHTMLHeader($header = '', $OE = '', $write = false)
    method SetHTMLFooter (line 12324) | function SetHTMLFooter($footer = '', $OE = '')
    method _getHtmlHeight (line 12390) | function _getHtmlHeight($html)
    method writeHTMLHeaders (line 12439) | function writeHTMLHeaders()
    method writeHTMLFooters (line 12472) | function writeHTMLFooters()
    method _shareHeaderFooterWidth (line 12510) | function _shareHeaderFooterWidth($cl, $cc, $cr)
    method _createHTMLheaderFooter (line 12527) | function _createHTMLheaderFooter($arr, $hf)
    method DefHeaderByName (line 12636) | function DefHeaderByName($name, $arr)
    method DefFooterByName (line 12647) | function DefFooterByName($name, $arr)
    method SetHeaderByName (line 12658) | function SetHeaderByName($name, $side = 'O', $write = false)
    method SetFooterByName (line 12666) | function SetFooterByName($name, $side = 'O')
    method DefHTMLHeaderByName (line 12674) | function DefHTMLHeaderByName($name, $html)
    method DefHTMLFooterByName (line 12684) | function DefHTMLFooterByName($name, $html)
    method SetHTMLHeaderByName (line 12694) | function SetHTMLHeaderByName($name, $side = 'O', $write = false)
    method SetHTMLFooterByName (line 12702) | function SetHTMLFooterByName($name, $side = 'O')
    method SetHeader (line 12710) | function SetHeader($Harray = [], $side = '', $write = false)
    method SetFooter (line 12857) | function SetFooter($Farray = [], $side = '')
    method SetWatermarkText (line 13005) | function SetWatermarkText($txt = '', $alpha = -1)
    method SetWatermarkImage (line 13013) | function SetWatermarkImage($src, $alpha = -1, $size = 'D', $pos = 'F')
    method Footer (line 13026) | function Footer()
    method WriteHTML (line 13145) | function WriteHTML($html, $mode = HTMLParserMode::DEFAULT_MODE, $init ...
    method WriteFixedPosHTML (line 13908) | function WriteFixedPosHTML($html, $x, $y, $w, $h, $overflow = 'visible...
    method initialiseBlock (line 14772) | function initialiseBlock(&$blk)
    method border_details (line 14800) | function border_details($bd)
    method _borderPadding (line 14884) | function _borderPadding($a, $b, &$px, &$py)
    method SetPagedMediaCSS (line 14908) | function SetPagedMediaCSS($name, $first, $oddEven)
    method ClearFloats (line 15278) | function ClearFloats($clear, $blklvl = 0)
    method GetFloatDivInfo (line 15310) | function GetFloatDivInfo($blklvl = 0, $clear = false)
    method _setListMarker (line 15342) | function _setListMarker($listitemtype, $listitemimage, $listitemposition)
    method _getListMarkerWidth (line 15574) | function _getListMarkerWidth(&$currblk, &$a, &$i)
    method _saveTextBuffer (line 15761) | function _saveTextBuffer($t, $link = '', $intlink = '', $return = false)
    method _saveCellTextBuffer (line 15826) | function _saveCellTextBuffer($t, $link = '', $intlink = '')
    method printbuffer (line 15881) | function printbuffer($arrayaux, $blockstate = 0, $is_table = false, $t...
    method _setDashBorder (line 16597) | function _setDashBorder($style, $div, $cp, $side)
    method _setBorderLine (line 16611) | function _setBorderLine($b, $k = 1)
    method PaintDivBB (line 16622) | function PaintDivBB($divider = '', $blockstate = 0, $blvl = 0)
    method _EllipseArc (line 17750) | function _EllipseArc($x0, $y0, $rx, $ry, $seg = 1, $part = false, $sta...
    method PaintDivLnBorder (line 17822) | function PaintDivLnBorder($state = 0, $blvl = 0, $h = 0)
    method PaintImgBorder (line 17922) | function PaintImgBorder($objattr, $is_table)
    method Reset (line 18001) | function Reset()
    method ReadMetaTags (line 18077) | function ReadMetaTags($html)
    method ReadCharset (line 18105) | function ReadCharset($html)
    method setCSS (line 18117) | function setCSS($arrayaux, $type = '', $tag = '')
    method SetStyle (line 18979) | function SetStyle($tag, $enable)
    method SetStylesArray (line 18993) | function SetStylesArray($arr)
    method SetStyles (line 19013) | function SetStyles($str)
    method ResetStyles (line 19028) | function ResetStyles()
    method DisableTags (line 19037) | function DisableTags($str = '')
    method TableCheckMinWidth (line 19052) | function TableCheckMinWidth($maxwidth, $forcewrap = 0, $textbuffer = [...
    method shrinkTable (line 19287) | function shrinkTable(&$table, $k)
    method read_short (line 19431) | function read_short(&$fh)
    method _packCellBorder (line 19441) | function _packCellBorder($cell)
    method _getBorderWidths (line 19455) | function _getBorderWidths($bindata)
    method _unpackCellBorder (line 19472) | function _unpackCellBorder($bindata)
    method _tableColumnWidth (line 19533) | function _tableColumnWidth(&$table, $firstpass = false)
    method _tableWidth (line 20003) | function _tableWidth(&$table)
    method _tableHeight (line 20305) | function _tableHeight(&$table)
    method _tableGetWidth (line 20640) | function _tableGetWidth(&$table, $i, $j)
    method _splitTableGetWidth (line 20665) | function _splitTableGetWidth(&$table, $i, $j)
    method _tableGetHeight (line 20695) | function _tableGetHeight(&$table, $i, $j)
    method _tableGetMaxRowHeight (line 20724) | function _tableGetMaxRowHeight($table, $row)
    method _tableRect (line 20751) | function _tableRect($x, $y, $w, $h, $bord = -1, $details = [], $buffer...
    method setBorder (line 21284) | function setBorder(&$var, $flag, $set = true)
    method issetBorder (line 21294) | function issetBorder($var, $flag)
    method _table2cellBorder (line 21301) | function _table2cellBorder(&$tableb, &$cbdb, &$cellb, $bval)
    method _fixTableBorders (line 21313) | function _fixTableBorders(&$table)
    method _reverseTableDir (line 21830) | function _reverseTableDir(&$table)
    method _tableWrite (line 21869) | function _tableWrite(&$table, $split = false, $startrow = 0, $startcol...
    method _putextgstates (line 23307) | function _putextgstates()
    method SetProtection (line 23321) | function SetProtection($permissions = [], $user_pass = '', $owner_pass...
    method Bookmark (line 23328) | function Bookmark($txt, $level = 0, $y = 0)
    method TOC (line 23362) | function TOC(
    method TOCpagebreakByArray (line 23391) | function TOCpagebreakByArray($a)
    method TOCpagebreak (line 23444) | function TOCpagebreak($tocfont = '', $tocfontsize = '', $tocindent = '...
    method TOC_Entry (line 23465) | function TOC_Entry($txt, $level = 0, $toc_id = 0)
    method MovePages (line 23512) | function MovePages($target_page, $start_page, $end_page = -1)
    method DeletePages (line 23770) | function DeletePages($start_page, $end_page = -1)
    method IndexEntry (line 23940) | function IndexEntry($txt, $xref = '')
    method IndexEntrySee (line 23981) | function IndexEntrySee($txta, $txtb)
    method filesInDir (line 24003) | private function filesInDir($directory)
    method InsertIndex (line 24017) | function InsertIndex($usedivletters = 1, $useLinking = false, $indexCo...
    method AcceptPageBreak (line 24237) | function AcceptPageBreak()
    method SetColumns (line 24287) | function SetColumns($NbCol, $vAlign = '', $gap = 5)
    method SetCol (line 24369) | function SetCol($CurrCol)
    method AddColumn (line 24383) | function AddColumn()
    method NewColumn (line 24389) | function NewColumn()
    method printcolumnbuffer (line 24424) | function printcolumnbuffer()
    method columnAdjustPregReplace (line 24892) | function columnAdjustPregReplace($type, $xadj, $yadj, $pattern, $subject)
    method printcellbuffer (line 24922) | function printcellbuffer()
    method printtablebuffer (line 24969) | function printtablebuffer()
    method printkwtbuffer (line 25145) | function printkwtbuffer()
    method printfloatbuffer (line 25323) | function printfloatbuffer()
    method Circle (line 25334) | function Circle($x, $y, $r, $style = 'S')
    method Ellipse (line 25339) | function Ellipse($x, $y, $rx, $ry, $style = 'S')
    method AutosizeText (line 25361) | function AutosizeText($text, $w, $font, $style, $szfont = 72)
    method magic_reverse_dir (line 25428) | function magic_reverse_dir(&$chunk, $dir, &$chunkOTLdata)
    method getBasicOTLdata (line 25474) | function getBasicOTLdata(&$chunkOTLdata, $unicode, &$is_strong)
    method _setBidiCodes (line 25503) | function _setBidiCodes($mode = 'start', $bdf = '')
    method SetSubstitutions (line 25544) | function SetSubstitutions()
    method SubstituteChars (line 25554) | function SubstituteChars($html)
    method SubstituteCharsSIP (line 25571) | function SubstituteCharsSIP(&$writehtml_a, &$writehtml_i, &$writehtml_e)
    method SubstituteCharsNonCore (line 25592) | function SubstituteCharsNonCore(&$writehtml_a, &$writehtml_i, &$writeh...
    method SubstituteCharsMB (line 25708) | function SubstituteCharsMB(&$writehtml_a, &$writehtml_i, &$writehtml_e)
    method setHiEntitySubstitutions (line 25980) | function setHiEntitySubstitutions()
    method SubstituteHiEntities (line 25990) | function SubstituteHiEntities($html)
    method is_utf8 (line 26004) | function is_utf8(&$string)
    method purify_utf8 (line 26026) | function purify_utf8($html, $lo = true)
    method purify_utf8_text (line 26068) | function purify_utf8_text($txt)
    method all_entities_to_utf8 (line 26080) | function all_entities_to_utf8($txt)
    method WriteBarcode (line 26100) | function WriteBarcode($code, $showtext = 1, $x = '', $y = '', $size = ...
    method WriteBarcode2 (line 26480) | function WriteBarcode2($code, $x = '', $y = '', $size = 1, $height = 1...
    method StartTransform (line 26574) | function StartTransform($returnstring = false)
    method StopTransform (line 26583) | function StopTransform($returnstring = false)
    method transformScale (line 26592) | function transformScale($s_x, $s_y, $x = '', $y = '', $returnstring = ...
    method transformTranslate (line 26628) | function transformTranslate($t_x, $t_y, $returnstring = false)
    method transformRotate (line 26647) | function transformRotate($angle, $x = '', $y = '', $returnstring = false)
    method transformSkew (line 26681) | function transformSkew($angle_x, $angle_y, $x = '', $y = '', $returnst...
    method _transform (line 26714) | function _transform($tm, $returnstring = false)
    method markScriptToLang (line 26724) | function markScriptToLang($html)
    method columnAdjustAdd (line 26850) | function columnAdjustAdd($type, $k, $xadj, $yadj, $a, $b, $c = 0, $d =...
    method ConvertAngle (line 26903) | function ConvertAngle($s, $makepositive = true)
    method lesser_entity_decode (line 26938) | function lesser_entity_decode($html)
    method AdjustHTML (line 26951) | function AdjustHTML($html, $tabSpaces = 8)
    method tabs2spaces_callback (line 27120) | function tabs2spaces_callback($matches)
    method date_callback (line 27126) | function date_callback($matches)
    method OverWrite (line 27132) | function OverWrite($file_in, $search, $replacement, $dest = Destinatio...
    method Thumbnail (line 27292) | function Thumbnail($file, $npr = 3, $spacing = 10)
    method SetPageTemplate (line 27336) | function SetPageTemplate($tplidx = '')
    method SetDocTemplate (line 27345) | function SetDocTemplate($file = '', $continue = 0, $continue2pages = 0)
    method _set_object_javascript (line 27359) | function _set_object_javascript($string)
    method SetJS (line 27369) | function SetJS($script)
    method toFloat (line 27381) | public function toFloat($num)
    method getFontDescriptor (line 27397) | public function getFontDescriptor()
    method _out (line 27405) | public function _out($s)
    method aliasReplace (line 27417) | protected function aliasReplace($html, $PAGENO, $NbPgGp, $NbPg)

FILE: tests/TestCase.php
  class TestCase (line 22) | class TestCase extends \PHPUnit\Framework\TestCase
    method assertEqualsRN (line 38) | public static function assertEqualsRN($expected, $actual, string $mess...
    method assertEqualsRemoveBlankLinesLeadingWhitespace (line 48) | public static function assertEqualsRemoveBlankLinesLeadingWhitespace($...
    method assertStringContainsStringRemoveBlankLinesLeadingWhitespace (line 57) | public static function assertStringContainsStringRemoveBlankLinesLeadi...
    method stripWhitespaceAndBlankLines (line 66) | protected static function stripWhitespaceAndBlankLines(string $string)...
    method getFileSystem (line 77) | protected function getFileSystem(): Filesystem
    method getNewFileSystem (line 87) | protected function getNewFileSystem(): Filesystem
    method getInMemoryFileSystem (line 113) | protected function getInMemoryFileSystem(): FileSystem
    method getNewInMemoryFileSystem (line 122) | protected function getNewInMemoryFileSystem(): FileSystem
    method tearDown (line 160) | protected function tearDown(): void
    method getLogger (line 177) | protected function getLogger(): LoggerInterface
    method getNewLogger (line 186) | protected function getNewLogger(): LoggerInterface
    method getTestLogger (line 199) | protected function getTestLogger(): TestLogger
    method markTestSkippedOnWindows (line 208) | protected function markTestSkippedOnWindows(string $message = 'Skipped...

FILE: tests/Unit/Composer/ComposerPackageTest.php
  class ComposerPackageTest (line 12) | class ComposerPackageTest extends TestCase
    method testParseJson (line 18) | public function testParseJson(): void
    method testGetRequiresNames (line 35) | public function testGetRequiresNames(): void
    method testGetRequiresNamesDoesNotContain (line 51) | public function testGetRequiresNamesDoesNotContain(): void
    method testAutoloadPsr0 (line 68) | public function testAutoloadPsr0(): void
    method testAutoloadPsr4 (line 85) | public function testAutoloadPsr4(): void
    method testAutoloadClassmap (line 102) | public function testAutoloadClassmap(): void
    method testAutoloadFiles (line 119) | public function testAutoloadFiles(): void
    method testPsr4Array (line 133) | public function testPsr4Array(): void
    method testOverrideAutoload (line 165) | public function testOverrideAutoload(): void
    method testMissingComposer (line 173) | public function testMissingComposer(): void
    method test_is_copy (line 182) | public function test_is_copy(): void
    method test_did_copy (line 199) | public function test_did_copy(): void
    method test_is_delete (line 216) | public function test_is_delete(): void
    method test_did_delete (line 233) | public function test_did_delete(): void
    method testGetPackageAbsolutePathHasNoBackslashes (line 254) | public function testGetPackageAbsolutePathHasNoBackslashes(): void

FILE: tests/Unit/Composer/Extra/StraussConfigTest.php
  class StraussConfigTest (line 22) | class StraussConfigTest extends TestCase
    method getInput (line 24) | protected function getInput(string $cli): InputInterface
    method testGetters (line 46) | public function testGetters(): void
    method testExtraKey (line 107) | public function testExtraKey(): void
    method testDefaultTargetDir (line 162) | public function testDefaultTargetDir(): void
    method testDefaultNamespacePrefixFromAutoloaderPsr4 (line 208) | public function testDefaultNamespacePrefixFromAutoloaderPsr4(): void
    method testDefaultNamespacePrefixFromAutoloaderPsr0 (line 239) | public function testDefaultNamespacePrefixFromAutoloaderPsr0(): void
    method testDefaultNamespacePrefixWithNoAutoloader (line 271) | public function testDefaultNamespacePrefixWithNoAutoloader(): void
    method testDefaultClassmapPrefixFromAutoloaderPsr4 (line 296) | public function testDefaultClassmapPrefixFromAutoloaderPsr4(): void
    method testDefaultClassmapPrefixFromAutoloaderPsr0 (line 327) | public function testDefaultClassmapPrefixFromAutoloaderPsr0(): void
    method testDefaultClassmapPrefixWithNoAutoloader (line 360) | public function testDefaultClassmapPrefixWithNoAutoloader(): void
    method testGetPackagesFromConfig (line 385) | public function testGetPackagesFromConfig(): void
    method testGetOldSyntaxExcludePackagesFromPrefixing (line 429) | public function testGetOldSyntaxExcludePackagesFromPrefixing(): void
    method testGetExcludePackagesFromPrefixing (line 457) | public function testGetExcludePackagesFromPrefixing(): void
    method testGetExcludeFilePatternsFromPrefixingDefault (line 486) | public function testGetExcludeFilePatternsFromPrefixingDefault(): void
    method testGetExcludeFilePatternsFromPrefixingDefaultAfterExcludingPackages (line 511) | public function testGetExcludeFilePatternsFromPrefixingDefaultAfterExc...
    method testGetPackagesNoConfig (line 541) | public function testGetPackagesNoConfig(): void
    method testMapMozartConfig (line 583) | public function testMapMozartConfig(): void
    method testNamespacePrefixHasNoSlash (line 645) | public function testNamespacePrefixHasNoSlash(): void
    method testIncludeModifiedDateDefaultTrue (line 667) | public function testIncludeModifiedDateDefaultTrue(): void
    method testIncludeModifiedDate (line 694) | public function testIncludeModifiedDate(): void
    method testIncludeAuthorDefaultTrue (line 718) | public function testIncludeAuthorDefaultTrue(): void
    method testIncludeAuthorFalse (line 741) | public function testIncludeAuthorFalse(): void
    method testDeleteVendorPackages (line 764) | public function testDeleteVendorPackages(): void
    method testUpdateCallSitesConfigTrue (line 788) | public function testUpdateCallSitesConfigTrue(): void
    method testUpdateCallSitesConfigFalse (line 812) | public function testUpdateCallSitesConfigFalse(): void
    method testUpdateCallSitesConfigList (line 838) | public function testUpdateCallSitesConfigList(): void
    method testUpdateCallSitesCliTrue (line 864) | public function testUpdateCallSitesCliTrue(): void
    method testUpdateCallSitesCliFalse (line 892) | public function testUpdateCallSitesCliFalse(): void
    method testUpdateCallSitesCliList (line 921) | public function testUpdateCallSitesCliList(): void
    method test_functions_prefix (line 949) | public function test_functions_prefix(): void
    method test_functions_prefix_disabled (line 973) | public function test_functions_prefix_disabled(): void
    method test_functions_not_set (line 998) | public function test_functions_not_set(): void
    method testConstantPrefixIsMappedFromComposerExtra (line 1022) | public function testConstantPrefixIsMappedFromComposerExtra(): void
    method test_optimize_autoloader_default_true (line 1045) | public function test_optimize_autoloader_default_true(): void
    method test_optimize_autoloader_false (line 1067) | public function test_optimize_autoloader_false(): void

FILE: tests/Unit/Composer/ProjectComposerPackageTest.php
  class ProjectComposerPackageTest (line 13) | class ProjectComposerPackageTest extends TestCase
    method testParseJson (line 19) | public function testParseJson(): void
    method testGetFlatAutoloadKey (line 34) | public function testGetFlatAutoloadKey(): void

FILE: tests/Unit/Console/ApplicationTest.php
  class ApplicationTest (line 11) | class ApplicationTest extends TestCase
    method testInstantiation (line 17) | public function testInstantiation(): void

FILE: tests/Unit/Console/Commands/DependenciesCommandTest.php
  class DependenciesCommandTest (line 17) | class DependenciesCommandTest extends TestCase
    method getSut (line 20) | protected function getSut(
    method it_fails_gracefully_when_composer_json_absent (line 57) | public function it_fails_gracefully_when_composer_json_absent(): void
    method it_handles_malformed_json_with_grace (line 91) | public function it_handles_malformed_json_with_grace(): void
    method test_it_handles_absent_extra_config_with_grace (line 129) | public function test_it_handles_absent_extra_config_with_grace(): void
    method it_handles_malformed_extra_config_with_grace (line 166) | public function it_handles_malformed_extra_config_with_grace(): void
    method it_handles_absent_mozart_config_with_grace (line 204) | public function it_handles_absent_mozart_config_with_grace(): void
    method it_handles_malformed_mozart_config__with_grace (line 244) | public function it_handles_malformed_mozart_config__with_grace(): void

FILE: tests/Unit/DiscoveredFilesTest.php
  class DiscoveredFilesTest (line 17) | class DiscoveredFilesTest extends TestCase
    method testFileCanBeAddedAndGotten (line 27) | public function testFileCanBeAddedAndGotten(): void
    method testFileMultipleFilesWithDifferentPathsCanBeAddedAndGotten (line 56) | public function testFileMultipleFilesWithDifferentPathsCanBeAddedAndGo...
    method testFilesWithSamePathsAreOverwritten (line 92) | public function testFilesWithSamePathsAreOverwritten(): void

FILE: tests/Unit/FileEnumeratorTest.php
  class FileEnumeratorTest (line 23) | class FileEnumeratorTest extends TestCase
    method test_file_does_not_exist (line 28) | public function test_file_does_not_exist(): void

FILE: tests/Unit/Files/FileWithDependencyTest.php
  class FileWithDependencyTest (line 12) | class FileWithDependencyTest extends TestCase
    method test_is_do_delete (line 19) | public function test_is_do_delete(): void
    method test_handles_null_package_absolute_path (line 47) | public function test_handles_null_package_absolute_path(): void

FILE: tests/Unit/Helpers/FileSystemTest.php
  class FileSystemTest (line 14) | class FileSystemTest extends TestCase
    method testFileAttributes (line 22) | public function testFileAttributes(): void
    method testIsDirTrue (line 41) | public function testIsDirTrue(): void
    method testMakeAbsoluteAddsLeadingSlashForUnixPaths (line 68) | public function testMakeAbsoluteAddsLeadingSlashForUnixPaths(): void
    method testMakeAbsolutePreservesWindowsDriveLetter (line 96) | public function testMakeAbsolutePreservesWindowsDriveLetter(): void
    method testMakeAbsolutePreservesLowercaseWindowsDriveLetter (line 124) | public function testMakeAbsolutePreservesLowercaseWindowsDriveLetter()...
    method testMakeAbsoluteRestoresLeadingSlashAfterNormalization (line 155) | public function testMakeAbsoluteRestoresLeadingSlashAfterNormalization...
    method testIsDirFalse (line 181) | public function testIsDirFalse(): void
    method testDirectoryExistsWithRelativePathSegments (line 209) | public function testDirectoryExistsWithRelativePathSegments(): void
    method testDirectoryExistsWithMultipleRelativeSegments (line 240) | public function testDirectoryExistsWithMultipleRelativeSegments(): void
    method testDirectoryExistsWithRelativePathSegmentsNonExistent (line 269) | public function testDirectoryExistsWithRelativePathSegmentsNonExistent...

FILE: tests/Unit/Helpers/NamespaceSortTest.php
  class NamespaceSortTest (line 10) | class NamespaceSortTest extends TestCase
    method namespaceSortDataProvider (line 12) | public static function namespaceSortDataProvider(): array
    method testNamespaceSort (line 65) | public function testNamespaceSort(array $inputs, bool $order, string $...

FILE: tests/Unit/LicenserTest.php
  class LicenserTest (line 25) | class LicenserTest extends TestCase
    method testFindLicenceFilesPathsAreRelative (line 30) | public function testFindLicenceFilesPathsAreRelative(): void
    method testAppendHeaderCommentInformationNoHeader (line 88) | public function testAppendHeaderCommentInformationNoHeader(): void
    method testAppendHeaderCommentNoDate (line 138) | public function testAppendHeaderCommentNoDate(): void
    method testAppendHeaderCommentNoAuthor (line 179) | public function testAppendHeaderCommentNoAuthor(): void
    method testWithLicenceAlreadyInHeader (line 219) | public function testWithLicenceAlreadyInHeader(): void
    method testWithTwoCommentsBeforeFirstCode (line 277) | public function testWithTwoCommentsBeforeFirstCode(): void
    method testUnusualHeaderCommentStyle (line 346) | public function testUnusualHeaderCommentStyle(): void
    method testCommentWithLicenseWord (line 400) | public function testCommentWithLicenseWord(): void
    method testIncorrectlyMatching (line 468) | public function testIncorrectlyMatching(): void
    method testLicenseDetailsOnlyInsertedOncePerFile (line 544) | public function testLicenseDetailsOnlyInsertedOncePerFile(): void

FILE: tests/Unit/Pipeline/Aliases/AliasesTest.php
  class AliasesTest (line 21) | class AliasesTest extends TestCase
    method setUp (line 24) | protected function setUp(): void
    method test_class_in_aliases_array (line 41) | public function test_class_in_aliases_array(): void
    method test_functions (line 92) | public function test_functions(): void
    method test_namespaced_interfaces (line 137) | public function test_namespaced_interfaces(): void
    method test_namespaced_functions (line 186) | public function test_namespaced_functions(): void

FILE: tests/Unit/Pipeline/Autoload/ComposerAutoloadGeneratorTest.php
  class ComposerAutoloadGeneratorTest (line 13) | class ComposerAutoloadGeneratorTest extends \BrianHenryIE\Strauss\TestCase
    method testGetFileIdentifier (line 18) | public function testGetFileIdentifier(): void

FILE: tests/Unit/Pipeline/Autoload/DumpAutoloadTest.php
  class DumpAutoloadTest (line 20) | class DumpAutoloadTest extends \BrianHenryIE\Strauss\TestCase
    method testGeneratedPrefixedAutoloader (line 25) | public function testGeneratedPrefixedAutoloader():void
    method test_create_installed_versions_files (line 81) | public function test_create_installed_versions_files(): void
    method test_optimize_autoloader_defaults_to_true_without_capability_interface (line 211) | public function test_optimize_autoloader_defaults_to_true_without_capa...
    method test_optimize_autoloader_uses_capability_interface_when_available (line 229) | public function test_optimize_autoloader_uses_capability_interface_whe...

FILE: tests/Unit/Pipeline/Autoload/VendorComposerAutoloadTest.php
  class VendorComposerAutoloadTest (line 13) | class VendorComposerAutoloadTest extends TestCase
    method test_add_aliases_file_to_true_composer (line 22) | public function test_add_aliases_file_to_true_composer(): void

FILE: tests/Unit/Pipeline/AutoloadTest.php
  class AutoloadTest (line 17) | class AutoloadTest extends TestCase
    method tearDown (line 20) | protected function tearDown(): void
    method testGenerateClassmap (line 35) | public function testGenerateClassmap(): void
    method testGenerateClassmapParentRelativeDir (line 76) | public function testGenerateClassmapParentRelativeDir(): void
    method testGenerateFilesAutoloader (line 115) | public function testGenerateFilesAutoloader(): void

FILE: tests/Unit/Pipeline/ChangeEnumeratorTest.php
  class ChangeEnumeratorTest (line 19) | class ChangeEnumeratorTest extends TestCase
    method testFunctionReplacement (line 24) | public function testFunctionReplacement(): void

FILE: tests/Unit/Pipeline/Cleanup/CleanupTest.php
  class CleanupTest (line 13) | class CleanupTest extends \BrianHenryIE\Strauss\TestCase
    method test_optimize_autoloader_defaults_to_true_without_capability_interface (line 15) | public function test_optimize_autoloader_defaults_to_true_without_capa...
    method test_optimize_autoloader_uses_capability_interface_when_available (line 31) | public function test_optimize_autoloader_uses_capability_interface_whe...

FILE: tests/Unit/Pipeline/Cleanup/InstalledJsonTest.php
  class InstalledJsonTest (line 17) | class InstalledJsonTest extends \BrianHenryIE\Strauss\TestCase
    method test_remove_dead_file_entries (line 21) | public function test_remove_dead_file_entries(): void
    method test_updates_nothing (line 40) | public function test_updates_nothing(): void
    method test_updates_path (line 76) | public function test_updates_path(): void
    method test_updates_path_target_directory (line 185) | public function test_updates_path_target_directory(): void
    method test_updates_psr0_entry (line 234) | public function test_updates_psr0_entry(): void
    method test_excluded_package_removed_from_target_installed_json_but_retained_in_vendor_installed_json (line 337) | public function test_excluded_package_removed_from_target_installed_js...
    method extractPackageNamesFromInstalledJson (line 405) | private function extractPackageNamesFromInstalledJson(string $installe...

FILE: tests/Unit/Pipeline/CopierTest.php
  class CopierTest (line 14) | class CopierTest extends TestCase
    method test_file_is_copied (line 20) | public function test_file_is_copied(): void
    method test_file_is_skipped (line 51) | public function test_file_is_skipped(): void
    method test_file_not_found (line 82) | public function test_file_not_found(): void
    method testCreateDirectory (line 108) | public function testCreateDirectory(): void

FILE: tests/Unit/Pipeline/FileCopyScannerTest.php
  class FileCopyScannerTest (line 17) | class FileCopyScannerTest extends TestCase
    method test_file_is_excluded (line 23) | public function test_file_is_excluded(): void

FILE: tests/Unit/Pipeline/FileSymbolScannerTest.php
  class FileSymbolScannerTest (line 20) | class FileSymbolScannerTest extends TestCase
    method testSingleNamespace (line 33) | public function testSingleNamespace(): void
    method testGlobalNamespace (line 75) | public function testGlobalNamespace(): void
    method testMultipleNamespace (line 112) | public function testMultipleNamespace(): void
    method testMultipleNamespaceGlobalFirst (line 156) | public function testMultipleNamespaceGlobalFirst(): void
    method testItDoesNotFindNamespaceInComment (line 202) | public function testItDoesNotFindNamespaceInComment(): void
    method testMultipleClasses (line 266) | public function testMultipleClasses(): void
    method test_it_does_not_treat_comments_as_classes (line 306) | public function test_it_does_not_treat_comments_as_classes(): void
    method test_it_does_not_treat_multiline_comments_as_classes (line 344) | public function test_it_does_not_treat_multiline_comments_as_classes()...
    method test_it_does_not_treat_multiline_comments_opening_line_as_classes (line 387) | public function test_it_does_not_treat_multiline_comments_opening_line...
    method test_it_does_not_treat_multiline_comments_on_one_line_as_classes (line 426) | public function test_it_does_not_treat_multiline_comments_on_one_line_...
    method test_it_does_not_treat_comments_with_semicolons_as_classes (line 464) | public function test_it_does_not_treat_comments_with_semicolons_as_cla...
    method test_it_parses_classes_after_semicolon (line 501) | public function test_it_parses_classes_after_semicolon(): void
    method test_it_parses_classes_followed_by_comment (line 535) | public function test_it_parses_classes_followed_by_comment(): void
    method it_does_not_replace_inside_named_namespace_but_does_inside_explicit_global_namespace_a (line 579) | public function it_does_not_replace_inside_named_namespace_but_does_in...
    method testExcludePackagesFromPrefix (line 618) | public function testExcludePackagesFromPrefix(): void
    method testExcludeFilePatternsFromPrefix (line 655) | public function testExcludeFilePatternsFromPrefix(): void
    method testNamespaceReplacementPatterns (line 694) | public function testNamespaceReplacementPatterns(): void
    method testPhraseClassObjectIsNotMistaken (line 739) | public function testPhraseClassObjectIsNotMistaken(): void
    method testDefineConstant (line 793) | public function testDefineConstant(): void
    method test_commented_namespace_is_invalid (line 845) | public function test_commented_namespace_is_invalid(): void
    method testDiscoversGlobalFunctions (line 895) | public function testDiscoversGlobalFunctions(): void
    method testDiscoversGlobalFunctionInFunctionExists (line 947) | public function testDiscoversGlobalFunctionInFunctionExists(): void
    method testDoesNotIncludeBuiltInPhpFunctions (line 994) | public function testDoesNotIncludeBuiltInPhpFunctions(): void
    method test_finds_functions_in_second_namespace (line 1049) | public function test_finds_functions_in_second_namespace(): void
    method testTemplateFileWithPlaceholdersIsSkippedGracefully (line 1100) | public function testTemplateFileWithPlaceholdersIsSkippedGracefully():...

FILE: tests/Unit/Pipeline/MarkSymbolsForRenamingTest.php
  class MarkSymbolsForRenamingTest (line 18) | class MarkSymbolsForRenamingTest extends TestCase
    method testExcludedPackageSymbolsNotMarkedForRenaming (line 29) | public function testExcludedPackageSymbolsNotMarkedForRenaming(): void
    method testNonExcludedPackageSymbolsStillMarkedForRenaming (line 72) | public function testNonExcludedPackageSymbolsStillMarkedForRenaming():...
    method testExcludeConstantsByNameNotMarkedForRenaming (line 114) | public function testExcludeConstantsByNameNotMarkedForRenaming(): void

FILE: tests/Unit/PrefixerTest.php
  class PrefixerTest (line 32) | class PrefixerTest extends TestCase
    method testNamespaceReplacer (line 34) | public function testNamespaceReplacer(): void
    method testClassnameReplacer (line 125) | public function testClassnameReplacer(): void
    method testTypeFunctionParameter (line 167) | public function testTypeFunctionParameter(): void
    method test_it_replaces_class_declarations (line 175) | public function test_it_replaces_class_declarations(): void
    method test_it_replaces_abstract_class_declarations (line 193) | public function test_it_replaces_abstract_class_declarations(): void
    method test_it_replaces_interface_class_declarations (line 212) | public function test_it_replaces_interface_class_declarations(): void
    method test_it_replaces_class_declarations_that_extend_other_classes (line 231) | public function test_it_replaces_class_declarations_that_extend_other_...
    method test_it_replaces_class_declarations_that_implement_interfaces (line 250) | public function test_it_replaces_class_declarations_that_implement_int...
    method testItReplacesNamespacesInInterface (line 270) | public function testItReplacesNamespacesInInterface(): void
    method test_it_stores_replaced_class_names (line 289) | public function test_it_stores_replaced_class_names(): void
    method test_it_replaces_class_declarations_psr2 (line 304) | public function test_it_replaces_class_declarations_psr2(): void
    method test_it_replaces_class (line 325) | public function test_it_replaces_class(): void
    method it_does_not_replace_inside_namespace_multiline (line 350) | public function it_does_not_replace_inside_namespace_multiline(): void
    method test_it_does_not_replace_inside_namespace_singleline (line 382) | public function test_it_does_not_replace_inside_namespace_singleline()...
    method it_does_not_replace_inside_named_namespace_but_does_inside_explicit_global_namespace_b (line 408) | public function it_does_not_replace_inside_named_namespace_but_does_in...
    method it_replaces_namespace_declarations (line 432) | public function it_replaces_namespace_declarations(): void
    method test_it_doesnt_replaces_namespace_inside_namespace (line 452) | public function test_it_doesnt_replaces_namespace_inside_namespace(): ...
    method test_it_does_notreplaces_partial_namespace_declarations (line 468) | public function test_it_does_notreplaces_partial_namespace_declaration...
    method test_it_doesnt_prefix_already_prefixed_namespace (line 484) | public function test_it_doesnt_prefix_already_prefixed_namespace(): void
    method testDoesNotDoublePrefixAlreadyUpdatedNamespace (line 508) | public function testDoesNotDoublePrefixAlreadyUpdatedNamespace(): void
    method test_it_doesnt_double_replace_namespaces_that_also_exist_inside_another_namespace (line 529) | public function test_it_doesnt_double_replace_namespaces_that_also_exi...
    method it_replaces_namespace_use_as_declarations (line 552) | public function it_replaces_namespace_use_as_declarations(): void
    method test_it_doesnt_prefix_function_types_that_happen_to_match_the_namespace (line 572) | public function test_it_doesnt_prefix_function_types_that_happen_to_ma...
    method testLeadingSlashInString (line 588) | public function testLeadingSlashInString(): void
    method testDoubleLeadingSlashInString (line 604) | public function testDoubleLeadingSlashInString(): void
    method testItReplacesSlashedNamespaceInFunctionParameter (line 620) | public function testItReplacesSlashedNamespaceInFunctionParameter(): void
    method testItReplacesNamespaceInFunctionParameterDefaultArgumentValue (line 638) | public function testItReplacesNamespaceInFunctionParameterDefaultArgum...
    method testItReplacesNamespaceConcatenatedStringConst (line 656) | public function testItReplacesNamespaceConcatenatedStringConst(): void
    method testClassnameNotConfusedWithNamespace (line 677) | public function testClassnameNotConfusedWithNamespace(): void
    method testClassExtendsNamespacedClassIsPrefixed (line 691) | public function testClassExtendsNamespacedClassIsPrefixed(): void
    method testNewNamespacedClassIsPrefixed (line 710) | public function testNewNamespacedClassIsPrefixed(): void
    method testStaticNamespacedClassIsPrefixed (line 730) | public function testStaticNamespacedClassIsPrefixed(): void
    method testReturnedNamespacedClassIsPrefixed (line 749) | public function testReturnedNamespacedClassIsPrefixed(): void
    method testNamespacedStaticIsPrefixed (line 768) | public function testNamespacedStaticIsPrefixed(): void
    method testDoNotReplaceInStringThatIsNotCode (line 791) | public function testDoNotReplaceInStringThatIsNotCode(): void
    method testDoNotReplaceInVariableNames (line 814) | public function testDoNotReplaceInVariableNames(): void
    method testReplaceConstants (line 831) | public function testReplaceConstants(): void
    method testStaticFunctionCallOfNamespacedClassIsPrefixed (line 872) | public function testStaticFunctionCallOfNamespacedClassIsPrefixed(): void
    method testItPrefixesGroupedNamespacedClasses (line 898) | public function testItPrefixesGroupedNamespacedClasses(): void
    method testStaticSimpleCall (line 916) | public function testStaticSimpleCall(): void
    method testStaticVariableAssignment (line 942) | public function testStaticVariableAssignment(): void
    method testStaticIfConditionSingle (line 967) | public function testStaticIfConditionSingle(): void
    method testStaticIfConditionMultipleAND (line 1008) | public function testStaticIfConditionMultipleAND(): void
    method testStaticIfConditionMultipleOR (line 1048) | public function testStaticIfConditionMultipleOR(): void
    method testStaticArrayNonAssociativeSingle (line 1088) | public function testStaticArrayNonAssociativeSingle(): void
    method testStaticArrayNonAssociativeMultipleAND (line 1117) | public function testStaticArrayNonAssociativeMultipleAND(): void
    method testStaticArrayNonAssociationMultipleOR (line 1146) | public function testStaticArrayNonAssociationMultipleOR(): void
    method testStaticArrayAssociativeSingle (line 1175) | public function testStaticArrayAssociativeSingle(): void
    method testStaticArrayAssociativeMultipleAND (line 1204) | public function testStaticArrayAssociativeMultipleAND(): void
    method testStaticArrayAssociativeMultipleOR (line 1232) | public function testStaticArrayAssociativeMultipleOR(): void
    method testDoublePrefixBug (line 1260) | public function testDoublePrefixBug(): void
    method testItDoesNotPrefixClassnameInsideNamespaceName (line 1320) | public function testItDoesNotPrefixClassnameInsideNamespaceName(): void
    method testItDoesNotPrefixClassnameInsideInsideNamespaceName (line 1348) | public function testItDoesNotPrefixClassnameInsideInsideNamespaceName(...
    method testItDoesNotPrefixClassnameInsideEndNamespaceName (line 1382) | public function testItDoesNotPrefixClassnameInsideEndNamespaceName(): ...
    method testItDoesNotPrefixClassDeclarationInsideNamespace (line 1417) | public function testItDoesNotPrefixClassDeclarationInsideNamespace(): ...
    method testItDoesNotPrefixReturnTypeWillChangeAsClassname (line 1452) | public function testItDoesNotPrefixReturnTypeWillChangeAsClassname(): ...
    method testItReplacesStaticInsideSquareArray (line 1490) | public function testItReplacesStaticInsideSquareArray(): void
    method testItReplacesStaticInsideMultilineTernary (line 1533) | public function testItReplacesStaticInsideMultilineTernary(): void
    method testItPrefixesNamespacedFunctionUse (line 1588) | public function testItPrefixesNamespacedFunctionUse(): void
    method testPrefixUseFunction (line 1653) | public function testPrefixUseFunction(): void
    method testPrefixGlobalClassUse (line 1686) | public function testPrefixGlobalClassUse(): void
    method test_prefix_no_newline_after_opening_php_replace_namespace (line 1733) | public function test_prefix_no_newline_after_opening_php_replace_names...
    method test_global_class_phpdoc_end_delimiter (line 1760) | public function test_global_class_phpdoc_end_delimiter(): void
    method testPrefixesFullNamespaceInInstanceOf (line 1807) | public function testPrefixesFullNamespaceInInstanceOf(): void
    method testPrefixesFQDNWithMutedErrors (line 1855) | public function testPrefixesFQDNWithMutedErrors(): void
    method testPrefixesAliasedGlobalClass (line 1920) | public function testPrefixesAliasedGlobalClass(): void
    method testReplaceFunctions (line 1952) | public function testReplaceFunctions(): void
    method testPrepareRelativeNamespaces (line 2033) | public function testPrepareRelativeNamespaces(): void
    method test_dont_double_slash (line 2128) | public function test_dont_double_slash(): void
    method test_relative_namespace_in_function_parameter (line 2212) | public function test_relative_namespace_in_function_parameter(): void
    method test_relative_namespace_constant (line 2268) | public function test_relative_namespace_constant(): void
    method test_relative_phpdoc (line 2332) | public function test_relative_phpdoc(): void
    method test_relative_return_type (line 2387) | public function test_relative_return_type(): void
    method test_relative_static_property (line 2444) | public function test_relative_static_property(): void
    method test_relative_constructor_property (line 2515) | public function test_relative_constructor_property(): void
    method test_relative_exception_type (line 2577) | public function test_relative_exception_type(): void
    method test_namespace_in_string_with_variable (line 2666) | public function test_namespace_in_string_with_variable(): void
    method testForAbsenceOfFunctionPrefixInClass (line 2736) | public function testForAbsenceOfFunctionPrefixInClass(): void
    method testInclude (line 2805) | public function testInclude(): void
    method testRelativeInterfaceInImplementsNotPrefixed (line 2864) | public function testRelativeInterfaceInImplementsNotPrefixed(): void

FILE: tests/Unit/Types/DiscoveredSymbolTest.php
  class DiscoveredSymbolTest (line 13) | class DiscoveredSymbolTest extends TestCase
    method testCreate (line 20) | public function testCreate(): void
    method testMultipleSourceFiles (line 36) | public function testMultipleSourceFiles(): void
    method testReplacement (line 58) | public function testReplacement(): void

FILE: tests/Unit/Types/DiscoveredSymbolsTest.php
  class DiscoveredSymbolsTest (line 12) | class DiscoveredSymbolsTest extends TestCase
    method testReturnsFunctions (line 19) | public function testReturnsFunctions(): void
    method testGetNamespaceSymbol (line 36) | public function testGetNamespaceSymbol(): void
    method testGetNamespaceSymbolMissing (line 56) | public function testGetNamespaceSymbolMissing(): void
Condensed preview — 223 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,334K chars).
[
  {
    "path": ".gitattributes",
    "chars": 777,
    "preview": "#\n# Exclude these files from release archives.\n# This will also make them unavailable when using Composer with `--prefer"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 447,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\nA bug report gen"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 758,
    "preview": "version: 2\nupdates:\n\n  # Maintain dependencies for GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory:"
  },
  {
    "path": ".github/workflows/claude-code-review.yml",
    "chars": 2623,
    "preview": "name: Claude Code Review\n\non:\n  pull_request_target:\n    types: [opened, synchronize, ready_for_review, reopened]\n    # "
  },
  {
    "path": ".github/workflows/claude.yml",
    "chars": 1907,
    "preview": "name: Claude Code\n\non:\n  issue_comment:\n    types: [created]\n  pull_request_review_comment:\n    types: [created]\n  issue"
  },
  {
    "path": ".github/workflows/codecoverage.yml",
    "chars": 10831,
    "preview": "name: Code Coverage\n\n# Runs PHPUnit with code coverage enabled, commits the html report to\n# GitHub Pages, generates a R"
  },
  {
    "path": ".github/workflows/main.yml",
    "chars": 7630,
    "preview": "name: Lint and test\n\non:\n  push:\n    branches:\n      - master\n      - main\n    paths:\n      - '**.php'\n      - 'composer"
  },
  {
    "path": ".github/workflows/phpstan.yml",
    "chars": 2464,
    "preview": "name: PHPStan Analysis\n\non:\n  pull_request:\n    types: [opened, synchronize, ready_for_review, reopened]\n#    branches: "
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 8358,
    "preview": "name: Build, tag and attach releases\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n\nconcurrency:\n  # Cance"
  },
  {
    "path": ".github/workflows/updateversionfromchangelog.yml",
    "chars": 1102,
    "preview": "# When a new version number is added to the changelog, update the bin.\n\nname: Update version from changelog\n\non:\n  push:"
  },
  {
    "path": ".gitignore",
    "chars": 204,
    "preview": ".idea/\nvendor/\n\n.DS_Store\ncomposer.lock\n.phpunit.result.cache\n\n*.phar\n\ntests/_reports\n\ntemptestdir\nbuild\nscratch\n\n# GitH"
  },
  {
    "path": ".phive/phars.xml",
    "chars": 309,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phive xmlns=\"https://phar.io/phive\">\n  <phar name=\"brianhenryie/php-diff-test\" v"
  },
  {
    "path": ".typos.toml",
    "chars": 298,
    "preview": "[files]\nextend-exclude = [\n    \".git/\",\n    \"tests/Issues/data/\",\n    \"/src/Pipeline/FileSymbol/builtinsymbols.php\",\n]\ni"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 6422,
    "preview": "# Change Log\n\n## 0.27.2 April 2025\n\n* Fix: over-eager cleanup – preserve vendor autoload entries for `exclude_from_copy`"
  },
  {
    "path": "LICENSE",
    "chars": 1095,
    "preview": "The MIT License (MIT)\n\nCopyright (c) Coen Jacobs <coenjacobs@gmail.com>\n\nPermission is hereby granted, free of charge, t"
  },
  {
    "path": "README.md",
    "chars": 16226,
    "preview": "[![PHPUnit ](.github/coverage.svg)](https://brianhenryie.github.io/strauss/) [![PHPStan ](.github/phpstan.svg)](https://"
  },
  {
    "path": "bin/strauss",
    "chars": 1378,
    "preview": "#!/usr/bin/env php\n<?php\ncall_user_func(function ($version) {\n    $autoloaders = Phar::running() === ''\n        ? [\n    "
  },
  {
    "path": "bootstrap.php",
    "chars": 1803,
    "preview": "<?php\n/**\n * When strauss is installed via Composer, this will help load the aliases file.\n *\n * When `composer install "
  },
  {
    "path": "composer.json",
    "chars": 7315,
    "preview": "{\n    \"name\": \"brianhenryie/strauss\",\n    \"description\": \"Prefixes dependencies namespaces so they are unique to your pl"
  },
  {
    "path": "phive.phar.asc",
    "chars": 854,
    "preview": "-----BEGIN PGP SIGNATURE-----\n\niQJBBAABCgArFiEEavclJwq4HgTXlEJUnYqYspstXXkFAmbHq+UNHHRlYW1AcGhh\nci5pbwAKCRCdipiymy1deRwW"
  },
  {
    "path": "phpcs.xml",
    "chars": 567,
    "preview": "<?xml version=\"1.0\"?>\n<!--suppress XmlUnboundNsPrefix -->\n<ruleset name=\"strauss\">\n    <description>Coding standard rule"
  },
  {
    "path": "phpstan-baseline.neon",
    "chars": 7371,
    "preview": "parameters:\n\tignoreErrors:\n\t\t-\n\t\t\tmessage: \"#^Parameter \\\\#1 \\\\$namespacePrefix of method BrianHenryIE\\\\\\\\Strauss\\\\\\\\Com"
  },
  {
    "path": "phpstan.neon",
    "chars": 878,
    "preview": "# phpstan analyse --memory-limit=-1 --level 8 --verbose\n# phpstan analyse --memory-limit=-1 --level max --generate-basel"
  },
  {
    "path": "phpunit.xml",
    "chars": 777,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" backupGlobals=\"fal"
  },
  {
    "path": "scripts/createphar.sh",
    "chars": 512,
    "preview": "#!/bin/bash\n\n# chmod +x scripts/createphar.sh\n# ./scripts/createphar.sh\n\nrm -rf build\ncomposer install --no-dev\nwget -O "
  },
  {
    "path": "scripts/getbuiltinphp.php",
    "chars": 3581,
    "preview": "<?php\n/**\n * Get all built-in PHP classes, interfaces, traits.\n *\n * TODO: consider using JetBrains/phpstorm-stubs or Ph"
  },
  {
    "path": "src/Composer/ComposerPackage.php",
    "chars": 10669,
    "preview": "<?php\n/**\n * Object for getting typed values from composer.json.\n *\n * Use this for dependencies. Use ProjectComposerPac"
  },
  {
    "path": "src/Composer/Extra/ReplaceConfigInterface.php",
    "chars": 1090,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Composer\\Extra;\n\nuse BrianHenryIE\\Strauss\\Config\\AutoloadFilesEnumeratorConfigInte"
  },
  {
    "path": "src/Composer/Extra/StraussConfig.php",
    "chars": 30860,
    "preview": "<?php\n/**\n * The extra/strauss key in composer.json.\n */\n\nnamespace BrianHenryIE\\Strauss\\Composer\\Extra;\n\nuse BrianHenry"
  },
  {
    "path": "src/Composer/ProjectComposerPackage.php",
    "chars": 2710,
    "preview": "<?php\n/**\n * Extends ComposerPackage to return the typed Strauss config.\n */\n\nnamespace BrianHenryIE\\Strauss\\Composer;\n\n"
  },
  {
    "path": "src/Config/AliasesConfigInterface.php",
    "chars": 545,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface AliasesConfigInterface\n{\n\n    /**\n     * The directory where th"
  },
  {
    "path": "src/Config/AutoloadConfigInterface.php",
    "chars": 1093,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\n\ninterface AutoloadCon"
  },
  {
    "path": "src/Config/AutoloadFilesEnumeratorConfigInterface.php",
    "chars": 771,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface AutoloadFilesEnumeratorConfigInterface\n{\n    public function ge"
  },
  {
    "path": "src/Config/ChangeEnumeratorConfigInterface.php",
    "chars": 934,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\n\ninterface ChangeEnume"
  },
  {
    "path": "src/Config/CleanupConfigInterface.php",
    "chars": 690,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface CleanupConfigInterface\n{\n    public function getAbsoluteVendorD"
  },
  {
    "path": "src/Config/CopierConfigInterface.php",
    "chars": 142,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface CopierConfigInterface\n{\n\n    public function getAbsoluteTargetD"
  },
  {
    "path": "src/Config/FileCopyScannerConfigInterface.php",
    "chars": 614,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface FileCopyScannerConfigInterface\n{\n\n    public function getAbsolu"
  },
  {
    "path": "src/Config/FileEnumeratorConfig.php",
    "chars": 523,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface FileEnumeratorConfig\n{\n\n    public function getAbsoluteVendorDi"
  },
  {
    "path": "src/Config/FileSymbolScannerConfigInterface.php",
    "chars": 561,
    "preview": "<?php\n/**\n * @see \\BrianHenryIE\\Strauss\\Composer\\Extra\\StraussConfig\n */\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\nuse Br"
  },
  {
    "path": "src/Config/LicenserConfigInterface.php",
    "chars": 486,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface LicenserConfigInterface\n{\n    public function isIncludeModified"
  },
  {
    "path": "src/Config/MarkSymbolsForRenamingConfigInterface.php",
    "chars": 1486,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface MarkSymbolsForRenamingConfigInterface\n{\n    public function get"
  },
  {
    "path": "src/Config/OptimizeAutoloaderConfigInterface.php",
    "chars": 145,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface OptimizeAutoloaderConfigInterface\n{\n    public function isOptim"
  },
  {
    "path": "src/Config/PrefixerConfigInterface.php",
    "chars": 690,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Config;\n\ninterface PrefixerConfigInterface\n{\n    public function getAbsoluteVendor"
  },
  {
    "path": "src/Console/Application.php",
    "chars": 784,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Console;\n\nuse BrianHenryIE\\Strauss\\Console\\Commands\\DependenciesCommand;\nuse Brian"
  },
  {
    "path": "src/Console/Commands/AbstractRenamespacerCommand.php",
    "chars": 6518,
    "preview": "<?php\n/**\n * Log level, filesystem\n */\n\nnamespace BrianHenryIE\\Strauss\\Console\\Commands;\n\nuse BrianHenryIE\\Strauss\\Compo"
  },
  {
    "path": "src/Console/Commands/DependenciesCommand.php",
    "chars": 17360,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Console\\Commands;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHen"
  },
  {
    "path": "src/Console/Commands/IncludeAutoloaderCommand.php",
    "chars": 3278,
    "preview": "<?php\n/**\n * Adds ~`require_once 'autoload_aliases.php'` to `vendor/autoload.php`.\n *\n * During development, when runnin"
  },
  {
    "path": "src/Console/Commands/ReplaceCommand.php",
    "chars": 8649,
    "preview": "<?php\n/**\n * Rename a namespace in files. (in-place renaming)\n *\n * strauss replace --from \"YourCompany\\\\Project\" --to \""
  },
  {
    "path": "src/Files/DiscoveredFiles.php",
    "chars": 800,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Files;\n\nclass DiscoveredFiles\n{\n    /** @var array<string,FileBase|File|FileWithDe"
  },
  {
    "path": "src/Files/File.php",
    "chars": 4388,
    "preview": "<?php\n/**\n * A file without a dependency means the project src files and the vendor/composer autoload files.\n */\n\nnamesp"
  },
  {
    "path": "src/Files/FileBase.php",
    "chars": 1412,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Files;\n\nuse BrianHenryIE\\Strauss\\Types\\DiscoveredSymbol;\n\ninterface FileBase\n{\n\n  "
  },
  {
    "path": "src/Files/FileWithDependency.php",
    "chars": 2338,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Files;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHenryIE\\Straus"
  },
  {
    "path": "src/Files/HasDependency.php",
    "chars": 388,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Files;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\n\ninterface HasDependenc"
  },
  {
    "path": "src/Helpers/FileSystem.php",
    "chars": 13352,
    "preview": "<?php\n/**\n * This class extends Flysystem's Filesystem class to add some additional functionality, particularly around\n "
  },
  {
    "path": "src/Helpers/FlysystemBackCompatInterface.php",
    "chars": 328,
    "preview": "<?php\n/**\n * These methods were added in FlySystem x (TODO)\n */\n\nnamespace BrianHenryIE\\Strauss\\Helpers;\n\nuse League\\Fly"
  },
  {
    "path": "src/Helpers/FlysystemBackCompatTrait.php",
    "chars": 1276,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Helpers;\n\nuse Elazar\\Flystream\\StripProtocolPathNormalizer;\nuse League\\Flysystem\\F"
  },
  {
    "path": "src/Helpers/InMemoryFilesystemAdapter.php",
    "chars": 1980,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Helpers;\n\nuse League\\Flysystem\\Config;\nuse League\\Flysystem\\FileAttributes;\nuse Le"
  },
  {
    "path": "src/Helpers/Log/PadColonColumnsLogProcessor.php",
    "chars": 1579,
    "preview": "<?php\n/**\n * Attempt to align text following `:` in a log message.\n *\n * But use `:::` to indicate it should be padded.\n"
  },
  {
    "path": "src/Helpers/Log/RelativeFilepathLogProcessor.php",
    "chars": 1038,
    "preview": "<?php\n/**\n * A logger that changes file paths to be relative to the project directory.\n *\n * @see \\BrianHenryIE\\Strauss\\"
  },
  {
    "path": "src/Helpers/NamespaceSort.php",
    "chars": 1066,
    "preview": "<?php\n/**\n * Given two namespaces, sort them by the number of levels, then the length of the final part\n */\n\nnamespace B"
  },
  {
    "path": "src/Helpers/ReadOnlyFileSystem.php",
    "chars": 11428,
    "preview": "<?php\n/**\n * When running with `--dry-run` the filesystem should be read-only.\n *\n * This should work with read operatio"
  },
  {
    "path": "src/Helpers/StripFsRootPathNormalizer.php",
    "chars": 1683,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Helpers;\n\nuse League\\Flysystem\\PathNormalizer;\nuse League\\Flysystem\\WhitespacePath"
  },
  {
    "path": "src/Pipeline/Aliases/Aliases.php",
    "chars": 13097,
    "preview": "<?php\n/**\n * When replacements are made in-situ in the vendor directory, add aliases for the original class fqdns so\n * "
  },
  {
    "path": "src/Pipeline/Aliases/autoload_aliases.template.php",
    "chars": 4785,
    "preview": "<?php\n\n// FunctionsAndConstants\n\nnamespace BrianHenryIE\\Strauss {\n\n    use BrianHenryIE\\Strauss\\Types\\AutoloadAliasInter"
  },
  {
    "path": "src/Pipeline/Autoload/ComposerAutoloadGenerator.php",
    "chars": 2870,
    "preview": "<?php\n/**\n * Extend Composer's `AutoloadGenerator` to override the `getFileIdentifier()` method's hash to provide true u"
  },
  {
    "path": "src/Pipeline/Autoload/DumpAutoload.php",
    "chars": 11459,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Pipeline\\Autoload;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHe"
  },
  {
    "path": "src/Pipeline/Autoload/VendorComposerAutoload.php",
    "chars": 13312,
    "preview": "<?php\n/**\n * Edit vendor/autoload.php to also load the vendor/composer/autoload_aliases.php file and the vendor-prefixed"
  },
  {
    "path": "src/Pipeline/Autoload.php",
    "chars": 3251,
    "preview": "<?php\n/**\n * Generate an `autoload.php` file in the root of the target directory.\n *\n * @see \\Composer\\Autoload\\ClassMap"
  },
  {
    "path": "src/Pipeline/AutoloadedFilesEnumerator.php",
    "chars": 7663,
    "preview": "<?php\n/**\n * Use each package's autoload key to determine which files in the package are to be prefixed, apply exclusion"
  },
  {
    "path": "src/Pipeline/ChangeEnumerator.php",
    "chars": 6661,
    "preview": "<?php\n/**\n * Determine the replacements to be made to the discovered symbols.\n *\n * Typically, this will just be a prefi"
  },
  {
    "path": "src/Pipeline/Cleanup/Cleanup.php",
    "chars": 14169,
    "preview": "<?php\n/**\n * Deletes source files and empty directories.\n */\n\nnamespace BrianHenryIE\\Strauss\\Pipeline\\Cleanup;\n\nuse Bria"
  },
  {
    "path": "src/Pipeline/Cleanup/InstalledJson.php",
    "chars": 27677,
    "preview": "<?php\n/**\n * Changes \"install-path\" to point to vendor-prefixed target directory.\n *\n * * create new vendor-prefixed/com"
  },
  {
    "path": "src/Pipeline/Copier.php",
    "chars": 3923,
    "preview": "<?php\n/**\n * Prepares the destination by deleting any files about to be copied.\n * Copies the files.\n *\n * TODO: Exclude"
  },
  {
    "path": "src/Pipeline/DependenciesEnumerator.php",
    "chars": 9427,
    "preview": "<?php\n/**\n * Build a list of ComposerPackage objects for all dependencies.\n */\n\nnamespace BrianHenryIE\\Strauss\\Pipeline;"
  },
  {
    "path": "src/Pipeline/FileCopyScanner.php",
    "chars": 6225,
    "preview": "<?php\n/**\n * Loop over the discovered files and mark the file to be copied or not.\n *\n * ```\n * \"exclude_from_copy\": {\n "
  },
  {
    "path": "src/Pipeline/FileEnumerator.php",
    "chars": 5398,
    "preview": "<?php\n/**\n * Build a list of files for the Composer packages.\n */\n\nnamespace BrianHenryIE\\Strauss\\Pipeline;\n\nuse BrianHe"
  },
  {
    "path": "src/Pipeline/FileSymbol/builtinsymbols.php",
    "chars": 105522,
    "preview": "<?php\n/**\n * A list of built-in classes, interfaces, traits and functions.\n *\n * Required so that they are not modified "
  },
  {
    "path": "src/Pipeline/FileSymbolScanner.php",
    "chars": 11110,
    "preview": "<?php\n/**\n * The purpose of this class is only to find changes that should be made.\n * i.e. classes and namespaces to ch"
  },
  {
    "path": "src/Pipeline/Licenser.php",
    "chars": 12094,
    "preview": "<?php\n/**\n * Copies license files from original folders.\n * Edits Phpdoc to record the file was changed.\n *\n * MIT state"
  },
  {
    "path": "src/Pipeline/MarkSymbolsForRenaming.php",
    "chars": 9580,
    "preview": "<?php\n\n/**\n * Symbols found in autoloaded files should be prefixed, unless:\n * * The `exclude_from_prefix` rules apply t"
  },
  {
    "path": "src/Pipeline/Prefixer.php",
    "chars": 32813,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Pipeline;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHenryIE\\Str"
  },
  {
    "path": "src/Types/AutoloadAliasInterface.php",
    "chars": 908,
    "preview": "<?php\n/**\n * After files are modified, an `autoload_aliases.php` file is created so the previous classnames continue to\n"
  },
  {
    "path": "src/Types/ClassSymbol.php",
    "chars": 2279,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Types;\n\nuse BrianHenryIE\\Strauss\\Files\\FileBase;\n\n/**\n * @phpstan-import-type Clas"
  },
  {
    "path": "src/Types/ConstantSymbol.php",
    "chars": 97,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Types;\n\nclass ConstantSymbol extends DiscoveredSymbol\n{\n\n}\n"
  },
  {
    "path": "src/Types/DiscoveredSymbol.php",
    "chars": 2559,
    "preview": "<?php\n/**\n * A namespace, class, interface or trait discovered in the project.\n */\n\nnamespace BrianHenryIE\\Strauss\\Types"
  },
  {
    "path": "src/Types/DiscoveredSymbols.php",
    "chars": 8403,
    "preview": "<?php\n/**\n * @see \\BrianHenryIE\\Strauss\\Pipeline\\FileSymbolScanner\n */\n\nnamespace BrianHenryIE\\Strauss\\Types;\n\nuse Brian"
  },
  {
    "path": "src/Types/FunctionSymbol.php",
    "chars": 97,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Types;\n\nclass FunctionSymbol extends DiscoveredSymbol\n{\n\n}\n"
  },
  {
    "path": "src/Types/InterfaceSymbol.php",
    "chars": 1390,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Types;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHenryIE\\Straus"
  },
  {
    "path": "src/Types/NamespaceSymbol.php",
    "chars": 303,
    "preview": "<?php\n/**\n * Should this be a {@see \\PhpParser\\Node\\Stmt\\Namespace_} instead?\n */\n\nnamespace BrianHenryIE\\Strauss\\Types;"
  },
  {
    "path": "src/Types/TraitSymbol.php",
    "chars": 1359,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Types;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHenryIE\\Straus"
  },
  {
    "path": "tests/Integration/Autoload/DumpAutoloadFeatureTest.php",
    "chars": 14611,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Autoload;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHenryIE\\Str"
  },
  {
    "path": "tests/Integration/Autoload/VendorComposerAutoloadFeatureTest.php",
    "chars": 8800,
    "preview": "<?php\n/**\n * @see VendorComposerAutoload\n */\n\nnamespace BrianHenryIE\\Strauss\\Autoload;\n\nuse BrianHenryIE\\Strauss\\Integra"
  },
  {
    "path": "tests/Integration/ChangeEnumeratorIntegrationTest.php",
    "chars": 2932,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\n\n/**\n * @coversNothing\n */\nclass C"
  },
  {
    "path": "tests/Integration/Cleanup/ExcludeFromCopyAutoloadIntegrationTest.php",
    "chars": 10086,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Pipeline\\Cleanup;\n\nuse BrianHenryIE\\Strauss\\Composer\\Extra\\StraussConfig;\nuse Bria"
  },
  {
    "path": "tests/Integration/Cleanup/InstalledJsonIntegrationTest.php",
    "chars": 14929,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Pipeline\\Cleanup;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\n\n/**\n * @coversDe"
  },
  {
    "path": "tests/Integration/CleanupIntegrationTest.php",
    "chars": 8633,
    "preview": "<?php\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryIE\\Strauss\\Composer\\Extra\\StraussConfig;\nuse Bria"
  },
  {
    "path": "tests/Integration/CleanupSymlinkIntegrationTest.php",
    "chars": 3525,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\n\n/**\n * @coversN"
  },
  {
    "path": "tests/Integration/CopierFeatureTest.php",
    "chars": 34753,
    "preview": "<?php\n/**\n * Tests auto-generated by Claude.\n *\n * Regression tests ahead of addressing an issue related to copying file"
  },
  {
    "path": "tests/Integration/CopierIntegrationTest.php",
    "chars": 10005,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHe"
  },
  {
    "path": "tests/Integration/DryRunFeatureTest.php",
    "chars": 7678,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryIE\\Strauss\\Composer\\Extra\\StraussConfig;\nuse Bri"
  },
  {
    "path": "tests/Integration/DumpAutoloadFeatureTest.php",
    "chars": 2116,
    "preview": "<?php\n/**\n * After files have been copied and prefixed, we use Composer's tools to generate the autoload files.\n */\n\nnam"
  },
  {
    "path": "tests/Integration/ExcludeFromPrefixFeatureTest.php",
    "chars": 2773,
    "preview": "<?php\n// file_patterns\n\nnamespace BrianHenryIE\\Strauss;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\n\nclass ExcludeFro"
  },
  {
    "path": "tests/Integration/FileCopyScannerIntegrationTest.php",
    "chars": 5266,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHe"
  },
  {
    "path": "tests/Integration/FileEnumeratorIntegrationTest.php",
    "chars": 3418,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryIE\\Strauss\\Composer\\ComposerPackage;\nuse BrianHe"
  },
  {
    "path": "tests/Integration/Helpers/FileSystemIntegrationTest.php",
    "chars": 1694,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Helpers;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\nuse League\\Flysystem\\Local"
  },
  {
    "path": "tests/Integration/Helpers/PadColonColumnsLogProcessorIntegrationTest.php",
    "chars": 874,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Helpers;\n\nuse BrianHenryIE\\ColorLogger\\ColorLogger;\nuse BrianHenryIE\\Strauss\\Helpe"
  },
  {
    "path": "tests/Integration/Helpers/ReadOnlyFileSystemIntegrationTest.php",
    "chars": 7523,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Helpers;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\nuse League\\Flysystem\\Local"
  },
  {
    "path": "tests/Integration/OutputLevelFeatureTest.php",
    "chars": 2364,
    "preview": "<?php\n/**\n * Test --info, --debug, --quiet, etc.\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryI"
  },
  {
    "path": "tests/Integration/Pipeline/Aliases/AliasesFeatureTest.php",
    "chars": 7981,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Pipeline\\Aliases;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\n\n/**\n * @coversNo"
  },
  {
    "path": "tests/Integration/ReplaceCommandIntegrationTest.php",
    "chars": 1626,
    "preview": "<?php\n/**\n * TODO: update issue number\n *\n * Add functionality to change the namespace in the project's own source files"
  },
  {
    "path": "tests/Integration/ReplacerIntegrationTest.php",
    "chars": 9010,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\n\n/**\n * Class Re"
  },
  {
    "path": "tests/Integration/UpdateCallSitesIntegrationTest.php",
    "chars": 2817,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Integration;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\n\n/**\n * @coversN"
  },
  {
    "path": "tests/IntegrationTestCase.php",
    "chars": 11647,
    "preview": "<?php\n/**\n * Creates a deletes a temp directory for tests.\n *\n * Could just system temp directory, but this is useful fo"
  },
  {
    "path": "tests/Issues/MozartIssue106Test.php",
    "chars": 1934,
    "preview": "<?php\n/**\n * @see https://github.com/coenjacobs/mozart/blob/3b1243ca8505fa6436569800dc34269178930f39/tests/replacers/Cla"
  },
  {
    "path": "tests/Issues/MozartIssue108Test.php",
    "chars": 2978,
    "preview": "<?php\n/**\n * This is interesting for two reasons.\n *\n * 1. The published package on packagist does not contain a compose"
  },
  {
    "path": "tests/Issues/MozartIssue109Test.php",
    "chars": 1923,
    "preview": "<?php\n/**\n * nesbot/carbon empty searchNamespace\n * @see https://github.com/coenjacobs/mozart/issues/109\n *\n * Comments "
  },
  {
    "path": "tests/Issues/MozartIssue124Test.php",
    "chars": 4814,
    "preview": "<?php\n/**\n *\n * @see https://github.com/coenjacobs/mozart/blob/3b1243ca8505fa6436569800dc34269178930f39/tests/replacers/"
  },
  {
    "path": "tests/Issues/MozartIssue128Test.php",
    "chars": 1666,
    "preview": "<?php\n/**\n * @see https://github.com/coenjacobs/mozart/issues/128\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nuse"
  },
  {
    "path": "tests/Issues/MozartIssue129Test.php",
    "chars": 2771,
    "preview": "<?php\n/**\n * Namespaces with escaped backslashes in strings are not replaced.\n *\n * @see https://github.com/coenjacobs/m"
  },
  {
    "path": "tests/Issues/MozartIssue130Test.php",
    "chars": 1571,
    "preview": "<?php\n/**\n * Carbon Fields, including non-class files\n * @see https://github.com/coenjacobs/mozart/issues/130\n *\n * Basi"
  },
  {
    "path": "tests/Issues/MozartIssue13Test.php",
    "chars": 1572,
    "preview": "<?php\n/**\n * Namespaces in constants not replaced\n * @see https://github.com/coenjacobs/mozart/issues/13\n *\n */\n\nnamespa"
  },
  {
    "path": "tests/Issues/MozartIssue43Test.php",
    "chars": 1710,
    "preview": "<?php\n/**\n * Root directories can not be deleted\n * @see https://github.com/coenjacobs/mozart/issues/43\n *\n * \"File alre"
  },
  {
    "path": "tests/Issues/MozartIssue48Test.php",
    "chars": 1929,
    "preview": "<?php\n/**\n * Multiple paths inside PSR-4 key\n * @see https://github.com/coenjacobs/mozart/issues/48\n *\n */\n\nnamespace Br"
  },
  {
    "path": "tests/Issues/MozartIssue62Test.php",
    "chars": 1760,
    "preview": "<?php\n/**\n * AWS not working after Mozart has been ran\n * @see https://github.com/coenjacobs/mozart/issues/62\n *\n * Poss"
  },
  {
    "path": "tests/Issues/MozartIssue66Test.php",
    "chars": 1567,
    "preview": "<?php\n/**\n * Packages with files autoloaders do not autoload those files\n * @see https://github.com/coenjacobs/mozart/is"
  },
  {
    "path": "tests/Issues/MozartIssue86Test.php",
    "chars": 3092,
    "preview": "<?php\n/**\n * @see https://github.com/coenjacobs/mozart/blob/3b1243ca8505fa6436569800dc34269178930f39/tests/replacers/Cla"
  },
  {
    "path": "tests/Issues/MozartIssue89Test.php",
    "chars": 3195,
    "preview": "<?php\n/**\n * @see https://github.com/coenjacobs/mozart/issues/89\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nuse "
  },
  {
    "path": "tests/Issues/MozartIssue90Test.php",
    "chars": 2027,
    "preview": "<?php\n/**\n * @see https://github.com/coenjacobs/mozart/issues/90\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nuse "
  },
  {
    "path": "tests/Issues/MozartIssue93Test.php",
    "chars": 2065,
    "preview": "<?php\n/**\n * @see https://github.com/coenjacobs/mozart/blob/3b1243ca8505fa6436569800dc34269178930f39/tests/replacers/Cla"
  },
  {
    "path": "tests/Issues/MozartIssue97Test.php",
    "chars": 1265,
    "preview": "<?php\n/**\n * The Packagist named crewlabs/unsplash has the composer name unsplash/unsplash.\n */\n\nnamespace BrianHenryIE\\"
  },
  {
    "path": "tests/Issues/MozartIssue99Test.php",
    "chars": 1354,
    "preview": "<?php\n/**\n * A PSR-0 test.\n *\n * This worked very easily because once the files are copied, Strauss doesn't care about a"
  },
  {
    "path": "tests/Issues/StraussIssue101Test.php",
    "chars": 1816,
    "preview": "<?php\n/**\n * Was over-eagerly deleting autoload keys.\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/101#issu"
  },
  {
    "path": "tests/Issues/StraussIssue104Test.php",
    "chars": 1328,
    "preview": "<?php\n/**\n * `vendor-prefixed` directory permissions changed after Flysystem update.\n *\n * @see https://github.com/Brian"
  },
  {
    "path": "tests/Issues/StraussIssue108Test.php",
    "chars": 1805,
    "preview": "<?php\n/**\n * `use GlobalClass as Alias;` should be replaced with `use Prefixed_GlobalClass as Alias;`.\n *\n *\n *\n * @see "
  },
  {
    "path": "tests/Issues/StraussIssue109Test.php",
    "chars": 1300,
    "preview": "<?php\n/**\n * Defined CLI arguments are breaking the extra.strauss config even when they are not present.\n *\n * @see http"
  },
  {
    "path": "tests/Issues/StraussIssue111Test.php",
    "chars": 1300,
    "preview": "<?php\n/**\n * Should prefix modified classnames in phpdoc\n *\n * @see https://github.com/BrianHenryIE/strauss/pull/111\n */"
  },
  {
    "path": "tests/Issues/StraussIssue114Test.php",
    "chars": 1577,
    "preview": "<?php\n/**\n * `$data = @\\Aws\\parse_ini_file($filename, true, INI_SCANNER_NORMAL);` muted errors not prefixed.\n *\n * @see "
  },
  {
    "path": "tests/Issues/StraussIssue119Test.php",
    "chars": 1324,
    "preview": "<?php\n/**\n * `class final` appears in `symfony/console/CHANGELOG.md` causing `symfony/polyfill-php80/Resources/stubs/Att"
  },
  {
    "path": "tests/Issues/StraussIssue11Test.php",
    "chars": 4810,
    "preview": "<?php\n/**\n * When users migrate from Mozart, the settings are only preserved when the extra \"mozart\" key\n * is still use"
  },
  {
    "path": "tests/Issues/StraussIssue133Test.php",
    "chars": 1607,
    "preview": "<?php\n/**\n * Error when `config.vendor-dir` is multiple directories deep.\n *\n * @see https://github.com/BrianHenryIE/str"
  },
  {
    "path": "tests/Issues/StraussIssue136Test.php",
    "chars": 1919,
    "preview": "<?php\n/**\n * Error when `config.vendor-dir` is multiple directories deep.\n *\n * @see https://github.com/BrianHenryIE/str"
  },
  {
    "path": "tests/Issues/StraussIssue143Test.php",
    "chars": 5493,
    "preview": "<?php\n/**\n * Error when composer.json is in a subdirectory of the project; a sibling diretcory of the vendor directory.\n"
  },
  {
    "path": "tests/Issues/StraussIssue14Test.php",
    "chars": 2030,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/issues/14\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nu"
  },
  {
    "path": "tests/Issues/StraussIssue154Test.php",
    "chars": 14661,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/issues/154\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\n"
  },
  {
    "path": "tests/Issues/StraussIssue159Test.php",
    "chars": 1232,
    "preview": "<?php\n/**\n * Strauss generated autoload doesn't respect `\"platform-check\": false`.\n *\n * @see https://github.com/BrianHe"
  },
  {
    "path": "tests/Issues/StraussIssue163Test.php",
    "chars": 2477,
    "preview": "<?php\n/**\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nuse BrianHenryIE\\Strauss\\IntegrationTestCase;\n\n/**\n * @pack"
  },
  {
    "path": "tests/Issues/StraussIssue166Test.php",
    "chars": 1308,
    "preview": "<?php\n/**\n * namespaced trait name\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/166\n */\n\nnamespace BrianHen"
  },
  {
    "path": "tests/Issues/StraussIssue172Test.php",
    "chars": 1176,
    "preview": "<?php\n/**\n * Improper dealing with global namespaces\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/172\n */\n\n"
  },
  {
    "path": "tests/Issues/StraussIssue173Test.php",
    "chars": 2777,
    "preview": "<?php\n/**\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/173\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues"
  },
  {
    "path": "tests/Issues/StraussIssue179Test.php",
    "chars": 1864,
    "preview": "<?php\n/**\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/179\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues"
  },
  {
    "path": "tests/Issues/StraussIssue183Test.php",
    "chars": 4397,
    "preview": "<?php\n/**\n * New `bootstrap.php` file to load the aliases file is incorrect\n *\n * @see https://github.com/BrianHenryIE/s"
  },
  {
    "path": "tests/Issues/StraussIssue188Test.php",
    "chars": 2637,
    "preview": "<?php\n/**\n * Improper dealing with global namespaces\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/172\n */\n\n"
  },
  {
    "path": "tests/Issues/StraussIssue189Test.php",
    "chars": 1668,
    "preview": "<?php\n/**\n * Fix: namespaces defined in psr4 autoloaders that do not contain classes, i.e. only sub-namespaces have clas"
  },
  {
    "path": "tests/Issues/StraussIssue191Test.php",
    "chars": 1399,
    "preview": "<?php\n/**\n * Really an issue in brianhenryie/simple-php-code-parser; this is a regression test\n *\n * @see https://github"
  },
  {
    "path": "tests/Issues/StraussIssue19Test.php",
    "chars": 1594,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/issues/19\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nu"
  },
  {
    "path": "tests/Issues/StraussIssue200Test.php",
    "chars": 1591,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/pull/200\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nus"
  },
  {
    "path": "tests/Issues/StraussIssue204Test.php",
    "chars": 2267,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/issues/204\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\n"
  },
  {
    "path": "tests/Issues/StraussIssue206Test.php",
    "chars": 2340,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/pull/206\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nus"
  },
  {
    "path": "tests/Issues/StraussIssue207Test.php",
    "chars": 5037,
    "preview": "<?php\n/**\n * Copy all files in Fremius / Action Scheduler / Plugin Update Checker packages.\n *\n * TODO: But these packag"
  },
  {
    "path": "tests/Issues/StraussIssue212Test.php",
    "chars": 1095,
    "preview": "<?php\n/**\n * `symfony/polyfill-php83` fatal error.\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/212\n */\n\nna"
  },
  {
    "path": "tests/Issues/StraussIssue213Test.php",
    "chars": 1505,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/pull/213\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nus"
  },
  {
    "path": "tests/Issues/StraussIssue215Test.php",
    "chars": 1994,
    "preview": "<?php\n/**\n * When using Strauss to process the DomPDF package, not all files are being copied over.\n * Specifically, the"
  },
  {
    "path": "tests/Issues/StraussIssue225Test.php",
    "chars": 2966,
    "preview": "<?php\n/**\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/225\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues"
  },
  {
    "path": "tests/Issues/StraussIssue22Test.php",
    "chars": 3311,
    "preview": "<?php\n/**\n * Metapackages!\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/22\n */\n\nnamespace BrianHenryIE\\Stra"
  },
  {
    "path": "tests/Issues/StraussIssue230Test.php",
    "chars": 1487,
    "preview": "<?php\n/**\n *  willdurand/geocoder:4.6.0\n *\n * `vendor-prefixed/willdurand/geocoder/StatefulGeocoder.php`\n *\n * @see http"
  },
  {
    "path": "tests/Issues/StraussIssue247Test.php",
    "chars": 2118,
    "preview": "<?php\n/**\n * Fix invalid constant replacements.\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/247\n */\n\nnames"
  },
  {
    "path": "tests/Issues/StraussIssue249Test.php",
    "chars": 2632,
    "preview": "<?php\n/**\n * [warning] Package directory unexpectedly DOES NOT exist: /path/to/vendor-prefixed/freemius/wordpress-sdk\n *"
  },
  {
    "path": "tests/Issues/StraussIssue258Test.php",
    "chars": 1380,
    "preview": "<?php\n/**\n * classmap prefix applied repeatedly\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/258\n */\n\nnames"
  },
  {
    "path": "tests/Issues/StraussIssue261Test.php",
    "chars": 1129,
    "preview": "<?php\n/**\n * Don't fail when an autoloaded directory is missing.\n *\n * @see https://github.com/BrianHenryIE/strauss/issu"
  },
  {
    "path": "tests/Issues/StraussIssue262Test.php",
    "chars": 2241,
    "preview": "<?php\n/**\n * Symlink removed although it is in exclude_from_copy\n *\n * @see https://github.com/BrianHenryIE/strauss/issu"
  },
  {
    "path": "tests/Issues/StraussIssue27Test.php",
    "chars": 2270,
    "preview": "<?php\n/**\n * Problem with too many replacements due to common class, domain, namespace names, \"Normalizer\".\n *\n * @see h"
  },
  {
    "path": "tests/Issues/StraussIssue33Test.php",
    "chars": 2046,
    "preview": "<?php\n/**\n *\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nuse BrianHenryIE\\Strauss\\Composer\\Extra\\StraussConfig;\nu"
  },
  {
    "path": "tests/Issues/StraussIssue34Test.php",
    "chars": 2256,
    "preview": "<?php\n/**\n * Don't double prefix when updating project code on repeated runs.\n *\n * @see https://github.com/BrianHenryIE"
  },
  {
    "path": "tests/Issues/StraussIssue37Test.php",
    "chars": 998,
    "preview": "<?php\n/**\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/37\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;"
  },
  {
    "path": "tests/Issues/StraussIssue44Test.php",
    "chars": 1405,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/issues/44\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nu"
  },
  {
    "path": "tests/Issues/StraussIssue47Test.php",
    "chars": 7129,
    "preview": "<?php\n/**\n * When the namespace being replaced is a substring of the prefix, the order of replacements\n * is important, "
  },
  {
    "path": "tests/Issues/StraussIssue49Test.php",
    "chars": 1840,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/issues/49\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nu"
  },
  {
    "path": "tests/Issues/StraussIssue65Test.php",
    "chars": 2220,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/issues/65\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nu"
  },
  {
    "path": "tests/Issues/StraussIssue66Test.php",
    "chars": 1672,
    "preview": "<?php\n/**\n * WPGraphQL had the word \"namespace\" in a comment and it was tripping up the matches.\n *\n * @see https://gith"
  },
  {
    "path": "tests/Issues/StraussIssue74Test.php",
    "chars": 2470,
    "preview": "<?php\n/**\n * Also prefix global functions\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/74\n */\n\nnamespace Br"
  },
  {
    "path": "tests/Issues/StraussIssue76Test.php",
    "chars": 1192,
    "preview": "<?php\n/**\n * Test PSR-4 array of autoload values.\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/76\n */\n\nname"
  },
  {
    "path": "tests/Issues/StraussIssue79Test.php",
    "chars": 1729,
    "preview": "<?php\n/**\n * JsonException core PHP class, polyfilled by Symfony, incorrectly replaced\n *\n *\n *\n * @see https://github.c"
  },
  {
    "path": "tests/Issues/StraussIssue80Test.php",
    "chars": 3468,
    "preview": "<?php\n/**\n * Incorrectly not prefixing when the word \"namespace\" is on the same line as `<?php `.\n *\n * @see https://git"
  },
  {
    "path": "tests/Issues/StraussIssue81Test.php",
    "chars": 7517,
    "preview": "<?php\n/**\n * How to handle prefixed dependencies also used by dev-dependencies\n *\n * @see https://github.com/BrianHenryI"
  },
  {
    "path": "tests/Issues/StraussIssue83Test.php",
    "chars": 1757,
    "preview": "<?php\n/**\n * instanceof not prefixed properly.\n *\n * @see https://github.com/BrianHenryIE/strauss/issues/83\n */\n\nnamespa"
  },
  {
    "path": "tests/Issues/StraussIssue87Test.php",
    "chars": 1878,
    "preview": "<?php\n/**\n * Strauss does not remove namespaced classes from the composer classmap files when optimize-autoloader is ena"
  },
  {
    "path": "tests/Issues/StraussIssue88Test.php",
    "chars": 1750,
    "preview": "<?php\n/**\n * `return (string) \\Aws\\serialize($command)->getUri();` not prefixed properly.\n *\n * @see https://github.com/"
  },
  {
    "path": "tests/Issues/StraussIssue8Test.php",
    "chars": 1224,
    "preview": "<?php\n/**\n * @see https://github.com/BrianHenryIE/strauss/issues/8\n */\n\nnamespace BrianHenryIE\\Strauss\\Tests\\Issues;\n\nus"
  },
  {
    "path": "tests/Issues/StraussIssue91Test.php",
    "chars": 977,
    "preview": "<?php\n/**\n * Undefined offset: 1\n *\n * @see https://github.com/BrianHenryIE/strauss/pull/91\n */\n\nnamespace BrianHenryIE\\"
  },
  {
    "path": "tests/Issues/StraussIssue93Test.php",
    "chars": 1126,
    "preview": "<?php\n/**\n * Cleanup vendor/composer/installed.json after delete-vendor-directories\n *\n * @see https://github.com/BrianH"
  },
  {
    "path": "tests/Issues/data/Mpdf.php",
    "chars": 959678,
    "preview": "<?php\n\nnamespace Mpdf;\n\nuse Mpdf\\Config\\ConfigVariables;\nuse Mpdf\\Config\\FontVariables;\nuse Mpdf\\Conversion;\nuse Mpdf\\Cs"
  },
  {
    "path": "tests/TestCase.php",
    "chars": 6330,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss;\n\nuse BrianHenryIE\\ColorLogger\\ColorLogger;\nuse BrianHenryIE\\Strauss\\Helpers\\FileS"
  },
  {
    "path": "tests/Unit/Composer/ComposerPackageTest.php",
    "chars": 6510,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Composer;\n\nuse Composer\\Factory;\nuse Composer\\IO\\NullIO;\nuse BrianHenryIE\\Strauss\\"
  },
  {
    "path": "tests/Unit/Composer/Extra/StraussConfigTest.php",
    "chars": 27815,
    "preview": "<?php\n/**\n * Should accept Strauss config and Mozart config.\n *\n * Should have sensible defaults.\n */\n\nnamespace BrianHe"
  },
  {
    "path": "tests/Unit/Composer/ProjectComposerPackageTest.php",
    "chars": 1193,
    "preview": "<?php\n\nnamespace BrianHenryIE\\Strauss\\Composer;\n\nuse BrianHenryIE\\Strauss\\Composer\\Extra\\StraussConfig;\nuse BrianHenryIE"
  },
  {
    "path": "tests/Unit/Composer/composerpackage-test-easypost-php.json",
    "chars": 751,
    "preview": "{\n  \"name\": \"easypost/easypost-php\",\n  \"description\": \"EasyPost Shipping API Client Library for PHP\",\n  \"keywords\": [\n  "
  },
  {
    "path": "tests/Unit/Composer/composerpackage-test-libmergepdf.json",
    "chars": 715,
    "preview": "{\n  \"name\": \"iio/libmergepdf\",\n  \"description\": \"Library for merging multiple PDFs\",\n  \"keywords\": [\"pdf\", \"merge\"],\n  \""
  },
  {
    "path": "tests/Unit/Composer/composerpackage-test-php-di.json",
    "chars": 1385,
    "preview": "{\n  \"name\": \"php-di/php-di\",\n  \"type\": \"library\",\n  \"description\": \"The dependency injection container for humans\",\n  \"k"
  },
  {
    "path": "tests/Unit/Composer/projectcomposerpackage-test-1.json",
    "chars": 179,
    "preview": "{\n  \"name\": \"brianhenryie/strauss-config-test\",\n  \"require\": {\n    \"league/container\": \"*\"\n  },\n\n  \"autoload\": {\n    \"ps"
  },
  {
    "path": "tests/Unit/Composer/projectcomposerpackage-test-getProjectPhpFiles.json",
    "chars": 228,
    "preview": "{\n  \"name\": \"brianhenryie/strauss-config-test\",\n  \"autoload\": {\n    \"psr-4\": {\n      \"BrianHenryIE\\\\Strauss\\\\\": [\"src\",\""
  }
]

// ... and 23 more files (download for full content)

About this extraction

This page contains the full source code of the BrianHenryIE/strauss GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 223 files (2.0 MB), approximately 545.4k tokens, and a symbol index with 1480 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!