mirror of
https://github.com/composer/composer
synced 2025-05-10 09:02:59 +00:00
Merge remote-tracking branch 'guilliamxavier/lax-schema'
This commit is contained in:
commit
084fff2014
6 changed files with 116 additions and 75 deletions
|
@ -94,9 +94,7 @@ Out of the box, Composer supports four types:
|
||||||
CMSs like the [SilverStripe installer](https://github.com/silverstripe/silverstripe-installer)
|
CMSs like the [SilverStripe installer](https://github.com/silverstripe/silverstripe-installer)
|
||||||
or full fledged applications distributed as packages. This can for example
|
or full fledged applications distributed as packages. This can for example
|
||||||
be used by IDEs to provide listings of projects to initialize when creating
|
be used by IDEs to provide listings of projects to initialize when creating
|
||||||
a new workspace. Setting the type to `project` also makes the `name` and
|
a new workspace.
|
||||||
`description` fields optional, making it a good choice for closed source
|
|
||||||
projects wishing to use `composer validate`.
|
|
||||||
- **metapackage:** An empty package that contains requirements and will trigger
|
- **metapackage:** An empty package that contains requirements and will trigger
|
||||||
their installation, but contains no files and will not write anything to the
|
their installation, but contains no files and will not write anything to the
|
||||||
filesystem. As such, it does not require a dist or source key to be
|
filesystem. As such, it does not require a dist or source key to be
|
||||||
|
|
|
@ -2,27 +2,6 @@
|
||||||
"$schema": "https://json-schema.org/draft-04/schema#",
|
"$schema": "https://json-schema.org/draft-04/schema#",
|
||||||
"title": "Package",
|
"title": "Package",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"type": {
|
|
||||||
"not": {
|
|
||||||
"enum": ["project"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["name", "description"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"type": {
|
|
||||||
"enum": ["project"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["type"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
|
@ -196,9 +196,9 @@ class JsonFile
|
||||||
|
|
||||||
$schemaData = (object) array('$ref' => $schemaFile);
|
$schemaData = (object) array('$ref' => $schemaFile);
|
||||||
|
|
||||||
if ($schema === self::LAX_SCHEMA) {
|
if ($schema !== self::LAX_SCHEMA) {
|
||||||
$schemaData->additionalProperties = true;
|
$schemaData->additionalProperties = false;
|
||||||
$schemaData->oneOf = null;
|
$schemaData->required = array('name', 'description');
|
||||||
}
|
}
|
||||||
|
|
||||||
$validator = new Validator();
|
$validator = new Validator();
|
||||||
|
|
|
@ -63,16 +63,6 @@ class ConfigValidator
|
||||||
$json->validateSchema();
|
$json->validateSchema();
|
||||||
} catch (JsonValidationException $e) {
|
} catch (JsonValidationException $e) {
|
||||||
foreach ($e->getErrors() as $message) {
|
foreach ($e->getErrors() as $message) {
|
||||||
if ($message === 'type : The property type is required') {
|
|
||||||
$message .= ' (see https://getcomposer.org/doc/04-schema.md#type)';
|
|
||||||
}
|
|
||||||
if ($message === 'name : The property name is required') {
|
|
||||||
$message .= ' (or set "type" to "project" to remove this requirement)';
|
|
||||||
}
|
|
||||||
if ($message === 'description : The property description is required') {
|
|
||||||
$message .= ' (or set "type" to "project" to remove this requirement)';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($laxValid) {
|
if ($laxValid) {
|
||||||
$publishErrors[] = $message;
|
$publishErrors[] = $message;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -37,44 +37,6 @@ class ComposerSchemaTest extends TestCase
|
||||||
$this->assertEquals($expectedError, $this->check($json));
|
$this->assertEquals($expectedError, $this->check($json));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRequiredProperties()
|
|
||||||
{
|
|
||||||
$json = '{ }';
|
|
||||||
$result = $this->check($json);
|
|
||||||
$this->assertContains(array('property' => 'type', 'message' => 'The property type is required', 'constraint' => 'required'), $result);
|
|
||||||
$this->assertContains(array('property' => 'name', 'message' => 'The property name is required', 'constraint' => 'required'), $result);
|
|
||||||
$this->assertContains(array('property' => 'description', 'message' => 'The property description is required', 'constraint' => 'required'), $result);
|
|
||||||
$this->assertContains(array('property' => '', 'message' => 'Failed to match exactly one schema', 'constraint' => 'oneOf'), $result);
|
|
||||||
|
|
||||||
$json = '{ "name": "vendor/package" }';
|
|
||||||
$this->assertEquals(array(
|
|
||||||
array('property' => 'type', 'message' => 'The property type is required', 'constraint' => 'required'),
|
|
||||||
array('property' => 'description', 'message' => 'The property description is required', 'constraint' => 'required'),
|
|
||||||
array('property' => '', 'message' => 'Failed to match exactly one schema', 'constraint' => 'oneOf'),
|
|
||||||
), $this->check($json));
|
|
||||||
|
|
||||||
$json = '{ "description": "generic description" }';
|
|
||||||
$this->assertEquals(array(
|
|
||||||
array('property' => 'type', 'message' => 'The property type is required', 'constraint' => 'required'),
|
|
||||||
array('property' => 'name', 'message' => 'The property name is required', 'constraint' => 'required'),
|
|
||||||
array('property' => '', 'message' => 'Failed to match exactly one schema', 'constraint' => 'oneOf'),
|
|
||||||
), $this->check($json));
|
|
||||||
|
|
||||||
$json = '{ "type": "library" }';
|
|
||||||
$this->assertEquals(array(
|
|
||||||
array('property' => 'type', 'message' => 'Does not have a value in the enumeration ["project"]', 'constraint' => 'enum', 'enum' => array('project')),
|
|
||||||
array('property' => 'name', 'message' => 'The property name is required', 'constraint' => 'required'),
|
|
||||||
array('property' => 'description', 'message' => 'The property description is required', 'constraint' => 'required'),
|
|
||||||
array('property' => '', 'message' => 'Failed to match exactly one schema', 'constraint' => 'oneOf'),
|
|
||||||
), $this->check($json));
|
|
||||||
|
|
||||||
$json = '{ "type": "project" }';
|
|
||||||
$this->assertTrue($this->check($json));
|
|
||||||
|
|
||||||
$json = '{ "name": "vendor/package", "description": "description" }';
|
|
||||||
$this->assertTrue($this->check($json));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testOptionalAbandonedProperty()
|
public function testOptionalAbandonedProperty()
|
||||||
{
|
{
|
||||||
$json = '{"name": "vendor/package", "description": "description", "abandoned": true}';
|
$json = '{"name": "vendor/package", "description": "description", "abandoned": true}';
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Composer\Test\Json;
|
||||||
|
|
||||||
use Seld\JsonLint\ParsingException;
|
use Seld\JsonLint\ParsingException;
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
|
use Composer\Json\JsonValidationException;
|
||||||
use Composer\Test\TestCase;
|
use Composer\Test\TestCase;
|
||||||
|
|
||||||
class JsonFileTest extends TestCase
|
class JsonFileTest extends TestCase
|
||||||
|
@ -93,6 +94,117 @@ class JsonFileTest extends TestCase
|
||||||
{
|
{
|
||||||
$json = new JsonFile(__DIR__.'/Fixtures/composer.json');
|
$json = new JsonFile(__DIR__.'/Fixtures/composer.json');
|
||||||
$this->assertTrue($json->validateSchema());
|
$this->assertTrue($json->validateSchema());
|
||||||
|
$this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSchemaValidationError()
|
||||||
|
{
|
||||||
|
$file = tempnam(sys_get_temp_dir(), 'c');
|
||||||
|
file_put_contents($file, '{ "name": null }');
|
||||||
|
$json = new JsonFile($file);
|
||||||
|
$expectedMessage = sprintf('"%s" does not match the expected JSON schema', $file);
|
||||||
|
$expectedError = 'name : NULL value found, but a string is required';
|
||||||
|
try {
|
||||||
|
$json->validateSchema();
|
||||||
|
$this->fail('Expected exception to be thrown (strict)');
|
||||||
|
} catch (JsonValidationException $e) {
|
||||||
|
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||||
|
$this->assertContains($expectedError, $e->getErrors());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$json->validateSchema(JsonFile::LAX_SCHEMA);
|
||||||
|
$this->fail('Expected exception to be thrown (lax)');
|
||||||
|
} catch (JsonValidationException $e) {
|
||||||
|
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||||
|
$this->assertContains($expectedError, $e->getErrors());
|
||||||
|
}
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSchemaValidationLaxAdditionalProperties()
|
||||||
|
{
|
||||||
|
$file = tempnam(sys_get_temp_dir(), 'c');
|
||||||
|
file_put_contents($file, '{ "name": "vendor/package", "description": "generic description", "foo": "bar" }');
|
||||||
|
$json = new JsonFile($file);
|
||||||
|
try {
|
||||||
|
$json->validateSchema();
|
||||||
|
$this->fail('Expected exception to be thrown (strict)');
|
||||||
|
} catch (JsonValidationException $e) {
|
||||||
|
$this->assertEquals(sprintf('"%s" does not match the expected JSON schema', $file), $e->getMessage());
|
||||||
|
$this->assertEquals(array('The property foo is not defined and the definition does not allow additional properties'), $e->getErrors());
|
||||||
|
}
|
||||||
|
$this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA));
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSchemaValidationLaxRequired()
|
||||||
|
{
|
||||||
|
$file = tempnam(sys_get_temp_dir(), 'c');
|
||||||
|
$json = new JsonFile($file);
|
||||||
|
|
||||||
|
$expectedMessage = sprintf('"%s" does not match the expected JSON schema', $file);
|
||||||
|
|
||||||
|
file_put_contents($file, '{ }');
|
||||||
|
try {
|
||||||
|
$json->validateSchema();
|
||||||
|
$this->fail('Expected exception to be thrown (strict)');
|
||||||
|
} catch (JsonValidationException $e) {
|
||||||
|
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||||
|
$errors = $e->getErrors();
|
||||||
|
$this->assertContains('name : The property name is required', $errors);
|
||||||
|
$this->assertContains('description : The property description is required', $errors);
|
||||||
|
}
|
||||||
|
$this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA));
|
||||||
|
|
||||||
|
file_put_contents($file, '{ "name": "vendor/package" }');
|
||||||
|
try {
|
||||||
|
$json->validateSchema();
|
||||||
|
$this->fail('Expected exception to be thrown (strict)');
|
||||||
|
} catch (JsonValidationException $e) {
|
||||||
|
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||||
|
$this->assertEquals(array('description : The property description is required'), $e->getErrors());
|
||||||
|
}
|
||||||
|
$this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA));
|
||||||
|
|
||||||
|
file_put_contents($file, '{ "description": "generic description" }');
|
||||||
|
try {
|
||||||
|
$json->validateSchema();
|
||||||
|
$this->fail('Expected exception to be thrown (strict)');
|
||||||
|
} catch (JsonValidationException $e) {
|
||||||
|
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||||
|
$this->assertEquals(array('name : The property name is required'), $e->getErrors());
|
||||||
|
}
|
||||||
|
$this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA));
|
||||||
|
|
||||||
|
file_put_contents($file, '{ "type": "library" }');
|
||||||
|
try {
|
||||||
|
$json->validateSchema();
|
||||||
|
$this->fail('Expected exception to be thrown (strict)');
|
||||||
|
} catch (JsonValidationException $e) {
|
||||||
|
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||||
|
$errors = $e->getErrors();
|
||||||
|
$this->assertContains('name : The property name is required', $errors);
|
||||||
|
$this->assertContains('description : The property description is required', $errors);
|
||||||
|
}
|
||||||
|
$this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA));
|
||||||
|
|
||||||
|
file_put_contents($file, '{ "type": "project" }');
|
||||||
|
try {
|
||||||
|
$json->validateSchema();
|
||||||
|
$this->fail('Expected exception to be thrown (strict)');
|
||||||
|
} catch (JsonValidationException $e) {
|
||||||
|
$this->assertEquals($expectedMessage, $e->getMessage());
|
||||||
|
$errors = $e->getErrors();
|
||||||
|
$this->assertContains('name : The property name is required', $errors);
|
||||||
|
$this->assertContains('description : The property description is required', $errors);
|
||||||
|
}
|
||||||
|
$this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA));
|
||||||
|
|
||||||
|
file_put_contents($file, '{ "name": "vendor/package", "description": "generic description" }');
|
||||||
|
$this->assertTrue($json->validateSchema());
|
||||||
|
$this->assertTrue($json->validateSchema(JsonFile::LAX_SCHEMA));
|
||||||
|
|
||||||
|
unlink($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testParseErrorDetectMissingCommaMultiline()
|
public function testParseErrorDetectMissingCommaMultiline()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue