ember-template-lint
Advanced tools
Comparing version 0.5.0-alpha.1 to 0.5.0
Changelog | ||
========= | ||
## v0.3.5 | ||
## v0.5.0 | ||
- Update the `bare-strings` rule to allow the following configuration: | ||
* boolean -- `true` for enabled / `false` for disabled | ||
* array -- an array of whitelisted strings | ||
* object -- An object with the following keys: | ||
* `whitelist` -- An array of whitelisted strings | ||
* `globalAttributes` -- An array of attributes to check on every element. | ||
* `elementAttributes` -- An object whose keys are tag names and value is an array of attributes to check for that tag name. | ||
- Change default `.template-lintrc.js` file value for `bare-strings` to be `true`, which defaults the configuration to: | ||
```js | ||
{ | ||
whitelist: ['(', ')', ',', '.', '&', '+', '-', '=', '*', '/', '#', '%', '!', '?', ':', '[', ']', '{', '}'], | ||
globalAttributes: [ 'title' ], | ||
elementAttributes: { input: [ 'placeholder' ], img: [ 'alt' ]} | ||
}; | ||
``` | ||
- Fix bug with `bare-strings` where an allowed whitelisted string would only be allowed once in a given string. i.e `&&` would have failed, even though `&` was a whitelisted string. | ||
## v0.3.4 | ||
- Add support for TextNode/CommentNode location information. Now the `bare-strings` / `html-comments` rules include line and column info. | ||
- Add `nested-interactive` rule. Usage of nested interactive content can lead to UX problems, accessibility problems, bugs and in some | ||
cases to DOM errors. You should not put interactive content elements nested inside other interactive content elements. | ||
## v0.3.3 | ||
- Fix issue with per-template rule configuration. | ||
## v0.3.2 | ||
- Fix issue with `block-indentation` rule when a given block starts on the same line as a previous item. i.e.: | ||
```hbs | ||
{{! good }} | ||
{{#each foo as |bar|}} | ||
<span>{{bar.name}}:</span><span>{{bar.title}}</span> | ||
{{/each}} | ||
``` | ||
## v0.3.1 | ||
- Add `html-comments` rule which forbids the usage of HTML comments (other than `<!-- template-lint bare-strings=false -->` style control comments). | ||
## v0.3.0 | ||
- Change default configuration so that no plugins are enabled (warns when `.template-lintrc.js` is not found). | ||
## v0.2.13 | ||
- Add better default whitelist for `bare-strings` rule. | ||
## v0.2.12 | ||
- Add blueprint that generate `.template-lintrc.js`. | ||
- Deprecate using ember-cli-template-lint without a `.template-lintrc.js`. | ||
- Initial migration of plugins from ember-cli-template-lint. | ||
- Implement new node API for the Linter. | ||
- Implement new result objects. |
'use strict'; | ||
module.exports = function(addonContext, name) { | ||
module.exports = function(options) { | ||
var log = options.log; | ||
var config = options.config; | ||
var ruleName = options.name; | ||
function BasePlugin(options) { | ||
@@ -11,5 +15,5 @@ this.options = options; | ||
this.config = this.parseConfig( | ||
addonContext.loadConfig()[name] | ||
); | ||
this.ruleName = ruleName; | ||
this.config = this.parseConfig(config); | ||
this._log = log; | ||
} | ||
@@ -76,3 +80,3 @@ | ||
// handle <!-- template-lint block-indentation=false --> | ||
if (key === name && value === 'false') { | ||
if (key === ruleName && value === 'false') { | ||
this.config = false; | ||
@@ -87,4 +91,7 @@ } | ||
BasePlugin.prototype.log = function(message) { | ||
addonContext.logLintingError(name, this.options.moduleName, message); | ||
BasePlugin.prototype.log = function(result) { | ||
result.moduleId = this.options.moduleName; | ||
result.rule = this.ruleName; | ||
this._log(result); | ||
}; | ||
@@ -91,0 +98,0 @@ |
@@ -25,3 +25,2 @@ 'use strict'; | ||
var calculateLocationDisplay = require('../helpers/calculate-location-display'); | ||
var buildPlugin = require('./base'); | ||
@@ -122,3 +121,3 @@ var astInfo = require('../helpers/ast-node-info'); | ||
var attributeValueNode = attribute.value; | ||
var additionalDescription = 'in `' + attributeType + '` attribute '; | ||
var additionalDescription = ' in `' + attributeType + '` attribute'; | ||
var isGlobalAttribute = this.config.globalAttributes.indexOf(attributeType) > -1; | ||
@@ -153,6 +152,8 @@ var isElementAttribute = this.config.elementAttributes[tag] && this.config.elementAttributes[tag].indexOf(attributeType) > -1; | ||
if (bareStringText) { | ||
var locationDisplay = calculateLocationDisplay(this.options.moduleName, loc && loc.start); | ||
var warning = 'Non-translated string used ' + additionalDescription + locationDisplay + ': `' + bareStringText + '`.'; | ||
this.log(warning); | ||
this.log({ | ||
message: 'Non-translated string used' + additionalDescription, | ||
line: loc.start.line, | ||
column: loc.start.column, | ||
source: bareStringText | ||
}); | ||
} | ||
@@ -159,0 +160,0 @@ }; |
@@ -51,3 +51,2 @@ 'use strict'; | ||
var calculateLocationDisplay = require('../helpers/calculate-location-display'); | ||
var buildPlugin = require('./base'); | ||
@@ -152,4 +151,4 @@ var VOID_TAGS = { area: true, | ||
if(correctedEndColumn !== startColumn) { | ||
var startLocation = calculateLocationDisplay(this.options.moduleName, node.loc && node.loc.start); | ||
var endLocation = calculateLocationDisplay(this.options.moduleName, node.loc && node.loc.end); | ||
var startLocation = 'L' + node.loc.start.line + ':C' + node.loc.start.column; | ||
var endLocation = 'L' + node.loc.end.line + ':C' + node.loc.end.column; | ||
@@ -159,3 +158,9 @@ var warning = 'Incorrect indentation for `' + displayName + '` beginning at ' + startLocation + | ||
'was found at ' + correctedEndColumn + '.'; | ||
this.log(warning); | ||
this.log({ | ||
message: warning, | ||
line: node.loc.end.line, | ||
column: node.loc.end.column, | ||
source: this.sourceForNode(node) | ||
}); | ||
} | ||
@@ -252,4 +257,3 @@ }; | ||
var startLocation = calculateLocationDisplay(this.options.moduleName, child.loc && child.loc.start); | ||
var startLocation = 'L' + child.loc.start.line + ':C' + child.loc.start.column; | ||
var warning = 'Incorrect indentation for `' + display + '` beginning at ' + startLocation + | ||
@@ -259,3 +263,8 @@ '. Expected `' + display + '` to be at an indentation of ' + expectedStartColumn + ' but ' + | ||
this.log(warning); | ||
this.log({ | ||
message: warning, | ||
line: child.loc && child.loc.start.line, | ||
column: child.loc && child.loc.start.column, | ||
source: this.sourceForNode(node) | ||
}); | ||
} | ||
@@ -262,0 +271,0 @@ } |
'use strict'; | ||
var calculateLocationDisplay = require('../helpers/calculate-location-display'); | ||
var AstNodeInfo = require('../helpers/ast-node-info'); | ||
@@ -32,5 +31,8 @@ var buildPlugin = require('./base'); | ||
LogHtmlComments.prototype.process = function(node) { | ||
var location = calculateLocationDisplay(this.options.moduleName, node.loc && node.loc.start); | ||
this.log('Html comment detected `<!--' + node.value + '-->` at ' + location + | ||
'. Use Handlebars comment instead `{{!--' + node.value +'--}}`'); | ||
this.log({ | ||
message: 'HTML comment detected', | ||
line: node.loc && node.loc.start.line, | ||
column: node.loc && node.loc.start.column, | ||
source: '<!--' + node.value + '-->' | ||
}); | ||
}; | ||
@@ -37,0 +39,0 @@ |
@@ -19,3 +19,2 @@ 'use strict'; | ||
var calculateLocationDisplay = require('../helpers/calculate-location-display'); | ||
var buildPlugin = require('./base'); | ||
@@ -209,4 +208,3 @@ | ||
return 'Don\'t use ' + childNodeError + ' inside ' + parentNodeError + ' ' + | ||
calculateLocationDisplay(this.options.moduleName, node.loc.start); | ||
return 'Do not use ' + childNodeError + ' inside ' + parentNodeError; | ||
}; | ||
@@ -217,3 +215,9 @@ | ||
if (this.isInteractiveElement(node, whitelistTests)) { | ||
this.log(this.getLogMessage(node, parentInteractiveNode)); | ||
this.log({ | ||
message: this.getLogMessage(node, parentInteractiveNode), | ||
line: node.loc && node.loc.start.line, | ||
column: node.loc && node.loc.start.column, | ||
source: this.sourceForNode(node) | ||
}); | ||
return; | ||
@@ -220,0 +224,0 @@ } |
'use strict'; | ||
var calculateLocationDisplay = require('../helpers/calculate-location-display'); | ||
var buildPlugin = require('./base'); | ||
@@ -31,5 +30,8 @@ | ||
LogTripleCurlies.prototype.process = function(node) { | ||
var location = calculateLocationDisplay(this.options.moduleName, node.loc && node.loc.start); | ||
this.log('Usage of triple curly brackets is unsafe `{{{' + node.path.original + '}}}` at ' + location); | ||
this.log({ | ||
message: 'Usage of triple curly brackets is unsafe', | ||
line: node.loc && node.loc.start.line, | ||
column: node.loc && node.loc.start.column, | ||
source: '{{{' + node.path.original + '}}}' | ||
}); | ||
}; | ||
@@ -36,0 +38,0 @@ |
'use strict'; | ||
/*eslint no-console: [0] */ | ||
var path = require('path'); | ||
@@ -7,4 +9,4 @@ var existsSync = require('exists-sync'); | ||
function buildDefaultConfig(ui) { | ||
ui.log(chalk.yellow('\nember-cli-template-lint requires a configuration file to enable rules. Please generate one with `ember generate ember-cli-template-lint`.')); | ||
function buildDefaultConfig(console) { | ||
console.log(chalk.yellow('\nember-cli-template-lint requires a configuration file to enable rules. Please generate one with `ember generate ember-cli-template-lint`.')); | ||
@@ -19,3 +21,3 @@ return {}; | ||
if(existsSync(configPath + '.js') || existsSync(configPath + '.json')) { | ||
if(existsSync(configPath) || existsSync(configPath + '.js') || existsSync(configPath + '.json')) { | ||
return require(configPath); | ||
@@ -22,0 +24,0 @@ } else { |
{ | ||
"name": "ember-template-lint", | ||
"version": "0.5.0-alpha.1", | ||
"version": "0.5.0", | ||
"description": "Lint your templates.", | ||
@@ -19,3 +19,5 @@ "scripts": { | ||
"devDependencies": { | ||
"assert-diff": "^1.0.1", | ||
"eslint-plugin-node": "^1.0.0", | ||
"espower-loader": "^1.0.0", | ||
"glob": "^7.0.0", | ||
@@ -26,3 +28,5 @@ "loader.js": "^4.0.1", | ||
"mocha-only-detector": "^0.1.0", | ||
"rimraf": "^2.5.2" | ||
"power-assert": "^1.3.1", | ||
"rimraf": "^2.5.2", | ||
"testem": "^1.6.0" | ||
}, | ||
@@ -29,0 +33,0 @@ "keywords": [], |
# ember-cli-template-lint | ||
[![Build Status](https://travis-ci.org/rwjblue/ember-cli-template-lint.svg?branch=master)](https://travis-ci.org/rwjblue/ember-cli-template-lint) | ||
[![Build Status](https://travis-ci.org/rwjblue/ember-template-lint.svg?branch=master)](https://travis-ci.org/rwjblue/ember-template-lint) | ||
ember-cli-template-lint will lint your templates and add a test for each asserting | ||
that all style rules have been satisfied. | ||
ember-template-lint will lint your template and return error results. This is commonly | ||
used through ember-cli-template-lint which adds failing lint tests for consuming ember-cli | ||
applications. | ||
@@ -16,15 +17,13 @@ For example, given the rule `bare-strings` is enabled, this template would be | ||
Thus a the test `TemplateLint: app/components/my-thing/template.hbs` would | ||
fail with the assertion "A bare string was found (0:5)". | ||
When ran throught the linters `verify` method we would have a single result indicating that | ||
the `bare-strings` rule found an error. | ||
## Install | ||
To install ember-cli-template-lint | ||
To install ember-template-lint | ||
``` | ||
ember install ember-cli-template-lint | ||
npm install --save-dev ember-template-lint | ||
``` | ||
__Ember CLI >= 2.4.2 is required for linting templates__ | ||
## Configuration | ||
@@ -205,19 +204,5 @@ | ||
* `npm install` | ||
* `bower install` | ||
### Running | ||
* `ember server` | ||
* Visit your app at http://localhost:4200. | ||
### Running Tests | ||
* `npm run test-node` | ||
* `ember test` | ||
* `ember test --server` | ||
### Building | ||
* `ember build` | ||
For more information on using ember-cli, visit [http://www.ember-cli.com/](http://www.ember-cli.com/). | ||
* `npm test` |
'use strict'; | ||
var assert = require('assert'); | ||
var _compile = require('htmlbars').compile; | ||
var plugins = require('../../ext/plugins'); | ||
var assert = require('power-assert'); | ||
var assertDiff = require('assert-diff'); | ||
var Linter = require('../../lib/index'); | ||
@@ -13,62 +13,56 @@ module.exports = function(options) { | ||
var addonContext, messages, config; | ||
var linter, config; | ||
function compile(template) { | ||
_compile(template, { | ||
rawSource: template, | ||
moduleName: 'layout.hbs', | ||
plugins: { | ||
ast: [ | ||
plugins[options.name](addonContext) | ||
] | ||
} | ||
}); | ||
function verify(template) { | ||
linter.config[options.name] = config; | ||
return linter.verify({ source: template, moduleId: 'layout.hbs' }); | ||
} | ||
beforeEach(function() { | ||
messages = []; | ||
config = {}; | ||
config[options.name] = options.config; | ||
var fullConfig = {}; | ||
fullConfig[options.name] = config = options.config; | ||
addonContext = { | ||
logLintingError: function(pluginName, moduleName, message) { | ||
messages.push(message); | ||
}, | ||
loadConfig: function() { | ||
return config; | ||
} | ||
}; | ||
linter = new Linter({ | ||
config: fullConfig | ||
}); | ||
}); | ||
options.bad.forEach(function(badItem) { | ||
var testMethod = badItem.focus ? it.only : it; | ||
var expectedMessages = badItem.messages || [badItem.message]; | ||
var testMethod; | ||
if (badItem.focus) { | ||
testMethod = it.only; | ||
} else { | ||
testMethod = it; | ||
} | ||
testMethod('logs a message in the console when given `' + badItem.template + '`', function() { | ||
var expectedResults = badItem.results || [badItem.result]; | ||
if (badItem.config) { | ||
config[options.name] = badItem.config; | ||
config = badItem.config; | ||
} | ||
compile(badItem.template); | ||
var actual = verify(badItem.template); | ||
assert.deepEqual(messages, expectedMessages); | ||
assertDiff.deepEqual(actual, expectedResults); | ||
}); | ||
it('passes with `' + badItem.template + '` when rule is disabled', function() { | ||
config[options.name] = false; | ||
compile(badItem.template); | ||
config = false; | ||
var actual = verify(badItem.template); | ||
assert.deepEqual(messages, []); | ||
assert.deepEqual(actual, []); | ||
}); | ||
it('passes with `' + badItem.template + '` when disabled via inline comment - single rule', function() { | ||
compile(DISABLE_ONE + '\n' + badItem.template); | ||
var actual = verify(DISABLE_ONE + '\n' + badItem.template); | ||
assert.deepEqual(messages, []); | ||
assert.deepEqual(actual, []); | ||
}); | ||
it('passes with `' + badItem.template + '` when disabled via inline comment - all rules', function() { | ||
compile(DISABLE_ALL + '\n' + badItem.template); | ||
var actual = verify(DISABLE_ALL + '\n' + badItem.template); | ||
assert.deepEqual(messages, []); | ||
assert.deepEqual(actual, []); | ||
}); | ||
@@ -82,13 +76,14 @@ }); | ||
testMethod('passes when given `' + template + '`', function() { | ||
var actual; | ||
if (typeof item === 'string') { | ||
compile(item); | ||
actual = verify(item); | ||
} else { | ||
if (item.config !== undefined) { | ||
config[options.name] = item.config; | ||
config = item.config; | ||
} | ||
compile(template); | ||
actual = verify(template); | ||
} | ||
assert.deepEqual(messages, []); | ||
assert.deepEqual(actual, []); | ||
}); | ||
@@ -95,0 +90,0 @@ }); |
'use strict'; | ||
var assert = require('assert'); | ||
var assert = require('power-assert'); | ||
var _compile = require('htmlbars').compile; | ||
@@ -9,6 +9,12 @@ var buildPlugin = require('./../../ext/plugins/base'); | ||
describe('base plugin tests', function() { | ||
var addonContext, messages, config; | ||
var messages, config; | ||
function plugin(addonContext) { | ||
var FakePlugin = buildPlugin(addonContext, 'fake'); | ||
function plugin() { | ||
var FakePlugin = buildPlugin({ | ||
log: function(result) { | ||
messages.push(result.source); | ||
}, | ||
name: 'fake', | ||
config: config | ||
}); | ||
@@ -20,3 +26,8 @@ FakePlugin.prototype.detect = function(node) { | ||
FakePlugin.prototype.process = function(node) { | ||
this.log(this.sourceForNode(node)); | ||
this.log({ | ||
message: 'Node source', | ||
line: node.loc && node.loc.start.line, | ||
column: node.loc && node.loc.start.column, | ||
source: this.sourceForNode(node) | ||
}); | ||
}; | ||
@@ -33,3 +44,3 @@ | ||
ast: [ | ||
plugin(addonContext) | ||
plugin() | ||
] | ||
@@ -43,11 +54,2 @@ } | ||
config = {}; | ||
addonContext = { | ||
logLintingError: function(pluginName, moduleName, message) { | ||
messages.push(message); | ||
}, | ||
loadConfig: function() { | ||
return config; | ||
} | ||
}; | ||
}); | ||
@@ -54,0 +56,0 @@ |
'use strict'; | ||
var assert = require('assert'); | ||
var assert = require('power-assert'); | ||
var _compile = require('htmlbars').compile; | ||
@@ -5,0 +5,0 @@ |
@@ -67,8 +67,38 @@ 'use strict'; | ||
bad: [ | ||
{ template: '\n howdy', message: 'Non-translated string used (\'layout.hbs\'@ L1:C0): `\n howdy`.' }, | ||
{ template: '<div>\n 1234\n</div>', message: 'Non-translated string used (\'layout.hbs\'@ L1:C5): `\n 1234\n`.' }, | ||
{ | ||
template: '\n howdy', | ||
result: { | ||
rule: 'bare-strings', | ||
moduleId: 'layout.hbs', | ||
message: 'Non-translated string used', | ||
line: 1, | ||
column: 0, | ||
source: '\n howdy' | ||
} | ||
}, | ||
{ | ||
template: '<div>\n 1234\n</div>', | ||
result: { | ||
rule: 'bare-strings', | ||
moduleId: 'layout.hbs', | ||
message: 'Non-translated string used', | ||
line: 1, | ||
column: 5, | ||
source: '\n 1234\n' | ||
} | ||
}, | ||
{ | ||
template: '<a title="hahaha trolol"></a>', | ||
message: 'Non-translated string used in `title` attribute (\'layout.hbs\'@ L1:C4): `hahaha trolol`.' | ||
result: { | ||
rule: 'bare-strings', | ||
moduleId: 'layout.hbs', | ||
message: 'Non-translated string used in `title` attribute', | ||
line: 1, | ||
column: 4, | ||
source: 'hahaha trolol' | ||
} | ||
}, | ||
@@ -78,3 +108,11 @@ | ||
template: '<input placeholder="trolol">', | ||
message: 'Non-translated string used in `placeholder` attribute (\'layout.hbs\'@ L1:C8): `trolol`.' | ||
result: { | ||
rule: 'bare-strings', | ||
moduleId: 'layout.hbs', | ||
message: 'Non-translated string used in `placeholder` attribute', | ||
line: 1, | ||
column: 8, | ||
source: 'trolol' | ||
} | ||
}, | ||
@@ -85,3 +123,11 @@ | ||
template: '<div data-foo="derpy"></div>', | ||
message: 'Non-translated string used in `data-foo` attribute (\'layout.hbs\'@ L1:C6): `derpy`.' | ||
result: { | ||
rule: 'bare-strings', | ||
moduleId: 'layout.hbs', | ||
message: 'Non-translated string used in `data-foo` attribute', | ||
line: 1, | ||
column: 6, | ||
source: 'derpy' | ||
} | ||
}, | ||
@@ -92,3 +138,11 @@ | ||
template: '<img data-alt="some alternate here">', | ||
message: 'Non-translated string used in `data-alt` attribute (\'layout.hbs\'@ L1:C6): `some alternate here`.' | ||
result: { | ||
rule: 'bare-strings', | ||
moduleId: 'layout.hbs', | ||
message: 'Non-translated string used in `data-alt` attribute', | ||
line: 1, | ||
column: 6, | ||
source: 'some alternate here' | ||
} | ||
}, | ||
@@ -99,5 +153,18 @@ | ||
template: '<div>Bady\n <input placeholder="trolol">\n</div>', | ||
messages: [ | ||
'Non-translated string used (\'layout.hbs\'@ L1:C5): `Bady\n `.', | ||
'Non-translated string used in `placeholder` attribute (\'layout.hbs\'@ L2:C10): `trolol`.' | ||
results: [ | ||
{ | ||
rule: 'bare-strings', | ||
moduleId: 'layout.hbs', | ||
message: 'Non-translated string used', | ||
line: 1, | ||
column: 5, | ||
source: 'Bady\n ' | ||
}, { | ||
rule: 'bare-strings', | ||
moduleId: 'layout.hbs', | ||
message: 'Non-translated string used in `placeholder` attribute', | ||
line: 2, | ||
column: 10, | ||
source: 'trolol' | ||
} | ||
] | ||
@@ -104,0 +171,0 @@ } |
@@ -94,8 +94,23 @@ 'use strict'; | ||
message: 'Incorrect indentation for `each` beginning at (\'layout.hbs\'@ L2:C2). Expected `{{/each}}` ending at (\'layout.hbs\'@ L3:C17) to be at an indentation of 2 but was found at 8.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `each` beginning at L2:C2. Expected `{{/each}}` ending at L3:C17 to be at an indentation of 2 but was found at 8.', | ||
moduleId: 'layout.hbs', | ||
source: '{{#each cats as |dog|}}\n {{/each}}', | ||
line: 3, | ||
column: 17 | ||
} | ||
}, | ||
{ | ||
template: '<div>\n <p>Stuff goes here</p></div>', | ||
message: 'Incorrect indentation for `div` beginning at (\'layout.hbs\'@ L1:C0). Expected `</div>` ending at (\'layout.hbs\'@ L2:C30) to be at an indentation of 0 but was found at 24.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `div` beginning at L1:C0. Expected `</div>` ending at L2:C30 to be at an indentation of 0 but was found at 24.', | ||
moduleId: 'layout.hbs', | ||
source: '<div>\n <p>Stuff goes here</p></div>', | ||
line: 2, | ||
column: 30 | ||
} | ||
}, | ||
@@ -105,3 +120,10 @@ { | ||
message: 'Incorrect indentation for `<p>` beginning at (\'layout.hbs\'@ L2:C0). Expected `<p>` to be at an indentation of 2 but was found at 0.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `<p>` beginning at L2:C0. Expected `<p>` to be at an indentation of 2 but was found at 0.', | ||
moduleId: 'layout.hbs', | ||
source: '<div>\n<p>Stuff goes here</p>\n</div>', | ||
line: 2, | ||
column: 0 | ||
} | ||
}, | ||
@@ -111,3 +133,10 @@ { | ||
message: 'Incorrect indentation for `<p>` beginning at (\'layout.hbs\'@ L2:C0). Expected `<p>` to be at an indentation of 2 but was found at 0.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `<p>` beginning at L2:C0. Expected `<p>` to be at an indentation of 2 but was found at 0.', | ||
moduleId: 'layout.hbs', | ||
source: '{{#if}}\n<p>Stuff goes here</p>\n{{/if}}', | ||
line: 2, | ||
column: 0 | ||
} | ||
}, | ||
@@ -122,3 +151,10 @@ { | ||
message: 'Incorrect indentation for `if` beginning at (\'layout.hbs\'@ L3:C2). Expected `{{/if}}` ending at (\'layout.hbs\'@ L5:C11) to be at an indentation of 2 but was found at 4.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `if` beginning at L3:C2. Expected `{{/if}}` ending at L5:C11 to be at an indentation of 2 but was found at 4.', | ||
moduleId: 'layout.hbs', | ||
source: '{{#if something}}\n Good night\n {{/if}}', | ||
line: 5, | ||
column: 11 | ||
} | ||
}, | ||
@@ -133,3 +169,10 @@ { | ||
message: 'Incorrect indentation for `<p>` beginning at (\'layout.hbs\'@ L2:C2). Expected `<p>` to be at an indentation of 4 but was found at 2.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `<p>` beginning at L2:C2. Expected `<p>` to be at an indentation of 4 but was found at 2.', | ||
moduleId: 'layout.hbs', | ||
source: '<div>\n <p>Hi!</p>\n</div>', | ||
line: 2, | ||
column: 2 | ||
} | ||
}, | ||
@@ -142,3 +185,10 @@ { | ||
message: 'Incorrect indentation for `{{bar}}` beginning at (\'layout.hbs\'@ L3:C0). Expected `{{bar}}` to be at an indentation of 2 but was found at 0.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `{{bar}}` beginning at L3:C0. Expected `{{bar}}` to be at an indentation of 2 but was found at 0.', | ||
moduleId: 'layout.hbs', | ||
source: '<div>\n {{foo}}\n{{bar}}\n</div>', | ||
line: 3, | ||
column: 0 | ||
} | ||
}, | ||
@@ -151,3 +201,10 @@ { | ||
message: 'Incorrect indentation for `{{bar}}` beginning at (\'layout.hbs\'@ L3:C0). Expected `{{bar}}` to be at an indentation of 2 but was found at 0.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `{{bar}}` beginning at L3:C0. Expected `{{bar}}` to be at an indentation of 2 but was found at 0.', | ||
moduleId: 'layout.hbs', | ||
source: '<div>\n Foo:\n{{bar}}\n</div>', | ||
line: 3, | ||
column: 0 | ||
} | ||
}, | ||
@@ -161,3 +218,11 @@ { | ||
'</div>', | ||
message: 'Incorrect indentation for `some-thing` beginning at (\'layout.hbs\'@ L2:C18). Expected `{{/some-thing}}` ending at (\'layout.hbs\'@ L3:C17) to be at an indentation of 18 but was found at 2.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `some-thing` beginning at L2:C18. Expected `{{/some-thing}}` ending at L3:C17 to be at an indentation of 18 but was found at 2.', | ||
moduleId: 'layout.hbs', | ||
source: '{{#some-thing}}\n {{/some-thing}}', | ||
line: 3, | ||
column: 17 | ||
} | ||
}, | ||
@@ -172,5 +237,13 @@ { | ||
'{{/if}}', | ||
message: 'Incorrect indentation for `p` beginning at (\'layout.hbs\'@ L2:C10). Expected `</p>` ending at (\'layout.hbs\'@ L4:C6) to be at an indentation of 10 but was found at 2.' | ||
result: { | ||
rule: 'block-indentation', | ||
message: 'Incorrect indentation for `p` beginning at L2:C10. Expected `</p>` ending at L4:C6 to be at an indentation of 10 but was found at 2.', | ||
moduleId: 'layout.hbs', | ||
source: '<p>\n Bar\n </p>', | ||
line: 4, | ||
column: 6 | ||
} | ||
} | ||
] | ||
}); |
@@ -20,11 +20,25 @@ 'use strict'; | ||
template: '<!-- comment here -->', | ||
message: 'Html comment detected `<!-- comment here -->` at (\'layout.hbs\'@ L1:C3). ' + | ||
'Use Handlebars comment instead `{{!-- comment here --}}`' | ||
result: { | ||
rule: 'html-comments', | ||
message: 'HTML comment detected', | ||
moduleId: 'layout.hbs', | ||
source: '<!-- comment here -->', | ||
line: 1, | ||
column: 3 | ||
} | ||
}, | ||
{ | ||
template: '<!--comment here-->', | ||
message: 'Html comment detected `<!--comment here-->` at (\'layout.hbs\'@ L1:C3). ' + | ||
'Use Handlebars comment instead `{{!--comment here--}}`' | ||
result: { | ||
rule: 'html-comments', | ||
message: 'HTML comment detected', | ||
moduleId: 'layout.hbs', | ||
source: '<!--comment here-->', | ||
line: 1, | ||
column: 3 | ||
} | ||
} | ||
] | ||
}); |
@@ -57,17 +57,185 @@ 'use strict'; | ||
bad: [ | ||
{ config: ['a'], template: '<a href="/">button<a href="/">!</a></a>', message: 'Don\'t use <a> inside <a> (\'layout.hbs\'@ L1:C18)' }, | ||
{ config: ['a', 'button'], template: '<a href="/">button<button>!</button></a>', message: 'Don\'t use <button> inside <a> (\'layout.hbs\'@ L1:C18)' }, | ||
{ config: ['a', 'button'], template: '<button>button<a href="/">!</a></button>', message: 'Don\'t use <a> inside <button> (\'layout.hbs\'@ L1:C14)' }, | ||
{ config: ['button'], template: '<button>button<button>!</button></button>', message: 'Don\'t use <button> inside <button> (\'layout.hbs\'@ L1:C14)' }, | ||
{ config: ['button', 'input'], template: '<button><input type="text"></button>', message: 'Don\'t use <input> inside <button> (\'layout.hbs\'@ L1:C8)' }, | ||
{ config: ['button', 'details'], template: '<button><details><summary>Some details</summary><p>!</p></details></button>', message: 'Don\'t use <details> inside <button> (\'layout.hbs\'@ L1:C8)' }, | ||
{ config: ['button', 'embed'], template: '<button><embed type="video/quicktime" src="movie.mov" width="640" height="480"></button>', message: 'Don\'t use <embed> inside <button> (\'layout.hbs\'@ L1:C8)' }, | ||
{ config: ['button', 'iframe'], template: '<button><iframe src="/frame.html" width="640" height="480"></iframe></button>', message: 'Don\'t use <iframe> inside <button> (\'layout.hbs\'@ L1:C8)' }, | ||
{ config: ['button', 'select'], template: '<button><select></select></button>', message: 'Don\'t use <select> inside <button> (\'layout.hbs\'@ L1:C8)' }, | ||
{ config: ['button', 'textarea'], template: '<button><textarea></textarea></button>', message: 'Don\'t use <textarea> inside <button> (\'layout.hbs\'@ L1:C8)' }, | ||
{ config: ['button', 'tabindex'], template: '<div tabindex="1"><button></button></div>', message: 'Don\'t use <button> inside an element with attribute `tabindex` (\'layout.hbs\'@ L1:C18)' }, | ||
{ config: ['button', 'tabindex'], template: '<button><div tabindex="1"></div></button>', message: 'Don\'t use an element with attribute `tabindex` inside <button> (\'layout.hbs\'@ L1:C8)' }, | ||
{ config: ['button', 'img'], template: '<button><img usemap=""></button>', message: 'Don\'t use an element with attribute `usemap` inside <button> (\'layout.hbs\'@ L1:C8)' }, | ||
{ config: ['button', 'object'], template: '<object usemap=""><button></button></object>', message: 'Don\'t use <button> inside an element with attribute `usemap` (\'layout.hbs\'@ L1:C18)' } | ||
{ | ||
config: ['a'], | ||
template: '<a href="/">button<a href="/">!</a></a>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <a> inside <a>', | ||
moduleId: 'layout.hbs', | ||
source: '<a href=\"/\">!</a>', | ||
line: 1, | ||
column: 18 | ||
} | ||
}, | ||
{ | ||
config: ['a', 'button'], | ||
template: '<a href="/">button<button>!</button></a>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <button> inside <a>', | ||
moduleId: 'layout.hbs', | ||
source: '<button>!</button>', | ||
line: 1, | ||
column: 18 | ||
} | ||
}, | ||
{ | ||
config: ['a', 'button'], | ||
template: '<button>button<a href="/">!</a></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <a> inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<a href=\"/\">!</a>', | ||
line: 1, | ||
column: 14 | ||
} | ||
}, | ||
{ | ||
config: ['button'], | ||
template: '<button>button<button>!</button></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <button> inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<button>!</button>', | ||
line: 1, | ||
column: 14 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'input'], | ||
template: '<button><input type="text"></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <input> inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<input type="text">', | ||
line: 1, | ||
column: 8 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'details'], | ||
template: '<button><details><summary>Some details</summary><p>!</p></details></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <details> inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<details><summary>Some details</summary><p>!</p></details>', | ||
line: 1, | ||
column: 8 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'embed'], | ||
template: '<button><embed type="video/quicktime" src="movie.mov" width="640" height="480"></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <embed> inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<embed type=\"video/quicktime\" src=\"movie.mov\" width=\"640\" height=\"480\">', | ||
line: 1, | ||
column: 8 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'iframe'], | ||
template: '<button><iframe src="/frame.html" width="640" height="480"></iframe></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <iframe> inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<iframe src=\"/frame.html\" width=\"640\" height=\"480\"></iframe>', | ||
line: 1, | ||
column: 8 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'select'], | ||
template: '<button><select></select></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <select> inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<select></select>', | ||
line: 1, | ||
column: 8 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'textarea'], | ||
template: '<button><textarea></textarea></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <textarea> inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<textarea></textarea>', | ||
line: 1, | ||
column: 8 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'tabindex'], | ||
template: '<div tabindex="1"><button></button></div>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <button> inside an element with attribute `tabindex`', | ||
moduleId: 'layout.hbs', | ||
source: '<button></button>', | ||
line: 1, | ||
column: 18 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'tabindex'], | ||
template: '<button><div tabindex="1"></div></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use an element with attribute `tabindex` inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<div tabindex=\"1\"></div>', | ||
line: 1, | ||
column: 8 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'img'], | ||
template: '<button><img usemap=""></button>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use an element with attribute `usemap` inside <button>', | ||
moduleId: 'layout.hbs', | ||
source: '<img usemap=\"\">', | ||
line: 1, | ||
column: 8 | ||
} | ||
}, | ||
{ | ||
config: ['button', 'object'], | ||
template: '<object usemap=""><button></button></object>', | ||
result: { | ||
rule: 'nested-interactive', | ||
message: 'Do not use <button> inside an element with attribute `usemap`', | ||
moduleId: 'layout.hbs', | ||
source: '<button></button>', | ||
line: 1, | ||
column: 18 | ||
} | ||
} | ||
] | ||
}); |
@@ -17,4 +17,15 @@ 'use strict'; | ||
bad: [ | ||
{ template: '\n {{{foo}}}', message: 'Usage of triple curly brackets is unsafe `{{{foo}}}` at (\'layout.hbs\'@ L2:C1)' } | ||
{ | ||
template: '\n {{{foo}}}', | ||
result: { | ||
rule: 'triple-curlies', | ||
message: 'Usage of triple curly brackets is unsafe', | ||
moduleId: 'layout.hbs', | ||
source: '{{{foo}}}', | ||
line: 2, | ||
column: 1 | ||
} | ||
} | ||
] | ||
}); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
69345
41
1917
11
206
5