Throw exception on invalid file URI
parent
a43d2b2a0f
commit
6611a30d90
|
@ -3,6 +3,8 @@ declare(strict_types = 1);
|
||||||
|
|
||||||
namespace LanguageServer;
|
namespace LanguageServer;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively Searches files with matching filename, starting at $path.
|
* Recursively Searches files with matching filename, starting at $path.
|
||||||
*
|
*
|
||||||
|
@ -29,7 +31,15 @@ function findFilesRecursive(string $path, string $pattern): array {
|
||||||
*/
|
*/
|
||||||
function pathToUri(string $filepath): string {
|
function pathToUri(string $filepath): string {
|
||||||
$filepath = trim(str_replace('\\', '/', $filepath), '/');
|
$filepath = trim(str_replace('\\', '/', $filepath), '/');
|
||||||
$filepath = implode('/', array_map('urlencode', explode('/', $filepath)));
|
$parts = explode('/', $filepath);
|
||||||
|
// Don't %-encode the colon after a Windows drive letter
|
||||||
|
$first = array_shift($parts);
|
||||||
|
if (substr($first, -1) !== ':') {
|
||||||
|
$first = urlencode($first);
|
||||||
|
}
|
||||||
|
$parts = array_map('urlencode', $parts);
|
||||||
|
array_unshift($parts, $first);
|
||||||
|
$filepath = implode('/', $parts);
|
||||||
return 'file:///' . $filepath;
|
return 'file:///' . $filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +51,10 @@ function pathToUri(string $filepath): string {
|
||||||
*/
|
*/
|
||||||
function uriToPath(string $uri)
|
function uriToPath(string $uri)
|
||||||
{
|
{
|
||||||
$filepath = urldecode(parse_url($uri)['path']);
|
$fragments = parse_url($uri);
|
||||||
|
if ($fragments === null || !isset($fragments['scheme']) || $fragments['scheme'] !== 'file') {
|
||||||
|
throw new InvalidArgumentException("Not a valid file URI: $uri");
|
||||||
|
}
|
||||||
|
$filepath = urldecode($fragments['path']);
|
||||||
return strpos($filepath, ':') === false ? $filepath : str_replace('/', '\\', $filepath);
|
return strpos($filepath, ':') === false ? $filepath : str_replace('/', '\\', $filepath);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ class FormatterTest extends TestCase
|
||||||
$input = file_get_contents(__DIR__ . '/../fixtures/format.php');
|
$input = file_get_contents(__DIR__ . '/../fixtures/format.php');
|
||||||
$output = file_get_contents(__DIR__ . '/../fixtures/format_expected.php');
|
$output = file_get_contents(__DIR__ . '/../fixtures/format_expected.php');
|
||||||
|
|
||||||
$edits = $formatter->format($input, 'whatever');
|
$edits = $formatter->format($input, 'file:///whatever');
|
||||||
$this->assertSame($output, $edits[0]->newText);
|
$this->assertSame($output, $edits[0]->newText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class FormatterTest extends TestCase
|
||||||
$formatter = new Formatter();
|
$formatter = new Formatter();
|
||||||
$expected = file_get_contents(__DIR__ . '/../fixtures/format_expected.php');
|
$expected = file_get_contents(__DIR__ . '/../fixtures/format_expected.php');
|
||||||
|
|
||||||
$edits = $formatter->format($expected, 'whatever');
|
$edits = $formatter->format($expected, 'file:///whatever');
|
||||||
$this->assertSame([], $edits);
|
$this->assertSame([], $edits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase;
|
||||||
use LanguageServer\Tests\MockProtocolStream;
|
use LanguageServer\Tests\MockProtocolStream;
|
||||||
use LanguageServer\{Server, Client, LanguageClient, Project};
|
use LanguageServer\{Server, Client, LanguageClient, Project};
|
||||||
use LanguageServer\Protocol\{TextDocumentIdentifier, TextDocumentItem, FormattingOptions};
|
use LanguageServer\Protocol\{TextDocumentIdentifier, TextDocumentItem, FormattingOptions};
|
||||||
|
use function LanguageServer\{pathToUri, uriToPath};
|
||||||
|
|
||||||
class FormattingTest extends TestCase
|
class FormattingTest extends TestCase
|
||||||
{
|
{
|
||||||
|
@ -27,19 +28,21 @@ class FormattingTest extends TestCase
|
||||||
$client = new LanguageClient(new MockProtocolStream());
|
$client = new LanguageClient(new MockProtocolStream());
|
||||||
$project = new Project($client);
|
$project = new Project($client);
|
||||||
$textDocument = new Server\TextDocument($project, $client);
|
$textDocument = new Server\TextDocument($project, $client);
|
||||||
|
$path = realpath(__DIR__ . '/../../../fixtures/format.php');
|
||||||
|
$uri = pathToUri($path);
|
||||||
|
|
||||||
// Trigger parsing of source
|
// Trigger parsing of source
|
||||||
$textDocumentItem = new TextDocumentItem();
|
$textDocumentItem = new TextDocumentItem();
|
||||||
$textDocumentItem->uri = 'whatever';
|
$textDocumentItem->uri = $uri;
|
||||||
$textDocumentItem->languageId = 'php';
|
$textDocumentItem->languageId = 'php';
|
||||||
$textDocumentItem->version = 1;
|
$textDocumentItem->version = 1;
|
||||||
$textDocumentItem->text = file_get_contents(__DIR__ . '/../../../fixtures/format.php');
|
$textDocumentItem->text = file_get_contents($path);
|
||||||
$textDocument->didOpen($textDocumentItem);
|
$textDocument->didOpen($textDocumentItem);
|
||||||
|
|
||||||
// how code should look after formatting
|
// how code should look after formatting
|
||||||
$expected = file_get_contents(__DIR__ . '/../../../fixtures/format_expected.php');
|
$expected = file_get_contents(__DIR__ . '/../../../fixtures/format_expected.php');
|
||||||
// Request formatting
|
// Request formatting
|
||||||
$result = $textDocument->formatting(new TextDocumentIdentifier('whatever'), new FormattingOptions());
|
$result = $textDocument->formatting(new TextDocumentIdentifier($uri), new FormattingOptions());
|
||||||
$this->assertEquals([0 => [
|
$this->assertEquals([0 => [
|
||||||
'range' => [
|
'range' => [
|
||||||
'start' => [
|
'start' => [
|
||||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types = 1);
|
||||||
namespace LanguageServer\Tests\Utils;
|
namespace LanguageServer\Tests\Utils;
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use InvalidArgumentException;
|
||||||
use function LanguageServer\{pathToUri, uriToPath};
|
use function LanguageServer\{pathToUri, uriToPath};
|
||||||
|
|
||||||
class FileUriTest extends TestCase
|
class FileUriTest extends TestCase
|
||||||
|
@ -24,11 +25,11 @@ class FileUriTest extends TestCase
|
||||||
|
|
||||||
// special chars are escaped
|
// special chars are escaped
|
||||||
$uri = pathToUri('c:/path/to/file/dürüm döner.php');
|
$uri = pathToUri('c:/path/to/file/dürüm döner.php');
|
||||||
$this->assertEquals('file:///c%3A/path/to/file/d%C3%BCr%C3%BCm+d%C3%B6ner.php', $uri);
|
$this->assertEquals('file:///c:/path/to/file/d%C3%BCr%C3%BCm+d%C3%B6ner.php', $uri);
|
||||||
|
|
||||||
//backslashes are transformed
|
//backslashes are transformed
|
||||||
$uri = pathToUri('c:\\foo\\bar.baz');
|
$uri = pathToUri('c:\\foo\\bar.baz');
|
||||||
$this->assertEquals('file:///c%3A/foo/bar.baz', $uri);
|
$this->assertEquals('file:///c:/foo/bar.baz', $uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUriToPath()
|
public function testUriToPath()
|
||||||
|
@ -51,4 +52,18 @@ class FileUriTest extends TestCase
|
||||||
$uri = 'file:///c:/foo/bar.baz';
|
$uri = 'file:///c:/foo/bar.baz';
|
||||||
$this->assertEquals('c:\\foo\\bar.baz', uriToPath($uri));
|
$this->assertEquals('c:\\foo\\bar.baz', uriToPath($uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUriToPathForUnknownProtocol()
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$uri = 'vfs:///whatever';
|
||||||
|
uriToPath($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUriToPathForInvalidProtocol()
|
||||||
|
{
|
||||||
|
$this->expectException(InvalidArgumentException::class);
|
||||||
|
$uri = 'http://www.google.com';
|
||||||
|
uriToPath($uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue