Merge "registration: Convert "config" into an object with metadata"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Thu, 14 Jul 2016 13:12:27 +0000 (13:12 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Thu, 14 Jul 2016 13:12:27 +0000 (13:12 +0000)
docs/extension.schema.json
docs/extension.schema.v1.json [new file with mode: 0644]
includes/registration/ExtensionProcessor.php
includes/registration/ExtensionRegistry.php
maintenance/updateExtensionJsonSchema.php [new file with mode: 0644]

index 3235c95..14a9731 100644 (file)
                        ],
                        "description": "A function to be called right after MediaWiki processes this file"
                },
+               "config_prefix": {
+                       "type": "string",
+                       "default": "wg",
+                       "description": "Prefix to put in front of configuration settings when exporting them to $GLOBALS"
+               },
                "config": {
                        "type": "object",
                        "description": "Configuration options for this extension",
-                       "properties": {
-                               "_prefix": {
-                                       "type": "string",
-                                       "default": "wg",
-                                       "description": "Prefix to put in front of configuration settings when exporting them to $GLOBALS"
-                               }
-                       },
                        "patternProperties": {
                                "^[a-zA-Z_\u007f-\u00ff][a-zA-Z0-9_\u007f-\u00ff]*$": {
                                        "properties": {
-                                               "_merge_strategy": {
+                                               "value": {
+                                                       "required": true
+                                               },
+                                               "merge_strategy": {
                                                        "type": "string",
                                                        "enum": [
                                                                "array_merge_recursive",
                                                                "array_merge"
                                                        ],
                                                        "default": "array_merge"
+                                               },
+                                               "description": {
+                                                       "type": ["string", "array"],
+                                                       "description": "A description of the config setting, mostly for documentation/developers"
                                                }
                                        }
                                }
diff --git a/docs/extension.schema.v1.json b/docs/extension.schema.v1.json
new file mode 100644 (file)
index 0000000..893facf
--- /dev/null
@@ -0,0 +1,886 @@
+{
+       "$schema": "http://json-schema.org/schema#",
+       "description": "MediaWiki extension.json schema",
+       "type": "object",
+       "properties": {
+               "manifest_version": {
+                       "type": "integer",
+                       "description": "Version of the extension.json schema the extension.json file is in.",
+                       "required": true
+               },
+               "name": {
+                       "type": "string",
+                       "description": "The extension's canonical name.",
+                       "required": true
+               },
+               "namemsg": {
+                       "type": "string",
+                       "description": "i18n message key of the extension's name."
+               },
+               "type": {
+                       "type": "string",
+                       "description": "The extension's type, as an index to $wgExtensionCredits.",
+                       "default": "other"
+               },
+               "author": {
+                       "type": [
+                               "string",
+                               "array"
+                       ],
+                       "description": "Extension's authors.",
+                       "items": {
+                               "type": "string"
+                       }
+               },
+               "version": {
+                       "type": "string",
+                       "description": "The version of this release of the extension."
+               },
+               "url": {
+                       "type": "string",
+                       "description": "URL to the homepage for the extension.",
+                       "format": "uri"
+               },
+               "description": {
+                       "type": "string",
+                       "description": "Raw description of the extension."
+               },
+               "descriptionmsg": {
+                       "type": "string",
+                       "description": "Message key for a i18n message describing the extension."
+               },
+               "license-name": {
+                       "type": "string",
+                       "description": "Short identifier for the license under which the extension is released.",
+                       "enum": [
+                               "AFL-1.1",
+                               "AFL-1.2",
+                               "AFL-2.0",
+                               "AFL-2.1",
+                               "AFL-3.0",
+                               "APL-1.0",
+                               "Aladdin",
+                               "ANTLR-PD",
+                               "Apache-1.0",
+                               "Apache-1.1",
+                               "Apache-2.0",
+                               "APSL-1.0",
+                               "APSL-1.1",
+                               "APSL-1.2",
+                               "APSL-2.0",
+                               "Artistic-1.0",
+                               "Artistic-1.0-cl8",
+                               "Artistic-1.0-Perl",
+                               "Artistic-2.0",
+                               "AAL",
+                               "BitTorrent-1.0",
+                               "BitTorrent-1.1",
+                               "BSL-1.0",
+                               "BSD-2-Clause",
+                               "BSD-2-Clause-FreeBSD",
+                               "BSD-2-Clause-NetBSD",
+                               "BSD-3-Clause",
+                               "BSD-3-Clause-Clear",
+                               "BSD-4-Clause",
+                               "BSD-4-Clause-UC",
+                               "CECILL-1.0",
+                               "CECILL-1.1",
+                               "CECILL-2.0",
+                               "CECILL-B",
+                               "CECILL-C",
+                               "ClArtistic",
+                               "CNRI-Python",
+                               "CNRI-Python-GPL-Compatible",
+                               "CPOL-1.02",
+                               "CDDL-1.0",
+                               "CDDL-1.1",
+                               "CPAL-1.0",
+                               "CPL-1.0",
+                               "CATOSL-1.1",
+                               "Condor-1.1",
+                               "CC-BY-1.0",
+                               "CC-BY-2.0",
+                               "CC-BY-2.5",
+                               "CC-BY-3.0",
+                               "CC-BY-ND-1.0",
+                               "CC-BY-ND-2.0",
+                               "CC-BY-ND-2.5",
+                               "CC-BY-ND-3.0",
+                               "CC-BY-NC-1.0",
+                               "CC-BY-NC-2.0",
+                               "CC-BY-NC-2.5",
+                               "CC-BY-NC-3.0",
+                               "CC-BY-NC-ND-1.0",
+                               "CC-BY-NC-ND-2.0",
+                               "CC-BY-NC-ND-2.5",
+                               "CC-BY-NC-ND-3.0",
+                               "CC-BY-NC-SA-1.0",
+                               "CC-BY-NC-SA-2.0",
+                               "CC-BY-NC-SA-2.5",
+                               "CC-BY-NC-SA-3.0",
+                               "CC-BY-SA-1.0",
+                               "CC-BY-SA-2.0",
+                               "CC-BY-SA-2.5",
+                               "CC-BY-SA-3.0",
+                               "CC0-1.0",
+                               "CUA-OPL-1.0",
+                               "D-FSL-1.0",
+                               "WTFPL",
+                               "EPL-1.0",
+                               "eCos-2.0",
+                               "ECL-1.0",
+                               "ECL-2.0",
+                               "EFL-1.0",
+                               "EFL-2.0",
+                               "Entessa",
+                               "ErlPL-1.1",
+                               "EUDatagrid",
+                               "EUPL-1.0",
+                               "EUPL-1.1",
+                               "Fair",
+                               "Frameworx-1.0",
+                               "FTL",
+                               "AGPL-1.0",
+                               "AGPL-3.0",
+                               "GFDL-1.1",
+                               "GFDL-1.2",
+                               "GFDL-1.3",
+                               "GPL-1.0",
+                               "GPL-1.0+",
+                               "GPL-2.0",
+                               "GPL-2.0+",
+                               "GPL-2.0-with-autoconf-exception",
+                               "GPL-2.0-with-bison-exception",
+                               "GPL-2.0-with-classpath-exception",
+                               "GPL-2.0-with-font-exception",
+                               "GPL-2.0-with-GCC-exception",
+                               "GPL-3.0",
+                               "GPL-3.0+",
+                               "GPL-3.0-with-autoconf-exception",
+                               "GPL-3.0-with-GCC-exception",
+                               "LGPL-2.1",
+                               "LGPL-2.1+",
+                               "LGPL-3.0",
+                               "LGPL-3.0+",
+                               "LGPL-2.0",
+                               "LGPL-2.0+",
+                               "gSOAP-1.3b",
+                               "HPND",
+                               "IBM-pibs",
+                               "IPL-1.0",
+                               "Imlib2",
+                               "IJG",
+                               "Intel",
+                               "IPA",
+                               "ISC",
+                               "JSON",
+                               "LPPL-1.3a",
+                               "LPPL-1.0",
+                               "LPPL-1.1",
+                               "LPPL-1.2",
+                               "LPPL-1.3c",
+                               "Libpng",
+                               "LPL-1.02",
+                               "LPL-1.0",
+                               "MS-PL",
+                               "MS-RL",
+                               "MirOS",
+                               "MIT",
+                               "Motosoto",
+                               "MPL-1.0",
+                               "MPL-1.1",
+                               "MPL-2.0",
+                               "MPL-2.0-no-copyleft-exception",
+                               "Multics",
+                               "NASA-1.3",
+                               "Naumen",
+                               "NBPL-1.0",
+                               "NGPL",
+                               "NOSL",
+                               "NPL-1.0",
+                               "NPL-1.1",
+                               "Nokia",
+                               "NPOSL-3.0",
+                               "NTP",
+                               "OCLC-2.0",
+                               "ODbL-1.0",
+                               "PDDL-1.0",
+                               "OGTSL",
+                               "OLDAP-2.2.2",
+                               "OLDAP-1.1",
+                               "OLDAP-1.2",
+                               "OLDAP-1.3",
+                               "OLDAP-1.4",
+                               "OLDAP-2.0",
+                               "OLDAP-2.0.1",
+                               "OLDAP-2.1",
+                               "OLDAP-2.2",
+                               "OLDAP-2.2.1",
+                               "OLDAP-2.3",
+                               "OLDAP-2.4",
+                               "OLDAP-2.5",
+                               "OLDAP-2.6",
+                               "OLDAP-2.7",
+                               "OPL-1.0",
+                               "OSL-1.0",
+                               "OSL-2.0",
+                               "OSL-2.1",
+                               "OSL-3.0",
+                               "OLDAP-2.8",
+                               "OpenSSL",
+                               "PHP-3.0",
+                               "PHP-3.01",
+                               "PostgreSQL",
+                               "Python-2.0",
+                               "QPL-1.0",
+                               "RPSL-1.0",
+                               "RPL-1.1",
+                               "RPL-1.5",
+                               "RHeCos-1.1",
+                               "RSCPL",
+                               "Ruby",
+                               "SAX-PD",
+                               "SGI-B-1.0",
+                               "SGI-B-1.1",
+                               "SGI-B-2.0",
+                               "OFL-1.0",
+                               "OFL-1.1",
+                               "SimPL-2.0",
+                               "Sleepycat",
+                               "SMLNJ",
+                               "SugarCRM-1.1.3",
+                               "SISSL",
+                               "SISSL-1.2",
+                               "SPL-1.0",
+                               "Watcom-1.0",
+                               "NCSA",
+                               "VSL-1.0",
+                               "W3C",
+                               "WXwindows",
+                               "Xnet",
+                               "X11",
+                               "XFree86-1.1",
+                               "YPL-1.0",
+                               "YPL-1.1",
+                               "Zimbra-1.3",
+                               "Zlib",
+                               "ZPL-1.1",
+                               "ZPL-2.0",
+                               "ZPL-2.1",
+                               "Unlicense"
+                       ]
+               },
+               "requires": {
+                       "type": "object",
+                       "description": "Indicates what versions of MediaWiki core are required. This syntax may be extended in the future, for example to check dependencies between other extensions.",
+                       "properties": {
+                               "MediaWiki": {
+                                       "type": "string",
+                                       "description": "Version constraint string against MediaWiki core."
+                               }
+                       }
+               },
+               "ResourceFileModulePaths": {
+                       "type": "object",
+                       "description": "Default paths to use for all ResourceLoader file modules",
+                       "additionalProperties": false,
+                       "properties": {
+                               "localBasePath": {
+                                       "type": "string",
+                                       "description": "Base path to prepend to all local paths, relative to current directory"
+                               },
+                               "remoteExtPath": {
+                                       "type": "string",
+                                       "description": "Base path to prepend to all remote paths, relative to $wgExtensionAssetsPath"
+                               },
+                               "remoteSkinPath": {
+                                       "type": "string",
+                                       "description": "Base path to prepend to all remote paths, relative to $wgStylePath"
+                               }
+                       }
+               },
+               "ResourceModules": {
+                       "type": "object",
+                       "description": "ResourceLoader modules to register",
+                       "patternProperties": {
+                               "^[a-zA-Z0-9-\\.]+$": {
+                                       "type": "object",
+                                       "anyOf": [
+                                               {
+                                                       "description": "A ResourceLoaderFileModule definition",
+                                                       "additionalProperties": false,
+                                                       "properties": {
+                                                               "localBasePath": {
+                                                                       "type": "string",
+                                                                       "description": "Base path to prepend to all local paths in $options. Defaults to $IP"
+                                                               },
+                                                               "remoteBasePath": {
+                                                                       "type": "string",
+                                                                       "description": "Base path to prepend to all remote paths in $options. Defaults to $wgScriptPath"
+                                                               },
+                                                               "remoteExtPath": {
+                                                                       "type": "string",
+                                                                       "description": "Equivalent of remoteBasePath, but relative to $wgExtensionAssetsPath"
+                                                               },
+                                                               "skipFunction": {
+                                                                       "type": "string",
+                                                                       "description": "Path to a file containing a JavaScript \"skip function\", if desired."
+                                                               },
+                                                               "scripts": {
+                                                                       "type": ["string", "array"],
+                                                                       "description": "Scripts to always include (array of file paths)",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               },
+                                                               "languageScripts": {
+                                                                       "type": "object",
+                                                                       "description": "Scripts to include in specific language contexts (mapping of language code to file path(s))",
+                                                                       "patternProperties": {
+                                                                               "^[a-zA-Z0-9-]{2,}$": {
+                                                                                       "type": [
+                                                                                               "string",
+                                                                                               "array"
+                                                                                       ],
+                                                                                       "items": {
+                                                                                               "type": "string"
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               },
+                                                               "skinScripts": {
+                                                                       "type": "object",
+                                                                       "description": "Scripts to include in specific skin contexts (mapping of skin name to script(s)",
+                                                                       "patternProperties": {
+                                                                               ".+": {
+                                                                                       "type": [
+                                                                                               "string",
+                                                                                               "array"
+                                                                                       ],
+                                                                                       "items": {
+                                                                                               "type": "string"
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               },
+                                                               "debugScripts": {
+                                                                       "type": ["string", "array"],
+                                                                       "description": "Scripts to include in debug contexts",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               },
+                                                               "loaderScripts": {
+                                                                       "type": ["string", "array"],
+                                                                       "description": "Scripts to include in the startup module",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               },
+                                                               "dependencies": {
+                                                                       "type": ["string", "array"],
+                                                                       "description": "Modules which must be loaded before this module",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               },
+                                                               "styles": {
+                                                                       "type": ["string", "array", "object"],
+                                                                       "description": "Styles to always load",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               },
+                                                               "skinStyles": {
+                                                                       "type": "object",
+                                                                       "description": "Styles to include in specific skin contexts (mapping of skin name to style(s))",
+                                                                       "patternProperties": {
+                                                                               ".+": {
+                                                                                       "type": [
+                                                                                               "string",
+                                                                                               "array"
+                                                                                       ],
+                                                                                       "items": {
+                                                                                               "type": "string"
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               },
+                                                               "messages": {
+                                                                       "type": ["string", "array"],
+                                                                       "description": "Messages to always load",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               },
+                                                               "group": {
+                                                                       "type": "string",
+                                                                       "description": "Group which this module should be loaded together with"
+                                                               },
+                                                               "position": {
+                                                                       "type": "string",
+                                                                       "description": "Position on the page to load this module at",
+                                                                       "enum": [
+                                                                               "bottom",
+                                                                               "top"
+                                                                       ]
+                                                               },
+                                                               "templates": {
+                                                                       "type": ["object", "array"],
+                                                                       "description": "Templates to be loaded for client-side usage"
+                                                               },
+                                                               "targets": {
+                                                                       "type": ["string", "array"],
+                                                                       "description": "ResourceLoader target the module can run on",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               }
+                                                       }
+                                               },
+                                               {
+                                                       "description": "A ResourceLoaderWikiModule definition",
+                                                       "additionalProperties": false,
+                                                       "properties": {
+                                                               "class": {
+                                                                       "enum": ["ResourceLoaderWikiModule"]
+                                                               },
+                                                               "group": {
+                                                                       "type": "string",
+                                                                       "description": "Group which this module should be loaded together with"
+                                                               },
+                                                               "position": {
+                                                                       "type": "string",
+                                                                       "description": "Position on the page to load this module at",
+                                                                       "enum": [
+                                                                               "bottom",
+                                                                               "top"
+                                                                       ]
+                                                               },
+                                                               "targets": {
+                                                                       "type": ["string", "array"],
+                                                                       "description": "ResourceLoader target the module can run on",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               },
+                                                               "scripts": {
+                                                                       "type": "array",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               },
+                                                               "styles": {
+                                                                       "type": "array",
+                                                                       "items": {
+                                                                               "type": "string"
+                                                                       }
+                                                               }
+                                                       }
+                                               },
+                                               {
+                                                       "description": "A ResourceLoaderImageModule definition",
+                                                       "additionalProperties": false,
+                                                       "properties": {
+                                                               "class": {
+                                                                       "enum": ["ResourceLoaderImageModule"]
+                                                               },
+                                                               "data": {
+                                                                       "type": "string"
+                                                               },
+                                                               "prefix": {
+                                                                       "type": "string"
+                                                               },
+                                                               "selector": {
+                                                                       "type": "string"
+                                                               },
+                                                               "selectorWithoutVariant": {
+                                                                       "type": "string"
+                                                               },
+                                                               "selectorWithVariant": {
+                                                                       "type": "string"
+                                                               },
+                                                               "variants": {
+                                                                       "type": "object"
+                                                               },
+                                                               "images": {
+                                                                       "type": "object"
+                                                               },
+                                                               "position": {
+                                                                       "enum": [
+                                                                               "top",
+                                                                               "bottom"
+                                                                       ]
+                                                               }
+                                                       }
+                                               },
+                                               {
+                                                       "description": "An arbitrary ResourceLoaderModule definition",
+                                                       "properties": {
+                                                               "class": {
+                                                                       "type": "string",
+                                                                       "pattern": "^((?!ResourceLoader(File|Image)Module).)*$"
+                                                               }
+                                                       },
+                                                       "required": ["class"]
+                                               }
+                                       ]
+                               }
+                       }
+               },
+               "ResourceModuleSkinStyles": {
+                       "type": "object",
+                       "description": "ResourceLoader modules for custom skin styles"
+               },
+               "ResourceLoaderSources": {
+                       "type": "object",
+                       "description": "ResourceLoader sources to register"
+               },
+               "ResourceLoaderLESSVars": {
+                       "type": "object",
+                       "description": "ResourceLoader LESS variables"
+               },
+               "ConfigRegistry": {
+                       "type": "object",
+                       "description": "Registry of factory functions to create Config objects"
+               },
+               "SessionProviders": {
+                       "type": "object",
+                       "description": "Session providers"
+               },
+               "AuthManagerAutoConfig": {
+                       "type": "object",
+                       "description": "AuthManager auto-configuration",
+                       "additionalProperties": false,
+                       "properties": {
+                               "preauth": {
+                                       "type": "object",
+                                       "description": "Pre-authentication providers"
+                               },
+                               "primaryauth": {
+                                       "type": "object",
+                                       "description": "Primary authentication providers"
+                               },
+                               "secondaryauth": {
+                                       "type": "object",
+                                       "description": "Secondary authentication providers"
+                               }
+                       }
+               },
+               "CentralIdLookupProviders": {
+                       "type": "object",
+                       "description": "Central ID lookup providers"
+               },
+               "namespaces": {
+                       "type": "array",
+                       "description": "Method to add extra namespaces",
+                       "items": {
+                               "type": "object",
+                               "properties": {
+                                       "id": {
+                                               "type": "integer"
+                                       },
+                                       "constant": {
+                                               "type": "string"
+                                       },
+                                       "name": {
+                                               "type": "string"
+                                       },
+                                       "gender": {
+                                               "type": "object",
+                                               "properties": {
+                                                       "male": {
+                                                               "type": "string"
+                                                       },
+                                                       "female": {
+                                                               "type": "string"
+                                                       }
+                                               }
+                                       },
+                                       "subpages": {
+                                               "type": "boolean",
+                                               "default": false
+                                       },
+                                       "content": {
+                                               "type": "boolean",
+                                               "default": false
+                                       },
+                                       "defaultcontentmodel": {
+                                               "type": "string"
+                                       },
+                                       "protection": {
+                                               "type": ["string", "array"],
+                                               "description": "Userright(s) required to edit in this namespace"
+                                       },
+                                       "capitallinkoverride": {
+                                               "type": "boolean",
+                                               "description": "Set $wgCapitalLinks on a per-namespace basis"
+                                       }
+                               },
+                               "required": ["id", "constant", "name"]
+                       }
+               },
+               "TrackingCategories": {
+                       "type": "array",
+                       "description": "Tracking category message keys",
+                       "items": {
+                               "type": "string"
+                       }
+               },
+               "DefaultUserOptions": {
+                       "type": "object",
+                       "description": "Default values of user options"
+               },
+               "HiddenPrefs": {
+                       "type": "array",
+                       "description": "Preferences users cannot set",
+                       "items": {
+                               "type": "string"
+                       }
+               },
+               "GroupPermissions": {
+                       "type": "object",
+                       "description": "Default permissions to give to user groups",
+                       "patternProperties": {
+                               "^[a-z]+$": {
+                                       "type": "object",
+                                       "patternProperties": {
+                                               "^[a-z]+$": {
+                                                       "type": "boolean"
+                                               }
+                                       }
+                               }
+                       }
+               },
+               "RevokePermissions": {
+                       "type": "object",
+                       "description": "Default permissions to revoke from user groups",
+                       "patternProperties": {
+                               "^[a-z]+$": {
+                                       "type": "object",
+                                       "patternProperties": {
+                                               "^[a-z]+$": {
+                                                       "type": "boolean"
+                                               }
+                                       }
+                               }
+                       }
+               },
+               "GrantPermissions": {
+                       "type": "object",
+                       "description": "Map of permissions granted to authorized consumers to their bundles, called 'grants'",
+                       "patternProperties": {
+                               "^[a-z]+$": {
+                                       "type": "object",
+                                       "patternProperties": {
+                                               "^[a-z]+$": {
+                                                       "type": "boolean"
+                                               }
+                                       }
+                               }
+                       }
+               },
+               "GrantPermissionGroups": {
+                       "type": "object",
+                       "description": "Map of grants to their UI grouping",
+                       "patternProperties": {
+                               "^[a-z]+$": {
+                                       "type": "string"
+                               }
+                       }
+               },
+               "ImplicitGroups": {
+                       "type": "array",
+                       "description": "Implicit groups"
+               },
+               "GroupsAddToSelf": {
+                       "type": "object",
+                       "description": "Groups a user can add to themselves"
+               },
+               "GroupsRemoveFromSelf": {
+                       "type": "object",
+                       "description": "Groups a user can remove from themselves"
+               },
+               "AddGroups": {
+                       "type": "object",
+                       "description": "Groups a user can add to users"
+               },
+               "RemoveGroups": {
+                       "type": "object",
+                       "description": "Groups a user can remove from users"
+               },
+               "AvailableRights": {
+                       "type": "array",
+                       "description": "User rights added by the extension",
+                       "items": {
+                               "type": "string"
+                       }
+               },
+               "ContentHandlers": {
+                       "type": "object",
+                       "description": "Mapping of model ID to class name",
+                       "patternProperties": {
+                               "^[A-Za-z]+$": {
+                                       "type": "string"
+                               }
+                       }
+               },
+               "RateLimits": {
+                       "type": "object",
+                       "description": "Rate limits"
+               },
+               "RecentChangesFlags": {
+                       "type": "object",
+                       "description": "Flags (letter symbols) shown on RecentChanges pages"
+               },
+               "MediaHandlers": {
+                       "type": "object",
+                       "description": "Plugins for media file type handling. Each entry in the array maps a MIME type to a PHP class name."
+               },
+               "ExtensionFunctions": {
+                       "type": [
+                               "array",
+                               "string"
+                       ],
+                       "description": "Function to call after setup has finished",
+                       "items": {
+                               "type": "string"
+                       }
+               },
+               "ExtensionMessagesFiles": {
+                       "type": "object",
+                       "description": "File paths containing PHP internationalization data"
+               },
+               "MessagesDirs": {
+                       "type": "object",
+                       "description": "Directory paths containing JSON internationalization data"
+               },
+               "ExtensionEntryPointListFiles": {
+                       "type": "object"
+               },
+               "SpecialPages": {
+                       "type": "object",
+                       "description": "SpecialPages implemented in this extension (mapping of page name to class name)"
+               },
+               "AutoloadClasses": {
+                       "type": "object"
+               },
+               "Hooks": {
+                       "type": [ "string", "object" ],
+                       "description": "Hooks this extension uses (mapping of hook name to callback)"
+               },
+               "JobClasses": {
+                       "type": "object",
+                       "description": "Job types this extension implements (mapping of job type to class name)"
+               },
+               "LogTypes": {
+                       "type": "array",
+                       "description": "List of new log types this extension uses"
+               },
+               "LogRestrictions": {
+                       "type": "object"
+               },
+               "FilterLogTypes": {
+                       "type": "object"
+               },
+               "ActionFilteredLogs": {
+                       "type": "object",
+                       "description": "List of log types which can be filtered by log actions",
+                       "patternProperties": {
+                               "^[a-z-]+$": {
+                                       "type": "object",
+                                       "patternProperties": {
+                                               "^[a-z-]+$": {
+                                                       "type": "array",
+                                                       "items": {
+                                                               "type": "string"
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               },
+               "LogNames": {
+                       "type": "object"
+               },
+               "LogHeaders": {
+                       "type": "object"
+               },
+               "LogActions": {
+                       "type": "object"
+               },
+               "LogActionsHandlers": {
+                       "type": "object"
+               },
+               "Actions": {
+                       "type": "object"
+               },
+               "APIModules": {
+                       "type": "object"
+               },
+               "APIFormatModules": {
+                       "type": "object"
+               },
+               "APIMetaModules": {
+                       "type": "object"
+               },
+               "APIPropModules": {
+                       "type": "object"
+               },
+               "APIListModules": {
+                       "type": "object"
+               },
+               "ValidSkinNames": {
+                       "type": "object"
+               },
+               "FeedClasses": {
+                       "type": "object",
+                       "description": "Available feeds objects"
+               },
+               "SkinOOUIThemes": {
+                       "type": "object"
+               },
+               "callback": {
+                       "type": [
+                               "array",
+                               "string"
+                       ],
+                       "description": "A function to be called right after MediaWiki processes this file"
+               },
+               "config": {
+                       "type": "object",
+                       "description": "Configuration options for this extension",
+                       "properties": {
+                               "_prefix": {
+                                       "type": "string",
+                                       "default": "wg",
+                                       "description": "Prefix to put in front of configuration settings when exporting them to $GLOBALS"
+                               }
+                       },
+                       "patternProperties": {
+                               "^[a-zA-Z_\u007f-\u00ff][a-zA-Z0-9_\u007f-\u00ff]*$": {
+                                       "properties": {
+                                               "_merge_strategy": {
+                                                       "type": "string",
+                                                       "enum": [
+                                                               "array_merge_recursive",
+                                                               "array_plus_2d",
+                                                               "array_plus",
+                                                               "array_merge"
+                                                       ],
+                                                       "default": "array_merge"
+                                               }
+                                       }
+                               }
+                       }
+               },
+               "ParserTestFiles": {
+                       "type": "array",
+                       "description": "Parser test suite files to be run by parserTests.php when no specific filename is passed to it"
+               },
+               "load_composer_autoloader": {
+                       "type": "boolean",
+                       "description": "Load the composer autoloader for this extension, if one is present"
+               }
+       }
+}
index ea17990..12218ce 100644 (file)
@@ -109,6 +109,7 @@ class ExtensionProcessor implements Processor {
                'MessagesDirs',
                'type',
                'config',
+               'config_prefix',
                'ParserTestFiles',
                'AutoloadClasses',
                'manifest_version',
@@ -161,7 +162,12 @@ class ExtensionProcessor implements Processor {
         * @return array
         */
        public function extractInfo( $path, array $info, $version ) {
-               $this->extractConfig( $info );
+               if ( $version === 2 ) {
+                       $this->extractConfig2( $info );
+               } else {
+                       // $version === 1
+                       $this->extractConfig1( $info );
+               }
                $this->extractHooks( $info );
                $dir = dirname( $path );
                $this->extractExtensionMessagesFiles( $dir, $info );
@@ -349,12 +355,12 @@ class ExtensionProcessor implements Processor {
        }
 
        /**
-        * Set configuration settings
+        * Set configuration settings for manifest_version == 1
         * @todo In the future, this should be done via Config interfaces
         *
         * @param array $info
         */
-       protected function extractConfig( array $info ) {
+       protected function extractConfig1( array $info ) {
                if ( isset( $info['config'] ) ) {
                        if ( isset( $info['config']['_prefix'] ) ) {
                                $prefix = $info['config']['_prefix'];
@@ -370,6 +376,29 @@ class ExtensionProcessor implements Processor {
                }
        }
 
+       /**
+        * Set configuration settings for manifest_version == 2
+        * @todo In the future, this should be done via Config interfaces
+        *
+        * @param array $info
+        */
+       protected function extractConfig2( array $info ) {
+               if ( isset( $info['config_prefix'] ) ) {
+                       $prefix = $info['config_prefix'];
+               } else {
+                       $prefix = 'wg';
+               }
+               if ( isset( $info['config'] ) ) {
+                       foreach ( $info['config'] as $key => $data ) {
+                               $value = $data['value'];
+                               if ( isset( $value['merge_strategy'] ) ) {
+                                       $value[ExtensionRegistry::MERGE_STRATEGY] = $value['merge_strategy'];
+                               }
+                               $this->globals["$prefix$key"] = $value;
+                       }
+               }
+       }
+
        protected function extractParserTestFiles( $dir, array $info ) {
                if ( isset( $info['ParserTestFiles'] ) ) {
                        foreach ( $info['ParserTestFiles'] as $path ) {
index dc53ca4..3bec457 100644 (file)
@@ -19,7 +19,7 @@ class ExtensionRegistry {
        /**
         * Version of the highest supported manifest version
         */
-       const MANIFEST_VERSION = 1;
+       const MANIFEST_VERSION = 2;
 
        /**
         * Version of the oldest supported manifest version
diff --git a/maintenance/updateExtensionJsonSchema.php b/maintenance/updateExtensionJsonSchema.php
new file mode 100644 (file)
index 0000000..427769f
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+
+require_once __DIR__ . '/Maintenance.php';
+
+class UpdateExtensionJsonSchema extends Maintenance {
+
+       public function __construct() {
+               parent::__construct();
+               $this->addDescription( 'Updates extension.json files to the latest manifest_version' );
+               $this->addArg( 'path', 'Location to the extension.json or skin.json you wish to convert',
+                       /* $required = */ true );
+       }
+
+       public function execute() {
+               $filename = $this->getArg( 0 );
+               if ( !is_readable( $filename ) ) {
+                       $this->error( "Error: Unable to read $filename", 1 );
+               }
+
+               $json = FormatJson::decode( file_get_contents( $filename ), true );
+               if ( $json === null ) {
+                       $this->error( "Error: Invalid JSON", 1 );
+               }
+
+               if ( !isset( $json['manifest_version'] ) ) {
+                       $json['manifest_version'] = 1;
+               }
+
+               if ( $json['manifest_version'] == ExtensionRegistry::MANIFEST_VERSION ) {
+                       $this->output( "Already at the latest version: {$json['manifest_version']}\n" );
+                       return;
+               }
+
+               while ( $json['manifest_version'] !== ExtensionRegistry::MANIFEST_VERSION ) {
+                       $json['manifest_version'] += 1;
+                       $func = "updateTo{$json['manifest_version']}";
+                       $this->$func( $json );
+               }
+
+               file_put_contents( $filename, FormatJson::encode( $json, "\t", FormatJson::ALL_OK ) . "\n" );
+               $this->output( "Updated to {$json['manifest_version']}...\n" );
+       }
+
+       protected function updateTo2( &$json ) {
+               if ( isset( $json['config'] ) ) {
+                       $config = $json['config'];
+                       $json['config'] = [];
+                       if ( isset( $config['_prefix'] ) ) {
+                               $json = wfArrayInsertAfter( $json, [
+                                       'config_prefix' => $config['_prefix']
+                               ], 'config' );
+                               unset( $config['_prefix'] );
+                       }
+
+                       foreach ( $config as $name => $value ) {
+                               if ( $name[0] !== '@' ) {
+                                       $json['config'][$name] = [ 'value' => $value ];
+                                       if ( isset( $value[ExtensionRegistry::MERGE_STRATEGY] ) ) {
+                                               $json['config'][$name]['merge_strategy'] = $value[ExtensionRegistry::MERGE_STRATEGY];
+                                               unset( $value[ExtensionRegistry::MERGE_STRATEGY] );
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+$maintClass = 'UpdateExtensionJsonSchema';
+require_once RUN_MAINTENANCE_IF_MAIN;