This is a bit of clean-up for a couple reasons.
### Finding files
Make it easier to find files in the repository based on their module name. This applies to features like "Find File" in text editors (eg. {key command P} / {key ctrl P} in Atom and Sublime Text), as well as to repository viewers (eg. {key T} on GitHub).
### Contributing
Even in our current core stack (with good ol' ResourceLoader concatenating files), there's a fair amount of complexity that can overwhelm new contributors. And even for experienced contributors, we don't all work with all files all the time. So being able to easily tell which (other) files load as part of a given module is quite useful.
I would expect this to reduce overall confusion, but also reduce risk of forgetting to declare dependencies between related code paths (given files in the same directory but part of separate modules). It would also make it easier to create something in less feedback cycles of "try this", "get an error" (eg. for cases where we do detect something is broken, missing dependencies tends to not be one of them, though).
### Past
Some past work has been put in towards this, but so far only in certain sub-trees. Never across the board.
Some past conversions in `resources/src/`
* <https://gerrit.wikimedia.org/r/161765> (2014)
* {0bfdd927beb0861868c1bdb5c67cb17344b78cd0} (2015)
* {648667ac9f0848dfbb75b513d79c73d7a5e5b7b1}
Also, we've been doing fairly well in `resources/lib/` where every module has its own directory now, yay!
### Future
This will also get things in a better shape of the future that awaits us in T133462, where it'll likely become a prerequisite for a module to either be one file, or be its own directory. Even if we don't enforce that, it'd be even more confusing than today if we have files importing each other using `require('./example');` but also have files in the same directory that aren't reachable as part of the module.
## Proposal
The proposal is the following two mandates:
(NOTE) Every file shipped in a ResourceLoader module must be in `resources/` in a (sub) directory named after the module ~~, or as a single file containing the module name in its file name~~.
(NOTE) There must not be files in a module directory that are part of a different module.
##### Currently fine as-is
* "jquery.chosen" is at `resources/lib/jquery.chosen/`
* "moment" is at `resources/lib/moment/`
* "qunit" is at `resources/lib/qunitjs/`
* "jquery.tipsy" is at `resources/src/jquery.tipsy/`
* "mediawiki.toolbar" is at `resources/src/mediawiki.toolbar/`
* "mediawiki.widgets.datetime" is at `resources/src/mediawiki.widgets.datetime/`
* "startup" is at `resources/src/startup.js`
##### Examples to change
* `resources/lib/jquery/`
This directory contains things loosely related to "jQuery" in some way or another, registered as multiple different modules. The ones that are single-file modules could be moved up to be in `lib/` directory. The others should get their own directory. Leaving `jquery/` to only contain `jquery.js` and `jquery.migrate.js` – the contents of the module currently registered as "jquery".
* `resources/src/mediawiki/`
** `api.js`
** `api/`
*** `category.js`
** `htmlform/`
** `page/`
*** `ready.js`
*** `startup.js`
*** `watch.js`
This the "api" and "page" are remnants of my attempt to make the directory structure reflect the run-time class hierarchy (instead of the module/bundle structure). This is also predates things like `module.exports`.
The idea was to roughly be able to translate a public identifier in JavaScript (e.g. `mw.Api.prototype.isCategory` or `mw.page.watch.updateLinks()`) to a path on the file system. I didn't think about this well, and I regret doing it. It didn't work because the way we namespace our modules is by module name, not my namespace hierarchy. Even in the above examples we can see a few clear flaws and limitations:
* `mediawiki/api/category.js` does not translate to `mw.api.category = {}`. Rather it translates to the module name `mediawiki.api.category`. The actual identifier is `mw.Api` and several methods such as `mw.Api#isCategory`.
* `mediawiki/page/watch.js` - This was at some point the first and only module to justify my (bad) idea. We did have `mw.page.watch`. It existed. But it doesn't exist anymore. And the other files in the directory mostly don't have any public identifiers. They're just run-time logic with their file reflecting the module names: `mediawiki.page.startup`, `mediawiki.page.ready`, etc.
Given that all of these are single-file modules, there are two ways we could solve them:
1. Put them directly in `resources/src/` as `mediawiki.api.category.js` and `mediawiki.page.ready.js`.
2. Give some of the related modules their own shared directory, e.g. `resources/src/mediawiki.api/` and `resources/src/mediawiki.page/`, with the single-file modules living inside of it.
Both of these would satisfy the two proposed mandates.
## Progress
Below listing is based on the structure as it was when we started.
Reference: https://gerrit.wikimedia.org/g/mediawiki/core/+/42956b99b558294e5aa8c6c0e2a8f18513478022/resources/
Items are checked off when the file or directory has been checked recursively to match the above two principles (and renamed or split as needed).
resources/lib/
* [x] CLDRPluralRuleParser/
* [x] html5shiv/
* [x] jquery/
* [x] jquery.chosen/
* [x] jquery.client/
* [x] jquery.i18n/
* [x] jquery.ui/ – T219604
* [x] moment/
* [x] mustache/
* [x] oojs-router/
* [ ] oojs-ui/
* [x] oojs/
* [x] qunitjs/
* [x] sinonjs/
resources/src/
* [x] jquery.tipsy/
* [ ] jquery/
** [x] jquery.color
** [ ] jquery.confirmable
** ~~jquery.hidpi~~ (removed)
** [x] jquery.lengthLength
** [ ] jquery.makeCollapsible
** [x] jquery.farbtastic
** [x] jquery.tablesorter
** [x] jquery.spinner
** [ ] (misc)
* [ ] mediawiki.action/
* [x] mediawiki.hidpi-skip.js
* [ ] mediawiki.language/
* [ ] mediawiki.legacy/
* ~~mediawiki.less/~~ //(less importdir: not a module)//
* [x] mediawiki.libs.jpegmeta/
* [x] mediawiki.libs.pluralruleparser/
* [x] mediawiki.messagePoster/
* [ ] mediawiki.rcfilters/
* [x] mediawiki.router/
* [ ] mediawiki.skinning/
* [x] mediawiki.special/
* [x] mediawiki.toolbar/
* [ ] mediawiki.ui/
* [x] mediawiki.widgets.datetime/
* [x] mediawiki.widgets.visibleLengthLimit/
* [ ] mediawiki.widgets/
* [x] mediawiki/
** [x] mediawiki/api/
** [x] mediawiki/htmlform/
** [x] mediawiki/page/
* [x] moment/
* [ ] oojs-global.js
* [ ] oojs-ui-local.js
* [x] startup.js
## Follow-up
>>! **<https://gerrit.wikimedia.org/r/432151>** wrote:
> - Consider merging 'mediawiki.ForeignApi' and 'mediawiki.ForeignApi.core.'.
> - Consider merging 'mediawiki.page.ready' and 'mediawiki.page.startup'.
See T192623 further about these.
>>! **<https://gerrit.wikimedia.org/r/c/432152>** wrote:
> ```name=Element.js,lang=js
> // FIXME: mw.htmlform.Checker also sets this to empty object
> mw.htmlform = {};
> ```
> ```name=Checker.js,lang=js
> // FIXME: mw.htmlform.Element also sets this to empty object
> mw.htmlform = {};
> ```