{"id":23138249,"url":"https://github.com/softlayer/ember-style-guide","last_synced_at":"2025-04-04T09:44:03.150Z","repository":{"id":33901018,"uuid":"37616099","full_name":"softlayer/ember-style-guide","owner":"softlayer","description":null,"archived":false,"fork":false,"pushed_at":"2017-08-04T14:44:27.000Z","size":84,"stargazers_count":40,"open_issues_count":6,"forks_count":9,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-02-09T20:26:58.406Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"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/softlayer.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":"2015-06-17T19:25:54.000Z","updated_at":"2022-05-04T13:35:25.000Z","dependencies_parsed_at":"2022-09-04T11:01:32.851Z","dependency_job_id":null,"html_url":"https://github.com/softlayer/ember-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softlayer%2Fember-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softlayer%2Fember-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softlayer%2Fember-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/softlayer%2Fember-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/softlayer","download_url":"https://codeload.github.com/softlayer/ember-style-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247157133,"owners_count":20893210,"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-12-17T13:10:17.841Z","updated_at":"2025-04-04T09:44:03.123Z","avatar_url":"https://github.com/softlayer.png","language":null,"readme":"\n# Ember.js Style Guide\n\nThis document extends the [JavaScript Style Guide](javascript.md) to provide\nEmber.js specific guidance.\n\nThese guidelines are specific to:\n\n* Ember 1.13.x\n* [ember-cli-jsdoc 1.3.1](https://github.com/softlayer/ember-cli-jsdoc/releases)\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in [RFC 2119](http://www.ietf.org/rfc/rfc2119.txt)\n\n\n## Table of Contents\n\n### Conventions\n\n* [Computed Properties](#computed-properties)\n* [Templates](#templates)\n\n\n### Grammar\n\n* [Type Checking](#type-checking)\n* [Comments](#comments)\n    * [JSDoc tags utilizing](#jsdoc-tags-utilizing)\n    * [General rules](#general-rules)\n    * [File Structure](#file-structure-1)\n    * [Modules](#modules)\n    * [Functions](#functions)\n    * [Constants](#constants)\n    * [Properties](#properties)\n    * [Acceptable Deviations](#acceptable-deviations)\n    * [Example of the tags in use](#example-of-the-tags-in-use)\n* [Newlines](#newlines)\n\n\n### Testing\n* [Ember.js Testing Guide](ember-testing.md)\n\n\n### Ember Data\n\n* [Be explicit with Ember Data attribute types](#be-explicit-with-ember-data-attribute-types)\n\n\n### File Structure\n\n* [File Structure](#file-structure-2)\n\n\n### Architecture Philosophy\n\n* [Where should DOM interactions occur in an Ember application?](#where-should-dom-interactions-occur-in-an-ember-application)\n* [Where to put actions in an Ember application](#where-to-put-actions-in-an-ember-application)\n* [Routes](#routes)\n* [Defining functions to be called when events are triggered](#defining-functions-to-be-called-when-events-are-triggered)\n* [Observers](#observers)\n\n\n---\n\n### Computed Properties\n\n* **MUST** always return a value\n    * At minimum a `null` value\n    * Other values are acceptable as appropriate\n\n\n### Templates\n\n* **MUST** use double quotes in all template syntax (e.g. attributes, property\nvalues, closure actions, etc) for non-bound values\n    * **MAY** use single quotes if passing a value that contains a double\n    quote, such as with `{{the-component label='The \"First\" One'}}`, though it\n    is **RECOMMENDED** to use HTML entities or bound values.\n\n\n### Type checking\n\n* **MUST** be performed via the use of `Ember.typeOf` for every type except for `Symbol`.\n* `Symbol` **MUST** be checked via `typeof`, due to\n[this Ember.js issue](https://github.com/emberjs/ember.js/issues/11673).\n\n\n### Comments\n\nSince JSDoc does not yet currently fully support ES6 syntax its conventions do\nnot always reflect the architecture of an Ember application. The style guides\nand examples in this section serve to remedy these discrepancies.\n\nThe [ember-cli-jsdoc](https://github.com/softlayer/ember-cli-jsdoc) addon\nshould be used to achieve the support presented in this guide.\n\n\n##### JSDoc tags utilizing\n\nOnly the following Block Tags are acceptable for use in documenting your code:\n\n* [@abstract](http://usejsdoc.org/tags-abstract.html)\n* [@augments](http://usejsdoc.org/tags-augments.html)\n* [@callback](http://www.usejsdoc.org/tags-callback.html)\n* [@constant](http://www.usejsdoc.org/tags-constant.html)\n* [@default](http://usejsdoc.org/tags-default.html)\n    * **MUST** be used for types other than String, Number, Array, Boolean, or\n    null\n    * For String, Number, Array, Boolean, and null types the\n    [default tag plugin](https://github.com/notmessenger/jsdoc-plugins#defaulttag)\n    will automatically add them\n* [@enum](http://www.usejsdoc.org/tags-enum.html)\n* [@example](http://usejsdoc.org/tags-example.html)\n* [@fires](http://www.usejsdoc.org/tags-fires.html)\n* [@function](http://www.usejsdoc.org/tags-function.html)\n    * Only set a name when contained within the \"actions\" hash. Then the name\n    **MUST** be preceded by the text of “actions:”  See the code example in the\n    \"[Example of the tags in use](#example-of-the-tags-in-use)\" section.\n* [@ignore](http://usejsdoc.org/tags-ignore.html)\n* [@listens](http://www.usejsdoc.org/tags-listens.html)\n    * **MUST NOT** use for `.on()` calls - the\n    [emberListensTag plugin](https://github.com/notmessenger/jsdoc-plugins#emberlistenstag)\n    will automatically add them\n    * The use of `.on()` calls is restricted.  See [Defining functions to be called when events are triggered](#defining-functions-to-be-called-when-events-are-triggered)\n* [@module](http://www.usejsdoc.org/tags-module.html)\n* [@override](http://www.usejsdoc.org/tags-override.html)\n* [@param](http://www.usejsdoc.org/tags-param.html)\n* [@private](http://www.usejsdoc.org/tags-private.html)\n* [@protected](http://www.usejsdoc.org/tags-protected.html)\n* [@returns](http://www.usejsdoc.org/tags-returns.html)\n* [@see](http://www.usejsdoc.org/tags-see.html)\n* [@throws](http://www.usejsdoc.org/tags-throws.html)\n* [@type](http://usejsdoc.org/tags-type.html)\n* [@typedef](http://usejsdoc.org/tags-typedef.html)\n\nOnly the following Inline Tags are acceptable for use in documenting your code:\n\n* [@link](http://www.usejsdoc.org/tags-inline-link.html)\n\nThese tags are not currently allowed for use but once JSDoc offers additional\nsupport for them aligning with our needs we will begin using them.  In the\nmeantime the `@augments` tag should be used.\n\n* [@mixes](http://usejsdoc.org/tags-mixes.html)\n* [@mixin](http://usejsdoc.org/tags-mixin.html)\n\n\n##### General rules\n\n* `@type` and `@param`\n    * types **MUST** be their most generic form (e.g. Array vs ember.Array,\n    Object vs ember.Object)\n    * a `*` refers to native JavaScript types\n    * more specific ember.* types **MUST** be used when warranted\n\n* `@param`\n    * **MUST** use the JSDoc syntax for optional parameters and default values\n    * **MUST NOT** use the Google Closure Compiler syntax\n\n* `@override`\n    * This tag indicates that a symbol overrides a symbol with the same name in\n    a parent class.  Given this definition it could be argued that properties\n    such as `classNameBindings`, `tagName`, and others would fall within this\n    category and that `beforeModel`, `setupController`, and similar certainly do.\n    Even with limited experience with Ember.js you will quickly learn to\n    recognize these properties and methods and realize that they are overriding\n    their parental definitions.  Therefore, to reduce the tediousness of having\n    to declare this tag in all of these places then, the following rules are to\n    be observed:\n        * This tag **MUST NOT** be used in Route or Component objects\n        * This tag **MUST** be used as appropriate in all other locations (i.e.\n        Ember Data application adapter)\n\n* It is **RECOMMENDED** to alphabetize the contents of the `@param`, `@type`,\nand `@returns` tags when multiple types are represented.\n\n\n##### File structure\n\nThis commenting structure **MUST** be used as a template when creating new\nComponent, Controller, Mixin, or Route files.  Route files will not contain all\nof the represented structures. The \"[File Structure](#file-structure-2)\" Section\ndescribes what should be placed in each section.\n\n```\n...({\n\n    // -------------------------------------------------------------------------\n    // Dependencies\n\n\n    // -------------------------------------------------------------------------\n    // Attributes\n\n\n    // -------------------------------------------------------------------------\n    // Actions\n\n\n    // -------------------------------------------------------------------------\n    // Events\n\n\n    // -------------------------------------------------------------------------\n    // Properties\n\n\n    // -------------------------------------------------------------------------\n    // Observers\n\n\n    // -------------------------------------------------------------------------\n    // Methods\n\n});\n```\n\n##### Modules\n\n* **MUST** have a DocBlock immediately preceding the definition\n* A short description...\n    * ... **MUST** be present if there are no other DocBlocks in the file\n    * ... **MAY** be included in all other scenarios as appropriate\n* **MAY** contain a long description\n* **MUST** contain a `@module` tag, listed as the first one\n    * **MUST NOT** be followed by a value\n* **MAY** contain any of these tags:\n    * @augments\n    * @example\n    * @see\n    * @link\n* **MUST NOT** contain any other tags\n\n```javascript\nimport Ember from 'ember';\nimport TooltipEnabled from 'sl-ember-components/mixins/sl-tooltip-enabled';\n\n/**\n * Short description\n *\n * A longer description that\n * spans multiple lines\n *\n * @module\n * @augments ember/Component\n * @augments sl-ember-components/mixins/sl-tooltip-enabled\n */\nexport default Ember.Component.extend( TooltipEnabled, {\n    ...\n});\n```\n\n##### Functions\n\n* **MUST** have a DocBlock immediately preceding the definition\n* **SHOULD** contain a short description\n* **MAY** contain a long description\n* **MUST** contain\n    * @function\n    * @override IF overriding a previously-defined function\n    * @returns\n* **MAY** contain any of these tags:\n    * @abstract\n    * @callback\n    * @example\n    * @listens\n    * @param\n    * @private\n    * @protected\n    * @see\n    * @throws\n* **MUST NOT** contain any other tags\n\n```javascript\n/*\n * @override\n * @function\n * @returns {undefined}\n */\nconfig: function() {...},\n\n/*\n * @function\n * @param {Number} first\n * @param {Number} second\n * @returns {Number}\n */\nadd: function( first, second ) {...}\n```\n\n##### Constants\n\n* **MUST** have a DocBlock immediately preceding the definition\n* **SHOULD** contain a short description\n* **MAY** contain a long description\n* **MUST** contain\n    * @constant\n* **SHOULD** contain\n    * @default if a non-simple type\n* **MAY** contain\n    * @example\n    * @link\n    * @see\n* **MUST NOT** contain any other tags\n\n```javascript\n/**\n * Number of months in a year\n *\n * @constant {Number}\n */\nnumberOfMonths: 12\n```\n\n##### Properties\n\n* **MUST** have a DocBlock immediately preceding the definition\n* **SHOULD** contain a short description\n* **MAY** contain a long description\n* **MUST** contain\n    * @type\n* **SHOULD** contain\n    * @default if a non-simple type\n* **MAY** contain\n    * @example\n    * @link\n    * @private\n    * @protected\n    * @see\n* **MUST NOT** contain any other tags\n\n```javascript\n/*\n * @override\n * @type {String}\n */\nname: 'configuration',\n\n/**\n * String representing the full timezone name\n *\n * @type {String}\n */\ntimezone: null,\n\n/**\n * Emergency Notification model\n *\n * @type {?Array.\u003cmodule:app/models/emergency-notification\u003e}\n */\nemergencyNotifications: null\n```\n\n##### Acceptable Deviations\n\nTo lessen the burden of creating documentation in scenarios where it does not\nadd any value, it is not required to create full DocBlocks in the following\nscenarios:\n\n* Within...\n    * Ember Components\n    * Ember Controllers\n* For...\n    * dependencies\n    * attributes\n    * actions hash (NOT the individual actions!)\n\nIn these scenarios a shortened, single-line comment containing the `@type` tag\nis all that is needed.\n\n```javascript\nimport Ember from 'ember';\nimport TooltipEnabled from 'sl-ember-components/mixins/sl-tooltip-enabled';\n\n/**\n* @module\n* @augments ember/Component\n* @augments sl-ember-components/mixins/sl-tooltip-enabled\n*/\nexport default Ember.Component.extend( TooltipEnabled, {\n\n    // -------------------------------------------------------------------------\n    // Dependencies\n\n    // -------------------------------------------------------------------------\n    // Attributes\n\n    /** @type {String[]} */\n    classNames: [\n        'alert',\n        'sl-alert'\n    ],\n\n    /** @type {String[]} */\n    classNameBindings: [\n        'themeClassName',\n        'dismissable:alert-dismissable'\n    ],\n\n    /** @type {String} */\n    ariaRole: 'alert',\n\n    // -------------------------------------------------------------------------\n    // Actions\n\n    /** @type {Object} */\n    actions: {\n\n        /**\n         * Trigger a bound \"dismiss\" action when the alert is dismissed\n         *\n         * @function actions:dismiss\n         * @returns {undefined}\n         */\n        dismiss: function() {\n            this.sendAction( 'dismiss' );\n        }\n    },\n\n    // -------------------------------------------------------------------------\n    // Events\n\n    // -------------------------------------------------------------------------\n    // Properties\n\n    // -------------------------------------------------------------------------\n    // Observers\n\n    // -------------------------------------------------------------------------\n    // Methods\n\n});\n```\n\n##### Example of the tags in use\n\n```javascript\nimport Ember from 'ember';\nimport TooltipEnabled from 'sl-ember-components/mixins/sl-tooltip-enabled';\n\n/**\n * The provided command line arguments\n *\n * @ignore\n * @type {Array.\u003cString, *\u003e}\n */\nvar argv = require( 'minimist' )( process.argv.slice( 2 ) );\n\n/**\n * @module\n * @augments ember/Component\n * @augments module:app/mixins/the-mixin\n * @augments sl-ember-components/mixins/sl-tooltip-enabled\n */\nexport default Ember.Component.extend( TooltipEnabled, {\n\n    // -------------------------------------------------------------------------\n    // Dependencies\n\n    // -------------------------------------------------------------------------\n    // Attributes\n\n    /** @type {String[]} */\n    classNames: [\n        'alert'\n    ],\n\n    // -------------------------------------------------------------------------\n    // Actions\n\n    /** @type {Object} */\n    actions: {\n\n        /**\n         * Trigger a bound \"dismiss\" action when the alert is dismissed\n         *\n         * @function actions:dismiss\n         * @returns {undefined}\n         */\n        dismiss: function() {\n            this.sendAction( 'dismiss' );\n        }\n    },\n\n    // -------------------------------------------------------------------------\n    // Events\n\n    // -------------------------------------------------------------------------\n    // Properties\n\n    /**\n     * Access level\n     *\n     * @constant\n     */\n    accessLevel = 1,\n\n    /**\n     * @typedef {Object.\u003cString, Boolean\u003e} ActionDivider\n     * @property {Boolean} divider Must be set to true\n     */\n\n    /**\n     * @typedef {Object} ActionOption\n     * @property {String} action\n     * @property {String} label\n     */\n\n    /**\n     * Definition for the Actions button\n     *\n     * @example\n     *  [{ divider: true },\n     *  { action: 'cancelItem', label: 'Cancel Device' }]\n     *\n     * @type {Array.\u003cActionDivider|ActionOption\u003e}\n     */\n    actionsButton: [\n        { divider: true },\n        { action: 'cancelItem', label: 'Cancel Device' }\n    ],\n\n    /**\n     * Whether to make the alert dismissible or not\n     *\n     * @type {Boolean}\n     */\n    dismissible: false,\n\n    /**\n     * Array of filter objects\n     *\n     * @type {ember/Array}\n     * @default ember/Array\n     */\n    filters: Ember.A(),\n\n    /**\n     * Alias for application loading flag\n     *\n     * @type {module:app/controllers/application~isLoading}\n     */\n    isLoading: Ember.computed.alias( 'controllers.application.isLoading' ),\n\n    // -------------------------------------------------------------------------\n    // Observers\n\n    /**\n     * Initialize children array\n     *\n     * @function\n     * @returns {undefined}\n     */\n    init() {\n        this._super( ...arguments );\n\n        this.set( 'children', [] );\n    },\n\n    /**\n     * React to route changes\n     *\n     * @function\n     * @returns {undefined}\n     */\n    reactToRouteChange: Ember.observer(\n        'currentRouteName',\n        function() {\n            ...\n        }\n    ),\n\n    // -------------------------------------------------------------------------\n    // Methods\n\n    /**\n     * Example callback definition\n     *\n     * @callback thisIsACallback\n     * @param {Number} responseCode\n     * @param {String} responseMessage\n     */\n\n    /**\n     * Use the callback\n     *\n     * @function\n     * @param {thisIsACallback} callback\n     * @returns {undefined}\n     */\n    usingTheCallback: function( callback ) {\n        ...\n    },\n\n    /**\n     * Returns lowercase path when ember-cli-mirage is not enabled\n     *\n     * @override\n     * @param {String} type\n     * @returns {String}\n     */\n    pathForType: function( type ) {\n        type = this._super( ...arguments );\n        return config.isEmberCliMirageEnabled ? type : type.toLowerCase();\n    },\n\n    /**\n     * The generated Bootstrap \"theme\" style class for the alert\n     *\n     * @function\n     * @returns {String} Defaults to \"alert-info\"\n     */\n    themeClassName: function() {\n        return 'alert-' + this.get( 'theme' );\n    }.property( 'theme' ),\n\n    /**\n     * Does some secret-squirrel stuff\n     *\n     * Also refer to {@link module:app/components/info-button} for more details\n     *\n     * @private\n     * @function\n     * @param {ember/Array} input\n     * @param {String} [modifier]\n     * @throws {ember/Error} If `input` is empty\n     * @returns {ember/RSVP.Promise} Resolution of promise contains possible types of String, Number, Boolean\n     */\n    secretStuff: function( input, modifier ) {\n        Ember.assert(\n            '`input` must not be empty',\n            !Ember.isEmpty( input )\n        );\n\n        return Ember.RSVP.Promise();\n    },\n\n    /**\n     * @abstract\n     * @function\n     * @returns {undefined}\n     */\n    showHandler() {}\n});\n\n/**\n * @memberof module:addon/components/sl-grid\n * @enum {String}\n * @property {String} LEFT \"left\"\n * @property {String} RIGHT \"right\"\n */\nexport const ColumnAlign = Object.freeze({\n    LEFT: 'left',\n    RIGHT: 'right'\n});\n```\n\n\n### Newlines\n\n* Newlines **MUST** be employed in the following scenarios:\n    * When defining:\n        * attributeBindings\n        * classNames\n        * classNameBindings\n    * When using:\n        * Ember.observer\n        * Ember.on\n        * Ember.computed\n        * Ember.assert\n        * In assert statements in tests\n\n```javascript\n// SAMPLE: attributeBindings, classNames, classNameBindings\n\nattributeBindings: [\n    'data-target',\n    'data-toggle',\n    'disabled',\n    'type'\n],\n\nclassNames: [\n    'form-group'\n],\n\nclassNameBindings: [\n    'themeClassName',\n    'dismissable:alert-dismissable'\n]\n\n\n// SAMPLE: Ember.observer, Ember.computed\n\nupdateData: Ember.observer(\n    'series',\n    function() {\n        ...\n    }\n),\n\nthemeClassName: Ember.computed(\n    'theme',\n    'anotherTheme',\n    function() {\n        ...\n    }\n)\n\n\n// SAMPLE: Test assertions\n\nassert.strictEqual(\n    component.get( 'dismissable' ),\n    true,\n    'Component is dismissable'\n);\n```\n\n* The requirement to use soft tabs set to 4 spaces is intended to be applied\nto JavaScript files but should also be applied to JSON files whenever possible.\nA scenario where this is not possible though, for example, is in the\n`package.json` file. Whenever the `-save` or `--save-dev` flags are used the\nfile is re-created with 2 spaces so there is no need to try to maintain 4 spaces.\n\n\n\n### Be explicit with Ember Data attribute types\n\nEven though Ember Data can be used without using explicit types in `attr()`,\nalways supply an attribute type to ensure the right data transform is used\n\n```javascript\n// Good\nexport default DS.Model.extend({\n    firstName: DS.attr( 'string' ),\n    jerseyNumber: DS.attr( 'number' )\n});\n\n\n// Bad\nexport default DS.Model.extend({\n    firstName: DS.attr(),\n    jerseyNumber: DS.attr()\n});\n```\n\n\n### File Structure\nThe contents in a file **MUST** be organized in the following order for each\ntype that exists:\n\n* Dependencies\n    * services\n* Attributes\n    * arrangedContent\n    * attributeBindings\n    * classNames\n    * classNameBindings\n    * defaultLayout / layout / layoutName\n    * queryParams\n    * sortBy\n    * tagName\n    * template / templateName\n* Actions\n* Events\n* Properties\n* Observers\n* Methods\n\nWithin each of the represented structures above the attributes, action,\nproperties, etc **MUST** be listed alphabetically in their respective sections.\n\n\n### Where should DOM interactions occur in an Ember application?\n\n* **SHOULD** be contained in the Component whenever possible.  This is the\nclosest layer to where the DOM was likely created.\n* If the interaction needs to be shared across Components or if there is an\napplication-specific implementation required, then routes **SHOULD** be used.\n\n\n### Where to put actions in an Ember application\n\n* As close to where things are \"happening\".  This is most usually the Component.\n* If the action needs to be shared with other Components or Routes, place it in\nthe lowest-level of shared access between the items requiring shared access.\n\n\n### Routes\n\n* Manage application state\n* Can contain application-specific DOM knowledge and interaction, though\nComponents should be the first place such needs should be implemented\n\n\n### Defining functions to be called when events are triggered\n\n* From [Proper Use Of Ember on()](http://notmessenger.com/proper-use-of-ember-on):\n    * `on()` **SHOULD NOT** be used *except* for in cases of *very rare* exception\n    * `this._super( ...arguments )` **MUST** always be called\n    * In `init()` the call to `this._super( ...arguments )` should be before\n    using this for anything else.\n\n\n### Observers\n\nA good pattern to follow for improved performance is the one presented in the\nvideo at [https://youtu.be/cp1Jk92ve2s?t=1097](https://youtu.be/cp1Jk92ve2s?t=1097)\nfrom timestamp 18:18 to 20:15\n","funding_links":[],"categories":["Packages"],"sub_categories":["Styleguides"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftlayer%2Fember-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoftlayer%2Fember-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoftlayer%2Fember-style-guide/lists"}