{"id":15172929,"url":"https://github.com/eccenux/wikiploy","last_synced_at":"2025-10-26T04:31:08.588Z","repository":{"id":176574173,"uuid":"655402133","full_name":"Eccenux/Wikiploy","owner":"Eccenux","description":"User scripts and gadgets deployment (JS/CSS) for MediaWiki (Wikipedia).","archived":false,"fork":false,"pushed_at":"2024-06-11T18:06:29.000Z","size":338,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-11T02:03:37.106Z","etag":null,"topics":["deployment","gadgets","mediawiki","rollout","wikipedia"],"latest_commit_sha":null,"homepage":"https://en.wikipedia.org/wiki/Wikipedia:Wikiploy","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Eccenux.png","metadata":{"files":{"readme":"README.building your project.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-18T19:30:21.000Z","updated_at":"2024-06-11T18:06:32.000Z","dependencies_parsed_at":"2024-03-28T13:50:42.212Z","dependency_job_id":"4ed8f966-d835-49cb-97ba-04b2f3babcff","html_url":"https://github.com/Eccenux/Wikiploy","commit_stats":null,"previous_names":["eccenux/wikiploy"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eccenux%2FWikiploy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eccenux%2FWikiploy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eccenux%2FWikiploy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Eccenux%2FWikiploy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Eccenux","download_url":"https://codeload.github.com/Eccenux/Wikiploy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219864035,"owners_count":16555943,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deployment","gadgets","mediawiki","rollout","wikipedia"],"created_at":"2024-09-27T10:24:00.705Z","updated_at":"2025-10-26T04:31:03.192Z","avatar_url":"https://github.com/Eccenux.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Building your project\n\nThere are various ways to build scripts. You can use [browserify](https://browserify.org/), webpack, TypeScript compiler, etc., or even choose not to build at all. Wikiploy doesn't force the use of any specific tool (you are free to choose whatever you are comfortable with). However, not all solutions are equally well-suited for the wiki world, and choosing the right solution takes time.\n\nLet me save you some time. Below is a recommended project setup based on some of my real scripts and years of experience building gadgets. If you're interested, you can take a look at a real-world script: [wikibot-jsbot-core](https://github.com/Eccenux/wikibot-jsbot-core) (it's a bit experimental, but you might find some interesting constructs there). For a more stable example, you might want to explore the template repository for Wikiploy: [wikiploy-rollout-example](https://github.com/Eccenux/wikiploy-rollout-example).\n\n## Recommended setup for building scripts\n\nExample `.gitignore` for your project:\n```\n/node_modules\n*.lnk\n*.priv.*\nbot.config.*\n```\n\nYour `package.json` (crucial part being `scripts`):\n```js\n{\n\t\"name\": \"wiki-gadget-yourgadgetname\",\n\t\"type\": \"commonjs\",\n\t\"scripts\": {\n\t\t\"test\": \"mocha\",\n\t\t\"build-less\": \"lessc src/less/main.less dist/yourGadgetName.css\",\n\t\t\"build-js\": \"browserify src/main.js -o dist/yourGadgetName.js\",\n\t\t\"build\": \"npm run build-less \u0026\u0026 npm run build-js \u0026\u0026 node -e \\\"console.log('Build done');\\\" \",\n\t\t\"deploy-dev\": \"node wikiploy-dev.mjs\",\n\t\t\"deploy\": \"node wikiploy.mjs\",\n\t\t\"rollout-dev\": \"npm run build \u0026\u0026 npm run deploy-dev\",\n\t\t\"rollout\": \"npm run build \u0026\u0026 npm run deploy\"\n\t},\n\t\"devDependencies\": {\n\t\t\"browserify\": \"17.x\",\n\t\t\"chai\": \"4.x\",\n\t\t\"eslint\": \"8.x\",\n\t\t\"less\": \"4.x\",\n\t\t\"mocha\": \"10.x\",\n\t\t\"wikiploy\": \"2.x\"\n\t},\n}\n```\n\nYour `src/main.js` could look something like this:\n```js\nvar { MyGadget } = require(\"./MyGadget\");\n\n// instance\nvar gadget = new MyGadget();\n\n// init elements\n$(function(){\n\tgadget.init();\n})\n```\n\nYour `src/MyGadget.js` could look something like this:\n```js\nfunction MyGadget() {\n\t/** Initialize things when DOM is ready. */\n\tthis.init = function() {\n\t\tconsole.log(\"init done\");\n\t}\n}\n\nmodule.exports = { MyGadget };\n```\n\nAlso should also create a starting point for your CSS `src/less/main.less`:\n```css\n@primary-color: darken(#3498db, 10%);\n@secondary-color: darken(#e74c3c, 20%);\n\n.yourGadgetName {\n    background-color: @primary-color;\n    color: white;\n\n\t.header {\n\t\tbackground-color: @secondary-color;\n\t\ttext-align: center;\n\t}\n}\n```\n\nRemember to install tools after changing `package.json`:\n```bash\nnpm i\n```\n\nAnd now you should already be able to build the script:\n```bash\nnpm run build\n```\n\nNow we just need to setup things so that we don't have to build and deploy things manually.\n\n## Visual Studio Code setup\n\n[VSC](https://code.visualstudio.com/) is a free editor that has evolved over the years to become almost like an IDE. It is great for developing JS scripts.\n\nAdd `.vscode/extensions.json` to help install a set of **extensions**:\n```js\n{\n\t\"recommendations\": [\n\t\t\"gsppvo.vscode-commandbar\",\n\t\t\"hbenl.vscode-test-explorer\",\n\t\t\"hbenl.vscode-mocha-test-adapter\"\n\t]\n}\n```\n\nVSC **settings** `.vscode/settings.json`:\n```js\n{\n    \"editor.detectIndentation\": false,\n    \"editor.useTabStops\": true,\n    \"editor.insertSpaces\": false,\n\t\"search.exclude\": {\n\t\t\"package-lock.json\": true,\n\t\t\"**/dist/\": true,\n\t},\n}\n```\n\nUsing tabs vs spaces is obviously your preference. People tend to have conflicting opinions on that. The simple truth is that a tab is one byte, and 4 spaces are 4 bytes, but use whatever works for your project. Just remember to enforce it at the project level so that the style is consistent.\n\nVSC **tasks** `.vscode/tasks.json`:\n```js\n{\n\t\"version\": \"2.0.0\",\n\t\"tasks\": [\n\t\t{\n\t\t\t\"type\": \"npm\",\n\t\t\t\"script\": \"test\",\n\t\t\t\"group\": \"test\",\n\t\t\t\"problemMatcher\": [],\n\t\t\t\"label\": \"Run tests\",\n\t\t\t\"detail\": \"mocha\"\n\t\t},\n\t\t{\n\t\t\t\"type\": \"npm\",\n\t\t\t\"script\": \"deploy-dev\",\n\t\t\t\"group\": \"none\",\n\t\t\t\"problemMatcher\": [],\n\t\t\t\"label\": \"Run dev deploy\",\n\t\t\t\"detail\": \"Run deploy script (wikiploy)\"\n\t\t},\n\t\t{\n\t\t\t\"type\": \"npm\",\n\t\t\t\"script\": \"deploy\",\n\t\t\t\"group\": \"none\",\n\t\t\t\"problemMatcher\": [],\n\t\t\t\"label\": \"Run deploy\",\n\t\t\t\"detail\": \"Run deploy script (wikiploy)\"\n\t\t},\n\t\t{\n\t\t\t\"type\": \"npm\",\n\t\t\t\"script\": \"rollout-dev\",\n\t\t\t\"group\": \"none\",\n\t\t\t\"problemMatcher\": [],\n\t\t\t\"label\": \"Run dev rollout\",\n\t\t\t\"detail\": \"Run rollout script (browserify \u0026 wikiploy)\"\n\t\t},\n\t\t{\n\t\t\t\"type\": \"npm\",\n\t\t\t\"script\": \"rollout\",\n\t\t\t\"group\": \"none\",\n\t\t\t\"problemMatcher\": [],\n\t\t\t\"label\": \"Run rollout\",\n\t\t\t\"detail\": \"Run rollout script (browserify \u0026 wikiploy)\"\n\t\t},\n\t\t{\n\t\t\t\"type\": \"npm\",\n\t\t\t\"script\": \"install\",\n\t\t\t\"group\": \"none\",\n\t\t\t\"problemMatcher\": [],\n\t\t\t\"label\": \"npm install\",\n\t\t\t\"detail\": \"install dependencies from package\"\n\t\t}\n\t]\n}\n```\n\nWhen you use tasks, VSC runs an interactive terminal. This makes some scripts work better:\n- Any scripts that use colors in the terminal will work with tasks.\n- An interactive shell is required for the `userPrompt` helper (see *Deploy script*).\n- Text progress (like in npm install) looks much better with tasks.\n\nVCS **commandbar** `.vscode/commandbar.json`:\n```js\n// Remember to change VSC settings (UI): in `files.associations` add `commandbar.json: jsonc`\n{\n\t\"skipTerminateQuickPick\": true,\n\t\"skipSwitchToOutput\": false,\n\t\"skipErrorMessage\": true,\n\t\"commands\": [\n\t\t// \"commandType\": \"script\" runs npm script directly\n\t\t{\n\t\t\t\"text\": \"test\",\n\t\t\t\"tooltip\": \"Run mocha tests.\",\n\t\t\t\"color\": \"lightgreen\",\n\t\t\t\"commandType\": \"script\",\n\t\t\t\"command\": \"test\",\n\t\t\t\"priority\": 0\n\t\t},\n\t\t\n\t\t{\n\t\t\t\"text\": \"build\",\n\t\t\t\"tooltip\": \"Run the browserify build.\",\n\t\t\t\"color\": \"lightgreen\",\n\t\t\t\"commandType\": \"script\",\n\t\t\t\"command\": \"build\",\n\t\t\t\"priority\": 0\n\t\t},\n\t\t\n\t\t// running deployment as a task (so that prompts work)\n\t\t// note that \"Run dev deploy\" is a label from tasks.json \n\t\t{\n\t\t\t\"text\": \"wikiploy-dev\",\n\t\t\t\"tooltip\": \"Deploy pre-built script.\",\n\t\t\t\"color\": \"lightgreen\",\n\t\t\t\"commandType\": \"palette\",\n\t\t\t\"command\": \"workbench.action.tasks.runTask|Run dev deploy\",\n\t\t\t\"priority\": 0\n\t\t},\n\n\t\t// this our one-click rollout\n\t\t{\n\t\t\t\"text\": \"build \u0026 deploy-dev\",\n\t\t\t\"tooltip\": \"Build (browserify) and deploy (wikiploy).\",\n\t\t\t\"color\": \"lightgreen\",\n\t\t\t\"commandType\": \"palette\",\n\t\t\t\"command\": \"workbench.action.tasks.runTask|Run dev rollout\",\n\t\t\t\"priority\": 0\n\t\t}\n\t]\n}\n```\n\nNote: You should also change VSC settings (UI) under `files.associations` to add `commandbar.json: jsonc` (JSON with comments). This allows comments in JSON, making it more understandable. Otherwise, VSC will complain about inline comments.\n\nAlso, note: Above, we only added dev tasks to the command bar. This is just for brevity. The same commands can be added for other tasks.\n\n## Deploy script\n\nYour **bot password** configuration `bot.config.mjs`:\n```js\n/**\n\tBot with edit\u0026create rights.\n\t\n\thttps://test.wikipedia.org/wiki/Special:BotPasswords/Wikiploy\n\n\tThe new password to log in with Nux@Wikiploy.\n\tWhere \"Nux\" is a Wikipedia username and \"Wikiploy\" is a bot name choosen in [[Special:BotPasswords]].\n */\nexport const username = 'Nux@Wikiploy';\nexport const password = '0abc...fckgw';\n```\n\nYour **common deployment script** `wikiploy-common.mjs`:\n```js\nimport { DeployConfig, userPrompt } from 'wikiploy';\n\n/**\n * Add config.\n * @param {Array} configs DeployConfig array.\n * @param {String} site Domian of a MW site.\n */\nexport function addConfig(configs, site) {\n\tconfigs.push(new DeployConfig({\n\t\tsrc: 'dist/yourGadgetName.js',\n\t\tdst: '~/yourGadgetName.js',\n\t\tsite,\n\t\tnowiki: true,\n\t}));\n\tconfigs.push(new DeployConfig({\n\t\tsrc: 'dist/yourGadgetName.css',\n\t\tdst: '~/yourGadgetName.css',\n\t\tsite,\n\t}));\n}\n\n/**\n * Read and setup summary.\n * @param {WikiployLite} ployBot \n */\nexport async function setupSummary(ployBot) {\n\tconst summary = await userPrompt('Summary of changes (empty for default summary):');\n\tif (typeof summary === 'string' \u0026\u0026 summary.length) {\n\t\tployBot.summary = () =\u003e {\n\t\t\treturn summary;\n\t\t};\n\t}\n}\n```\nWe use a separate file to define common functions, making changes to both release and dev Wikiploy scripts simpler.\n\nNote that `~` in `dst` properties will be replaced with `User:SomeName`, representing the user space of the currently logged-in user (your user space). For more details about this basic code and `DeployConfig` properties, refer to the [Wikiploy rollout example](https://github.com/Eccenux/wikiploy-rollout-example/).\n\nYour minimal **developer deployment script** `wikiploy-dev.mjs`:\n```js\nimport { WikiployLite } from 'wikiploy';\n\nimport * as botpass from './bot.config.mjs';\nconst ployBot = new WikiployLite(botpass);\n\n// common deploy function(s)\nimport { addConfig, setupSummary } from './wikiploy-common.mjs';\n\n// run asynchronously to be able to wait for results\n(async () =\u003e {\n\t// custom summary from a prompt\n\tawait setupSummary(ployBot);\n\n\t// push out file(s) to wiki\n\tconst configs = [];\n\taddConfig(configs, 'en.wikipedia.org');\n\n\tawait ployBot.deploy(configs);\n\n})().catch(err =\u003e {\n\tconsole.error(err);\n\tprocess.exit(1);\n});\n```\n\nYour **main deployment script** `wikiploy.mjs`:\n```js\nimport { WikiployLite } from 'wikiploy';\n\nimport * as botpass from './bot.config.mjs';\nconst ployBot = new WikiployLite(botpass);\n\n// common deploy function(s)\nimport { addConfig, setupSummary } from './wikiploy-common.mjs';\n\n// run asynchronously to be able to wait for results\n(async () =\u003e {\n\t// custom summary from a prompt\n\tawait setupSummary(ployBot);\n\n\t// push out file(s) to wiki\n\tconst configs = [];\n\taddConfig(configs, 'pl.wikipedia.org');\n\taddConfig(configs, 'en.wikipedia.org');\n\taddConfig(configs, 'pl.wikisource.org');\n\n\tawait ployBot.deploy(configs);\n\n})().catch(err =\u003e {\n\tconsole.error(err);\n\tprocess.exit(1);\n});\n```\n\n## Appendix: Release vs dev release\n\n### Deploying as a gadget\n\nThere are various ways you could develop gadgets. The most standard way would be to deploy to the `MediaWiki:Gadget-` namespace.\n\nIn `wikiploy-common.mjs` add:\n```js\nexport function addConfigRelease(configs, site) {\n\tconfigs.push(new DeployConfig({\n\t\tsrc: 'dist/yourGadgetName.js',\n\t\tdst: 'MediaWiki:Gadget-yourGadgetName.js',\n\t\tsite,\n\t\tnowiki: true,\n\t}));\n\tconfigs.push(new DeployConfig({\n\t\tsrc: 'dist/yourGadgetName.css',\n\t\tdst: 'MediaWiki:Gadget-yourGadgetName.css',\n\t\tsite,\n\t}));\n}\n```\n\nIn your main deployment script you could have something like (`wikiploy.mjs`):\n```js\n\t// dev version\n\taddConfig(configs, 'en.wikipedia.org');\n\t// release versions\n\taddConfigRelease(configs, 'pl.wikipedia.org');\n\taddConfigRelease(configs, 'pl.wikisource.org');\n\taddConfigRelease(configs, 'en.wikipedia.org');\n```\nThe script doesn't have any limits. However, you do need interface-admin rights to deploy to the `MediaWiki:Gadget-` namespace. So, you might need to use `~/` to deploy to your user-space.\n\n### Release version in your user space\n\n**If you do *not* have interface-admin rights**, the functions could look like this:\n\n```js\nexport function addConfig(configs, site, isRelease) {\n\tlet deploymentName = isRelease ? '~/yourGadgetName' : '~/yourGadgetName-dev';\n\tconfigs.push(new DeployConfig({\n\t\tsrc: 'dist/yourGadgetName.js',\n\t\tdst: `${deploymentName}.js`,\n\t\tsite,\n\t\tnowiki: true,\n\t}));\n\tconfigs.push(new DeployConfig({\n\t\tsrc: 'dist/yourGadgetName.css',\n\t\tdst: `${deploymentName}.css`,\n\t\tsite,\n\t}));\n}\nexport function addConfigRelease(configs, site) {\n\taddConfig(configs, site, true);\n}\n```\n\nIn this case, you have both dev and release versions in your user space. Frankly, this might be the best choice, even if you have admin rights, especially if you use the *loader pattern*.\n\n### Loader pattern for gadgets\n\nEven if you have all administrative rights on a wiki, you might still want to load the main script from a small loader. The **loader pattern** allows you to provide conditions for loading the main script from the gadget file.\n\nThe loader pattern is most useful when you want to test specific capabilities of a device and only then load the script. This is how you could load popups (which don't work well on touch devices, i.e., devices that cannot hover).\n\nExample of what `MediaWiki:Gadget-Popups.js` could look like:\n```js\n// only on devices that can hover (not on touch-only, so not on smartphones)\nif (window.matchMedia \u0026\u0026 !window.matchMedia(\"(hover: none)\").matches) {\n\timportScript('User:Nux/Popups.js');\n}\n```\n\nYou could also have a gadget that is default, but only works on specific pages:\n```js\n// load config\nvar config = mw.config.get( [\n\t'wgNamespaceNumber',\n\t'wgTitle',\n] );\n// only on AfD subpages\nif ( config.wgNamespaceNumber == 4 \u0026\u0026 config.wgTitle.startsWith('Articles for deletion/') ) {\n\timportScript('User:Nux/AfD-helper.js');\n}\n```\nThe loader pattern is beneficial because it improves website performance. In this pattern, the main gadget code is only loaded when it can be useful.\n\nLoading from the `User` namespace might also help make it clear who is responsible for the gadget. However, it might not work when there is no single user responsible, such as when the main author becomes inactive. The community can always decide to fork the script, so that should not be a problem in practice.\n\n## Appendix: Exporting stuff \n\nNote that *browserify* will wrap your code with a function automatically, so you don't have to worry about leaking variables to the global scope (you should still remember to define variables with `var`, `let`, or `const`).\n\nIf you want to ***intentionally* expose** a variable, there are two ways to do that:\n\n1. Use the `window` object (only if you have to).\n2. Use *userjs* hooks (`mw.hook`).\n\nExposing things in `main.js` could look something like this:\n```js\nvar { MyGadget } = require(\"./MyGadget\");\n\n// instance\nvar gadget = new MyGadget();\n\n// expose for external usage (*not* recommended)\nwindow.yourGadgetName = gadget;\n\n// hook when object is ready\nmw.hook('userjs.yourGadgetName.loaded').fire(gadget);\n\n$(function(){\n\t// load Mediwiki core dependency\n\t// (in this case util is for `mw.util.addPortletLink`)\n\tmw.loader.using([\"mediawiki.util\"]).then( function() {\n\t\tgadget.init();\n\n\t\t// hook when initial elements are ready \n\t\tmw.hook('userjs.yourGadgetName.ready').fire(gadget);\n\t});\n});\n```\n\nAs you can see, hooks are better because you can keep the name of the variable short. It's also much easier to make sure each dependency is loaded so other devs can use your hooks in other gadgets, and your users can customize the script.\n\nUser options:\n```js\nmw.hook('userjs.yourGadgetName.loaded').add(function (gadget) {\n\tgadget.options.createTool = false;\n});\nimportScript('User:Nux/yourGadgetName.js');\n```\nA more advanced customization:\n```js\nmw.hook('userjs.yourGadgetName.ready').add(function (gadget) {\n\tvar $tool = $('#some-unique-gadget-tool a');\n\t$tool.text($tool.text() + ' \u0026 plugin');\n});\n```\n\n## Appendix: Using classes\n\nJS has classes for a long time. They don't work in IE and you cannot use them in default gadgets on Wikipedia. If you are building a default gadget you might want to add [babeljs](https://babeljs.io/) as a build step.\n```bash\n# install\nnpm install --save-dev babelify @babel/core\n# build\nbrowserify script.js -t babelify --outfile bundle.js\n```\n\nIf the gadget is intended for advanced users it is safe to assume they won't use IE. So for most scripts you can probably skip babelify. But as of 2023 you will need `requiresES6` option in the gadget definition.\n\n```\nyourClassyGadgetName [ResourceLoader | requiresES6 | dependencies = mediawiki.util] | yourGadgetName.js | yourGadgetName.css\n```\n\n\nExample `MyGadget.js` with a link in the toolbar:\n```js\n/**\n * Wikiploy gadget example.\n * \n * History and docs:\n * https://github.com/Eccenux/wikiploy-rollout-example\n * \n * Deployed using: [[Wikipedia:Wikiploy]]\n */\nclass MyGadget {\n\tconstructor() {\n\t\tthis.options = {\n\t\t\tcreateTool: true,\n\t\t};\n\t}\n\n\t/** Initialize things when DOM is ready. */\n\tinit() {\n\t\t// Example link in the tools sidebar\n\t\tif (this.options.createTool) {\n\t\t\tvar portletId = mw.config.get('skin') === 'timeless' ? 'p-pagemisc' : 'p-tb';\n\t\t\tvar linkLabel = 'My gadget dialog';\n\t\t\tvar itemId = 'some-unique-gadget-tool';\n\t\t\tvar item = mw.util.addPortletLink(portletId, '#', linkLabel, itemId);\n\t\t\t$(item).on('click', (evt) =\u003e {\n\t\t\t\tevt.preventDefault();\n\t\t\t\tthis.openDialog();\n\t\t\t});\n\t\t}\n\t}\n\n\t/** Open some dialog. */\n\topenDialog() {\n\t\t// Open a dialog window here\n\t}\n}\n\nmodule.exports = { MyGadget };\n```\n\nThis MyGadget class will work with the `main.js` example from the section above.\n\n## Appendix: Unit testing\n\nUnit testing is important for the stability of tools. Not everything needs to be unit tested, but if you perform any kind of parsing or other complicated tasks, it is a good habit to add automatic tests.\n\nThere are many testing frameworks, but I mostly use Mocha/Chai. This is mainly because the [Chai assert API](https://www.chaijs.com/api/assert/) is very functional.\n\nBelow is an example test of `imdb.redir()` function. The test file `test/imdb.test.js`:\n```js\n/* global require, describe, it */\nconst { assert } = require('chai');\nconst imdb = require('../src/imdb');\n\ndescribe('imdb', function () {\n\tdescribe('imdb redir', function () {\n\t\t// test function specific to *imdb redir*\n\t\tfunction test(text, expected) {\n\t\t\t// wrap\n\t\t\tlet result = imdb.redir(text);\n\t\t\tif (result !== expected) {\n\t\t\t\tconsole.log({text, result, expected});\n\t\t\t}\n\t\t\tassert.equal(result, expected);\n\t\t}\n\t\t// actual test\n\t\tit('should resolve redirs', function () {\n\t\t\ttest(`[[IMDb.com]]`, `[[IMDb]]`);\n\t\t\ttest(`[[IMDb.com|abc]]`, `[[IMDb|abc]]`);\n\t\t});\n\t});\n});\n```\nYou don't have to define a `test` function, but having a function like that can help test many different cases quickly.\n\nVisual Studio Code will let you run or even debug each `it` function separately, thanks to the *Vscode Test Explorer* extension.\n\n## Appendix: Wiki2git\n\nSo now that we have everthing setup we need code right? If you already have a gadget you might to import it from Wikipedia.\n\n```bash\n# install\nnpm i -g wiki-to-git\n\n# get metadata and insert commits to `src/NavFrame.js`\nwiki2git-load --site pl.wikipedia.org -p \"MediaWiki:Gadget-NavFrame.js\"\nwiki2git-commit --site pl.wikipedia.org --repo \"gadget-NavFrame\" -o \"src/NavFrame.js\"\n\n# get metadata and insert commits to `src/NavFrame.css`\nwiki2git-load --site pl.wikipedia.org -p \"MediaWiki:Gadget-NavFrame.css\"\nwiki2git-commit --site pl.wikipedia.org --repo \"gadget-NavFrame\" -o \"src/NavFrame.css\"\n```\n\nNote that in the example above `gadget-NavFrame` is a repository folder.\nThis can be a repo that already exists or something that you've already setup.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feccenux%2Fwikiploy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feccenux%2Fwikiploy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feccenux%2Fwikiploy/lists"}