Skip to content

Commit 8434a43

Browse files
committedMar 13, 2015
initial commit
0 parents  commit 8434a43

File tree

9 files changed

+554
-0
lines changed

9 files changed

+554
-0
lines changed
 

‎.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.DS_Store
2+
*.log
3+
node_modules

‎.htlmhintrc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"tagname-lowercase": true,
3+
"attr-lowercase": true,
4+
"attr-value-double-quotes": true,
5+
"attr-value-not-empty": true,
6+
"attr-no-duplication": true,
7+
"doctype-first": true,
8+
"tag-pair": true,
9+
"tag-self-close": true,
10+
"spec-char-escape": true,
11+
"id-unique": true,
12+
"src-not-empty": true,
13+
"head-script-disabled": true,
14+
"img-alt-require": true,
15+
"doctype-html5": true,
16+
"id-class-value": true,
17+
"style-disabled": true,
18+
"space-tab-mixed-disabled": true,
19+
"id-class-ad-disabled": true,
20+
"href-abs-or-rel": true,
21+
"attr-unsafe-chars": true
22+
}

‎.jshintrc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"asi": true,
3+
"curly": true,
4+
"eqeqeq": true,
5+
"immed": true,
6+
"latedef": true,
7+
"newcap": true,
8+
"noarg": true,
9+
"sub": true,
10+
"undef": true,
11+
"boss": true,
12+
"eqnull": true,
13+
"node": true,
14+
"indent": 4
15+
}

‎LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2015 kazu69
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

‎Readme.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
gulp-htmlhint-inline
2+
================
3+
4+
## Usage
5+
6+
First, install `gulp-htmlhint-inline` as a development dependency:
7+
8+
```shell
9+
npm install --save-dev gulp-htmlhint-inline
10+
```
11+
12+
Then, add it to your `gulpfile.js`:
13+
14+
```javascript
15+
var gulp = require('gulp'),
16+
htmlhint_inline = require('gulp-htmlhint-inline');
17+
18+
gulp.task('htmlhint', function () {
19+
var options = {
20+
htmlhintrc: './.htmlhintrc',
21+
ignores: {
22+
'<?php': '?>'
23+
},
24+
patterns: [
25+
{
26+
match: /hoge/g,
27+
replacement: 'fuga'
28+
}
29+
]
30+
};
31+
32+
gulp.src('test/*.phtml')
33+
.pipe(htmlhint_inline(options))
34+
.pipe(htmlhint_inline.reporter())
35+
.pipe(htmlhint_inline.reporter('fail'));
36+
});
37+
```
38+
39+
## Options
40+
41+
#### htmlhintrc
42+
Type: String Default value: null
43+
44+
```htmlhintrc``` file must be a valid JSON.
45+
If you specify this file, options that have been defined in it will be used in the global.
46+
If there is specified in the task options, the options in this file will be overwritten.
47+
48+
```json
49+
{
50+
"tagname-lowercase": true
51+
}
52+
```
53+
54+
#### ignores
55+
Type: Object Default: {}
56+
57+
Remove program tag pairs.
58+
59+
#### patterns
60+
Type: Array Default: []
61+
62+
Enable the replacement by the pattern
63+
64+
##### patterns.match
65+
66+
Type: RegExp|String
67+
68+
Indicates the matching expression.
69+
70+
##### patterns.replacement
71+
72+
Type: String | Function
73+
74+
#### reporter
75+
76+
##### Default Reporter
77+
78+
```js
79+
var gulp = require('gulp'),
80+
htmlhint_inline = require('gulp-htmlhint-inline');
81+
82+
gulp.task('htmlhint', function () {
83+
var options = {
84+
htmlhintrc: './.htmlhintrc',
85+
ignores: {
86+
'<?php': '?>'
87+
}
88+
};
89+
90+
gulp.src('test/*.phtml')
91+
.pipe(htmlhint_inline(options))
92+
.pipe(htmlhint_inline.reporter());
93+
});
94+
```
95+
96+
##### Fail Reporter
97+
98+
In order to end the task when your task happened error of HTMLHint, please use this reporter.
99+
100+
```js
101+
var gulp = require('gulp'),
102+
htmlhint_inline = require('gulp-htmlhint-inline');
103+
104+
gulp.task('htmlhint', function () {
105+
var options = {
106+
htmlhintrc: './.htmlhintrc',
107+
ignores: {
108+
'<?php': '?>'
109+
}
110+
};
111+
112+
gulp.src('test/*.phtml')
113+
.pipe(htmlhint_inline(options))
114+
.pipe(htmlhint_inline.reporter('fail'));
115+
});
116+
```
117+
118+
##### Custom Reporter
119+
120+
You can also use the custom reporter that you have created.
121+
122+
```js
123+
124+
var gulp = require('gulp'),
125+
htmlhint_inline = require('gulp-htmlhint-inline');
126+
127+
gulp.task('htmlhint', function () {
128+
var options = {
129+
htmlhintrc: './.htmlhintrc',
130+
ignores: {
131+
'<?php': '?>'
132+
}
133+
};
134+
135+
var cutomReporter = function (file) {
136+
if (!file.htmlhint_inline.success) {
137+
console.log('custom reporter: htmlhint-inline fail in '+ file.path);
138+
}
139+
}
140+
141+
return gulp.src('test/*.phtml')
142+
.pipe(htmlhint_inline(options))
143+
.pipe(htmlhint_inline.reporter())
144+
.pipe(htmlhint_inline.reporter(cutomReporter));
145+
});
146+
147+
```
148+
149+
## License
150+
151+
[MIT License](http://en.wikipedia.org/wiki/MIT_License)
152+
153+
[npm-url]: https://npmjs.org/package/gulp-htmlhint-inline
154+
[npm-image]: https://badge.fury.io/js/gulp-htmlhint-inline.png

‎gulpfile.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
3+
var gulp = require('gulp'),
4+
jshint = require('gulp-jshint'),
5+
htmlhint_inline = require('./index.js');
6+
7+
gulp.task('lint', function () {
8+
return gulp.src('./*.js')
9+
.pipe(jshint())
10+
.pipe(jshint.reporter('default', { verbose: true }))
11+
.pipe(jshint.reporter('fail'));
12+
});
13+
14+
gulp.task('test', ['lint'], function () {
15+
var options = {
16+
htmlhintrc: './.htmlhintrc',
17+
ignores: {
18+
'<?php': '?>'
19+
},
20+
patterns: [
21+
{
22+
match: /hoge/g,
23+
replacement: 'fuga'
24+
}
25+
]
26+
};
27+
return gulp.src('test/*.phtml')
28+
.pipe(htmlhint_inline(options))
29+
.pipe(htmlhint_inline.reporter())
30+
.pipe(htmlhint_inline.reporter('fail'));
31+
});

‎index.js

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
var fs = require('fs'),
2+
through2 = require('through2'),
3+
gutil = require('gulp-util'),
4+
tempfile = require('tempfile'),
5+
HTMLHint = require('htmlhint').HTMLHint,
6+
PluginError = gutil.PluginError;
7+
8+
var PLUGIN_NAME = 'gulp-htmlhint-inline';
9+
10+
var log = gutil.log,
11+
color = gutil.colors;
12+
13+
var escape = function(string) {
14+
'use strict';
15+
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
16+
}
17+
18+
var removeTagEachLIne = function(lines, start, end) {
19+
'use strict';
20+
21+
var tagSection = false;
22+
23+
lines.forEach(function (line, i) {
24+
var startTag = escape(start),
25+
stopTag = escape(end),
26+
starts = new RegExp(startTag, 'i').test(line),
27+
stops = new RegExp(stopTag, 'i').test(line),
28+
inline = new RegExp(startTag + '.+?' + stopTag, 'ig');
29+
30+
if(starts && (starts && stops)) {
31+
lines[i] = line.replace(inline, '');
32+
}
33+
else if(starts && !stops) {
34+
tagSection = true;
35+
lines[i] = '';
36+
}
37+
else if(stops) {
38+
lines[i] = '';
39+
tagSection = false;
40+
}
41+
42+
if(tagSection) { lines[i] = ''; }
43+
});
44+
}
45+
46+
var removeTags = function(source, ignores) {
47+
'use strict';
48+
49+
var lines = source.split('\n');
50+
for (var key in ignores) {
51+
if (ignores.hasOwnProperty(key)) {
52+
removeTagEachLIne(lines, key, ignores[key]);
53+
}
54+
}
55+
return lines.join('\n');
56+
}
57+
58+
var removePatterns = function (source, patterns) {
59+
'use strict';
60+
return patterns.reduce(function (content, pattern){
61+
return content.replace(pattern.match, pattern.replacement || '');
62+
}, source);
63+
}
64+
65+
var removeStrings = function(file, ignores, patterns) {
66+
'use strict';
67+
68+
var source = file.contents.toString();
69+
70+
if(ignores && Object.keys(ignores).length !== 0) {
71+
source = removeTags(source, ignores);
72+
}
73+
74+
if(patterns && Array.isArray(patterns)) {
75+
source = removePatterns(source, patterns);
76+
}
77+
78+
return source;
79+
}
80+
81+
var hint = function(file, options) {
82+
'use strict';
83+
84+
var ignores, patterns, htmlhintrcRuleset;
85+
86+
if(options.ignores) { ignores = options.ignores || {} }
87+
88+
if(options.patterns) { patterns = options.patterns || []; }
89+
90+
if (options.htmlhintrc && options.htmlhintrc === typeof String) {
91+
try {
92+
var htmlhintrc = fs.readFileSync(options.htmlhintrc);
93+
htmlhintrcRuleset = JSON.parse(htmlhintrc);
94+
} catch (err) {
95+
throw new Error( PLUGIN_NAME + ': Cannot parse .htmlhintrc' );
96+
}
97+
}
98+
99+
var ruleset = HTMLHint.defaultRuleset,
100+
html = removeStrings(file, ignores, patterns);
101+
102+
for(var rule in htmlhintrcRuleset) {
103+
ruleset[rule] = htmlhintrcRuleset[rule];
104+
}
105+
106+
return HTMLHint.verify(html, ruleset);
107+
}
108+
109+
var gulpHtmlhintInline = function(options) {
110+
'use strict';
111+
112+
var transform = function(file, enc, callback) {
113+
if(file.isNull()) {
114+
this.psuh(file);
115+
return callback();
116+
}
117+
118+
if (file.isStream()) {
119+
this.emit('error', new PluginError(PLUGIN_NAME, 'Streams are not supported!'));
120+
return callback(null, file);
121+
}
122+
123+
if(file.isBuffer()) {
124+
file.htmlhint_inline = hint(file, options);
125+
return callback(null, file);
126+
}
127+
128+
this.push(file);
129+
callback();
130+
}
131+
132+
return through2.obj(transform);
133+
}
134+
135+
gulpHtmlhintInline.defaultReporter = function(file) {
136+
'use strict';
137+
138+
var report = file.htmlhint_inline;
139+
140+
report.success = false;
141+
142+
if(report.length === 0) { report.success = true; }
143+
144+
if(report.success) { log(color.green(file.path + ' lint free.')); }
145+
146+
if(!report.success) {
147+
log(color.cyan(report.length) + ' error' + (report.length === 1 ? '' : 's') + ' found');
148+
149+
report.forEach(function(message) {
150+
var evidence = message.evidence,
151+
line = message.line,
152+
col = message.col,
153+
msg = '';
154+
155+
if (col === 0) {
156+
evidence = color.red('?') + evidence;
157+
} else if(col > evidence.length) {
158+
evidence = evidence + color.red(' ');
159+
} else {
160+
evidence = evidence.slice(0, col - 1) + color.red(evidence[col - 1]) + evidence.slice(col);
161+
}
162+
163+
msg = color.red('[') + color.yellow('L ' + message.line) + color.red(':') + color.yellow('C' + message.col) + color.red(']') + ' ' + color.yellow(message.message);
164+
log(msg);
165+
log(evidence);
166+
});
167+
}
168+
}
169+
170+
gulpHtmlhintInline.failReporter = function() {
171+
'use strict';
172+
173+
var error = null,
174+
fails = false;
175+
176+
var transform = function(file, encoding, callback) {
177+
(fails = fails || []).push(file.path);
178+
179+
if(file.htmlhint_inline && file.htmlhint_inline.length !== 0) {
180+
error = new PluginError(PLUGIN_NAME, {
181+
message: PLUGIN_NAME + ' failed for: ' + fails.join(', '),
182+
showStack: false
183+
});
184+
}
185+
186+
callback(null, file);
187+
}
188+
189+
var flush = function(callback) {
190+
callback(error);
191+
}
192+
193+
return through2.obj(transform, flush);
194+
}
195+
196+
gulpHtmlhintInline.reporter = function(customReporter) {
197+
'use strict';
198+
199+
var reporter = gulpHtmlhintInline.defaultReporter,
200+
result = null;
201+
202+
if(typeof customReporter === 'function') { reporter = customReporter; }
203+
204+
if(typeof customReporter === 'object' && typeof customReporter.reporter === 'function') {
205+
reporter = customReporter.reporter;
206+
}
207+
208+
if(customReporter === 'fail') { return gulpHtmlhintInline.failReporter(); }
209+
210+
var stream = through2.obj(function(file, enc, callback) {
211+
if (file.htmlhint_inline) { reporter(file); }
212+
callback(null, file);
213+
});
214+
215+
return stream;
216+
}
217+
218+
if (exports && typeof exports === 'object') { module.exports = gulpHtmlhintInline; }

‎package.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "gulp-htmlhint-inline",
3+
"description": "Gulp plugin for linting inline html",
4+
"version": "0.0.1",
5+
"homepage": "https://github.com/kazu69/gulp-htmlhint-inline",
6+
"main": "index.js",
7+
"author": {
8+
"name": "kazu69"
9+
},
10+
"repository": {
11+
"type": "git",
12+
"url": "git://github.com/kazu69/gulp-htmlhint-inline.git"
13+
},
14+
"bugs": {
15+
"url": "https://github.com/kazu69/gulp-htmlhint-inline/issues"
16+
},
17+
"licenses": [
18+
{
19+
"type": "MIT",
20+
"url": "https://github.com/kazu69/gulp-htmlhint-inline/blob/master/LICENSE"
21+
}
22+
],
23+
"engines": {
24+
"node": ">= 0.8.0"
25+
},
26+
"scripts": {
27+
"test": "gulp test"
28+
},
29+
"dependencies": {
30+
"gulp-util": "^3.0.4",
31+
"htmlhint": "^0.9.7",
32+
"through2": "^0.6.3"
33+
},
34+
"devDependencies": {
35+
"gulp": "^3.8.11",
36+
"gulp-jshint": "^1.9.2"
37+
},
38+
"peerDependencies": {
39+
"gulp": "^3.8.11"
40+
},
41+
"keywords": [
42+
"gulpplugin",
43+
"lint",
44+
"htmlhint",
45+
"inline",
46+
"gulp"
47+
],
48+
"maintainers": [
49+
{
50+
"name": "kazu69"
51+
}
52+
]
53+
}

‎test/index.phtml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
ecoh 'htmlhint-inline';
3+
?>
4+
<!doctype html>
5+
<html lang="en">
6+
<head>
7+
<meta charset="UTF-8">
8+
<title>gulp htmlhint-inline</title>
9+
<script>
10+
var a, b, c;
11+
<?php if(true): ?>
12+
var test = 'test';
13+
<?prp endif: ?>
14+
console.log(test);
15+
</script>
16+
</head>
17+
<body>
18+
<?php /*
19+
// test comment area
20+
<div>
21+
<?php // echo 'test'; ?>
22+
<img src="" alt="">
23+
<ul>
24+
<li></li>
25+
</ul>
26+
</div>
27+
*/?>
28+
<p>hoge</p>
29+
<ul id="test" class="<?php echo 'test'; ?>" data-list="<?php echo 'list'; ?>">
30+
<?php foreach($array as $val): ?>
31+
<li class="item">
32+
<a onlick="void(0);" href="<?php echo 'https://github.com'; ?>">github</a>
33+
</li>
34+
<?php endforeach; ?>
35+
</ul>
36+
<small>hogemoge</small>
37+
</body>
38+
</html>

0 commit comments

Comments
 (0)
Please sign in to comment.