axyseo 2.1.51 → 2.1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,7 +35,10 @@ const transformRelatedKeyword = keywords => keywords.map(keyword => typeof keywo
35
35
  */
36
36
  exports.transformRelatedKeyword = transformRelatedKeyword;
37
37
  const getTextFullPage = data => {
38
- const faqString = data.faqs.status ? data.faqs.questions.map(i => i.question + ' ' + i.answer).join(' ') : '';
38
+ // const faqString = data.faqs.status
39
+ // ? data.faqs.questions.map(i => i.question + ' ' + i.answer).join(' ')
40
+ // : '';
41
+ const faqString = '';
39
42
  const html = data.body_html || data.descriptionHtml;
40
43
  const bodyString = html?.length > 0 ? html.replace(/<\/?[^>]+(>|$)/g, ' ').replace(/\s+/g, ' ').trim() : '';
41
44
  return [faqString, data.title, bodyString, data?.metafields_avadaSEO_after_content, data.metafields_global_title_tag, data.metafields_global_description_tag].join(' ').toLowerCase();
@@ -1 +1 @@
1
- {"version":3,"file":"checkRelatedKeywords.js","names":["_default","paper","researcher","data","getData","related_keywords","transformRelatedKeyword","string","getTextFullPage","countWordsInRelatedKeywords","keywords","map","keyword","text","exports","faqString","faqs","status","questions","i","question","answer","join","html","body_html","descriptionHtml","bodyString","length","replace","trim","title","metafields_avadaSEO_after_content","metafields_global_title_tag","metafields_global_description_tag","toLowerCase","escapeRegExp","total","split","filter","word","words","totalWordUsed","isWordUsedExceeding","forEach","toLocaleLowerCase","escapedKeyword","regex","RegExp","match","percentage","parseFloat","toFixed"],"sources":["../../../../src/languageProcessing/researches/checkRelatedKeywords.js"],"sourcesContent":["/**\n * Checks how many sentences from a text contain at least one transition word or two-part transition word\n * that are defined in the transition words config and two part transition words config.\n *\n * @param {Paper} paper The Paper object to get text from.\n * @param {Researcher} researcher The researcher.\n *\n * @returns {object} An object with the total number of sentences in the text\n * and the total number of sentences containing one or more transition words.\n */\nexport default function(paper, researcher) {\n const data = paper.getData();\n const related_keywords = transformRelatedKeyword(data?.related_keywords || []);\n const string = getTextFullPage(data);\n return countWordsInRelatedKeywords({related_keywords, string});\n}\n\nexport const transformRelatedKeyword = keywords =>\n keywords.map(keyword => (typeof keyword === 'string' ? {text: keyword} : keyword)) || [];\n\n/**\n *\n * @param data\n * @returns {string}\n */\nconst getTextFullPage = data => {\n const faqString = data.faqs.status\n ? data.faqs.questions.map(i => i.question + ' ' + i.answer).join(' ')\n : '';\n const html = data.body_html || data.descriptionHtml;\n const bodyString =\n html?.length > 0\n ? html\n .replace(/<\\/?[^>]+(>|$)/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n : '';\n return [\n faqString,\n data.title,\n bodyString,\n data?.metafields_avadaSEO_after_content,\n data.metafields_global_title_tag,\n data.metafields_global_description_tag\n ]\n .join(' ')\n .toLowerCase();\n};\n\nconst escapeRegExp = string => {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n};\n\n/**\n *\n * @param related_keywords\n * @param string\n * @returns {{totalWordUsed: number, words: {}, isWordUsedExceeding: boolean}}\n */\nconst countWordsInRelatedKeywords = ({related_keywords, string}) => {\n const total = string.split(/\\s+/).filter(word => word.length > 0).length;\n const words = {};\n let totalWordUsed = 0;\n let isWordUsedExceeding = false;\n\n related_keywords.forEach(({text}) => {\n const keyword = text.toLocaleLowerCase();\n const escapedKeyword = escapeRegExp(keyword);\n const regex = new RegExp(`(?:^|\\\\W)${escapedKeyword}(?:\\\\W|$)`, 'gu');\n const length = (string.match(regex) || []).length;\n\n const percentage = parseFloat(((length / total) * 100).toFixed(1));\n if (!isWordUsedExceeding) {\n isWordUsedExceeding = percentage > 1;\n }\n totalWordUsed += length;\n words[text] = {length, percentage};\n });\n\n return {totalWordUsed, words, isWordUsedExceeding};\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"checkRelatedKeywords.js","names":["_default","paper","researcher","data","getData","related_keywords","transformRelatedKeyword","string","getTextFullPage","countWordsInRelatedKeywords","keywords","map","keyword","text","exports","faqString","html","body_html","descriptionHtml","bodyString","length","replace","trim","title","metafields_avadaSEO_after_content","metafields_global_title_tag","metafields_global_description_tag","join","toLowerCase","escapeRegExp","total","split","filter","word","words","totalWordUsed","isWordUsedExceeding","forEach","toLocaleLowerCase","escapedKeyword","regex","RegExp","match","percentage","parseFloat","toFixed"],"sources":["../../../../src/languageProcessing/researches/checkRelatedKeywords.js"],"sourcesContent":["/**\n * Checks how many sentences from a text contain at least one transition word or two-part transition word\n * that are defined in the transition words config and two part transition words config.\n *\n * @param {Paper} paper The Paper object to get text from.\n * @param {Researcher} researcher The researcher.\n *\n * @returns {object} An object with the total number of sentences in the text\n * and the total number of sentences containing one or more transition words.\n */\nexport default function(paper, researcher) {\n const data = paper.getData();\n const related_keywords = transformRelatedKeyword(data?.related_keywords || []);\n const string = getTextFullPage(data);\n return countWordsInRelatedKeywords({related_keywords, string});\n}\n\nexport const transformRelatedKeyword = keywords =>\n keywords.map(keyword => (typeof keyword === 'string' ? {text: keyword} : keyword)) || [];\n\n/**\n *\n * @param data\n * @returns {string}\n */\nconst getTextFullPage = data => {\n // const faqString = data.faqs.status\n // ? data.faqs.questions.map(i => i.question + ' ' + i.answer).join(' ')\n // : '';\n const faqString = '';\n const html = data.body_html || data.descriptionHtml;\n const bodyString =\n html?.length > 0\n ? html\n .replace(/<\\/?[^>]+(>|$)/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n : '';\n return [\n faqString,\n data.title,\n bodyString,\n data?.metafields_avadaSEO_after_content,\n data.metafields_global_title_tag,\n data.metafields_global_description_tag\n ]\n .join(' ')\n .toLowerCase();\n};\n\nconst escapeRegExp = string => {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n};\n\n/**\n *\n * @param related_keywords\n * @param string\n * @returns {{totalWordUsed: number, words: {}, isWordUsedExceeding: boolean}}\n */\nconst countWordsInRelatedKeywords = ({related_keywords, string}) => {\n const total = string.split(/\\s+/).filter(word => word.length > 0).length;\n const words = {};\n let totalWordUsed = 0;\n let isWordUsedExceeding = false;\n\n related_keywords.forEach(({text}) => {\n const keyword = text.toLocaleLowerCase();\n const escapedKeyword = escapeRegExp(keyword);\n const regex = new RegExp(`(?:^|\\\\W)${escapedKeyword}(?:\\\\W|$)`, 'gu');\n const length = (string.match(regex) || []).length;\n\n const percentage = parseFloat(((length / total) * 100).toFixed(1));\n if (!isWordUsedExceeding) {\n isWordUsedExceeding = percentage > 1;\n }\n totalWordUsed += length;\n words[text] = {length, percentage};\n });\n\n return {totalWordUsed, words, isWordUsedExceeding};\n};\n"],"mappings":"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","ignoreList":[]}
@@ -54,6 +54,20 @@ class KeyphraseDensityAssessment extends _assessment.default {
54
54
  const keyphraseLength = this._keyphraseCount.keyphraseLength;
55
55
  this._keyphraseDensity = researcher.getResearch('getKeyphraseDensity');
56
56
  this._keyphraseDensity = this._keyphraseDensity * (0, _keyphraseLengthFactor.default)(keyphraseLength);
57
+
58
+ // For collection pages: density % is meaningless on 150–300 word content
59
+ // and conflicts with related-keyword coverage. Treat density as good when
60
+ // the keyword is already placed in the introduction AND in a subheading.
61
+ this._placementOverride = false;
62
+ const pageType = typeof paper?.getPageType === 'function' ? paper.getPageType() : null;
63
+ this._pageType = pageType;
64
+ if (pageType === 'collection' || pageType === 'product') {
65
+ const firstParagraph = researcher.getResearch('findKeywordInFirstParagraph');
66
+ const subHeadings = researcher.getResearch('matchKeywordInSubheadings');
67
+ const inIntro = !!(firstParagraph && (firstParagraph.foundInOneSentence || firstParagraph.foundInParagraph));
68
+ const inSubheading = !!(subHeadings && subHeadings.matches > 0);
69
+ this._placementOverride = inIntro && inSubheading;
70
+ }
57
71
  const assessmentResult = new _AssessmentResult.default({
58
72
  config: this._config
59
73
  });
@@ -75,6 +89,20 @@ class KeyphraseDensityAssessment extends _assessment.default {
75
89
  if (roundedDensity >= 1 && roundedDensity <= 1.5) {
76
90
  status = 'good';
77
91
  }
92
+
93
+ // Placement-based overrides (see getResult for how _placementOverride is set):
94
+ // - collection: short content (150–300 words) makes % unreliable; pass
95
+ // purely on placement (intro + subheading).
96
+ // - product: keep the displayed 1.0–1.5% target, but accept the wider
97
+ // 0.8–2.0% range when placement is already correct, so refinement
98
+ // doesn't loop over a ±0.2% drift.
99
+ if (this._placementOverride) {
100
+ if (this._pageType === 'collection') {
101
+ status = 'good';
102
+ } else if (this._pageType === 'product' && roundedDensity >= 0.8 && roundedDensity <= 2.0) {
103
+ status = 'good';
104
+ }
105
+ }
78
106
  const score = this.getScore(_analysis.MAIN_CONTENT_POINTS, status);
79
107
  this._config = (0, _lodash.merge)(this._config, {
80
108
  roundedDensity
@@ -1 +1 @@
1
- {"version":3,"file":"KeywordDensityAssessment.js","names":["_lodash","require","_assessment","_interopRequireDefault","_AssessmentResult","_keyphraseLengthFactor","_analysis","e","__esModule","default","KeyphraseDensityAssessment","Assessment","constructor","config","defaultConfig","id","KEYPHRASE_DENSITY_ID","fixPosition","docUrl","ctaType","priority","title","content","good","bad","improve","identifier","_config","merge","getResult","paper","researcher","_keyphraseCount","getResearch","keyphraseLength","_keyphraseDensity","keyphraseLengthFactor","assessmentResult","AssessmentResult","calculatedResult","calculateResult","setScore","score","setStatus","status","setTitle","density","roundedDensity","parseFloat","toFixed","getScore","MAIN_CONTENT_POINTS","isApplicable","_default","exports"],"sources":["../../../../../src/scoring/assessments/seo/KeywordDensityAssessment.js"],"sourcesContent":["import {merge} from 'lodash';\nimport Assessment from '../assessment';\nimport AssessmentResult from '../../../values/AssessmentResult';\n\nimport keyphraseLengthFactor from '../../../scoring/helpers/assessments/keyphraseLengthFactor';\nimport {KEYPHRASE_DENSITY_ID, MAIN_CONTENT_POINTS} from '@axyseo/const/analysis';\n\n/**\n * Represents the assessment that will look if the keyphrase density is within the recommended range.\n */\nclass KeyphraseDensityAssessment extends Assessment {\n /**\n *\n * @param config\n */\n constructor(config = {}) {\n super();\n\n const defaultConfig = {\n id: KEYPHRASE_DENSITY_ID,\n fixPosition: 'highlightKeyword',\n docUrl:\n 'https://docs.avada.io/seo-suite-help-center/seo-audit/on-page-seo/checklist#main-keyword-density',\n ctaType: 'fix',\n priority: 'high',\n title: 'Main keyword density',\n content: {\n good: 'Keyword density is optimized, between 1 - 1.5%.',\n bad: 'Keep keyword density from 1% - 1.5%.',\n improve: ''\n }\n };\n\n this.identifier = KEYPHRASE_DENSITY_ID;\n this._config = merge(defaultConfig, config);\n }\n\n /**\n * Runs the keyphrase density module, based on this returns an assessment\n * result with score.\n *\n * @param {Paper} paper The paper to use for the assessment.\n * @param {Researcher} researcher The researcher used for calling the research.\n *\n * @returns {AssessmentResult} The result of the assessment.\n */\n getResult({paper, researcher}) {\n\n this._keyphraseCount = researcher.getResearch('getKeyphraseCount');\n const keyphraseLength = this._keyphraseCount.keyphraseLength;\n\n this._keyphraseDensity = researcher.getResearch('getKeyphraseDensity');\n this._keyphraseDensity = this._keyphraseDensity * keyphraseLengthFactor(keyphraseLength);\n\n const assessmentResult = new AssessmentResult({config: this._config});\n\n const calculatedResult = this.calculateResult(paper);\n\n assessmentResult.setScore(calculatedResult.score);\n assessmentResult.setStatus(calculatedResult.status);\n assessmentResult.setTitle(calculatedResult.title);\n return assessmentResult;\n }\n\n /**\n *\n * @returns {{title: string, score: number, status: string}}\n */\n calculateResult() {\n let status = 'bad';\n const density = this._keyphraseDensity;\n const roundedDensity = parseFloat(density.toFixed(2));\n if (roundedDensity >= 1 && roundedDensity <= 1.5) {\n status = 'good';\n }\n\n const score = this.getScore(MAIN_CONTENT_POINTS, status);\n this._config = merge(this._config, {\n roundedDensity\n });\n return {\n roundedDensity,\n score,\n status\n };\n }\n\n /**\n * Checks whether the paper has a text of the minimum required length and a keyphrase is set. Language-specific length requirements and methods\n * of counting text length may apply (e.g. for Japanese, the text should be counted in characters instead of words, which also makes the minimum\n * required length higher).\n *\n * @param {Paper} \t\tpaper \t\tThe paper to use for the assessment.\n * @param {Researcher} researcher The paper to use for the assessment.\n *\n * @returns {boolean} True if applicable.\n */\n isApplicable(paper, researcher) {\n return true;\n }\n}\n\nexport default KeyphraseDensityAssessment;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"KeywordDensityAssessment.js","names":["_lodash","require","_assessment","_interopRequireDefault","_AssessmentResult","_keyphraseLengthFactor","_analysis","e","__esModule","default","KeyphraseDensityAssessment","Assessment","constructor","config","defaultConfig","id","KEYPHRASE_DENSITY_ID","fixPosition","docUrl","ctaType","priority","title","content","good","bad","improve","identifier","_config","merge","getResult","paper","researcher","_keyphraseCount","getResearch","keyphraseLength","_keyphraseDensity","keyphraseLengthFactor","_placementOverride","pageType","getPageType","_pageType","firstParagraph","subHeadings","inIntro","foundInOneSentence","foundInParagraph","inSubheading","matches","assessmentResult","AssessmentResult","calculatedResult","calculateResult","setScore","score","setStatus","status","setTitle","density","roundedDensity","parseFloat","toFixed","getScore","MAIN_CONTENT_POINTS","isApplicable","_default","exports"],"sources":["../../../../../src/scoring/assessments/seo/KeywordDensityAssessment.js"],"sourcesContent":["import {merge} from 'lodash';\nimport Assessment from '../assessment';\nimport AssessmentResult from '../../../values/AssessmentResult';\n\nimport keyphraseLengthFactor from '../../../scoring/helpers/assessments/keyphraseLengthFactor';\nimport {KEYPHRASE_DENSITY_ID, MAIN_CONTENT_POINTS} from '@axyseo/const/analysis';\n\n/**\n * Represents the assessment that will look if the keyphrase density is within the recommended range.\n */\nclass KeyphraseDensityAssessment extends Assessment {\n /**\n *\n * @param config\n */\n constructor(config = {}) {\n super();\n\n const defaultConfig = {\n id: KEYPHRASE_DENSITY_ID,\n fixPosition: 'highlightKeyword',\n docUrl:\n 'https://docs.avada.io/seo-suite-help-center/seo-audit/on-page-seo/checklist#main-keyword-density',\n ctaType: 'fix',\n priority: 'high',\n title: 'Main keyword density',\n content: {\n good: 'Keyword density is optimized, between 1 - 1.5%.',\n bad: 'Keep keyword density from 1% - 1.5%.',\n improve: ''\n }\n };\n\n this.identifier = KEYPHRASE_DENSITY_ID;\n this._config = merge(defaultConfig, config);\n }\n\n /**\n * Runs the keyphrase density module, based on this returns an assessment\n * result with score.\n *\n * @param {Paper} paper The paper to use for the assessment.\n * @param {Researcher} researcher The researcher used for calling the research.\n *\n * @returns {AssessmentResult} The result of the assessment.\n */\n getResult({paper, researcher}) {\n\n this._keyphraseCount = researcher.getResearch('getKeyphraseCount');\n const keyphraseLength = this._keyphraseCount.keyphraseLength;\n\n this._keyphraseDensity = researcher.getResearch('getKeyphraseDensity');\n this._keyphraseDensity = this._keyphraseDensity * keyphraseLengthFactor(keyphraseLength);\n\n // For collection pages: density % is meaningless on 150–300 word content\n // and conflicts with related-keyword coverage. Treat density as good when\n // the keyword is already placed in the introduction AND in a subheading.\n this._placementOverride = false;\n const pageType =\n typeof paper?.getPageType === 'function' ? paper.getPageType() : null;\n this._pageType = pageType;\n if (pageType === 'collection' || pageType === 'product') {\n const firstParagraph = researcher.getResearch('findKeywordInFirstParagraph');\n const subHeadings = researcher.getResearch('matchKeywordInSubheadings');\n const inIntro = !!(\n firstParagraph &&\n (firstParagraph.foundInOneSentence || firstParagraph.foundInParagraph)\n );\n const inSubheading = !!(subHeadings && subHeadings.matches > 0);\n this._placementOverride = inIntro && inSubheading;\n }\n\n const assessmentResult = new AssessmentResult({config: this._config});\n\n const calculatedResult = this.calculateResult(paper);\n\n assessmentResult.setScore(calculatedResult.score);\n assessmentResult.setStatus(calculatedResult.status);\n assessmentResult.setTitle(calculatedResult.title);\n return assessmentResult;\n }\n\n /**\n *\n * @returns {{title: string, score: number, status: string}}\n */\n calculateResult() {\n let status = 'bad';\n const density = this._keyphraseDensity;\n const roundedDensity = parseFloat(density.toFixed(2));\n if (roundedDensity >= 1 && roundedDensity <= 1.5) {\n status = 'good';\n }\n\n // Placement-based overrides (see getResult for how _placementOverride is set):\n // - collection: short content (150–300 words) makes % unreliable; pass\n // purely on placement (intro + subheading).\n // - product: keep the displayed 1.0–1.5% target, but accept the wider\n // 0.8–2.0% range when placement is already correct, so refinement\n // doesn't loop over a ±0.2% drift.\n if (this._placementOverride) {\n if (this._pageType === 'collection') {\n status = 'good';\n } else if (\n this._pageType === 'product' &&\n roundedDensity >= 0.8 &&\n roundedDensity <= 2.0\n ) {\n status = 'good';\n }\n }\n\n const score = this.getScore(MAIN_CONTENT_POINTS, status);\n this._config = merge(this._config, {\n roundedDensity\n });\n return {\n roundedDensity,\n score,\n status\n };\n }\n\n /**\n * Checks whether the paper has a text of the minimum required length and a keyphrase is set. Language-specific length requirements and methods\n * of counting text length may apply (e.g. for Japanese, the text should be counted in characters instead of words, which also makes the minimum\n * required length higher).\n *\n * @param {Paper} \t\tpaper \t\tThe paper to use for the assessment.\n * @param {Researcher} researcher The paper to use for the assessment.\n *\n * @returns {boolean} True if applicable.\n */\n isApplicable(paper, researcher) {\n return true;\n }\n}\n\nexport default KeyphraseDensityAssessment;\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"RelatedKeywordsDensityAssessment.js","names":["_lodash","require","_AssessmentResult","_interopRequireDefault","_assessment","_analysis","e","__esModule","default","RelatedKeywordsDensityAssessment","Assessment","constructor","config","defaultConfig","id","RELATED_KEYWORDS_DENSITY_ID","fixPosition","ctaType","docUrl","priority","title","content","good","bad","improve","identifier","_config","merge","calculateResult","data","relatedKeywords","hasDescription","words","status","totalWords","Object","values","filter","word","percentage","isEmpty","length","score","getScore","MAIN_CONTENT_POINTS","getResult","paper","researcher","getResearch","getData","result","assessmentResult","AssessmentResult","setScore","setStatus","setData","isApplicable","exports"],"sources":["../../../../../src/scoring/assessments/seo/RelatedKeywordsDensityAssessment.js"],"sourcesContent":["import {isEmpty, merge} from 'lodash';\nimport AssessmentResult from '../../../values/AssessmentResult';\nimport Assessment from '../assessment';\nimport {MAIN_CONTENT_POINTS, RELATED_KEYWORDS_DENSITY_ID} from '@axyseo/const/analysis';\n\n/**\n * Represents the assessment that checks whether there are enough transition words in the text.\n */\nexport default class RelatedKeywordsDensityAssessment extends Assessment {\n /**\n * Sets the identifier and the config.\n *\n * @param {object} config The configuration to use.\n *\n * @returns {void}\n */\n constructor(config = {}) {\n super();\n\n const defaultConfig = {\n id: RELATED_KEYWORDS_DENSITY_ID,\n fixPosition: 'description',\n ctaType: 'fix',\n docUrl:\n 'https://docs.avada.io/seo-suite-help-center/seo-audit/on-page-seo/checklist#related-keywords',\n priority: 'high',\n title: 'Related keywords density',\n content: {\n good: 'Related keywords density optimized',\n bad:\n 'Use each secondary keyword from 0.5% to 1%. Place where it reads naturally.',\n improve: ''\n }\n };\n\n this.identifier = RELATED_KEYWORDS_DENSITY_ID;\n this._config = merge(defaultConfig, config);\n }\n\n /**\n *\n * @param data\n * @param relatedKeywords\n * @param hasDescription\n * @returns {{score: number, status: string, words}}\n */\n calculateResult(data, relatedKeywords, hasDescription) {\n const {words} = relatedKeywords;\n let status = 'good';\n\n const totalWords = Object.values(words).filter(word => word.percentage === 0);\n if(!hasDescription || isEmpty(words) || totalWords.length > 0){\n status = 'bad';\n }\n const score = this.getScore(MAIN_CONTENT_POINTS, status);\n\n return {\n score,\n status,\n words\n };\n }\n\n /**\n *\n * @param paper\n * @param researcher\n * @returns {AssessmentResult}\n */\n getResult({paper, researcher}) {\n const relatedKeywords = researcher.getResearch('checkRelatedKeywords');\n const data = paper.getData();\n const hasDescription = paper.hasDescription();\n const result = this.calculateResult(data, relatedKeywords, hasDescription);\n const assessmentResult = new AssessmentResult({config: this._config});\n\n assessmentResult.setScore(result.score);\n assessmentResult.setStatus(result.status);\n assessmentResult.setData(result.words);\n\n return assessmentResult;\n }\n\n /**\n * Checks if the transition words assessment is applicable to the paper. Language-specific length requirements and methods of counting text length\n * may apply (e.g. for Japanese, the text should be counted in characters instead of words, which also makes the minimum required length higher).\n *\n * @param {Paper} paper The paper to check.\n * @param {Researcher} researcher The researcher object.\n *\n * @returns {boolean} Returns true if the language is available, the paper is not empty and the text is longer than the minimum required length.\n */\n isApplicable(paper, researcher) {\n return true;\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,iBAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,WAAA,GAAAD,sBAAA,CAAAF,OAAA;AACA,IAAAI,SAAA,GAAAJ,OAAA;AAAwF,SAAAE,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAExF;AACA;AACA;AACe,MAAMG,gCAAgC,SAASC,mBAAU,CAAC;EACvE;AACF;AACA;AACA;AACA;AACA;AACA;EACEC,WAAWA,CAACC,MAAM,GAAG,CAAC,CAAC,EAAE;IACvB,KAAK,CAAC,CAAC;IAEP,MAAMC,aAAa,GAAG;MACpBC,EAAE,EAAEC,qCAA2B;MAC/BC,WAAW,EAAE,aAAa;MAC1BC,OAAO,EAAE,KAAK;MACdC,MAAM,EACJ,8FAA8F;MAChGC,QAAQ,EAAE,MAAM;MAChBC,KAAK,EAAE,0BAA0B;MACjCC,OAAO,EAAE;QACPC,IAAI,EAAE,oCAAoC;QAC1CC,GAAG,EACD,6EAA6E;QAC/EC,OAAO,EAAE;MACX;IACF,CAAC;IAED,IAAI,CAACC,UAAU,GAAGV,qCAA2B;IAC7C,IAAI,CAACW,OAAO,GAAG,IAAAC,aAAK,EAACd,aAAa,EAAED,MAAM,CAAC;EAC7C;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;EACEgB,eAAeA,CAACC,IAAI,EAAEC,eAAe,EAAEC,cAAc,EAAE;IACrD,MAAM;MAACC;IAAK,CAAC,GAAGF,eAAe;IAC/B,IAAIG,MAAM,GAAG,MAAM;IAEnB,MAAMC,UAAU,GAAGC,MAAM,CAACC,MAAM,CAACJ,KAAK,CAAC,CAACK,MAAM,CAACC,IAAI,IAAIA,IAAI,CAACC,UAAU,KAAK,CAAC,CAAC;IAC7E,IAAG,CAACR,cAAc,IAAI,IAAAS,eAAO,EAACR,KAAK,CAAC,IAAIE,UAAU,CAACO,MAAM,GAAG,CAAC,EAAC;MAC5DR,MAAM,GAAG,KAAK;IAChB;IACA,MAAMS,KAAK,GAAG,IAAI,CAACC,QAAQ,CAACC,6BAAmB,EAAEX,MAAM,CAAC;IAExD,OAAO;MACLS,KAAK;MACLT,MAAM;MACND;IACF,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;AACA;EACEa,SAASA,CAAC;IAACC,KAAK;IAAEC;EAAU,CAAC,EAAE;IAC7B,MAAMjB,eAAe,GAAGiB,UAAU,CAACC,WAAW,CAAC,sBAAsB,CAAC;IACtE,MAAMnB,IAAI,GAAGiB,KAAK,CAACG,OAAO,CAAC,CAAC;IAC5B,MAAMlB,cAAc,GAAGe,KAAK,CAACf,cAAc,CAAC,CAAC;IAC7C,MAAMmB,MAAM,GAAG,IAAI,CAACtB,eAAe,CAACC,IAAI,EAAEC,eAAe,EAAEC,cAAc,CAAC;IAC1E,MAAMoB,gBAAgB,GAAG,IAAIC,yBAAgB,CAAC;MAACxC,MAAM,EAAE,IAAI,CAACc;IAAO,CAAC,CAAC;IAErEyB,gBAAgB,CAACE,QAAQ,CAACH,MAAM,CAACR,KAAK,CAAC;IACvCS,gBAAgB,CAACG,SAAS,CAACJ,MAAM,CAACjB,MAAM,CAAC;IACzCkB,gBAAgB,CAACI,OAAO,CAACL,MAAM,CAAClB,KAAK,CAAC;IAEtC,OAAOmB,gBAAgB;EACzB;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEK,YAAYA,CAACV,KAAK,EAAEC,UAAU,EAAE;IAC9B,OAAO,IAAI;EACb;AACF;AAACU,OAAA,CAAAjD,OAAA,GAAAC,gCAAA","ignoreList":[]}
1
+ {"version":3,"file":"RelatedKeywordsDensityAssessment.js","names":["_lodash","require","_AssessmentResult","_interopRequireDefault","_assessment","_analysis","e","__esModule","default","RelatedKeywordsDensityAssessment","Assessment","constructor","config","defaultConfig","id","RELATED_KEYWORDS_DENSITY_ID","fixPosition","ctaType","docUrl","priority","title","content","good","bad","improve","identifier","_config","merge","calculateResult","data","relatedKeywords","hasDescription","words","status","totalWords","Object","values","filter","word","percentage","isEmpty","length","score","getScore","MAIN_CONTENT_POINTS","getResult","paper","researcher","getResearch","getData","result","assessmentResult","AssessmentResult","setScore","setStatus","setData","isApplicable","exports"],"sources":["../../../../../src/scoring/assessments/seo/RelatedKeywordsDensityAssessment.js"],"sourcesContent":["import {isEmpty, merge} from 'lodash';\nimport AssessmentResult from '../../../values/AssessmentResult';\nimport Assessment from '../assessment';\nimport {MAIN_CONTENT_POINTS, RELATED_KEYWORDS_DENSITY_ID} from '@axyseo/const/analysis';\n\n/**\n * Represents the assessment that checks whether there are enough transition words in the text.\n */\nexport default class RelatedKeywordsDensityAssessment extends Assessment {\n /**\n * Sets the identifier and the config.\n *\n * @param {object} config The configuration to use.\n *\n * @returns {void}\n */\n constructor(config = {}) {\n super();\n\n const defaultConfig = {\n id: RELATED_KEYWORDS_DENSITY_ID,\n fixPosition: 'description',\n ctaType: 'fix',\n docUrl:\n 'https://docs.avada.io/seo-suite-help-center/seo-audit/on-page-seo/checklist#related-keywords',\n priority: 'high',\n title: 'Related keywords density',\n content: {\n good: 'Related keywords density optimized',\n bad:\n 'Use each secondary keyword from 0.5% to 1%. Place where it reads naturally.',\n improve: ''\n }\n };\n\n this.identifier = RELATED_KEYWORDS_DENSITY_ID;\n this._config = merge(defaultConfig, config);\n }\n\n /**\n *\n * @param data\n * @param relatedKeywords\n * @param hasDescription\n * @returns {{score: number, status: string, words}}\n */\n calculateResult(data, relatedKeywords, hasDescription) {\n const {words} = relatedKeywords;\n let status = 'good';\n const totalWords = Object.values(words).filter(word => word.percentage === 0);\n if(!hasDescription || isEmpty(words) || totalWords.length > 0){\n status = 'bad';\n }\n const score = this.getScore(MAIN_CONTENT_POINTS, status);\n\n return {\n score,\n status,\n words\n };\n }\n\n /**\n *\n * @param paper\n * @param researcher\n * @returns {AssessmentResult}\n */\n getResult({paper, researcher}) {\n const relatedKeywords = researcher.getResearch('checkRelatedKeywords');\n const data = paper.getData();\n const hasDescription = paper.hasDescription();\n const result = this.calculateResult(data, relatedKeywords, hasDescription);\n const assessmentResult = new AssessmentResult({config: this._config});\n\n assessmentResult.setScore(result.score);\n assessmentResult.setStatus(result.status);\n assessmentResult.setData(result.words);\n\n return assessmentResult;\n }\n\n /**\n * Checks if the transition words assessment is applicable to the paper. Language-specific length requirements and methods of counting text length\n * may apply (e.g. for Japanese, the text should be counted in characters instead of words, which also makes the minimum required length higher).\n *\n * @param {Paper} paper The paper to check.\n * @param {Researcher} researcher The researcher object.\n *\n * @returns {boolean} Returns true if the language is available, the paper is not empty and the text is longer than the minimum required length.\n */\n isApplicable(paper, researcher) {\n return true;\n }\n}\n"],"mappings":";;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,iBAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,WAAA,GAAAD,sBAAA,CAAAF,OAAA;AACA,IAAAI,SAAA,GAAAJ,OAAA;AAAwF,SAAAE,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAExF;AACA;AACA;AACe,MAAMG,gCAAgC,SAASC,mBAAU,CAAC;EACvE;AACF;AACA;AACA;AACA;AACA;AACA;EACEC,WAAWA,CAACC,MAAM,GAAG,CAAC,CAAC,EAAE;IACvB,KAAK,CAAC,CAAC;IAEP,MAAMC,aAAa,GAAG;MACpBC,EAAE,EAAEC,qCAA2B;MAC/BC,WAAW,EAAE,aAAa;MAC1BC,OAAO,EAAE,KAAK;MACdC,MAAM,EACJ,8FAA8F;MAChGC,QAAQ,EAAE,MAAM;MAChBC,KAAK,EAAE,0BAA0B;MACjCC,OAAO,EAAE;QACPC,IAAI,EAAE,oCAAoC;QAC1CC,GAAG,EACD,6EAA6E;QAC/EC,OAAO,EAAE;MACX;IACF,CAAC;IAED,IAAI,CAACC,UAAU,GAAGV,qCAA2B;IAC7C,IAAI,CAACW,OAAO,GAAG,IAAAC,aAAK,EAACd,aAAa,EAAED,MAAM,CAAC;EAC7C;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;EACEgB,eAAeA,CAACC,IAAI,EAAEC,eAAe,EAAEC,cAAc,EAAE;IACrD,MAAM;MAACC;IAAK,CAAC,GAAGF,eAAe;IAC/B,IAAIG,MAAM,GAAG,MAAM;IACnB,MAAMC,UAAU,GAAGC,MAAM,CAACC,MAAM,CAACJ,KAAK,CAAC,CAACK,MAAM,CAACC,IAAI,IAAIA,IAAI,CAACC,UAAU,KAAK,CAAC,CAAC;IAC7E,IAAG,CAACR,cAAc,IAAI,IAAAS,eAAO,EAACR,KAAK,CAAC,IAAIE,UAAU,CAACO,MAAM,GAAG,CAAC,EAAC;MAC5DR,MAAM,GAAG,KAAK;IAChB;IACA,MAAMS,KAAK,GAAG,IAAI,CAACC,QAAQ,CAACC,6BAAmB,EAAEX,MAAM,CAAC;IAExD,OAAO;MACLS,KAAK;MACLT,MAAM;MACND;IACF,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;AACA;EACEa,SAASA,CAAC;IAACC,KAAK;IAAEC;EAAU,CAAC,EAAE;IAC7B,MAAMjB,eAAe,GAAGiB,UAAU,CAACC,WAAW,CAAC,sBAAsB,CAAC;IACtE,MAAMnB,IAAI,GAAGiB,KAAK,CAACG,OAAO,CAAC,CAAC;IAC5B,MAAMlB,cAAc,GAAGe,KAAK,CAACf,cAAc,CAAC,CAAC;IAC7C,MAAMmB,MAAM,GAAG,IAAI,CAACtB,eAAe,CAACC,IAAI,EAAEC,eAAe,EAAEC,cAAc,CAAC;IAC1E,MAAMoB,gBAAgB,GAAG,IAAIC,yBAAgB,CAAC;MAACxC,MAAM,EAAE,IAAI,CAACc;IAAO,CAAC,CAAC;IAErEyB,gBAAgB,CAACE,QAAQ,CAACH,MAAM,CAACR,KAAK,CAAC;IACvCS,gBAAgB,CAACG,SAAS,CAACJ,MAAM,CAACjB,MAAM,CAAC;IACzCkB,gBAAgB,CAACI,OAAO,CAACL,MAAM,CAAClB,KAAK,CAAC;IAEtC,OAAOmB,gBAAgB;EACzB;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEK,YAAYA,CAACV,KAAK,EAAEC,UAAU,EAAE;IAC9B,OAAO,IAAI;EACb;AACF;AAACU,OAAA,CAAAjD,OAAA,GAAAC,gCAAA","ignoreList":[]}
@@ -27,7 +27,10 @@ export const transformRelatedKeyword = keywords => keywords.map(keyword => typeo
27
27
  * @returns {string}
28
28
  */
29
29
  const getTextFullPage = data => {
30
- const faqString = data.faqs.status ? data.faqs.questions.map(i => i.question + ' ' + i.answer).join(' ') : '';
30
+ // const faqString = data.faqs.status
31
+ // ? data.faqs.questions.map(i => i.question + ' ' + i.answer).join(' ')
32
+ // : '';
33
+ const faqString = '';
31
34
  const html = data.body_html || data.descriptionHtml;
32
35
  const bodyString = html?.length > 0 ? html.replace(/<\/?[^>]+(>|$)/g, ' ').replace(/\s+/g, ' ').trim() : '';
33
36
  return [faqString, data.title, bodyString, data?.metafields_avadaSEO_after_content, data.metafields_global_title_tag, data.metafields_global_description_tag].join(' ').toLowerCase();
@@ -1 +1 @@
1
- {"version":3,"file":"checkRelatedKeywords.js","names":["paper","researcher","data","getData","related_keywords","transformRelatedKeyword","string","getTextFullPage","countWordsInRelatedKeywords","keywords","map","keyword","text","faqString","faqs","status","questions","i","question","answer","join","html","body_html","descriptionHtml","bodyString","length","replace","trim","title","metafields_avadaSEO_after_content","metafields_global_title_tag","metafields_global_description_tag","toLowerCase","escapeRegExp","total","split","filter","word","words","totalWordUsed","isWordUsedExceeding","forEach","toLocaleLowerCase","escapedKeyword","regex","RegExp","match","percentage","parseFloat","toFixed"],"sources":["../../../../src/languageProcessing/researches/checkRelatedKeywords.js"],"sourcesContent":["/**\n * Checks how many sentences from a text contain at least one transition word or two-part transition word\n * that are defined in the transition words config and two part transition words config.\n *\n * @param {Paper} paper The Paper object to get text from.\n * @param {Researcher} researcher The researcher.\n *\n * @returns {object} An object with the total number of sentences in the text\n * and the total number of sentences containing one or more transition words.\n */\nexport default function(paper, researcher) {\n const data = paper.getData();\n const related_keywords = transformRelatedKeyword(data?.related_keywords || []);\n const string = getTextFullPage(data);\n return countWordsInRelatedKeywords({related_keywords, string});\n}\n\nexport const transformRelatedKeyword = keywords =>\n keywords.map(keyword => (typeof keyword === 'string' ? {text: keyword} : keyword)) || [];\n\n/**\n *\n * @param data\n * @returns {string}\n */\nconst getTextFullPage = data => {\n const faqString = data.faqs.status\n ? data.faqs.questions.map(i => i.question + ' ' + i.answer).join(' ')\n : '';\n const html = data.body_html || data.descriptionHtml;\n const bodyString =\n html?.length > 0\n ? html\n .replace(/<\\/?[^>]+(>|$)/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n : '';\n return [\n faqString,\n data.title,\n bodyString,\n data?.metafields_avadaSEO_after_content,\n data.metafields_global_title_tag,\n data.metafields_global_description_tag\n ]\n .join(' ')\n .toLowerCase();\n};\n\nconst escapeRegExp = string => {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n};\n\n/**\n *\n * @param related_keywords\n * @param string\n * @returns {{totalWordUsed: number, words: {}, isWordUsedExceeding: boolean}}\n */\nconst countWordsInRelatedKeywords = ({related_keywords, string}) => {\n const total = string.split(/\\s+/).filter(word => word.length > 0).length;\n const words = {};\n let totalWordUsed = 0;\n let isWordUsedExceeding = false;\n\n related_keywords.forEach(({text}) => {\n const keyword = text.toLocaleLowerCase();\n const escapedKeyword = escapeRegExp(keyword);\n const regex = new RegExp(`(?:^|\\\\W)${escapedKeyword}(?:\\\\W|$)`, 'gu');\n const length = (string.match(regex) || []).length;\n\n const percentage = parseFloat(((length / total) * 100).toFixed(1));\n if (!isWordUsedExceeding) {\n isWordUsedExceeding = percentage > 1;\n }\n totalWordUsed += length;\n words[text] = {length, percentage};\n });\n\n return {totalWordUsed, words, isWordUsedExceeding};\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"checkRelatedKeywords.js","names":["paper","researcher","data","getData","related_keywords","transformRelatedKeyword","string","getTextFullPage","countWordsInRelatedKeywords","keywords","map","keyword","text","faqString","html","body_html","descriptionHtml","bodyString","length","replace","trim","title","metafields_avadaSEO_after_content","metafields_global_title_tag","metafields_global_description_tag","join","toLowerCase","escapeRegExp","total","split","filter","word","words","totalWordUsed","isWordUsedExceeding","forEach","toLocaleLowerCase","escapedKeyword","regex","RegExp","match","percentage","parseFloat","toFixed"],"sources":["../../../../src/languageProcessing/researches/checkRelatedKeywords.js"],"sourcesContent":["/**\n * Checks how many sentences from a text contain at least one transition word or two-part transition word\n * that are defined in the transition words config and two part transition words config.\n *\n * @param {Paper} paper The Paper object to get text from.\n * @param {Researcher} researcher The researcher.\n *\n * @returns {object} An object with the total number of sentences in the text\n * and the total number of sentences containing one or more transition words.\n */\nexport default function(paper, researcher) {\n const data = paper.getData();\n const related_keywords = transformRelatedKeyword(data?.related_keywords || []);\n const string = getTextFullPage(data);\n return countWordsInRelatedKeywords({related_keywords, string});\n}\n\nexport const transformRelatedKeyword = keywords =>\n keywords.map(keyword => (typeof keyword === 'string' ? {text: keyword} : keyword)) || [];\n\n/**\n *\n * @param data\n * @returns {string}\n */\nconst getTextFullPage = data => {\n // const faqString = data.faqs.status\n // ? data.faqs.questions.map(i => i.question + ' ' + i.answer).join(' ')\n // : '';\n const faqString = '';\n const html = data.body_html || data.descriptionHtml;\n const bodyString =\n html?.length > 0\n ? html\n .replace(/<\\/?[^>]+(>|$)/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n : '';\n return [\n faqString,\n data.title,\n bodyString,\n data?.metafields_avadaSEO_after_content,\n data.metafields_global_title_tag,\n data.metafields_global_description_tag\n ]\n .join(' ')\n .toLowerCase();\n};\n\nconst escapeRegExp = string => {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n};\n\n/**\n *\n * @param related_keywords\n * @param string\n * @returns {{totalWordUsed: number, words: {}, isWordUsedExceeding: boolean}}\n */\nconst countWordsInRelatedKeywords = ({related_keywords, string}) => {\n const total = string.split(/\\s+/).filter(word => word.length > 0).length;\n const words = {};\n let totalWordUsed = 0;\n let isWordUsedExceeding = false;\n\n related_keywords.forEach(({text}) => {\n const keyword = text.toLocaleLowerCase();\n const escapedKeyword = escapeRegExp(keyword);\n const regex = new RegExp(`(?:^|\\\\W)${escapedKeyword}(?:\\\\W|$)`, 'gu');\n const length = (string.match(regex) || []).length;\n\n const percentage = parseFloat(((length / total) * 100).toFixed(1));\n if (!isWordUsedExceeding) {\n isWordUsedExceeding = percentage > 1;\n }\n totalWordUsed += length;\n words[text] = {length, percentage};\n });\n\n return {totalWordUsed, words, isWordUsedExceeding};\n};\n"],"mappings":"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","ignoreList":[]}
@@ -48,6 +48,20 @@ class KeyphraseDensityAssessment extends Assessment {
48
48
  const keyphraseLength = this._keyphraseCount.keyphraseLength;
49
49
  this._keyphraseDensity = researcher.getResearch('getKeyphraseDensity');
50
50
  this._keyphraseDensity = this._keyphraseDensity * keyphraseLengthFactor(keyphraseLength);
51
+
52
+ // For collection pages: density % is meaningless on 150–300 word content
53
+ // and conflicts with related-keyword coverage. Treat density as good when
54
+ // the keyword is already placed in the introduction AND in a subheading.
55
+ this._placementOverride = false;
56
+ const pageType = typeof paper?.getPageType === 'function' ? paper.getPageType() : null;
57
+ this._pageType = pageType;
58
+ if (pageType === 'collection' || pageType === 'product') {
59
+ const firstParagraph = researcher.getResearch('findKeywordInFirstParagraph');
60
+ const subHeadings = researcher.getResearch('matchKeywordInSubheadings');
61
+ const inIntro = !!(firstParagraph && (firstParagraph.foundInOneSentence || firstParagraph.foundInParagraph));
62
+ const inSubheading = !!(subHeadings && subHeadings.matches > 0);
63
+ this._placementOverride = inIntro && inSubheading;
64
+ }
51
65
  const assessmentResult = new AssessmentResult({
52
66
  config: this._config
53
67
  });
@@ -69,6 +83,20 @@ class KeyphraseDensityAssessment extends Assessment {
69
83
  if (roundedDensity >= 1 && roundedDensity <= 1.5) {
70
84
  status = 'good';
71
85
  }
86
+
87
+ // Placement-based overrides (see getResult for how _placementOverride is set):
88
+ // - collection: short content (150–300 words) makes % unreliable; pass
89
+ // purely on placement (intro + subheading).
90
+ // - product: keep the displayed 1.0–1.5% target, but accept the wider
91
+ // 0.8–2.0% range when placement is already correct, so refinement
92
+ // doesn't loop over a ±0.2% drift.
93
+ if (this._placementOverride) {
94
+ if (this._pageType === 'collection') {
95
+ status = 'good';
96
+ } else if (this._pageType === 'product' && roundedDensity >= 0.8 && roundedDensity <= 2.0) {
97
+ status = 'good';
98
+ }
99
+ }
72
100
  const score = this.getScore(MAIN_CONTENT_POINTS, status);
73
101
  this._config = merge(this._config, {
74
102
  roundedDensity
@@ -1 +1 @@
1
- {"version":3,"file":"KeywordDensityAssessment.js","names":["merge","Assessment","AssessmentResult","keyphraseLengthFactor","KEYPHRASE_DENSITY_ID","MAIN_CONTENT_POINTS","KeyphraseDensityAssessment","constructor","config","defaultConfig","id","fixPosition","docUrl","ctaType","priority","title","content","good","bad","improve","identifier","_config","getResult","paper","researcher","_keyphraseCount","getResearch","keyphraseLength","_keyphraseDensity","assessmentResult","calculatedResult","calculateResult","setScore","score","setStatus","status","setTitle","density","roundedDensity","parseFloat","toFixed","getScore","isApplicable"],"sources":["../../../../../src/scoring/assessments/seo/KeywordDensityAssessment.js"],"sourcesContent":["import {merge} from 'lodash';\nimport Assessment from '../assessment';\nimport AssessmentResult from '../../../values/AssessmentResult';\n\nimport keyphraseLengthFactor from '../../../scoring/helpers/assessments/keyphraseLengthFactor';\nimport {KEYPHRASE_DENSITY_ID, MAIN_CONTENT_POINTS} from '@axyseo/const/analysis';\n\n/**\n * Represents the assessment that will look if the keyphrase density is within the recommended range.\n */\nclass KeyphraseDensityAssessment extends Assessment {\n /**\n *\n * @param config\n */\n constructor(config = {}) {\n super();\n\n const defaultConfig = {\n id: KEYPHRASE_DENSITY_ID,\n fixPosition: 'highlightKeyword',\n docUrl:\n 'https://docs.avada.io/seo-suite-help-center/seo-audit/on-page-seo/checklist#main-keyword-density',\n ctaType: 'fix',\n priority: 'high',\n title: 'Main keyword density',\n content: {\n good: 'Keyword density is optimized, between 1 - 1.5%.',\n bad: 'Keep keyword density from 1% - 1.5%.',\n improve: ''\n }\n };\n\n this.identifier = KEYPHRASE_DENSITY_ID;\n this._config = merge(defaultConfig, config);\n }\n\n /**\n * Runs the keyphrase density module, based on this returns an assessment\n * result with score.\n *\n * @param {Paper} paper The paper to use for the assessment.\n * @param {Researcher} researcher The researcher used for calling the research.\n *\n * @returns {AssessmentResult} The result of the assessment.\n */\n getResult({paper, researcher}) {\n\n this._keyphraseCount = researcher.getResearch('getKeyphraseCount');\n const keyphraseLength = this._keyphraseCount.keyphraseLength;\n\n this._keyphraseDensity = researcher.getResearch('getKeyphraseDensity');\n this._keyphraseDensity = this._keyphraseDensity * keyphraseLengthFactor(keyphraseLength);\n\n const assessmentResult = new AssessmentResult({config: this._config});\n\n const calculatedResult = this.calculateResult(paper);\n\n assessmentResult.setScore(calculatedResult.score);\n assessmentResult.setStatus(calculatedResult.status);\n assessmentResult.setTitle(calculatedResult.title);\n return assessmentResult;\n }\n\n /**\n *\n * @returns {{title: string, score: number, status: string}}\n */\n calculateResult() {\n let status = 'bad';\n const density = this._keyphraseDensity;\n const roundedDensity = parseFloat(density.toFixed(2));\n if (roundedDensity >= 1 && roundedDensity <= 1.5) {\n status = 'good';\n }\n\n const score = this.getScore(MAIN_CONTENT_POINTS, status);\n this._config = merge(this._config, {\n roundedDensity\n });\n return {\n roundedDensity,\n score,\n status\n };\n }\n\n /**\n * Checks whether the paper has a text of the minimum required length and a keyphrase is set. Language-specific length requirements and methods\n * of counting text length may apply (e.g. for Japanese, the text should be counted in characters instead of words, which also makes the minimum\n * required length higher).\n *\n * @param {Paper} \t\tpaper \t\tThe paper to use for the assessment.\n * @param {Researcher} researcher The paper to use for the assessment.\n *\n * @returns {boolean} True if applicable.\n */\n isApplicable(paper, researcher) {\n return true;\n }\n}\n\nexport default KeyphraseDensityAssessment;\n"],"mappings":"AAAA,SAAQA,KAAK,QAAO,QAAQ;AAC5B,OAAOC,UAAU;AACjB,OAAOC,gBAAgB;AAEvB,OAAOC,qBAAqB;AAC5B,SAAQC,oBAAoB,EAAEC,mBAAmB;;AAEjD;AACA;AACA;AACA,MAAMC,0BAA0B,SAASL,UAAU,CAAC;EAClD;AACF;AACA;AACA;EACEM,WAAWA,CAACC,MAAM,GAAG,CAAC,CAAC,EAAE;IACvB,KAAK,CAAC,CAAC;IAEP,MAAMC,aAAa,GAAG;MACpBC,EAAE,EAAEN,oBAAoB;MACxBO,WAAW,EAAE,kBAAkB;MAC/BC,MAAM,EACJ,kGAAkG;MACpGC,OAAO,EAAE,KAAK;MACdC,QAAQ,EAAE,MAAM;MAChBC,KAAK,EAAE,sBAAsB;MAC7BC,OAAO,EAAE;QACPC,IAAI,EAAE,iDAAiD;QACvDC,GAAG,EAAE,sCAAsC;QAC3CC,OAAO,EAAE;MACX;IACF,CAAC;IAED,IAAI,CAACC,UAAU,GAAGhB,oBAAoB;IACtC,IAAI,CAACiB,OAAO,GAAGrB,KAAK,CAACS,aAAa,EAAED,MAAM,CAAC;EAC7C;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEc,SAASA,CAAC;IAACC,KAAK;IAAEC;EAAU,CAAC,EAAE;IAE7B,IAAI,CAACC,eAAe,GAAGD,UAAU,CAACE,WAAW,CAAC,mBAAmB,CAAC;IAClE,MAAMC,eAAe,GAAG,IAAI,CAACF,eAAe,CAACE,eAAe;IAE5D,IAAI,CAACC,iBAAiB,GAAGJ,UAAU,CAACE,WAAW,CAAC,qBAAqB,CAAC;IACtE,IAAI,CAACE,iBAAiB,GAAG,IAAI,CAACA,iBAAiB,GAAGzB,qBAAqB,CAACwB,eAAe,CAAC;IAExF,MAAME,gBAAgB,GAAG,IAAI3B,gBAAgB,CAAC;MAACM,MAAM,EAAE,IAAI,CAACa;IAAO,CAAC,CAAC;IAErE,MAAMS,gBAAgB,GAAG,IAAI,CAACC,eAAe,CAACR,KAAK,CAAC;IAEpDM,gBAAgB,CAACG,QAAQ,CAACF,gBAAgB,CAACG,KAAK,CAAC;IACjDJ,gBAAgB,CAACK,SAAS,CAACJ,gBAAgB,CAACK,MAAM,CAAC;IACnDN,gBAAgB,CAACO,QAAQ,CAACN,gBAAgB,CAACf,KAAK,CAAC;IACjD,OAAOc,gBAAgB;EACzB;;EAEA;AACF;AACA;AACA;EACEE,eAAeA,CAAA,EAAG;IAChB,IAAII,MAAM,GAAG,KAAK;IAClB,MAAME,OAAO,GAAG,IAAI,CAACT,iBAAiB;IACtC,MAAMU,cAAc,GAAGC,UAAU,CAACF,OAAO,CAACG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrD,IAAIF,cAAc,IAAI,CAAC,IAAIA,cAAc,IAAI,GAAG,EAAE;MAChDH,MAAM,GAAG,MAAM;IACjB;IAEA,MAAMF,KAAK,GAAG,IAAI,CAACQ,QAAQ,CAACpC,mBAAmB,EAAE8B,MAAM,CAAC;IACxD,IAAI,CAACd,OAAO,GAAGrB,KAAK,CAAC,IAAI,CAACqB,OAAO,EAAE;MACjCiB;IACF,CAAC,CAAC;IACF,OAAO;MACLA,cAAc;MACdL,KAAK;MACLE;IACF,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEO,YAAYA,CAACnB,KAAK,EAAEC,UAAU,EAAE;IAC9B,OAAO,IAAI;EACb;AACF;AAEA,eAAelB,0BAA0B","ignoreList":[]}
1
+ {"version":3,"file":"KeywordDensityAssessment.js","names":["merge","Assessment","AssessmentResult","keyphraseLengthFactor","KEYPHRASE_DENSITY_ID","MAIN_CONTENT_POINTS","KeyphraseDensityAssessment","constructor","config","defaultConfig","id","fixPosition","docUrl","ctaType","priority","title","content","good","bad","improve","identifier","_config","getResult","paper","researcher","_keyphraseCount","getResearch","keyphraseLength","_keyphraseDensity","_placementOverride","pageType","getPageType","_pageType","firstParagraph","subHeadings","inIntro","foundInOneSentence","foundInParagraph","inSubheading","matches","assessmentResult","calculatedResult","calculateResult","setScore","score","setStatus","status","setTitle","density","roundedDensity","parseFloat","toFixed","getScore","isApplicable"],"sources":["../../../../../src/scoring/assessments/seo/KeywordDensityAssessment.js"],"sourcesContent":["import {merge} from 'lodash';\nimport Assessment from '../assessment';\nimport AssessmentResult from '../../../values/AssessmentResult';\n\nimport keyphraseLengthFactor from '../../../scoring/helpers/assessments/keyphraseLengthFactor';\nimport {KEYPHRASE_DENSITY_ID, MAIN_CONTENT_POINTS} from '@axyseo/const/analysis';\n\n/**\n * Represents the assessment that will look if the keyphrase density is within the recommended range.\n */\nclass KeyphraseDensityAssessment extends Assessment {\n /**\n *\n * @param config\n */\n constructor(config = {}) {\n super();\n\n const defaultConfig = {\n id: KEYPHRASE_DENSITY_ID,\n fixPosition: 'highlightKeyword',\n docUrl:\n 'https://docs.avada.io/seo-suite-help-center/seo-audit/on-page-seo/checklist#main-keyword-density',\n ctaType: 'fix',\n priority: 'high',\n title: 'Main keyword density',\n content: {\n good: 'Keyword density is optimized, between 1 - 1.5%.',\n bad: 'Keep keyword density from 1% - 1.5%.',\n improve: ''\n }\n };\n\n this.identifier = KEYPHRASE_DENSITY_ID;\n this._config = merge(defaultConfig, config);\n }\n\n /**\n * Runs the keyphrase density module, based on this returns an assessment\n * result with score.\n *\n * @param {Paper} paper The paper to use for the assessment.\n * @param {Researcher} researcher The researcher used for calling the research.\n *\n * @returns {AssessmentResult} The result of the assessment.\n */\n getResult({paper, researcher}) {\n\n this._keyphraseCount = researcher.getResearch('getKeyphraseCount');\n const keyphraseLength = this._keyphraseCount.keyphraseLength;\n\n this._keyphraseDensity = researcher.getResearch('getKeyphraseDensity');\n this._keyphraseDensity = this._keyphraseDensity * keyphraseLengthFactor(keyphraseLength);\n\n // For collection pages: density % is meaningless on 150–300 word content\n // and conflicts with related-keyword coverage. Treat density as good when\n // the keyword is already placed in the introduction AND in a subheading.\n this._placementOverride = false;\n const pageType =\n typeof paper?.getPageType === 'function' ? paper.getPageType() : null;\n this._pageType = pageType;\n if (pageType === 'collection' || pageType === 'product') {\n const firstParagraph = researcher.getResearch('findKeywordInFirstParagraph');\n const subHeadings = researcher.getResearch('matchKeywordInSubheadings');\n const inIntro = !!(\n firstParagraph &&\n (firstParagraph.foundInOneSentence || firstParagraph.foundInParagraph)\n );\n const inSubheading = !!(subHeadings && subHeadings.matches > 0);\n this._placementOverride = inIntro && inSubheading;\n }\n\n const assessmentResult = new AssessmentResult({config: this._config});\n\n const calculatedResult = this.calculateResult(paper);\n\n assessmentResult.setScore(calculatedResult.score);\n assessmentResult.setStatus(calculatedResult.status);\n assessmentResult.setTitle(calculatedResult.title);\n return assessmentResult;\n }\n\n /**\n *\n * @returns {{title: string, score: number, status: string}}\n */\n calculateResult() {\n let status = 'bad';\n const density = this._keyphraseDensity;\n const roundedDensity = parseFloat(density.toFixed(2));\n if (roundedDensity >= 1 && roundedDensity <= 1.5) {\n status = 'good';\n }\n\n // Placement-based overrides (see getResult for how _placementOverride is set):\n // - collection: short content (150–300 words) makes % unreliable; pass\n // purely on placement (intro + subheading).\n // - product: keep the displayed 1.0–1.5% target, but accept the wider\n // 0.8–2.0% range when placement is already correct, so refinement\n // doesn't loop over a ±0.2% drift.\n if (this._placementOverride) {\n if (this._pageType === 'collection') {\n status = 'good';\n } else if (\n this._pageType === 'product' &&\n roundedDensity >= 0.8 &&\n roundedDensity <= 2.0\n ) {\n status = 'good';\n }\n }\n\n const score = this.getScore(MAIN_CONTENT_POINTS, status);\n this._config = merge(this._config, {\n roundedDensity\n });\n return {\n roundedDensity,\n score,\n status\n };\n }\n\n /**\n * Checks whether the paper has a text of the minimum required length and a keyphrase is set. Language-specific length requirements and methods\n * of counting text length may apply (e.g. for Japanese, the text should be counted in characters instead of words, which also makes the minimum\n * required length higher).\n *\n * @param {Paper} \t\tpaper \t\tThe paper to use for the assessment.\n * @param {Researcher} researcher The paper to use for the assessment.\n *\n * @returns {boolean} True if applicable.\n */\n isApplicable(paper, researcher) {\n return true;\n }\n}\n\nexport default KeyphraseDensityAssessment;\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"RelatedKeywordsDensityAssessment.js","names":["isEmpty","merge","AssessmentResult","Assessment","MAIN_CONTENT_POINTS","RELATED_KEYWORDS_DENSITY_ID","RelatedKeywordsDensityAssessment","constructor","config","defaultConfig","id","fixPosition","ctaType","docUrl","priority","title","content","good","bad","improve","identifier","_config","calculateResult","data","relatedKeywords","hasDescription","words","status","totalWords","Object","values","filter","word","percentage","length","score","getScore","getResult","paper","researcher","getResearch","getData","result","assessmentResult","setScore","setStatus","setData","isApplicable"],"sources":["../../../../../src/scoring/assessments/seo/RelatedKeywordsDensityAssessment.js"],"sourcesContent":["import {isEmpty, merge} from 'lodash';\nimport AssessmentResult from '../../../values/AssessmentResult';\nimport Assessment from '../assessment';\nimport {MAIN_CONTENT_POINTS, RELATED_KEYWORDS_DENSITY_ID} from '@axyseo/const/analysis';\n\n/**\n * Represents the assessment that checks whether there are enough transition words in the text.\n */\nexport default class RelatedKeywordsDensityAssessment extends Assessment {\n /**\n * Sets the identifier and the config.\n *\n * @param {object} config The configuration to use.\n *\n * @returns {void}\n */\n constructor(config = {}) {\n super();\n\n const defaultConfig = {\n id: RELATED_KEYWORDS_DENSITY_ID,\n fixPosition: 'description',\n ctaType: 'fix',\n docUrl:\n 'https://docs.avada.io/seo-suite-help-center/seo-audit/on-page-seo/checklist#related-keywords',\n priority: 'high',\n title: 'Related keywords density',\n content: {\n good: 'Related keywords density optimized',\n bad:\n 'Use each secondary keyword from 0.5% to 1%. Place where it reads naturally.',\n improve: ''\n }\n };\n\n this.identifier = RELATED_KEYWORDS_DENSITY_ID;\n this._config = merge(defaultConfig, config);\n }\n\n /**\n *\n * @param data\n * @param relatedKeywords\n * @param hasDescription\n * @returns {{score: number, status: string, words}}\n */\n calculateResult(data, relatedKeywords, hasDescription) {\n const {words} = relatedKeywords;\n let status = 'good';\n\n const totalWords = Object.values(words).filter(word => word.percentage === 0);\n if(!hasDescription || isEmpty(words) || totalWords.length > 0){\n status = 'bad';\n }\n const score = this.getScore(MAIN_CONTENT_POINTS, status);\n\n return {\n score,\n status,\n words\n };\n }\n\n /**\n *\n * @param paper\n * @param researcher\n * @returns {AssessmentResult}\n */\n getResult({paper, researcher}) {\n const relatedKeywords = researcher.getResearch('checkRelatedKeywords');\n const data = paper.getData();\n const hasDescription = paper.hasDescription();\n const result = this.calculateResult(data, relatedKeywords, hasDescription);\n const assessmentResult = new AssessmentResult({config: this._config});\n\n assessmentResult.setScore(result.score);\n assessmentResult.setStatus(result.status);\n assessmentResult.setData(result.words);\n\n return assessmentResult;\n }\n\n /**\n * Checks if the transition words assessment is applicable to the paper. Language-specific length requirements and methods of counting text length\n * may apply (e.g. for Japanese, the text should be counted in characters instead of words, which also makes the minimum required length higher).\n *\n * @param {Paper} paper The paper to check.\n * @param {Researcher} researcher The researcher object.\n *\n * @returns {boolean} Returns true if the language is available, the paper is not empty and the text is longer than the minimum required length.\n */\n isApplicable(paper, researcher) {\n return true;\n }\n}\n"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,KAAK,QAAO,QAAQ;AACrC,OAAOC,gBAAgB;AACvB,OAAOC,UAAU;AACjB,SAAQC,mBAAmB,EAAEC,2BAA2B;;AAExD;AACA;AACA;AACA,eAAe,MAAMC,gCAAgC,SAASH,UAAU,CAAC;EACvE;AACF;AACA;AACA;AACA;AACA;AACA;EACEI,WAAWA,CAACC,MAAM,GAAG,CAAC,CAAC,EAAE;IACvB,KAAK,CAAC,CAAC;IAEP,MAAMC,aAAa,GAAG;MACpBC,EAAE,EAAEL,2BAA2B;MAC/BM,WAAW,EAAE,aAAa;MAC1BC,OAAO,EAAE,KAAK;MACdC,MAAM,EACJ,8FAA8F;MAChGC,QAAQ,EAAE,MAAM;MAChBC,KAAK,EAAE,0BAA0B;MACjCC,OAAO,EAAE;QACPC,IAAI,EAAE,oCAAoC;QAC1CC,GAAG,EACD,6EAA6E;QAC/EC,OAAO,EAAE;MACX;IACF,CAAC;IAED,IAAI,CAACC,UAAU,GAAGf,2BAA2B;IAC7C,IAAI,CAACgB,OAAO,GAAGpB,KAAK,CAACQ,aAAa,EAAED,MAAM,CAAC;EAC7C;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;EACEc,eAAeA,CAACC,IAAI,EAAEC,eAAe,EAAEC,cAAc,EAAE;IACrD,MAAM;MAACC;IAAK,CAAC,GAAGF,eAAe;IAC/B,IAAIG,MAAM,GAAG,MAAM;IAEnB,MAAMC,UAAU,GAAGC,MAAM,CAACC,MAAM,CAACJ,KAAK,CAAC,CAACK,MAAM,CAACC,IAAI,IAAIA,IAAI,CAACC,UAAU,KAAK,CAAC,CAAC;IAC7E,IAAG,CAACR,cAAc,IAAIzB,OAAO,CAAC0B,KAAK,CAAC,IAAIE,UAAU,CAACM,MAAM,GAAG,CAAC,EAAC;MAC5DP,MAAM,GAAG,KAAK;IAChB;IACA,MAAMQ,KAAK,GAAG,IAAI,CAACC,QAAQ,CAAChC,mBAAmB,EAAEuB,MAAM,CAAC;IAExD,OAAO;MACLQ,KAAK;MACLR,MAAM;MACND;IACF,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;AACA;EACEW,SAASA,CAAC;IAACC,KAAK;IAAEC;EAAU,CAAC,EAAE;IAC7B,MAAMf,eAAe,GAAGe,UAAU,CAACC,WAAW,CAAC,sBAAsB,CAAC;IACtE,MAAMjB,IAAI,GAAGe,KAAK,CAACG,OAAO,CAAC,CAAC;IAC5B,MAAMhB,cAAc,GAAGa,KAAK,CAACb,cAAc,CAAC,CAAC;IAC7C,MAAMiB,MAAM,GAAG,IAAI,CAACpB,eAAe,CAACC,IAAI,EAAEC,eAAe,EAAEC,cAAc,CAAC;IAC1E,MAAMkB,gBAAgB,GAAG,IAAIzC,gBAAgB,CAAC;MAACM,MAAM,EAAE,IAAI,CAACa;IAAO,CAAC,CAAC;IAErEsB,gBAAgB,CAACC,QAAQ,CAACF,MAAM,CAACP,KAAK,CAAC;IACvCQ,gBAAgB,CAACE,SAAS,CAACH,MAAM,CAACf,MAAM,CAAC;IACzCgB,gBAAgB,CAACG,OAAO,CAACJ,MAAM,CAAChB,KAAK,CAAC;IAEtC,OAAOiB,gBAAgB;EACzB;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEI,YAAYA,CAACT,KAAK,EAAEC,UAAU,EAAE;IAC9B,OAAO,IAAI;EACb;AACF","ignoreList":[]}
1
+ {"version":3,"file":"RelatedKeywordsDensityAssessment.js","names":["isEmpty","merge","AssessmentResult","Assessment","MAIN_CONTENT_POINTS","RELATED_KEYWORDS_DENSITY_ID","RelatedKeywordsDensityAssessment","constructor","config","defaultConfig","id","fixPosition","ctaType","docUrl","priority","title","content","good","bad","improve","identifier","_config","calculateResult","data","relatedKeywords","hasDescription","words","status","totalWords","Object","values","filter","word","percentage","length","score","getScore","getResult","paper","researcher","getResearch","getData","result","assessmentResult","setScore","setStatus","setData","isApplicable"],"sources":["../../../../../src/scoring/assessments/seo/RelatedKeywordsDensityAssessment.js"],"sourcesContent":["import {isEmpty, merge} from 'lodash';\nimport AssessmentResult from '../../../values/AssessmentResult';\nimport Assessment from '../assessment';\nimport {MAIN_CONTENT_POINTS, RELATED_KEYWORDS_DENSITY_ID} from '@axyseo/const/analysis';\n\n/**\n * Represents the assessment that checks whether there are enough transition words in the text.\n */\nexport default class RelatedKeywordsDensityAssessment extends Assessment {\n /**\n * Sets the identifier and the config.\n *\n * @param {object} config The configuration to use.\n *\n * @returns {void}\n */\n constructor(config = {}) {\n super();\n\n const defaultConfig = {\n id: RELATED_KEYWORDS_DENSITY_ID,\n fixPosition: 'description',\n ctaType: 'fix',\n docUrl:\n 'https://docs.avada.io/seo-suite-help-center/seo-audit/on-page-seo/checklist#related-keywords',\n priority: 'high',\n title: 'Related keywords density',\n content: {\n good: 'Related keywords density optimized',\n bad:\n 'Use each secondary keyword from 0.5% to 1%. Place where it reads naturally.',\n improve: ''\n }\n };\n\n this.identifier = RELATED_KEYWORDS_DENSITY_ID;\n this._config = merge(defaultConfig, config);\n }\n\n /**\n *\n * @param data\n * @param relatedKeywords\n * @param hasDescription\n * @returns {{score: number, status: string, words}}\n */\n calculateResult(data, relatedKeywords, hasDescription) {\n const {words} = relatedKeywords;\n let status = 'good';\n const totalWords = Object.values(words).filter(word => word.percentage === 0);\n if(!hasDescription || isEmpty(words) || totalWords.length > 0){\n status = 'bad';\n }\n const score = this.getScore(MAIN_CONTENT_POINTS, status);\n\n return {\n score,\n status,\n words\n };\n }\n\n /**\n *\n * @param paper\n * @param researcher\n * @returns {AssessmentResult}\n */\n getResult({paper, researcher}) {\n const relatedKeywords = researcher.getResearch('checkRelatedKeywords');\n const data = paper.getData();\n const hasDescription = paper.hasDescription();\n const result = this.calculateResult(data, relatedKeywords, hasDescription);\n const assessmentResult = new AssessmentResult({config: this._config});\n\n assessmentResult.setScore(result.score);\n assessmentResult.setStatus(result.status);\n assessmentResult.setData(result.words);\n\n return assessmentResult;\n }\n\n /**\n * Checks if the transition words assessment is applicable to the paper. Language-specific length requirements and methods of counting text length\n * may apply (e.g. for Japanese, the text should be counted in characters instead of words, which also makes the minimum required length higher).\n *\n * @param {Paper} paper The paper to check.\n * @param {Researcher} researcher The researcher object.\n *\n * @returns {boolean} Returns true if the language is available, the paper is not empty and the text is longer than the minimum required length.\n */\n isApplicable(paper, researcher) {\n return true;\n }\n}\n"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,KAAK,QAAO,QAAQ;AACrC,OAAOC,gBAAgB;AACvB,OAAOC,UAAU;AACjB,SAAQC,mBAAmB,EAAEC,2BAA2B;;AAExD;AACA;AACA;AACA,eAAe,MAAMC,gCAAgC,SAASH,UAAU,CAAC;EACvE;AACF;AACA;AACA;AACA;AACA;AACA;EACEI,WAAWA,CAACC,MAAM,GAAG,CAAC,CAAC,EAAE;IACvB,KAAK,CAAC,CAAC;IAEP,MAAMC,aAAa,GAAG;MACpBC,EAAE,EAAEL,2BAA2B;MAC/BM,WAAW,EAAE,aAAa;MAC1BC,OAAO,EAAE,KAAK;MACdC,MAAM,EACJ,8FAA8F;MAChGC,QAAQ,EAAE,MAAM;MAChBC,KAAK,EAAE,0BAA0B;MACjCC,OAAO,EAAE;QACPC,IAAI,EAAE,oCAAoC;QAC1CC,GAAG,EACD,6EAA6E;QAC/EC,OAAO,EAAE;MACX;IACF,CAAC;IAED,IAAI,CAACC,UAAU,GAAGf,2BAA2B;IAC7C,IAAI,CAACgB,OAAO,GAAGpB,KAAK,CAACQ,aAAa,EAAED,MAAM,CAAC;EAC7C;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;EACEc,eAAeA,CAACC,IAAI,EAAEC,eAAe,EAAEC,cAAc,EAAE;IACrD,MAAM;MAACC;IAAK,CAAC,GAAGF,eAAe;IAC/B,IAAIG,MAAM,GAAG,MAAM;IACnB,MAAMC,UAAU,GAAGC,MAAM,CAACC,MAAM,CAACJ,KAAK,CAAC,CAACK,MAAM,CAACC,IAAI,IAAIA,IAAI,CAACC,UAAU,KAAK,CAAC,CAAC;IAC7E,IAAG,CAACR,cAAc,IAAIzB,OAAO,CAAC0B,KAAK,CAAC,IAAIE,UAAU,CAACM,MAAM,GAAG,CAAC,EAAC;MAC5DP,MAAM,GAAG,KAAK;IAChB;IACA,MAAMQ,KAAK,GAAG,IAAI,CAACC,QAAQ,CAAChC,mBAAmB,EAAEuB,MAAM,CAAC;IAExD,OAAO;MACLQ,KAAK;MACLR,MAAM;MACND;IACF,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;AACA;EACEW,SAASA,CAAC;IAACC,KAAK;IAAEC;EAAU,CAAC,EAAE;IAC7B,MAAMf,eAAe,GAAGe,UAAU,CAACC,WAAW,CAAC,sBAAsB,CAAC;IACtE,MAAMjB,IAAI,GAAGe,KAAK,CAACG,OAAO,CAAC,CAAC;IAC5B,MAAMhB,cAAc,GAAGa,KAAK,CAACb,cAAc,CAAC,CAAC;IAC7C,MAAMiB,MAAM,GAAG,IAAI,CAACpB,eAAe,CAACC,IAAI,EAAEC,eAAe,EAAEC,cAAc,CAAC;IAC1E,MAAMkB,gBAAgB,GAAG,IAAIzC,gBAAgB,CAAC;MAACM,MAAM,EAAE,IAAI,CAACa;IAAO,CAAC,CAAC;IAErEsB,gBAAgB,CAACC,QAAQ,CAACF,MAAM,CAACP,KAAK,CAAC;IACvCQ,gBAAgB,CAACE,SAAS,CAACH,MAAM,CAACf,MAAM,CAAC;IACzCgB,gBAAgB,CAACG,OAAO,CAACJ,MAAM,CAAChB,KAAK,CAAC;IAEtC,OAAOiB,gBAAgB;EACzB;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEI,YAAYA,CAACT,KAAK,EAAEC,UAAU,EAAE;IAC9B,OAAO,IAAI;EACb;AACF","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axyseo",
3
- "version": "2.1.51",
3
+ "version": "2.1.53",
4
4
  "main": "build/cjs/index.js",
5
5
  "module": "build/esm/index.js",
6
6
  "exports": {