Manual:Coding conventions/JavaScript/fr

Cette page décrit les conventions de codage pour JavaScript dans la base de code MediaWiki. Voir aussi les conventions générales.

Linting
Nous utilisons ESLint comme outil de qualité de code, avec le préréglage eslint-config-wikimedia pour encoder la plupart de nos règles de style de codage et de qualité de code. Reportez-vous à Intégrations sur eslint.org pour trouver de nombreux éditeurs de texte ou IDE dotés de modules permettant de fournir un retour en direct pendant la saisie.

Configuration de Linter
Pour exclure des fichiers ou des répertoires de l'analyse (par exemple des bibliothèques tierces), vous pouvez configurer les modèles ignorés dans ESLint, via un fichier. Notez que  est exclu par défaut, donc la plupart des dépôts n'ont pas besoin de mettre en place des règles d'ignorance.

Chaque dépôt a besoin d'un fichier  dans le répertoire racine du dépôt. L'exemple suivant montre un fichier de configuration ESLint :

Voir .eslintrc.json dans MediaWiki et ÉditeurVisuel pour des exemples concrets.

N'oubliez pas de définir  pour éviter une "succession magique" involontaire des configurations d'eslint dans des répertoires parents non liés que vous ou le serveur CI pourriez avoir mis en place sur le disque (par exemple parmi une extension MediaWiki et MediaWiki core, ou entre votre répertoire de projet et quelque chose dans votre répertoire personnel).

La préselection eslint-config-wikimedia fournit différents profils que les projets peuvent choisir à leur convenance, tel que les différentes langues, ou les varables d'environnement globales à l'exécution. Par exemple :


 * - pour le code du navigateur et prévoit un support ES5
 * - pour le code du navigateur qui utilise ES6
 * - pour le code Node.js 10+ et prévoit un support ES2018
 * - un mixin pour les tests QUnit

Vous devez vous attendre à utiliser plusieurs fichiers  dans un répertoire pour définir différentes attentes environnementales pour différents sous-répertoires. Cela permet de s'assurer que vous n'utilisez pas accidentellement les méthodes  dans le code serveur que vous pensez exécuter sur le serveur ou que vous ne faites pas référence à QUnit dans le code de production. files in subdirectories automatically inherit from the parent directory's configuration, so they only need to contain the things that are specific to that directory (example file).

Intégration continue
Projects are encouraged to enforce ESLint passing by including it their  script via the "test" command in. Voir Continuous integration/Entry points pour plus d'informations à ce sujet.

If your project has a fairly heavy test pipeline, one could define an  or even   script in   to make it easy to run just those from the command-line during local development (so that one doesn't have to open each file in an editor and/or to wait for CI).

To expose other command-line features from ESLint (such as linting individual files outside a text editor, or using the --fix feature), define "eslint" as its own script in package.json without any argument. Vous pouvez ensuite l'invoquer à partir de la ligne de commande comme suit :

Espaces
Nous utilisons les conventions suivantes :


 * Indentation avec tabulations.
 * Pas d'espace à la suite d'un autre espace.
 * Utilisez des lignes vides pour séparer un bloc de code logiquement lié à un autre.
 * Un espace des deux côtés des opérateurs binaires et des opérateurs d'affectation.
 * Les mots-clés suivis d'une " " (parenthèse gauche) doivent être séparés par un espace. Cela permet de distinguer visuellement les mots-clés des appels de fonction.
 * Il ne doit pas y avoir d'espace entre le nom de la fonction et la parenthèse gauche d'une liste d'arguments.
 * Il doit y avoir un espace à l'intérieur des parenthèses (comme dans les instructions if, les appels de fonction et les listes d'arguments).
 * N'utilisez pas les opérateurs comme s'il s'agissait de fonctions (par exemple,  ,  ,  ,  ...).

Ces aspects et d'autres de notre guide de style sont appliqués avec ESLint.

Longueur de ligne
Les lignes ne doivent pas comporter plus de 80 à 100 caractères. Si une déclaration ne tient pas sur une seule ligne, répartissez-la sur plusieurs lignes. La suite d'une déclaration doit être indentée d'un niveau supplémentaire.

Les appels de fonction et les objets doivent être soit sur une seule ligne, soit répartis sur plusieurs lignes, avec une ligne pour chaque fragment. Évitez de fermer un appel de fonction ou un objet à une indentation différente de celle de son ouverture.

Structure
En résumé :

Fermeture
If a module bundle can't or otherwise isn't yet registered using package files, then its individual JavaScript files should have a file-level closure around its code. This gives the code its own scope, and avoids leakage of variables from or to other files, including in debug mode, and in a way that is understood by static analysis. This pattern is known as an immediately-invoked function expression (or "iffy" ).

For package files this is not needed, as their are executed as a "module" file rather than a "script" file, which naturally have their own local scope. ESLint should also be configured accordingly (set, like in this example).

Déclarations
Variables must be declared before use. Each assignment must be on its own line. Variables may be declared near or at their first assignment.

If combining multiple  assignments in one statement, then declarations that don't assign a value should be listed before assignments. The subsequent lines should be indented another level.

Functions should be declared before use. In the function body, function declarations should go after variable declarations and before any main statements.

Commentaires
Comments should be on their own line and go over the code they describe.

Within a comment, the opening syntax (e.g. slash-slash, or slash-star) should be separated from the text by a single space, and the text should start with a capital letter. If the comment is a valid sentence, then a full stop should be placed at the end of it.

Use line comments within functions and other code blocks (including for multi-line comments).

Use block comments only for documentation blocks. This helps maintain consistent formatting for inline comments (e.g. not some as blocks and some as multi-line comments, or having to convert from one to the other). It also avoids confusing documentation engines. It also makes it easy to disable parts of the code during development by simply moving the end-comment notation a few lines down, without being short-circuited by an inline block comment.

Be liberal with comments and don't fear file size because of it. All code is automatically minified by ResourceLoader before being shipped.

Commentaires sur la documentation

 * Text in free-form blocks should be sentence case (e.g. description of methods, parameters, return values etc.)
 * Start sentences with a capital letter.
 * Continue sentences belonging to an annotation on the next line, indented with one additional space.

Documentation générée

 * We are currently moving from JSDuck to JSDoc, as the former is unmaintained.

The below will be updated once JSDoc is adopted in MediaWiki core.

Use JSDuck to build documentation (see https://doc.wikimedia.org).

JSDuck is pre-installed in Fresh environments and in WMF CI. To install it in custom developer environment, use to install it from RubyGems. See the upstream guide for more information.

To generate the documentation, the standard entry point  should be used, as defined in.

Configure JSDuck in your project via a  file. See JSDuck configuration, or check examples.

Balises
We use the following annotations. They should be used in the order as they are described here, for consistency. See the JSDuck documentation for how these work.


 * @abstract
 * @private
 * @ignore
 * @static
 * @class Name (name is optional, engine will guess name from context)
 * @singleton
 * @extends ClassName
 * @mixins ClassName
 * @constructor
 * @inheritable
 * @member
 * @method name (name is optional, guessed)
 * @property name (name is optional, guessed)
 * @inheritdoc
 * @deprecated
 * @param {Type} name Optional text.
 * @return {Type} Optional text.
 * @chainable
 * @throws {Type}
 * @cfg {Type} [name="default value"] (used when a configuration object is passed to the class constructor, use one for each property and don't include those of parent constructors)

Types
Primitive types and special values: boolean, number, string, undefined, null.

Built-in classes: Object, Array, Function, Date, RegExp, Error.

Égalité

 * Use strict equality operators ( and  ) instead of (loose) equality (  and  ). The latter does type coercion.
 * No Yoda conditionals.

Contrôles de type

 * string:
 * number:
 * boolean:
 * Function:
 * null:
 * object:
 * Plain Object:
 * Array:
 * HTMLElement:
 * undefined:
 * Local variables:
 * Properties:
 * Global variables:

Chaînes
Use single quotes instead of double quotes for string literals. Remember there are no "magic quotes" in JavaScript i.e.  and   work everywhere.

To extract part of a string, use the  method for consistency. Avoid the, or   methods which are redundant, easily mistaken, and may have unexpected side effects.

Exportation
Use globals exposed by the browser (such as document, location, navigator) directly and not as properties of the window object. This improves confidence in code through static analysis and may also power other IDE features. In addition to browser globals, the only globals that are safe to use are,   and.

Avoid creating new global variables. Avoid modifying globals not "owned" by your code. For example, built-in globals such as String or Object must not be extended with additional utility methods, and similarly functionality relating to OOjs or jQuery, should not be assigned to those globals.

To publicly expose functionality for re-use, use  from Package files, and/or assign properties within the   hierarchy, e.g..

Note that configuration variables exposed by MediaWiki must be accessed via. For backward compatibility with legacy user scripts and gadgets, many -prefixed configuration keys are still defined as global varables as well, but these are deprecated. (See T72470.)

Environnement
Modifying built-in protypes such as  is considered harmful. This is not supported in MediaWiki code, and doing so will likely result in breakage of unrelated features.

Nommage
All variables must be named using CamelCase starting with a lowercase letter, or use all caps (with underscores for separation) if the variable represents some kind of constant value.

All functions must be named using CamelCase, generally starting with a lowercase letter unless the function is a class constructor, in which case it must start with an uppercase letter. Method functions are preferred to start with verb, e.g.  instead of "foo".

Abréviations
Names with acronyms in them should treat the acronym as a normal word and only uppercase the first letter as-needed. This applies to two-letter abbreviations as well, such as. For example,  as opposed to "getHTMLAPISource".

jQuery
Distinguish DOM nodes from jQuery objects by prefixing variables with a dollar sign if they will hold a jQuery object, e.g. . This helps reduce mistakes where conditions use incorrect conditional checks, such as   instead of. Where DOM methods often return null (which is falsey), jQuery methods return an empty collection object (which, like native arrays and other objects in JavaScript, are truthly).

npm
When publishing a standalone project to npmjs.org, consider publishing it under the  namespace. Note that some standalone projects, that are aimed at use outside the Wikimedia community and have a sufficiently unique name, currently use an unnamespaced package name (e.g. "oojs" and "visualeditor"). T239742

Création d'éléments
Pour créer un élément ordinaire, utilisez la syntaxe simple dans le constructeur jQuery :

When creating elements based on the tag name from a variable (which may contain arbitrary html):

Only use when you need to parse HTML (as opposed to creating a plain element).

Collections
Different types of collections sometimes look similar but have different behaviour and should be treated as such. This confusion is mostly caused by the fact that arrays in JavaScript look a lot like arrays in other languages, but are in fact just an extension of Object. We use the following conventions:

Avoid using a  loop to iterate over an array (as opposed to a plain object), because    will result in many unexpected behaviours, including: keys as strings, unstable iteration order, indexes may skip gaps, iteration may include other non-numerical properties.

Stockage
Keys in localStorage and/or sessionStorage should be accessed via  or.

Clés
Keys should start with  and use camel case and/or hyphens. Do not use underscores or other separators. Examples of real keys:



Beware that contrary to cookies via mw.cookie, there is no wiki prefix or cookie prefix added by default. If values must vary by wiki, you must manually include  as part of the key.

Valeurs
Values must be strings. Beware that attempting to store other value types will silently cast to a string (e.g.  would become  ).

Space is limited. Use short and concise values over object structures where possible. A few example:


 * For boolean state (true/false, expanded/collapsed) use "1" or "0".
 * For values that are always numbers, store them as-is and cast with  on the way out (avoid  ).
 * For values that are always strings, store them as-is.
 * For lists of software-defined values, consider comma-separated or pipe-separated strings to reduce space and processing cost.
 * For lists of values that may be user-generated or are otherwise complex in nature, use JSON.

Stratégie d'éviction
Remember that Local storage does not have any eviction strategy by default. Therefore the following should be avoided:


 * Avoid using user-generated input as part of a key name.
 * Avoid keys containing identifiers for user-generated entities (e.g. user names, category names, page ids, or other user-provided or system-provided variables).
 * In general avoid approaches that involve creating a potentially large number of storage keys.

For example, if a feature needs to store state about a variable entity (e.g. current page), it might make sense to use a single key for this feature as a whole and to limit the stored information only to the last few iterations (LRU). The slight increase in retrieval cost (the whole key, instead of separate smaller ones) is considered worth it, as otherwise the number of keys would grow uncontrollably.

Even if the keys are not dependent on user-input, you may still want to use a single key for your feature because otherwise past versions of your software will have stored data that you can't clean up. By using a single key you can roundtrip it in a way that naturally doesn't persist unknown sub properties.

Use of a tracking key is also an anti-pattern and does not avoid the above issues, as this would leak due to race conditions in HTML5 web storage being shared and non-atomic between multiple open browser tabs.

When feature's use of Local storage is to be removed, be sure to implement an eviction strategy first to clean up old values. Typically mw.requestIdleCallback is used to gracefully look for the key and remove it. See T121646 for a more scalable approach.

Informations personnelles
Avoid storing personal information in Local storage as it remains when a user logs out or closes their browser. Use Session storage instead. See T179752.

Code asynchrone
Asynchronuous code should follow, and be compatible with, the Promise standard.

When you define an asynchronous method for other code to call, you may internally construct the returned thenable object either using $.Deferred or native Promise. Remember to depend on the  polyfill if using Promise (this polyfill is automatically skipped and excluded from your module bundle in modern browsers).

When you call an asynchronous method, use only standard Promise-compatible methods such as  and. Avoid using jQuery-specific methods like  or , which could stop working without warning if the method you are calling internally transitions from $.Deferred to native Promise.

Note that there are also subtle legacy behaviours in the "done" and "fail" callbacks. Pay close attention when migrating existing code from  to   as doing so may cause the code to stop working correctly. Specifically, the "done" and "fail" callbacks invoke your callback synchronously if the Deferred was already settled by the time you attach your callback. This means your callback may be invoked before the attaching statement is finished running.

For example:

Réutiliser les modules ResourceLoader
Don't reinvent the wheel. Much JavaScript functionality and MediaWiki-related utilities ship with MediaWiki core that are stable and you can (literally) depend on them. See ResourceLoader/Core modules before rolling your own code.

Pièges
Read more:
 * Be careful to preserve compatibility with left-to-right and right-to-left languages (i.e.  or  ), especially when styling text containers. Putting those declarations in CSS file will allow them to be automatically flipped for RTL-languages by CSSJanus in ResourceLoader.
 * Use  and   appropriately.
 * jQuery#attr, jQuery API
 * Attributes and custom properties, javascript.info
 * Consistently quote attribute selector values:  instead of   (jqbug 8229).
 * As of jQuery 1.4 the jQuery constructor has a new feature that allows passing an object as second argument, like . Don't use this. It makes code harder to follow, fails on attributes (such as 'size') that are also methods, and is unstable due to this mixing of jQuery methods with element attributes. A future jQuery method or plugin called "title" might convert an element into a heading, which means the title attribute can also no longer be set through this method. Be explicit and call ,  ,   etc. directly.

Utiliser CSS pour styliser de nombreux éléments
N'appliquez pas de style à un grand nombre d'éléments à la fois car cela peut dégrader les performances. Utilisez plutôt la classe d'un parent commun (ou ajoutez-en un) et appliquez le CSS dans un fichier  ou. Grâce à ResourceLoader, tout sera chargé dans la même requête HTTP, de sorte qu'il n'y a pas de dégradation des performances due à la présence d'un fichier CSS distinct. Ne mettez pas de CSS dans les attributs "style" en ligne, n'insérez pas non plus d'éléments "style" à partir de JavaScript.

Références

 * JavaScript Style Guide, Contribute to jQuery
 * Code Conventions for JavaScript, Douglas Crockford
 * Programming Style & Your Brain, Douglas Crockford on YouTube