{"id":21406625,"url":"https://github.com/ringcentral/ringcentral-javascript","last_synced_at":"2025-10-26T11:46:09.326Z","repository":{"id":53972487,"uuid":"98871517","full_name":"ringcentral/ringcentral-javascript","owner":"ringcentral","description":"JavaScript Style Guide","archived":false,"fork":false,"pushed_at":"2022-01-27T20:09:47.000Z","size":434,"stargazers_count":27,"open_issues_count":5,"forks_count":10,"subscribers_count":46,"default_branch":"master","last_synced_at":"2025-06-16T09:04:32.358Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/ringcentral.png","metadata":{"files":{"readme":"README.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}},"created_at":"2017-07-31T09:24:02.000Z","updated_at":"2025-03-30T00:43:09.000Z","dependencies_parsed_at":"2022-08-13T05:21:09.026Z","dependency_job_id":null,"html_url":"https://github.com/ringcentral/ringcentral-javascript","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/ringcentral/ringcentral-javascript","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fringcentral-javascript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fringcentral-javascript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fringcentral-javascript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fringcentral-javascript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ringcentral","download_url":"https://codeload.github.com/ringcentral/ringcentral-javascript/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ringcentral%2Fringcentral-javascript/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265227898,"owners_count":23731059,"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":[],"created_at":"2024-11-22T16:41:04.770Z","updated_at":"2025-10-26T11:46:09.242Z","avatar_url":"https://github.com/ringcentral.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RingCentral JavaScript Style Guide\n\nReact-specific guidelines described at [RingCentral React Style Guide](https://github.com/ringcentral/ringcentral-javascript/tree/master/react-style-guide)\n\n## Table of contents\n\n1. [Overview](#overview)\n1. [Language statements and features](#language-statements-and-features)\n1. [Spaces and alignments](#spaces-and-alignments)\n1. [Naming](#naming)\n\n## Overview\n\nThis document provides a set of common rules regarding to source code in JavaScript.\nIt allow us to make and keep our codebase well organized and maintainable. \n\n## Language statements and features\n\n### Use brackets for all control constructs\n\nuse brackets for all control constructs like ```if```, ```else```, ```try```, ```for```, ```while```. Even for one liners\n\n\u003e Reason: using brackets makes code as predictable as possible. It avoid bugs caused to forgotten bracket by misprint. Also it's don't require developer to add/remove brackets when body of construct transform from one line to multi-line form and vice versa. It makes diffs more clear.\n\n```javascript\n// BAD\nlet bar = [];\nif (isValid(foo)) bar.push('bar');\n\n// BAD\nif (isValid(foo))\n    bar.push('bar');\n\n// BAD\nfor (let i=0; i\u003cAMOUNT; i++) bar.push(i);\n\n// GOOD\nif (isValid(foo)) {\n    bar.push('bar');\n}\n\n// GOOD\nfor (let i=0; i\u003cAMOUNT; i++) {\n    bar.push(i);\n}\n```\n\n### Always add semicolon ```;``` at the end of statements\n\n```javascript\n// BAD\nlet foo = 'foo'\nlet bar = ['bar', 'baz']\n\n// GOOD\nlet foo = 'foo';\nlet bar = ['bar', 'baz'];\n```\n\n### Prefer ```const``` / ```let``` vs ```var```\n\n\u003e Reason: ```const``` / ```let``` is block scoped, vs ```var``` is function scoped. Using unassigned ```const``` / ```let``` variable cause an ```ReferenceError``` exception, but unassigned ```var``` still work silently without warnings and may cause hard to reproduce bugs. One more reason to use ```const``` / ```let``` is that redeclaration the same variable will trigger ```SyntaxError``` versus silent continuation of execution with ```var``` declaration\n\n```javascript\n// BAD\nfunction foo() {\n    var bar = baz();\n    // ...\n    var bar = null; // work\n}\n\n// GOOD (to avoid implicit errors)\nfunction foo() {\n    let bar = baz();\n    // ...\n    let bar = baz(); // SyntaxError exception prevent re-declaration\n}\n\n// BAD\nfunction foo() {\n    baz(bar); // work, bar === undefined\n    // ...\n    var bar = 'bar'; \n}\n\n// GOOD (to avoid implicit errors)\nfunction foo() {\n    baz(bar); // SyntaxError\n    // ...\n    let bar = 'bar'; \n}\n```\n\n### Use trailing comma\n\nFor multi-line structures, the trailing comma is required. For oneline definitions it should not be used.\n\n\u003e Reason: it helps to make history and code review cleaner. It allows to move/remove the last element without changing a previous line.\n\n```javascript\n// BAD\nlet foo = {bar: 1, baz: 5,};\nlet bar = ['bar', 'baz',];\n\n// GOOD\nlet foo = {bar: 1, baz: 5};\nlet bar = ['bar', 'baz'];\n\n// BAD\nlet foo = {\n    bar: 1,\n    baz: 5,\n    qux: 8\n};\nlet bar = [\n    'bar',\n    'baz',\n    'qux'\n];\n\n// GOOD\nlet foo = {\n    bar: 1,\n    baz: 5,\n    qux: 8,\n};\nlet bar = [\n    'bar',\n    'baz',\n    'qux',\n];\n```\n\n### Use separate ```const``` / ```let``` declaration per variable\n\n\u003e Reason: it allows to avoid bugs with global scope variables (caused by misprinted comma). It's easier to maintain. It makes diffs more clear.\n\n```javascript\n// BAD\nconst FOO = 'FOO',\n    BAR = 17;\nlet foo, bar = 17;\n\n// GOOD\nconst FOO = 'FOO';\nconst BAR = 17;\nlet foo;\nlet bar = 17;\n```\n\n### Use strict comparison operator to avoid potential type-casting bugs\n\n```javascript\n// BAD\nif (foo == '') {\n    bar();\n}\nif (foo == null) {\n    bar();\n}\n\n// GOOD\nif (foo === '') {\n    bar();\n}\nif (foo === null) {\n    bar();\n}\n```\n\n### Do not reassign variables inside ```if```, ```while```, etc.\n\nIt easy to misprint and leads to bugs\n\n```javascript\n// BAD\nif (foo.bar = baz) {\n    calculate();\n}\n\n// GOOD\nfoo.bar = baz;\nif (foo.bar === true) {\n    calculate();\n}\n```\n\n### Don't define functions inside block\n\n```javascript\n// BAD\nfunction qux() {\n    if (foo) {\n        function bar() {\n            // ...\n        }\n        // ...\n        bar();\n    }\n}\n\n// GOOD\nfunction qux() {\n    if (foo) {\n        // ...\n        bar();\n    }\n}\n\nfunction bar() {\n    // ...\n}\n\n// GOOD, but avoid inner functions\nfunction qux() {\n    if (foo) {\n        // ...\n        bar();\n    }\n    \n    function bar() {\n        // ...\n    }\n}\n\n```\n\n### Put dot ```.``` before the property, don't leave it at the end of line\n\n```javascript\n// BAD\nmodel.\n    foo().\n    bar().\n    baz;\n\n// GOOD\nmodel\n    .foo()\n    .bar()\n    .baz();\n\n// BAD\nexpect(actualValue, 'should contains foo, bar').\n    to.have.ordered.members(['foo', 'bar']);\n    \n// GOOD\nexpect(actualValue, 'should contains foo, bar')\n    .to.have.ordered.members(['foo', 'bar']);\n```\n\n### Do not use ternary inside ternary - no nested ternary\n\n\u003e Reason: it's really hard to maintain such code\n\n```javascript\n// BAD\nlet result = foo \u003c bar ? foo : (foo \u003e baz ? 'FOO' : baz);\n\n// GOOD\nlet result;\nif (foo \u003c bar) {\n    result = foo;\n} else {\n    result = foo \u003e baz ? 'FOO' : baz;\n}\n```\n### Don't use else, if return stops function execution before\n\u003e Reason: it's necessary and makes code cleaner\n```javascript\n// BAD\nconst foo = () =\u003e {\n    if (isBar) {\n        return 'bar';\n    } else {\n        return 'baz';\n    }\n}\n\n// GOOD\nconst foo = () =\u003e {\n    if (isBar) {\n        return 'bar';\n    }\n    \n    return 'baz';\n}\n```\n\n### Make function calls clear and predictable\n\n```javascript\n// BAD \ncondition \u0026\u0026 foo();\n\n// GOOD\nif (condition === true) {\n    foo();\n}\n\n// BAD \nisCondition \u0026\u0026 foo();\n\n// GOOD\nif (isCondition) {\n    foo();\n}\n\n```\n\n### Make the code more flat and plain\nEach indent makes code's reading difficult. Return the result from the function as soon as possible.\n\n```javascript\n// BAD \nfunction getUserActions() {\n    if (isActionsAvailable) {\n        if (isUserEnabled) {\n            return [/*some actions for enabled user*/];\n        } else if (isUserDisabled) {\n            return [/*some actions for disabled user*/];\n        } else {\n            return [/*other actions*/];\n        }\n    }\n    return [];\n}\n\n// GOOD\nfunction getUserActions() {\n    if (!isActionsAvailable) {\n        return [];\n    }\n    if (isUserEnabled) {\n        return [/*some actions for enabled user*/];\n    } \n    if (isUserDisabled) {\n        return [/*some actions for disabled user*/];\n    }\n    return [/*other actions*/];\n}\n\n\n// BAD \nclass SomePopup extends Component {\n    renderFooter() {\n        if (isFooterAvailable) {\n            return (\n                \u003cFooter \n                    there=\"there\" \n                    are=\"are\"\n                    many=\"many\"\n                    properties \n                    here\n                /\u003e\n            );\n        }\n        return null;\n    }\n}\n\n// GOOD\nclass SomePopup extends Component {\n    renderFooter() {\n        if (!isFooterAvailable) {\n            return null;\n        }\n        return (\n            \u003cFooter \n                there=\"there\" \n                are=\"are\"\n                many=\"many\"\n                properties \n                here\n            /\u003e\n        );\n    }\n}\n```\n\n### Put all non dynamic imports at the top of file\n\n\u003e Reason: it improves a file navigation\n\n### Prefer named export vs default export\n\n\u003e Reason: it saves exported variable names, makes imports, a refactoring and a navigation easier\n\n```javascript\n\n// BAD\nexport default class Foo {\n    // ...\n}\n\n// GOD\nexport class Foo {\n    // ...\n}\n\n````\n\n### Do not use ```with``` statement\n\nDo not use ```with``` statement - it cause of confusing and bad maintainable code\n\n```javascript\n// BAD\nwith (_) {\n    trace(sort(bar), trim(baz));\n}\n\n// GOOD\ntrace(_.sort(bar), _.trim(baz));\n```\n\n### Use shorthand object properties\n\u003e Reason: it makes code cleaner\n```javascript\n// BAD\nconst foo = {\n    a: a,\n    b: b,\n    c: function() {},\n};\n\n// GOOD\nconst foo = {\n    a, \n    b,\n    c() {},\n};\n\n```\n\u003ca name=\"move-shorthand-properties-up\"\u003e\u003c/a\u003e\n[#](#move-shorthand-properties-up) Move shorthand properties up \n```javascript\n// BAD\nconst foo = {\n    c: 'bar',\n    a,\n    d: 'baz',\n    b,\n};\n\n// GOOD\nconst foo = {\n    a,\n    b,\n    c: 'bar',\n    d: 'baz',\n};\n```\n### Avoid using nested functions\n\n\u003e Reason: it bad for testing and maintaining. It's always better to make separate, outer-scope free functions and methods instead of mash of inner functions. \n\n### Do not leave console calls\n\nDo not leave console calls in your code\n\n### Do not leave commented code, just remove it\n\n\u003e Reason: it just a noise for other developers. We always can find anything using history of version control system.\n\n### Specify `TODO` | `FIXME` comment with task id or username\n\n\u003e Reason: to not keep not evident and forgotten comments please specify a comment with a task id which is connected with a problem. If it's a light problem and you are going to solve it soon you can provide just your username. \n\u003cdetails\u003e\n  \u003csummary\u003eRead more\u003c/summary\u003e\n  \n  ---\n  \n  TODO is a useful tool for developers.\n  There are a few cases when TODO comments could be added:\n  \n  * the developer is working on the task, and he noticed that part of his work is temporarily blocked (say, his particular task depends on API that not yet ready)\n  * the developer is working on the task and noticed that he would like to make one/few little improvements later in the scope of this task. However, the task is already done and could be sent for code-review to the boost a process.\n  * the developer detects some issue in the code and unable to fix it in the scope of his task, but he would like to improve the situation.\n  \n  **Do not leave anonymous TODO without the id**. Usually, anonymous TODO's live too long while it not linked to the issue tracking system.\n  Signed TODO's increases the factor of responsibility. When the developer signs TODO it like a short-term note for the author. But, it also a flag that author is responsible to resolve it ASAP. Finally, it makes such part of code clear for reviewers.\n  \n  ---\n  \n\u003c/details\u003e\n\n\n```javascript\n\nclass UserService {\n    // BAD\n    getAllUsers() {\n        // TODO implement when backend is ready\n    }\n        \n    // GOOD\n    getAllUsers() {\n        // TODO [UIA-12345] implement when backend is ready\n    }\n    \n    // GOOD (if you know that you will do it no later than two weeks)\n    getAllUsers() {\n       // TODO (trump.wang) implement when backend is ready\n    }\n    \n    // GOOD (to add FIXME if you see some problem code)\n    badMethod() {\n        // FIXME [UIA-12345] rewrite this to a better structure\n        // ...bad code\n    }\n}\n\n```\n\n## Spaces and alignments\n\n### Do not exceed 120 column width\n\n\u003e Reason: it's hard to read and maintain\n\nException: long links and international strings can exceed that limitation\n\n### Do not align values horizontally\n\n\u003e Reason: alignment may increase readability for some cases, but it's a root of few problems. It bad for maintaining, because of change of one line can trigger realignment of all nearest aligned lines. So, owner of such change will mislead reviewers, and makes commits history dirty. Also it cause a redundant merge conflicts.\n\n```javascript\n// BAD\nlet foo = {\n    first:          'foo',\n    second:         'bar',\n    thisOneIsLong:  'baz',\n};\n\n// GOOD\nlet foo = {\n    first: 'foo',\n    second: 'bar',\n    thisOneIsLong: 'baz',\n};\n```\n\n### Set one space before function body curly bracket ```{```, do not set space after function name\n```javascript\n// BAD\nfunction isFooBar () {\n    // ...\n}\n\n\n\n// GOOD\nfunction isFooBar() {\n    // ...\n}\n```\n\n### Set one space before nearly curly brackets ```{``` followed by keywords: (```do```, ```for```, ```if```, ```else```, etc.)\n\n```javascript\n// BAD\nif (isValid){\n    // ...\n}\n\n// GOOD\nif (isValid) {\n    // ...\n}\n\n// BAD\nwhile (foo \u003e bar){\n    // ...\n}\n\n// GOOD\nwhile (foo \u003e bar) {\n    // ...\n}\n```\n\n### Set one space around keywords (```do```, ```for```, ```if```, ```else```, etc.)\n\n```javascript\n// BAD\nif(isValid) {\n    foo();\n}else{\n    bar();\n    baz();\n}\n\n// GOOD \nif (isValid) {\n    foo();\n} else {\n    bar();\n    baz();\n}\n\n// BAD\nif(isValid) {\n    foo();\n}else if(quux \u003c 0){\n    bar();\n    baz();\n}\n\n// GOOD\nif (isValid) {\n    foo();\n} else if (quux \u003c 0) {\n    bar();\n    baz();\n}\n\n// BAD\nfor(const foo of listFoo) {\n    bar(foo);\n}\n\n// GOOD\nfor (const foo of listFoo) {\n    bar(foo);\n}\n```\n\n### Do not new line before ```else``` or ```else if```\n\n```javascript\n// BAD\nif (isFoo(bar)) {\n    foo();\n}\nelse {\n    bar();\n}\n\n// GOOD\nif (isFoo(bar)) {\n    foo();\n} else {\n    bar();\n}\n\n// BAD\nif (isFoo(bar)) {\n    foo();\n} else if (quux \u003e baz)\n{\n    bar();\n}\nelse {\n    bar();\n    barBaz();\n}\n\n// GOOD\nif (isFoo(bar)) {\n    foo();\n} else if (quux \u003e baz) {\n    bar();\n} else {\n    bar();\n    barBaz();\n}\n``` \n\n## Naming\n\nNaming should be expressive. It should be maximally clear and avoid unnecessary abbreviations.\n\n*ClassName* should be same as *ClassName*.js. Avoid multiple classes per file.\n*ClassName* should begin with Letter in upper case.\n```javascript\n// GOOD\nThingsStore.js\nLogger.js\n```\n\n*methodName* should be verbs like and be in *camelCase*\n```javascript\n// GOOD\nsumbitMessage(message) { /* */ }\nsave(data) {/* */ }\nhasMessages() { /* */ }\n```\n\n*variableName* should be in *camelCase*\n```javascript\n// GOOD\nlet store = new Store();\nlet formatParser = getParser();\n```\n\n*ENUMERIC_CONSTANTS* should be *ALL_IN_UPPER_CASE*\n```javascript\n// GOOD\nconst MODE_EDIT = 'MODE_EDIT';\nconst PARSER_ID_MARKDOWN = 14;\n```\n\nBoolean variables and methods who returns Boolean values should contains verb prefix (```has```, ```is```, ```should```, etc.)\n```javascript\n// GOOD\nconst isValid = isEmail(email);\n\n// GOOD\nlet canProceedFlow = this.getListLength() \u003e 0;\n\nisUserAuthorized() {\n    if ( /* */ ) {\n        return true;        \n    }\n}\n``` \n\n### Handlers naming\n\nTo make handlers organized keep following rules:  \n\nuse `handle` prefix for class members\n\nuse `on` prefix for component props\n\nuse action right away after prefix `onClickButton` no `onButtonClick`\n\nuse first-verb form of words in names\n\n```javascript\nexport class MyAwesomeComponent extends React.PureComponent {\n    \n    // ...\n    \n    // GOOD\n    handleClose = () =\u003e {\n        // event handler logic\n    };\n    \n    // GOOD\n    handleClickNextButton = event =\u003e {\n        // event handler logic\n    };\n    \n    // GOOD\n    handleClickPrevButton = event =\u003e {\n        // event handler logic\n    };\n    \n    // ALSO GOOD\n    handleConnectMediaStreamView = payload =\u003e {\n        // event handler logic\n    };\n    \n    // STILL GOOD\n    handleChangeStreamQuality = nextValue =\u003e {\n        // event handler logic\n    };\n    \n    render() {\n        return (\n            \u003cPanel closable onClose={this.handleClose}\u003e\n                \u003cMediaStreamView\n                    stream={this.getStream()}\n                    onConnect={this.handleConnectMediaStreamView}\n                    onChangeStreamQuality={this.handleChangeStreamQuality}\n                /\u003e\n                \u003cButton onClick={this.handleClickPrevButton}Prev\u003c/Button\u003e\n                \u003cButton onClick={this.handleClickNextButton}\u003eNext\u003c/Button\u003e\n            \u003c/Panel\u003e\n        );\n    }\n}\n```\n\n### renderXXX\n\nFor better navigation, we recommend to use `render` prefix for any method which returns JSX or component.  \n\n```javascript\nexport class MyCompositeComponent {\n    \n    // ...\n    \n    // GOOD\n    renderHeaderToolbar() {\n        return (\n            \u003cHeaderToolbar\u003e\n                \u003cAction name=\"like\"\u003eLike\u003c/Action\u003e\n                \u003cAction name=\"pin\"\u003ePin\u003c/Action\u003e\n                \u003cAction name=\"share\"\u003eShare\u003c/Action\u003e\n            \u003c/HeaderToolbar\u003e\n        );\n    }\n    \n    // GOOD\n    renderImageBlock() {\n        let {url, title, description} = this.props;\n        \n        return (\n            \u003cBlock\u003e\n                \u003ch3\u003e{title}\u003c/h3\u003e\n                \u003cp\u003e{description}\u003c/p\u003e\n                \u003cImage src={url} /\u003e\n            \u003c/Block\u003e\n        );\n    }\n    \n    // BAD - should be renderCommentsList\n    getCommentsList() {\n        let {id} = this.props;\n        \n        return \u003cResourceCommentsList resourceId={id} /\u003e;\n    }\n    \n    render() {\n        return (\n            \u003cdiv\u003e\n                {this.renderHeaderToolbar()}\n                {this.renderImageBlock()}\n                {this.getCommentsList()}\n            \u003c/div\u003e\n        );\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fringcentral%2Fringcentral-javascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fringcentral%2Fringcentral-javascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fringcentral%2Fringcentral-javascript/lists"}