Skip to content

Commit

Permalink
feat: new audit result schema
Browse files Browse the repository at this point in the history
  • Loading branch information
dipratap committed Sep 18, 2024
1 parent b59c457 commit 0b71522
Show file tree
Hide file tree
Showing 3 changed files with 642 additions and 688 deletions.
15 changes: 10 additions & 5 deletions src/metatags/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,23 @@ export const MODERATE = 'Moderate';

// Audit result constants
export const NON_UNIQUE = 'non-unique';
export const MISSING_TAGS = 'missing_tags';
export const EMPTY_TAGS = 'empty_tags';
export const LENGTH_CHECK_FAIL_TAGS = 'length_check_fail_tags';
export const DUPLICATE_TAGS = 'duplicate_tags';
export const MULTIPLE_H1_COUNT = 'multiple_h1_count';

// Tags lengths
export const TAG_LENGTHS = {
[TITLE]: {
minLength: 40,
maxLength: 60,
minLength: 25,
maxLength: 75,
},
[DESCRIPTION]: {
minLength: 140,
maxLength: 160,
minLength: 100,
maxLength: 180,
},
[H1]: {
maxLength: 60,
maxLength: 75,
},
};
168 changes: 58 additions & 110 deletions src/metatags/seo-checks.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@
*/

import {
DESCRIPTION,
TITLE,
H1,
TAG_LENGTHS,
HIGH,
MODERATE, NON_UNIQUE,
DESCRIPTION, TITLE, H1, TAG_LENGTHS, MISSING_TAGS, EMPTY_TAGS,
LENGTH_CHECK_FAIL_TAGS, DUPLICATE_TAGS, MULTIPLE_H1_COUNT,
} from './constants.js';

class SeoChecks {
Expand All @@ -34,38 +30,6 @@ class SeoChecks {
};
}

/**
* Sorts Non Unique H1 tags in descending order of their occurrence count
*/
sortNonUniqueH1Tags() {
if (!this.detectedTags[H1][0] || !this.detectedTags[H1][0][NON_UNIQUE]) {
return;
}
// Convert the non-unique H1 tags object to an array of [key, value] entries
const sortedEntries = Object.entries(this.detectedTags[H1][0][NON_UNIQUE])
.sort(([, a], [, b]) => b.count - a.count); // Sort by `count` in descending order

this.detectedTags[H1][0][NON_UNIQUE] = Object.fromEntries(sortedEntries);
}

/**
* Adds an entry to the detected tags array.
* @param {string} pageUrl - The URL of the page.
* @param {string} tagName - The name of the tag (e.g., 'title', 'description', 'h1').
* @param {string} tagContent - The content of the tag.
* @param {string} seoImpact - The impact level of the issue (e.g., 'High', 'Moderate').
* @param {string} seoOpportunityText - The text describing the SEO opportunity or issue.
*/
addDetectedTagEntry(pageUrl, tagName, tagContent, seoImpact, seoOpportunityText) {
this.detectedTags[tagName].push({
pageUrl,
tagName,
tagContent,
seoImpact,
seoOpportunityText,
});
}

/**
* Creates a message for length checks.
* @param {string} tagName - The name of the tag (e.g., 'title', 'description', 'h1').
Expand All @@ -92,13 +56,8 @@ class SeoChecks {
[TITLE, DESCRIPTION, H1].forEach((tagName) => {
if (pageTags[tagName] === undefined
|| (Array.isArray(pageTags[tagName]) && pageTags[tagName].length === 0)) {
this.addDetectedTagEntry(
url,
tagName,
'',
HIGH,
`The ${tagName} tag on this page is missing. It's recommended to have a ${tagName} tag on each page.`,
);
this.detectedTags[tagName][MISSING_TAGS] ??= { pageUrls: [] };
this.detectedTags[tagName][MISSING_TAGS].pageUrls.push(url);
}
});
}
Expand All @@ -110,28 +69,20 @@ class SeoChecks {
* @param {object} pageTags - An object containing the tags of the page.
*/
checkForTagsLength(url, pageTags) {
[TITLE, DESCRIPTION].forEach((tagName) => {
if (pageTags[tagName]?.length > TAG_LENGTHS[tagName].maxLength
|| pageTags[tagName]?.length < TAG_LENGTHS[tagName].minLength) {
this.addDetectedTagEntry(
url,
tagName,
pageTags[tagName],
MODERATE,
SeoChecks.createLengthCheckText(tagName, pageTags[tagName]),
);
const checkTag = (tagName, tagContent) => {
if (tagContent === '') {
this.detectedTags[tagName][EMPTY_TAGS] ??= { pageUrls: [] };
this.detectedTags[tagName][EMPTY_TAGS].pageUrls.push(url);
} else if (tagContent.length > TAG_LENGTHS[tagName].maxLength
|| tagContent.length < TAG_LENGTHS[tagName].minLength) {
this.detectedTags[tagName][LENGTH_CHECK_FAIL_TAGS] ??= {};
this.detectedTags[tagName][LENGTH_CHECK_FAIL_TAGS].url = url;
this.detectedTags[tagName][LENGTH_CHECK_FAIL_TAGS].tagContent = tagContent;
}
});

if (Array.isArray(pageTags[H1]) && pageTags[H1][0]?.length > TAG_LENGTHS[H1].maxLength) {
this.addDetectedTagEntry(
url,
H1,
pageTags[H1][0],
MODERATE,
SeoChecks.createLengthCheckText(H1, pageTags[H1][0]),
);
}
};
checkTag(TITLE, pageTags[TITLE]);
checkTag(DESCRIPTION, pageTags[DESCRIPTION]);
checkTag(H1, pageTags[H1][0]);
}

/**
Expand All @@ -140,56 +91,47 @@ class SeoChecks {
* @param {object} pageTags - An object containing the tags of the page.
*/
checkForH1Count(url, pageTags) {
if (Array.isArray(pageTags[H1]) && pageTags[H1]?.length > 1) {
this.addDetectedTagEntry(
url,
H1,
JSON.stringify(pageTags[H1]),
MODERATE,
`There are ${pageTags[H1].length} H1 tags on this page, which is more than the recommended count of 1.`,
);
if (pageTags[H1]?.length > 1) {
this.detectedTags[H1][MULTIPLE_H1_COUNT] ??= [];
this.detectedTags[H1][MULTIPLE_H1_COUNT].push({
pageUrl: url,
tagContent: JSON.stringify(pageTags[H1]),
});
}
}

/**
* Checks for tag uniqueness and adds to detected tags array if found lacking.
* @param {object} pageTags - An object containing the tags of the page.
* @param {string} url - The URL of the page.
*/
checkForUniqueness(url, pageTags) {
const tags = {
[TITLE]: pageTags[TITLE],
[DESCRIPTION]: pageTags[DESCRIPTION],
[H1]: Array.isArray(pageTags[H1]) ? pageTags[H1] : [],
};
[TITLE, DESCRIPTION].forEach((tagName) => {
const tagContent = tags[tagName];
if (tagContent && this.allTags[tagName][tagContent.toLowerCase()]) {
this.addDetectedTagEntry(
url,
tagName,
tagContent,
HIGH,
`The ${tagName} tag on this page is identical to the one on ${this.allTags[tagName][tagContent.toLowerCase()]}. `
+ `It's recommended to have unique ${tagName} tags for each page.`,
);
}
this.allTags[tagName][tagContent?.toLowerCase()] = url;
});
tags[H1].forEach((tag) => {
this.allTags[H1][tag] ??= { count: 0, urls: [] };
this.allTags[H1][tag].urls.push(url);
this.allTags[H1][tag].count += 1;

if (this.allTags[H1][tag].count > 1) {
if (!this.detectedTags[H1][0] || !this.detectedTags[H1][0][NON_UNIQUE]) {
this.detectedTags[H1].unshift({ [NON_UNIQUE]: {} });
checkForUniqueness() {
[TITLE, DESCRIPTION, H1].forEach((tagName) => {
Object.values(this.allTags[tagName]).forEach((value) => {
if (value?.pageUrls?.size > 1) {
this.detectedTags[tagName][DUPLICATE_TAGS] ??= [];
this.detectedTags[tagName][DUPLICATE_TAGS].push({
tagContent: value.tagContent,
pageUrls: Array.from(value.pageUrls),
});
}
this.detectedTags[H1][0][NON_UNIQUE][tag] = { ...this.allTags[H1][tag] };
}
});
});
}

/**
* Adds tag data entry to all Tags Object
* @param url
* @param tagName
* @param tagContent
*/
addToAllTags(url, tagName, tagContent) {
const tagContentLowerCase = tagContent.toLowerCase();
this.allTags[tagName][tagContentLowerCase] ??= {
pageUrls: new Set(),
tagContent,
};
this.allTags[tagName][tagContentLowerCase].pageUrls.add(url);
}

/**
* Performs all SEO checks on the provided tags.
* @param {string} url - The URL of the page.
Expand All @@ -199,7 +141,10 @@ class SeoChecks {
this.checkForMissingTags(url, pageTags);
this.checkForTagsLength(url, pageTags);
this.checkForH1Count(url, pageTags);
this.checkForUniqueness(url, pageTags);
// store tag data in all tags object to be used in later checks like uniqueness
this.addToAllTags(TITLE, pageTags[TITLE]);
this.addToAllTags(DESCRIPTION, pageTags[DESCRIPTION]);
pageTags[H1].forEach((tagContent) => this.addToAllTags(H1, tagContent));
}

/**
Expand All @@ -210,12 +155,15 @@ class SeoChecks {
return this.detectedTags;
}

finalChecks() {
this.checkForUniqueness();
}

/**
* Processes detected tags, including sorting non-unique H1 tags.
*/
organizeDetectedTags() {
this.sortNonUniqueH1Tags();
}
// organizeDetectedTags() {
// }
}

export default SeoChecks;
Loading

0 comments on commit 0b71522

Please sign in to comment.