"$schema": "http://json-schema.org/schema#",
"description": "MediaWiki extension.json schema",
"type": "object",
+ "additionalProperties": false,
"properties": {
"manifest_version": {
"type": "integer",
"type": "array",
"description": "List of service wiring files to be loaded by the default instance of MediaWikiServices"
},
+ "attributes": {
+ "description":"Registration information for other extensions",
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": ["array", "object"]
+ }
+ }
+ }
+ }
+ },
"load_composer_autoloader": {
"type": "boolean",
"description": "Load the composer autoloader for this extension, if one is present"
'ValidSkinNames',
];
+ /**
+ * Top-level attributes that come from MW core
+ *
+ * @var string[]
+ */
+ protected static $coreAttributes = [
+ 'SkinOOUIThemes',
+ 'TrackingCategories',
+ ];
+
/**
* Mapping of global settings to their specific merge strategies.
*
*/
protected $attributes = [];
+ /**
+ * Extension attributes, keyed by name =>
+ * settings.
+ *
+ * @var array
+ */
+ protected $extAttributes = [];
+
/**
* @param string $path
* @param array $info
$this->callbacks[$name] = $info['callback'];
}
+ if ( $version === 2 ) {
+ $this->extractAttributes( $path, $info );
+ }
+
foreach ( $info as $key => $val ) {
+ // If it's a global setting,
if ( in_array( $key, self::$globalSettings ) ) {
$this->storeToArray( $path, "wg$key", $val, $this->globals );
+ continue;
+ }
// Ignore anything that starts with a @
- } elseif ( $key[0] !== '@' && !in_array( $key, self::$notAttributes )
- && !in_array( $key, self::$creditsAttributes )
- ) {
- $this->storeToArray( $path, $key, $val, $this->attributes );
+ if ( $key[0] === '@' ) {
+ continue;
+ }
+
+ if ( $version === 2 ) {
+ // Only whitelisted attributes are set
+ if ( in_array( $key, self::$coreAttributes ) ) {
+ $this->storeToArray( $path, $key, $val, $this->attributes );
+ }
+ } else {
+ // version === 1
+ if ( !in_array( $key, self::$notAttributes )
+ && !in_array( $key, self::$creditsAttributes )
+ ) {
+ // If it's not blacklisted, it's an attribute
+ $this->storeToArray( $path, $key, $val, $this->attributes );
+ }
+ }
+
+ }
+ }
+
+ /**
+ * @param string $path
+ * @param array $info
+ */
+ protected function extractAttributes( $path, array $info ) {
+ if ( isset( $info['attributes'] ) ) {
+ foreach ( $info['attributes'] as $extName => $value ) {
+ $this->storeToArray( $path, $extName, $value, $this->extAttributes );
}
}
}
}
}
+ // Merge $this->extAttributes into $this->attributes depending on what is loaded
+ foreach ( $this->extAttributes as $extName => $value ) {
+ // Only set the attribute if $extName is loaded (and hence present in credits)
+ if ( isset( $this->credits[$extName] ) ) {
+ foreach ( $value as $attrName => $attrValue ) {
+ $this->storeToArray(
+ '', // Don't provide a path since it's impossible to generate an error here
+ $extName . $attrName,
+ $attrValue,
+ $this->attributes
+ );
+ }
+ unset( $this->extAttributes[$extName] );
+ }
+ }
+
return [
'globals' => $this->globals,
'defines' => $this->defines,
];
}
+ /**
+ * Attributes under manifest_version 2
+ *
+ * @covers ExtensionProcessor::extractAttributes
+ * @covers ExtensionProcessor::getExtractedInfo
+ */
+ public function testExtractAttributes() {
+ $processor = new ExtensionProcessor();
+ // Load FooBar extension
+ $processor->extractInfo( $this->dir, [ 'name' => 'FooBar' ], 2 );
+ $processor->extractInfo(
+ $this->dir,
+ [
+ 'name' => 'Baz',
+ 'attributes' => [
+ // Loaded
+ 'FooBar' => [
+ 'Plugins' => [
+ 'ext.baz.foobar',
+ ],
+ ],
+ // Not loaded
+ 'FizzBuzz' => [
+ 'MorePlugins' => [
+ 'ext.baz.fizzbuzz',
+ ],
+ ],
+ ],
+ ],
+ 2
+ );
+
+ $info = $processor->getExtractedInfo();
+ $this->assertArrayHasKey( 'FooBarPlugins', $info['attributes'] );
+ $this->assertSame( [ 'ext.baz.foobar' ], $info['attributes']['FooBarPlugins'] );
+ $this->assertArrayNotHasKey( 'FizzBuzzMorePlugins', $info['attributes'] );
+ }
+
+ /**
+ * Attributes under manifest_version 1
+ *
+ * @covers ExtensionProcessor::extractInfo
+ */
+ public function testAttributes1() {
+ $processor = new ExtensionProcessor();
+ $processor->extractInfo(
+ $this->dir,
+ [
+ 'name' => 'FooBar',
+ 'FooBarPlugins' => [
+ 'ext.baz.foobar',
+ ],
+ 'FizzBuzzMorePlugins' => [
+ 'ext.baz.fizzbuzz',
+ ],
+ ],
+ 1
+ );
+
+ $info = $processor->getExtractedInfo();
+ $this->assertArrayHasKey( 'FooBarPlugins', $info['attributes'] );
+ $this->assertSame( [ 'ext.baz.foobar' ], $info['attributes']['FooBarPlugins'] );
+ $this->assertArrayHasKey( 'FizzBuzzMorePlugins', $info['attributes'] );
+ $this->assertSame( [ 'ext.baz.fizzbuzz' ], $info['attributes']['FizzBuzzMorePlugins'] );
+ }
+
public function testGlobalSettingsDocumentedInSchema() {
global $IP;
$globalSettings = TestingAccessWrapper::newFromClass(