/SEO_Sniffer

For checking the SEO.

Primary LanguageJavaScript

Build Status npm version License: LGPL v3

SEO_Sniffer

Develop a Node.js package to let user can use this package to scan a HTML file and show all of the SEO defects.

Features

Implement following 5 pre-defined SEO rules for this package

  1. Detect if any <img /> tag without alt attribute
  2. Detect if any <a /> tag without rel attribute
  3. In <head> tag
  4. Detect if header doesn’t have <title> tag
  5. Detect if header doesn’t have <meta name=“descriptions” ... /> tag
  6. Detect if header doesn’t have <meta name=“keywords” ... /> tag
  7. Detect if there’re more than 15 <strong> tag in HTML (15 is a value should be configurable by user)
  8. Detect if a HTML have more than one <H1> tag.

Development Requirement

  1. User is free to chain any rules by themselves
  2. For example, they can only use the rule 1 and 4 or only use rule 2.
  3. The order of rules is doesn’t matter
  4. User can define and use their own rules easily
  5. The input can be:
  6. A HTML file (User is able to config the input path)
  7. Node Readable Stream
  8. The output can be:
  9. A file (User is able to config the output destination)
  10. Node Writable Stream
  11. Console
  12. Package should be flexible:
  13. When you want to implement additional rules for <meta> tag, The code changes should be small. Ex: Checking <meta name=“robots” /> existing or not?!

Prerequisites

Developing by the Node.js 11.5

Installation

npm install seo_sniffer

Initializing Input/Output

By Constructor

const sniffer = new SnifferManager({
  input: 'PathToFile',
  // 'PathToFile' or fs.ReadStream
  
  output: 'PathToFile'
  // 'PathToFile' or fs.WriteStream or 'console'
})

By setInput()/setOutput()

const sniffer = new SnifferManager()

sniffer.setInput('PathToFile')
// 'PathToFile' or fs.ReadStream

sniffer.setOnput('PathToFile')
// 'PathToFile' or fs.WriteStream or 'console'

Check Methods & Export Reports

hasTagWithoutAttr()

Export Tag/Attribute:

`Has ${diff} ${tag} tag without ${attribute}.`
`No found any ${tag} tag without ${attribute}.`

Export Tag/Attribute/Value:

`Has ${diff} ${tag} tag without ${attribute}="${value}".`
`No found any ${tag} tag without ${attribute}="${value}".`

isTagNotExist()

Export Tag:

`Not find any match on the ${tag}!!`
`Find matches on the ${tag}: ${counter}`

Export Tag/Attribute:

`Not find any match on the ${tag} with ${attribute}!!`
`Find matches on the ${tag} with ${attribute}: ${counter}`

Export Tag/Attribute/Value:

`Not find any match on the ${tag} with ${attribute}="${value}"!!`
`Find matches on the ${tag} with ${attribute}="${value}": ${counter}`

isTagOverLimit()

Export Tag:

`There are ${counter} ${tag} tag, it's over the limit ${limit}!!`
`Find matches on the ${tag} tag: ${counter}`

Export Tag/Attribute:

`There are ${counter} ${tag} with ${attribute}, it's over the limit ${limit}!!`
`Find matches on the ${tag} with ${attribute}: ${counter}`

Export Tag/Attribute/Value:

`There are ${counter} ${tag} with ${attribute}="${value}", it's over the limit ${limit}!!`
`Find matches on the ${tag} with ${attribute}="${value}": ${counter}`

isTagNotOnly()

Export is the same with "isTagOverLimit"

detectSubRules()

Calling the other check methods to detect by the setting in the subRules.

Rule Set Format

{
  rule: 'Check_Method_Name',
  tag: 'HTML_Tag_Name',
  attribute: 'Attribute_Name',
  value: 'Attribute_Value',
  subRules: [{Rule_set}, ...]
  limit: Integer
}
  • Must have: rule & tag
  • If you want to use the subRules, the rule must be "detectSubRules" and the limit will be useless.
  • The limit will be setting up with a default 0, if you are not setting a value.

Predefine Rules

isImageWithoutAlt

Detect if any <img /> tag without alt attribute

{
  rule: 'hasTagWithoutAttr',
  tag: 'img',
  attribute: 'alt'
}

isAWithoutRel

Detect if any <a /> tag without rel attribute

{
  rule: 'hasTagWithoutAttr',
  tag: 'a',
  attribute: 'rel'
}

isHeadLegal

In <head> tag

  • Detect if header doesn’t have <title> tag
  • Detect if header doesn’t have <meta name=“descriptions” ... /> tag
  • Detect if header doesn’t have <meta name=“keywords” ... /> tag
{
  rule: 'detectSubRules',
  tag: 'head',
  subRules: [{
    rule: 'isTagNotExist',
    tag: 'title'
  },
  {
    rule: 'isTagNotExist',
    tag: 'meta',
    attribute: 'name',
    value: 'description'
  },
  {
    rule: 'isTagNotExist',
    tag: 'meta',
    attribute: 'name',
    value: 'keywords'
  }]
}

isStrongOverLimit

Detect if there’re more than 15 <strong> tag in HTML (15 is a value should be configurable by user)

{
  rule: 'isTagOverLimit',
  tag: 'strong',
  limit: 15
}

isH1NotOnly

Detect if a HTML have more than one <H1> tag

{
  rule: 'isTagNotOnly',
  tag: 'H1'
}

Example

Basic

By Constructor

const { SnifferManager } = require('seo_sniffer')

const ioConfig = {
  input: 'PathToFile',
  // input: fs.createReadStream('PathToFile'),

  output: 'PathToFile'
  // output: fs.createWriteStream('PathToFile')
  // output: 'console'
}

const sniffer = new SnifferManager(ioConfig)

sniffer.detect()

By setInput()/setOutput()

const { SnifferManager } = require('seo_sniffer')

const ioConfig = {
  input: 'PathToFile',
  // input: fs.createReadStream('PathToFile'),

  output: 'PathToFile'
  // output: fs.createWriteStream('PathToFile')
  // output: 'console'
}

const sniffer = new SnifferManager()

sniffer.setInput('PathToFile')
// 'PathToFile' or fs.createReadStream(PathToFile)

sniffer.setOnput('PathToFile')
// 'PathToFile' or fs.createWriteStream(PathToFile) or 'console'

sniffer.detect()

No Input/Output by console

const { SnifferManager } = require('seo_sniffer')

const sniffer = new SnifferManager()

sniffer.check('YourContext')
// sniffer.check('YourContext', [Rules])

Choice from the Predefine Rules

const { PredefineRules, SnifferManager } = require('seo_sniffer')

const ioConfig = {
  input: 'PathToFile',
  // input: fs.createReadStream('PathToFile'),

  output: 'PathToFile'
  // output: fs.createWriteStream('PathToFile')
  // output: 'console'
}

const sniffer = new SnifferManager(ioConfig)

sniffer.detect([
  PredefineRules.isImageWithoutAlt,
  PredefineRules.isAWithoutRel,
  PredefineRules.isHeadLegal
])

Modify the Predefine Rules

If you want to implement additional rules for <meta> tag. Ex: Checking <meta name=“robots” />

const { PredefineRules, SnifferManager } = require('seo_sniffer')

const ioConfig = {
  input: 'PathToFile',
  // input: fs.createReadStream('PathToFile'),

  output: 'PathToFile'
  // output: fs.createWriteStream('PathToFile')
  // output: 'console'
}

const sniffer = new SnifferManager(ioConfig)

PredefineRules.isHeadLegal.subRules.push({
  rule: 'isTagNotExist',
  tag: 'meta',
  attribute: 'name',
  value: 'robots'
})

sniffer.reinitDefaultRules()

sniffer.detect()

If you want to reset the limit of <strong> from 15 to 5

const { PredefineRules, SnifferManager } = require('seo_sniffer')

const ioConfig = {
  input: 'PathToFile',
  // input: fs.createReadStream('PathToFile'),

  output: 'PathToFile'
  // output: fs.createWriteStream('PathToFile')
  // output: 'console'
}

const sniffer = new SnifferManager(ioConfig)

PredefineRules.isStrongOverLimit.limit = 5

sniffer.reinitDefaultRules()

sniffer.detect()

Customize the rule

The Customize rules & the predefine rules can be used in the same time.

const { SnifferManager } = require('seo_sniffer')

const ioConfig = {
  input: 'PathToFile',
  // input: fs.createReadStream('PathToFile'),

  output: 'PathToFile'
  // output: fs.createWriteStream('PathToFile')
  // output: 'console'
}

const sniffer = new SnifferManager(ioConfig)

sniffer.detect([{
  rule: 'isTagNotExist',
  tag: 'meta',
  attribute: 'name',
  value: 'robots'
},
{
  rule: 'isTagNotExist',
  tag: 'meta',
  attribute: 'name',
  value: 'keywords'
}])

Mixed Customize/Predefine rules

const { PredefineRules, SnifferManager } = require('seo_sniffer')

const ioConfig = {
  input: 'PathToFile',
  // input: fs.createReadStream('PathToFile'),

  output: 'PathToFile'
  // output: fs.createWriteStream('PathToFile')
  // output: 'console'
}

const sniffer = new SnifferManager(ioConfig)

sniffer.detect([
  PredefineRules.isStrongOverLimit,
  PredefineRules.isImageWithoutAlt,
  {
    rule: 'isTagNotExist',
    tag: 'meta',
    attribute: 'name',
    value: 'robots'
  },
  {
    rule: 'isTagNotExist',
    tag: 'meta',
    attribute: 'name',
    value: 'keywords'
  }
])