Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Enforcing coding standards in a JS project

Enforcing coding standards in a JS project

Talk given at JSConf Budapest (Budapest, Hungary) - May 2015

Sebastiano Armeli

May 14, 2015
Tweet

More Decks by Sebastiano Armeli

Other Decks in Programming

Transcript

  1. ENFORCING 
 CODING 
 STANDARDS 
 in a JS PROJECT

    Sebastiano Armeli @sebarmeli 14/05/2015 - JSConf BD
  2. to enforce verb (used with object), enforced, enforcing. to put

    or keep in force; to compel obedience to: “to enforce a rule; Traffic laws will be strictly enforced.”
  3. standard noun a rule or principle that is used as

    a basis for judgment: “They tried to establish standards for a new approach.”
  4. commit 111111 Author: Sebastiano Armeli Date: Sun Dec 21 22:08:00

    2014 -0500 adding something commit 2222222 Author: Sebastiano Armeli Date: Thu Dec 18 15:35:39 2014 -0500 it will work, trust me
  5. ! IDE (Editorconfig) ! Quality & Style tools (JSHint, JSCS,

    ESLint) ! Git commits standards ! Build tools (Grunt, Gulp) ! Language - Transpiler (ES6 - Babel) ! Complexity tool (Plato) Summary 1/2
  6. ! Testing (Mocha, Karma) ! Automated Release Flow (Jenkins, NPM)

    ! Setup script ! Documentation Summary 2/2
  7. root = true [*] indent_style = space indent_size = 2

    end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true .editorconfig
  8. { "curly": true, "eqeqeq": false, "latedef": true, "newcap": true, "noarg":

    true, "sub": true, "boss": true, "indent": 2, "noempty": true, "expr": true, "eqnull": true, "esnext": true, "browser": true, "white": true, "undef": true, "predef": [ “require”, "module", “exports", "CustomEvent"] } .jshintrc
  9. { "curly": true, "eqeqeq": false, "latedef": true, "newcap": true, "noarg":

    true, "sub": true, "boss": true, "indent": 2, "noempty": true, "expr": true, "eqnull": true, "esnext": true, "browser": true, "white": true, "undef": true, "predef": [ “require”, "module", “exports", "CustomEvent"] } .jshintrc
  10. { "curly": true, "eqeqeq": false, "latedef": true, "newcap": true, "noarg":

    true, "sub": true, "boss": true, "indent": 2, "noempty": true, "expr": true, "eqnull": true, "esnext": true, "browser": true, "white": true, "undef": true, "predef": [ “require”, "module", “exports", "CustomEvent"] } .jshintrc
  11. { "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try"],

    "disallowImplicitTypeConversion": ["string"], "disallowMultipleLineBreaks": true, "disallowMixedSpacesAndTabs": true, "disallowKeywords": ["with"], "disallowMultipleVarDecl": true, "disallowTrailingComma": true, "disallowTrailingWhitespace": true, "maximumLineLength": 80, "esnext": true } .jscsrc
  12. { "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try"],

    "disallowImplicitTypeConversion": ["string"], "disallowMultipleLineBreaks": true, "disallowMixedSpacesAndTabs": true, "disallowKeywords": ["with"], "disallowMultipleVarDecl": true, "disallowTrailingComma": true, "disallowTrailingWhitespace": true, "maximumLineLength": 80, "esnext": true } .jscsrc
  13. { "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try"],

    "disallowImplicitTypeConversion": ["string"], "disallowMultipleLineBreaks": true, "disallowMixedSpacesAndTabs": true, "disallowKeywords": ["with"], "disallowMultipleVarDecl": true, "disallowTrailingComma": true, "disallowTrailingWhitespace": true, "maximumLineLength": 80, "esnext": true } .jscsrc
  14. rules: space-before-blocks: 2 eqeqeq: [2, 'smart'] curly: [2, 'multi-line'] quotes:

    [2, 'single'] space-after-keywords: 2 no-unused-vars: [2, args: none] no-comma-dangle: 2 no-unused-expressions: 0 no-multi-spaces: 2 …
  15. rules: space-before-blocks: 2 eqeqeq: [2, 'smart'] curly: [2, 'multi-line'] quotes:

    [2, 'single'] space-after-keywords: 2 no-unused-vars: [2, args: none] no-comma-dangle: 2 no-unused-expressions: 0 no-multi-spaces: 2 …
  16. no-unused-vars: [2, args: none] function test1(a, b) { var c,

    d = 2; return a + d; } test1(1, 2); Error!! function test2(a, b, c) { return a + b; } test2(1, 2); Ok
  17. "use strict”; module.exports = function(context) { return { "NewExpression": function(node)

    { if (node.callee.name === "Object") { context.report(node, “Error …”); } } }; }; no-new-object.js let obj = new Object(); let obj = {};
  18. "use strict”; module.exports = function(context) { return { "NewExpression": function(node)

    { if (node.callee.name === "Object") { context.report(node, “Error …”); } } }; }; no-new-object.js let obj = {};
  19. Git Commits (feat | fix | docs | style |

    refactor | test | chore)(<scope>): <description> E.g. doc(readme): update with additional links.
  20. Changelog conventional-changelog Changelog.md commit 7aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Author: Sebastiano Armeli <[email protected]> Date:

    Tue Jan 6 11:48:59 2015 -0500 refactor(BaseAd): Removed addToStreamTime method from BaseAd commit 7bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb Author: Sebastiano Armeli <[email protected]> Date: Tue Jan 6 00:04:49 2015 -0500 style(gpt): rearrange for better readability
  21. var gulp = require('gulp'); var plugins = require(‘gulp-load-plugins')(); … gulp.task('eslint',

    function() { return gulp.src(['src/**/*.js']) .pipe(plugins.eslint()) .pipe(plugins.eslint.format()) .pipe(plugins.eslint.failOnError()); }); … gulpfile.js
  22. describe('#_onContainerResume', function() { it('should call play when container resumes', function()

    { videoAd.views.set(mockedVideoAdMetadata.id, { play: function() {}, hasBeenPlayed: true }); sinon.stub(videoAd.views.get(mockedVideoAdMetadata.id), 'play'); videoAd._onContainerResume(); expect(videoAd.views.get(mockedVideoAdMetadata.id).play).to.have .been.called; }); });
  23. module.exports = function(config) { config.set({ basePath: '../', frameworks: ['mocha', 'fixture'],

    files: [ …. ], browsers: ‘Chrome’, singleRun: false, preprocessors: { '**/*.html': ['html2js'], '**/*.json': ['html2js'] }, sauceLabs: { … } }); }; karma.conf.js
  24. module.exports = function(config) { config.set({ basePath: '../', frameworks: ['mocha', 'fixture'],

    files: [ …. ], browsers: ‘Chrome’, singleRun: false, preprocessors: { '**/*.html': ['html2js'], '**/*.json': ['html2js'] }, sauceLabs: { … } }); }; karma.conf.js
  25. module.exports = function(config) { config.set({ basePath: '../', frameworks: ['mocha', 'fixture'],

    files: [ …. ], browsers: ‘Chrome’, singleRun: false, preprocessors: { '**/*.html': ['html2js'], '**/*.json': ['html2js'] }, sauceLabs: { … } }); }; karma.conf.js
  26. Sebastiano Armeli <…@spotify.com> Brice Lin <[email protected]> <…@gmail.com> Jason Palmer <[email protected]>

    <[email protected]> Joseph Werle <[email protected]> <…@gmail.com> Olof Kihlberg <…@spotify.com> Sigfrido Chirinos <…@spotify.com> .mailmap