Skip to content

Commit

Permalink
cover all
Browse files Browse the repository at this point in the history
  • Loading branch information
harttle committed Jun 27, 2017
1 parent 7b4d94c commit 136b77b
Show file tree
Hide file tree
Showing 19 changed files with 275 additions and 173 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/
coverage/
tmp/
*.log
*.swp
Expand Down
54 changes: 2 additions & 52 deletions bin/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

const program = require('commander')
const pkg = require('../package.json')
const Validator = require('..')
const path = require('path')
const http = require('http')
const url = require('url')
const mkServer = require('../src/http')

/// /////////////////////////////////////////////////////////////////
// Initialize CLI
Expand All @@ -31,56 +29,8 @@ if (program['conf']) {
var configPath = path.resolve(process.cwd(), program['conf'])
config = require(configPath)
}
var validator = config ? Validator(config) : Validator()

/// /////////////////////////////////////////////////////////////////
// Initialize Server
var routes = {}
const server = http.createServer((req, res) => {
var data = ''
req.on('data', (chunk) => {
data += chunk
})
req.on('end', () => {
var urlObj = url.parse(req.url, true)
var route = routes[urlObj.pathname]
if (!route) {
res.statusCode = 404
res.end()
}
req.params = urlObj.query
req.body = data
route(req, res)
})
})

/*
* Router: /
*/
var usage = [
'Usage:',
' GET / for help',
' POST /validate with HTML body to validate',
' POST /validate?fast=true with HTML body to fast validate'
].join('\n')
routes['/'] = function (req, res) {
res.end(usage)
}

/*
* Router: /validate
*/
routes['/validate'] = function (req, res) {
var fastMode = (req.params.fast === 'true')
var result = validator.validate(req.body, {fastMode: fastMode})
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(result, null, 4))
}

/// ///////////////////////////////////////////////////////////////
// Return Server
var server = mkServer(config)
server.listen(program['port'], program['host'], function () {
console.log(`[http] listening to ${program['host']}:${program['port']}`)
})

module.exports = server
4 changes: 4 additions & 0 deletions examples/http.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
# start http server first: node ./bin/http.js

curl localhost:4444/validate -X POST --data '<html></html>'
31 changes: 11 additions & 20 deletions src/engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ function Engine (rules) {
}

Engine.prototype.setRules = function (rules) {
logger.debug('setting rules %J', rules)
assert(typeof rules === 'object',
'rules object expected, but ' + (typeof rules) + ' found')
this.config = ruleParser.mkConfig(rules)
Expand Down Expand Up @@ -214,26 +213,18 @@ module.exports = function (rules) {
}

function behaveBuggyAsTheCPPVersion (doc, errorGenertor) {
try {
var head = findFirstTagChild(findFirstTagChild(doc))
if (head.tagName !== 'head') {
return
var head = findFirstTagChild(findFirstTagChild(doc))
var noscriptAppeared = false

head.childNodes.forEach((node) => {
if (node.tagName === 'noscript') {
noscriptAppeared = true
} else if (node.tagName && noscriptAppeared) {
// it's a tag after noscript
var err = ERR.INVALID_NOSCRIPT
errorGenertor(err)
}

var noscriptAppeared = false
head.childNodes.forEach((node) => {
if (node.tagName === 'noscript') {
noscriptAppeared = true
} else if (node.tagName && noscriptAppeared) {
// it's a tag after noscript
var err = ERR.INVALID_NOSCRIPT
errorGenertor(err)
}
})
} catch (e) {
// let it be...
console.log('behaveBuggyAsTheCPPVersion error:', e)
}
})
}

function findFirstTagChild (parent) {
Expand Down
50 changes: 50 additions & 0 deletions src/http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const Validator = require('..')
const url = require('url')
const http = require('http')
const usage = [
'Usage:',
' GET / for help',
' POST /validate with HTML body to validate',
' POST /validate?fast=true with HTML body to fast validate'
].join('\n')

function mkServer (rules) {
var validator = rules ? Validator(rules) : Validator()
var routes = {}
var server = mkRouter(routes)

routes['/'] = function (req, res) {
res.end(usage)
}

routes['/validate'] = function (req, res) {
var fastMode = (req.params.fast === 'true')
var result = validator.validate(req.body, {fastMode: fastMode})
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify(result, null, 4))
}

return server
}

function mkRouter (routes) {
return http.createServer((req, res) => {
var data = ''
req.on('data', (chunk) => {
data += chunk
})
req.on('end', () => {
var urlObj = url.parse(req.url, true)
var route = routes[urlObj.pathname]
if (!route) {
res.statusCode = 404
return res.end()
}
req.params = urlObj.query
req.body = data
route(req, res)
})
})
}

module.exports = mkServer
11 changes: 5 additions & 6 deletions src/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function match (root, path) {
* create logger method with STDOUT instance and trace ID
* @param {Function} output STDOUT instance
* @param {String} id trace ID
* legacy:
* legal:
* createWith(console.log.bind(console), 'mip:cache:getCache')
*/
function createWith (output, id) {
Expand All @@ -55,7 +55,7 @@ function createWith (output, id) {
* Pad number to 2-digit.
* @param {Number} n The number
* @return {String} 2-digit number string
* legacy:
* legal:
* pad(2) // 02
* pad(22) // 22
*/
Expand All @@ -66,7 +66,7 @@ function pad (n) {
/*
* Generate a timestamp from current time
* @return {String} the timestamp string
* legacy:
* legal:
* timestamp() // "2016/09/27-17:31:22"
*/
function timestamp () {
Expand All @@ -88,7 +88,7 @@ var formatRegExp = /%[sdjJ%]/g
* format arguments to a single string
* @param {String} f Optional, the format string
* @return {String} the formated string
* legacy:
* legal:
* format('%s', 'foo', 'bar') // foo bar
* format('%d', '200', 'bar') // 200 bar
* format('%j', {foo: 'bar'}, 'bar')
Expand All @@ -104,8 +104,7 @@ function format (f) {
var str = ''
if (isString(f)) {
i++
str += String(f).replace(formatRegExp, function (x) {
if (i >= len) return x
str += f.replace(formatRegExp, function (x) {
switch (x) {
case '%%':
return '%'
Expand Down
19 changes: 9 additions & 10 deletions src/matcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function matchValue (src, target) {
* object match: match src with target
* @param {Object} src the object to match
* @param {Object} target the object to match with
* legacy:
* legal:
* match({
* id: 'modal-user'
* }, {
Expand All @@ -58,7 +58,7 @@ function match (src, target) {
* attributes match
* @param {ASTNode} node the node of which attributes will be matched
* @param {Object} target the attribute list object to match with
* legacy:
* legal:
* matchAttrs(node, {
* style: 'color:red',
* id: '/mip-.+/'
Expand All @@ -76,7 +76,7 @@ function matchAttrs (node, target) {
* match ancestor name
* @param {ASTNode} node the node of which parent will be matched
* @param {String} ancestorNodeName string or regex-like string to match with
* legacy:
* legal:
* matchAncestor(node, 'form');
* matchAncestor(node, '/form|div|section/'
*/
Expand All @@ -94,7 +94,7 @@ function matchAncestor (node, ancestorNodeName) {
* match parent name
* @param {ASTNode} node the node of which parent will be matched
* @param {String} parentNodeName string or regex-like string to match with
* legacy:
* legal:
* matchParent(node, 'form');
* matchParent(node, '/form|div|section/'
*/
Expand All @@ -112,7 +112,7 @@ function matchParent (node, parentNodeName) {
* match descendant node name
* @param {ASTNode} node the node of which parent will be matched
* @param {String} descendantNodeName string or regex-like string to match with
* legacy:
* legal:
* matchDescendant(node, 'form');
* matchDescendant(node, '/form|div|section/'
*/
Expand All @@ -127,7 +127,7 @@ function matchDescendant (node, descendantNodeName) {
* nomatch descendant node name
* @param {ASTNode} node the node of which parent will be matched
* @param {String} descendantNodeName string or regex-like string to match with
* legacy:
* legal:
* nomatchDescendant(node, 'form');
* nomatchDescendant(node, '/form|div|section/'
*/
Expand All @@ -141,8 +141,7 @@ function nomatchDescendant (node, descendantNodeName) {
}

function dfsUntil (node, predict) {
var children = node.childNodes || []
return predict(node) || children.some(child => dfsUntil(child, predict))
return predict(node) || node.childNodes.some(child => dfsUntil(child, predict))
}

/*
Expand All @@ -163,7 +162,7 @@ function createNode (nodeName, attrsObj) {

/*
* Generate a fingerprint for given nodeName and attributes
* legacy:
* legal:
* // returns: <div id="modal">
* fingerprintByObject('div', {id: 'modal'});
*/
Expand Down Expand Up @@ -191,7 +190,7 @@ function fingerprintByTag (node) {
* Match tagnames from the given HTML
* @param {Array} tagNames
* @param {String} html
* legacy: matchTagNames(['div', 'head', 'iframe'], '<div><iframe></div>')
* legal: matchTagNames(['div', 'head', 'iframe'], '<div><iframe></div>')
*/
function matchTagNames (tagNames, html) {
var tagsStr = tagNames.join('|')
Expand Down
6 changes: 3 additions & 3 deletions src/rule-parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ function mkConfig (rules) {
}
}

function typedRules (config) {
var rules = TYPED_RULES[config]
function typedRules (type) {
var rules = TYPED_RULES[type]
if (!rules) {
throw new Error('rules not found for config ' + config)
throw new Error('rules not found for type ' + type)
}
return rules
}
Expand Down
4 changes: 3 additions & 1 deletion src/validators/disallowed_tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ function validatePolyfill (error, engine) {
var tagName = tag.match(/\w+/)
var rules = _.get(engine.config.nodes, `${tagName}`)
_.map(rules, rule => {
if (!rule.disallow) return
if (!rule.disallow) {
return
}

var err = ERR.DISALLOWED_TAG
error(err, tag)
Expand Down
17 changes: 7 additions & 10 deletions src/validators/duplicate_unique_tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,11 @@ exports.onBegin = function (error, engine) {

_.forOwn(engine.config.nodes, (rules, ruleName) => {
_.map(rules, rule => {
if (rule.duplicate) {
_.map(rule.duplicate, pattern => {
var fingerprint = matcher.fingerprintByObject(ruleName, pattern)
var hash = fingerprint + rule.id
cache[hash] = 0
})
}
_.map(rule.duplicate, pattern => {
var fingerprint = matcher.fingerprintByObject(ruleName, pattern)
var hash = fingerprint + rule.id
cache[hash] = 0
})
})
})
validatePolyfill(error, engine)
Expand All @@ -27,8 +25,7 @@ exports.onBegin = function (error, engine) {
exports.onNode = function (node, rule, error) {
if (!rule.duplicate || _.includes(POLYFILL_TAGS, node.nodeName)) return

var duplicates = _.isArray(rule.duplicate)
? rule.duplicate : [rule.duplicate]
var duplicates = rule.duplicate

_.map(duplicates, pattern => {
if (!matcher.matchAttrs(node, pattern)) return
Expand All @@ -46,7 +43,7 @@ function validatePolyfill (error, engine) {
POLYFILL_TAGS.forEach(tag => {
var rules = _.get(engine.config.nodes, `${tag}`)
_.map(rules, rule => {
if (!rule.duplicate) return
if (rule.duplicate.length === 0) return
var matches = matcher.matchTagNames([tag], engine.html)
if (matches.length > 1) {
error(ERR.DUPLICATE_UNIQUE_TAG, tag)
Expand Down

0 comments on commit 136b77b

Please sign in to comment.