├── .eslintignore ├── example ├── .jshintrc ├── entry.js └── webpack.config.js ├── test ├── .jshintrc ├── fixtures │ ├── .jshintrc │ ├── default.js │ └── failure.js ├── webpack.config.js └── loader.test.js ├── .gitattributes ├── .prettierrc ├── .jshintrc ├── codecov.yml ├── CHANGELOG.md ├── .github ├── CODEOWNERS ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE.md └── CONTRIBUTING.md ├── .gitignore ├── .editorconfig ├── .eslintrc.js ├── .babelrc ├── commitlint.config.js ├── LICENSE ├── lib ├── loadRcConfig.js └── index.js ├── package.json ├── .circleci └── config.yml └── README.md /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /test/trash 4 | -------------------------------------------------------------------------------- /example/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "latedef": true, 3 | "undef": true 4 | } -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.jshintrc", 3 | "quotmark": true 4 | } 5 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | yarn.lock -diff 2 | package-lock.json -diff 3 | * text=auto 4 | bin/* eol=lf -------------------------------------------------------------------------------- /test/fixtures/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.jshintrc", 3 | "quotmark": "double" 4 | } 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "arrowParens": "always" 5 | } 6 | -------------------------------------------------------------------------------- /example/entry.js: -------------------------------------------------------------------------------- 1 | console.log("Test"); 2 | 3 | x_a(); 4 | 5 | function x_a() { 6 | // used before defined 7 | } -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "expr": true, 4 | "shadow": true, 5 | "mocha": true, 6 | "node": true 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/default.js: -------------------------------------------------------------------------------- 1 | "use strict"; // eslint-disable-line 2 | 3 | /* eslint-disable */ 4 | 5 | if (true) "WEB"; 6 | else "PACK"; 7 | -------------------------------------------------------------------------------- /test/fixtures/failure.js: -------------------------------------------------------------------------------- 1 | "use strict"; // eslint-disable-line 2 | 3 | /* eslint-disable */ 4 | 5 | if (true) "WEB" 6 | else "PACK" 7 | -------------------------------------------------------------------------------- /test/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mode: 'development', 3 | output: { 4 | path: `${__dirname}/trash/`, 5 | filename: 'bundle.js', 6 | }, 7 | module: {}, 8 | }; 9 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | branch: master 3 | coverage: 4 | precision: 2 5 | round: down 6 | range: 70...100 7 | status: 8 | project: 'no' 9 | patch: 'yes' 10 | comment: 'off' 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These are the default owners for everything in 2 | # webpack-contrib 3 | @webpack-contrib/org-maintainers 4 | 5 | # Add repository specific users / groups 6 | # below here for libs that are not maintained by the org. 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /example/out 3 | /test/trash 4 | *.log 5 | logs 6 | npm-debug.log* 7 | .eslintcache 8 | /coverage 9 | /dist 10 | /local 11 | /reports 12 | /node_modules 13 | .DS_Store 14 | Thumbs.db 15 | .idea 16 | .vscode 17 | *.sublime-project 18 | *.sublime-workspace 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | insert_final_newline = false 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | plugins: ['prettier'], 4 | extends: ['@webpack-contrib/eslint-config-webpack'], 5 | rules: { 6 | 'prettier/prettier': [ 7 | 'error', 8 | { singleQuote: true, trailingComma: 'es5', arrowParens: 'always' }, 9 | ], 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | module.exports = { 3 | entry: "./entry.js", 4 | output: { 5 | path: path.join(__dirname, "out"), 6 | filename: "bundle.js" 7 | }, 8 | module: { 9 | preLoaders: [ 10 | { test: /\.js$/, loader: path.join(__dirname, "..") } 11 | ] 12 | }, 13 | jshint: { 14 | camelcase: true 15 | } 16 | }; -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "useBuiltIns": true, 7 | "targets": { 8 | "node": "6.9.0" 9 | }, 10 | "exclude": [ 11 | "transform-async-to-generator", 12 | "transform-regenerator" 13 | ] 14 | } 15 | ] 16 | ], 17 | "plugins": [ 18 | [ 19 | "transform-object-rest-spread", 20 | { 21 | "useBuiltIns": true 22 | } 23 | ] 24 | ], 25 | "env": { 26 | "test": { 27 | "presets": [ 28 | "env" 29 | ], 30 | "plugins": [ 31 | "transform-object-rest-spread" 32 | ] 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const Configuration = { 3 | extends: ['@commitlint/config-conventional'], 4 | 5 | rules: { 6 | 'body-leading-blank': [1, 'always'], 7 | 'footer-leading-blank': [1, 'always'], 8 | 'header-max-length': [2, 'always', 72], 9 | 'scope-case': [2, 'always', 'lower-case'], 10 | 'subject-case': [2, 'never', ['sentence-case', 'start-case', 'pascal-case', 'upper-case']], 11 | 'subject-empty': [2, 'never'], 12 | 'subject-full-stop': [2, 'never', '.'], 13 | 'type-case': [2, 'always', 'lower-case'], 14 | 'type-empty': [2, 'never'], 15 | 'type-enum': [2, 'always', [ 16 | 'build', 17 | 'chore', 18 | 'ci', 19 | 'docs', 20 | 'feat', 21 | 'fix', 22 | 'perf', 23 | 'refactor', 24 | 'revert', 25 | 'style', 26 | 'test', 27 | ], 28 | ], 29 | }, 30 | }; 31 | 32 | module.exports = Configuration; 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | 11 | This PR contains a: 12 | 13 | - [ ] **bugfix** 14 | - [ ] new **feature** 15 | - [ ] **code refactor** 16 | - [ ] **test update** 17 | - [ ] **typo fix** 18 | - [ ] **metadata update** 19 | 20 | ### Motivation / Use-Case 21 | 22 | 27 | 28 | ### Breaking Changes 29 | 30 | 34 | 35 | ### Additional Info 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright JS Foundation and other contributors 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | 'Software'), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 11 | 12 | * Operating System: 13 | * Node Version: 14 | * NPM Version: 15 | * webpack Version: 16 | * jshint-loader Version: 17 | 18 | 19 | 20 | This issue is for a: 21 | 22 | - [ ] **bug** 23 | - [ ] **feature** request 24 | - [ ] **modification** request 25 | 26 | ### Code 27 | 28 | ##### CLI Command 29 | 30 | ```bash 31 | # paste the CLI command you're using. if this isn't applicable, it's safe to remove. 32 | $ {the command} 33 | ``` 34 | 35 | ##### webpack.config.js 36 | 37 | ```js 38 | // If your bitchin' code blocks are over 20 lines, please paste a link to a gist 39 | // (https://gist.github.com). 40 | ``` 41 | 42 | ```js 43 | // additional code, HEY YO remove this block if you don't need it 44 | ``` 45 | 46 | ### Expected Behavior 47 | 48 | 49 | 50 | ### Actual Behavior 51 | 52 | 53 | 54 | ### How Do We Reproduce? 55 | 56 | 62 | 63 | ### New Feature Use Case 64 | 65 | -------------------------------------------------------------------------------- /lib/loadRcConfig.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const RcLoader = require('rcloader'); 4 | const stripJsonComments = require('strip-json-comments'); 5 | 6 | const shjs = require('shelljs'); 7 | const _ = require('lodash'); 8 | 9 | // setup RcLoader 10 | const rcLoader = new RcLoader('.jshintrc', null, { 11 | loader(path) { 12 | return path; 13 | }, 14 | }); 15 | 16 | // eslint-disable-next-line consistent-return 17 | function loadRcConfig(callback) { 18 | const sync = typeof callback !== 'function'; 19 | 20 | if (sync) { 21 | const fp = rcLoader.for(this.resourcePath); 22 | if (typeof fp !== 'string') { 23 | // no .jshintrc found 24 | return {}; 25 | } 26 | this.addDependency(fp); 27 | const options = loadConfig(fp); 28 | delete options.dirname; 29 | return options; 30 | } 31 | 32 | // eslint-disable-next-line consistent-return 33 | rcLoader.for(this.resourcePath, (err, fp) => { 34 | if (typeof fp !== 'string') { 35 | // no .jshintrc found 36 | return callback(null, {}); 37 | } 38 | 39 | this.addDependency(fp); 40 | const options = loadConfig(fp); 41 | delete options.dirname; 42 | callback(err, options); 43 | }); 44 | } 45 | 46 | function loadConfig(fp) { 47 | if (!fp) { 48 | return {}; 49 | } 50 | 51 | if (!shjs.test('-e', fp)) { 52 | throw new Error(`Can't find config file: ${fp}`); 53 | } 54 | 55 | try { 56 | let config = JSON.parse(stripJsonComments(shjs.cat(fp))); 57 | config.dirname = path.dirname(fp); 58 | 59 | if (config.extends) { 60 | const baseConfig = loadConfig( 61 | path.resolve(config.dirname, config.extends) 62 | ); 63 | // eslint-disable-next-line consistent-return 64 | config = _.merge({}, baseConfig, config, (a, b) => { 65 | if (_.isArray(a)) { 66 | return a.concat(b); 67 | } 68 | }); 69 | delete config.extends; 70 | } 71 | 72 | return config; 73 | } catch (err) { 74 | throw new Error(`Can't parse config file: ${fp}\nError:${err}`); 75 | } 76 | } 77 | 78 | module.exports = loadRcConfig; 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jshint-loader", 3 | "version": "0.8.4", 4 | "description": "A JSHint loader for webpack", 5 | "license": "MIT", 6 | "repository": "webpack-contrib/jshint-loader", 7 | "author": "Tobias Koppers @sokra", 8 | "homepage": "https://github.com/webpack-contrib/jshint-loader", 9 | "bugs": "https://github.com/webpack-contrib/jshint-loader/issues", 10 | "bin": "", 11 | "main": "lib/index.js", 12 | "engines": { 13 | "node": ">= 6.9.0 <7.0.0 || >= 8.9.0" 14 | }, 15 | "scripts": { 16 | "commitlint": "commitlint", 17 | "commitmsg": "commitlint -e $GIT_PARAMS", 18 | "lint": "eslint --cache src test", 19 | "ci:lint:commits": "commitlint --from=${CIRCLE_BRANCH} --to=${CIRCLE_SHA1}", 20 | "lint-staged": "lint-staged", 21 | "release": "standard-version", 22 | "release:ci": "conventional-github-releaser -p angular", 23 | "release:validate": "commitlint --from=$(git describe --tags --abbrev=0) --to=$(git rev-parse HEAD)", 24 | "security": "nsp check", 25 | "test": "jest --env=node", 26 | "test:watch": "jest --watch", 27 | "test:coverage": "jest --env=node --collectCoverageFrom='src/**/*.js' --coverage", 28 | "ci:lint": "npm run lint && npm run security", 29 | "ci:test": "npm run test -- --runInBand", 30 | "ci:coverage": "npm run test:coverage -- --runInBand", 31 | "defaults": "webpack-defaults" 32 | }, 33 | "files": [ 34 | "lib/" 35 | ], 36 | "peerDependencies": { 37 | "jshint": "^2.5.0", 38 | "webpack": "^4.5.0" 39 | }, 40 | "dependencies": { 41 | "@webpack-contrib/schema-utils": "^1.0.0-beta.0", 42 | "loader-utils": "^1.1.0", 43 | "lodash": "4.17.4", 44 | "rcloader": "=0.1.2", 45 | "shelljs": "0.7.6", 46 | "strip-json-comments": "0.1.x" 47 | }, 48 | "devDependencies": { 49 | "@commitlint/cli": "^6.1.3", 50 | "@commitlint/config-conventional": "^6.1.3", 51 | "@webpack-contrib/eslint-config-webpack": "^2.0.4", 52 | "babel-cli": "^6.26.0", 53 | "babel-jest": "^22.4.3", 54 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 55 | "babel-polyfill": "^6.26.0", 56 | "babel-preset-env": "^1.6.1", 57 | "conventional-github-releaser": "^2.0.2", 58 | "cross-env": "^5.1.4", 59 | "del": "^3.0.0", 60 | "del-cli": "^1.1.0", 61 | "eslint": "^4.19.1", 62 | "eslint-plugin-import": "^2.10.0", 63 | "eslint-plugin-prettier": "^2.6.0", 64 | "husky": "^0.14.3", 65 | "jest": "^22.4.3", 66 | "jshint": "^2.9.2", 67 | "lint-staged": "^7.0.4", 68 | "memory-fs": "^0.4.1", 69 | "mocha": "^3.0.2", 70 | "nsp": "^3.2.1", 71 | "pre-commit": "^1.2.2", 72 | "prettier": "^1.11.1", 73 | "should": "^10.0.0", 74 | "sinon": "^1.17.5", 75 | "standard-version": "^4.3.0", 76 | "webpack": "^4.5.0", 77 | "webpack-defaults": "^2.3.0" 78 | }, 79 | "keywords": [ 80 | "webpack" 81 | ], 82 | "pre-commit": "lint-staged", 83 | "lint-staged": { 84 | "*.js": [ 85 | "eslint --fix", 86 | "git add" 87 | ] 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/loader.test.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const webpack = require('webpack'); 4 | 5 | const loadRcConfig = require('../lib/loadRcConfig'); 6 | 7 | const config = require('./webpack.config'); 8 | 9 | describe('jshint loader', () => { 10 | let conf = {}; 11 | 12 | beforeEach(() => { 13 | conf = Object.assign({}, config, { 14 | entry: './test/fixtures/default.js', 15 | }); 16 | 17 | conf.module.rules = [ 18 | { 19 | test: /\.js$/, 20 | enforce: 'pre', 21 | exclude: /node_modules/, 22 | use: { 23 | loader: path.resolve(`${__dirname}/../lib/index`), 24 | options: {}, 25 | }, 26 | }, 27 | ]; 28 | }); 29 | 30 | test('should find and coalesce nested .jshintrc files', () => { 31 | const host = { 32 | resourcePath: conf.entry, 33 | addDependency() {}, 34 | }; 35 | expect(loadRcConfig.call(host)).toEqual({ 36 | bitwise: true, 37 | expr: true, 38 | shadow: true, 39 | mocha: true, 40 | node: true, 41 | quotmark: 'double', 42 | }); 43 | }); 44 | 45 | test('should respect & overwrite lint options in webpack config', (done) => { 46 | conf.module.rules[0].use.options.asi = true; 47 | 48 | webpack(conf, (err, stats) => { 49 | expect(stats.hasWarnings()).toBeFalsy(); 50 | expect(stats.hasErrors()).toBeFalsy(); 51 | done(); 52 | }); 53 | }); 54 | 55 | test('should emit errors when emitErrors is enabled', (done) => { 56 | conf.entry = './test/fixtures/failure.js'; 57 | conf.module.rules[0].use.options.emitErrors = true; 58 | 59 | webpack(conf, (err, stats) => { 60 | const hasErrors = stats.hasErrors(); 61 | const hasWarnings = stats.hasWarnings(); 62 | 63 | expect(hasErrors).toBeTruthy(); 64 | expect(hasWarnings).toBeFalsy(); 65 | done(); 66 | }); 67 | }); 68 | 69 | test('should stop compilation when failOnHint is enabled', (done) => { 70 | conf.bail = true; 71 | conf.entry = './test/fixtures/failure.js'; 72 | conf.module.rules[0].use.options = { 73 | emitErrors: true, 74 | failOnHint: true, 75 | }; 76 | 77 | webpack(conf, (err, stats) => { 78 | expect(stats.hasErrors()).toBeTruthy(); 79 | done(); 80 | }); 81 | }); 82 | 83 | // TODO: Write tests for context and arguments 84 | describe('custom transform', () => { 85 | let mockReporter; 86 | 87 | beforeEach(() => { 88 | mockReporter = jest.fn(); 89 | conf.entry = './test/fixtures/failure.js'; 90 | conf.module.rules[0].use.options.reporter = mockReporter; 91 | }); 92 | 93 | test('should call the transform function', (done) => { 94 | webpack(conf, () => { 95 | expect(mockReporter.mock.calls.length).toBeTruthy(); 96 | done(); 97 | }); 98 | }); 99 | }); 100 | 101 | describe('with default settings', () => { 102 | test('should emit warnings', (done) => { 103 | conf.entry = './test/fixtures/failure.js'; 104 | webpack(conf, (err, stats) => { 105 | const hasWarnings = stats.hasWarnings(); 106 | expect(hasWarnings).toBeTruthy(); 107 | done(); 108 | }); 109 | }); 110 | 111 | test('should not emit errors', (done) => { 112 | webpack(conf, (err, stats) => { 113 | const hasErrors = stats.hasErrors(); 114 | expect(hasErrors).toBeFalsy(); 115 | done(); 116 | }); 117 | }); 118 | }); 119 | }); 120 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License http://www.opensource.org/licenses/mit-license.php 3 | Author Tobias Koppers @sokra 4 | */ 5 | /* eslint guard-for-in: off, no-param-reassign: off */ 6 | const jshint = require('jshint').JSHINT; 7 | const loaderUtils = require('loader-utils'); 8 | 9 | const loadRcConfig = require('./loadRcConfig'); 10 | 11 | function jsHint(input, options) { 12 | // copy options to own object 13 | // if (this.options.jshint) { 14 | // for (const name in this.options.jshint) { 15 | // options[name] = this.options.jshint[name]; 16 | // } 17 | // } 18 | 19 | // copy query into options 20 | // const query = loaderUtils.getOptions(this) || {}; 21 | // for (const name in query) { 22 | // options[name] = query[name]; 23 | // } 24 | 25 | // copy globals from options 26 | const globals = {}; 27 | if (options.globals) { 28 | if (Array.isArray(options.globals)) { 29 | options.globals.forEach((g) => { 30 | globals[g] = true; 31 | }, this); 32 | } else { 33 | for (const g in options.globals) { 34 | globals[g] = options.globals[g]; 35 | } 36 | } 37 | delete options.globals; 38 | } 39 | 40 | // console.log('options', options); 41 | 42 | // move flags 43 | const { emitErrors, failOnHint, reporter } = options; 44 | delete options.emitErrors; 45 | delete options.failOnHint; 46 | delete options.reporter; 47 | 48 | // module system globals 49 | globals.require = true; 50 | globals.module = true; 51 | globals.exports = true; 52 | globals.global = true; 53 | globals.process = true; 54 | globals.define = true; 55 | 56 | const source = input.split(/\r\n?|\n/g); 57 | const result = jshint(source, options, globals); 58 | const { errors } = jshint; 59 | 60 | if (!result) { 61 | if (reporter) { 62 | reporter.call(this, errors); 63 | } else { 64 | const hints = []; 65 | if (errors) { 66 | errors.forEach((error) => { 67 | if (!error) return; 68 | const message = ` ${error.reason} @ line ${error.line} char ${ 69 | error.character 70 | }\n ${error.evidence}`; 71 | hints.push(message); 72 | }, this); 73 | } 74 | const message = hints.join('\n\n'); 75 | const emitter = emitErrors ? this.emitError : this.emitWarning; 76 | if (emitter) { 77 | emitter(`jshint results in errors\n${message}`); 78 | } else { 79 | throw new Error( 80 | `Your module system doesn't support emitWarning. Update availible? \n${message}` 81 | ); 82 | } 83 | } 84 | } 85 | if (failOnHint && !result) { 86 | throw new Error( 87 | 'jshint-loader: Module Build Failed due to a jshint error.' 88 | ); 89 | } 90 | } 91 | 92 | // eslint-disable-next-line consistent-return 93 | module.exports = function loader(input, map) { 94 | if (this.cacheable) { 95 | this.cacheable(); 96 | } 97 | 98 | const callback = this.async(); 99 | 100 | if (!callback) { 101 | // load .jshintrc synchronously 102 | const config = loadRcConfig.call(this); 103 | const options = Object.assign({}, config, loaderUtils.getOptions(this)); 104 | jsHint.call(this, input, options); 105 | return input; 106 | } 107 | 108 | // load .jshintrc asynchronously 109 | // eslint-disable-next-line consistent-return 110 | loadRcConfig.call(this, (err, config) => { 111 | if (err) { 112 | return callback(err); 113 | } 114 | 115 | try { 116 | const options = Object.assign({}, config, loaderUtils.getOptions(this)); 117 | jsHint.call(this, input, options); 118 | } catch (e) { 119 | return callback(e); 120 | } 121 | callback(null, input, map); 122 | }); 123 | }; 124 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | unit_tests: &unit_tests 2 | steps: 3 | - checkout 4 | - restore_cache: 5 | key: dependency-cache-{{ checksum "package-lock.json" }} 6 | - run: 7 | name: NPM Rebuild 8 | command: npm install 9 | - run: 10 | name: Run unit tests. 11 | command: npm run ci:test 12 | canary_tests: &canary_tests 13 | steps: 14 | - checkout 15 | - restore_cache: 16 | key: dependency-cache-{{ checksum "package-lock.json" }} 17 | - run: 18 | name: NPM Rebuild 19 | command: npm install 20 | - run: 21 | name: Install Webpack Canary 22 | command: npm i --no-save webpack@next 23 | - run: 24 | name: Run unit tests. 25 | command: if [[ $(compver --name webpack --gte next --lt latest) < 1 ]] ; then printf "Next is older than Latest - Skipping Canary Suite"; else npm run ci:test ; fi 26 | 27 | version: 2 28 | jobs: 29 | dependency_cache: 30 | docker: 31 | - image: webpackcontrib/circleci-node-base:latest 32 | steps: 33 | - checkout 34 | - restore_cache: 35 | key: dependency-cache-{{ checksum "package-lock.json" }} 36 | - run: 37 | name: Install Dependencies 38 | command: npm install 39 | - save_cache: 40 | key: dependency-cache-{{ checksum "package-lock.json" }} 41 | paths: 42 | - ./node_modules 43 | 44 | node8-latest: 45 | docker: 46 | - image: webpackcontrib/circleci-node8:latest 47 | steps: 48 | - checkout 49 | - restore_cache: 50 | key: dependency-cache-{{ checksum "package-lock.json" }} 51 | - run: 52 | name: NPM Rebuild 53 | command: npm install 54 | - run: 55 | name: Run unit tests. 56 | command: npm run ci:coverage 57 | - run: 58 | name: Submit coverage data to codecov. 59 | command: bash <(curl -s https://codecov.io/bash) 60 | when: on_success 61 | node6-latest: 62 | docker: 63 | - image: webpackcontrib/circleci-node6:latest 64 | <<: *unit_tests 65 | node9-latest: 66 | docker: 67 | - image: webpackcontrib/circleci-node9:latest 68 | <<: *unit_tests 69 | node8-canary: 70 | docker: 71 | - image: webpackcontrib/circleci-node8:latest 72 | <<: *canary_tests 73 | analysis: 74 | docker: 75 | - image: webpackcontrib/circleci-node-base:latest 76 | steps: 77 | - checkout 78 | - restore_cache: 79 | key: dependency-cache-{{ checksum "package-lock.json" }} 80 | - run: 81 | name: NPM Rebuild 82 | command: npm install 83 | - run: 84 | name: Run linting. 85 | command: npm run lint 86 | - run: 87 | name: Run NSP Security Check. 88 | command: npm run security 89 | - run: 90 | name: Validate Commit Messages 91 | command: npm run ci:lint:commits 92 | publish: 93 | docker: 94 | - image: webpackcontrib/circleci-node-base:latest 95 | steps: 96 | - checkout 97 | - restore_cache: 98 | key: dependency-cache-{{ checksum "package-lock.json" }} 99 | - run: 100 | name: NPM Rebuild 101 | command: npm install 102 | # - run: 103 | # name: Validate Commit Messages 104 | # command: npm run release:validate 105 | - run: 106 | name: Publish to NPM 107 | command: printf "noop running conventional-github-releaser" 108 | 109 | version: 2.0 110 | workflows: 111 | version: 2 112 | validate-publish: 113 | jobs: 114 | - dependency_cache 115 | - node6-latest: 116 | requires: 117 | - dependency_cache 118 | filters: 119 | tags: 120 | only: /.*/ 121 | - analysis: 122 | requires: 123 | - dependency_cache 124 | filters: 125 | tags: 126 | only: /.*/ 127 | - node8-latest: 128 | requires: 129 | - analysis 130 | - node6-latest 131 | filters: 132 | tags: 133 | only: /.*/ 134 | - node9-latest: 135 | requires: 136 | - analysis 137 | - node6-latest 138 | filters: 139 | tags: 140 | only: /.*/ 141 | - node8-canary: 142 | requires: 143 | - analysis 144 | - node6-latest 145 | filters: 146 | tags: 147 | only: /.*/ 148 | - publish: 149 | requires: 150 | - node8-latest 151 | - node8-canary 152 | - node9-latest 153 | filters: 154 | branches: 155 | only: 156 | - master 157 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | 7 | [![npm][npm]][npm-url] 8 | [![node][node]][node-url] 9 | [![deps][deps]][deps-url] 10 | [![tests][tests]][tests-url] 11 | [![chat][chat]][chat-url] 12 | 13 | # jshint-loader 14 | 15 | A JSHint loader module for webpack. Runs [JSHint](http://jshint.com/) on 16 | JavaScript files in a bundle at build-time. 17 | 18 | ## Requirements 19 | 20 | This module requires a minimum of Node v6.9.0 and Webpack v4.0.0. 21 | 22 | ## Getting Started 23 | 24 | To begin, you'll need to install `jshint-loader`: 25 | 26 | ```console 27 | $ npm install jshint-loader --save-dev 28 | ``` 29 | 30 | Then add the loader to your `webpack` config. For example: 31 | 32 | ```js 33 | // webpack.config.js 34 | module.exports = { 35 | module: { 36 | rules: [ 37 | { 38 | test: /.js/, 39 | enforce: 'pre', 40 | exclude: /node_modules/, 41 | use: [ 42 | { 43 | loader: `jshint-loader`, 44 | options: {...options} 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | } 51 | ``` 52 | 53 | 54 | And run `webpack` via your preferred method. 55 | 56 | ## Options 57 | 58 | All valid JSHint options are valid on this object, in addition to the custom 59 | loader options listed below: 60 | 61 | delete options.; 62 | delete options.; 63 | delete options.; 64 | 65 | ### `emitErrors` 66 | 67 | Type: `Boolean` 68 | Default: `undefined` 69 | 70 | Instructs the loader to emit all JSHint warnings and errors as webpack errors. 71 | 72 | ### `failOnHint` 73 | 74 | Type: `Boolean` 75 | Default: `undefined` 76 | 77 | Instructs the loader to cause the webpack build to fail on all JSHint warnings 78 | and errors. 79 | 80 | ### `reporter` 81 | 82 | Type: `Function` 83 | Default: `undefined` 84 | 85 | A function used to format and emit JSHint warnings and errors. 86 | 87 | ## Custom Reporter 88 | 89 | By default, `jshint-loader` will provide a default reporter. 90 | 91 | However, if you prefer a custom reporter, pass a function under the `reporter` 92 | property in `jshint` options. (see *usage* above) 93 | 94 | The reporter function will be passed an array of errors/warnings produced by 95 | JSHint with the following structure: 96 | ```js 97 | [ 98 | { 99 | id: [string, usually '(error)'], 100 | code: [string, error/warning code], 101 | reason: [string, error/warning message], 102 | evidence: [string, a piece of code that generated this error] 103 | line: [number] 104 | character: [number] 105 | scope: [string, message scope; 106 | usually '(main)' unless the code was eval'ed] 107 | 108 | [+ a few other legacy fields that you don't need to worry about.] 109 | }, 110 | // ... 111 | // more errors/warnings 112 | ] 113 | ``` 114 | 115 | The reporter function will be excuted with the loader context as `this`. You may 116 | emit messages using `this.emitWarning(...)` or `this.emitError(...)`. See 117 | [webpack docs on loader context](https://webpack.js.org/api/loaders/#the-loader-context). 118 | 119 | _Note: JSHint reporters are **not compatible** with JSHint-loader! 120 | This is due to the fact that reporter input is only processed from one file; not 121 | multiple files. Error reporting in this manner differs from 122 | [traditional reporters](http://www.JSHint.com/docs/reporters/) for JSHint 123 | since the loader plugin (i.e. JSHint-loader) is executed for each source file; 124 | and thus the reporter is executed for each file._ 125 | 126 | The output in webpack CLI will usually be: 127 | ```js 128 | ... 129 | WARNING in ./path/to/file.js 130 | 131 | ... 132 | ``` 133 | ` 134 | 135 | ## Contributing 136 | 137 | Please take a moment to read our contributing guidelines if you haven't yet done so. 138 | 139 | #### [CONTRIBUTING](./.github/CONTRIBUTING) 140 | 141 | ## License 142 | 143 | #### [MIT](./LICENSE) 144 | 145 | [npm]: https://img.shields.io/npm/v/jshint-loader.svg 146 | [npm-url]: https://npmjs.com/package/jshint-loader 147 | 148 | [node]: https://img.shields.io/node/v/jshint-loader.svg 149 | [node-url]: https://nodejs.org 150 | 151 | [deps]: https://david-dm.org/webpack-contrib/jshint-loader.svg 152 | [deps-url]: https://david-dm.org/webpack-contrib/jshint-loader 153 | 154 | [tests]: https://img.shields.io/circleci/project/github/webpack-contrib/jshint-loader.svg 155 | [tests-url]: https://circleci.com/gh/webpack-contrib/jshint-loader 156 | 157 | [cover]: https://codecov.io/gh/webpack-contrib/jshint-loader/branch/master/graph/badge.svg 158 | [cover-url]: https://codecov.io/gh/webpack-contrib/jshint-loader 159 | 160 | [chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg 161 | [chat-url]: https://gitter.im/webpack/webpack 162 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing in @webpack-contrib 2 | 3 | We'd always love contributions to further improve the webpack / webpack-contrib ecosystem! 4 | Here are the guidelines we'd like you to follow: 5 | 6 | * [Questions and Problems](#question) 7 | * [Issues and Bugs](#issue) 8 | * [Feature Requests](#feature) 9 | * [Pull Request Submission Guidelines](#submit-pr) 10 | * [Commit Message Conventions](#commit) 11 | 12 | ### Got a Question or Problem? 13 | 14 | Please submit support requests and questions to StackOverflow using the tag [[webpack]](http://stackoverflow.com/tags/webpack). 15 | StackOverflow is better suited for this kind of support though you may also inquire in [Webpack Gitter](https://gitter.im/webpack/webpack). 16 | The issue tracker is for bug reports and feature discussions. 17 | 18 | ### Found an Issue or Bug? 19 | 20 | Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available. 21 | 22 | We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs, we ask that you to provide a minimal reproduction scenario (github repo or failing test case). Having a live, reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions like: 23 | 24 | - version of Webpack used 25 | - version of the loader / plugin you are creating a bug report for 26 | - the use-case that fails 27 | 28 | A minimal reproduce scenario allows us to quickly confirm a bug (or point out config problems) as well as confirm that we are fixing the right problem. 29 | 30 | We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it. 31 | 32 | Unfortunately, we are not able to investigate / fix bugs without a minimal reproduction, so if we don't hear back from you we are going to close an issue that doesn't have enough info to be reproduced. 33 | 34 | ### Feature Requests? 35 | 36 | You can *request* a new feature by creating an issue on Github. 37 | 38 | If you would like to *implement* a new feature, please submit an issue with a proposal for your work `first`, to be sure that particular makes sense for the project. 39 | 40 | ### Pull Request Submission Guidelines 41 | 42 | Before you submit your Pull Request (PR) consider the following guidelines: 43 | 44 | - Search Github for an open or closed PR that relates to your submission. You don't want to duplicate effort. 45 | - Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit). Adherence to these conventions is necessary because release notes are automatically generated from these messages. 46 | - Fill out our `Pull Request Template`. Your pull request will not be considered if it is ignored. 47 | - Please sign the `Contributor License Agreement (CLA)` when a pull request is opened. We cannot accept your pull request without this. Make sure you sign with the primary email address associated with your local / github account. 48 | 49 | ### Webpack Contrib Commit Conventions 50 | 51 | Each commit message consists of a **header**, a **body** and a **footer**. The header has a special 52 | format that includes a **type**, a **scope** and a **subject**: 53 | 54 | ``` 55 | (): 56 | 57 | 58 | 59 |