Changes between Version 26 and Version 27 of WebInspectorCodingStyleGuide


Ignore:
Timestamp:
Jun 18, 2020 1:25:05 PM (4 years ago)
Author:
Devin Rousso
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • WebInspectorCodingStyleGuide

    v26 v27  
    88* [https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/OSXHIGuidelines/TerminologyWording.html#//apple_ref/doc/uid/20000957-CH15-SW4 Guidelines for UI labels]
    99* [https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/OSXHIGuidelines/Keyboard.html#//apple_ref/doc/uid/20000957-CH84-SW1 Guidelines for keyboard shortcuts]
     10
     11== Localization
     12
     13* Include a unique key and comment when dealing with arbitrary strings. Use `@` in the key to denote where in the interface the string can be found. (ex: `WI.UIString("Frames")` vs `WI.UIString("Frames", "Frames @ Execution Context Picker", "Title for list of HTML subframe JavaScript execution contexts")`).
     14
    1015== Tokens, spacing, indentation, syntax
    1116
     
    1318* Indent with 4 spaces.
    1419* Double quoted strings; use template strings if a bunch of interpolation is required.
    15 * The opening bracket `'{'` after a named, non-inlined function goes on the next line. Anywhere else, the opening bracket `'{'` stays on the same line.
    16 * Style for object literals is: `{key1: value1, key2: value2}`. When key and variable names coincide, use the syntax {expression} rather than {expression: expression}.
     20* The `{` after a named, non-inlined function goes on the next line. Anywhere else, the `{` stays on the same line.
     21* Style for object literals is: `{key1: value1, key2: value2}`. When key and variable names coincide, use the syntax `{key}` rather than `{key: key}`. If the object is complex enough, each `key: value,` should be on its own line.
    1722* Add new lines before and after different tasks performed in the same function.
    18 * Else-blocks should share a line with leading } or }).
     23* Else-blocks should share a line with leading `}`.
    1924* Long promise chains should place `.then()` blocks on a new line.
    20 * Calling a constructor with no arguments should have no parenthesis `'()'`. eg. `var map = new Map;`
     25* Calling a constructor with no arguments should have no parenthesis `'()'`. (ex: `var map = new Map;`)
    2126* Put anonymous functions inline if they are not used as a subroutine.
    22 * Prefer `let` to `var`, unless the variable is not used in a block scoping manner. Be careful when using `let` with `case` switches, as [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let all switch cases share the same block by default].
     27* Prefer `let` to `var`, unless the variable is not used in a block scoping manner. Be careful when using `let` with `case` switches, as [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let all switch cases share the same block by default]. Only use `const` for values that will not change between executions (i.e. actual constants).
    2328* Use arrow functions when possible, unless it makes code less readable. See below for examples.
    2429* For default parameters, add a space around the default assignment: `function foo(isGood = false)`
    25 * Trivial public getters can be made a single line and moved to the top of the list of getters in a class.
     30* Trivial public getters can be made a single line and moved to the top of the list of getters in a class, unless there is a corresponding setter.
    2631
    2732== Naming things
    2833
    29 * Avoid using the "on" prefix where possible. The `_onFoo` methods can just be `_foo` or `_handleFoo`.
    30 * New class names should use the name of the base class as a suffix. (ex: `TimelinesContentView` < `ContentView`). Exceptions: classes extending `WebInspector.Object` (unless they are a represented object), and deep hierarchies such as `DebuggerSidebarPanel` < `NavigationSidebarPanel` < `SidebarPanel` < `Object`.
     34* Avoid using the "on" prefix where possible. The `_onFoo` methods can just be `_foo` or `_handleFoo` (preferred for event listeners).
     35* New class names should use the name of the base class as a suffix. (ex: `TimelinesContentView` < `ContentView`). Exceptions: classes extending `WI.Object` (unless they are a represented object).
    3136* Spell out `identifier` instead of `id` if not doing so would result in a name ending with capitalized `Id`. For example, just `this.id` is fine, but `this.breakpointId` should be `this.breakpointIdentifier`.
    3237* An object's events live on the `Event` property of the constructor. Event names are properties on the `Event` object, and property values duplicate the event name, but are lowercased, hyphenated, and prefixed with the constructor name. See the skeleton example below.
     
    3540== API preferences
    3641
    37 * Use [http://people.mozilla.org/~jorendorff/es6-draft.html#sec-keyed-collection `Map` and `Set` collections] instead of plain objects if the key values are unknown or not monotonic (i.e., frequently added then removed).
    38 * Use `hsla()' over hex or RGB colors in CSS.
     42* Use `Map` and `Set` collections instead of plain objects if the key values are unknown or not monotonic (i.e., frequently added then removed).
     43* Use `hsla()` over hex or `rgba` for colors in CSS.
    3944* Use `for..of` syntax when performing actions on each element. Use `forEach` when chaining methods in a functional style. Use a classical for loop when doing index math.
    40 * When using `forEach` or `map`, supply the `this`-object as the optional second parameter rather than binding it.
     45* When using `forEach` or `map`, use an arrow function or supply the `this`-object as the optional second parameter rather than binding it.
    4146* In promise chains, use arrow functions for lexical `this`, rather than assigning `const instance = this;' or `.bind`ing every function's `this`-argument.
    4247* Use destructuring assignment when digging values out of a JSON object or "args" object.
     
    4651== Layering and abstractions
    4752
    48 * Firewall the protocol inside the Manager classes. JSON objects received from the protocol are called "payload" in the code. The payload is usually deconstructed at the Managers level and passes down as smart objects inheriting from `WebInspector.Object`.
     53* Firewall the protocol inside the Manager classes. JSON objects received from the protocol are called "payload" in the code. The payload is usually deconstructed at the Managers level and passes down as smart objects inheriting from `WI.Object`.
    4954* Avoid accessing *View classes from *Manager or *Object classes. This is a layering violation that prevents writing tests for models.
    5055* Avoid storing DOM elements in *Manager or *Object classes. (see above.)
     
    7378* To reject a promise, throw an `Error` instance or call the `reject` callback with an `Error` instance.
    7479* A `.catch()` block is considered resolved if it does not re-throw an `Error` instance. Re-throw if you want to log an error message and allow other parts of a chain (i.e, an API client) to handle an error condition.
    75 * Don't directly pass a promise's `resolve` function to `Object.addEventListener`, as it will leak the promise if the event never fires. Instead, use a single-fire `WebInspector.EventListener` object defined outside of the promise chain and connect it inside a `.then()` body. Inside the `.catch` block, disconnect the `EventListener` if necessary.
     80* Don't directly pass a promise's `resolve` function to `Object.addEventListener`, as it will leak the promise if the event never fires. Instead, use a single-fire `WI.EventListener` object defined outside of the promise chain and connect it inside a `.then()` body. Inside the `.catch` block, disconnect the `EventListener` if necessary.
    7681* For APIs that return promises, document what the fulfilled value will be, if any. Example: `createSession() // --> (sessionId)`
    7782
     
    118123=== When not to arrow
    119124
    120 When assigning a function to a subclass prototype (in the old way of setting up classes), always use the normal function syntax, to avoid breaking subclasses who use a different 'this' binding. Note that arrow functions are NOT acceptable for assigning functions to singleton objects like WebInspector, since the captured lexical `this` is typically the global object.
     125When assigning a function to a subclass prototype (in the old way of setting up classes), always use the normal function syntax, to avoid breaking subclasses who use a different 'this' binding. Note that arrow functions are NOT acceptable for assigning functions to singleton objects like `WI`, since the captured lexical `this` is typically the global object.
    121126
    122127GOOD:
     
    126131Foo.prototype.compute = function(a, b, c) { Base.prototype.compute.call(this, a, b, c); }
    127132
    128 WebInspector.UIString = function(format, args) { ... }
     133WI.UIString = function(format, args) { ... }
    129134}}}
    130135
     
    135140Foo.prototype.compute = (a, b, c) => { Base.prototype.compute.call(this, a, b, c); }
    136141
    137 WebInspector.UIString = (format, args) => { ... } // this will be window.
     142WI.UIString = (format, args) => { ... } // this will be window.
    138143}}}
    139144
     
    162167
    163168{{{
    164 WebInspector.NewObjectType = class NewObjectType extends WebInspector.Object
     169WI.NewObjectType = class NewObjectType extends WI.Object
    165170{
    166171    constructor(type, param)
    167172    {
    168        super();
    169        console.assert(param instanceof WebInspector.ExpectedType);
    170        this._type = type;
    171        this._propertyName = param;
     173        console.assert(param instanceof WI.ExpectedType);
     174
     175        super();
     176
     177        this._type = type;
     178        this._propertyName = param;
    172179    }
    173180
     
    176183    static computeBestWidth(things)
    177184    {
    178         ....
     185        // ...
    179186        return 3.14159;
    180187    }
     
    192199    {
    193200        this._propertyName = value;
    194         this.dispatchEventToListeners(WebInspector.NewObjectType.Event.PropertyWasChanged);
    195     }
    196 
    197     publicMethod: function()
     201        this.dispatchEventToListeners(WI.NewObjectType.Event.PropertyWasChanged);
     202    }
     203
     204    publicMethod()
    198205    {
    199206        /* public methods called outside the class */
     
    202209    // Protected
    203210
    204     handleEvent: function(event)
    205     {
    206         /* delegate methods, event handlers, and overrides. */
     211    protectedMethod(event)
     212    {
     213        /* delegate methods and overrides */
    207214    }
    208215
    209216    // Private
    210217
    211     _privateMethod: function()
     218    _privateMethod()
    212219    {
    213220        /* private methods are underscore prefixed */
     
    215222};
    216223
    217 WebInspector.NewObjectType.Event = {
    218     PropertyWasChanged: "new-object-type-property-was-changed"
     224WI.NewObjectType.Event = {
     225    PropertyWasChanged: "new-object-type-property-was-changed",
    219226};
    220227