private function loadAndParseFile($fileName, $rootDir)
    {
        if (!$this->configuration->isRemoteFileInclusionEnabled()) {
            $rootDir = \realpath($rootDir);
            $fullPath = \realpath($rootDir . '/' . $fileName);

            if (!\is_readable($fullPath)) {
                throw new FileNotFoundException($fileName);
            }
        } else {
            $fullPath = $rootDir . '/' . $fileName;
            if (!\filter_var($fullPath, FILTER_VALIDATE_URL) && !\is_readable($fullPath)) {
                throw new FileNotFoundException($fileName);
            }
        }

        // Prevent LFI directory traversal attacks
        if (!$this->configuration->isDirectoryTraversalAllowed() &&
            \substr($fullPath, 0, \strlen($rootDir)) !== $rootDir
        ) {
            throw new FileNotFoundException($fileName);
        }

        $cacheKey = \md5($fullPath);

        // cache based on file name, prevents including/parsing the same file multiple times
        if (isset($this->cachedFiles[$cacheKey])) {
            return $this->cachedFiles[$cacheKey];
        }

        $fileExtension = (\pathinfo($fileName, PATHINFO_EXTENSION));

        if (\in_array($fileExtension, ['yaml', 'yml', 'raml'], true)) {
            $rootDir = \dirname($rootDir . '/' . $fileName);

            // RAML and YAML files are always parsed
            $fileData = $this->parseRamlString(
                \file_get_contents($fullPath),
                $rootDir
            );
            $fileData = $this->includeAndParseFiles($fileData, $rootDir);
        } else {
            $loader = \array_key_exists($fileExtension, $this->fileLoaders) ? $this->fileLoaders[$fileExtension] : $this->fileLoaders['*'];

            $fileData = $loader->loadFile($fullPath);
            $this->cachedFilesPaths[\md5($fileData)] = $fullPath;
        }

        // cache before returning
        $this->cachedFiles[$cacheKey] = $fileData;

        $this->includedFiles[] = $fullPath;

        return $fileData;
    }