diff --git a/docs/rules.md b/docs/rules.md index 692f06f..e3d1245 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -170,6 +170,20 @@ Pug must not contain any ID literals. div(id='id') ``` +# disallowJavaScriptCode: `true` + +Pug must not contain any JavaScript code. + +```pug +//- Invalid +- var someVariable = 1 +div(class=someVariable) +div= someVariable +if someVariable +each item in someVariable +while someVariable +``` + # disallowLegacyMixinCall: `true` The Pug template must not contain legacy mixin call. diff --git a/lib/rules/disallow-javascript-code.js b/lib/rules/disallow-javascript-code.js new file mode 100644 index 0000000..b1cc55c --- /dev/null +++ b/lib/rules/disallow-javascript-code.js @@ -0,0 +1,40 @@ +// # disallowJavaScriptCode: `true` +// +// Pug must not contain any JavaScript code. +// +// ```pug +// //- Invalid +// - var someVariable = 1 +// div(class=someVariable) +// div= someVariable +// if someVariable +// each item in someVariable +// while someVariable +// ``` + +var utils = require('../utils'); + +module.exports = function () {}; + +module.exports.prototype = { + name: 'disallowJavaScriptCode', + + configure: function (options) { + utils.validateTrueOptions(this.name, options); + }, + + lint: function (file, errors) { + file.addErrorForAllTokensByFilter(function (token) { + return token.type === 'code' || + token.type === 'each' || + token.type === 'while' || + token.type === 'if' || + token.type === 'else-if' || + token.type === 'else' || + token.type === 'case' || + token.type === 'when' || + token.type === 'default' || + (token.type === 'attribute' && token.val !== true && !(/^-?\d*\.?\d*$/.test(token.val) || /^"(?:[^"\\]|\\.)*"$/.test(token.val) || /^'(?:[^'\\]|\\.)*'$/.test(token.val))); + }, errors, 'JavaScript code must not be used'); + } +}; diff --git a/test/rules/disallow-javascript-code.test.js b/test/rules/disallow-javascript-code.test.js new file mode 100644 index 0000000..886d17f --- /dev/null +++ b/test/rules/disallow-javascript-code.test.js @@ -0,0 +1,48 @@ +module.exports = createTest; + +var assert = require('assert'); + +function createTest(linter) { + describe('disallowJavaScriptCode', function () { + describe('true', function () { + before(function () { + linter.configure({disallowJavaScriptCode: true}); + }); + + it('should report JavaScript code', function () { + assert.equal(linter.checkString('- var x = 777\nbody= x').length, 2); + }); + + it('should report JavaScript code in attribute', function () { + assert.equal(linter.checkString('p(x=y)').length, 1); + assert.equal(linter.checkString('p(x=`y`)').length, 1); + assert.equal(linter.checkString('p(x=true)').length, 1); + }); + + it('should not report JavaScript code in attribute', function () { + assert.equal(linter.checkString('p(x=1)').length, 0); + assert.equal(linter.checkString('p(x="y")').length, 0); + assert.equal(linter.checkString('p(x="y\\"y")').length, 0); + assert.equal(linter.checkString('p(x=\'y\')').length, 0); + assert.equal(linter.checkString('p(x=\'y\\\'y\')').length, 0); + assert.equal(linter.checkString('input(checked)').length, 0); + }); + + it('should report JavaScript code in each', function () { + assert.equal(linter.checkString('each a in b\n\t\tp').length, 1); + }); + + it('should report JavaScript code in while', function () { + assert.equal(linter.checkString('while true\n\t\tp').length, 1); + }); + + it('should report JavaScript code in condition', function () { + assert.equal(linter.checkString('if true\n\t\tp\nelse if true\n\tp\nelse\n\tp').length, 3); + }); + + it('should report JavaScript code in case', function () { + assert.equal(linter.checkString('case x\n\twhen y\n\t\tp\n\tdefault\n\t\tp').length, 3); + }); + }); + }); +}