From 0eb3bab6607120f98a621cc1ffe97c30e4f1b6e3 Mon Sep 17 00:00:00 2001 From: Martijn van der Klis Date: Tue, 12 Nov 2024 16:01:18 +0100 Subject: [PATCH 01/92] Converts the sentence length assessment to use the HTML Parser --- .../helpers/sentence/sentencesLengthSpec.js | 57 +++++--- .../researches/countSentencesFromTextSpec.js | 138 ++++++++++++------ .../SentenceLengthInTextAssessmentSpec.js | 129 ++++++++++++---- .../checkForTooLongSentencesSpec.js | 50 ------- .../helpers/sentence/sentencesLength.js | 35 +++-- .../helpers/word/getAllWordsFromTree.js | 27 +++- .../researches/countSentencesFromText.js | 12 +- .../SentenceLengthInTextAssessment.js | 51 +++---- .../assessments/checkForTooLongSentences.js | 13 -- 9 files changed, 290 insertions(+), 222 deletions(-) delete mode 100644 packages/yoastseo/spec/scoring/helpers/assessments/checkForTooLongSentencesSpec.js delete mode 100644 packages/yoastseo/src/scoring/helpers/assessments/checkForTooLongSentences.js diff --git a/packages/yoastseo/spec/languageProcessing/helpers/sentence/sentencesLengthSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/sentence/sentencesLengthSpec.js index 0b50b8e7b7b..5495caa60f8 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/sentence/sentencesLengthSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/sentence/sentencesLengthSpec.js @@ -1,41 +1,50 @@ import sentencesLength from "../../../../src/languageProcessing/helpers/sentence/sentencesLength"; +import getSentencesFromTree from "../../../../src/languageProcessing/helpers/sentence/getSentencesFromTree"; import JapaneseResearcher from "../../../../src/languageProcessing/languages/ja/Researcher"; import EnglishResearcher from "../../../../src/languageProcessing/languages/en/Researcher"; import Paper from "../../../../src/values/Paper"; +import buildTree from "../../../specHelpers/parse/buildTree"; describe( "A test to count sentence lengths.", function() { it( "should not return a length for an empty sentence", function() { - const sentences = [ "", "A sentence" ]; - const mockResearcher = new EnglishResearcher( new Paper( "" ) ); + const mockPaper = new Paper( "

A sentence

" ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); - const lengths = sentencesLength( sentences, mockResearcher ); + const sentenceLengths = sentencesLength( getSentencesFromTree( mockPaper ), mockResearcher ); - expect( lengths ).toEqual( [ - { sentence: "A sentence", sentenceLength: 2 }, - ] ); + expect( sentenceLengths.length ).toEqual( 1 ); + expect( sentenceLengths[ 0 ].sentenceLength ).toEqual( 2 ); + expect( sentenceLengths[ 0 ].sentence.text ).toEqual( "A sentence" ); } ); it( "should return the sentences and their length (the HTML tags should not be counted if present)", function() { - const sentences = [ "A good text", "this is a textstring " ]; - const mockResearcher = new EnglishResearcher( new Paper( "" ) ); - - const lengths = sentencesLength( sentences, mockResearcher ); - - expect( lengths ).toEqual( [ - { sentence: "A good text", sentenceLength: 3 }, - { sentence: "this is a textstring ", sentenceLength: 4 }, - ] ); + const mockPaper = new Paper( "

A good text

" + + "

this is a string

" ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentenceLengths = sentencesLength( getSentencesFromTree( mockPaper ), mockResearcher ); + + expect( sentenceLengths.length ).toEqual( 2 ); + expect( sentenceLengths[ 0 ].sentenceLength ).toEqual( 3 ); + expect( sentenceLengths[ 0 ].sentence.text ).toEqual( "A good text" ); + expect( sentenceLengths[ 1 ].sentenceLength ).toEqual( 4 ); + expect( sentenceLengths[ 1 ].sentence.text ).toEqual( "this is a string" ); } ); it( "should return the sentences and their length for Japanese (so counting characters)", function() { - const sentences = [ "自然おのずから存在しているもの", "歩くさわやかな森 自然 " ]; - const mockJapaneseResearcher = new JapaneseResearcher( new Paper( "" ) ); - - const lengths = sentencesLength( sentences, mockJapaneseResearcher ); - - expect( lengths ).toEqual( [ - { sentence: "自然おのずから存在しているもの", sentenceLength: 15 }, - { sentence: "歩くさわやかな森 自然 ", sentenceLength: 10 }, - ] ); + const mockPaper = new Paper( "

自然おのずから存在しているもの

" + + "

歩くさわやかな森 自然

" ); + const mockJapaneseResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockJapaneseResearcher ); + + const sentenceLengths = sentencesLength( getSentencesFromTree( mockPaper ), mockJapaneseResearcher ); + + expect( sentenceLengths.length ).toEqual( 2 ); + expect( sentenceLengths[ 0 ].sentenceLength ).toEqual( 15 ); + expect( sentenceLengths[ 0 ].sentence.text ).toEqual( "自然おのずから存在しているもの" ); + expect( sentenceLengths[ 1 ].sentenceLength ).toEqual( 10 ); + expect( sentenceLengths[ 1 ].sentence.text ).toEqual( "歩くさわやかな森 自然 " ); } ); } ); diff --git a/packages/yoastseo/spec/languageProcessing/researches/countSentencesFromTextSpec.js b/packages/yoastseo/spec/languageProcessing/researches/countSentencesFromTextSpec.js index 79fca670a80..0b65b6c2ae5 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/countSentencesFromTextSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/countSentencesFromTextSpec.js @@ -1,68 +1,122 @@ -/* eslint-disable capitalized-comments, spaced-comment */ import getSentences from "../../../src/languageProcessing/researches/countSentencesFromText.js"; import Paper from "../../../src/values/Paper"; import EnglishResearcher from "../../../src/languageProcessing/languages/en/Researcher"; +import JapaneseResearcher from "../../../src/languageProcessing/languages/ja/Researcher"; +import buildTree from "../../specHelpers/parse/buildTree"; describe( "counts words in sentences from text", function() { - let paper; - it( "returns sentences with question mark", function() { - paper = new Paper( "Hello. How are you? Bye" ); - expect( getSentences( paper, new EnglishResearcher() )[ 0 ].sentenceLength ).toBe( 1 ); - expect( getSentences( paper, new EnglishResearcher() )[ 1 ].sentenceLength ).toBe( 3 ); - expect( getSentences( paper, new EnglishResearcher() )[ 2 ].sentenceLength ).toBe( 1 ); + const mockPaper = new Paper( "Hello. How are you? Bye" ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 1 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 3 ); + expect( sentences[ 2 ].sentenceLength ).toBe( 1 ); } ); it( "returns sentences with exclamation mark", function() { - paper = new Paper( "Hello. How are you! Bye" ); - expect( getSentences( paper, new EnglishResearcher() )[ 0 ].sentenceLength ).toBe( 1 ); - expect( getSentences( paper, new EnglishResearcher() )[ 1 ].sentenceLength ).toBe( 3 ); - expect( getSentences( paper, new EnglishResearcher() )[ 2 ].sentenceLength ).toBe( 1 ); + const mockPaper = new Paper( "Hello. How are you! Bye" ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 1 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 3 ); + expect( sentences[ 2 ].sentenceLength ).toBe( 1 ); } ); it( "returns sentences with many spaces", function() { - paper = new Paper( "Hello. How are you! Bye" ); - expect( getSentences( paper, new EnglishResearcher() )[ 0 ].sentenceLength ).toBe( 1 ); - expect( getSentences( paper, new EnglishResearcher() )[ 1 ].sentenceLength ).toBe( 3 ); - expect( getSentences( paper, new EnglishResearcher() )[ 2 ].sentenceLength ).toBe( 1 ); + const mockPaper = new Paper( "Hello. How are you! Bye" ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 1 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 3 ); + expect( sentences[ 2 ].sentenceLength ).toBe( 1 ); } ); it( "returns sentences with html-tags, should only count words", function() { - paper = new Paper( "This is a text a bunch of words in an alt-tag" ); - expect( getSentences( paper, new EnglishResearcher() )[ 0 ].sentenceLength ).toBe( 4 ); + const mockPaper = new Paper( "This is a text a bunch of words in an alt-tag" ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 4 ); } ); it( "returns sentences with html-tags, should only count words", function() { - paper = new Paper( "This is a text a bunch of words in an alt-tag. Another sentence." ); - expect( getSentences( paper, new EnglishResearcher() )[ 0 ].sentenceLength ).toBe( 4 ); - expect( getSentences( paper, new EnglishResearcher() )[ 1 ].sentenceLength ).toBe( 2 ); + const mockPaper = new Paper( "This is a text a bunch of words in an alt-tag. Another sentence." ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 4 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 2 ); } ); it( "should not count sentences inside elements we want to exclude from the analysis", function() { - paper = new Paper( "This is a text. With some code.. Another sentence." ); - expect( getSentences( paper, new EnglishResearcher() )[ 0 ].sentenceLength ).toBe( 4 ); - expect( getSentences( paper, new EnglishResearcher() )[ 1 ].sentenceLength ).toBe( 2 ); + const mockPaper = new Paper( "This is a text. With some code.. Another sentence." ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 4 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 2 ); } ); - /*it( "returns sentences with question mark in Japanese", function() { - paper = new Paper( "雨が降っている。 いつ終わるの? さようなら" ); - expect( getSentences( paper, new JapaneseResearcher() )[ 0 ].sentenceLength ).toBe( 8 ); - expect( getSentences( paper, new JapaneseResearcher() )[ 1 ].sentenceLength ).toBe( 7 ); - expect( getSentences( paper, new JapaneseResearcher() )[ 2 ].sentenceLength ).toBe( 5 ); + it( "returns sentences with question mark in Japanese", function() { + const mockPaper = new Paper( "雨が降っている。 いつ終わるの? さようなら" ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 8 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 7 ); + expect( sentences[ 2 ].sentenceLength ).toBe( 5 ); } ); it( "returns sentences with exclamation mark", function() { - paper = new Paper( "雨が降っている. いつ終わるの!さようなら" ); - expect( getSentences( paper, new JapaneseResearcher() )[ 0 ].sentenceLength ).toBe( 8 ); - expect( getSentences( paper, new JapaneseResearcher() )[ 1 ].sentenceLength ).toBe( 7 ); - expect( getSentences( paper, new JapaneseResearcher() )[ 2 ].sentenceLength ).toBe( 5 ); + const mockPaper = new Paper( "雨が降っている. いつ終わるの!さようなら" ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 8 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 7 ); + expect( sentences[ 2 ].sentenceLength ).toBe( 5 ); } ); it( "returns sentences with many spaces", function() { - paper = new Paper( "雨が降っている。 いつ終わるの? さようなら" ); - expect( getSentences( paper, new JapaneseResearcher() )[ 0 ].sentenceLength ).toBe( 8 ); - expect( getSentences( paper, new JapaneseResearcher() )[ 1 ].sentenceLength ).toBe( 7 ); - expect( getSentences( paper, new JapaneseResearcher() )[ 2 ].sentenceLength ).toBe( 5 ); + const mockPaper = new Paper( "雨が降っている。 いつ終わるの? さようなら" ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 8 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 7 ); + expect( sentences[ 2 ].sentenceLength ).toBe( 5 ); } ); it( "returns sentences with html-tags, should count characters in Japanese", function() { - paper = new Paper( "いつ終わるの 自分を大事にして下さい" ); - expect( getSentences( paper, new JapaneseResearcher() )[ 0 ].sentenceLength ).toBe( 6 ); + const mockPaper = new Paper( "いつ終わるの 自分を大事にして下さい" ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 6 ); } ); it( "returns sentences with html-tags, should count characters in Japanese", function() { - paper = new Paper( "いつ終わるの 自分を大事にして下さい. 春がやってきます。" ); - expect( getSentences( paper, new JapaneseResearcher() )[ 0 ].sentenceLength ).toBe( 7 ); - expect( getSentences( paper, new JapaneseResearcher() )[ 1 ].sentenceLength ).toBe( 9 ); - } );*/ + const mockPaper = new Paper( "いつ終わるの 自分を大事にして下さい. 春がやってきます。" ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentences = getSentences( mockPaper, mockResearcher ); + + expect( sentences[ 0 ].sentenceLength ).toBe( 7 ); + expect( sentences[ 1 ].sentenceLength ).toBe( 9 ); + } ); } ); diff --git a/packages/yoastseo/spec/scoring/assessments/readability/SentenceLengthInTextAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/readability/SentenceLengthInTextAssessmentSpec.js index 38b6d5ea83a..ad1cb7b091f 100644 --- a/packages/yoastseo/spec/scoring/assessments/readability/SentenceLengthInTextAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/readability/SentenceLengthInTextAssessmentSpec.js @@ -5,6 +5,7 @@ import Paper from "../../../../src/values/Paper.js"; import Mark from "../../../../src/values/Mark.js"; import addMark from "../../../../src/markers/addMark"; import Factory from "../../../../src/helpers/factory.js"; +import buildTree from "../../../specHelpers/parse/buildTree"; import DefaultResearcher from "../../../../src/languageProcessing/languages/_default/Researcher"; import EnglishResearcher from "../../../../src/languageProcessing/languages/en/Researcher"; @@ -12,19 +13,21 @@ import PolishResearcher from "../../../../src/languageProcessing/languages/pl/Re import RussianResearcher from "../../../../src/languageProcessing/languages/ru/Researcher"; import ItalianResearcher from "../../../../src/languageProcessing/languages/it/Researcher"; import TurkishResearcher from "../../../../src/languageProcessing/languages/tr/Researcher"; +import japaneseConfig from "../../../../src/languageProcessing/languages/ja/config/sentenceLength"; const shortSentenceDefault = "Word ".repeat( 18 ) + "word. "; const longSentenceDefault = "Word ".repeat( 20 ) + "word. "; const shortSentence15WordsLimit = "Word ".repeat( 13 ) + "word. "; const longSentence15WordsLimit = "Word ".repeat( 15 ) + "word. "; -import japaneseConfig from "../../../../src/languageProcessing/languages/ja/config/sentenceLength"; - // eslint-disable-next-line max-statements describe( "An assessment for sentence length", function() { it( "returns the score for all short sentences using the default config", function() { const mockPaper = new Paper( shortSentenceDefault ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new DefaultResearcher( mockPaper ) ); + const mockResearcher = new DefaultResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 9 ); @@ -34,7 +37,10 @@ describe( "An assessment for sentence length", function() { it( "returns the score for 50% long sentences using the default config", function() { const mockPaper = new Paper( shortSentenceDefault + longSentenceDefault ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new DefaultResearcher( mockPaper ) ); + const mockResearcher = new DefaultResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 3 ); @@ -46,7 +52,10 @@ describe( "An assessment for sentence length", function() { it( "returns the score for 100% long sentences using the default config", function() { const mockPaper = new Paper( longSentenceDefault ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new DefaultResearcher( mockPaper ) ); + const mockResearcher = new DefaultResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 3 ); @@ -58,7 +67,10 @@ describe( "An assessment for sentence length", function() { it( "returns the score for 25% long sentences using the default config", function() { const mockPaper = new Paper( longSentenceDefault + shortSentenceDefault + shortSentenceDefault + shortSentenceDefault ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new DefaultResearcher( mockPaper ) ); + const mockResearcher = new DefaultResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 9 ); @@ -68,7 +80,10 @@ describe( "An assessment for sentence length", function() { it( "returns the score for 30% long sentences using the default config", function() { const mockPaper = new Paper( longSentenceDefault.repeat( 3 ) + shortSentenceDefault.repeat( 7 ) ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new DefaultResearcher( mockPaper ) ); + const mockResearcher = new DefaultResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 6 ); @@ -80,7 +95,10 @@ describe( "An assessment for sentence length", function() { it( "returns the score for 100% long sentences in a language that overrides the default recommended length config", function() { const mockPaper = new Paper( longSentence15WordsLimit ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new RussianResearcher( mockPaper ) ); + const mockResearcher = new RussianResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 3 ); @@ -90,8 +108,15 @@ describe( "An assessment for sentence length", function() { expect( assessment.hasMarks() ).toBe( true ); expect( new SentenceLengthInTextAssessment().getMarks( mockPaper, new RussianResearcher( mockPaper ) ) ).toEqual( [ new Mark( { - original: "Word Word Word Word Word Word Word Word Word Word Word Word Word Word Word word.", - marked: addMark( "Word Word Word Word Word Word Word Word Word Word Word Word Word Word Word word." ), + position: { + startOffset: 0, + endOffset: 81, + startOffsetBlock: 0, + endOffsetBlock: 81, + clientId: "", + attributeId: "", + isFirstSection: false, + }, } ), ] ); } ); @@ -173,7 +198,10 @@ describe( "An assessment for sentence length", function() { it( "returns the score for 20% long sentences in a language that overrides the default config" + " for maximum allowed percentage of long sentences", function() { const mockPaper = new Paper( longSentenceDefault.repeat( 4 ) + shortSentenceDefault.repeat( 16 ) ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new PolishResearcher( mockPaper ) ); + const mockResearcher = new PolishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 6 ); @@ -186,7 +214,10 @@ describe( "An assessment for sentence length", function() { it( "returns the score for 25% long sentences in a language that overrides the default config for both recommended " + "maximum sentence length, and the maximum allowed percentage of long sentences", function() { const mockPaper = new Paper( longSentence15WordsLimit + shortSentence15WordsLimit.repeat( 3 ) ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new TurkishResearcher( mockPaper ) ); + const mockResearcher = new TurkishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 6 ); @@ -237,9 +268,12 @@ describe( "An assessment for sentence length", function() { it( "returns the score for 100% long sentences in a language that should count sentence length in characters (Japanese)", function() { const mockPaper = new Paper( "" ); - const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, Factory.buildMockResearcher( [ + const mockResearcher = Factory.buildMockResearcher( [ { sentence: "", sentenceLength: 41 }, - ], false, false, japaneseConfig ) ); + ], false, false, japaneseConfig ); + buildTree( mockPaper, mockResearcher ); + + const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 3 ); @@ -398,10 +432,13 @@ describe( "An assessment for sentence length for cornerstone content", function( it( "returns the score for 25% long sentences in a language that overrides the default cornerstone configuration", function() { const mockPaper = new Paper( longSentenceDefault + shortSentenceDefault.repeat( 3 ) ); + const mockResearcher = new PolishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 20, farTooMany: 25, - }, true ).getResult( mockPaper, new PolishResearcher( mockPaper ) ); + }, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 3 ); @@ -428,10 +465,13 @@ describe( "An assessment for sentence length for cornerstone content", function( it( "returns the score for 25% long sentences using the default cornerstone configuration", function() { const mockPaper = new Paper( longSentenceDefault + shortSentenceDefault.repeat( 3 ) ); + const mockResearcher = new DefaultResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 20, farTooMany: 25, - }, true ).getResult( mockPaper, new DefaultResearcher( mockPaper ) ); + }, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 6 ); @@ -445,10 +485,13 @@ describe( "An assessment for sentence length for cornerstone content", function( describe( "An assessment for sentence length for product pages", function() { it( "returns the score for 100% short sentences in English using the product page configuration", function() { const mockPaper = new Paper( shortSentenceDefault ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 20, farTooMany: 25, - }, false, true ).getResult( mockPaper, new EnglishResearcher( mockPaper ) ); + }, false, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 9 ); @@ -458,10 +501,13 @@ describe( "An assessment for sentence length for product pages", function() { it( "returns the score for 100% long sentences in English using the product page configuration", function() { const mockPaper = new Paper( longSentenceDefault ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 20, farTooMany: 25, - }, false, true ).getResult( mockPaper, new EnglishResearcher( mockPaper ) ); + }, false, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 3 ); @@ -473,10 +519,13 @@ describe( "An assessment for sentence length for product pages", function() { it( "returns the score for 25% long sentences in English using the product page configuration", function() { const mockPaper = new Paper( longSentenceDefault + shortSentenceDefault.repeat( 3 ) ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 20, farTooMany: 25, - }, true ).getResult( mockPaper, new EnglishResearcher( mockPaper ) ); + }, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 6 ); @@ -488,10 +537,13 @@ describe( "An assessment for sentence length for product pages", function() { it( "returns the score for 100% short sentences in English using the cornerstone product page configuration", function() { const mockPaper = new Paper( shortSentenceDefault ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 15, farTooMany: 20, - }, true, true ).getResult( mockPaper, new EnglishResearcher( mockPaper ) ); + }, true, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 9 ); @@ -501,10 +553,13 @@ describe( "An assessment for sentence length for product pages", function() { it( "returns the score for 100% long sentences in English using the cornerstone product page configuration", function() { const mockPaper = new Paper( longSentenceDefault ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 15, farTooMany: 20, - }, true, true ).getResult( mockPaper, new EnglishResearcher( mockPaper ) ); + }, true, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 3 ); @@ -516,10 +571,13 @@ describe( "An assessment for sentence length for product pages", function() { it( "returns the score for 20% long sentences in English using the cornerstone product page configuration", function() { const mockPaper = new Paper( longSentenceDefault + shortSentenceDefault.repeat( 4 ) ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 15, farTooMany: 20, - }, true, true ).getResult( mockPaper, new EnglishResearcher( mockPaper ) ); + }, true, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 6 ); @@ -531,10 +589,13 @@ describe( "An assessment for sentence length for product pages", function() { it( "returns the score for 25% long sentences in English using the cornerstone product page configuration", function() { const mockPaper = new Paper( longSentenceDefault + shortSentenceDefault.repeat( 3 ) ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 15, farTooMany: 20, - }, true, true ).getResult( mockPaper, new EnglishResearcher( mockPaper ) ); + }, true, true ).getResult( mockPaper, mockResearcher ); expect( assessment.hasScore() ).toBe( true ); expect( assessment.getScore() ).toEqual( 3 ); @@ -547,15 +608,23 @@ describe( "An assessment for sentence length for product pages", function() { describe( "A test for marking too long sentences", function() { it( "returns markers for too long sentences", function() { - const paper = new Paper( "This is a too long sentence, because it has over twenty words, and that is hard too read, don't you think?" ); - const sentenceLengthInText = Factory.buildMockResearcher( [ { sentence: "This is a too long sentence, because it has over twenty" + - " words, and that is hard too read, don't you think?", sentenceLength: 21 } ] ); + const mockPaper = new Paper( "This is a too long sentence, because it has over twenty words, and that is hard too read, don't you think?" ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + const expected = [ - new Mark( { original: "This is a too long sentence, because it has over twenty words, and that is hard too read, don't you think?", - marked: "This is a too long sentence, because it has over twenty words, and that is hard too" + - " read, don't you think?" } ), + new Mark( { + position: { + startOffset: 0, + endOffset: 106, + startOffsetBlock: 0, + endOffsetBlock: 106, + attributeId: "", + clientId: "", + isFirstSection: false, + } } ), ]; - expect( new SentenceLengthInTextAssessment().getMarks( paper, sentenceLengthInText ) ).toEqual( expected ); + expect( new SentenceLengthInTextAssessment().getMarks( mockPaper, mockResearcher ) ).toEqual( expected ); } ); it( "returns no markers if no sentences are too long", function() { diff --git a/packages/yoastseo/spec/scoring/helpers/assessments/checkForTooLongSentencesSpec.js b/packages/yoastseo/spec/scoring/helpers/assessments/checkForTooLongSentencesSpec.js deleted file mode 100644 index e6bb9eff4b1..00000000000 --- a/packages/yoastseo/spec/scoring/helpers/assessments/checkForTooLongSentencesSpec.js +++ /dev/null @@ -1,50 +0,0 @@ -import checkForTooLongSentences from "../../../../src/scoring/helpers/assessments/checkForTooLongSentences.js"; - -describe( "Checks if sentences are too long", function() { - it( "Returns no sentences, none are too long", function() { - var sentences = - [ - { sentence: "", sentenceLength: 32 }, - { sentence: "", sentenceLength: 64 }, - { sentence: "", sentenceLength: 128 }, - ]; - var recommendedValue = 256; - expect( checkForTooLongSentences( sentences, recommendedValue ) ).toEqual( [ ] ); - } ); - it( "Returns all sentences, all are too long", function() { - var sentences = - [ - { sentence: "", sentenceLength: 32 }, - { sentence: "", sentenceLength: 64 }, - { sentence: "", sentenceLength: 128 }, - ]; - var recommendedValue = 16; - expect( checkForTooLongSentences( sentences, recommendedValue ) ).toEqual( sentences ); - } ); - it( "Returns 2 sentences that exceed the recommended value", function() { - var sentences = - [ - { sentence: "", sentenceLength: 32 }, - { sentence: "", sentenceLength: 64 }, - { sentence: "", sentenceLength: 128 }, - { sentence: "", sentenceLength: 256 }, - ]; - var recommendedValue = 96; - var expectedOutput = - [ - { sentence: "", sentenceLength: 128 }, - { sentence: "", sentenceLength: 256 }, - ]; - expect( checkForTooLongSentences( sentences, recommendedValue ) ).toEqual( expectedOutput ); - } ); - it( "Returns no sentences, since they are the exact allowed length.", function() { - var sentences = - [ - { sentence: "", sentenceLength: 64 }, - { sentence: "", sentenceLength: 64 }, - { sentence: "", sentenceLength: 64 }, - ]; - var recommendedValue = 64; - expect( checkForTooLongSentences( sentences, recommendedValue ) ).toEqual( [ ] ); - } ); -} ); diff --git a/packages/yoastseo/src/languageProcessing/helpers/sentence/sentencesLength.js b/packages/yoastseo/src/languageProcessing/helpers/sentence/sentencesLength.js index 382d94e5411..e6a33d33bd8 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/sentence/sentencesLength.js +++ b/packages/yoastseo/src/languageProcessing/helpers/sentence/sentencesLength.js @@ -1,31 +1,30 @@ -import wordCount from "../word/countWords.js"; -import { forEach } from "lodash"; -import { stripFullTags as stripHTMLTags } from "../sanitize/stripHTMLTags.js"; +import { getWordsFromTokens } from "../word/getAllWordsFromTree"; + +/** + * @typedef {Object} SentenceLength + * @property {Sentence} sentence The sentence. + * @property {number} sentenceLength The length of the sentence. + */ /** * Returns an array with the length of each sentence. * - * @param {Array} sentences Array with sentences from text. + * @param {Sentence[]} sentences Array with sentences from text. * @param {Researcher} researcher The researcher to use for analysis. * - * @returns {Array} Array with the length of each sentence. + * @returns {SentenceLength[]} Array with the length of each sentence. */ export default function( sentences, researcher ) { const sentencesWordCount = []; - forEach( sentences, function( sentence ) { - // For counting words we want to omit the HTMLtags. - const strippedSentence = stripHTMLTags( sentence ); - // A helper to count characters for languages that don't count number of words for text length. - const countCharacters = researcher.getHelper( "customCountLength" ); - const length = countCharacters ? countCharacters( strippedSentence ) : wordCount( strippedSentence ); - if ( length <= 0 ) { - return; + sentences.forEach( sentence => { + const customLengthHelper = researcher.getHelper( "customCountLength" ); + const length = customLengthHelper ? customLengthHelper( sentence.text ) : getWordsFromTokens( sentence.tokens ).length; + if ( length > 0 ) { + sentencesWordCount.push( { + sentence: sentence, + sentenceLength: length, + } ); } - - sentencesWordCount.push( { - sentence: sentence, - sentenceLength: length, - } ); } ); return sentencesWordCount; } diff --git a/packages/yoastseo/src/languageProcessing/helpers/word/getAllWordsFromTree.js b/packages/yoastseo/src/languageProcessing/helpers/word/getAllWordsFromTree.js index 7266af95299..b0f3429a1e2 100644 --- a/packages/yoastseo/src/languageProcessing/helpers/word/getAllWordsFromTree.js +++ b/packages/yoastseo/src/languageProcessing/helpers/word/getAllWordsFromTree.js @@ -2,22 +2,33 @@ import getSentencesFromTree from "../sentence/getSentencesFromTree"; import { flatMap } from "lodash"; import removePunctuation from "../sanitize/removePunctuation"; +/** + * Gets the words from the tokens. + * + * @param {Token[]} tokens The tokens to get the words from. + * + * @returns {string[]} Array of words retrieved from the tokens. + */ +export function getWordsFromTokens( tokens ) { + // Retrieve all texts from the tokens. + let words = tokens.map( token => token.text ); + // Remove punctuation and spaces. + words = words.map( token => removePunctuation( token ) ); + // Filter out empty tokens. + return words.filter( word => word.trim() !== "" ); +} + /** * Gets the words from the tree, i.e. from the paragraph and heading nodes. * These two node types are the nodes that should contain words for the analysis. * * @param {Paper} paper The paper to get the tree and words from. * - * @returns {String[]} Array of words retrieved from the tree. + * @returns {string[]} Array of words retrieved from the tree. */ export default function( paper ) { const sentences = getSentencesFromTree( paper ); // Get all the tokens from each sentence. - const tokens = sentences.map( sentence => sentence.tokens ); - let words = flatMap( tokens ).map( token => token.text ); - // Remove punctuation and spaces. - words = words.map( token => removePunctuation( token ) ); - - // Filter out empty tokens. - return words.filter( word => word.trim() !== "" ); + const tokens = flatMap( sentences.map( sentence => sentence.tokens ) ); + return getWordsFromTokens( tokens ); } diff --git a/packages/yoastseo/src/languageProcessing/researches/countSentencesFromText.js b/packages/yoastseo/src/languageProcessing/researches/countSentencesFromText.js index 25932359050..78f87ee31ee 100644 --- a/packages/yoastseo/src/languageProcessing/researches/countSentencesFromText.js +++ b/packages/yoastseo/src/languageProcessing/researches/countSentencesFromText.js @@ -1,19 +1,13 @@ -import getSentences from "../helpers/sentence/getSentences"; import sentencesLength from "../helpers/sentence/sentencesLength.js"; -import removeHtmlBlocks from "../helpers/html/htmlParser"; -import { filterShortcodesFromHTML } from "../helpers"; +import getSentencesFromTree from "../helpers/sentence/getSentencesFromTree"; /** * Count sentences in the text. * @param {Paper} paper The Paper object to get text from. * @param {Researcher} researcher The researcher to use for analysis. - * @returns {Array} The sentences from the text. + * @returns {SentenceLength[]} The sentences from the text. */ export default function( paper, researcher ) { - const memoizedTokenizer = researcher.getHelper( "memoizedTokenizer" ); - let text = paper.getText(); - text = removeHtmlBlocks( text ); - text = filterShortcodesFromHTML( text, paper._attributes && paper._attributes.shortcodes ); - const sentences = getSentences( text, memoizedTokenizer ); + const sentences = getSentencesFromTree( paper ); return sentencesLength( sentences, researcher ); } diff --git a/packages/yoastseo/src/scoring/assessments/readability/SentenceLengthInTextAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/SentenceLengthInTextAssessment.js index 155bbce76eb..9c08b32f382 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/SentenceLengthInTextAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/SentenceLengthInTextAssessment.js @@ -1,13 +1,10 @@ import { __, sprintf } from "@wordpress/i18n"; -import { map, merge } from "lodash"; +import { merge } from "lodash"; import Assessment from "../assessment"; -import getTooLongSentences from "../../helpers/assessments/checkForTooLongSentences"; import formatNumber from "../../../helpers/formatNumber"; import { inRangeEndInclusive as inRange } from "../../helpers/assessments/inRange"; -import addMark from "../../../markers/addMark"; -import { createAnchorOpeningTag } from "../../../helpers/shortlinker"; -import { stripIncompleteTags as stripTags } from "../../../languageProcessing/helpers/sanitize/stripHTMLTags"; +import { createAnchorOpeningTag } from "../../../helpers"; import AssessmentResult from "../../../values/AssessmentResult"; import Mark from "../../../values/Mark"; @@ -70,7 +67,7 @@ class SentenceLengthInTextAssessment extends Assessment { assessmentResult.setScore( score ); assessmentResult.setText( this.translateScore( score, percentage ) ); - assessmentResult.setHasMarks( ( percentage > 0 ) ); + assessmentResult.setHasMarks( percentage > 0 ); return assessmentResult; } @@ -99,13 +96,22 @@ class SentenceLengthInTextAssessment extends Assessment { if ( researcher.getConfig( "sentenceLength" ) ) { this._config = this.getLanguageSpecificConfig( researcher ); } - const sentenceObjects = this.getTooLongSentences( sentenceCount ); + const tooLongSentences = this.getTooLongSentences( sentenceCount ); - return map( sentenceObjects, function( sentenceObject ) { - const sentence = stripTags( sentenceObject.sentence ); + return tooLongSentences.map( tooLongSentence => { + const sentence = tooLongSentence.sentence; + const startOffset = sentence.sourceCodeRange.startOffset; + const endOffset = sentence.sourceCodeRange.endOffset; return new Mark( { - original: sentence, - marked: addMark( sentence ), + position: { + startOffset, + endOffset, + startOffsetBlock: startOffset - ( sentence.parentStartOffset || 0 ), + endOffsetBlock: endOffset - ( sentence.parentStartOffset || 0 ), + clientId: sentence.parentClientId || "", + attributeId: sentence.parentAttributeId || "", + isFirstSection: sentence.isParentFirstSectionOfBlock || false, + }, } ); } ); } @@ -179,14 +185,14 @@ class SentenceLengthInTextAssessment extends Assessment { /** * Calculates the percentage of sentences that are too long. * - * @param {Array} sentences The sentences to calculate the percentage for. + * @param {SentenceLength[]} sentences The sentences to calculate the percentage for. * @returns {number} The calculates percentage of too long sentences. */ calculatePercentage( sentences ) { let percentage = 0; if ( sentences.length !== 0 ) { - const tooLongTotal = this.countTooLongSentences( sentences ); + const tooLongTotal = this.getTooLongSentences( sentences ).length; percentage = formatNumber( ( tooLongTotal / sentences.length ) * 100 ); } @@ -222,23 +228,12 @@ class SentenceLengthInTextAssessment extends Assessment { } /** - * Gets the sentences that are qualified as being too long. - * - * @param {array} sentences The sentences to filter through. - * @returns {array} Array with all the sentences considered to be too long. + * Returns the sentences that are qualified as being too long. + * @param {SentenceLength[]} sentences The sentences to filter. + * @returns {SentenceLength[]} Array with all the sentences considered to be too long. */ getTooLongSentences( sentences ) { - return getTooLongSentences( sentences, this._config.recommendedLength ); - } - - /** - * Get the total amount of sentences that are qualified as being too long. - * - * @param {Array} sentences The sentences to filter through. - * @returns {Number} The amount of sentences that are considered too long. - */ - countTooLongSentences( sentences ) { - return this.getTooLongSentences( sentences ).length; + return sentences.filter( sentence => sentence.sentenceLength > this._config.recommendedLength ); } } diff --git a/packages/yoastseo/src/scoring/helpers/assessments/checkForTooLongSentences.js b/packages/yoastseo/src/scoring/helpers/assessments/checkForTooLongSentences.js deleted file mode 100644 index 088ba70fe39..00000000000 --- a/packages/yoastseo/src/scoring/helpers/assessments/checkForTooLongSentences.js +++ /dev/null @@ -1,13 +0,0 @@ -import { filter } from "lodash"; - -/** - * Checks for too long sentences. - * @param {array} sentences The array with objects containing sentences and their lengths. - * @param {number} recommendedValue The recommended maximum length of sentence. - * @returns {array} The array with objects containing too long sentences and their lengths. - */ -export default function( sentences, recommendedValue ) { - return filter( sentences, function( sentence ) { - return sentence.sentenceLength > recommendedValue; - } ); -} From 684baabd9e7f577bb7c518b6c221c51c9cd8b242 Mon Sep 17 00:00:00 2001 From: Martijn van der Klis Date: Wed, 13 Nov 2024 12:59:38 +0100 Subject: [PATCH 02/92] Adds a temporary output script and (a currently failing) unit test --- .../spec/fullTextTests/runFullTextTests.js | 29 +++++++++++++++++++ .../helpers/sentence/sentencesLengthSpec.js | 14 +++++++++ 2 files changed, 43 insertions(+) diff --git a/packages/yoastseo/spec/fullTextTests/runFullTextTests.js b/packages/yoastseo/spec/fullTextTests/runFullTextTests.js index f43f128c4ce..5bb6cf426dc 100644 --- a/packages/yoastseo/spec/fullTextTests/runFullTextTests.js +++ b/packages/yoastseo/spec/fullTextTests/runFullTextTests.js @@ -43,6 +43,7 @@ import { getLanguagesWithWordComplexity } from "../../src/helpers"; // Import test papers. import testPapers from "./testTexts"; +import fs from "fs"; testPapers.forEach( function( testPaper ) { // eslint-disable-next-line max-statements @@ -65,6 +66,34 @@ testPapers.forEach( function( testPaper ) { buildTree( paper, researcher ); + /** + * Writes the given contents to the given filename in the temporary directory tmp + * @param {string} filename The name of the file. + * @param {string} content The content of the file. + * @returns {void} + */ + const writeToTempFile = ( filename, content ) => { + // Creates a temporary directory in the current working directory to store the data, if it not yet exists. + // (i.e., packages/yoastseo/tmp/ if this function is called from packages/yoastseo/) + const dir = "tmp/"; + if ( ! fs.existsSync( dir ) ) { + fs.mkdirSync( dir ); + } + + // Writes the data to this temporary directory + fs.writeFileSync( dir + filename, content ); + }; + + // Collects the results and the header into list of ;-separated rows + const sentences = researcher.getResearch( "countSentencesFromText" ); + const resultLines = sentences.map( sentence => sentence.sentence.trimStart().split( " " )[ 0 ] + ";" + sentence.sentenceLength ); + + // Set doExport to true to write the results to a temporary file. + const doExport = true; + if ( doExport ) { + writeToTempFile( testPaper.name + ".csv", resultLines.join( "\n" ) ); + } + const expectedResults = testPaper.expectedResults; /** diff --git a/packages/yoastseo/spec/languageProcessing/helpers/sentence/sentencesLengthSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/sentence/sentencesLengthSpec.js index 5495caa60f8..aa8761cf6df 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/sentence/sentencesLengthSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/sentence/sentencesLengthSpec.js @@ -33,6 +33,20 @@ describe( "A test to count sentence lengths.", function() { expect( sentenceLengths[ 1 ].sentence.text ).toEqual( "this is a string" ); } ); + it( "should return the correct length for sentences containing hyphens", function() { + const mockPaper = new Paper( + "

My know-it-all mother-in-law made a state-of-the-art U-turn.

" + + "

Her ex-husband found that low-key amazing.

" ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const sentenceLengths = sentencesLength( getSentencesFromTree( mockPaper ), mockResearcher ); + + expect( sentenceLengths.length ).toEqual( 2 ); + expect( sentenceLengths[ 0 ].sentenceLength ).toEqual( 7 ); + expect( sentenceLengths[ 1 ].sentenceLength ).toEqual( 6 ); + } ); + it( "should return the sentences and their length for Japanese (so counting characters)", function() { const mockPaper = new Paper( "

自然おのずから存在しているもの

" + "

歩くさわやかな森 自然

" ); From e338b83c2588d333a9d0f1ba284152a196d4e123 Mon Sep 17 00:00:00 2001 From: Martijn van der Klis Date: Thu, 14 Nov 2024 09:00:21 +0100 Subject: [PATCH 03/92] First pass on converting the paragraph length assessment to use the HTML Parser --- .../helpers/html/matchParagraphsSpec.js | 42 ----- .../languages/ar/ResearcherSpec.js | 7 +- .../researches/getParagraphLengthSpec.js | 172 ++++++++++++++---- .../ParagraphTooLongAssessmentSpec.js | 93 +++++----- .../helpers/html/matchParagraphs.js | 62 ------- .../researches/getParagraphLength.js | 52 +++--- .../readability/ParagraphTooLongAssessment.js | 137 ++++++-------- 7 files changed, 272 insertions(+), 293 deletions(-) delete mode 100644 packages/yoastseo/spec/languageProcessing/helpers/html/matchParagraphsSpec.js delete mode 100644 packages/yoastseo/src/languageProcessing/helpers/html/matchParagraphs.js diff --git a/packages/yoastseo/spec/languageProcessing/helpers/html/matchParagraphsSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/html/matchParagraphsSpec.js deleted file mode 100644 index 52b14a1b13d..00000000000 --- a/packages/yoastseo/spec/languageProcessing/helpers/html/matchParagraphsSpec.js +++ /dev/null @@ -1,42 +0,0 @@ -import matchParagraphs from "../../../../src/languageProcessing/helpers/html/matchParagraphs.js"; - -describe( "Matches paragraphs in a text", function() { - it( "returns an array of paragraphs in

tags", function() { - const text = "

This is a text in p-tags

This is more text in p-tags

"; - expect( matchParagraphs( text ) ).toContain( "This is a text in p-tags" ); - } ); - - it( "returns an array of paragraphs from double linebreaks", function() { - const text = "This is a text\n\nwith double linebreaks"; - expect( matchParagraphs( text ) ).toContain( "This is a text" ); - expect( matchParagraphs( text ) ).toContain( "with double linebreaks" ); - } ); - - it( "returns the complete text if no paragraphs or linebreaks are found", function() { - const text = "This is a text without any paragraphs"; - expect( matchParagraphs( text ) ).toContain( "This is a text without any paragraphs" ); - } ); - - it( "returns empty string if there is no text", function() { - const text = ""; - expect( matchParagraphs( text ) ).toContain( "" ); - } ); - - it( "splits on headings", function() { - const text = "A piece of text

More piece of text

Another piece of text."; - const expected = [ "A piece of text", "Another piece of text." ]; - - const actual = matchParagraphs( text ); - - expect( actual ).toEqual( expected ); - } ); - - it( "should see
tags as paragraphs", function() { - const text = "A piece of text
More piece of text
Another piece of text."; - const expected = [ "A piece of text", "
More piece of text
", "Another piece of text." ]; - - const actual = matchParagraphs( text ); - - expect( actual ).toEqual( expected ); - } ); -} ); diff --git a/packages/yoastseo/spec/languageProcessing/languages/ar/ResearcherSpec.js b/packages/yoastseo/spec/languageProcessing/languages/ar/ResearcherSpec.js index ada24ba85ff..32310196451 100644 --- a/packages/yoastseo/spec/languageProcessing/languages/ar/ResearcherSpec.js +++ b/packages/yoastseo/spec/languageProcessing/languages/ar/ResearcherSpec.js @@ -1,6 +1,7 @@ import Researcher from "../../../../src/languageProcessing/languages/ar/Researcher.js"; import Paper from "../../../../src/values/Paper.js"; import getMorphologyData from "../../../specHelpers/getMorphologyData"; +import buildTree from "../../../specHelpers/parse/buildTree"; import functionWords from "../../../../src/languageProcessing/languages/ar/config/functionWords"; import transitionWords from "../../../../src/languageProcessing/languages/ar/config/transitionWords"; import firstWordExceptions from "../../../../src/languageProcessing/languages/ar/config/firstWordExceptions"; @@ -9,10 +10,12 @@ import twoPartTransitionWords from "../../../../src/languageProcessing/languages const morphologyDataAR = getMorphologyData( "ar" ); describe( "a test for Arabic Researcher", function() { - const researcher = new Researcher( new Paper( "This is another paper!" ) ); + const paper = new Paper( "This is another paper!" ); + const researcher = new Researcher( paper ); + buildTree( paper, researcher ); it( "checks if the Arabic Researcher still inherit the Abstract Researcher", function() { - expect( researcher.getResearch( "getParagraphLength" ) ).toEqual( [ { text: "This is another paper!", countLength: 4 } ] ); + expect( researcher.getResearch( "getParagraphLength" )[ 0 ].paragraphLength ).toEqual( 4 ); } ); it( "returns false if the default research is deleted in Arabic Researcher", function() { diff --git a/packages/yoastseo/spec/languageProcessing/researches/getParagraphLengthSpec.js b/packages/yoastseo/spec/languageProcessing/researches/getParagraphLengthSpec.js index 858b85c4259..af6d54b607d 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/getParagraphLengthSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/getParagraphLengthSpec.js @@ -2,109 +2,204 @@ import getParagraphLength from "../../../src/languageProcessing/researches/getPa import Paper from "../../../src/values/Paper.js"; import JapaneseResearcher from "../../../src/languageProcessing/languages/ja/Researcher.js"; import EnglishResearcher from "../../../src/languageProcessing/languages/en/Researcher.js"; +import buildTree from "../../specHelpers/parse/buildTree"; describe( "a test for getting paragraph length", function() { it( "returns the paragraph length of a paragraph between p tags", function() { const mockPaper = new Paper( "

Lorem ipsum

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 0 ].countLength ).toBe( 2 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 2 ); } ); it( "returns the paragraph length of a paragraph in Japanese between p tags", function() { const mockPaper = new Paper( "

これに対し日本国有鉄道

" ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 0 ].countLength ).toBe( 11 ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 11 ); } ); it( "returns the paragraph length of two paragraphs divided by double linebreaks and ends with a double linebreak", function() { const mockPaper = new Paper( "Lorem \n\n ipsum two \n\n" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 0 ].countLength ).toBe( 1 ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 1 ].countLength ).toBe( 2 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 1 ); + expect( paragraphLengths[ 1 ].paragraphLength ).toBe( 2 ); } ); it( "returns the paragraph length of two paragraphs in Japanese divided by double linebreaks and ends with a double linebreak", function() { const mockPaper = new Paper( "1964年 \n\n (昭和39年) \n\n" ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 0 ].countLength ).toBe( 5 ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 1 ].countLength ).toBe( 7 ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 5 ); + expect( paragraphLengths[ 1 ].paragraphLength ).toBe( 7 ); } ); it( "returns the paragraph length of two paragraphs divided by double linebreaks that don't end with a double linebreak", function() { const mockPaper = new Paper( "Lorem \n\n ipsum two" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 0 ].countLength ).toBe( 1 ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 1 ].countLength ).toBe( 2 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 1 ); + expect( paragraphLengths[ 1 ].paragraphLength ).toBe( 2 ); } ); it( "returns the paragraph length of two paragraphs in Japanese divided by double linebreaks that don't end with a double linebreak", function() { const mockPaper = new Paper( "1964年 \n\n (昭和39年)" ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 0 ].countLength ).toBe( 5 ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 1 ].countLength ).toBe( 7 ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 5 ); + expect( paragraphLengths[ 1 ].paragraphLength ).toBe( 7 ); } ); it( "returns the paragraph length of a paragraph without tags or double linebreaks", function() { const mockPaper = new Paper( "Lorem ipsum dolor sit amet" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 0 ].countLength ).toBe( 5 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 5 ); } ); it( "returns the paragraph length of a paragraph in Japanese without tags or double linebreaks", function() { const mockPaper = new Paper( "東京オリンピック開会直前の1964年(昭和39年)10月1日に開業した。" ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 0 ].countLength ).toBe( 36 ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 36 ); } ); it( "returns the paragraph length of 2 paragraphs, both between p tags", function() { const mockPaper = new Paper( "

Lorem ipsum

dolor sit amet

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 0 ].countLength ).toBe( 2 ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 1 ].countLength ).toBe( 3 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 2 ); + expect( paragraphLengths[ 1 ].paragraphLength ).toBe( 3 ); } ); it( "returns the paragraph length of 2 paragraphs in Japanese, both between p tags", function() { const mockPaper = new Paper( "

東京オリンピック開会直前の1964年

(昭和39年)10月1日に開業した。

" ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 0 ].countLength ).toBe( 18 ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 1 ].countLength ).toBe( 18 ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 18 ); + expect( paragraphLengths[ 1 ].paragraphLength ).toBe( 18 ); } ); it( "returns the paragraph length of 2 paragraphs, both between p tags, divided by double linebreaks", function() { const mockPaper = new Paper( "

Lorem ipsum

\n\n

dolor sit amet

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 0 ].countLength ).toBe( 2 ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 1 ].countLength ).toBe( 3 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 2 ); + expect( paragraphLengths[ 1 ].paragraphLength ).toBe( 3 ); } ); it( "returns the paragraph length of 2 paragraphs in Japanese, both between p tags, divided by double linebreaks", function() { const mockPaper = new Paper( "

東京オリンピック開会直前の1964年

\n\n

(昭和39年)10月1日に開業した。

" ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 0 ].countLength ).toBe( 18 ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 1 ].countLength ).toBe( 18 ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 18 ); + expect( paragraphLengths[ 1 ].paragraphLength ).toBe( 18 ); } ); it( "returns the paragraph length, with empty paragraphs", function() { const mockPaper = new Paper( "

test

more text

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() ).length ).toBe( 2 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths.length ).toBe( 2 ); } ); it( "returns the paragraph length, ignoring text inside an element we want to exclude from the analysis", function() { const mockPaper = new Paper( "

test ignore me

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() ).length ).toBe( 1 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths.length ).toBe( 1 ); } ); it( "returns the paragraph length, ignoring shortcodes", function() { const mockPaper = new Paper( "

test [shortcode]

", { shortcodes: [ "shortcode" ] } ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() ).length ).toBe( 1 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths.length ).toBe( 1 ); } ); it( "returns the paragraph length of paragraph without p tags or double linebreaks, but with h2 tags", function() { const mockPaper = new Paper( "

Lorem ipsum dolor sit amet

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() )[ 0 ].countLength ).toBe( 5 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 5 ); } ); it( "returns the paragraph length of paragraph in Japanese without p tags or double linebreaks, but with h2 tags", function() { const mockPaper = new Paper( "

(昭和39年)10月1日に開業した。

" ); - expect( getParagraphLength( mockPaper, new JapaneseResearcher() )[ 0 ].countLength ).toBe( 18 ); + const mockResearcher = new JapaneseResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 18 ); } ); xit( "returns the paragraph length of an empty paragraph with p tags", function() { const mockPaper = new Paper( "

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() ).countLength ).not.toContain( 0 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths.paragraphLength ).not.toContain( 0 ); } ); xit( "returns the paragraph length of an empty paragraph without p tags or double line breaks", function() { const mockPaper = new Paper( "" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher() ).countLength ).not.toContain( 0 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths.paragraphLength ).not.toContain( 0 ); } ); } ); @@ -112,17 +207,32 @@ describe( "a test for getting paragraph length of a text with image(s)", () => { it( "should not count a paragraph containing only an image", function() { // The paper contains 3 paragraphs: 2 paragraphs with text and one paragraph with only an image. const mockPaper = new Paper( "

test

more text

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher( mockPaper ) ).length ).toBe( 2 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths.length ).toBe( 2 ); } ); it( "should return 0 for paragraphs count when all paragraphs only contain images", function() { const mockPaper = new Paper( "

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher( mockPaper ) ).length ).toBe( 0 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths.length ).toBe( 0 ); } ); it( "should not include the image in the paragraph length calculation", function() { const mockPaper = new Paper( "

test

test

" ); - expect( getParagraphLength( mockPaper, new EnglishResearcher( mockPaper ) ).length ).toBe( 2 ); - expect( getParagraphLength( mockPaper, new EnglishResearcher( mockPaper ) )[ 0 ].countLength ).toBe( 1 ); + const mockResearcher = new EnglishResearcher( mockPaper ); + buildTree( mockPaper, mockResearcher ); + + const paragraphLengths = getParagraphLength( mockPaper, mockResearcher ); + + expect( paragraphLengths.length ).toBe( 2 ); + expect( paragraphLengths[ 0 ].paragraphLength ).toBe( 1 ); } ); } ); diff --git a/packages/yoastseo/spec/scoring/assessments/readability/ParagraphTooLongAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/readability/ParagraphTooLongAssessmentSpec.js index 3b8144c45c8..753bca7a923 100644 --- a/packages/yoastseo/spec/scoring/assessments/readability/ParagraphTooLongAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/readability/ParagraphTooLongAssessmentSpec.js @@ -5,6 +5,7 @@ import Factory from "../../../../src/helpers/factory.js"; import EnglishResearcher from "../../../../src/languageProcessing/languages/en/Researcher"; import JapaneseResearcher from "../../../../src/languageProcessing/languages/ja/Researcher"; import paragraphLengthJapanese from "../../../../src/languageProcessing/languages/ja/config/paragraphLength"; +import buildTree from "../../../specHelpers/parse/buildTree"; const paragraphTooLongAssessment = new ParagraphTooLongAssessment(); const shortTextJapanese = "は".repeat( 300 ); @@ -14,14 +15,14 @@ const veryLongTextJapanese = "は".repeat( 410 ); describe( "An assessment for scoring too long paragraphs.", function() { const paper = new Paper( "" ); it( "should score 1 paragraph with ok length", function() { - const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { countLength: 60, text: "" } ] ) ); + const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { paragraphLength: 60 } ] ) ); expect( assessment.getScore() ).toBe( 9 ); expect( assessment.getText() ).toBe( "Paragraph length: None of the paragraphs" + " are too long. Great job!" ); expect( assessment.hasMarks() ).toBe( false ); } ); it( "should score 1 slightly too long paragraph", function() { - const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { countLength: 160, text: "" } ] ) ); + const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { paragraphLength: 160 } ] ) ); expect( assessment.getScore() ).toBe( 6 ); expect( assessment.getText() ).toBe( "Paragraph length: 1 of the paragraphs" + " contains more than the recommended maximum of 150 words." + @@ -29,7 +30,7 @@ describe( "An assessment for scoring too long paragraphs.", function() { expect( assessment.hasMarks() ).toBe( true ); } ); it( "should score 1 extremely long paragraph", function() { - const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { countLength: 6000, text: "" } ] ) ); + const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { paragraphLength: 6000 } ] ) ); expect( assessment.getScore() ).toBe( 3 ); expect( assessment.getText() ).toBe( "Paragraph length: 1 of the paragraphs" + " contains more than the recommended maximum of 150 words." + @@ -37,16 +38,16 @@ describe( "An assessment for scoring too long paragraphs.", function() { expect( assessment.hasMarks() ).toBe( true ); } ); it( "should score 3 paragraphs with ok length", function() { - const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { countLength: 60, text: "" }, - { countLength: 71, text: "" }, { countLength: 83, text: "" } ] ) ); + const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { paragraphLength: 60 }, + { paragraphLength: 71 }, { paragraphLength: 83 } ] ) ); expect( assessment.getScore() ).toBe( 9 ); expect( assessment.getText() ).toBe( "Paragraph length: None of the paragraphs" + " are too long. Great job!" ); expect( assessment.hasMarks() ).toBe( false ); } ); it( "should score 3 paragraphs, one of which is too long", function() { - const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { countLength: 60, text: "" }, - { countLength: 71, text: "" }, { countLength: 183, text: "" } ] ) ); + const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { paragraphLength: 60 }, + { paragraphLength: 71 }, { paragraphLength: 183 } ] ) ); expect( assessment.getScore() ).toBe( 6 ); expect( assessment.getText() ).toBe( "Paragraph length: 1 of the paragraphs" + " contains more than the recommended maximum of 150 words." + @@ -54,8 +55,8 @@ describe( "An assessment for scoring too long paragraphs.", function() { expect( assessment.hasMarks() ).toBe( true ); } ); it( "should score 3 paragraphs, two of which are too long", function() { - const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { countLength: 60, text: "" }, - { countLength: 191, text: "" }, { countLength: 183, text: "" } ] ) ); + const assessment = paragraphTooLongAssessment.getResult( paper, Factory.buildMockResearcher( [ { paragraphLength: 60 }, + { paragraphLength: 191 }, { paragraphLength: 183 } ] ) ); expect( assessment.getScore() ).toBe( 6 ); expect( assessment.getText() ).toBe( "Paragraph length: 2 of the paragraphs" + " contain more than the recommended maximum of 150 words." + @@ -73,8 +74,11 @@ describe( "An assessment for scoring too long paragraphs in Japanese in which ch "in the calculation instead of word length", function() { it( "should score 1 slightly too long paragraph", function() { const paper = new Paper( longTextJapanese ); + const japaneseResearcher = new JapaneseResearcher( paper ); + buildTree( paper, japaneseResearcher ); + + const assessment = paragraphTooLongAssessment.getResult( paper, japaneseResearcher ); - const assessment = paragraphTooLongAssessment.getResult( paper, new JapaneseResearcher( paper ) ); expect( assessment.getScore() ).toBe( 6 ); expect( assessment.getText() ).toBe( "Paragraph length: 1 of the paragraphs" + " contains more than the recommended maximum of 300 characters." + @@ -83,8 +87,11 @@ describe( "An assessment for scoring too long paragraphs in Japanese in which ch } ); it( "should score 1 too long paragraph", function() { const paper = new Paper( veryLongTextJapanese ); + const japaneseResearcher = new JapaneseResearcher( paper ); + buildTree( paper, japaneseResearcher ); + + const assessment = paragraphTooLongAssessment.getResult( paper, japaneseResearcher ); - const assessment = paragraphTooLongAssessment.getResult( paper, new JapaneseResearcher( paper ) ); expect( assessment.getScore() ).toBe( 3 ); expect( assessment.getText() ).toBe( "Paragraph length: 1 of the paragraphs" + " contains more than the recommended maximum of 300 characters." + @@ -93,7 +100,11 @@ describe( "An assessment for scoring too long paragraphs in Japanese in which ch } ); it( "should score 2 slightly too long paragraphs", function() { const paper = new Paper( `${shortTextJapanese}

${longTextJapanese}

${longTextJapanese}

` ); - const assessment = paragraphTooLongAssessment.getResult( paper, new JapaneseResearcher( paper ) ); + const japaneseResearcher = new JapaneseResearcher( paper ); + buildTree( paper, japaneseResearcher ); + + const assessment = paragraphTooLongAssessment.getResult( paper, japaneseResearcher ); + expect( assessment.getScore() ).toBe( 6 ); expect( assessment.getText() ).toBe( "Paragraph length: 2 of the paragraphs" + " contain more than the recommended maximum of 300 characters." + @@ -310,8 +321,8 @@ describe( "A test for marking the sentences", function() { } ); it( "should return no markers when no paragraph is too long", function() { const paper = new Paper( "This is a very interesting paper." ); - const paragraphTooLong = Factory.buildMockResearcher( [ { countLength: 60, text: "" }, { countLength: 11, text: "" }, - { countLength: 13, text: "" } ] ); + const paragraphTooLong = Factory.buildMockResearcher( [ { paragraphLength: 60 }, { paragraphLength: 11 }, + { paragraphLength: 13 } ] ); const expected = []; expect( paragraphTooLongAssessment.getMarks( paper, paragraphTooLong ) ).toEqual( expected ); } ); @@ -327,9 +338,9 @@ describe( "test for paragraph too long assessment when is used in product page a }, }; const result = new ParagraphTooLongAssessment( config ).getResult( paper, Factory.buildMockResearcher( [ - { countLength: 60, text: "" }, - { countLength: 11, text: "" }, - { countLength: 13, text: "" }, + { paragraphLength: 60 }, + { paragraphLength: 11 }, + { paragraphLength: 13 }, ] ) ); expect( result.getScore() ).toEqual( 9 ); expect( result.getText() ).toEqual( "Paragraph length: " + @@ -344,9 +355,9 @@ describe( "test for paragraph too long assessment when is used in product page a }, }; const result = new ParagraphTooLongAssessment( config ).getResult( paper, Factory.buildMockResearcher( [ - { countLength: 110, text: "" }, - { countLength: 150, text: "" }, - { countLength: 150, text: "" }, + { paragraphLength: 110 }, + { paragraphLength: 150 }, + { paragraphLength: 150 }, ] ) ); expect( result.getScore() ).toEqual( 3 ); expect( result.getText() ).toEqual( "Paragraph length: 3 of the paragraphs contain" + @@ -361,9 +372,9 @@ describe( "test for paragraph too long assessment when is used in product page a }, }; const result = new ParagraphTooLongAssessment( config ).getResult( paper, Factory.buildMockResearcher( [ - { countLength: 90, text: "" }, - { countLength: 75, text: "" }, - { countLength: 80, text: "" }, + { paragraphLength: 90 }, + { paragraphLength: 75 }, + { paragraphLength: 80 }, ] ) ); expect( result.getScore() ).toEqual( 6 ); expect( result.getText() ).toEqual( "Paragraph length: 3 of the paragraphs contain " + @@ -377,9 +388,9 @@ describe( "test for paragraph too long assessment for languages that have langua it( "should assess a paper with paragraphs that contain less than 300 characters (green bullet)", function() { const paper = new Paper( "" ); const mockResearcher = Factory.buildMockResearcher( [ - { countLength: 200, text: "" }, - { countLength: 260, text: "" }, - { countLength: 100, text: "" }, + { paragraphLength: 200 }, + { paragraphLength: 260 }, + { paragraphLength: 100 }, ], false, false, @@ -393,9 +404,9 @@ describe( "test for paragraph too long assessment for languages that have langua it( "should assess a paper with two paragraphs that contain more than 400 characters (red bullet)", function() { const paper = new Paper( "" ); const mockResearcher = Factory.buildMockResearcher( [ - { countLength: 400, text: "" }, - { countLength: 300, text: "" }, - { countLength: 500, text: "" }, + { paragraphLength: 400 }, + { paragraphLength: 300 }, + { paragraphLength: 500 }, ], false, false, @@ -409,9 +420,9 @@ describe( "test for paragraph too long assessment for languages that have langua it( "should assess a paper with paragraphs that contain 300-400 characters (orange bullet)", function() { const paper = new Paper( "" ); const mockResearcher = Factory.buildMockResearcher( [ - { countLength: 350, text: "" }, - { countLength: 300, text: "" }, - { countLength: 390, text: "" }, + { paragraphLength: 350 }, + { paragraphLength: 300 }, + { paragraphLength: 390 }, ], false, false, @@ -427,9 +438,9 @@ describe( "test for paragraph too long assessment for languages that have langua it( "should assess a paper with paragraphs that contain less than 140 characters (green bullet)", function() { const paper = new Paper( "" ); const mockResearcher = Factory.buildMockResearcher( [ - { countLength: 100, text: "" }, - { countLength: 120, text: "" }, - { countLength: 90, text: "" }, + { paragraphLength: 100 }, + { paragraphLength: 120 }, + { paragraphLength: 90 }, ], false, false, @@ -443,9 +454,9 @@ describe( "test for paragraph too long assessment for languages that have langua it( "should assess a paper with three paragraphs that contain more than 200 characters (red bullet)", function() { const paper = new Paper( "" ); const mockResearcher = Factory.buildMockResearcher( [ - { countLength: 400, text: "" }, - { countLength: 300, text: "" }, - { countLength: 500, text: "" }, + { paragraphLength: 400 }, + { paragraphLength: 300 }, + { paragraphLength: 500 }, ], false, false, @@ -459,9 +470,9 @@ describe( "test for paragraph too long assessment for languages that have langua it( "should assess a paper with all paragraphs that contain 140-200 characters (orange bullet)", function() { const paper = new Paper( "" ); const mockResearcher = Factory.buildMockResearcher( [ - { countLength: 150, text: "" }, - { countLength: 170, text: "" }, - { countLength: 200, text: "" }, + { paragraphLength: 150 }, + { paragraphLength: 170 }, + { paragraphLength: 200 }, ], false, false, diff --git a/packages/yoastseo/src/languageProcessing/helpers/html/matchParagraphs.js b/packages/yoastseo/src/languageProcessing/helpers/html/matchParagraphs.js deleted file mode 100644 index 08c7ef8ac39..00000000000 --- a/packages/yoastseo/src/languageProcessing/helpers/html/matchParagraphs.js +++ /dev/null @@ -1,62 +0,0 @@ -import { filter, flatMap, map } from "lodash"; - -import { getBlocks } from "./html"; - -/** - * Matches the paragraphs in

-tags and returns the text in them. - * - * @param {string} text The text to match paragraph in. - * - * @returns {array} An array containing all paragraphs texts. - */ -const getParagraphsInTags = function( text ) { - let paragraphs = []; - // Matches everything between the

and

tags. - const regex = /]+)?>(.*?)<\/p>/ig; - let match; - - while ( ( match = regex.exec( text ) ) !== null ) { - paragraphs.push( match ); - } - - // Returns only the text from within the paragraph tags. - paragraphs = map( paragraphs, function( paragraph ) { - return paragraph[ 1 ]; - } ); - - return paragraphs.filter( paragraph => paragraph.length > 0 ); -}; - -/** - * Returns an array with all paragraphs from the text. - * - * @param {string} text The text to match paragraph in. - * - * @returns {Array} The array containing all paragraphs from the text. - */ -export default function( text ) { - let paragraphs = getParagraphsInTags( text ); - - if ( paragraphs.length > 0 ) { - return paragraphs; - } - - // If no

tags found, split on double linebreaks. - let blocks = getBlocks( text ); - - blocks = filter( blocks, function( block ) { - // Match explicit paragraph tags, or if a block has no HTML tags. - return 0 !== block.indexOf( " 0 ) { - return paragraphs; - } - - // If no paragraphs are found, return an array containing the entire text. - return [ text ]; -} diff --git a/packages/yoastseo/src/languageProcessing/researches/getParagraphLength.js b/packages/yoastseo/src/languageProcessing/researches/getParagraphLength.js index 353d71a5648..b018bbeb1ea 100644 --- a/packages/yoastseo/src/languageProcessing/researches/getParagraphLength.js +++ b/packages/yoastseo/src/languageProcessing/researches/getParagraphLength.js @@ -1,10 +1,10 @@ -import { imageRegex } from "../helpers/image/imageInText"; -import sanitizeLineBreakTag from "../helpers/sanitize/sanitizeLineBreakTag"; -import countWords from "../helpers/word/countWords.js"; -import matchParagraphs from "../helpers/html/matchParagraphs.js"; -import { filter } from "lodash"; -import removeHtmlBlocks from "../helpers/html/htmlParser"; -import { filterShortcodesFromHTML } from "../helpers"; +import { getWordsFromTokens } from "../helpers/word/getAllWordsFromTree"; + +/** + * @typedef {Object} ParagraphLength + * @property {Paragraph} paragraph The paragraph. + * @property {number} paragraphLength The length of the paragraph. + */ /** * Gets all paragraphs and their word counts or character counts from the text. @@ -12,33 +12,23 @@ import { filterShortcodesFromHTML } from "../helpers"; * @param {Paper} paper The paper object to get the text from. * @param {Researcher} researcher The researcher to use for analysis. * - * @returns {Array} The array containing an object with the paragraph word or character count and paragraph text. + * @returns {ParagraphLength[]} The array containing an object with the paragraph word or character count and paragraph text. */ export default function( paper, researcher ) { - let text = paper.getText(); - text = removeHtmlBlocks( text ); - text = filterShortcodesFromHTML( text, paper._attributes && paper._attributes.shortcodes ); - - // Remove images from text before retrieving the paragraphs. - // This step is done here so that applying highlight in captions is possible for ParagraphTooLongAssessment. - text = text.replace( imageRegex, "" ); + const paragraphs = paper.getTree().findAll( node => node.name === "p" ); + const paragraphLengths = []; - // Replace line break tags containing attribute(s) with paragraph tag. - text = sanitizeLineBreakTag( text ); - const paragraphs = matchParagraphs( text ); - const paragraphsLength = []; - - // An optional custom helper to count length to use instead of countWords. - const customCountLength = researcher.getHelper( "customCountLength" ); - - paragraphs.map( function( paragraph ) { - paragraphsLength.push( { - countLength: customCountLength ? customCountLength( paragraph ) : countWords( paragraph ), - text: paragraph, - } ); + paragraphs.forEach( paragraph => { + const customLengthHelper = researcher.getHelper( "customCountLength" ); + const tokens = paragraph.sentences.map( sentence => sentence.tokens ).flat(); + const length = customLengthHelper ? customLengthHelper( paragraph.innerText() ) : getWordsFromTokens( tokens ).length; + if ( length > 0 ) { + paragraphLengths.push( { + paragraph: paragraph, + paragraphLength: length, + } ); + } } ); - return filter( paragraphsLength, function( paragraphLength ) { - return ( paragraphLength.countLength > 0 ); - } ); + return paragraphLengths; } diff --git a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js index 8db546553ed..e2d2f14f1a2 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js @@ -1,24 +1,23 @@ import { __, _n, sprintf } from "@wordpress/i18n"; -import { filter, map, merge } from "lodash"; +import { map, merge } from "lodash"; + import { stripBlockTagsAtStartEnd as stripHTMLTags } from "../../../languageProcessing/helpers/sanitize/stripHTMLTags"; import marker from "../../../markers/addMark"; -import { createAnchorOpeningTag } from "../../../helpers/shortlinker"; +import { createAnchorOpeningTag } from "../../../helpers"; import { inRangeEndInclusive as inRange } from "../../helpers/assessments/inRange"; import AssessmentResult from "../../../values/AssessmentResult"; import Mark from "../../../values/Mark"; import Assessment from "../assessment"; /** - * Represents the assessment that will look if the text has too long paragraphs. + * Represents the assessment that will look if the Paper contains paragraphs that are considered too long. */ export default class ParagraphTooLongAssessment extends Assessment { /** * Sets the identifier and the config. - * + * @constructor * @param {object} config The configuration to use. * @param {boolean} isProduct Whether product configuration should be used. - * - * @returns {void} */ constructor( config = {}, isProduct = false ) { super(); @@ -41,16 +40,13 @@ export default class ParagraphTooLongAssessment extends Assessment { /** * Returns an array containing only the paragraphs longer than the recommended length. * - * @param {array} paragraphsLength The array containing the lengths of individual paragraphs. - * @param {object} config The config to use. + * @param {ParagraphLength[]} paragraphsLength The array containing the lengths of individual paragraphs. + * @param {object} config The config to use. * - * @returns {array} The number of too long paragraphs. + * @returns {ParagraphLength[]} An array containing too long paragraphs. */ getTooLongParagraphs( paragraphsLength, config ) { - const recommendedLength = config.parameters.recommendedLength; - return filter( paragraphsLength, function( paragraph ) { - return paragraph.countLength > recommendedLength; - } ); + return paragraphsLength.filter( paragraph => paragraph.paragraphLength > config.parameters.recommendedLength ); } /** @@ -79,21 +75,21 @@ export default class ParagraphTooLongAssessment extends Assessment { /** * Returns the scores and text for the ParagraphTooLongAssessment. * - * @param {array} paragraphsLength The array containing the lengths of individual paragraphs. - * @param {array} tooLongParagraphs The number of too long paragraphs. - * @param {object} config The config to use. + * @param {ParagraphLength[]} paragraphsLength The array containing the lengths of individual paragraphs. + * @param {object} config The config to use. * - * @returns {{score: number, text: string }} The assessmentResult. + * @returns {AssessmentResult} The assessmentResult. */ - calculateResult( paragraphsLength, tooLongParagraphs, config ) { - let score; + calculateResult( paragraphsLength, config ) { + const assessmentResult = new AssessmentResult(); if ( paragraphsLength.length === 0 ) { - return {}; + return assessmentResult; } - const longestParagraphLength = paragraphsLength[ 0 ].countLength; - + paragraphsLength = paragraphsLength.sort( ( a, b ) => b.paragraphLength - a.paragraphLength ); + const longestParagraphLength = paragraphsLength[ 0 ].paragraphLength; + let score; if ( longestParagraphLength <= config.parameters.recommendedLength ) { // Green indicator. score = 9; @@ -109,67 +105,51 @@ export default class ParagraphTooLongAssessment extends Assessment { score = 3; } + assessmentResult.setScore( score ); + if ( score >= 7 ) { - return { - score: score, - hasMarks: false, - - text: sprintf( - /* translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag */ - __( - "%1$sParagraph length%2$s: None of the paragraphs are too long. Great job!", - "wordpress-seo" - ), - config.urlTitle, - "" + assessmentResult.setHasMarks( false ); + assessmentResult.setText( sprintf( + /* translators: %1$s expands to a link on yoast.com, %2$s expands to the anchor end tag */ + __( + "%1$sParagraph length%2$s: None of the paragraphs are too long. Great job!", + "wordpress-seo" ), - }; + config.urlTitle, + "" + ) ); + return assessmentResult; } - return { - score: score, - hasMarks: true, - text: sprintf( - /* translators: %1$s and %5$s expand to a link on yoast.com, %2$s expands to the anchor end tag, + + const tooLongParagraphs = this.getTooLongParagraphs( paragraphsLength, config ); + assessmentResult.setHasMarks( true ); + assessmentResult.setText( sprintf( + /* translators: %1$s and %5$s expand to a link on yoast.com, %2$s expands to the anchor end tag, %3$d expands to the number of paragraphs over the recommended word / character limit, %4$d expands to the word / character limit, %6$s expands to the word 'words' or 'characters'. */ - _n( - "%1$sParagraph length%2$s: %3$d of the paragraphs contains more than the recommended maximum of %4$d %6$s. %5$sShorten your paragraphs%2$s!", - "%1$sParagraph length%2$s: %3$d of the paragraphs contain more than the recommended maximum of %4$d %6$s. %5$sShorten your paragraphs%2$s!", - tooLongParagraphs.length, - "wordpress-seo" - ), - config.urlTitle, - "", + _n( + "%1$sParagraph length%2$s: %3$d of the paragraphs contains more than the recommended maximum of %4$d %6$s. %5$sShorten your paragraphs%2$s!", + "%1$sParagraph length%2$s: %3$d of the paragraphs contain more than the recommended maximum of %4$d %6$s. %5$sShorten your paragraphs%2$s!", tooLongParagraphs.length, - config.parameters.recommendedLength, - config.urlCallToAction, - this._config.countTextIn + "wordpress-seo" ), - }; - } - - /** - * Sort the paragraphs based on word count. - * - * @param {Array} paragraphs The array with paragraphs. - * - * @returns {Array} The array sorted on word counts. - */ - sortParagraphs( paragraphs ) { - return paragraphs.sort( - function( a, b ) { - return b.countLength - a.countLength; - } - ); + config.urlTitle, + "", + tooLongParagraphs.length, + config.parameters.recommendedLength, + config.urlCallToAction, + this._config.countTextIn + ) ); + return assessmentResult; } /** * Creates a marker for the paragraphs. * - * @param {object} paper The paper to use for the assessment. - * @param {Researcher} researcher The researcher used for calling research. + * @param {Paper} paper The paper to use for the assessment. + * @param {Researcher} researcher The researcher used for calling research. * - * @returns {Array} An array with marked paragraphs. + * @returns {Mark[]} An array with marked paragraphs. */ getMarks( paper, researcher ) { const paragraphsLength = researcher.getResearch( "getParagraphLength" ); @@ -190,27 +170,16 @@ export default class ParagraphTooLongAssessment extends Assessment { * @param {Paper} paper The paper to use for the assessment. * @param {Researcher} researcher The researcher used for calling research. * - * @returns {object} The assessment result. + * @returns {AssessmentResult} The assessment result. */ getResult( paper, researcher ) { - let paragraphsLength = researcher.getResearch( "getParagraphLength" ); + const paragraphsLength = researcher.getResearch( "getParagraphLength" ); const countTextInCharacters = researcher.getConfig( "countCharacters" ); if ( countTextInCharacters ) { this._config.countTextIn = __( "characters", "wordpress-seo" ); } - paragraphsLength = this.sortParagraphs( paragraphsLength ); - const config = this.getConfig( researcher ); - - const tooLongParagraphs = this.getTooLongParagraphs( paragraphsLength, config ); - const paragraphLengthResult = this.calculateResult( paragraphsLength, tooLongParagraphs, config ); - const assessmentResult = new AssessmentResult(); - - assessmentResult.setScore( paragraphLengthResult.score ); - assessmentResult.setText( paragraphLengthResult.text ); - assessmentResult.setHasMarks( paragraphLengthResult.hasMarks ); - - return assessmentResult; + return this.calculateResult( paragraphsLength, this.getConfig( researcher ) ); } /** From 151132ed58d6564b47f99c2763cf554607468ecf Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 27 Nov 2024 12:51:26 +0100 Subject: [PATCH 04/92] Enable AI button for SentenceLengthInTextAssessment.js and ParagraphTooLongAssessment.js --- .../assessments/readability/ParagraphTooLongAssessment.js | 4 +++- .../assessments/readability/SentenceLengthInTextAssessment.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js index e2d2f14f1a2..989c8735370 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js @@ -106,7 +106,9 @@ export default class ParagraphTooLongAssessment extends Assessment { } assessmentResult.setScore( score ); - + if ( score < 9 ) { + assessmentResult.setHasAIFixes( true ); + } if ( score >= 7 ) { assessmentResult.setHasMarks( false ); assessmentResult.setText( sprintf( diff --git a/packages/yoastseo/src/scoring/assessments/readability/SentenceLengthInTextAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/SentenceLengthInTextAssessment.js index 9c08b32f382..882b73a383b 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/SentenceLengthInTextAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/SentenceLengthInTextAssessment.js @@ -64,6 +64,9 @@ class SentenceLengthInTextAssessment extends Assessment { const score = this.calculateScore( percentage ); const assessmentResult = new AssessmentResult(); + if ( score < 9 ) { + assessmentResult.setHasAIFixes( true ); + } assessmentResult.setScore( score ); assessmentResult.setText( this.translateScore( score, percentage ) ); From a30b72d56d3162058363ebecbcbb28645a525414 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 27 Nov 2024 14:09:36 +0100 Subject: [PATCH 05/92] Return assessmentResult --- .../readability/ParagraphTooLongAssessment.js | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js index 76cc962f354..5e5f0b946fd 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js @@ -73,22 +73,15 @@ export default class ParagraphTooLongAssessment extends Assessment { } /** - * Returns the scores and text for the ParagraphTooLongAssessment. - * - * @param {ParagraphLength[]} paragraphsLength The array containing the lengths of individual paragraphs. + * Returns the score for the ParagraphTooLongAssessment. + * @param {array} paragraphsLength The array containing the lengths of individual paragraphs. * @param {object} config The config to use. - * - * @returns {AssessmentResult} The assessmentResult. + * @returns {number} The score. */ - calculateResult( paragraphsLength, config ) { - const assessmentResult = new AssessmentResult(); - - if ( paragraphsLength.length === 0 ) { - return assessmentResult; - } + getScore( paragraphsLength, config ) { + const sortedParagraphsLength = paragraphsLength.sort( ( a, b ) => b.paragraphLength - a.paragraphLength ); - paragraphsLength = paragraphsLength.sort( ( a, b ) => b.paragraphLength - a.paragraphLength ); - const longestParagraphLength = paragraphsLength[ 0 ].paragraphLength; + const longestParagraphLength = sortedParagraphsLength[ 0 ].paragraphLength; let score; if ( longestParagraphLength <= config.parameters.recommendedLength ) { // Green indicator. @@ -104,11 +97,30 @@ export default class ParagraphTooLongAssessment extends Assessment { // Red indicator. score = 3; } + return score; + } - assessmentResult.setScore( score ); - if ( score < 9 ) { - assessmentResult.setHasAIFixes( true ); + /** + * Returns the scores and text for the ParagraphTooLongAssessment. + * + * @param {ParagraphLength[]} paragraphsLength The array containing the lengths of individual paragraphs. + * @param {object} config The config to use. + * + * @returns {AssessmentResult} The assessmentResult. + */ + calculateResult( paragraphsLength, config ) { + const tooLongParagraphs = this.getTooLongParagraphs( paragraphsLength, config ); + + const assessmentResult = new AssessmentResult(); + + if ( paragraphsLength.length === 0 ) { + return assessmentResult; } + + const score = this.getScore( paragraphsLength, config ); + + assessmentResult.setScore( score ); + if ( score >= 7 ) { assessmentResult.setHasMarks( false ); assessmentResult.setText( sprintf( @@ -154,12 +166,11 @@ export default class ParagraphTooLongAssessment extends Assessment { config.parameters.recommendedLength, config.urlCallToAction ); + assessmentResult.setHasMarks( true ); + assessmentResult.setText( config.countCharacters ? characterFeedback : wordFeedback ); + assessmentResult.setHasAIFixes( true ); - return { - score: score, - hasMarks: true, - text: config.countCharacters ? characterFeedback : wordFeedback, - }; + return assessmentResult; } /** From 4b9349cbb92fec1a8e08964c9324706235ed35da Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 27 Nov 2024 14:59:00 +0100 Subject: [PATCH 06/92] Adapt getMarks for ParagraphTooLongAssessment.js --- .../readability/ParagraphTooLongAssessment.js | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js index 5e5f0b946fd..e7d9cbd813a 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js @@ -74,7 +74,7 @@ export default class ParagraphTooLongAssessment extends Assessment { /** * Returns the score for the ParagraphTooLongAssessment. - * @param {array} paragraphsLength The array containing the lengths of individual paragraphs. + * @param {ParagraphLength[]} paragraphsLength The array containing the lengths of individual paragraphs. * @param {object} config The config to use. * @returns {number} The score. */ @@ -199,14 +199,19 @@ export default class ParagraphTooLongAssessment extends Assessment { getMarks( paper, researcher ) { const paragraphsLength = researcher.getResearch( "getParagraphLength" ); const tooLongParagraphs = this.getTooLongParagraphs( paragraphsLength, this.getConfig( researcher ) ); - return map( tooLongParagraphs, function( paragraph ) { - const paragraphText = stripHTMLTags( paragraph.text ); - const marked = marker( paragraphText ); - return new Mark( { - original: paragraphText, - marked: marked, - } ); - } ); + return tooLongParagraphs.flatMap( ( { paragraph } ) => + paragraph.sentences.map( sentence => new Mark( { + position: { + startOffset: sentence.sourceCodeRange.startOffset, + endOffset: sentence.sourceCodeRange.endOffset, + startOffsetBlock: sentence.sourceCodeRange.startOffset - ( sentence.parentStartOffset || 0 ), + endOffsetBlock: sentence.sourceCodeRange.endOffset - ( sentence.parentStartOffset || 0 ), + clientId: sentence.parentClientId || "", + attributeId: sentence.parentAttributeId || "", + isFirstSection: sentence.isParentFirstSectionOfBlock || false, + }, + } ) ) + ); } /** From 904244f0c35e29c7c89a5f42caf8a211a60433b4 Mon Sep 17 00:00:00 2001 From: Leonidas Milosis Date: Wed, 11 Dec 2024 13:10:37 +0200 Subject: [PATCH 07/92] Only show a modified time tag if it's later than the created time --- src/presentations/indexable-post-type-presentation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/presentations/indexable-post-type-presentation.php b/src/presentations/indexable-post-type-presentation.php index 018e4eedec8..e497ef14abf 100644 --- a/src/presentations/indexable-post-type-presentation.php +++ b/src/presentations/indexable-post-type-presentation.php @@ -285,7 +285,7 @@ public function generate_open_graph_article_published_time() { * @return string The open graph article modified time. */ public function generate_open_graph_article_modified_time() { - if ( $this->source->post_modified_gmt !== $this->source->post_date_gmt ) { + if ( \strtotime( $this->source->post_modified_gmt ) > \strtotime( $this->source->post_date_gmt ) ) { return $this->date->format( $this->source->post_modified_gmt ); } From 500e2cb415188cf78043f2cc64e0f12c6db3c343 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 11 Dec 2024 14:32:30 +0100 Subject: [PATCH 08/92] Fix highlighting for paragraph length assessment --- .../readability/ParagraphTooLongAssessment.js | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js index e7d9cbd813a..ae325e23fbd 100644 --- a/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/readability/ParagraphTooLongAssessment.js @@ -1,8 +1,6 @@ import { __, _n, sprintf } from "@wordpress/i18n"; -import { map, merge } from "lodash"; +import { merge } from "lodash"; -import { stripBlockTagsAtStartEnd as stripHTMLTags } from "../../../languageProcessing/helpers/sanitize/stripHTMLTags"; -import marker from "../../../markers/addMark"; import { createAnchorOpeningTag } from "../../../helpers"; import { inRangeEndInclusive as inRange } from "../../helpers/assessments/inRange"; import AssessmentResult from "../../../values/AssessmentResult"; @@ -199,19 +197,19 @@ export default class ParagraphTooLongAssessment extends Assessment { getMarks( paper, researcher ) { const paragraphsLength = researcher.getResearch( "getParagraphLength" ); const tooLongParagraphs = this.getTooLongParagraphs( paragraphsLength, this.getConfig( researcher ) ); - return tooLongParagraphs.flatMap( ( { paragraph } ) => - paragraph.sentences.map( sentence => new Mark( { + return tooLongParagraphs.flatMap( ( { paragraph } ) => { + return new Mark( { position: { - startOffset: sentence.sourceCodeRange.startOffset, - endOffset: sentence.sourceCodeRange.endOffset, - startOffsetBlock: sentence.sourceCodeRange.startOffset - ( sentence.parentStartOffset || 0 ), - endOffsetBlock: sentence.sourceCodeRange.endOffset - ( sentence.parentStartOffset || 0 ), - clientId: sentence.parentClientId || "", - attributeId: sentence.parentAttributeId || "", - isFirstSection: sentence.isParentFirstSectionOfBlock || false, + startOffset: paragraph.sourceCodeLocation.startTag.endOffset, + endOffset: paragraph.sourceCodeLocation.endTag.startOffset, + startOffsetBlock: 0, + endOffsetBlock: paragraph.sourceCodeLocation.endOffset - paragraph.sourceCodeLocation.startOffset, + clientId: paragraph.clientId || "", + attributeId: paragraph.parentAttributeId || "", + isFirstSection: paragraph.isParentFirstSectionOfBlock || false, }, - } ) ) - ); + } ); + } ); } /** From 928996843200c185469fb09b2ee05bdb60268cf7 Mon Sep 17 00:00:00 2001 From: aidamarfuaty Date: Wed, 11 Dec 2024 14:34:08 +0100 Subject: [PATCH 09/92] Improve JSDoc --- .../languageProcessing/researches/countSentencesFromText.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/yoastseo/src/languageProcessing/researches/countSentencesFromText.js b/packages/yoastseo/src/languageProcessing/researches/countSentencesFromText.js index 78f87ee31ee..59ce61e0489 100644 --- a/packages/yoastseo/src/languageProcessing/researches/countSentencesFromText.js +++ b/packages/yoastseo/src/languageProcessing/researches/countSentencesFromText.js @@ -2,9 +2,11 @@ import sentencesLength from "../helpers/sentence/sentencesLength.js"; import getSentencesFromTree from "../helpers/sentence/getSentencesFromTree"; /** - * Count sentences in the text. + * Gets the sentences from the text and calculates the length of each sentence. + * * @param {Paper} paper The Paper object to get text from. * @param {Researcher} researcher The researcher to use for analysis. + * * @returns {SentenceLength[]} The sentences from the text. */ export default function( paper, researcher ) { From 3099a9d37068c54671077475677106db2d45aee3 Mon Sep 17 00:00:00 2001 From: Leonidas Milosis Date: Fri, 13 Dec 2024 12:14:09 +0200 Subject: [PATCH 10/92] Dont output dateModified attributes in schema if the modified time was earlier than the creation time --- src/generators/schema/article.php | 10 +++++++--- src/generators/schema/webpage.php | 5 ++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/generators/schema/article.php b/src/generators/schema/article.php index b2ba18176e8..bdf392deed4 100644 --- a/src/generators/schema/article.php +++ b/src/generators/schema/article.php @@ -55,11 +55,15 @@ public function generate() { ], 'headline' => $this->helpers->schema->html->smart_strip_tags( $this->helpers->post->get_post_title_with_fallback( $this->context->id ) ), 'datePublished' => $this->helpers->date->format( $this->context->post->post_date_gmt ), - 'dateModified' => $this->helpers->date->format( $this->context->post->post_modified_gmt ), - 'mainEntityOfPage' => [ '@id' => $this->context->main_schema_id ], - 'wordCount' => $this->word_count( $this->context->post->post_content, $this->context->post->post_title ), ]; + if ( \strtotime( $this->context->post->post_modified_gmt ) > \strtotime( $this->context->post->post_date_gmt ) ) { + $data['dateModified'] = $this->helpers->date->format( $this->context->post->post_modified_gmt ); + } + + $data['mainEntityOfPage'] = [ '@id' => $this->context->main_schema_id ]; + $data['wordCount'] = $this->word_count( $this->context->post->post_content, $this->context->post->post_title ); + if ( $this->context->post->comment_status === 'open' ) { $data['commentCount'] = \intval( $this->context->post->comment_count, 10 ); } diff --git a/src/generators/schema/webpage.php b/src/generators/schema/webpage.php index 615b21da6c7..06576fe5d79 100644 --- a/src/generators/schema/webpage.php +++ b/src/generators/schema/webpage.php @@ -52,7 +52,10 @@ public function generate() { if ( $this->context->indexable->object_type === 'post' ) { $data['datePublished'] = $this->helpers->date->format( $this->context->post->post_date_gmt ); - $data['dateModified'] = $this->helpers->date->format( $this->context->post->post_modified_gmt ); + + if ( \strtotime( $this->context->post->post_modified_gmt ) > \strtotime( $this->context->post->post_date_gmt ) ) { + $data['dateModified'] = $this->helpers->date->format( $this->context->post->post_modified_gmt ); + } if ( $this->context->indexable->object_sub_type === 'post' ) { $data = $this->add_author( $data, $this->context->post ); From 8c6b2f262fd87eb5b5564d586406c9dae8d8486e Mon Sep 17 00:00:00 2001 From: Leonidas Milosis Date: Fri, 13 Dec 2024 13:07:45 +0200 Subject: [PATCH 11/92] Fix PHPCS --- src/generators/schema/article.php | 6 +++--- src/generators/schema/webpage.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/generators/schema/article.php b/src/generators/schema/article.php index bdf392deed4..bdc8bcd1930 100644 --- a/src/generators/schema/article.php +++ b/src/generators/schema/article.php @@ -58,11 +58,11 @@ public function generate() { ]; if ( \strtotime( $this->context->post->post_modified_gmt ) > \strtotime( $this->context->post->post_date_gmt ) ) { - $data['dateModified'] = $this->helpers->date->format( $this->context->post->post_modified_gmt ); + $data['dateModified'] = $this->helpers->date->format( $this->context->post->post_modified_gmt ); } - + $data['mainEntityOfPage'] = [ '@id' => $this->context->main_schema_id ]; - $data['wordCount'] = $this->word_count( $this->context->post->post_content, $this->context->post->post_title ); + $data['wordCount'] = $this->word_count( $this->context->post->post_content, $this->context->post->post_title ); if ( $this->context->post->comment_status === 'open' ) { $data['commentCount'] = \intval( $this->context->post->comment_count, 10 ); diff --git a/src/generators/schema/webpage.php b/src/generators/schema/webpage.php index 06576fe5d79..e5abc2e456d 100644 --- a/src/generators/schema/webpage.php +++ b/src/generators/schema/webpage.php @@ -54,7 +54,7 @@ public function generate() { $data['datePublished'] = $this->helpers->date->format( $this->context->post->post_date_gmt ); if ( \strtotime( $this->context->post->post_modified_gmt ) > \strtotime( $this->context->post->post_date_gmt ) ) { - $data['dateModified'] = $this->helpers->date->format( $this->context->post->post_modified_gmt ); + $data['dateModified'] = $this->helpers->date->format( $this->context->post->post_modified_gmt ); } if ( $this->context->indexable->object_sub_type === 'post' ) { From 639f86cb07b268b082cdb169b554fe889c29a1ae Mon Sep 17 00:00:00 2001 From: Leonidas Milosis Date: Fri, 13 Dec 2024 13:08:29 +0200 Subject: [PATCH 12/92] Fix and add unit tests --- .../Unit/Generators/Schema_Generator_Test.php | 157 +++++++++++++++--- 1 file changed, 130 insertions(+), 27 deletions(-) diff --git a/tests/Unit/Generators/Schema_Generator_Test.php b/tests/Unit/Generators/Schema_Generator_Test.php index 07f487e73f4..e4e8fd160eb 100644 --- a/tests/Unit/Generators/Schema_Generator_Test.php +++ b/tests/Unit/Generators/Schema_Generator_Test.php @@ -430,8 +430,8 @@ public function test_generate_with_blocks() { $this->context->indexable->object_type = 'post'; $this->context->indexable->object_sub_type = 'post'; $this->context->post = (object) [ - 'post_date_gmt' => 'date', - 'post_modified_gmt' => 'date', + 'post_date_gmt' => '2024-12-13 09:58:08', + 'post_modified_gmt' => '2024-12-13 09:58:09', ]; $this->context->has_image = false; @@ -448,9 +448,15 @@ public function test_generate_with_blocks() { $this->date ->expects( 'format' ) - ->twice() - ->with( 'date' ) - ->andReturn( 'date' ); + ->once() + ->with( '2024-12-13 09:58:08' ) + ->andReturn( '2024-12-13 09:58:08' ); + + $this->date + ->expects( 'format' ) + ->once() + ->with( '2024-12-13 09:58:09' ) + ->andReturn( '2024-12-13 09:58:09' ); Monkey\Functions\expect( 'is_search' ) ->andReturn( false ); @@ -629,8 +635,8 @@ public function test_generate_with_block_not_having_generated_output() { $this->context->indexable->object_type = 'post'; $this->context->indexable->object_sub_type = 'post'; $this->context->post = (object) [ - 'post_date_gmt' => 'date', - 'post_modified_gmt' => 'date', + 'post_date_gmt' => '2024-12-13 09:58:08', + 'post_modified_gmt' => '2024-12-13 09:58:09', ]; $this->context->has_image = false; @@ -647,9 +653,15 @@ public function test_generate_with_block_not_having_generated_output() { $this->date ->expects( 'format' ) - ->twice() - ->with( 'date' ) - ->andReturn( 'date' ); + ->once() + ->with( '2024-12-13 09:58:08' ) + ->andReturn( '2024-12-13 09:58:08' ); + + $this->date + ->expects( 'format' ) + ->once() + ->with( '2024-12-13 09:58:09' ) + ->andReturn( '2024-12-13 09:58:09' ); Monkey\Functions\expect( 'is_search' ) ->andReturn( false ); @@ -694,8 +706,8 @@ public function test_validate_type_singular_array() { $this->context->indexable->object_type = 'post'; $this->context->indexable->object_sub_type = 'post'; $this->context->post = (object) [ - 'post_date_gmt' => 'date', - 'post_modified_gmt' => 'date', + 'post_date_gmt' => '2024-12-13 09:58:08', + 'post_modified_gmt' => '2024-12-13 09:58:09', ]; $this->context->has_image = false; @@ -712,9 +724,15 @@ public function test_validate_type_singular_array() { $this->date ->expects( 'format' ) - ->twice() - ->with( 'date' ) - ->andReturn( 'date' ); + ->once() + ->with( '2024-12-13 09:58:08' ) + ->andReturn( '2024-12-13 09:58:08' ); + + $this->date + ->expects( 'format' ) + ->once() + ->with( '2024-12-13 09:58:09' ) + ->andReturn( '2024-12-13 09:58:09' ); Monkey\Functions\expect( 'is_search' ) ->andReturn( false ); @@ -802,8 +820,8 @@ public function test_validate_type_unique_array() { $this->context->indexable->object_type = 'post'; $this->context->indexable->object_sub_type = 'post'; $this->context->post = (object) [ - 'post_date_gmt' => 'date', - 'post_modified_gmt' => 'date', + 'post_date_gmt' => '2024-12-13 09:58:08', + 'post_modified_gmt' => '2024-12-13 09:58:09', ]; $this->context->has_image = false; @@ -820,9 +838,15 @@ public function test_validate_type_unique_array() { $this->date ->expects( 'format' ) - ->twice() - ->with( 'date' ) - ->andReturn( 'date' ); + ->once() + ->with( '2024-12-13 09:58:08' ) + ->andReturn( '2024-12-13 09:58:08' ); + + $this->date + ->expects( 'format' ) + ->once() + ->with( '2024-12-13 09:58:09' ) + ->andReturn( '2024-12-13 09:58:09' ); Monkey\Functions\expect( 'is_search' ) ->andReturn( false ); @@ -905,8 +929,8 @@ public function test_get_graph_pieces_on_single_post_with_password_required() { $this->context->indexable->object_type = 'post'; $this->context->indexable->object_sub_type = 'post'; $this->context->post = (object) [ - 'post_date_gmt' => 'date', - 'post_modified_gmt' => 'date', + 'post_date_gmt' => '2024-12-13 09:58:08', + 'post_modified_gmt' => '2024-12-13 09:58:09', ]; $this->context->has_image = false; @@ -917,9 +941,15 @@ public function test_get_graph_pieces_on_single_post_with_password_required() { $this->date ->expects( 'format' ) - ->twice() - ->with( 'date' ) - ->andReturn( 'date' ); + ->once() + ->with( '2024-12-13 09:58:08' ) + ->andReturn( '2024-12-13 09:58:08' ); + + $this->date + ->expects( 'format' ) + ->once() + ->with( '2024-12-13 09:58:09' ) + ->andReturn( '2024-12-13 09:58:09' ); Monkey\Functions\expect( 'is_search' ) ->andReturn( false ); @@ -1100,6 +1130,79 @@ public function test_generate_with_search_page() { ); } + /** + * Tests with the generate with a post page that was published with schedule (aka, has a modified date earlier than a published date). + * + * @covers ::__construct + * @covers ::generate + * @covers ::get_graph_pieces + * + * @return void + */ + public function test_get_graph_pieces_on_scheduled_post() { + $this->stubEscapeFunctions(); + $this->current_page->expects( 'is_paged' )->andReturns( false ); + + $this->context->alternate_site_name = ''; + $this->context->indexable->object_type = 'post'; + $this->context->indexable->object_sub_type = 'post'; + $this->context->post = (object) [ + 'post_date_gmt' => '2024-12-13 09:58:08', + 'post_modified_gmt' => '2024-12-13 09:58:07', + ]; + $this->context->has_image = false; + + Monkey\Functions\expect( 'post_password_required' ) + ->once() + ->with( $this->context->post ) + ->andReturnFalse(); + + $this->article + ->expects( 'is_author_supported' ) + ->twice() + ->with( 'post' ) + ->andReturnFalse(); + + $this->date + ->expects( 'format' ) + ->once() + ->with( '2024-12-13 09:58:08' ) + ->andReturn( '2024-12-13 09:58:08' ); + + Monkey\Functions\expect( 'is_search' ) + ->andReturn( false ); + + $this->current_page + ->expects( 'is_front_page' ) + ->andReturnTrue(); + + $this->html + ->expects( 'smart_strip_tags' ) + ->times( 3 ) + ->andReturnArg( 0 ); + + $this->replace_vars_helper + ->expects( 'register_replace_vars' ) + ->once(); + + Monkey\Actions\expectDone( 'wpseo_pre_schema_block_type_yoast/faq-block' ) + ->with( $this->context->blocks['yoast/faq-block'], $this->context ); + + Monkey\Filters\expectApplied( 'wpseo_schema_needs_faq' ) + ->with( true ); + + $this->current_page->expects( 'is_home_static_page' )->andReturns( false ); + $this->current_page->expects( 'is_home_posts_page' )->andReturns( false ); + + $expected_schema = $this->get_expected_schema(); + unset( $expected_schema['@graph'][0]['dateModified'] ); + + $this->assertEquals( + $expected_schema, + $this->instance->generate( $this->context ) + ); + } + /** * The generated schema that is applicable for almost every test scenario in this file. * @@ -1132,8 +1235,8 @@ public function get_expected_schema() { '@id' => '#id-1', ], ], - 'datePublished' => 'date', - 'dateModified' => 'date', + 'datePublished' => '2024-12-13 09:58:08', + 'dateModified' => '2024-12-13 09:58:09', ], [ '@type' => 'WebSite', From 6ab136a867a35c3c9f39723a753a4f744ffb3587 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:59:36 +0100 Subject: [PATCH 13/92] Remove redundant config that is part of eslint/js/recommended All that are removed are already part of the eslint/js/recommended shared configuration. There is one exception: no-native-reassign. It is deprecated and has been replaced with no-global-assign, which is part of the recommened config. --- packages/eslint/default.yml | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/packages/eslint/default.yml b/packages/eslint/default.yml index 7507f0f1d82..db1ff97fb5a 100644 --- a/packages/eslint/default.yml +++ b/packages/eslint/default.yml @@ -25,39 +25,17 @@ plugins: rules: # Possible Errors comma-dangle: [2, "always-multiline"] - no-cond-assign: 2 # Warning to allow webpack hot reloading to not fail on no-console. no-console: [ 1, { allow: ["warn", "error", "trace"] } ] - no-constant-condition: 2 - no-control-regex: 2 - no-debugger: 2 - no-dupe-args: 2 - no-dupe-keys: 2 - no-duplicate-case: 2 - no-empty: 2 - no-empty-character-class: 2 - no-ex-assign: 2 - no-extra-boolean-cast: 2 no-extra-parens: 0 no-extra-semi: 2 - no-func-assign: 2 no-inner-declarations: [2, functions] - no-invalid-regexp: 2 - no-irregular-whitespace: 2 - no-negated-in-lhs: 2 - no-obj-calls: 2 - no-regex-spaces: 2 - no-sparse-arrays: 2 - no-unexpected-multiline: 2 - no-unreachable: 2 - use-isnan: 2 valid-jsdoc: [ 2, { "prefer": { "return": "returns" } }] - valid-typeof: 2 # Best Practices accessor-pairs: 2 @@ -72,15 +50,12 @@ rules: guard-for-in: 2 no-alert: 2 no-caller: 2 - no-case-declarations: 2 no-div-regex: 2 no-else-return: 2 - no-empty-pattern: 2 no-eq-null: 2 no-eval: 2 no-extend-native: 2 no-extra-bind: 2 - no-fallthrough: 2 no-floating-decimal: 0 no-implicit-coercion: 0 no-implied-eval: 2 @@ -92,14 +67,11 @@ rules: no-magic-number: 0 no-multi-spaces: 0 no-multi-str: 2 - no-native-reassign: 2 no-new-func: 2 no-new-wrappers: 2 no-new: 2 no-octal-escape: 2 - no-octal: 2 no-proto: 2 - no-redeclare: 2 no-return-assign: 2 no-script-url: 2 no-self-compare: 2 @@ -108,10 +80,8 @@ rules: no-unused-expressions: 2 no-useless-call: 2 no-useless-concat: 2 - no-useless-escape: 2 no-void: 2 no-warning-comments: [ 2, { "terms": [ "todo" ], "location": "anywhere" } ] - no-with: 2 radix: 2 vars-on-top: 0 wrap-iife: 2 @@ -123,14 +93,10 @@ rules: # Variables init-declarations: 0 no-catch-shadow: 2 - no-delete-var: 2 no-label-var: 2 - no-shadow-restricted-names: 2 no-shadow: [ 2, { "builtinGlobals": false, "hoist": "all", "allow": [] } ] no-undef-init: 2 - no-undef: 2 no-undefined: 2 - no-unused-vars: 2 no-use-before-define: 2 prefer-const: 2 From 4d2b9341182cc66426cfa9a9d9af5ec1b30c823b Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:13:53 +0100 Subject: [PATCH 14/92] Remove explicitly disabled rules The Yoast configuration isn't responsible for rules other configs migh have enabled. This also cleans up our config a bit, keeping the focus on things we want to enforece. Some of these rules are interesting to us to enforce in the future. I'll create a new issue to track that. --- packages/eslint/default.yml | 35 ----------------------------------- 1 file changed, 35 deletions(-) diff --git a/packages/eslint/default.yml b/packages/eslint/default.yml index db1ff97fb5a..11064ca6d1f 100644 --- a/packages/eslint/default.yml +++ b/packages/eslint/default.yml @@ -28,7 +28,6 @@ rules: # Warning to allow webpack hot reloading to not fail on no-console. no-console: [ 1, { allow: ["warn", "error", "trace"] } ] - no-extra-parens: 0 no-extra-semi: 2 no-inner-declarations: [2, functions] valid-jsdoc: [ 2, { @@ -39,12 +38,8 @@ rules: # Best Practices accessor-pairs: 2 - block-scoped-var: 0 complexity: [2, 10] - consistent-return: 0 curly: 2 - default-case: 0 - dot-location: 0 dot-notation: 2 eqeqeq: 2 guard-for-in: 2 @@ -56,16 +51,11 @@ rules: no-eval: 2 no-extend-native: 2 no-extra-bind: 2 - no-floating-decimal: 0 - no-implicit-coercion: 0 no-implied-eval: 2 - no-invalid-this: 0 no-iterator: 2 no-labels: 2 no-lone-blocks: 2 no-loop-func: 2 - no-magic-number: 0 - no-multi-spaces: 0 no-multi-str: 2 no-new-func: 2 no-new-wrappers: 2 @@ -75,23 +65,18 @@ rules: no-return-assign: 2 no-script-url: 2 no-self-compare: 2 - no-sequences: 0 - no-throw-literal: 0 no-unused-expressions: 2 no-useless-call: 2 no-useless-concat: 2 no-void: 2 no-warning-comments: [ 2, { "terms": [ "todo" ], "location": "anywhere" } ] radix: 2 - vars-on-top: 0 wrap-iife: 2 - yoda: 0 # Strict strict: 2 # Variables - init-declarations: 0 no-catch-shadow: 2 no-label-var: 2 no-shadow: [ 2, { "builtinGlobals": false, "hoist": "all", "allow": [] } ] @@ -105,11 +90,8 @@ rules: global-require: 2 handle-callback-err: 2 no-mixed-requires: 2 - no-new-require: 0 no-path-concat: 2 no-process-exit: 2 - no-restricted-modules: 0 - no-sync: 0 # Stylistic Issues array-bracket-spacing: [2, always] @@ -121,36 +103,25 @@ rules: computed-property-spacing: [2, always] consistent-this: [2, "that"] eol-last: 2 - func-names: 0 - func-style: 0 - id-length: 0 - id-match: 0 indent: [2, tab, {"SwitchCase": 1}] jsx-quotes: [2, "prefer-double"] key-spacing: [2, {"beforeColon": false, "afterColon": true}] keyword-spacing: [2, {"before": true, "after": true}] linebreak-style: [2, unix] - lines-around-comment: 0 max-depth: 2 max-len: [2, 150, 4] max-nested-callbacks: 2 - max-params: 0 max-statements: [2, 30] new-cap: 2 new-parens: 2 - newline-after-var: 0 - newline-per-chained-call: 0 no-array-constructor: 2 no-bitwise: 2 - no-continue: 0 no-inline-comments: 2 - no-lonely-if: 0 no-mixed-spaces-and-tabs: [2, "smart-tabs"] no-multiple-empty-lines: 2 no-negated-condition: 2 no-nested-ternary: 2 no-new-object: 2 - no-plusplus: 0 no-restricted-syntax: [ 'error', { @@ -171,14 +142,10 @@ rules: } ] no-spaced-func: 2 - no-ternary: 0 no-trailing-spaces: 2 - no-underscore-dangle: 0 no-unneeded-ternary: 2 no-whitespace-before-property: 2 object-curly-spacing: [2, "always"] - one-var: 0 - operator-assignment: 0 operator-linebreak: 2 padded-blocks: [2, "never"] quote-props: [2, "as-needed", {"keywords": true}] @@ -186,14 +153,12 @@ rules: require-jsdoc: [2, {"require": {"MethodDefinition": true, "ClassDeclaration": true, "ArrowFunctionExpression": true, "FunctionExpression": true}}] semi-spacing: 2 semi: [2, always] - sort-vars: 0 space-before-blocks: 2 space-before-function-paren: [2, "never"] space-in-parens: [2, "always", {"exceptions": ["empty"]}] space-infix-ops: 2 space-unary-ops: [2, {"words": false, "nonwords": false, "overrides": { "!": true }}] spaced-comment: [2, "always"] - wrap-regex: 0 # Accessibility rules. https://github.com/evcohen/eslint-plugin-jsx-a11y # Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. From 6bec3d5f990ded8d13f8c0c7aaad2c7f52618a83 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 6 Nov 2024 15:22:43 +0100 Subject: [PATCH 15/92] Remove redundant options that match the rule's defaults --- packages/eslint/default.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/eslint/default.yml b/packages/eslint/default.yml index 11064ca6d1f..203260cdc49 100644 --- a/packages/eslint/default.yml +++ b/packages/eslint/default.yml @@ -95,19 +95,19 @@ rules: # Stylistic Issues array-bracket-spacing: [2, always] - block-spacing: [2, always] + block-spacing: 2 brace-style: [2, 1tbs] camelcase: 2 comma-spacing: 2 comma-style: 2 computed-property-spacing: [2, always] - consistent-this: [2, "that"] + consistent-this: 2 eol-last: 2 indent: [2, tab, {"SwitchCase": 1}] - jsx-quotes: [2, "prefer-double"] - key-spacing: [2, {"beforeColon": false, "afterColon": true}] - keyword-spacing: [2, {"before": true, "after": true}] - linebreak-style: [2, unix] + jsx-quotes: 2 + key-spacing: 2 + keyword-spacing: 2 + linebreak-style: 2 max-depth: 2 max-len: [2, 150, 4] max-nested-callbacks: 2 @@ -152,7 +152,7 @@ rules: quotes: [2, double, avoid-escape] require-jsdoc: [2, {"require": {"MethodDefinition": true, "ClassDeclaration": true, "ArrowFunctionExpression": true, "FunctionExpression": true}}] semi-spacing: 2 - semi: [2, always] + semi: 2 space-before-blocks: 2 space-before-function-paren: [2, "never"] space-in-parens: [2, "always", {"exceptions": ["empty"]}] From 76e41fbd74ca9c3fcc5bdaa8804fba692437caa3 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 13 Nov 2024 08:55:46 +0100 Subject: [PATCH 16/92] Remove redundant and deprecated rule no-shadow is its official replacement and caches the same problems --- packages/eslint/default.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/eslint/default.yml b/packages/eslint/default.yml index 203260cdc49..953da25c96a 100644 --- a/packages/eslint/default.yml +++ b/packages/eslint/default.yml @@ -77,7 +77,6 @@ rules: strict: 2 # Variables - no-catch-shadow: 2 no-label-var: 2 no-shadow: [ 2, { "builtinGlobals": false, "hoist": "all", "allow": [] } ] no-undef-init: 2 From 7b935bbb2e2423946bf4b6ffecf7490bdf0b6523 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:32:12 +0100 Subject: [PATCH 17/92] Replace deprecated rules with their suggested replacement --- packages/eslint/default.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint/default.yml b/packages/eslint/default.yml index 953da25c96a..e5bf1f414f7 100644 --- a/packages/eslint/default.yml +++ b/packages/eslint/default.yml @@ -120,7 +120,7 @@ rules: no-multiple-empty-lines: 2 no-negated-condition: 2 no-nested-ternary: 2 - no-new-object: 2 + no-object-constructor: 2 no-restricted-syntax: [ 'error', { @@ -140,7 +140,7 @@ rules: message: 'A textdomain needs to be provided for translation calls.', } ] - no-spaced-func: 2 + func-call-spacing: 2 no-trailing-spaces: 2 no-unneeded-ternary: 2 no-whitespace-before-property: 2 From e457c634c23cb80821b4ecc8c6437346868e88d6 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:14:07 +0100 Subject: [PATCH 18/92] Group plugin rules together This doesn't change any of the rules, only the order in which they are in the config. This makes it easier to find details about a certain rule and understand its origin and purpose. --- packages/eslint/default.yml | 221 ++++++++++++++++++------------------ 1 file changed, 109 insertions(+), 112 deletions(-) diff --git a/packages/eslint/default.yml b/packages/eslint/default.yml index e5bf1f414f7..6b0542bcd2d 100644 --- a/packages/eslint/default.yml +++ b/packages/eslint/default.yml @@ -23,28 +23,30 @@ plugins: # http://eslint.org/docs/rules/ rules: - # Possible Errors - comma-dangle: [2, "always-multiline"] - - # Warning to allow webpack hot reloading to not fail on no-console. - no-console: [ 1, { allow: ["warn", "error", "trace"] } ] - no-extra-semi: 2 - no-inner-declarations: [2, functions] - valid-jsdoc: [ 2, { - "prefer": { - "return": "returns" - } - }] + # Native ESLint rules + ## ESLint "Possible problems - These rules relate to possible logic errors in code:" (https://eslint.org/docs/latest/rules/#possible-problems). + no-inner-declarations: [ 2, "functions" ] + no-self-compare: 2 + no-use-before-define: 2 - # Best Practices + ## ESLint "Suggestions - These rules suggest alternate ways of doing things:" (https://eslint.org/docs/latest/rules/#suggestions). accessor-pairs: 2 - complexity: [2, 10] + camelcase: 2 + complexity: [ 2, 10 ] + consistent-this: 2 curly: 2 dot-notation: 2 eqeqeq: 2 guard-for-in: 2 + max-depth: 2 + max-nested-callbacks: 2 + max-statements: [ 2, 30 ] + new-cap: 2 no-alert: 2 + no-array-constructor: 2 + no-bitwise: 2 no-caller: 2 + no-console: [ 1, { allow: [ "warn", "error", "trace" ] } ] no-div-regex: 2 no-else-return: 2 no-eq-null: 2 @@ -52,75 +54,21 @@ rules: no-extend-native: 2 no-extra-bind: 2 no-implied-eval: 2 + no-inline-comments: 2 no-iterator: 2 + no-label-var: 2 no-labels: 2 no-lone-blocks: 2 no-loop-func: 2 no-multi-str: 2 + no-negated-condition: 2 + no-nested-ternary: 2 no-new-func: 2 no-new-wrappers: 2 no-new: 2 + no-object-constructor: 2 no-octal-escape: 2 no-proto: 2 - no-return-assign: 2 - no-script-url: 2 - no-self-compare: 2 - no-unused-expressions: 2 - no-useless-call: 2 - no-useless-concat: 2 - no-void: 2 - no-warning-comments: [ 2, { "terms": [ "todo" ], "location": "anywhere" } ] - radix: 2 - wrap-iife: 2 - - # Strict - strict: 2 - - # Variables - no-label-var: 2 - no-shadow: [ 2, { "builtinGlobals": false, "hoist": "all", "allow": [] } ] - no-undef-init: 2 - no-undefined: 2 - no-use-before-define: 2 - prefer-const: 2 - - # Node.js and CommonJS - callback-return: 2 - global-require: 2 - handle-callback-err: 2 - no-mixed-requires: 2 - no-path-concat: 2 - no-process-exit: 2 - - # Stylistic Issues - array-bracket-spacing: [2, always] - block-spacing: 2 - brace-style: [2, 1tbs] - camelcase: 2 - comma-spacing: 2 - comma-style: 2 - computed-property-spacing: [2, always] - consistent-this: 2 - eol-last: 2 - indent: [2, tab, {"SwitchCase": 1}] - jsx-quotes: 2 - key-spacing: 2 - keyword-spacing: 2 - linebreak-style: 2 - max-depth: 2 - max-len: [2, 150, 4] - max-nested-callbacks: 2 - max-statements: [2, 30] - new-cap: 2 - new-parens: 2 - no-array-constructor: 2 - no-bitwise: 2 - no-inline-comments: 2 - no-mixed-spaces-and-tabs: [2, "smart-tabs"] - no-multiple-empty-lines: 2 - no-negated-condition: 2 - no-nested-ternary: 2 - no-object-constructor: 2 no-restricted-syntax: [ 'error', { @@ -140,59 +88,108 @@ rules: message: 'A textdomain needs to be provided for translation calls.', } ] + no-return-assign: 2 + no-script-url: 2 + no-shadow: [ 2, { "builtinGlobals": false, "hoist": "all", "allow": [ ] } ] + no-undef-init: 2 + no-undefined: 2 + no-unneeded-ternary: 2 + no-unused-expressions: 2 + no-useless-call: 2 + no-useless-concat: 2 + no-void: 2 + no-warning-comments: [ 2, { "terms": [ "todo" ], "location": "anywhere" } ] + prefer-const: 2 + radix: 2 + strict: 2 + + # Plugin: Stylistic rules (https://eslint.style/packages/default). + array-bracket-spacing: [ 2, always ] + block-spacing: 2 + brace-style: [ 2, 1tbs ] + comma-dangle: [ 2, "always-multiline" ] + comma-spacing: 2 + comma-style: 2 + computed-property-spacing: [ 2, always ] + eol-last: 2 func-call-spacing: 2 + indent: [ 2, tab, { "SwitchCase": 1 } ] + jsx-quotes: 2 + key-spacing: 2 + keyword-spacing: 2 + linebreak-style: 2 + max-len: [ 2, 150, 4 ] + new-parens: 2 + no-extra-semi: 2 + no-mixed-spaces-and-tabs: [ 2, "smart-tabs" ] + no-multiple-empty-lines: 2 no-trailing-spaces: 2 - no-unneeded-ternary: 2 no-whitespace-before-property: 2 - object-curly-spacing: [2, "always"] + object-curly-spacing: [ 2, "always" ] operator-linebreak: 2 - padded-blocks: [2, "never"] - quote-props: [2, "as-needed", {"keywords": true}] - quotes: [2, double, avoid-escape] - require-jsdoc: [2, {"require": {"MethodDefinition": true, "ClassDeclaration": true, "ArrowFunctionExpression": true, "FunctionExpression": true}}] + padded-blocks: [ 2, "never" ] + quote-props: [ 2, "as-needed", { "keywords": true } ] + quotes: [ 2, double, avoid-escape ] semi-spacing: 2 semi: 2 space-before-blocks: 2 - space-before-function-paren: [2, "never"] - space-in-parens: [2, "always", {"exceptions": ["empty"]}] + space-before-function-paren: [ 2, "never" ] + space-in-parens: [ 2, "always", { "exceptions": [ "empty" ] } ] space-infix-ops: 2 - space-unary-ops: [2, {"words": false, "nonwords": false, "overrides": { "!": true }}] - spaced-comment: [2, "always"] + space-unary-ops: [ 2, { "words": false, "nonwords": false, "overrides": { "!": true } } ] + spaced-comment: [ 2, "always" ] + wrap-iife: 2 + + # Plugin: JSDoc rules (https://github.com/gajus/eslint-plugin-jsdoc) + require-jsdoc: [ 2, { "require": { "MethodDefinition": true, "ClassDeclaration": true, "ArrowFunctionExpression": true, "FunctionExpression": true } } ] + valid-jsdoc: [ 2, { + "prefer": { + "return": "returns" + } + } ] + + # Plugin: Node rules (https://github.com/eslint-community/eslint-plugin-n) + callback-return: 2 + global-require: 2 + handle-callback-err: 2 + no-mixed-requires: 2 + no-path-concat: 2 + no-process-exit: 2 + - # Accessibility rules. https://github.com/evcohen/eslint-plugin-jsx-a11y + # Plugin: jsx-a11y rules (https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). # Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. - jsx-a11y/label-has-for: [2, { "required": "id" } ] + jsx-a11y/label-has-for: [ 2, { "required": "id" } ] - # React plugins settings (https://github.com/yannickcr/eslint-plugin-react/tree/master/docs/rules) - react/jsx-tag-spacing: [2, {"beforeClosing": "never"}] - react/jsx-pascal-case: 2 - react/jsx-no-bind: 2 - react/jsx-max-props-per-line: [2, {"maximum": 6}] # A high maximum to make sure it is always a smell when it occurs. - react/jsx-max-depth: [2, {"max": 8}] # A high maximum to make sure it is always a smell when it occurs. - react/jsx-indent-props: [2, "tab"] - react/jsx-indent: [2, "tab"] - react/jsx-first-prop-new-line: [2, "multiline"] + # Plugin: React rules (https://github.com/jsx-eslint/eslint-plugin-react) + react/boolean-prop-naming: 2 + react/button-has-type: 0 # See https://github.com/yannickcr/eslint-plugin-react/issues/1555 + react/default-props-match-prop-types: 2 + react/forbid-foreign-prop-types: 2 + react/jsx-boolean-value: [ 2, "always" ] + react/jsx-closing-bracket-location: [ 2, "line-aligned" ] + react/jsx-curly-spacing: [ 2, { "when": "always", "children": true } ] react/jsx-equals-spacing: 2 - react/jsx-curly-spacing: [2, {"when": "always", "children": true}] - react/jsx-closing-bracket-location: [2, "line-aligned"] - react/jsx-boolean-value: [2, "always"] - - react/void-dom-elements-no-children: 2 - react/self-closing-comp: 2 - react/require-default-props: [2, { "ignoreFunctionalComponents": true }] - react/prefer-es6-class: 2 - react/no-unused-state: 2 - react/no-unused-prop-types: 2 + react/jsx-first-prop-new-line: [ 2, "multiline" ] + react/jsx-indent-props: [ 2, "tab" ] + react/jsx-indent: [ 2, "tab" ] + react/jsx-max-depth: [ 2, { "max": 8 } ] # A high maximum to make sure it is always a smell when it occurs. + react/jsx-max-props-per-line: [ 2, { "maximum": 6 } ] # A high maximum to make sure it is always a smell when it occurs. + react/jsx-no-bind: 2 + react/jsx-pascal-case: 2 + react/jsx-tag-spacing: [ 2, { "beforeClosing": "never" } ] + react/no-access-state-in-setstate: 2 + react/no-redundant-should-component-update: 2 + react/no-render-return-value: 2 react/no-this-in-sfc: 2 react/no-typos: 2 - react/no-render-return-value: 2 - react/no-redundant-should-component-update: 2 - react/no-access-state-in-setstate: 2 - react/forbid-foreign-prop-types: 2 - react/default-props-match-prop-types: 2 - react/button-has-type: 0 # See https://github.com/yannickcr/eslint-plugin-react/issues/1555 - react/boolean-prop-naming: 2 + react/no-unused-prop-types: 2 + react/no-unused-state: 2 + react/prefer-es6-class: 2 + react/require-default-props: [ 2, { "ignoreFunctionalComponents": true } ] + react/self-closing-comp: 2 + react/void-dom-elements-no-children: 2 - # Import rules (https://github.com/import-js/eslint-plugin-import) + # Plugin: Import rules (https://github.com/import-js/eslint-plugin-import) import/no-extraneous-dependencies: 2 import/no-unresolved: 2 From 929705c710e9a8e8d26e18ebfc6160de02c4a3fd Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:33:16 +0100 Subject: [PATCH 19/92] Replace 1 and 2 with warn and error This is more clear than the integer values, but changes nothing else --- packages/eslint/default.yml | 258 ++++++++++++++++++------------------ 1 file changed, 129 insertions(+), 129 deletions(-) diff --git a/packages/eslint/default.yml b/packages/eslint/default.yml index 6b0542bcd2d..98e6e0d73e9 100644 --- a/packages/eslint/default.yml +++ b/packages/eslint/default.yml @@ -25,52 +25,52 @@ plugins: rules: # Native ESLint rules ## ESLint "Possible problems - These rules relate to possible logic errors in code:" (https://eslint.org/docs/latest/rules/#possible-problems). - no-inner-declarations: [ 2, "functions" ] - no-self-compare: 2 - no-use-before-define: 2 + no-inner-declarations: [ error, "functions" ] + no-self-compare: error + no-use-before-define: error ## ESLint "Suggestions - These rules suggest alternate ways of doing things:" (https://eslint.org/docs/latest/rules/#suggestions). - accessor-pairs: 2 - camelcase: 2 - complexity: [ 2, 10 ] - consistent-this: 2 - curly: 2 - dot-notation: 2 - eqeqeq: 2 - guard-for-in: 2 - max-depth: 2 - max-nested-callbacks: 2 - max-statements: [ 2, 30 ] - new-cap: 2 - no-alert: 2 - no-array-constructor: 2 - no-bitwise: 2 - no-caller: 2 - no-console: [ 1, { allow: [ "warn", "error", "trace" ] } ] - no-div-regex: 2 - no-else-return: 2 - no-eq-null: 2 - no-eval: 2 - no-extend-native: 2 - no-extra-bind: 2 - no-implied-eval: 2 - no-inline-comments: 2 - no-iterator: 2 - no-label-var: 2 - no-labels: 2 - no-lone-blocks: 2 - no-loop-func: 2 - no-multi-str: 2 - no-negated-condition: 2 - no-nested-ternary: 2 - no-new-func: 2 - no-new-wrappers: 2 - no-new: 2 - no-object-constructor: 2 - no-octal-escape: 2 - no-proto: 2 + accessor-pairs: error + camelcase: error + complexity: [ error, 10 ] + consistent-this: error + curly: error + dot-notation: error + eqeqeq: error + guard-for-in: error + max-depth: error + max-nested-callbacks: error + max-statements: [ error, 30 ] + new-cap: error + no-alert: error + no-array-constructor: error + no-bitwise: error + no-caller: error + no-console: [ warn, { allow: [ "warn", "error", "trace" ] } ] + no-div-regex: error + no-else-return: error + no-eq-null: error + no-eval: error + no-extend-native: error + no-extra-bind: error + no-implied-eval: error + no-inline-comments: error + no-iterator: error + no-label-var: error + no-labels: error + no-lone-blocks: error + no-loop-func: error + no-multi-str: error + no-negated-condition: error + no-nested-ternary: error + no-new-func: error + no-new-wrappers: error + no-new: error + no-object-constructor: error + no-octal-escape: error + no-proto: error no-restricted-syntax: [ - 'error', + error, { selector: 'CallExpression[callee.name=/^(__)$/][arguments.length!=2]', message: 'A textdomain needs to be provided for translation calls.', @@ -88,108 +88,108 @@ rules: message: 'A textdomain needs to be provided for translation calls.', } ] - no-return-assign: 2 - no-script-url: 2 - no-shadow: [ 2, { "builtinGlobals": false, "hoist": "all", "allow": [ ] } ] - no-undef-init: 2 - no-undefined: 2 - no-unneeded-ternary: 2 - no-unused-expressions: 2 - no-useless-call: 2 - no-useless-concat: 2 - no-void: 2 - no-warning-comments: [ 2, { "terms": [ "todo" ], "location": "anywhere" } ] - prefer-const: 2 - radix: 2 - strict: 2 + no-return-assign: error + no-script-url: error + no-shadow: [ error, { "builtinGlobals": false, "hoist": "all", "allow": [ ] } ] + no-undef-init: error + no-undefined: error + no-unneeded-ternary: error + no-unused-expressions: error + no-useless-call: error + no-useless-concat: error + no-void: error + no-warning-comments: [ error, { "terms": [ "todo" ], "location": "anywhere" } ] + prefer-const: error + radix: error + strict: error # Plugin: Stylistic rules (https://eslint.style/packages/default). - array-bracket-spacing: [ 2, always ] - block-spacing: 2 - brace-style: [ 2, 1tbs ] - comma-dangle: [ 2, "always-multiline" ] - comma-spacing: 2 - comma-style: 2 - computed-property-spacing: [ 2, always ] - eol-last: 2 - func-call-spacing: 2 - indent: [ 2, tab, { "SwitchCase": 1 } ] - jsx-quotes: 2 - key-spacing: 2 - keyword-spacing: 2 - linebreak-style: 2 - max-len: [ 2, 150, 4 ] - new-parens: 2 - no-extra-semi: 2 - no-mixed-spaces-and-tabs: [ 2, "smart-tabs" ] - no-multiple-empty-lines: 2 - no-trailing-spaces: 2 - no-whitespace-before-property: 2 - object-curly-spacing: [ 2, "always" ] - operator-linebreak: 2 - padded-blocks: [ 2, "never" ] - quote-props: [ 2, "as-needed", { "keywords": true } ] - quotes: [ 2, double, avoid-escape ] - semi-spacing: 2 - semi: 2 - space-before-blocks: 2 - space-before-function-paren: [ 2, "never" ] - space-in-parens: [ 2, "always", { "exceptions": [ "empty" ] } ] - space-infix-ops: 2 - space-unary-ops: [ 2, { "words": false, "nonwords": false, "overrides": { "!": true } } ] - spaced-comment: [ 2, "always" ] - wrap-iife: 2 + array-bracket-spacing: [ error, always ] + block-spacing: error + brace-style: [ error, 1tbs ] + comma-dangle: [ error, "always-multiline" ] + comma-spacing: error + comma-style: error + computed-property-spacing: [ error, always ] + eol-last: error + func-call-spacing: error + indent: [ error, tab, { "SwitchCase": 1 } ] + jsx-quotes: error + key-spacing: error + keyword-spacing: error + linebreak-style: error + max-len: [ error, 150, 4 ] + new-parens: error + no-extra-semi: error + no-mixed-spaces-and-tabs: [ error, "smart-tabs" ] + no-multiple-empty-lines: error + no-trailing-spaces: error + no-whitespace-before-property: error + object-curly-spacing: [ error, "always" ] + operator-linebreak: error + padded-blocks: [ error, "never" ] + quote-props: [ error, "as-needed", { "keywords": true } ] + quotes: [ error, double, avoid-escape ] + semi-spacing: error + semi: error + space-before-blocks: error + space-before-function-paren: [ error, "never" ] + space-in-parens: [ error, "always", { "exceptions": [ "empty" ] } ] + space-infix-ops: error + space-unary-ops: [ error, { "words": false, "nonwords": false, "overrides": { "!": true } } ] + spaced-comment: [ error, "always" ] + wrap-iife: error # Plugin: JSDoc rules (https://github.com/gajus/eslint-plugin-jsdoc) - require-jsdoc: [ 2, { "require": { "MethodDefinition": true, "ClassDeclaration": true, "ArrowFunctionExpression": true, "FunctionExpression": true } } ] - valid-jsdoc: [ 2, { + require-jsdoc: [ error, { "require": { "MethodDefinition": true, "ClassDeclaration": true, "ArrowFunctionExpression": true, "FunctionExpression": true } } ] + valid-jsdoc: [ error, { "prefer": { "return": "returns" } } ] # Plugin: Node rules (https://github.com/eslint-community/eslint-plugin-n) - callback-return: 2 - global-require: 2 - handle-callback-err: 2 - no-mixed-requires: 2 - no-path-concat: 2 - no-process-exit: 2 + callback-return: error + global-require: error + handle-callback-err: error + no-mixed-requires: error + no-path-concat: error + no-process-exit: error # Plugin: jsx-a11y rules (https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). # Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. - jsx-a11y/label-has-for: [ 2, { "required": "id" } ] + jsx-a11y/label-has-for: [ error, { "required": "id" } ] # Plugin: React rules (https://github.com/jsx-eslint/eslint-plugin-react) - react/boolean-prop-naming: 2 + react/boolean-prop-naming: error react/button-has-type: 0 # See https://github.com/yannickcr/eslint-plugin-react/issues/1555 - react/default-props-match-prop-types: 2 - react/forbid-foreign-prop-types: 2 - react/jsx-boolean-value: [ 2, "always" ] - react/jsx-closing-bracket-location: [ 2, "line-aligned" ] - react/jsx-curly-spacing: [ 2, { "when": "always", "children": true } ] - react/jsx-equals-spacing: 2 - react/jsx-first-prop-new-line: [ 2, "multiline" ] - react/jsx-indent-props: [ 2, "tab" ] - react/jsx-indent: [ 2, "tab" ] - react/jsx-max-depth: [ 2, { "max": 8 } ] # A high maximum to make sure it is always a smell when it occurs. - react/jsx-max-props-per-line: [ 2, { "maximum": 6 } ] # A high maximum to make sure it is always a smell when it occurs. - react/jsx-no-bind: 2 - react/jsx-pascal-case: 2 - react/jsx-tag-spacing: [ 2, { "beforeClosing": "never" } ] - react/no-access-state-in-setstate: 2 - react/no-redundant-should-component-update: 2 - react/no-render-return-value: 2 - react/no-this-in-sfc: 2 - react/no-typos: 2 - react/no-unused-prop-types: 2 - react/no-unused-state: 2 - react/prefer-es6-class: 2 - react/require-default-props: [ 2, { "ignoreFunctionalComponents": true } ] - react/self-closing-comp: 2 - react/void-dom-elements-no-children: 2 + react/default-props-match-prop-types: error + react/forbid-foreign-prop-types: error + react/jsx-boolean-value: [ error, "always" ] + react/jsx-closing-bracket-location: [ error, "line-aligned" ] + react/jsx-curly-spacing: [ error, { "when": "always", "children": true } ] + react/jsx-equals-spacing: error + react/jsx-first-prop-new-line: [ error, "multiline" ] + react/jsx-indent-props: [ error, "tab" ] + react/jsx-indent: [ error, "tab" ] + react/jsx-max-depth: [ error, { "max": 8 } ] # A high maximum to make sure it is always a smell when it occurs. + react/jsx-max-props-per-line: [ error, { "maximum": 6 } ] # A high maximum to make sure it is always a smell when it occurs. + react/jsx-no-bind: error + react/jsx-pascal-case: error + react/jsx-tag-spacing: [ error, { "beforeClosing": "never" } ] + react/no-access-state-in-setstate: error + react/no-redundant-should-component-update: error + react/no-render-return-value: error + react/no-this-in-sfc: error + react/no-typos: error + react/no-unused-prop-types: error + react/no-unused-state: error + react/prefer-es6-class: error + react/require-default-props: [ error, { "ignoreFunctionalComponents": true } ] + react/self-closing-comp: error + react/void-dom-elements-no-children: error # Plugin: Import rules (https://github.com/import-js/eslint-plugin-import) - import/no-extraneous-dependencies: 2 - import/no-unresolved: 2 + import/no-extraneous-dependencies: error + import/no-unresolved: error From 4bae9a25ea6b3c4f9c31e5630471954904d145b4 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:05:13 +0100 Subject: [PATCH 20/92] Update URLs refering to the old location of the package --- packages/eslint/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eslint/package.json b/packages/eslint/package.json index ccb8cbd12cf..7c6ec71fa6d 100644 --- a/packages/eslint/package.json +++ b/packages/eslint/package.json @@ -14,15 +14,15 @@ ], "repository": { "type": "git", - "url": "https://github.com/Yoast/javascript.git", + "url": "https://github.com/Yoast/wordpress-seo.git", "directory": "packages/eslint" }, "author": "Team Yoast ", "license": "GPL-3.0", "bugs": { - "url": "https://github.com/Yoast/eslint/issues" + "url": "https://github.com/Yoast/wordpress-seo/issues" }, - "homepage": "https://github.com/Yoast/eslint#readme", + "homepage": "https://github.com/Yoast/wordpress-seo/tree/main/packages/eslint", "dependencies": { "js-yaml": "^3.6.0" }, From 9ff8a34b89fc2b140c8a1bf1b0cae8cc1b88e420 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:05:48 +0100 Subject: [PATCH 21/92] Add plugins that the config uses as dependencies As recommended by https://eslint.org/docs/latest/extend/shareable-configs#publishing-a-shareable-config --- packages/eslint/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eslint/package.json b/packages/eslint/package.json index 7c6ec71fa6d..0c0dd73d096 100644 --- a/packages/eslint/package.json +++ b/packages/eslint/package.json @@ -24,11 +24,11 @@ }, "homepage": "https://github.com/Yoast/wordpress-seo/tree/main/packages/eslint", "dependencies": { + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "eslint-plugin-react": "^7.35.0", "js-yaml": "^3.6.0" }, "peerDependencies": { - "eslint-plugin-import": ">=2.27.5", - "eslint-plugin-jsx-a11y": ">=6.1.1", - "eslint-plugin-react": ">=7.11.1" } } From 61c5adb6e8e7c7af0b2d340d5a5e8865b7e6102e Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:12:01 +0100 Subject: [PATCH 22/92] Update shared preset to a flat config --- packages/eslint/default.mjs | 215 +++++++++++++++++++++ packages/eslint/default.yml | 195 ------------------- packages/eslint/index.js | 35 ---- packages/eslint/package.json | 12 +- yarn.lock | 354 +++++++++++++++++++++++++++++++++-- 5 files changed, 559 insertions(+), 252 deletions(-) create mode 100644 packages/eslint/default.mjs delete mode 100644 packages/eslint/default.yml delete mode 100644 packages/eslint/index.js diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs new file mode 100644 index 00000000000..10595d4b4ae --- /dev/null +++ b/packages/eslint/default.mjs @@ -0,0 +1,215 @@ +import globals from "globals"; +import js from "@eslint/js"; +import reactPlugin from "eslint-plugin-react"; +import jsxA11YPlugin from "eslint-plugin-jsx-a11y"; +import jsdocPlugin from "eslint-plugin-jsdoc"; +import nodePlugin from "eslint-plugin-n"; +import importPlugin from "eslint-plugin-import"; +import stylisticPlugin from "@stylistic/eslint-plugin"; + +export default [ + js.configs.recommended, + reactPlugin.configs.flat.recommended, + jsxA11YPlugin.flatConfigs.recommended, + importPlugin.flatConfigs.recommended, + { + plugins: { + jsdoc: jsdocPlugin, + node: nodePlugin, + stylistic: stylisticPlugin, + }, + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.amd, + ...globals.browser, + ...globals.jquery, + ...globals.node, + }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + + // https://eslint.org/docs/rules/ + rules: { + // Native ESLint rules + // - ESLint "Possible problems - These rules relate to possible logic errors in code:" (https://eslint.org/docs/latest/rules/#possible-problems). + "no-inner-declarations": [ "error", "functions" ], + "no-self-compare": "error", + "no-use-before-define": "error", + + // - ESLint "Suggestions - These rules suggest alternate ways of doing things:" (https://eslint.org/docs/latest/rules/#suggestions). + "accessor-pairs": "error", + camelcase: "error", + complexity: [ "error", 10 ], + "consistent-this": "error", + curly: "error", + "dot-notation": "error", + eqeqeq: "error", + "guard-for-in": "error", + "max-depth": "error", + "max-nested-callbacks": "error", + "max-statements": [ "error", 30 ], + "new-cap": "error", + "no-alert": "error", + "no-array-constructor": "error", + "no-bitwise": "error", + "no-caller": "error", + "no-console": [ "warn", { allow: [ "warn", "error", "trace" ], } ], + "no-div-regex": "error", + "no-else-return": "error", + "no-eq-null": "error", + "no-eval": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-implied-eval": "error", + "no-inline-comments": "error", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": "error", + "no-lone-blocks": "error", + "no-loop-func": "error", + "no-multi-str": "error", + "no-negated-condition": "error", + "no-nested-ternary": "error", + "no-new-func": "error", + "no-new-wrappers": "error", + "no-new": "error", + "no-object-constructor": "error", + "no-octal-escape": "error", + "no-proto": "error", + "no-restricted-syntax": [ + "error", + { + selector: "CallExpression[callee.name=/^(__)$/][arguments.length!=2]", + message: "A textdomain needs to be provided for translation calls.", + }, { + selector: "CallExpression[callee.name=/^(_x)$/][arguments.length!=3]", + message: "A textdomain needs to be provided for translation calls.", + }, { + selector: "CallExpression[callee.name=/^(_n)$/][arguments.length!=4]", + message: "A textdomain needs to be provided for translation calls.", + }, { + selector: "CallExpression[callee.name=/^(_nx)$/][arguments.length!=5]", + message: "A textdomain needs to be provided for translation calls.", + } + ], + "no-return-assign": "error", + "no-script-url": "error", + "no-shadow": [ "error", { builtinGlobals: false, hoist: "all", allow: [], } ], + "no-undef-init": "error", + "no-undefined": "error", + "no-unneeded-ternary": "error", + "no-unused-expressions": "error", + "no-useless-call": "error", + "no-useless-concat": "error", + "no-void": "error", + "no-warning-comments": [ "error", { terms: [ "todo" ], location: "anywhere", } ], + "prefer-const": "error", + radix: "error", + strict: "error", + + // Plugin: Stylistic rules (https://eslint.style/packages/default). + "stylistic/array-bracket-spacing": [ "error", "always" ], + "stylistic/block-spacing": "error", + "stylistic/brace-style": [ "error", "1tbs" ], + "stylistic/comma-dangle": [ "error", "always-multiline" ], + "stylistic/comma-spacing": "error", + "stylistic/comma-style": "error", + "stylistic/computed-property-spacing": [ "error", "always" ], + "stylistic/eol-last": "error", + "stylistic/func-call-spacing": "error", + "stylistic/indent": [ "error", "tab", { SwitchCase: 1, } ], + "stylistic/jsx-quotes": "error", + "stylistic/key-spacing": "error", + "stylistic/keyword-spacing": "error", + "stylistic/linebreak-style": "error", + "stylistic/max-len": [ "error", 4 ], + "stylistic/new-parens": "error", + "stylistic/no-extra-semi": "error", + "stylistic/no-mixed-spaces-and-tabs": [ "error", "smart-tabs" ], + "stylistic/no-multiple-empty-lines": "error", + "stylistic/no-trailing-spaces": "error", + "stylistic/no-whitespace-before-property": "error", + "stylistic/object-curly-spacing": [ "error", "always" ], + "stylistic/operator-linebreak": "error", + "stylistic/padded-blocks": [ "error", "never" ], + "stylistic/quote-props": [ "error", "as-needed", { keywords: true, } ], + "stylistic/quotes": [ "error", "double", "avoid-escape" ], + "stylistic/semi-spacing": "error", + "stylistic/semi": "error", + "stylistic/space-before-blocks": "error", + "stylistic/space-before-function-paren": [ "error", "never" ], + "stylistic/space-in-parens": [ "error", "always", { exceptions: [ "empty" ], } ], + "stylistic/space-infix-ops": "error", + "stylistic/space-unary-ops": [ "error", { words: false, nonwords: false, overrides: { "!": true, }, } ], + "stylistic/spaced-comment": [ "error", "always" ], + "stylistic/wrap-iife": "error", + + // Plugin: JSDoc rules (https://github.com/gajus/eslint-plugin-jsdoc) + "jsdoc/require-jsdoc": [ "error", { + require: { + MethodDefinition: true, + ClassDeclaration: true, + ArrowFunctionExpression: true, + FunctionExpression: true, + }, + } ], + "jsdoc/require-returns": "error", + + // Plugin: Node rules (https://github.com/eslint-community/eslint-plugin-n) + "node/callback-return": "error", + "node/global-require": "error", + "node/handle-callback-err": "error", + "node/no-mixed-requires": "error", + "node/no-path-concat": "error", + "node/no-process-exit": "error", + + // Plugin: jsx-a11y rules (https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). + // Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. + "jsx-a11y/label-has-for": [ "error", { required: "id", } ], + + // Plugin: React rules (https://github.com/jsx-eslint/eslint-plugin-react) + "react/boolean-prop-naming": "error", + "react/button-has-type": 0, + "react/default-props-match-prop-types": "error", + "react/forbid-foreign-prop-types": "error", + "react/jsx-boolean-value": [ "error", "always" ], + "react/jsx-closing-bracket-location": [ "error", "line-aligned" ], + "react/jsx-curly-spacing": [ "error", { when: "always", children: true, } ], + "react/jsx-equals-spacing": "error", + "react/jsx-first-prop-new-line": [ "error", "multiline" ], + "react/jsx-indent-props": [ "error", "tab" ], + "react/jsx-indent": [ "error", "tab" ], + "react/jsx-max-depth": [ "error", { max: 8, } ], + "react/jsx-max-props-per-line": [ "error", { maximum: 6, } ], + "react/jsx-no-bind": "error", + "react/jsx-pascal-case": "error", + "react/jsx-tag-spacing": [ "error", { beforeClosing: "never", } ], + "react/no-access-state-in-setstate": "error", + "react/no-redundant-should-component-update": "error", + "react/no-render-return-value": "error", + "react/no-this-in-sfc": "error", + "react/no-typos": "error", + "react/no-unused-prop-types": "error", + "react/no-unused-state": "error", + "react/prefer-es6-class": "error", + "react/require-default-props": [ "error", { ignoreFunctionalComponents: true, } ], + "react/self-closing-comp": "error", + "react/void-dom-elements-no-children": "error", + + // Plugin: Import rules (https://github.com/import-js/eslint-plugin-import) + "import/no-extraneous-dependencies": "error", + "import/no-unresolved": "error", + }, + "settings": { + "jsdoc": { + "tagNamePreference": { + "return": "returns" + } + } + } + } ]; diff --git a/packages/eslint/default.yml b/packages/eslint/default.yml deleted file mode 100644 index 98e6e0d73e9..00000000000 --- a/packages/eslint/default.yml +++ /dev/null @@ -1,195 +0,0 @@ -extends: - - "eslint:recommended" - - "plugin:react/recommended" - - "plugin:jsx-a11y/recommended" - - "plugin:import/recommended" - -parserOptions: - ecmaVersion: 2017 - ecmaFeatures: - jsx: true - sourceType: "module" - -env: - amd: true - browser: true - es6: true - jquery: true - node: true - -plugins: - - react - - "jsx-a11y" - -# http://eslint.org/docs/rules/ -rules: - # Native ESLint rules - ## ESLint "Possible problems - These rules relate to possible logic errors in code:" (https://eslint.org/docs/latest/rules/#possible-problems). - no-inner-declarations: [ error, "functions" ] - no-self-compare: error - no-use-before-define: error - - ## ESLint "Suggestions - These rules suggest alternate ways of doing things:" (https://eslint.org/docs/latest/rules/#suggestions). - accessor-pairs: error - camelcase: error - complexity: [ error, 10 ] - consistent-this: error - curly: error - dot-notation: error - eqeqeq: error - guard-for-in: error - max-depth: error - max-nested-callbacks: error - max-statements: [ error, 30 ] - new-cap: error - no-alert: error - no-array-constructor: error - no-bitwise: error - no-caller: error - no-console: [ warn, { allow: [ "warn", "error", "trace" ] } ] - no-div-regex: error - no-else-return: error - no-eq-null: error - no-eval: error - no-extend-native: error - no-extra-bind: error - no-implied-eval: error - no-inline-comments: error - no-iterator: error - no-label-var: error - no-labels: error - no-lone-blocks: error - no-loop-func: error - no-multi-str: error - no-negated-condition: error - no-nested-ternary: error - no-new-func: error - no-new-wrappers: error - no-new: error - no-object-constructor: error - no-octal-escape: error - no-proto: error - no-restricted-syntax: [ - error, - { - selector: 'CallExpression[callee.name=/^(__)$/][arguments.length!=2]', - message: 'A textdomain needs to be provided for translation calls.', - }, - { - selector: 'CallExpression[callee.name=/^(_x)$/][arguments.length!=3]', - message: 'A textdomain needs to be provided for translation calls.', - }, - { - selector: 'CallExpression[callee.name=/^(_n)$/][arguments.length!=4]', - message: 'A textdomain needs to be provided for translation calls.', - }, - { - selector: 'CallExpression[callee.name=/^(_nx)$/][arguments.length!=5]', - message: 'A textdomain needs to be provided for translation calls.', - } - ] - no-return-assign: error - no-script-url: error - no-shadow: [ error, { "builtinGlobals": false, "hoist": "all", "allow": [ ] } ] - no-undef-init: error - no-undefined: error - no-unneeded-ternary: error - no-unused-expressions: error - no-useless-call: error - no-useless-concat: error - no-void: error - no-warning-comments: [ error, { "terms": [ "todo" ], "location": "anywhere" } ] - prefer-const: error - radix: error - strict: error - - # Plugin: Stylistic rules (https://eslint.style/packages/default). - array-bracket-spacing: [ error, always ] - block-spacing: error - brace-style: [ error, 1tbs ] - comma-dangle: [ error, "always-multiline" ] - comma-spacing: error - comma-style: error - computed-property-spacing: [ error, always ] - eol-last: error - func-call-spacing: error - indent: [ error, tab, { "SwitchCase": 1 } ] - jsx-quotes: error - key-spacing: error - keyword-spacing: error - linebreak-style: error - max-len: [ error, 150, 4 ] - new-parens: error - no-extra-semi: error - no-mixed-spaces-and-tabs: [ error, "smart-tabs" ] - no-multiple-empty-lines: error - no-trailing-spaces: error - no-whitespace-before-property: error - object-curly-spacing: [ error, "always" ] - operator-linebreak: error - padded-blocks: [ error, "never" ] - quote-props: [ error, "as-needed", { "keywords": true } ] - quotes: [ error, double, avoid-escape ] - semi-spacing: error - semi: error - space-before-blocks: error - space-before-function-paren: [ error, "never" ] - space-in-parens: [ error, "always", { "exceptions": [ "empty" ] } ] - space-infix-ops: error - space-unary-ops: [ error, { "words": false, "nonwords": false, "overrides": { "!": true } } ] - spaced-comment: [ error, "always" ] - wrap-iife: error - - # Plugin: JSDoc rules (https://github.com/gajus/eslint-plugin-jsdoc) - require-jsdoc: [ error, { "require": { "MethodDefinition": true, "ClassDeclaration": true, "ArrowFunctionExpression": true, "FunctionExpression": true } } ] - valid-jsdoc: [ error, { - "prefer": { - "return": "returns" - } - } ] - - # Plugin: Node rules (https://github.com/eslint-community/eslint-plugin-n) - callback-return: error - global-require: error - handle-callback-err: error - no-mixed-requires: error - no-path-concat: error - no-process-exit: error - - - # Plugin: jsx-a11y rules (https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). - # Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. - jsx-a11y/label-has-for: [ error, { "required": "id" } ] - - # Plugin: React rules (https://github.com/jsx-eslint/eslint-plugin-react) - react/boolean-prop-naming: error - react/button-has-type: 0 # See https://github.com/yannickcr/eslint-plugin-react/issues/1555 - react/default-props-match-prop-types: error - react/forbid-foreign-prop-types: error - react/jsx-boolean-value: [ error, "always" ] - react/jsx-closing-bracket-location: [ error, "line-aligned" ] - react/jsx-curly-spacing: [ error, { "when": "always", "children": true } ] - react/jsx-equals-spacing: error - react/jsx-first-prop-new-line: [ error, "multiline" ] - react/jsx-indent-props: [ error, "tab" ] - react/jsx-indent: [ error, "tab" ] - react/jsx-max-depth: [ error, { "max": 8 } ] # A high maximum to make sure it is always a smell when it occurs. - react/jsx-max-props-per-line: [ error, { "maximum": 6 } ] # A high maximum to make sure it is always a smell when it occurs. - react/jsx-no-bind: error - react/jsx-pascal-case: error - react/jsx-tag-spacing: [ error, { "beforeClosing": "never" } ] - react/no-access-state-in-setstate: error - react/no-redundant-should-component-update: error - react/no-render-return-value: error - react/no-this-in-sfc: error - react/no-typos: error - react/no-unused-prop-types: error - react/no-unused-state: error - react/prefer-es6-class: error - react/require-default-props: [ error, { "ignoreFunctionalComponents": true } ] - react/self-closing-comp: error - react/void-dom-elements-no-children: error - - # Plugin: Import rules (https://github.com/import-js/eslint-plugin-import) - import/no-extraneous-dependencies: error - import/no-unresolved: error diff --git a/packages/eslint/index.js b/packages/eslint/index.js deleted file mode 100644 index c11d5a4dc66..00000000000 --- a/packages/eslint/index.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @fileoverview Converts YAML file into JSON. - * @author Nicholas C. Zakas - */ - - -// ------------------------------------------------------------------------------ -// Requirements -// ------------------------------------------------------------------------------ - -var fs = require( "fs" ), - path = require( "path" ), - yaml = require( "js-yaml" ); - -// ------------------------------------------------------------------------------ -// Bootstrapping -// ------------------------------------------------------------------------------ - -var filePath = path.resolve( __dirname, "./default.yml" ), - config; - -try { - config = yaml.safeLoad( fs.readFileSync( filePath, "utf8" ) ) || {}; -} catch ( e ) { - console.error( "Error reading YAML file: " + filePath ); - e.message = "Cannot read config file: " + filePath + "\nError: " + e.message; - throw e; -} - - -// ------------------------------------------------------------------------------ -// Public Interface -// ------------------------------------------------------------------------------ - -module.exports = config; diff --git a/packages/eslint/package.json b/packages/eslint/package.json index 0c0dd73d096..e805b176dff 100644 --- a/packages/eslint/package.json +++ b/packages/eslint/package.json @@ -7,10 +7,9 @@ "eslint", "eslintconfig" ], - "main": "index.js", + "main": "default.mjs", "files": [ - "index.js", - "default.yml" + "default.mjs" ], "repository": { "type": "git", @@ -24,11 +23,16 @@ }, "homepage": "https://github.com/Yoast/wordpress-seo/tree/main/packages/eslint", "dependencies": { + "@eslint/js": "^9.14.0", + "@stylistic/eslint-plugin": "^2.11.0", "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.5.0", "eslint-plugin-jsx-a11y": "^6.10.2", + "eslint-plugin-n": "^17.13.1", "eslint-plugin-react": "^7.35.0", - "js-yaml": "^3.6.0" + "globals": "^15.12.0" }, "peerDependencies": { + "eslint": "^8.57 || >= 9" } } diff --git a/yarn.lock b/yarn.lock index f20d2c35353..c9826d80202 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2739,6 +2739,15 @@ esquery "^1.5.0" jsdoc-type-pratt-parser "~4.0.0" +"@es-joy/jsdoccomment@~0.49.0": + version "0.49.0" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.49.0.tgz#e5ec1eda837c802eca67d3b29e577197f14ba1db" + integrity sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q== + dependencies: + comment-parser "1.4.1" + esquery "^1.6.0" + jsdoc-type-pratt-parser "~4.1.0" + "@esbuild/aix-ppc64@0.23.1": version "0.23.1" resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz#51299374de171dbd80bb7d838e1cfce9af36f353" @@ -2969,6 +2978,13 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz#81fd50d11e2c32b2d6241470e3185b70c7b30699" integrity sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg== +"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.4.1": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== + dependencies: + eslint-visitor-keys "^3.4.3" + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -2976,6 +2992,11 @@ dependencies: eslint-visitor-keys "^3.3.0" +"@eslint-community/regexpp@^4.11.0": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + "@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": version "4.10.0" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" @@ -3021,6 +3042,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@^9.14.0": + version "9.14.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.14.0.tgz#2347a871042ebd11a00fd8c2d3d56a265ee6857e" + integrity sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg== + "@fal-works/esbuild-plugin-global-externals@^2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz#c05ed35ad82df8e6ac616c68b92c2282bd083ba4" @@ -4819,6 +4845,11 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + "@pkgr/utils@^2.3.1": version "2.4.2" resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" @@ -6326,6 +6357,17 @@ estraverse "^5.3.0" picomatch "^4.0.2" +"@stylistic/eslint-plugin@^2.11.0": + version "2.11.0" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-2.11.0.tgz#50d0289f36f7201055b7fa1729fdc1d8c46e93fa" + integrity sha512-PNRHbydNG5EH8NK4c+izdJlxajIR6GxcUhzsYNRsn6Myep4dsZt0qFCz3rCPnkvgO5FYibDcMqgNHUT+zvjYZw== + dependencies: + "@typescript-eslint/utils" "^8.13.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + estraverse "^5.3.0" + picomatch "^4.0.2" + "@svgr/babel-plugin-add-jsx-attribute@8.0.0": version "8.0.0" resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz#4001f5d5dd87fa13303e36ee106e3ff3a7eb8b22" @@ -7341,6 +7383,14 @@ "@typescript-eslint/types" "8.13.0" "@typescript-eslint/visitor-keys" "8.13.0" +"@typescript-eslint/scope-manager@8.16.0": + version "8.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz#ebc9a3b399a69a6052f3d88174456dd399ef5905" + integrity sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg== + dependencies: + "@typescript-eslint/types" "8.16.0" + "@typescript-eslint/visitor-keys" "8.16.0" + "@typescript-eslint/type-utils@6.10.0": version "6.10.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.10.0.tgz#1007faede067c78bdbcef2e8abb31437e163e2e1" @@ -7366,6 +7416,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.13.0.tgz#3f35dead2b2491a04339370dcbcd17bbdfc204d8" integrity sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng== +"@typescript-eslint/types@8.16.0": + version "8.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.16.0.tgz#49c92ae1b57942458ab83d9ec7ccab3005e64737" + integrity sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ== + "@typescript-eslint/typescript-estree@5.18.0": version "5.18.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.18.0.tgz#6498e5ee69a32e82b6e18689e2f72e4060986474" @@ -7406,6 +7461,20 @@ semver "^7.6.0" ts-api-utils "^1.3.0" +"@typescript-eslint/typescript-estree@8.16.0": + version "8.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz#9d741e56e5b13469b5190e763432ce5551a9300c" + integrity sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw== + dependencies: + "@typescript-eslint/types" "8.16.0" + "@typescript-eslint/visitor-keys" "8.16.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + "@typescript-eslint/utils@6.10.0": version "6.10.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.10.0.tgz#4d76062d94413c30e402c9b0df8c14aef8d77336" @@ -7441,6 +7510,16 @@ "@typescript-eslint/types" "8.13.0" "@typescript-eslint/typescript-estree" "8.13.0" +"@typescript-eslint/utils@^8.13.0": + version "8.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.16.0.tgz#c71264c437157feaa97842809836254a6fc833c3" + integrity sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.16.0" + "@typescript-eslint/types" "8.16.0" + "@typescript-eslint/typescript-estree" "8.16.0" + "@typescript-eslint/visitor-keys@5.18.0": version "5.18.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.18.0.tgz#c7c07709823804171d569017f3b031ced7253e60" @@ -7465,6 +7544,14 @@ "@typescript-eslint/types" "8.13.0" eslint-visitor-keys "^3.4.3" +"@typescript-eslint/visitor-keys@8.16.0": + version "8.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz#d5086afc060b01ff7a4ecab8d49d13d5a7b07705" + integrity sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ== + dependencies: + "@typescript-eslint/types" "8.16.0" + eslint-visitor-keys "^4.2.0" + "@ungap/structured-clone@^1.0.0", "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" @@ -10140,6 +10227,11 @@ aria-query@^5.0.0, aria-query@^5.3.0: dependencies: dequal "^2.0.3" +aria-query@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" @@ -10686,6 +10778,11 @@ axe-core@^4.0.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.3.tgz#64a4c85509e0991f5168340edc4bedd1ceea6966" integrity sha512-vwPpH4Aj4122EW38mxO/fxhGKtwWTMLDIJfZ1He0Edbtjcfna/R3YB67yVhezUMzqc3Jr3+Ii50KRntlENL4xQ== +axe-core@^4.10.0: + version "4.10.2" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.2.tgz#85228e3e1d8b8532a27659b332e39b7fa0e022df" + integrity sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w== + axe-core@^4.2.0, axe-core@^4.3.5: version "4.4.1" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413" @@ -10726,6 +10823,11 @@ axobject-query@^3.2.1: dependencies: dequal "^2.0.3" +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== + b4a@^1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" @@ -14806,6 +14908,14 @@ enhanced-resolve@^5.15.0: graceful-fs "^4.2.4" tapable "^2.2.0" +enhanced-resolve@^5.17.1: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + enquirer@^2.3.6: version "2.4.1" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" @@ -14959,10 +15069,10 @@ es-abstract@^1.17.2, es-abstract@^1.17.4, es-abstract@^1.18.0-next.1, es-abstrac string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.0" -es-abstract@^1.17.5, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2, es-abstract@^1.23.3: - version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" - integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== +es-abstract@^1.17.5, es-abstract@^1.23.3: + version "1.23.4" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.4.tgz#f006871f484d6a78229d2343557f2597f8333ed4" + integrity sha512-HR1gxH5OaiN7XH7uiWH0RLw0RcFySiSoW1ctxmD1ahTw3uGBtkmm/ng0tDU1OtYx5OK6EOL5Y6O21cDflG3Jcg== dependencies: array-buffer-byte-length "^1.0.1" arraybuffer.prototype.slice "^1.0.3" @@ -14979,7 +15089,7 @@ es-abstract@^1.17.5, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23 function.prototype.name "^1.1.6" get-intrinsic "^1.2.4" get-symbol-description "^1.0.2" - globalthis "^1.0.3" + globalthis "^1.0.4" gopd "^1.0.1" has-property-descriptors "^1.0.2" has-proto "^1.0.3" @@ -14995,10 +15105,10 @@ es-abstract@^1.17.5, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23 is-string "^1.0.7" is-typed-array "^1.1.13" is-weakref "^1.0.2" - object-inspect "^1.13.1" + object-inspect "^1.13.3" object-keys "^1.1.1" object.assign "^4.1.5" - regexp.prototype.flags "^1.5.2" + regexp.prototype.flags "^1.5.3" safe-array-concat "^1.1.2" safe-regex-test "^1.0.3" string.prototype.trim "^1.2.9" @@ -15141,6 +15251,58 @@ es-abstract@^1.22.1: unbox-primitive "^1.0.2" which-typed-array "^1.1.13" +es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" + has-symbols "^1.0.3" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" + is-callable "^1.2.7" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.3" + is-string "^1.0.7" + is-typed-array "^1.1.13" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.15" + es-define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" @@ -15209,9 +15371,9 @@ es-iterator-helpers@^1.0.15, es-iterator-helpers@^1.0.17: safe-array-concat "^1.1.2" es-iterator-helpers@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz#f6d745d342aea214fe09497e7152170dc333a7a6" - integrity sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw== + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz#2f1a3ab998b30cb2d10b195b587c6d9ebdebf152" + integrity sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q== dependencies: call-bind "^1.0.7" define-properties "^1.2.1" @@ -15221,6 +15383,7 @@ es-iterator-helpers@^1.1.0: function-bind "^1.1.2" get-intrinsic "^1.2.4" globalthis "^1.0.4" + gopd "^1.0.1" has-property-descriptors "^1.0.2" has-proto "^1.0.3" has-symbols "^1.0.3" @@ -15238,7 +15401,7 @@ es-module-lexer@^1.4.1: resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5" integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w== -es-module-lexer@^1.5.0: +es-module-lexer@^1.5.0, es-module-lexer@^1.5.3: version "1.5.4" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== @@ -15422,6 +15585,13 @@ escodegen@^2.1.0: optionalDependencies: source-map "~0.6.1" +eslint-compat-utils@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz#7fc92b776d185a70c4070d03fd26fde3d59652e4" + integrity sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q== + dependencies: + semver "^7.5.4" + eslint-config-prettier@^8.3.0: version "8.10.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" @@ -15473,6 +15643,15 @@ eslint-module-utils@^2.8.0: dependencies: debug "^3.2.7" +eslint-plugin-es-x@^7.8.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz#a207aa08da37a7923f2a9599e6d3eb73f3f92b74" + integrity sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ== + dependencies: + "@eslint-community/eslint-utils" "^4.1.2" + "@eslint-community/regexpp" "^4.11.0" + eslint-compat-utils "^0.5.1" + eslint-plugin-import@^2.25.2: version "2.26.0" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" @@ -15562,6 +15741,23 @@ eslint-plugin-jsdoc@^46.4.6: semver "^7.5.4" spdx-expression-parse "^3.0.1" +eslint-plugin-jsdoc@^50.5.0: + version "50.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.5.0.tgz#3b34b7846eb6c40750e68e97ae9441455fde7a75" + integrity sha512-xTkshfZrUbiSHXBwZ/9d5ulZ2OcHXxSvm/NPo494H/hadLRJwOq5PMV0EUpMqsb9V+kQo+9BAgi6Z7aJtdBp2A== + dependencies: + "@es-joy/jsdoccomment" "~0.49.0" + are-docs-informative "^0.0.2" + comment-parser "1.4.1" + debug "^4.3.6" + escape-string-regexp "^4.0.0" + espree "^10.1.0" + esquery "^1.6.0" + parse-imports "^2.1.1" + semver "^7.6.3" + spdx-expression-parse "^4.0.0" + synckit "^0.9.1" + eslint-plugin-jsx-a11y@^6.1.1: version "6.4.1" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz#a2d84caa49756942f42f1ffab9002436391718fd" @@ -15579,6 +15775,27 @@ eslint-plugin-jsx-a11y@^6.1.1: jsx-ast-utils "^3.1.0" language-tags "^1.0.5" +eslint-plugin-jsx-a11y@^6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483" + integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q== + dependencies: + aria-query "^5.3.2" + array-includes "^3.1.8" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "^4.10.0" + axobject-query "^4.1.0" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + hasown "^2.0.2" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + safe-regex-test "^1.0.3" + string.prototype.includes "^2.0.1" + eslint-plugin-jsx-a11y@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" @@ -15619,6 +15836,20 @@ eslint-plugin-jsx-a11y@^6.8.0: object.entries "^1.1.7" object.fromentries "^2.0.7" +eslint-plugin-n@^17.13.1: + version "17.13.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-n/-/eslint-plugin-n-17.13.1.tgz#3178c87989ad23417d22c5f66a13ecb1e9c5245e" + integrity sha512-97qzhk1z3DdSJNCqT45EslwCu5+LB9GDadSyBItgKUfGsXAmN/aa7LRQ0ZxHffUxUzvgbTPJL27/pE9ZQWHy7A== + dependencies: + "@eslint-community/eslint-utils" "^4.4.1" + enhanced-resolve "^5.17.1" + eslint-plugin-es-x "^7.8.0" + get-tsconfig "^4.8.1" + globals "^15.11.0" + ignore "^5.3.2" + minimatch "^9.0.5" + semver "^7.6.3" + eslint-plugin-playwright@^0.15.3: version "0.15.3" resolved "https://registry.yarnpkg.com/eslint-plugin-playwright/-/eslint-plugin-playwright-0.15.3.tgz#9fd8753688351bcaf41797eb6a7df8807fd5eb1b" @@ -15701,7 +15932,7 @@ eslint-plugin-react@^7.34.1: semver "^6.3.1" string.prototype.matchall "^4.0.10" -eslint-plugin-react@^7.37.2: +eslint-plugin-react@^7.35.0, eslint-plugin-react@^7.37.2: version "7.37.2" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz#cd0935987876ba2900df2f58339f6d92305acc7a" integrity sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w== @@ -15943,7 +16174,7 @@ eslint@^8.57.0: strip-ansi "^6.0.1" text-table "^0.2.0" -espree@^10.3.0: +espree@^10.1.0, espree@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== @@ -15994,6 +16225,13 @@ esquery@^1.4.2, esquery@^1.5.0: dependencies: estraverse "^5.1.0" +esquery@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + esrecurse@^4.1.0, esrecurse@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" @@ -17491,6 +17729,13 @@ get-symbol-description@^1.0.2: es-errors "^1.3.0" get-intrinsic "^1.2.4" +get-tsconfig@^4.8.1: + version "4.8.1" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.8.1.tgz#8995eb391ae6e1638d251118c7b56de7eb425471" + integrity sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg== + dependencies: + resolve-pkg-maps "^1.0.0" + get-uri@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-6.0.2.tgz#e019521646f4a8ff6d291fbaea2c46da204bb75b" @@ -17815,6 +18060,11 @@ globals@^13.12.0, globals@^13.19.0: dependencies: type-fest "^0.20.2" +globals@^15.11.0, globals@^15.12.0: + version "15.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.12.0.tgz#1811872883ad8f41055b61457a130221297de5b5" + integrity sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ== + globalthis@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" @@ -19017,6 +19267,11 @@ ignore@^5.1.9, ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +ignore@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + iltorb@^2.4.3: version "2.4.5" resolved "https://registry.yarnpkg.com/iltorb/-/iltorb-2.4.5.tgz#d64434b527099125c6839ed48b666247a172ef87" @@ -21272,7 +21527,7 @@ jscodeshift@^0.15.1: temp "^0.8.4" write-file-atomic "^2.3.0" -jsdoc-type-pratt-parser@^4.0.0: +jsdoc-type-pratt-parser@^4.0.0, jsdoc-type-pratt-parser@~4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz#ff6b4a3f339c34a6c188cbf50a16087858d22113" integrity sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg== @@ -22723,7 +22978,7 @@ minimatch@^9.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.4: +minimatch@^9.0.4, minimatch@^9.0.5: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== @@ -23674,6 +23929,11 @@ object-inspect@^1.13.1: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== +object-inspect@^1.13.3: + version "1.13.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a" + integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== + object-inspect@^1.7.0, object-inspect@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" @@ -24413,6 +24673,14 @@ parse-filepath@^1.0.1: map-cache "^0.2.0" path-root "^0.1.1" +parse-imports@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/parse-imports/-/parse-imports-2.2.1.tgz#0a6e8b5316beb5c9905f50eb2bbb8c64a4805642" + integrity sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ== + dependencies: + es-module-lexer "^1.5.3" + slashes "^3.0.12" + parse-json@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" @@ -27526,6 +27794,16 @@ regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.1" +regexp.prototype.flags@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42" + integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.2" + regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -27824,6 +28102,11 @@ resolve-pathname@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + resolve-pkg@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-0.1.0.tgz#02cc993410e2936962bd97166a1b077da9725531" @@ -28700,6 +28983,11 @@ slash@^5.1.0: resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce" integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== +slashes@^3.0.12: + version "3.0.12" + resolved "https://registry.yarnpkg.com/slashes/-/slashes-3.0.12.tgz#3d664c877ad542dc1509eaf2c50f38d483a6435a" + integrity sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA== + slice-ansi@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" @@ -28968,6 +29256,14 @@ spdx-expression-parse@^3.0.0, spdx-expression-parse@^3.0.1: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" +spdx-expression-parse@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz#a23af9f3132115465dac215c099303e4ceac5794" + integrity sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + spdx-license-ids@^3.0.0: version "3.0.7" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz#e9c18a410e5ed7e12442a549fbd8afa767038d65" @@ -29243,6 +29539,15 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" +string.prototype.includes@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz#eceef21283640761a81dbe16d6c7171a4edf7d92" + integrity sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + string.prototype.matchall@^4.0.10, string.prototype.matchall@^4.0.11: version "4.0.11" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" @@ -29933,6 +30238,14 @@ synckit@^0.8.5: "@pkgr/utils" "^2.3.1" tslib "^2.5.0" +synckit@^0.9.1: + version "0.9.2" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" + integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + table@^5.2.3: version "5.4.6" resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" @@ -30569,9 +30882,9 @@ ts-api-utils@^1.0.1: integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== ts-api-utils@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.0.tgz#709c6f2076e511a81557f3d07a0cbd566ae8195c" - integrity sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ== + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== ts-dedent@^2.0.0: version "2.2.0" @@ -30641,6 +30954,11 @@ tslib@^2.3.1, tslib@^2.5.0, tslib@^2.6.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@^2.6.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" From 7cf82021d038902cf21ac62c3ac31b68f4680e3f Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:06:55 +0100 Subject: [PATCH 23/92] Lint the config file itself Now it's a JS file, we can and should adhere to our own standards --- packages/eslint/default.mjs | 45 ++++---- packages/eslint/eslint.config.mjs | 4 + packages/eslint/package.json | 6 ++ yarn.lock | 174 +++++++++++++++++++++++++++++- 4 files changed, 204 insertions(+), 25 deletions(-) create mode 100644 packages/eslint/eslint.config.mjs diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index 10595d4b4ae..ba452197467 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -36,7 +36,8 @@ export default [ // https://eslint.org/docs/rules/ rules: { // Native ESLint rules - // - ESLint "Possible problems - These rules relate to possible logic errors in code:" (https://eslint.org/docs/latest/rules/#possible-problems). + // - ESLint "Possible problems - These rules relate to possible logic errors in code:" + // (https://eslint.org/docs/latest/rules/#possible-problems). "no-inner-declarations": [ "error", "functions" ], "no-self-compare": "error", "no-use-before-define": "error", @@ -58,7 +59,7 @@ export default [ "no-array-constructor": "error", "no-bitwise": "error", "no-caller": "error", - "no-console": [ "warn", { allow: [ "warn", "error", "trace" ], } ], + "no-console": [ "warn", { allow: [ "warn", "error", "trace" ] } ], "no-div-regex": "error", "no-else-return": "error", "no-eq-null": "error", @@ -95,11 +96,11 @@ export default [ }, { selector: "CallExpression[callee.name=/^(_nx)$/][arguments.length!=5]", message: "A textdomain needs to be provided for translation calls.", - } + }, ], "no-return-assign": "error", "no-script-url": "error", - "no-shadow": [ "error", { builtinGlobals: false, hoist: "all", allow: [], } ], + "no-shadow": [ "error", { builtinGlobals: false, hoist: "all", allow: [] } ], "no-undef-init": "error", "no-undefined": "error", "no-unneeded-ternary": "error", @@ -107,7 +108,7 @@ export default [ "no-useless-call": "error", "no-useless-concat": "error", "no-void": "error", - "no-warning-comments": [ "error", { terms: [ "todo" ], location: "anywhere", } ], + "no-warning-comments": [ "error", { terms: [ "todo" ], location: "anywhere" } ], "prefer-const": "error", radix: "error", strict: "error", @@ -122,7 +123,7 @@ export default [ "stylistic/computed-property-spacing": [ "error", "always" ], "stylistic/eol-last": "error", "stylistic/func-call-spacing": "error", - "stylistic/indent": [ "error", "tab", { SwitchCase: 1, } ], + "stylistic/indent": [ "error", "tab", { SwitchCase: 1 } ], "stylistic/jsx-quotes": "error", "stylistic/key-spacing": "error", "stylistic/keyword-spacing": "error", @@ -137,15 +138,15 @@ export default [ "stylistic/object-curly-spacing": [ "error", "always" ], "stylistic/operator-linebreak": "error", "stylistic/padded-blocks": [ "error", "never" ], - "stylistic/quote-props": [ "error", "as-needed", { keywords: true, } ], + "stylistic/quote-props": [ "error", "as-needed", { keywords: true } ], "stylistic/quotes": [ "error", "double", "avoid-escape" ], "stylistic/semi-spacing": "error", "stylistic/semi": "error", "stylistic/space-before-blocks": "error", "stylistic/space-before-function-paren": [ "error", "never" ], - "stylistic/space-in-parens": [ "error", "always", { exceptions: [ "empty" ], } ], + "stylistic/space-in-parens": [ "error", "always", { exceptions: [ "empty" ] } ], "stylistic/space-infix-ops": "error", - "stylistic/space-unary-ops": [ "error", { words: false, nonwords: false, overrides: { "!": true, }, } ], + "stylistic/space-unary-ops": [ "error", { words: false, nonwords: false, overrides: { "!": true } } ], "stylistic/spaced-comment": [ "error", "always" ], "stylistic/wrap-iife": "error", @@ -170,7 +171,7 @@ export default [ // Plugin: jsx-a11y rules (https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). // Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. - "jsx-a11y/label-has-for": [ "error", { required: "id", } ], + "jsx-a11y/label-has-for": [ "error", { required: "id" } ], // Plugin: React rules (https://github.com/jsx-eslint/eslint-plugin-react) "react/boolean-prop-naming": "error", @@ -179,16 +180,16 @@ export default [ "react/forbid-foreign-prop-types": "error", "react/jsx-boolean-value": [ "error", "always" ], "react/jsx-closing-bracket-location": [ "error", "line-aligned" ], - "react/jsx-curly-spacing": [ "error", { when: "always", children: true, } ], + "react/jsx-curly-spacing": [ "error", { when: "always", children: true } ], "react/jsx-equals-spacing": "error", "react/jsx-first-prop-new-line": [ "error", "multiline" ], "react/jsx-indent-props": [ "error", "tab" ], "react/jsx-indent": [ "error", "tab" ], - "react/jsx-max-depth": [ "error", { max: 8, } ], - "react/jsx-max-props-per-line": [ "error", { maximum: 6, } ], + "react/jsx-max-depth": [ "error", { max: 8 } ], + "react/jsx-max-props-per-line": [ "error", { maximum: 6 } ], "react/jsx-no-bind": "error", "react/jsx-pascal-case": "error", - "react/jsx-tag-spacing": [ "error", { beforeClosing: "never", } ], + "react/jsx-tag-spacing": [ "error", { beforeClosing: "never" } ], "react/no-access-state-in-setstate": "error", "react/no-redundant-should-component-update": "error", "react/no-render-return-value": "error", @@ -197,7 +198,7 @@ export default [ "react/no-unused-prop-types": "error", "react/no-unused-state": "error", "react/prefer-es6-class": "error", - "react/require-default-props": [ "error", { ignoreFunctionalComponents: true, } ], + "react/require-default-props": [ "error", { ignoreFunctionalComponents: true } ], "react/self-closing-comp": "error", "react/void-dom-elements-no-children": "error", @@ -205,11 +206,11 @@ export default [ "import/no-extraneous-dependencies": "error", "import/no-unresolved": "error", }, - "settings": { - "jsdoc": { - "tagNamePreference": { - "return": "returns" - } - } - } + settings: { + jsdoc: { + tagNamePreference: { + "return": "returns", + }, + }, + }, } ]; diff --git a/packages/eslint/eslint.config.mjs b/packages/eslint/eslint.config.mjs new file mode 100644 index 00000000000..3ecede8f7b8 --- /dev/null +++ b/packages/eslint/eslint.config.mjs @@ -0,0 +1,4 @@ +import yoastConfig from "./default.mjs"; +export default [ + ...yoastConfig, +]; diff --git a/packages/eslint/package.json b/packages/eslint/package.json index e805b176dff..b7cdd0063c6 100644 --- a/packages/eslint/package.json +++ b/packages/eslint/package.json @@ -11,6 +11,9 @@ "files": [ "default.mjs" ], + "scripts": { + "lint": "eslint . --max-warnings=0" + }, "repository": { "type": "git", "url": "https://github.com/Yoast/wordpress-seo.git", @@ -34,5 +37,8 @@ }, "peerDependencies": { "eslint": "^8.57 || >= 9" + }, + "devDependencies": { + "eslint": "^9.15.0" } } diff --git a/yarn.lock b/yarn.lock index c9826d80202..432e2d76ebe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2992,7 +2992,7 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.11.0": +"@eslint-community/regexpp@^4.11.0", "@eslint-community/regexpp@^4.12.1": version "4.12.1" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== @@ -3002,6 +3002,20 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== +"@eslint/config-array@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.0.tgz#3251a528998de914d59bb21ba4c11767cf1b3519" + integrity sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.9.0.tgz#168ee076f94b152c01ca416c3e5cf82290ab4fcd" + integrity sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg== + "@eslint/eslintrc@^2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.3.tgz#797470a75fe0fbd5a53350ee715e85e87baff22d" @@ -3032,6 +3046,21 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/eslintrc@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" + integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + "@eslint/js@8.53.0": version "8.53.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d" @@ -3042,11 +3071,28 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@9.15.0": + version "9.15.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.15.0.tgz#df0e24fe869143b59731942128c19938fdbadfb5" + integrity sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg== + "@eslint/js@^9.14.0": version "9.14.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.14.0.tgz#2347a871042ebd11a00fd8c2d3d56a265ee6857e" integrity sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg== +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + +"@eslint/plugin-kit@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz#812980a6a41ecf3a8341719f92a6d1e784a2e0e8" + integrity sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA== + dependencies: + levn "^0.4.1" + "@fal-works/esbuild-plugin-global-externals@^2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@fal-works/esbuild-plugin-global-externals/-/esbuild-plugin-global-externals-2.1.2.tgz#c05ed35ad82df8e6ac616c68b92c2282bd083ba4" @@ -3135,6 +3181,19 @@ resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324" integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ== +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + "@humanwhocodes/config-array@^0.11.13": version "0.11.13" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" @@ -3168,6 +3227,16 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b" + integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== + "@hutson/parse-repository-url@^3.0.0": version "3.0.2" resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" @@ -6839,6 +6908,11 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": version "4.17.41" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz#5077defa630c2e8d28aa9ffc2c01c157c305bef6" @@ -6943,7 +7017,7 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== -"@types/json-schema@^7.0.12": +"@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -13181,6 +13255,15 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.5: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + crypto-random-string@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" @@ -16000,6 +16083,14 @@ eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + eslint-utils@^1.3.1: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -16174,7 +16265,47 @@ eslint@^8.57.0: strip-ansi "^6.0.1" text-table "^0.2.0" -espree@^10.1.0, espree@^10.3.0: +eslint@^9.15.0: + version "9.15.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.15.0.tgz#77c684a4e980e82135ebff8ee8f0a9106ce6b8a6" + integrity sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.9.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.15.0" + "@eslint/plugin-kit" "^0.2.3" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.5" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.1.0, espree@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== @@ -16872,6 +17003,13 @@ file-entry-cache@^6.0.1: dependencies: flat-cache "^3.0.4" +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + file-sync-cmp@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz#a5e7a8ffbfa493b43b923bbd4ca89a53b63b612b" @@ -17185,6 +17323,14 @@ flat-cache@^3.0.4: flatted "^3.1.0" rimraf "^3.0.2" +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + flat@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" @@ -17200,6 +17346,11 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + flopmang@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/flopmang/-/flopmang-1.0.0.tgz#22c82f12b537d5d440d5f0ad87ac39109ff31e26" @@ -18060,6 +18211,11 @@ globals@^13.12.0, globals@^13.19.0: dependencies: type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + globals@^15.11.0, globals@^15.12.0: version "15.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-15.12.0.tgz#1811872883ad8f41055b61457a130221297de5b5" @@ -21622,6 +21778,11 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -21794,6 +21955,13 @@ keyv@3.0.0: dependencies: json-buffer "3.0.0" +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kind-of@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" From b5406a4a44cf9b64283b589c70da194d084977cc Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:32:08 +0100 Subject: [PATCH 24/92] Split off React specific config in a separate preset --- packages/eslint/default.mjs | 49 ++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index ba452197467..f9400502c59 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -9,10 +9,9 @@ import stylisticPlugin from "@stylistic/eslint-plugin"; export default [ js.configs.recommended, - reactPlugin.configs.flat.recommended, - jsxA11YPlugin.flatConfigs.recommended, importPlugin.flatConfigs.recommended, { + name: "yoast/recommended", plugins: { jsdoc: jsdocPlugin, node: nodePlugin, @@ -169,6 +168,38 @@ export default [ "node/no-path-concat": "error", "node/no-process-exit": "error", + // Plugin: Import rules (https://github.com/import-js/eslint-plugin-import) + "import/no-extraneous-dependencies": "error", + "import/no-unresolved": "error", + }, + settings: { + jsdoc: { + tagNamePreference: { + "return": "returns", + }, + }, + }, + } ]; + +export const reactConfig = [ + reactPlugin.configs.flat.recommended, + jsxA11YPlugin.flatConfigs.recommended, + { + name: "yoast/react", + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.amd, + ...globals.browser, + ...globals.jquery, + }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + rules: { // Plugin: jsx-a11y rules (https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). // Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. "jsx-a11y/label-has-for": [ "error", { required: "id" } ], @@ -201,16 +232,6 @@ export default [ "react/require-default-props": [ "error", { ignoreFunctionalComponents: true } ], "react/self-closing-comp": "error", "react/void-dom-elements-no-children": "error", - - // Plugin: Import rules (https://github.com/import-js/eslint-plugin-import) - "import/no-extraneous-dependencies": "error", - "import/no-unresolved": "error", }, - settings: { - jsdoc: { - tagNamePreference: { - "return": "returns", - }, - }, - }, - } ]; + }, +]; From f1838a19bc5c802c1874c7667f95e12ab41e5fcb Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 28 Nov 2024 15:37:39 +0100 Subject: [PATCH 25/92] Split off Node specific config in a separate preset --- packages/eslint/default.mjs | 43 ++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index f9400502c59..c252dde381e 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -14,22 +14,10 @@ export default [ name: "yoast/recommended", plugins: { jsdoc: jsdocPlugin, - node: nodePlugin, stylistic: stylisticPlugin, }, languageOptions: { ecmaVersion: "latest", - globals: { - ...globals.amd, - ...globals.browser, - ...globals.jquery, - ...globals.node, - }, - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, }, // https://eslint.org/docs/rules/ @@ -160,14 +148,6 @@ export default [ } ], "jsdoc/require-returns": "error", - // Plugin: Node rules (https://github.com/eslint-community/eslint-plugin-n) - "node/callback-return": "error", - "node/global-require": "error", - "node/handle-callback-err": "error", - "node/no-mixed-requires": "error", - "node/no-path-concat": "error", - "node/no-process-exit": "error", - // Plugin: Import rules (https://github.com/import-js/eslint-plugin-import) "import/no-extraneous-dependencies": "error", "import/no-unresolved": "error", @@ -235,3 +215,26 @@ export const reactConfig = [ }, }, ]; + +export const nodeConfig = [ + { + name: "yoast/node", + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.node, + }, + plugins: { + node: nodePlugin, + }, + rules: { + // Plugin: Node rules (https://github.com/eslint-community/eslint-plugin-n) + "node/callback-return": "error", + "node/global-require": "error", + "node/handle-callback-err": "error", + "node/no-mixed-requires": "error", + "node/no-path-concat": "error", + "node/no-process-exit": "error", + }, + }, +]; From a2c54e3ed3448aeb36341af9af825bdad123d6a9 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:44:34 +0100 Subject: [PATCH 26/92] Bake in support for Jest-based tests --- packages/eslint/default.mjs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index c252dde381e..e6be227aeae 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -159,7 +159,28 @@ export default [ }, }, }, - } ]; + }, + { + files: [ + "**/*.{spec,test,tests}.{js,jsx,mjs,cjs,ts,tsx}", + "{spec,test,tests}/**/*.{js,jsx,mjs,cjs,ts,tsx}", + ], + languageOptions: { + globals: { + ...globals.jest, + ...globals.node, + }, + }, + }, + { + files: [ "jest.config.{js,ts,cjs}" ], + languageOptions: { + globals: { + ...globals.commonjs, + }, + }, + }, +]; export const reactConfig = [ reactPlugin.configs.flat.recommended, From 8adb43cc1308780b4d574aea5d17e6598bdf3555 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:47:17 +0100 Subject: [PATCH 27/92] Let the consumer define language options --- packages/eslint/default.mjs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index e6be227aeae..ed39ba73b82 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -16,10 +16,6 @@ export default [ jsdoc: jsdocPlugin, stylistic: stylisticPlugin, }, - languageOptions: { - ecmaVersion: "latest", - }, - // https://eslint.org/docs/rules/ rules: { // Native ESLint rules @@ -187,19 +183,6 @@ export const reactConfig = [ jsxA11YPlugin.flatConfigs.recommended, { name: "yoast/react", - languageOptions: { - ecmaVersion: "latest", - globals: { - ...globals.amd, - ...globals.browser, - ...globals.jquery, - }, - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, - }, rules: { // Plugin: jsx-a11y rules (https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). // Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. @@ -240,11 +223,6 @@ export const reactConfig = [ export const nodeConfig = [ { name: "yoast/node", - languageOptions: { - ecmaVersion: "latest", - globals: { - ...globals.node, - }, plugins: { node: nodePlugin, }, From 6d2dc5456352c4ce6048e19de4eda1f3efc97dbc Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:47:58 +0100 Subject: [PATCH 28/92] Let the React preset detect the version --- packages/eslint/default.mjs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index ed39ba73b82..3b0f4b6293d 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -183,6 +183,11 @@ export const reactConfig = [ jsxA11YPlugin.flatConfigs.recommended, { name: "yoast/react", + settings: { + react: { + version: "detect", + }, + }, rules: { // Plugin: jsx-a11y rules (https://github.com/jsx-eslint/eslint-plugin-jsx-a11y). // Deprecated in v6.1.0 in favor of label-has-associated-control but we still want to require only for/id and not nesting. From 2ef531e69654c6aa1e42dfd78286052d03c651b6 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:48:11 +0100 Subject: [PATCH 29/92] Add type docs to config --- packages/eslint/default.mjs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index 3b0f4b6293d..7d512292061 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -7,6 +7,7 @@ import nodePlugin from "eslint-plugin-n"; import importPlugin from "eslint-plugin-import"; import stylisticPlugin from "@stylistic/eslint-plugin"; +/** @type {import('eslint').Linter.Config[]} */ export default [ js.configs.recommended, importPlugin.flatConfigs.recommended, @@ -178,6 +179,7 @@ export default [ }, ]; +/** @type {import('eslint').Linter.Config[]} */ export const reactConfig = [ reactPlugin.configs.flat.recommended, jsxA11YPlugin.flatConfigs.recommended, @@ -225,6 +227,7 @@ export const reactConfig = [ }, ]; +/** @type {import('eslint').Linter.Config[]} */ export const nodeConfig = [ { name: "yoast/node", From a9ddba1c022a07c9da1a08c0b3d2fd5e4c945a7a Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:48:32 +0100 Subject: [PATCH 30/92] Tweak jsDoc rule settings --- packages/eslint/default.mjs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index 7d512292061..c11c47e1c70 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -142,6 +142,9 @@ export default [ ArrowFunctionExpression: true, FunctionExpression: true, }, + // The fixer only adds empty blocks, which are easy to forget to fill in. + enableFixer: false, + exemptEmptyFunctions: true, } ], "jsdoc/require-returns": "error", From 7f4940485bc343c8260e1382880181c6d1a8000d Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:54:47 +0100 Subject: [PATCH 31/92] Prefer @const over @constant This is what we already use in most of our codebases. This moves that decision up one level into the shared config. --- packages/eslint/default.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index c11c47e1c70..473495de248 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -156,6 +156,7 @@ export default [ jsdoc: { tagNamePreference: { "return": "returns", + constant: "const", }, }, }, From 1e99ba2d4824253ac9d0fe4fcf478ce751f4e60d Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:53:46 +0100 Subject: [PATCH 32/92] Prevent having to eslint-ignore all long translation strings wp i18n, which we use for our translations, doesn't handle strings that span multiple lines. That's why we often add eslint ignore comments to those. By ignoring strings, we make a tradeoff: we no longer have to eslint-disable those translations, but we won't get feedback on long non-translation strings that might have been better readable on separate lines. --- packages/eslint/default.mjs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index 473495de248..572b5ebffe2 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -112,8 +112,15 @@ export default [ "stylistic/key-spacing": "error", "stylistic/keyword-spacing": "error", "stylistic/linebreak-style": "error", - "stylistic/max-len": [ "error", 4 ], - "stylistic/new-parens": "error", + "stylistic/max-len": [ + "error", + { + code: 150, + tabWidth: 4, + ignoreStrings: true, + }, + ], + "stylistic/new-parens": "error", "stylistic/no-extra-semi": "error", "stylistic/no-mixed-spaces-and-tabs": [ "error", "smart-tabs" ], "stylistic/no-multiple-empty-lines": "error", From e8929d43b0613248b939ca0bed7460feff1bd561 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Tue, 3 Dec 2024 11:58:00 +0100 Subject: [PATCH 33/92] Allow for testing side-effects of a constructor in tests This could be relevant when doing something like this: expect( new MyValueObject( null ) ).toThrow(...); --- packages/eslint/default.mjs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index 572b5ebffe2..e80ce1754b8 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -179,6 +179,10 @@ export default [ ...globals.node, }, }, + rules: { + // Some tests assert that a constructor throws an error, which is a valid use case. + "no-new": "off", + }, }, { files: [ "jest.config.{js,ts,cjs}" ], From 768273dc7d14f6964442f4292a371100e208c5f9 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:55:14 +0100 Subject: [PATCH 34/92] Allow for gradually solving existing complexity issues We have serveral cases where complexity is too high. To prevent us from adding eslint-ignore lines, we make this a warning, so we can set the max-warning threshlold. This will allow us to fix these cases gradually, while not losing track of them because they are ignored. --- packages/eslint/default.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index e80ce1754b8..2a79f7ac984 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -29,7 +29,7 @@ export default [ // - ESLint "Suggestions - These rules suggest alternate ways of doing things:" (https://eslint.org/docs/latest/rules/#suggestions). "accessor-pairs": "error", camelcase: "error", - complexity: [ "error", 10 ], + complexity: [ "warn", 10 ], "consistent-this": "error", curly: "error", "dot-notation": "error", @@ -37,7 +37,7 @@ export default [ "guard-for-in": "error", "max-depth": "error", "max-nested-callbacks": "error", - "max-statements": [ "error", 30 ], + "max-statements": [ "warn", 30 ], "new-cap": "error", "no-alert": "error", "no-array-constructor": "error", From f10ca9f136e149f3cabc54d759240c64473b8dd1 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 5 Dec 2024 11:07:00 +0100 Subject: [PATCH 35/92] Allow for omitting jsdoc on (arrow) function expressions We disable this rule in a lot of projects already. Most of the time these expressions can do without a bulky jsdoc block. Let's leave it up to the reviewer to identify the exceptions where more context is needed. --- packages/eslint/default.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint/default.mjs b/packages/eslint/default.mjs index 2a79f7ac984..a2726ca3cc4 100644 --- a/packages/eslint/default.mjs +++ b/packages/eslint/default.mjs @@ -146,8 +146,8 @@ export default [ require: { MethodDefinition: true, ClassDeclaration: true, - ArrowFunctionExpression: true, - FunctionExpression: true, + ArrowFunctionExpression: false, + FunctionExpression: false, }, // The fixer only adds empty blocks, which are easy to forget to fill in. enableFixer: false, From 0935820f8de4a5cb69aad660b0db47a1380ea8b9 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:04:05 +0100 Subject: [PATCH 36/92] Update helpers to a flat eslint config --- packages/helpers/eslint.config.mjs | 30 +++++++++++++++++++ packages/helpers/package.json | 3 ++ packages/helpers/src/ajaxHelper.js | 7 ++++- .../tests/__mocks__/@wordpress/i18n.js | 2 +- .../strings/stripTagsFromHtmlStringTest.js | 3 -- 5 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 packages/helpers/eslint.config.mjs diff --git a/packages/helpers/eslint.config.mjs b/packages/helpers/eslint.config.mjs new file mode 100644 index 00000000000..b5d9f81d493 --- /dev/null +++ b/packages/helpers/eslint.config.mjs @@ -0,0 +1,30 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build" ] }, + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + ...globals.jquery, + }, + }, + rules: { + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + }, + }, +]; diff --git a/packages/helpers/package.json b/packages/helpers/package.json index 0e349084362..a6d45b4d5c9 100644 --- a/packages/helpers/package.json +++ b/packages/helpers/package.json @@ -40,6 +40,9 @@ "@babel/preset-env": "^7.16.11", "@yoast/browserslist-config": "^1.2.3", "babel-plugin-styled-components": "^2.0.6", + "eslint": "^9.15.0", + "eslint-config-yoast": "^6.0.0", + "globals": "^15.12.0", "jest-styled-components": "^7.0.3", "react-test-renderer": "^18.2.0" }, diff --git a/packages/helpers/src/ajaxHelper.js b/packages/helpers/src/ajaxHelper.js index 7d2768ca5a9..9812920ee3b 100644 --- a/packages/helpers/src/ajaxHelper.js +++ b/packages/helpers/src/ajaxHelper.js @@ -71,6 +71,11 @@ const sendJQueryRequest = ( url, requestParams ) => { const parseHeaders = ( type, config ) => { if ( type === "jquery" ) { Object.assign( config, { + /** + * Adds configured headers to the request. + * + * @param {XMLHttpRequest} xhr The XMLHttpRequest object. + */ beforeSend: ( xhr ) => { jQuery.each( config.headers, ( headerName, headerValue ) => { xhr.setRequestHeader( headerName, headerValue ); @@ -96,7 +101,7 @@ const parseHeaders = ( type, config ) => { */ const overwriteObjectWithDefaultValues = ( target, defaults ) => { for ( const key in defaults ) { - if ( defaults.hasOwnProperty( key ) ) { + if ( Object.hasOwn( defaults, key ) ) { if ( typeof target[ key ] === "undefined" || target[ key ] === "" ) { target[ key ] = defaults[ key ]; } diff --git a/packages/helpers/tests/__mocks__/@wordpress/i18n.js b/packages/helpers/tests/__mocks__/@wordpress/i18n.js index faa8653a52a..ac9438a37e0 100644 --- a/packages/helpers/tests/__mocks__/@wordpress/i18n.js +++ b/packages/helpers/tests/__mocks__/@wordpress/i18n.js @@ -1,4 +1,4 @@ -/* eslint-disable require-jsdoc */ +/* eslint-disable jsdoc/require-jsdoc */ import { sprintf, setLocaleData } from "@wordpress/i18n"; diff --git a/packages/helpers/tests/strings/stripTagsFromHtmlStringTest.js b/packages/helpers/tests/strings/stripTagsFromHtmlStringTest.js index 80a9155745f..a50cc6a062a 100644 --- a/packages/helpers/tests/strings/stripTagsFromHtmlStringTest.js +++ b/packages/helpers/tests/strings/stripTagsFromHtmlStringTest.js @@ -24,7 +24,6 @@ describe( "stripTagsFromHtmlString", () => { ], [ "removes all the tags in a full HTML document", - // eslint-disable-next-line max-len "title

header

", "headeronetwothree", ], @@ -41,7 +40,6 @@ describe( "stripTagsFromHtmlString", () => { ], [ "removes all but the allowed tags", - // eslint-disable-next-line max-len "", "onetwothree", [ "a" ], @@ -53,7 +51,6 @@ describe( "stripTagsFromHtmlString", () => { ], [ "removes all but the allowed tags, keeping allowed attributes", - // eslint-disable-next-line max-len "", "onetwothree", [ "a" ], From a3acb5aab4541b5f2bb413224b6eab3b47c24936 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 5 Dec 2024 10:56:23 +0100 Subject: [PATCH 37/92] Update social-metadata-previews to a flat eslint config --- .../eslint.config.mjs | 40 +++++++++++++++++++ .../jest/__mocks__/@wordpress/i18n.js | 2 +- .../social-metadata-previews/package.json | 3 ++ .../tests/testHelpers/mockImage.js | 8 ++-- 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 packages/social-metadata-previews/eslint.config.mjs diff --git a/packages/social-metadata-previews/eslint.config.mjs b/packages/social-metadata-previews/eslint.config.mjs new file mode 100644 index 00000000000..42916411f57 --- /dev/null +++ b/packages/social-metadata-previews/eslint.config.mjs @@ -0,0 +1,40 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build" ] }, + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + }, + }, + rules: { + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + // Deviate from the Yoast config to allow for not using the error that is caught. + "no-unused-vars": [ "error", { caughtErrors: "none" } ], + }, + }, + { + files: [ "*.config.*", "jest/**" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/social-metadata-previews/jest/__mocks__/@wordpress/i18n.js b/packages/social-metadata-previews/jest/__mocks__/@wordpress/i18n.js index ffa3fe2aa9f..d7fd2c238c0 100644 --- a/packages/social-metadata-previews/jest/__mocks__/@wordpress/i18n.js +++ b/packages/social-metadata-previews/jest/__mocks__/@wordpress/i18n.js @@ -1,4 +1,4 @@ -/* eslint-disable require-jsdoc */ +/* eslint-disable jsdoc/require-jsdoc */ import { sprintf, setLocaleData } from "@wordpress/i18n"; diff --git a/packages/social-metadata-previews/package.json b/packages/social-metadata-previews/package.json index c415955ca64..60a728944f0 100644 --- a/packages/social-metadata-previews/package.json +++ b/packages/social-metadata-previews/package.json @@ -45,6 +45,9 @@ "@yoast/browserslist-config": "^1.2.3", "babel-plugin-styled-components": "^2.0.6", "browserslist": "^4.7.3", + "eslint": "^9.16.0", + "eslint-config-yoast": "^6.0.0", + "globals": "^15.13.0", "jest-styled-components": "^7.0.3", "raf": "^3.4.1", "react-test-renderer": "^18.2.0" diff --git a/packages/social-metadata-previews/tests/testHelpers/mockImage.js b/packages/social-metadata-previews/tests/testHelpers/mockImage.js index f91fd6fd60a..713e0cc5daa 100644 --- a/packages/social-metadata-previews/tests/testHelpers/mockImage.js +++ b/packages/social-metadata-previews/tests/testHelpers/mockImage.js @@ -7,7 +7,7 @@ * @returns {Object} Mocked image class that always loads successfully. */ export function createSuccessfulImage( width, height ) { - /* eslint-disable require-jsdoc */ + /* eslint-disable jsdoc/require-jsdoc */ class MockedImage { get src() { return this._src; @@ -23,7 +23,7 @@ export function createSuccessfulImage( width, height ) { } } } - /* eslint-enable require-jsdoc */ + /* eslint-enable */ return MockedImage; } @@ -37,7 +37,7 @@ export function createSuccessfulImage( width, height ) { * @returns {Object} Mocked image class that always fails to load. */ export function createFailingImage() { - /* eslint-disable require-jsdoc */ + /* eslint-disable jsdoc/require-jsdoc */ class MockedImage { get src() { return this._src; @@ -51,7 +51,7 @@ export function createFailingImage() { } } } - /* eslint-enable require-jsdoc */ + /* eslint-enable */ return MockedImage; } From a9f515f5f276e1e8fe9dd593b534690faa797627 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:42:25 +0100 Subject: [PATCH 38/92] Update ui-library to a flat eslint config Also lint all js, instead of just src. This requires some very minor fixes. --- packages/ui-library/.eslintrc.js | 70 ------------------- packages/ui-library/.storybook/main.js | 5 ++ packages/ui-library/.storybook/preview.js | 3 +- packages/ui-library/eslint.config.mjs | 57 +++++++++++++++ packages/ui-library/package.json | 8 +-- .../ui-library/src/elements/code/stories.js | 2 +- packages/ui-library/tests/storyshots.js | 4 ++ 7 files changed, 71 insertions(+), 78 deletions(-) delete mode 100644 packages/ui-library/.eslintrc.js create mode 100644 packages/ui-library/eslint.config.mjs diff --git a/packages/ui-library/.eslintrc.js b/packages/ui-library/.eslintrc.js deleted file mode 100644 index 39055263956..00000000000 --- a/packages/ui-library/.eslintrc.js +++ /dev/null @@ -1,70 +0,0 @@ -module.exports = { - root: true, - "extends": [ - "yoast", - ], - parser: "@babel/eslint-parser", - parserOptions: { - ecmaVersion: 2019, - sourceType: "module", - }, - plugins: [ - "@babel", - ], - settings: { - react: { - version: "detect", - }, - }, - rules: { - "no-unused-expressions": [ - "error", - { - allowShortCircuit: true, - allowTernary: true, - }, - ], - "max-len": [ - "error", - { - code: 150, - ignoreStrings: true, - ignorePattern: "[\t]*\n", - }, - ], - "space-unary-ops": [ - "error", - { - words: true, - nonwords: false, - overrides: { - "!": true, - "!!": true, - }, - }, - ], - "space-before-function-paren": [ - "error", - { - anonymous: "never", - named: "never", - asyncArrow: "always", - }, - ], - "template-curly-spacing": [ - "error", - "always", - ], - }, - overrides: [ - { - files: [ "src/**/*.stories.js", "src/**/stories.js" ], - rules: { - "no-unused-vars": "off", - "require-jsdoc": "off", - "valid-jsdoc": "off", - "react/prop-types": "off", - }, - }, - ], -}; diff --git a/packages/ui-library/.storybook/main.js b/packages/ui-library/.storybook/main.js index e2406ad66ec..dab6b601554 100644 --- a/packages/ui-library/.storybook/main.js +++ b/packages/ui-library/.storybook/main.js @@ -1,5 +1,10 @@ import { dirname, join } from "path"; +/** + * Get the absolute path of an installed package. + * @param {string} value The package name. + * @returns {string} The absolute path to the package. + */ function getAbsolutePath( value ) { return dirname( require.resolve( join( value, "package.json" ) ) ); } diff --git a/packages/ui-library/.storybook/preview.js b/packages/ui-library/.storybook/preview.js index 0c3cccfdc19..a276e233c1d 100644 --- a/packages/ui-library/.storybook/preview.js +++ b/packages/ui-library/.storybook/preview.js @@ -1,5 +1,6 @@ import Root from "../src/components/root"; import "./style.css"; +import React from "react"; const preview = { globalTypes: { @@ -36,7 +37,7 @@ const preview = { argTypesRegex: "^on[A-Z].*", }, backgrounds: { - default: "light", + "default": "light", values: [ { name: "light", diff --git a/packages/ui-library/eslint.config.mjs b/packages/ui-library/eslint.config.mjs new file mode 100644 index 00000000000..295887f9aa2 --- /dev/null +++ b/packages/ui-library/eslint.config.mjs @@ -0,0 +1,57 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build", "storybook-static" ] }, + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + }, + }, + rules: { + "template-curly-spacing": [ + "error", + "always", + ], + // Deviate from the Yoast config to allow use of short-circuit and ternary expressions to call functions with side effects, like setState. + "no-unused-expressions": [ + "error", + { + allowShortCircuit: true, + allowTernary: true, + }, + ], + // Deviate from the Yoast config to force spacing before async arrow function parentheses. + "space-before-function-paren": [ + "error", + { + anonymous: "never", + named: "never", + asyncArrow: "always", + }, + ], + }, + }, + { + files: [ "src/**/stories.*" ], + rules: { + "no-unused-vars": "off", + "require-jsdoc": "off", + "valid-jsdoc": "off", + "react/prop-types": "off", + }, + }, + { + files: [ "*.config.*", "scripts/**", ".storybook/**" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/ui-library/package.json b/packages/ui-library/package.json index fb2c510a367..d09da8547f5 100644 --- a/packages/ui-library/package.json +++ b/packages/ui-library/package.json @@ -25,13 +25,11 @@ "publish:storybook": "./scripts/publish-storybook.sh", "test:storyshots": "yarn build:storybook --test --quiet && jest tests/storyshots.js", "t_st": "yarn test:storyshots", - "lint": "eslint src --max-warnings=0" + "lint": "eslint . --max-warnings=0" }, "devDependencies": { "@babel/cli": "^7.23.9", "@babel/core": "^7.23.9", - "@babel/eslint-parser": "^7.23.9", - "@babel/eslint-plugin": "^7.23.5", "@babel/parser": "^7.23.9", "@babel/plugin-proposal-optional-chaining": "^7.21.0", "@babel/plugin-transform-runtime": "^7.23.9", @@ -60,9 +58,7 @@ "css-loader": "^6.10.0", "eslint": "^8.57.0", "eslint-config-yoast": "^6.0.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.34.1", + "globals": "^15.12.0", "jest": "^27.5.1", "postcss": "^8.4.19", "postcss-loader": "^7.3.4", diff --git a/packages/ui-library/src/elements/code/stories.js b/packages/ui-library/src/elements/code/stories.js index afcaf46e374..0528ca56b4e 100644 --- a/packages/ui-library/src/elements/code/stories.js +++ b/packages/ui-library/src/elements/code/stories.js @@ -19,7 +19,7 @@ export const Variants = { https://example.com/ (default) https://example.com/ (default with class `yst-w-fit`) - { /* eslint-disable-next-line max-len */ } + { /* eslint-disable-next-line stylistic/max-len */ } https://example.com/that_is_really_long/so_you_see_that_it_will_start_scrolling?oh_my_this_is_not_enough_text=lets_add_some_parameters&more_parameters=yes_please&one_more=for_good_measure (block) diff --git a/packages/ui-library/tests/storyshots.js b/packages/ui-library/tests/storyshots.js index f4912ba0072..140dedf084e 100644 --- a/packages/ui-library/tests/storyshots.js +++ b/packages/ui-library/tests/storyshots.js @@ -1,3 +1,7 @@ +/* eslint-disable import/no-unresolved -- + * The tests are currently disabled and these packages are not installed. + * We'll resolve this when fixing and re-enabling the tests. + */ import initStoryshots from "@storybook/addon-storyshots"; import { imageSnapshot } from "@storybook/addon-storyshots-puppeteer"; import path from "path"; From 2757e3c6b77508c88e2ae694baa439930e939ea7 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:01:02 +0100 Subject: [PATCH 39/92] Update yoastseo to a flat eslint config --- packages/yoastseo/.eslintrc.js | 74 ------------------ packages/yoastseo/eslint.config.mjs | 104 +++++++++++++++++++++++++ packages/yoastseo/package.json | 6 +- yarn.lock | 117 ++++++++++++---------------- 4 files changed, 157 insertions(+), 144 deletions(-) delete mode 100644 packages/yoastseo/.eslintrc.js create mode 100644 packages/yoastseo/eslint.config.mjs diff --git a/packages/yoastseo/.eslintrc.js b/packages/yoastseo/.eslintrc.js deleted file mode 100644 index e2eeb41fc70..00000000000 --- a/packages/yoastseo/.eslintrc.js +++ /dev/null @@ -1,74 +0,0 @@ -module.exports = { - root: true, - "extends": [ - "yoast", - ], - env: { - amd: true, - browser: true, - es6: true, - jquery: true, - node: true, - jest: true, - }, - plugins: [ - "@stylistic", - ], - parserOptions: { - ecmaVersion: 2019, - sourceType: "module", - }, - // The Yoast eslint config requires setting up the React version. - settings: { - react: { - version: "detect", - }, - "import/core-modules": [ "yoastseo" ], - }, - rules: { - complexity: [ "warn", 10 ], - "no-new": "off", - "max-statements": "off", - "new-cap": "off", - "no-redeclare": "off", - "no-prototype-builtins": "off", - // Longer grace period for Yoast config. - "no-shadow": [ "warn", { builtinGlobals: false, hoist: "all", allow: [] } ], - "require-jsdoc": [ "warn", - { require: { - MethodDefinition: true, - ClassDeclaration: true, - ArrowFunctionExpression: false, - FunctionExpression: true }, - } ], - "no-useless-backreference": "warn", - "no-useless-catch": "off", - "no-useless-escape": "warn", - // Disabling the default `comma-dangle` and `max-len` rule from Yoast. - // The `comma-dangle` and `max-len` rules are also deprecated, and it is recommended to use the `@stylistic` plugin. - "comma-dangle": "off", - "max-len": "off", - // Stylistic rules (https://eslint.style/packages/default) - "@stylistic/comma-dangle": [ "error", { - arrays: "always-multiline", - objects: "always-multiline", - imports: "always-multiline", - exports: "always-multiline", - functions: "never", - } ], - "@stylistic/max-len": [ "error", { - code: 150, - tabWidth: 4, - ignoreComments: true, - ignoreStrings: true, - ignoreRegExpLiterals: true, - } ], - // Import rules (https://github.com/import-js/eslint-plugin-import) - "import/default": "off", - "import/namespace": "off", - "import/no-named-as-default": "off", - "import/no-named-as-default-member": "off", - "import/no-extraneous-dependencies": "off", - "import/no-unresolved": [ "error", { ignore: [ "premium-configuration/data/morphologyData", "@yoast/feature-flag", "yoastseo" ] } ], - }, -}; diff --git a/packages/yoastseo/eslint.config.mjs b/packages/yoastseo/eslint.config.mjs new file mode 100644 index 00000000000..992826b7704 --- /dev/null +++ b/packages/yoastseo/eslint.config.mjs @@ -0,0 +1,104 @@ +import globals from "globals"; +import yoastConfig from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build", "vendor", "examples" ] }, + ...yoastConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + }, + }, + rules: { + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + + // Deviate from the Yoast config to ignore RegExp literals. + "stylistic/max-len": [ + "error", + { + code: 150, + tabWidth: 4, + ignoreComments: true, + ignoreStrings: true, + ignoreRegExpLiterals: true, + }, + ], + + // Deviate from the Yoast config to allow existing violations. New occurrences are still disallowed. + "no-useless-backreference": "warn", + + // Deviate from the Yoast config to allow cases like thing.hasOwnProperty("x"), which we often use. + "no-prototype-builtins": "off", + // Deviate from the Yoast config to allow default imports that share the name of a named export. + // We sometimes export a value as both a named export and a default export. + "import/no-named-as-default": "off", + + // Deviate from the Yoast config to ignore imports from premium-configuration, which might not be available in all environments. + "import/no-unresolved": [ "error", { ignore: [ "premium-configuration/data/morphologyData" ] } ], + }, + }, + { + files: [ "src/languageProcessing/**" ], + settings: { + "import/core-modules": [ "yoastseo" ], + }, + }, + { + // Enable node globals for the singleton script, as it is the only file that accounts for a Node environment as a fallback. + files: [ "src/helpers/shortlinker/singleton.js" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, + { + // Enable worker globals for worker scripts. + files: [ "src/worker/**" ], + languageOptions: { + globals: { + ...globals.worker, + }, + }, + }, + { + // Enable browser globals for the createWorker script, which is not a worker itself. + files: [ "src/worker/createWorker.js" ], + languageOptions: { + globals: { + ...globals.browser, + }, + }, + }, + { + files: [ "spec/**" ], + rules: { + "max-statements": "off", + // Deviate from the Yoast config to allow access properties from the default export that share a name with a named export. + // We sometimes export a value as both a named export and a default export that represents all the named exports as a single object. + // We exclusively do this in test, so we can keep this rule enabled in src. + "import/no-named-as-default-member": "off", + }, + }, + { + files: [ "Gruntfile.js", "grunt/**", "babel.config.js", "premium-configuration/**" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/yoastseo/package.json b/packages/yoastseo/package.json index 7ba51569a83..4f74ace5505 100644 --- a/packages/yoastseo/package.json +++ b/packages/yoastseo/package.json @@ -31,7 +31,7 @@ "clean": "rm -rf build", "pretest": "grunt get-premium-configuration", "test": "jest", - "lint": "eslint src spec --max-warnings 10" + "lint": "eslint . --max-warnings 10" }, "engines": { "node": ">=8.0.0" @@ -39,15 +39,13 @@ "devDependencies": { "@babel/cli": "^7.25.9", "@babel/core": "^7.26.0", - "@babel/eslint-parser": "^7.25.9", "@babel/preset-env": "^7.26.0", - "@stylistic/eslint-plugin": "^2.10.1", "@yoast/browserslist-config": "^1.2.3", "blob-polyfill": "^7.0.20220408", "console.table": "^0.10.0", "eslint": "^8.57.0", "eslint-config-yoast": "^6.0.0", - "eslint-plugin-import": "^2.31.0", + "globals": "^15.12.0", "grunt": "^1.6.1", "grunt-shell": "^4.0.0", "jest": "^29.7.0", diff --git a/yarn.lock b/yarn.lock index 432e2d76ebe..d5481dc2a88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -171,15 +171,6 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.1" -"@babel/eslint-parser@^7.23.9": - version "7.23.10" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.23.10.tgz#2d4164842d6db798873b40e0c4238827084667a2" - integrity sha512-3wSYDPZVnhseRnxRJH6ZVTNknBz76AEnyC+AYYhasjP3Yy23qz0ERR7Fcd2SHmYuSFJ2kY9gaaDd3vyqU09eSw== - dependencies: - "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" - eslint-visitor-keys "^2.1.0" - semver "^6.3.1" - "@babel/eslint-parser@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz#603c68a63078796527bc9d0833f5e52dd5f9224c" @@ -189,7 +180,7 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.1" -"@babel/eslint-plugin@^7.17.7", "@babel/eslint-plugin@^7.23.5": +"@babel/eslint-plugin@^7.17.7": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.23.5.tgz#77d4703e9f83b81e9fc13382810372beb2f10f94" integrity sha512-03+E/58Hoo/ui69gR+beFdGpplpoVK0BSIdke2iw4/Bz7eGN0ssRenNlnU4nmbkowNQOPCStKSwFr8H6DiY49g== @@ -3076,6 +3067,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.15.0.tgz#df0e24fe869143b59731942128c19938fdbadfb5" integrity sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg== +"@eslint/js@9.16.0": + version "9.16.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.16.0.tgz#3df2b2dd3b9163056616886c86e4082f45dbf3f4" + integrity sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg== + "@eslint/js@^9.14.0": version "9.14.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.14.0.tgz#2347a871042ebd11a00fd8c2d3d56a265ee6857e" @@ -6415,17 +6411,6 @@ "@types/express" "^4.7.0" file-system-cache "2.3.0" -"@stylistic/eslint-plugin@^2.10.1": - version "2.10.1" - resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-2.10.1.tgz#809924752a1a13ebff2b0b6d7884fd61d389a907" - integrity sha512-U+4yzNXElTf9q0kEfnloI9XbOyD4cnEQCxjUI94q0+W++0GAEQvJ/slwEj9lwjDHfGADRSr+Tco/z0XJvmDfCQ== - dependencies: - "@typescript-eslint/utils" "^8.12.2" - eslint-visitor-keys "^4.2.0" - espree "^10.3.0" - estraverse "^5.3.0" - picomatch "^4.0.2" - "@stylistic/eslint-plugin@^2.11.0": version "2.11.0" resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-2.11.0.tgz#50d0289f36f7201055b7fa1729fdc1d8c46e93fa" @@ -7449,14 +7434,6 @@ "@typescript-eslint/types" "6.10.0" "@typescript-eslint/visitor-keys" "6.10.0" -"@typescript-eslint/scope-manager@8.13.0": - version "8.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz#2f4aed0b87d72360e64e4ea194b1fde14a59082e" - integrity sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA== - dependencies: - "@typescript-eslint/types" "8.13.0" - "@typescript-eslint/visitor-keys" "8.13.0" - "@typescript-eslint/scope-manager@8.16.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz#ebc9a3b399a69a6052f3d88174456dd399ef5905" @@ -7485,11 +7462,6 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.10.0.tgz#f4f0a84aeb2ac546f21a66c6e0da92420e921367" integrity sha512-36Fq1PWh9dusgo3vH7qmQAj5/AZqARky1Wi6WpINxB6SkQdY5vQoT2/7rW7uBIsPDcvvGCLi4r10p0OJ7ITAeg== -"@typescript-eslint/types@8.13.0": - version "8.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.13.0.tgz#3f35dead2b2491a04339370dcbcd17bbdfc204d8" - integrity sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng== - "@typescript-eslint/types@8.16.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.16.0.tgz#49c92ae1b57942458ab83d9ec7ccab3005e64737" @@ -7521,20 +7493,6 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/typescript-estree@8.13.0": - version "8.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz#db8c93dd5437ca3ce417a255fb35ddc3c12c3e95" - integrity sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g== - dependencies: - "@typescript-eslint/types" "8.13.0" - "@typescript-eslint/visitor-keys" "8.13.0" - debug "^4.3.4" - fast-glob "^3.3.2" - is-glob "^4.0.3" - minimatch "^9.0.4" - semver "^7.6.0" - ts-api-utils "^1.3.0" - "@typescript-eslint/typescript-estree@8.16.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz#9d741e56e5b13469b5190e763432ce5551a9300c" @@ -7574,16 +7532,6 @@ eslint-scope "^5.1.1" eslint-utils "^3.0.0" -"@typescript-eslint/utils@^8.12.2": - version "8.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.13.0.tgz#f6d40e8b5053dcaeabbd2e26463857abf27d62c0" - integrity sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "8.13.0" - "@typescript-eslint/types" "8.13.0" - "@typescript-eslint/typescript-estree" "8.13.0" - "@typescript-eslint/utils@^8.13.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.16.0.tgz#c71264c437157feaa97842809836254a6fc833c3" @@ -7610,14 +7558,6 @@ "@typescript-eslint/types" "6.10.0" eslint-visitor-keys "^3.4.1" -"@typescript-eslint/visitor-keys@8.13.0": - version "8.13.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz#e97b0d92b266ef38a1faf40a74da289b66683a5b" - integrity sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw== - dependencies: - "@typescript-eslint/types" "8.13.0" - eslint-visitor-keys "^3.4.3" - "@typescript-eslint/visitor-keys@8.16.0": version "8.16.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz#d5086afc060b01ff7a4ecab8d49d13d5a7b07705" @@ -16305,6 +16245,46 @@ eslint@^9.15.0: natural-compare "^1.4.0" optionator "^0.9.3" +eslint@^9.16.0: + version "9.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.16.0.tgz#66832e66258922ac0a626f803a9273e37747f2a6" + integrity sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.9.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.16.0" + "@eslint/plugin-kit" "^0.2.3" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.5" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + espree@^10.0.1, espree@^10.1.0, espree@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" @@ -18221,6 +18201,11 @@ globals@^15.11.0, globals@^15.12.0: resolved "https://registry.yarnpkg.com/globals/-/globals-15.12.0.tgz#1811872883ad8f41055b61457a130221297de5b5" integrity sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ== +globals@^15.13.0: + version "15.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-15.13.0.tgz#bbec719d69aafef188ecd67954aae76a696010fc" + integrity sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g== + globalthis@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" From 8aebacc7789689d61a077c47761cb9e9923a590b Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:02:03 +0100 Subject: [PATCH 40/92] Autofix ESLint in yoastseo --- .../helpers/morphology/baseStemmerSpec.js | 2 +- .../morphology/exceptionListHelpersSpec.js | 2 +- .../helpers/word/markWordsInSentenceSpec.js | 2 +- .../ar/helpers/createBasicWordFormsSpec.js | 52 +++++++++---------- .../nl/helpers/internal/determineStemSpec.js | 4 +- .../researches/altTagCountSpec.js | 6 +-- .../researches/countSentencesFromTextSpec.js | 2 +- .../functionWordsInKeyphraseSpec.js | 8 +-- .../getPassiveVoiceResultSpec.js | 2 +- .../researches/getSentenceBeginningsSpec.js | 6 +-- .../researches/keyphraseDistributionSpec.js | 4 +- .../researches/keywordCountSpec.js | 2 +- .../configuration/otherAssessmentsSpec.js | 2 +- .../SentenceLengthInTextAssessmentSpec.js | 12 ++--- ...eadingDistributionTooLongAssessmentSpec.js | 4 +- .../seo/KeyphraseLengthAssessmentSpec.js | 2 +- .../MetaDescriptionKeywordAssessmentSpec.js | 2 +- .../src/config/transliterationsWPstyle.js | 10 ++-- .../languages/it/helpers/internal/stem.js | 2 +- .../researches/findKeywordInFirstParagraph.js | 2 +- .../researches/keywordCount.js | 2 +- .../InclusiveLanguageAssessment.js | 2 +- 22 files changed, 66 insertions(+), 66 deletions(-) diff --git a/packages/yoastseo/spec/languageProcessing/helpers/morphology/baseStemmerSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/morphology/baseStemmerSpec.js index 3969ee56dd9..9c17791f9a4 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/morphology/baseStemmerSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/morphology/baseStemmerSpec.js @@ -2,6 +2,6 @@ import baseStemmer from "../../../../src/languageProcessing/helpers/morphology/b describe( "Test for the base stemmer where it returns the input word", () => { it( "returns the input word", () => { - expect( baseStemmer( "cats" ) ).toBe( "cats" ); + expect( baseStemmer( "cats" ) ).toBe( "cats" ); } ); } ); diff --git a/packages/yoastseo/spec/languageProcessing/helpers/morphology/exceptionListHelpersSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/morphology/exceptionListHelpersSpec.js index e3605e1075d..21d826849d1 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/morphology/exceptionListHelpersSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/morphology/exceptionListHelpersSpec.js @@ -12,7 +12,7 @@ const prefixes = { describe( "Returns true if a word has the same ending as one of the entries in an array", () => { it( "Returns true if a word has the same ending as one of the entries in an array", () => { expect( checkIfWordEndingIsOnExceptionList( "ziekenhuis", [ "huis", "keuken" ] ) ).toEqual( true - ); + ); } ); it( "Returns true if a word is the same as one of the entries in an array", () => { expect( checkIfWordEndingIsOnExceptionList( "huis", [ "huis", "keuken" ] ) ).toEqual( true diff --git a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js index 912e4a02c8a..edb4713fde6 100644 --- a/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js +++ b/packages/yoastseo/spec/languageProcessing/helpers/word/markWordsInSentenceSpec.js @@ -166,7 +166,7 @@ describe( "Adds Yoast marks to specific words in a sentence for languages with c new Mark( { marked: "小さい花の刺繍しかし、それは在庫切れでしたマキシドレス。", original: "小さい花の刺繍しかし、それは在庫切れでしたマキシドレス。" } ), - ] + ] ); } ); diff --git a/packages/yoastseo/spec/languageProcessing/languages/ar/helpers/createBasicWordFormsSpec.js b/packages/yoastseo/spec/languageProcessing/languages/ar/helpers/createBasicWordFormsSpec.js index 6dd1212d613..571c059a361 100644 --- a/packages/yoastseo/spec/languageProcessing/languages/ar/helpers/createBasicWordFormsSpec.js +++ b/packages/yoastseo/spec/languageProcessing/languages/ar/helpers/createBasicWordFormsSpec.js @@ -1,13 +1,13 @@ import { createBasicWordForms } from "../../../../../src/languageProcessing/languages/ar/helpers/createBasicWordForms"; const wordsToStem = [ - // Creates prefixed forms based on an input word that starts with a valid prefix. - /* + // Creates prefixed forms based on an input word that starts with a valid prefix. + /* * Prefix ل "to, because" * To ignore "لتجاهل" * Ignore "تجاهل" */ - { + { original: "لتجاهل", forms: [ // Prefixed forms based on original: @@ -57,13 +57,13 @@ const wordsToStem = [ "وللتجاهل", "وبالتجاهل", ], - }, - /* + }, + /* * Prefix ب "with, in, by" * With happiness "بسعادة" * Happiness "سعادة" */ - { + { original: "بسعادة", forms: [ // Prefixed forms based on original: @@ -113,13 +113,13 @@ const wordsToStem = [ "وللسعادة", "وبالسعادة", ], - }, - /* + }, + /* * Prefix ال "the" * The home "المنزل" * Home "منزل" */ - { + { original: "المنزل", forms: [ // Prefixed forms based on original: @@ -169,13 +169,13 @@ const wordsToStem = [ "وللمنزل", "وبالمنزل", ], - }, - /* + }, + /* * Prefix ك "like, as" * Like a bird "كطائر" * Bird "طائر" */ - { + { original: "كطائر", forms: [ // Prefixed forms based on original: @@ -225,13 +225,13 @@ const wordsToStem = [ "وللطائر", "وبالطائر", ], - }, - /* + }, + /* * Prefix و "and" * And key "ومفتاح" * Key "مفتاح" */ - { + { original: "ومفتاح", forms: [ // Prefixed forms based on original: @@ -281,13 +281,13 @@ const wordsToStem = [ "وللمفتاح", "وبالمفتاح", ], - }, - /* + }, + /* * Prefix ف "so, then" * So I answered you "فأجبتك" * I answered you "أجبتك" */ - { + { original: "فأجبتك", forms: [ // Prefixed forms based on original: @@ -337,13 +337,13 @@ const wordsToStem = [ "وللأجبتك", "وبالأجبتك", ], - }, - /* + }, + /* * Prefix س "will, being willing" * He will write "سيكتب" * He writes "يكتب" */ - { + { original: "سيكتب", forms: [ // Prefixed forms based on original: @@ -393,13 +393,13 @@ const wordsToStem = [ "ولليكتب", "وباليكتب", ], - }, - /* + }, + /* * Prefix أ "Questioning prefix" * Did you eat? "أأكلت" * You ate "أكلت" */ - { + { original: "أأكلت", forms: [ // Prefixed forms based on original: @@ -449,7 +449,7 @@ const wordsToStem = [ "وللأكلت", "وبالأكلت", ], - }, + }, /* * Prefix وب "and with" * and with freedom "وبحرية" @@ -506,7 +506,7 @@ const wordsToStem = [ "وبالحرية", ], }, - /* + /* * Prefix لل and (to) for * and (to) for freedom "للحرية" * freedom "حرية" diff --git a/packages/yoastseo/spec/languageProcessing/languages/nl/helpers/internal/determineStemSpec.js b/packages/yoastseo/spec/languageProcessing/languages/nl/helpers/internal/determineStemSpec.js index eccdedca29e..ade50e5dfc4 100644 --- a/packages/yoastseo/spec/languageProcessing/languages/nl/helpers/internal/determineStemSpec.js +++ b/packages/yoastseo/spec/languageProcessing/languages/nl/helpers/internal/determineStemSpec.js @@ -179,12 +179,12 @@ const wordsToStem = [ [ "klimmen", "klim" ], [ "afklimmen", "afklim" ], [ "beklimmen", "beklim" ], - // Word that gets suffix -en and is in getVowelDoubling list and does not end in t/d (9di-12) + // Word that gets suffix -en and is in getVowelDoubling list and does not end in t/d (9di-12) [ "nivelleren", "nivelleer" ], [ "verafgoden", "verafgood" ], // Word that gets suffix -en and is in noVowelOrConsonantDoubling list and is in noun exception list (9dii-10) [ "vaten", "vat" ], - // Word that gets suffix -en and is in noVowelOrConsonantDoubling list and is in verb exception list (9dii-11) + // Word that gets suffix -en and is in noVowelOrConsonantDoubling list and is in verb exception list (9dii-11) [ "traden", "treed" ], // Word that gets suffix -en and does not end in t/d (9c-12) [ "werken", "werk" ], diff --git a/packages/yoastseo/spec/languageProcessing/researches/altTagCountSpec.js b/packages/yoastseo/spec/languageProcessing/researches/altTagCountSpec.js index 325c4dd0eb2..9400c8b16fb 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/altTagCountSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/altTagCountSpec.js @@ -21,11 +21,11 @@ describe( "Counts images in a text", function() { expect( stringToCheck.withAltNonKeyword ).toBe( 0 ); } ); - it( "returns object with the withAltKeyword as 1 when the keyword is set and present (1-word keyword)", function() { + it( "returns object with the withAltKeyword as 1 when the keyword is set and present (1-word keyword)", function() { const paper = new Paper( "string keyword", { keyword: "keyword", synonyms: "synonym, another synonym" } ); const researcher = new Researcher( paper ); researcher.addResearchData( "morphology", morphologyData ); - buildTree( paper, researcher ); + buildTree( paper, researcher ); const stringToCheck = altTagCountFunction( paper, researcher ); expect( stringToCheck.noAlt ).toBe( 0 ); @@ -303,7 +303,7 @@ describe( "Counts images in a text", function() { } ); } ); -/*describe( "test for alt tag attributes in Japanese", () => { +/* describe( "test for alt tag attributes in Japanese", () => { it( "returns result when no morphology data is supplied", () => { const paper = new Paper( "\"会えるトイレ\" " + "\"我が家はみんな元気じゃないです\"", diff --git a/packages/yoastseo/spec/languageProcessing/researches/countSentencesFromTextSpec.js b/packages/yoastseo/spec/languageProcessing/researches/countSentencesFromTextSpec.js index 79fca670a80..ee23501f00a 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/countSentencesFromTextSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/countSentencesFromTextSpec.js @@ -38,7 +38,7 @@ describe( "counts words in sentences from text", function() { expect( getSentences( paper, new EnglishResearcher() )[ 0 ].sentenceLength ).toBe( 4 ); expect( getSentences( paper, new EnglishResearcher() )[ 1 ].sentenceLength ).toBe( 2 ); } ); - /*it( "returns sentences with question mark in Japanese", function() { + /* it( "returns sentences with question mark in Japanese", function() { paper = new Paper( "雨が降っている。 いつ終わるの? さようなら" ); expect( getSentences( paper, new JapaneseResearcher() )[ 0 ].sentenceLength ).toBe( 8 ); expect( getSentences( paper, new JapaneseResearcher() )[ 1 ].sentenceLength ).toBe( 7 ); diff --git a/packages/yoastseo/spec/languageProcessing/researches/functionWordsInKeyphraseSpec.js b/packages/yoastseo/spec/languageProcessing/researches/functionWordsInKeyphraseSpec.js index 07e7be15571..34a74c8ff9d 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/functionWordsInKeyphraseSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/functionWordsInKeyphraseSpec.js @@ -8,7 +8,7 @@ import JapaneseResearcher from "../../../src/languageProcessing/languages/ja/Res import Paper from "../../../src/values/Paper.js"; describe( "Test for checking if the keyphrase contains function words only", function() { - /*it( "returns true if the keyphrase contains function words only", function() { + /* it( "returns true if the keyphrase contains function words only", function() { const mockPaper = new Paper( "", { keyword: "un deux", locale: "fr_FR" } ); expect( functionWordsInKeyphrase( mockPaper, new FrenchResearcher( mockPaper ) ) ).toBe( true ); } );*/ @@ -49,14 +49,14 @@ describe( "Test for checking if the keyphrase contains function words only", fun expect( functionWordsInKeyphrase( mockPaper, new EnglishResearcher( mockPaper ) ) ).toBe( false ); } ); - /*it( "returns false if there are content words in the keyphrase", function() { + /* it( "returns false if there are content words in the keyphrase", function() { const mockPaper = new Paper( "", { keyword: "daar zat iets en het was mooi", locale: "nl_NL" } ); expect( functionWordsInKeyphrase( mockPaper, new DutchResearcher( mockPaper ) ) ).toBe( false ); } );*/ } ); describe( "Test for checking if the keyphrase contains only function words for a language that uses a custom getWords helper (Japanese)", () => { - /*it( "returns false if the keyphrase is embedded in Japanese quotes", () => { + /* it( "returns false if the keyphrase is embedded in Japanese quotes", () => { let mockPaper = new Paper( "私の猫は愛らしいです。", { keyword: "「私の猫」", locale: "ja" } ); expect( functionWordsInKeyphrase( mockPaper, new JapaneseResearcher( mockPaper ) ) ).toBe( false ); @@ -80,7 +80,7 @@ describe( "Test for checking if the keyphrase contains only function words for a expect( functionWordsInKeyphrase( mockPaper, new JapaneseResearcher( mockPaper ) ) ).toBe( true ); } ); - /*it( "returns true if all the words in the keyphrase are function words (separated by spaces)", () => { + /* it( "returns true if all the words in the keyphrase are function words (separated by spaces)", () => { const mockPaper = new Paper( "私の猫は愛らしいです。", { keyword: "かしら かい を ばっかり", locale: "ja" } ); expect( functionWordsInKeyphrase( mockPaper, new JapaneseResearcher( mockPaper ) ) ).toBe( true ); } );*/ diff --git a/packages/yoastseo/spec/languageProcessing/researches/getPassiveVoiceResult/getPassiveVoiceResultSpec.js b/packages/yoastseo/spec/languageProcessing/researches/getPassiveVoiceResult/getPassiveVoiceResultSpec.js index dadf38bd357..5ff191f7d82 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/getPassiveVoiceResult/getPassiveVoiceResultSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/getPassiveVoiceResult/getPassiveVoiceResultSpec.js @@ -18,7 +18,7 @@ describe( "detecting passive voice in sentences", function() { expect( passiveVoice( paper, researcher ).passives.length ).toBe( 1 ); } ); - // For now the specs for Arabic and Hungarian are skipped. The shouldn't be skipped once Arabic and Hungarian passive voice are refactored. + // For now the specs for Arabic and Hungarian are skipped. The shouldn't be skipped once Arabic and Hungarian passive voice are refactored. it( "returns active voice for morphological language", function() { const paper = new Paper( "كتب الولد الخطاب.", { locale: "ar" } ); const researcher = new ArabicResearcher( paper ); diff --git a/packages/yoastseo/spec/languageProcessing/researches/getSentenceBeginningsSpec.js b/packages/yoastseo/spec/languageProcessing/researches/getSentenceBeginningsSpec.js index 4635d21cac8..c0ed0f9380b 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/getSentenceBeginningsSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/getSentenceBeginningsSpec.js @@ -206,7 +206,7 @@ describe( "gets the sentence beginnings and the count of consecutive duplicates. expect( getSentenceBeginnings( mockPaper, researcher )[ 1 ].count ).toBe( 1 ); } ); - /*it( "returns an object with sentence beginnings and counts for two sentences in German starting with different words.", function() { + /* it( "returns an object with sentence beginnings and counts for two sentences in German starting with different words.", function() { mockPaper = new Paper( "Ich bin wie du. Auf wiedersehen. ", { locale: "de_DE" } ); researcher = new GermanResearcher( mockPaper ); expect( getSentenceBeginnings( mockPaper, researcher )[ 0 ].word ).toBe( "ich" ); @@ -530,7 +530,7 @@ describe( "gets the sentence beginnings and the count of consecutive duplicates. expect( getSentenceBeginnings( mockPaper, researcher )[ 0 ].count ).toBe( 2 ); } );*/ - /*it( "returns an object with sentence beginnings and counts for three sentences all starting with the same words", () => { + /* it( "returns an object with sentence beginnings and counts for three sentences all starting with the same words", () => { mockPaper = new Paper( "Οι γάτες είναι χαριτωμένες. Οι γάτες είναι γλυκές. Οι γάτες είναι αξιολάτρευτες.", { locale: "el" } ); researcher = new GreekResearcher( mockPaper ); @@ -560,7 +560,7 @@ describe( "gets the sentence beginnings and the count of consecutive duplicates. expect( getSentenceBeginnings( mockPaper, researcher )[ 2 ].word ).toBe( "αυτός ο άνδρας" ); } ); - /*it( "returns an object with sentence beginnings and counts for two sentences in Japanese starting with different words.", function() { + /* it( "returns an object with sentence beginnings and counts for two sentences in Japanese starting with different words.", function() { // https://tatoeba.org/en/sentences/show/425148 // https://tatoeba.org/en/sentences/show/9431906 mockPaper = new Paper( "私たちはよくチェスをします。チェスは難しい。", { locale: "ja_JP" } ); diff --git a/packages/yoastseo/spec/languageProcessing/researches/keyphraseDistributionSpec.js b/packages/yoastseo/spec/languageProcessing/researches/keyphraseDistributionSpec.js index 4feb5e06832..f561a3331ce 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/keyphraseDistributionSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/keyphraseDistributionSpec.js @@ -250,9 +250,9 @@ describe( "Test for the research", function() { } ); } ); - //It’s the same as the English one above it, excepts the locale is Italian. But still the English morphology data is added. + // It’s the same as the English one above it, excepts the locale is Italian. But still the English morphology data is added. - /*it( "returns a score (for a language without morphology support) over all sentences and all topic forms; returns markers for " + + /* it( "returns a score (for a language without morphology support) over all sentences and all topic forms; returns markers for " + "sentences that contain the topic", function() { const paper = new Paper( sentencesIT.join( " " ), diff --git a/packages/yoastseo/spec/languageProcessing/researches/keywordCountSpec.js b/packages/yoastseo/spec/languageProcessing/researches/keywordCountSpec.js index 6007ea7c4a5..c1c121b4275 100644 --- a/packages/yoastseo/spec/languageProcessing/researches/keywordCountSpec.js +++ b/packages/yoastseo/spec/languageProcessing/researches/keywordCountSpec.js @@ -2645,7 +2645,7 @@ describe( "Test for counting the keyphrase in a text for Japanese", () => { expect( getKeyphraseCount( mockPaper, researcher ).markings ).toEqual( [ new Mark( { marked: "私のはかわいいです。", original: "私の猫はかわいい猫です。", - } ) ] ); + } ) ] ); } ); it( "counts a string if text with no keyphrase in it.", function() { diff --git a/packages/yoastseo/spec/scoring/assessments/inclusiveLanguage/configuration/otherAssessmentsSpec.js b/packages/yoastseo/spec/scoring/assessments/inclusiveLanguage/configuration/otherAssessmentsSpec.js index 2e73c9f378b..4cb8ba0a97c 100644 --- a/packages/yoastseo/spec/scoring/assessments/inclusiveLanguage/configuration/otherAssessmentsSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/inclusiveLanguage/configuration/otherAssessmentsSpec.js @@ -86,7 +86,7 @@ describe( "Checks various conditions for the 'normal' and 'abnormal' assessments } ); it( "targets potentially harmful phrases that include the word 'abnormal'", () => { const testData = [ - { + { identifier: "behaviorallyAbnormal", text: "I'm afraid this is behaviorally abnormal.", expectedFeedback: "Be careful when using behaviorally abnormal as it is potentially harmful. " + diff --git a/packages/yoastseo/spec/scoring/assessments/readability/SentenceLengthInTextAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/readability/SentenceLengthInTextAssessmentSpec.js index 10cc3eb3b68..f5fb97c36db 100644 --- a/packages/yoastseo/spec/scoring/assessments/readability/SentenceLengthInTextAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/readability/SentenceLengthInTextAssessmentSpec.js @@ -96,7 +96,7 @@ describe( "An assessment for sentence length", function() { ] ); } ); - /*it( "returns the score for 100% long sentences in a language with the sentence length limit of 25 words", function() { + /* it( "returns the score for 100% long sentences in a language with the sentence length limit of 25 words", function() { const mockPaper = new Paper( longSentence25WordsLimit ); const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new ItalianResearcher( mockPaper ) ); @@ -126,7 +126,7 @@ describe( "An assessment for sentence length", function() { expect( assessment.hasMarks() ).toBe( false ); } );*/ - /*it( "returns the score for 100% short sentences in a language that overrides the default with the maximum allowed percentage of long sentences of 15%", function() { + /* it( "returns the score for 100% short sentences in a language that overrides the default with the maximum allowed percentage of long sentences of 15%", function() { const mockPaper = new Paper( shortSentenceDefault ); const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, new PolishResearcher( mockPaper ) ); @@ -196,7 +196,7 @@ describe( "An assessment for sentence length", function() { expect( assessment.hasMarks() ).toBe( true ); } ); - /*it( "returns the score for 25% long sentences in Hebrew", function() { + /* it( "returns the score for 25% long sentences in Hebrew", function() { const mockPaper = new Paper( "text", { locale: "he_IL" } ); const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, Factory.buildMockResearcher( [ { sentence: "", sentenceLength: 16 }, @@ -223,7 +223,7 @@ describe( "An assessment for sentence length", function() { expect( assessment.hasMarks() ).toBe( false ); } );*/ - /*it( "returns the score for 100% short sentences in Turkish", function() { + /* it( "returns the score for 100% short sentences in Turkish", function() { const mockPaper = new Paper(); const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, Factory.buildMockResearcher( [ { sentence: "", sentenceLength: 14 }, @@ -249,7 +249,7 @@ describe( "An assessment for sentence length", function() { expect( assessment.hasMarks() ).toBe( true ); } ); - /*it( "returns the score for 100% short sentences in Japanese", function() { + /* it( "returns the score for 100% short sentences in Japanese", function() { const mockPaper = new Paper( "" ); const assessment = new SentenceLengthInTextAssessment().getResult( mockPaper, Factory.buildMockResearcher( [ { sentence: "", sentenceLength: 39 }, @@ -411,7 +411,7 @@ describe( "An assessment for sentence length for cornerstone content", function( expect( assessment.hasMarks() ).toBe( true ); } ); - /*it( "returns the score for 20% long sentences in Polish using the cornerstone configuration", function() { + /* it( "returns the score for 20% long sentences in Polish using the cornerstone configuration", function() { const mockPaper = new Paper( longSentenceDefault.repeat( 4 ) + shortSentenceDefault.repeat( 16 ) ); const assessment = new SentenceLengthInTextAssessment( { slightlyTooMany: 20, diff --git a/packages/yoastseo/spec/scoring/assessments/readability/SubheadingDistributionTooLongAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/readability/SubheadingDistributionTooLongAssessmentSpec.js index 0139b6569f1..a8a19be98e0 100644 --- a/packages/yoastseo/spec/scoring/assessments/readability/SubheadingDistributionTooLongAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/readability/SubheadingDistributionTooLongAssessmentSpec.js @@ -628,7 +628,7 @@ describe( "Language-specific configuration for specific types of content is used expect( assessment._config.slightlyTooMany ).toEqual( japaneseConfig.cornerstoneParameters.slightlyTooMany ); expect( assessment._config.farTooMany ).toEqual( japaneseConfig.cornerstoneParameters.farTooMany ); } ); - //Only need one test for japanese to test getLanguageSpecificConfig. The other tests are redundant. + // Only need one test for japanese to test getLanguageSpecificConfig. The other tests are redundant. // it( "should score short cornerstone content in Japanese (<500 characters), " + // "which does not have subheadings, as OK.", function() { // const paper = new Paper( shortCornerstoneTextJapanese ); @@ -665,7 +665,7 @@ describe( "A test for scoring too long text fragments without a subheading for l " Add subheadings to improve readability." ); } ); // you need 1 test to test the getLanguageSpecificConfig in the get result method. The rest of the tests is redundant. - /*it( "Scores a text where multiple sections are slightly too long.", function() { + /* it( "Scores a text where multiple sections are slightly too long.", function() { const paper = new Paper( shortTextJapanese + subheading + longTextJapanese + subheading + longTextJapanese ); const assessment = subheadingDistributionTooLong.getResult( paper, new JapaneseResearcher( paper ) ); diff --git a/packages/yoastseo/spec/scoring/assessments/seo/KeyphraseLengthAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/KeyphraseLengthAssessmentSpec.js index 4e61409f65d..61607d3e87b 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/KeyphraseLengthAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/KeyphraseLengthAssessmentSpec.js @@ -264,7 +264,7 @@ describe( "the keyphrase length assessment for regular posts and pages", functio } ); } ); -//Japanese tests do test character specific logic. So not removed. +// Japanese tests do test character specific logic. So not removed. describe( "the keyphrase length assessment for Japanese", function() { it( "should clear the memoized data", function() { primeLanguageSpecificData.cache.clear(); diff --git a/packages/yoastseo/spec/scoring/assessments/seo/MetaDescriptionKeywordAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/MetaDescriptionKeywordAssessmentSpec.js index f6c7751a5f3..59c1a25e00f 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/MetaDescriptionKeywordAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/MetaDescriptionKeywordAssessmentSpec.js @@ -124,7 +124,7 @@ describe( "a test for the meta description keyword assessment when the exact mat } ); - /*it( "returns a bad result when the meta description doesn't contain the exact match of the keyphrase in Japanese", function() { + /* it( "returns a bad result when the meta description doesn't contain the exact match of the keyphrase in Japanese", function() { const mockPaper = new Paper( "", { keyword: "『小さい花の刺繍』", synonyms: "野生のハーブの刺繡", description: "小さくて可愛い花の刺繍に関する一般一般の記事です。私は美しい猫を飼っています。" } ); diff --git a/packages/yoastseo/src/config/transliterationsWPstyle.js b/packages/yoastseo/src/config/transliterationsWPstyle.js index 6091dce554f..0d61fbeb29b 100644 --- a/packages/yoastseo/src/config/transliterationsWPstyle.js +++ b/packages/yoastseo/src/config/transliterationsWPstyle.js @@ -346,10 +346,10 @@ const transliterationsGeneral = [ * | U+1EF9 | ỹ | y | Latin small letter y with tilde | */ - // Currency signs: + // Currency signs: { letter: /[\u00A3]/g, alternative: "" }, { letter: /[\u20AC]/g, alternative: "E" }, - // Decompositions for Latin-1 Supplement: + // Decompositions for Latin-1 Supplement: { letter: /[\u00AA]/g, alternative: "a" }, { letter: /[\u00BA]/g, alternative: "o" }, { letter: /[\u00C0]/g, alternative: "A" }, @@ -414,7 +414,7 @@ const transliterationsGeneral = [ { letter: /[\u00FD]/g, alternative: "y" }, { letter: /[\u00FE]/g, alternative: "th" }, { letter: /[\u00FF]/g, alternative: "y" }, - // Decompositions for Latin Extended-A: + // Decompositions for Latin Extended-A: { letter: /[\u0100]/g, alternative: "A" }, { letter: /[\u0101]/g, alternative: "a" }, { letter: /[\u0102]/g, alternative: "A" }, @@ -563,12 +563,12 @@ const transliterationsGeneral = [ { letter: /[\u01DA]/g, alternative: "u" }, { letter: /[\u01DB]/g, alternative: "U" }, { letter: /[\u01DC]/g, alternative: "u" }, - // Decompositions for Latin Extended-B: + // Decompositions for Latin Extended-B: { letter: /[\u0218]/g, alternative: "S" }, { letter: /[\u0219]/g, alternative: "s" }, { letter: /[\u021A]/g, alternative: "T" }, { letter: /[\u021B]/g, alternative: "t" }, - // Vowels with diacritic (Chinese, Hanyu Pinyin): + // Vowels with diacritic (Chinese, Hanyu Pinyin): { letter: /[\u0251]/g, alternative: "a" }, { letter: /[\u1EA0]/g, alternative: "A" }, { letter: /[\u1EA1]/g, alternative: "a" }, diff --git a/packages/yoastseo/src/languageProcessing/languages/it/helpers/internal/stem.js b/packages/yoastseo/src/languageProcessing/languages/it/helpers/internal/stem.js index 12137d2d200..f3d2600c592 100644 --- a/packages/yoastseo/src/languageProcessing/languages/it/helpers/internal/stem.js +++ b/packages/yoastseo/src/languageProcessing/languages/it/helpers/internal/stem.js @@ -402,7 +402,7 @@ export default function stem( word, morphologyData ) { // Step 2: Verb suffix removal. if ( wordAfter0 === wordAfter1 ) { word = removeVerbSuffixes( word, morphologyData, rvText ); - } + } rvText = word.substring( rv ); diff --git a/packages/yoastseo/src/languageProcessing/researches/findKeywordInFirstParagraph.js b/packages/yoastseo/src/languageProcessing/researches/findKeywordInFirstParagraph.js index 4a9bac02a1c..a8bfea9ef70 100644 --- a/packages/yoastseo/src/languageProcessing/researches/findKeywordInFirstParagraph.js +++ b/packages/yoastseo/src/languageProcessing/researches/findKeywordInFirstParagraph.js @@ -37,7 +37,7 @@ export default function( paper, researcher ) { return ! ( paragraph.childNodes && paragraph.childNodes[ 0 ] && createShortcodeTagsRegex( [ "caption" ] ).test( paragraph.childNodes[ 0 ].value ) ); } ); - const firstParagraph = paragraphs[ 0 ]; + const firstParagraph = paragraphs[ 0 ]; const topicForms = researcher.getResearch( "morphology" ); const matchWordCustomHelper = researcher.getHelper( "matchWordCustomHelper" ); diff --git a/packages/yoastseo/src/languageProcessing/researches/keywordCount.js b/packages/yoastseo/src/languageProcessing/researches/keywordCount.js index 2512317c8b7..2cfac56e0f2 100644 --- a/packages/yoastseo/src/languageProcessing/researches/keywordCount.js +++ b/packages/yoastseo/src/languageProcessing/researches/keywordCount.js @@ -21,7 +21,7 @@ import { filterShortcodesFromHTML } from "../helpers"; * @returns {{markings: Mark[], count: number}} The number of keyphrase occurrences in the text and the Mark objects of the matches. */ export function countKeyphraseInText( sentences, keyphraseForms, locale, matchWordCustomHelper, - isExactMatchRequested, customSplitIntoTokensHelper ) { + isExactMatchRequested, customSplitIntoTokensHelper ) { const result = { count: 0, markings: [] }; sentences.forEach( sentence => { diff --git a/packages/yoastseo/src/scoring/assessments/inclusiveLanguage/InclusiveLanguageAssessment.js b/packages/yoastseo/src/scoring/assessments/inclusiveLanguage/InclusiveLanguageAssessment.js index da92d1bdd14..25877b3f8d5 100644 --- a/packages/yoastseo/src/scoring/assessments/inclusiveLanguage/InclusiveLanguageAssessment.js +++ b/packages/yoastseo/src/scoring/assessments/inclusiveLanguage/InclusiveLanguageAssessment.js @@ -38,7 +38,7 @@ export default class InclusiveLanguageAssessment { * @returns {void} */ constructor( { identifier, nonInclusivePhrases, inclusiveAlternatives, - score, feedbackFormat, learnMoreUrl, rule, ruleDescription, caseSensitive, category } ) { + score, feedbackFormat, learnMoreUrl, rule, ruleDescription, caseSensitive, category } ) { this.identifier = identifier; this.nonInclusivePhrases = nonInclusivePhrases; this.inclusiveAlternatives = inclusiveAlternatives; From ab34229778fb2abbc6a37ab78ef3466b0dad25fe Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:41:36 +0100 Subject: [PATCH 41/92] Fix remaining ESLint errors in yoastseo --- .../languages/en/helpers/internal/getVerbStemSpec.js | 2 +- .../assessments/seo/TextTitleAssessmentSpec.js | 2 +- .../getProminentWordsForInternalLinking.js | 12 ++++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/yoastseo/spec/languageProcessing/languages/en/helpers/internal/getVerbStemSpec.js b/packages/yoastseo/spec/languageProcessing/languages/en/helpers/internal/getVerbStemSpec.js index ddaba3255bb..ddc6d577571 100644 --- a/packages/yoastseo/spec/languageProcessing/languages/en/helpers/internal/getVerbStemSpec.js +++ b/packages/yoastseo/spec/languageProcessing/languages/en/helpers/internal/getVerbStemSpec.js @@ -4,7 +4,7 @@ import { checkIrregulars, normalizePrefixed, } from "../../../../../../src/languageProcessing/languages/en/helpers/internal/getVerbStem"; -import isUndefined from "lodash-es/isUndefined"; +import isUndefined from "lodash/isUndefined"; const morphologyData = getMorphologyData( "en" ); const regexVerb = morphologyData.en.verbs.regexVerb; diff --git a/packages/yoastseo/spec/scoring/assessments/seo/TextTitleAssessmentSpec.js b/packages/yoastseo/spec/scoring/assessments/seo/TextTitleAssessmentSpec.js index c232f58867e..e26e3a31697 100644 --- a/packages/yoastseo/spec/scoring/assessments/seo/TextTitleAssessmentSpec.js +++ b/packages/yoastseo/spec/scoring/assessments/seo/TextTitleAssessmentSpec.js @@ -1,6 +1,6 @@ import TextTitleAssessment from "../../../../src/scoring/assessments/seo/TextTitleAssessment"; -import { values } from "yoastseo"; +import { values } from "../../../../src"; const { Paper } = values; diff --git a/packages/yoastseo/src/languageProcessing/researches/getProminentWordsForInternalLinking.js b/packages/yoastseo/src/languageProcessing/researches/getProminentWordsForInternalLinking.js index feca93e50b2..f95b51275c0 100644 --- a/packages/yoastseo/src/languageProcessing/researches/getProminentWordsForInternalLinking.js +++ b/packages/yoastseo/src/languageProcessing/researches/getProminentWordsForInternalLinking.js @@ -25,16 +25,20 @@ const sanitizeText = function( text ) { return removeEmailAddresses( text ); }; +/** + * @typedef ProminentWordsForInternalLinking + * @property {ProminentWord[]} prominentWords Prominent words for this paper, filtered and sorted. + * @property {boolean} hasMetaDescription Whether the metadescription is available in the input paper. + * @property {boolean} hasTitle Whether the title is available in the input paper. + */ + /** * Retrieves the prominent words from the given paper. * * @param {Paper} paper The paper to determine the prominent words of. * @param {Researcher} researcher The researcher to use for analysis. * - * @returns {Object} result A compound result object. - * @returns {ProminentWord[]} result.prominentWords Prominent words for this paper, filtered and sorted. - * @returns {boolean} result.hasMetaDescription Whether the metadescription is available in the input paper. - * @returns {boolean} result.hasTitle Whether the title is available in the input paper. + * @returns {ProminentWordsForInternalLinking} result A compound result object. */ function getProminentWordsForInternalLinking( paper, researcher ) { const functionWords = researcher.getConfig( "functionWords" ); From 906cbf1bffb26e657c735c9834a7cf7acb371564 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:31:55 +0100 Subject: [PATCH 42/92] Update social-metadata-forms to a flat eslint config --- .../social-metadata-forms/eslint.config.mjs | 38 +++++++++++++++++++ .../jest/__mocks__/@wordpress/i18n.js | 2 +- packages/social-metadata-forms/package.json | 3 ++ .../src/SocialMetadataPreviewForm.js | 6 +-- .../src/redux/reducers/formReducer.js | 4 +- 5 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 packages/social-metadata-forms/eslint.config.mjs diff --git a/packages/social-metadata-forms/eslint.config.mjs b/packages/social-metadata-forms/eslint.config.mjs new file mode 100644 index 00000000000..d3ec5aa28e9 --- /dev/null +++ b/packages/social-metadata-forms/eslint.config.mjs @@ -0,0 +1,38 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build" ] }, + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + }, + }, + rules: { + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + }, + }, + { + files: [ "*.config.*", "jest/**" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/social-metadata-forms/jest/__mocks__/@wordpress/i18n.js b/packages/social-metadata-forms/jest/__mocks__/@wordpress/i18n.js index 0794fa12ab4..6935667003a 100644 --- a/packages/social-metadata-forms/jest/__mocks__/@wordpress/i18n.js +++ b/packages/social-metadata-forms/jest/__mocks__/@wordpress/i18n.js @@ -1,4 +1,4 @@ -/* eslint-disable require-jsdoc */ +/* eslint-disable jsdoc/require-jsdoc */ import { sprintf, setLocaleData } from "@wordpress/i18n"; diff --git a/packages/social-metadata-forms/package.json b/packages/social-metadata-forms/package.json index 5156d4294cd..f8e992f9c97 100644 --- a/packages/social-metadata-forms/package.json +++ b/packages/social-metadata-forms/package.json @@ -45,6 +45,9 @@ "@yoast/browserslist-config": "^1.2.3", "babel-plugin-styled-components": "^2.0.6", "browserslist": "^4.7.3", + "eslint": "^9.16.0", + "eslint-config-yoast": "^6.0.0", + "globals": "^15.13.0", "jest-styled-components": "^7.0.3", "raf": "^3.4.1", "react-test-renderer": "^18.2.0" diff --git a/packages/social-metadata-forms/src/SocialMetadataPreviewForm.js b/packages/social-metadata-forms/src/SocialMetadataPreviewForm.js index 25284a7bc22..348612dffc2 100644 --- a/packages/social-metadata-forms/src/SocialMetadataPreviewForm.js +++ b/packages/social-metadata-forms/src/SocialMetadataPreviewForm.js @@ -51,9 +51,9 @@ const Caret = styled.div` height: 24px; background-image: url( ${ props => getDirectionalStyle( - angleRight( getCaretColor( props.isActive ) ), - angleLeft( getCaretColor( props.isActive ) ) - ) } + angleRight( getCaretColor( props.isActive ) ), + angleLeft( getCaretColor( props.isActive ) ) + ) } ); color: ${ props => getCaretColor( props.isActive ) }; background-size: 24px; diff --git a/packages/social-metadata-forms/src/redux/reducers/formReducer.js b/packages/social-metadata-forms/src/redux/reducers/formReducer.js index b5a5382f9ee..4f271cbf5b5 100644 --- a/packages/social-metadata-forms/src/redux/reducers/formReducer.js +++ b/packages/social-metadata-forms/src/redux/reducers/formReducer.js @@ -59,7 +59,7 @@ function socialPreview( state = initialState, action ) { id: null, alt: "", } }; - default: + default: return state; } } @@ -80,7 +80,7 @@ function createNamedWrapperReducer( reducerFunction, platformName ) { return initialState; } if ( platform !== platformName ) { - return state; + return state; } return reducerFunction( state, action ); }; From 47490b0fe4fe546d14d9f505f28c60a51f40eb12 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:55:45 +0100 Subject: [PATCH 43/92] Update social-metadata-previews to a flat eslint config --- .../search-metadata-previews/.eslintrc.js | 62 ------------------- .../eslint.config.mjs | 42 +++++++++++++ .../search-metadata-previews/package.json | 4 +- .../src/snippet-editor/SnippetEditorFields.js | 6 +- .../tests/__mocks__/@wordpress/i18n.js | 2 +- 5 files changed, 47 insertions(+), 69 deletions(-) delete mode 100644 packages/search-metadata-previews/.eslintrc.js create mode 100644 packages/search-metadata-previews/eslint.config.mjs diff --git a/packages/search-metadata-previews/.eslintrc.js b/packages/search-metadata-previews/.eslintrc.js deleted file mode 100644 index 29711f47c72..00000000000 --- a/packages/search-metadata-previews/.eslintrc.js +++ /dev/null @@ -1,62 +0,0 @@ -module.exports = { - root: true, - "extends": [ - "yoast", - ], - settings: { - react: { - version: "detect", - }, - }, - parserOptions: { - ecmaVersion: 2020, - sourceType: "module", - }, - ignorePatterns: [ - "/build/", - "/coverage/", - "/dist/", - ], - rules: { - "no-prototype-builtins": 0, - "comma-dangle": [ - "error", - { - arrays: "always-multiline", - objects: "always-multiline", - imports: "always-multiline", - exports: "always-multiline", - functions: "never", - }, - ], - "import/no-unresolved": [ - "error", - { - ignore: [ "^@yoast/(components|helpers|replacement-variable-editor|style-guide)", "yoastseo" ], - }, - ], - }, - overrides: [ - { - files: [ "tests/**/*.js" ], - env: { - jest: true, - }, - rules: { - "no-restricted-imports": 0, - }, - }, - { - files: [ "**/*.js" ], - rules: { - // A wrapping label is not necessary when there already is an htmlFor attribute. - "react/default-props-match-prop-types": 1, - "react/no-unused-prop-types": 1, - "react/no-access-state-in-setstate": 1, - "react/no-unused-state": 1, - "react/jsx-no-bind": 1, - "react/require-default-props": 1, - }, - }, - ], -}; diff --git a/packages/search-metadata-previews/eslint.config.mjs b/packages/search-metadata-previews/eslint.config.mjs new file mode 100644 index 00000000000..07a0d07e726 --- /dev/null +++ b/packages/search-metadata-previews/eslint.config.mjs @@ -0,0 +1,42 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build" ] }, + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + }, + }, + rules: { + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + + // Deviate from the yoast config to allow existing usages of .bind in React components and unused state. New cases are still prohibited. + "react/jsx-no-bind": "warn", + "react/no-unused-state": "warn", + }, + }, + { + files: [ "*.config.*" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/search-metadata-previews/package.json b/packages/search-metadata-previews/package.json index 45b29899cdf..bea1f66d08d 100644 --- a/packages/search-metadata-previews/package.json +++ b/packages/search-metadata-previews/package.json @@ -51,9 +51,7 @@ "browserslist": "^4.7.3", "eslint": "^8.57.0", "eslint-config-yoast": "^6.0.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.34.1", + "globals": "^15.13.0", "jest-styled-components": "^7.0.3" }, "peerDependencies": { diff --git a/packages/search-metadata-previews/src/snippet-editor/SnippetEditorFields.js b/packages/search-metadata-previews/src/snippet-editor/SnippetEditorFields.js index 426634d1a63..f3265f01ac9 100644 --- a/packages/search-metadata-previews/src/snippet-editor/SnippetEditorFields.js +++ b/packages/search-metadata-previews/src/snippet-editor/SnippetEditorFields.js @@ -189,7 +189,7 @@ class SnippetEditorFields extends React.Component { * * @returns {void} */ - onFocusTitle() { + onFocusTitle() { this.props.onFocus( "title" ); } @@ -229,7 +229,7 @@ class SnippetEditorFields extends React.Component { * * @returns {void} */ - onChangeSlug( event ) { + onChangeSlug( event ) { this.props.onChange( "slug", event.target.value ); } @@ -238,7 +238,7 @@ class SnippetEditorFields extends React.Component { * * @returns {void} */ - onFocusDescription() { + onFocusDescription() { this.props.onFocus( "description" ); } diff --git a/packages/search-metadata-previews/tests/__mocks__/@wordpress/i18n.js b/packages/search-metadata-previews/tests/__mocks__/@wordpress/i18n.js index 0794fa12ab4..6935667003a 100644 --- a/packages/search-metadata-previews/tests/__mocks__/@wordpress/i18n.js +++ b/packages/search-metadata-previews/tests/__mocks__/@wordpress/i18n.js @@ -1,4 +1,4 @@ -/* eslint-disable require-jsdoc */ +/* eslint-disable jsdoc/require-jsdoc */ import { sprintf, setLocaleData } from "@wordpress/i18n"; From 5d60025448b1517c71089135e20d32d76362e381 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:09:00 +0100 Subject: [PATCH 44/92] Update replacement-variable-editor to a flat eslint config --- .../replacement-variable-editor/.eslintrc.js | 57 ------------------- .../eslint.config.mjs | 38 +++++++++++++ .../replacement-variable-editor/package.json | 4 +- .../src/SettingsSnippetEditorFields.js | 4 +- .../tests/serializationTest.js | 2 +- 5 files changed, 42 insertions(+), 63 deletions(-) delete mode 100644 packages/replacement-variable-editor/.eslintrc.js create mode 100644 packages/replacement-variable-editor/eslint.config.mjs diff --git a/packages/replacement-variable-editor/.eslintrc.js b/packages/replacement-variable-editor/.eslintrc.js deleted file mode 100644 index 1545f2075a8..00000000000 --- a/packages/replacement-variable-editor/.eslintrc.js +++ /dev/null @@ -1,57 +0,0 @@ -module.exports = { - root: true, - "extends": [ - "yoast", - ], - settings: { - react: { - version: "detect", - }, - }, - parserOptions: { - ecmaVersion: 2020, - sourceType: "module", - }, - ignorePatterns: [ - "/build/", - "/coverage/", - "/dist/", - ], - rules: { - "no-prototype-builtins": 0, - "comma-dangle": [ - "error", - { - arrays: "always-multiline", - objects: "always-multiline", - imports: "always-multiline", - exports: "always-multiline", - functions: "never", - }, - ], - "import/no-unresolved": [ - "error", - { - ignore: [ "^@yoast/(components|helpers|style-guide)" ], - }, - ], - }, - overrides: [ - { - files: [ "tests/**/*.js" ], - env: { - jest: true, - }, - rules: { - "no-restricted-imports": 0, - }, - }, - { - files: [ "**/*.js" ], - rules: { - "react/jsx-no-bind": 1, - "react/require-default-props": 1, - }, - }, - ], -}; diff --git a/packages/replacement-variable-editor/eslint.config.mjs b/packages/replacement-variable-editor/eslint.config.mjs new file mode 100644 index 00000000000..e69d9a907da --- /dev/null +++ b/packages/replacement-variable-editor/eslint.config.mjs @@ -0,0 +1,38 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build" ] }, + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + }, + }, + rules: { + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + }, + }, + { + files: [ "*.config.*" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/replacement-variable-editor/package.json b/packages/replacement-variable-editor/package.json index 30b493b14b9..0dcbf5c3a4d 100644 --- a/packages/replacement-variable-editor/package.json +++ b/packages/replacement-variable-editor/package.json @@ -53,9 +53,7 @@ "babel-plugin-styled-components": "^2.0.6", "eslint": "^8.57.0", "eslint-config-yoast": "^6.0.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.34.1", + "globals": "^15.13.0", "jest-styled-components": "^7.0.3", "react-test-renderer": "^18.2.0" }, diff --git a/packages/replacement-variable-editor/src/SettingsSnippetEditorFields.js b/packages/replacement-variable-editor/src/SettingsSnippetEditorFields.js index 7018762aa9c..50803362a93 100644 --- a/packages/replacement-variable-editor/src/SettingsSnippetEditorFields.js +++ b/packages/replacement-variable-editor/src/SettingsSnippetEditorFields.js @@ -83,7 +83,7 @@ class SettingsSnippetEditorFields extends React.Component { * * @returns {void} */ - setDescriptionRef( ref ) { + setDescriptionRef( ref ) { this.setRef( "description", ref ); } @@ -152,7 +152,7 @@ class SettingsSnippetEditorFields extends React.Component { * * @returns {void} */ - onFocusDescription() { + onFocusDescription() { this.props.onFocus( "description" ); } diff --git a/packages/replacement-variable-editor/tests/serializationTest.js b/packages/replacement-variable-editor/tests/serializationTest.js index 991204f5b48..64b4805fc50 100644 --- a/packages/replacement-variable-editor/tests/serializationTest.js +++ b/packages/replacement-variable-editor/tests/serializationTest.js @@ -421,7 +421,7 @@ describe( "replaceReplacementVariables", () => { } ); let editorState = EditorState.createWithContent( convertFromRaw( contentState ) ); - editorState = EditorState.acceptSelection( editorState, selection ); + editorState = EditorState.acceptSelection( editorState, selection ); const replacementVariables = [ { name: "title", label: "Title", value: "My title" } ]; const actual = replaceReplacementVariables( editorState, replacementVariables ).getSelection(); From 89e892b8a6234b91da0f6a5f81dec9f5d18b6ee1 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:59:25 +0100 Subject: [PATCH 45/92] Update related-keyphrase-suggestions to a flat eslint config --- .../.eslintignore | 2 - .../.eslintrc.js | 81 ------------------- .../eslint.config.mjs | 46 +++++++++++ .../package.json | 6 +- .../scripts/watch-css.js | 2 +- .../src/elements/TableButton/index.js | 4 +- .../components/RequestLimitReached.js | 2 +- .../tailwind.config.js | 10 +-- yarn.lock | 18 +---- 9 files changed, 57 insertions(+), 114 deletions(-) delete mode 100644 packages/related-keyphrase-suggestions/.eslintignore delete mode 100644 packages/related-keyphrase-suggestions/.eslintrc.js create mode 100644 packages/related-keyphrase-suggestions/eslint.config.mjs diff --git a/packages/related-keyphrase-suggestions/.eslintignore b/packages/related-keyphrase-suggestions/.eslintignore deleted file mode 100644 index 16d8d68f4c1..00000000000 --- a/packages/related-keyphrase-suggestions/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -build/ -node_modules/ \ No newline at end of file diff --git a/packages/related-keyphrase-suggestions/.eslintrc.js b/packages/related-keyphrase-suggestions/.eslintrc.js deleted file mode 100644 index 1e1f0fe46c9..00000000000 --- a/packages/related-keyphrase-suggestions/.eslintrc.js +++ /dev/null @@ -1,81 +0,0 @@ -module.exports = { - root: true, - "extends": [ - "yoast", - ], - parser: "@babel/eslint-parser", - parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - }, - plugins: [ - "@babel", - ], - settings: { - react: { - version: "detect", - }, - }, - rules: { - "no-unused-expressions": [ - "error", - { - allowShortCircuit: true, - allowTernary: true, - }, - ], - "max-len": [ - "error", - { - code: 150, - ignoreStrings: true, - ignorePattern: "[\t]*\n", - }, - ], - "space-unary-ops": [ - "error", - { - words: true, - nonwords: false, - overrides: { - "!": true, - "!!": true, - }, - }, - ], - "space-before-function-paren": [ - "error", - { - anonymous: "never", - named: "never", - asyncArrow: "always", - }, - ], - "template-curly-spacing": [ - "error", - "always", - ], - "import/no-unresolved": [ - "error", - { - ignore: [ - // Ignore UI library, or we have to build the code before linting. - // Because `main` in `package.json` points to the `build/index.js` (in the UI library), which is not present before building. - // As we are dealing with our source, not the actual NPM download, due to the monorepo setup. - "^@yoast/ui-library", - ], - }, - ], - }, - overrides: [ - { - files: [ "src/**/*.stories.js", "src/**/stories.js" ], - rules: { - "no-unused-vars": "off", - "require-jsdoc": "off", - "valid-jsdoc": "off", - "react/prop-types": "off", - }, - }, - ], -}; diff --git a/packages/related-keyphrase-suggestions/eslint.config.mjs b/packages/related-keyphrase-suggestions/eslint.config.mjs new file mode 100644 index 00000000000..9cc199dccfb --- /dev/null +++ b/packages/related-keyphrase-suggestions/eslint.config.mjs @@ -0,0 +1,46 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build" ] }, + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.builtin, + ...globals.browser, + }, + }, + rules: { + // Deviate from the Yoast config to allow use of short-circuit and ternary expressions to call functions with side effects, like setState. + "no-unused-expressions": [ + "error", + { + allowShortCircuit: true, + allowTernary: true, + }, + ], + + // Deviate from the Yoast config to force spacing before async arrow function parentheses. + "stylistic/space-before-function-paren": [ + "error", + { + anonymous: "never", + named: "never", + asyncArrow: "always", + }, + ], + }, + }, + { + files: [ "*.config.js", "scripts/**", ".storybook/**" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/related-keyphrase-suggestions/package.json b/packages/related-keyphrase-suggestions/package.json index 6ed52811d13..8ffe04bc238 100644 --- a/packages/related-keyphrase-suggestions/package.json +++ b/packages/related-keyphrase-suggestions/package.json @@ -26,8 +26,6 @@ "devDependencies": { "@babel/cli": "^7.25.9", "@babel/core": "^7.26.0", - "@babel/eslint-parser": "^7.25.9", - "@babel/eslint-plugin": "^7.25.9", "@babel/parser": "^7.26.1", "@babel/plugin-transform-optional-chaining": "^7.25.9", "@babel/plugin-transform-runtime": "^7.25.9", @@ -54,9 +52,7 @@ "css-loader": "^7.1.2", "eslint": "^8.57.0", "eslint-config-yoast": "^6.0.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.37.2", + "globals": "^15.13.0", "postcss": "^8.4.47", "postcss-loader": "^8.1.1", "puppeteer": "^23.6.0", diff --git a/packages/related-keyphrase-suggestions/scripts/watch-css.js b/packages/related-keyphrase-suggestions/scripts/watch-css.js index f912387b0e0..fe465e234cd 100644 --- a/packages/related-keyphrase-suggestions/scripts/watch-css.js +++ b/packages/related-keyphrase-suggestions/scripts/watch-css.js @@ -1,5 +1,5 @@ #!/usr/local/bin/node -/* eslint-disable require-jsdoc, no-console */ +/* eslint-disable jsdoc/require-jsdoc, no-console */ const fs = require( "fs" ); const path = require( "path" ); const { execSync } = require( "child_process" ); diff --git a/packages/related-keyphrase-suggestions/src/elements/TableButton/index.js b/packages/related-keyphrase-suggestions/src/elements/TableButton/index.js index a1c149c4bf3..d8060c91f41 100644 --- a/packages/related-keyphrase-suggestions/src/elements/TableButton/index.js +++ b/packages/related-keyphrase-suggestions/src/elements/TableButton/index.js @@ -47,7 +47,7 @@ const SuccessMessage = ( { variant, className = "" } ) => { classNames( "yst-success-message yst-animate-appear-disappear", `yst-success-message-${ variant }`, className, - ) } + ) } > { variants[ variant ].success.label } @@ -78,7 +78,7 @@ export const TableButton = forwardRef( ( { variant = "add", className = "", ...p className={ classNames( "yst-table-button", className, - ) } + ) } > { variants[ variant ].button.label } diff --git a/packages/related-keyphrase-suggestions/src/elements/UserMessage/components/RequestLimitReached.js b/packages/related-keyphrase-suggestions/src/elements/UserMessage/components/RequestLimitReached.js index 31ece032553..85796d7bbde 100644 --- a/packages/related-keyphrase-suggestions/src/elements/UserMessage/components/RequestLimitReached.js +++ b/packages/related-keyphrase-suggestions/src/elements/UserMessage/components/RequestLimitReached.js @@ -15,7 +15,7 @@ import { ArrowNarrowRightIcon } from "@heroicons/react/outline"; export const RequestLimitReached = ( { upsellLink, className = "" } ) => { return ( -
+
{ sprintf( /* translators: %s : Expands to "Semrush". */ __( "You've reached your request limit for today. Check back tomorrow or upgrade your plan over at %s.", "wordpress-seo" ), diff --git a/packages/related-keyphrase-suggestions/tailwind.config.js b/packages/related-keyphrase-suggestions/tailwind.config.js index 14fe0d82808..f26b4e3cb2f 100644 --- a/packages/related-keyphrase-suggestions/tailwind.config.js +++ b/packages/related-keyphrase-suggestions/tailwind.config.js @@ -9,17 +9,17 @@ module.exports = { ], theme: { extend: { - animation: { + animation: { "appear-disappear": "appearDisappear 1s ease-out forwards", - }, - keyframes: { + }, + keyframes: { appearDisappear: { "0%": { opacity: "0" }, "20%": { opacity: "1" }, "70%": { opacity: "1" }, "100%": { opacity: "0" }, }, - }, + }, }, - }, + }, }; diff --git a/yarn.lock b/yarn.lock index d5481dc2a88..646ba483e71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -171,15 +171,6 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.1" -"@babel/eslint-parser@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz#603c68a63078796527bc9d0833f5e52dd5f9224c" - integrity sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ== - dependencies: - "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" - eslint-visitor-keys "^2.1.0" - semver "^6.3.1" - "@babel/eslint-plugin@^7.17.7": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.23.5.tgz#77d4703e9f83b81e9fc13382810372beb2f10f94" @@ -187,13 +178,6 @@ dependencies: eslint-rule-composer "^0.3.0" -"@babel/eslint-plugin@^7.25.9": - version "7.25.9" - resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.25.9.tgz#a5b6cc46085e0a7d45c5dae36055ce30c5125dab" - integrity sha512-MWg1lz+JiP9l1fXkE0qCUVo+1XwgNRPs6GTc88hmw6qN3AdgmfTSkyHt0e1xOTsKdXW5xlh2Lsk3wrFZbW5rzQ== - dependencies: - eslint-rule-composer "^0.3.0" - "@babel/generator@^7.23.0", "@babel/generator@^7.23.6", "@babel/generator@^7.7.2": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" @@ -15955,7 +15939,7 @@ eslint-plugin-react@^7.34.1: semver "^6.3.1" string.prototype.matchall "^4.0.10" -eslint-plugin-react@^7.35.0, eslint-plugin-react@^7.37.2: +eslint-plugin-react@^7.35.0: version "7.37.2" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz#cd0935987876ba2900df2f58339f6d92305acc7a" integrity sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w== From cf69443fe91b0c393b4e10b1ff9c0cc41957b9ff Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:30:17 +0100 Subject: [PATCH 46/92] Update feature-flag to a flat eslint config --- packages/feature-flag/eslint.config.mjs | 37 +++++++++++++++++++++++++ packages/feature-flag/jest.config.js | 2 +- packages/feature-flag/package.json | 7 +++-- 3 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 packages/feature-flag/eslint.config.mjs diff --git a/packages/feature-flag/eslint.config.mjs b/packages/feature-flag/eslint.config.mjs new file mode 100644 index 00000000000..4c25ad04ab2 --- /dev/null +++ b/packages/feature-flag/eslint.config.mjs @@ -0,0 +1,37 @@ +import globals from "globals"; +import yoastConfig from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build" ] }, + ...yoastConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + }, + }, + rules: { + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + }, + }, + { + files: [ "*.config.*" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/feature-flag/jest.config.js b/packages/feature-flag/jest.config.js index 4e2ec903c50..1de1f0143ed 100644 --- a/packages/feature-flag/jest.config.js +++ b/packages/feature-flag/jest.config.js @@ -15,7 +15,7 @@ const config = { "clover", "text-summary", ], - "testEnvironment": "jsdom", + testEnvironment: "jsdom", }; module.exports = config; diff --git a/packages/feature-flag/package.json b/packages/feature-flag/package.json index 28ebd4f7541..e1c66d97a3f 100644 --- a/packages/feature-flag/package.json +++ b/packages/feature-flag/package.json @@ -18,7 +18,7 @@ "build:js": "babel src --out-dir build", "clean": "rm -rf build", "test": "jest", - "lint": "eslint ./src ./tests --max-warnings=0" + "lint": "eslint . --max-warnings=0" }, "devDependencies": { "@babel/cli": "^7.17.10", @@ -26,7 +26,10 @@ "@babel/plugin-transform-react-jsx": "^7.17.3", "@babel/preset-env": "^7.16.11", "@yoast/browserslist-config": "^1.2.3", - "babel-plugin-styled-components": "^2.0.6" + "babel-plugin-styled-components": "^2.0.6", + "eslint": "^9.16.0", + "eslint-config-yoast": "^6.0.0", + "globals": "^15.13.0" }, "publishConfig": { "access": "public" From e8264b28dd8dc444bfd5a98c8d434f209441e056 Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:37:22 +0100 Subject: [PATCH 47/92] Update browserlist-config to a flag elsint config --- .../browserslist-config/eslint.config.mjs | 36 +++++++++++++++++++ packages/browserslist-config/package.json | 3 ++ 2 files changed, 39 insertions(+) create mode 100644 packages/browserslist-config/eslint.config.mjs diff --git a/packages/browserslist-config/eslint.config.mjs b/packages/browserslist-config/eslint.config.mjs new file mode 100644 index 00000000000..1a81839d556 --- /dev/null +++ b/packages/browserslist-config/eslint.config.mjs @@ -0,0 +1,36 @@ +import globals from "globals"; +import yoastConfig from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...yoastConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.node, + }, + }, + rules: { + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + }, + }, + { + files: [ "*.config.*" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index a5ac3f5646f..f2cd2f8530d 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -27,6 +27,9 @@ }, "devDependencies": { "browserslist": "^4.7.3", + "eslint": "^9.16.0", + "eslint-config-yoast": "^6.0.0", + "globals": "^15.13.0", "jest": "^29.7.0" } } From d99b94e6b8d1cb802e26306315175652f89169cc Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:44:25 +0100 Subject: [PATCH 48/92] Update analysis-report to use a flat eslint config --- packages/analysis-report/.eslintrc.js | 66 ------------------- packages/analysis-report/eslint.config.mjs | 41 ++++++++++++ packages/analysis-report/package.json | 4 +- .../tests/__mocks__/@wordpress/i18n.js | 2 +- 4 files changed, 43 insertions(+), 70 deletions(-) delete mode 100644 packages/analysis-report/.eslintrc.js create mode 100644 packages/analysis-report/eslint.config.mjs diff --git a/packages/analysis-report/.eslintrc.js b/packages/analysis-report/.eslintrc.js deleted file mode 100644 index bf921b075c6..00000000000 --- a/packages/analysis-report/.eslintrc.js +++ /dev/null @@ -1,66 +0,0 @@ -module.exports = { - root: true, - "extends": [ - "yoast", - ], - settings: { - react: { - version: "detect", - }, - }, - parserOptions: { - ecmaVersion: 2020, - sourceType: "module", - }, - ignorePatterns: [ - "/build/", - ], - rules: { - "no-prototype-builtins": 0, - "comma-dangle": [ - "error", - { - arrays: "always-multiline", - objects: "always-multiline", - imports: "always-multiline", - exports: "always-multiline", - functions: "never", - }, - ], - "import/no-unresolved": [ - "error", - { - ignore: [ "^@yoast/(components|helpers|style-guide)" ], - }, - ], - }, - overrides: [ - { - files: [ "tests/**/*.js" ], - env: { - jest: true, - }, - rules: { - "no-restricted-imports": 0, - }, - }, - { - files: [ "**/*.js" ], - rules: { - complexity: [ 1, 6 ], - // A wrapping label is not necessary when there already is an htmlFor attribute. - "jsx-a11y/label-has-for": [ "error", { required: "id" } ], - "require-jsdoc": 1, - "react/button-has-type": 1, - "react/default-props-match-prop-types": 1, - "react/no-unused-prop-types": 1, - "react/no-access-state-in-setstate": 1, - "react/no-unused-state": 1, - "react/jsx-no-bind": 1, - "react/jsx-no-target-blank": 1, - "react/require-default-props": 1, - "react/forbid-foreign-prop-types": 1, - }, - }, - ], -}; diff --git a/packages/analysis-report/eslint.config.mjs b/packages/analysis-report/eslint.config.mjs new file mode 100644 index 00000000000..6217b3cbba1 --- /dev/null +++ b/packages/analysis-report/eslint.config.mjs @@ -0,0 +1,41 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { ignores: [ "build" ] }, + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + }, + }, + rules: { + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + + // Deviate from the Yoast config to allow existing violations. New occurrences are still disallowed. + "react/jsx-no-bind": "warn", + }, + }, + { + files: [ "*.config.js", "tools/jest/**" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/analysis-report/package.json b/packages/analysis-report/package.json index bbbae94eb83..e64d3ae2e96 100644 --- a/packages/analysis-report/package.json +++ b/packages/analysis-report/package.json @@ -38,9 +38,7 @@ "babel-plugin-styled-components": "^2.0.6", "eslint": "^8.57.0", "eslint-config-yoast": "^6.0.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.34.1", + "globals": "^15.13.0", "jest": "^27.5.1", "jest-styled-components": "^7.0.8", "react-test-renderer": "^18.2.0" diff --git a/packages/analysis-report/tests/__mocks__/@wordpress/i18n.js b/packages/analysis-report/tests/__mocks__/@wordpress/i18n.js index 0794fa12ab4..6935667003a 100644 --- a/packages/analysis-report/tests/__mocks__/@wordpress/i18n.js +++ b/packages/analysis-report/tests/__mocks__/@wordpress/i18n.js @@ -1,4 +1,4 @@ -/* eslint-disable require-jsdoc */ +/* eslint-disable jsdoc/require-jsdoc */ import { sprintf, setLocaleData } from "@wordpress/i18n"; From 625f942de5704a16b3b0a7ee0d06567df7da0d0e Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:17:00 +0100 Subject: [PATCH 49/92] Update js to use a flat eslint config --- packages/js/.eslintrc.js | 114 --------------------------------- packages/js/eslint.config.mjs | 116 ++++++++++++++++++++++++++++++++++ packages/js/package.json | 8 +-- yarn.lock | 14 +--- 4 files changed, 119 insertions(+), 133 deletions(-) delete mode 100644 packages/js/.eslintrc.js create mode 100644 packages/js/eslint.config.mjs diff --git a/packages/js/.eslintrc.js b/packages/js/.eslintrc.js deleted file mode 100644 index ed4fe8ecd26..00000000000 --- a/packages/js/.eslintrc.js +++ /dev/null @@ -1,114 +0,0 @@ -module.exports = { - root: true, - "extends": [ - "yoast", - ], - settings: { - react: { - version: "detect", - }, - }, - parser: "@babel/eslint-parser", - parserOptions: { - ecmaVersion: 2019, - sourceType: "module", - }, - plugins: [ - "@babel", - ], - rules: { - "no-prototype-builtins": 0, - "comma-dangle": [ - "error", - { - arrays: "always-multiline", - objects: "always-multiline", - imports: "always-multiline", - exports: "always-multiline", - functions: "never", - }, - ], - "import/no-unresolved": [ - "error", - { - ignore: [ - // This is our internal externals used within `packages/js`, not actually a package. - "^@yoast/externals/(components|contexts|redux)$", - // Ignore UI library and schema-blocks, or we have to build the code before linting. - // Because `main` in `package.json` points to the `build/index.js` (in the UI library), which is not present before building. - // As we are dealing with our source, not the actual NPM download, due to the monorepo setup. - "^@yoast/(ui-library|schema-blocks|style-guide|components|helpers|search-metadata-previews|social-metadata-forms|replacement-variable-editor|analysis-report|feature-flag|related-keyphrase-suggestions)$", - "^@wordpress/(annotations|api|edit-post|sanitize)$", - "^jquery$", - "yoastseo", - ], - }, - ], - }, - overrides: [ - { - files: [ "**/*.js" ], - rules: { - // Custom rules: only for temporary exceptions that should be removed over time - camelcase: 1, - complexity: [ 1, 6 ], - "brace-style": 1, - "max-statements": 1, - "max-len": [ - "error", - { - code: 150, - ignoreStrings: true, - ignoreTemplateLiterals: true, - ignorePattern: "[\t]*\n", - }, - ], - "no-shadow": 1, - "require-jsdoc": 1, - "react/jsx-no-bind": 1, - "react/jsx-no-target-blank": 1, - "react/no-access-state-in-setstate": 1, - "react/no-deprecated": 1, - "react/no-unused-prop-types": 1, - "react/prop-types": 1, - "react/require-default-props": 1, - "no-restricted-imports": [ - "error", - { - name: "react", - message: "Please use @wordpress/element instead. No need to import just for JSX.", - - }, - { - name: "react-dom", - message: "Please use @wordpress/element instead.", - }, - - ], - - // Disabled rules - // In the editor, we're using the pragma `wp.element.createElement` - "react/react-in-jsx-scope": 0, - }, - - }, - { - files: [ "tests/**/*.js" ], - env: { - jest: true, - }, - rules: { - "no-restricted-imports": 0, - "no-undefined": 0, - "react/display-name": 0, - }, - }, - // Ignore Proptypes in the dashboard. - { - files: [ "src/dashboard/**/*.js" ], - rules: { - "react/prop-types": 0, - }, - }, - ], -}; diff --git a/packages/js/eslint.config.mjs b/packages/js/eslint.config.mjs new file mode 100644 index 00000000000..75b09930076 --- /dev/null +++ b/packages/js/eslint.config.mjs @@ -0,0 +1,116 @@ +import globals from "globals"; +import yoastConfig, { reactConfig } from "eslint-config-yoast"; + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + ...yoastConfig, + ...reactConfig, + { + languageOptions: { + ecmaVersion: "latest", + globals: { + ...globals.browser, + ...globals.jquery, + // Webpack maps `global` to the window. + global: false, + }, + }, + rules: { + // Account for webpack externals and potentially unbuilt packages in the monorepo setup. + "import/no-unresolved": [ + "error", + { + ignore: [ + // This is our internal externals used within `packages/js`, not actually a package. + "^@yoast/externals/(components|contexts|redux)$", + // Ignore UI library and schema-blocks, or we have to build the code before linting. + // Because `main` in `package.json` points to the `build/index.js` (in the UI library), which is not present before building. + // As we are dealing with our source, not the actual NPM download, due to the monorepo setup. + "^@yoast/(ui-library|schema-blocks|style-guide|components|helpers|search-metadata-previews|social-metadata-forms|replacement-variable-editor|analysis-report|feature-flag|related-keyphrase-suggestions)$", + "^@wordpress/(annotations|api|edit-post|sanitize)$", + "^jquery$", + "yoastseo", + ], + }, + ], + "no-restricted-imports": [ + "error", + { + name: "react", + message: "Please use @wordpress/element instead. No need to import just for JSX.", + + }, + { + name: "react-dom", + message: "Please use @wordpress/element instead.", + }, + ], + // Disabled rules + // In the editor, we're using the pragma `wp.element.createElement` + "react/react-in-jsx-scope": "off", + + // Deviate from the Yoast config to prohibit dangling commas in functions. + "stylistic/comma-dangle": [ + "error", + { + functions: "never", + arrays: "always-multiline", + objects: "always-multiline", + imports: "always-multiline", + exports: "always-multiline", + }, + ], + // Deviate from the Yoast config to allow longer template literals. + "stylistic/max-len": [ + "error", + { + code: 150, + ignoreStrings: true, + ignoreTemplateLiterals: true, + ignorePattern: "[\t]*\n", + }, + ], + + // Deviate from the Yoast config to allow existing violations. New occurrences are still disallowed. + complexity: [ "warn", 6 ], + "no-shadow": "warn", + "jsdoc/require-jsdoc": "warn", + "react/jsx-no-bind": "warn", + "react/no-access-state-in-setstate": "warn", + "react/no-unused-prop-types": "warn", + "react/prop-types": "warn", + "react/require-default-props": "warn", + + "no-prototype-builtins": "off", + }, + }, + { + files: [ "src/externals/**" ], + languageOptions: { + globals: { + ...globals.commonjs, + }, + }, + }, + { + files: [ "tests/**" ], + rules: { + "no-undefined": "off", + }, + }, + // Ignore Proptypes in the dashboard. + { + files: [ "src/dashboard/**" ], + rules: { + "react/prop-types": "off", + }, + }, + { + files: [ "*.config.*" ], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, +]; diff --git a/packages/js/package.json b/packages/js/package.json index 267309cb351..d68ed5b6d2b 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "cd ../.. && wp-scripts build --config config/webpack/webpack.config.js", "test": "jest", - "lint": "eslint src tests --max-warnings=59" + "lint": "eslint . --max-warnings=41" }, "dependencies": { "@draft-js-plugins/mention": "^5.0.0", @@ -73,8 +73,6 @@ }, "devDependencies": { "@babel/core": "^7.17.9", - "@babel/eslint-parser": "^7.17.0", - "@babel/eslint-plugin": "^7.17.7", "@jest/globals": "^27.5.1", "@testing-library/jest-dom": "^6.1.3", "@testing-library/react": "^14.0.0", @@ -87,9 +85,7 @@ "case-sensitive-paths-webpack-plugin": "^2.1.2", "eslint": "^8.57.0", "eslint-config-yoast": "^6.0.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-react": "^7.34.1", + "globals": "^15.13.0", "jest": "^27.5.1", "jest-styled-components": "^7.0.3", "raf": "^3.4.1", diff --git a/yarn.lock b/yarn.lock index 646ba483e71..a615af80508 100644 --- a/yarn.lock +++ b/yarn.lock @@ -162,7 +162,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/eslint-parser@^7.16.0", "@babel/eslint-parser@^7.17.0": +"@babel/eslint-parser@^7.16.0": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.23.3.tgz#7bf0db1c53b54da0c8a12627373554a0828479ca" integrity sha512-9bTuNlyx7oSstodm1cR1bECj4fkiknsDa1YniISkJemMY3DGhJNYBECbe6QD/q54mp2J8VO66jW3/7uP//iFCw== @@ -171,13 +171,6 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.1" -"@babel/eslint-plugin@^7.17.7": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/eslint-plugin/-/eslint-plugin-7.23.5.tgz#77d4703e9f83b81e9fc13382810372beb2f10f94" - integrity sha512-03+E/58Hoo/ui69gR+beFdGpplpoVK0BSIdke2iw4/Bz7eGN0ssRenNlnU4nmbkowNQOPCStKSwFr8H6DiY49g== - dependencies: - eslint-rule-composer "^0.3.0" - "@babel/generator@^7.23.0", "@babel/generator@^7.23.6", "@babel/generator@^7.7.2": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" @@ -15970,11 +15963,6 @@ eslint-plugin-yoast@^1.0.1: dependencies: requireindex "~1.1.0" -eslint-rule-composer@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" - integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== - eslint-scope@3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" From 507cb467575c17cd6ae400171fd9d01f7590366c Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:17:43 +0100 Subject: [PATCH 50/92] Fix new linting errors about React imports --- packages/js/tests/InstallationSuccessPage.test.js | 1 - .../components/AIAssessmentFixesButton.test.js | 1 - packages/js/tests/components/SidebarCollapsibleTest.js | 1 - .../js/tests/insights/components/text-formality-upsell.test.js | 1 - packages/js/tests/setupTests.js | 1 + 5 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/js/tests/InstallationSuccessPage.test.js b/packages/js/tests/InstallationSuccessPage.test.js index 959ae692c8d..669f53ad32d 100644 --- a/packages/js/tests/InstallationSuccessPage.test.js +++ b/packages/js/tests/InstallationSuccessPage.test.js @@ -1,4 +1,3 @@ -import React from "react"; import { InstallationSuccessPage } from "../src/installation-success"; import { render } from "./test-utils"; diff --git a/packages/js/tests/ai-assessment-fixes/components/AIAssessmentFixesButton.test.js b/packages/js/tests/ai-assessment-fixes/components/AIAssessmentFixesButton.test.js index a2bc7b3279f..010cc30b524 100644 --- a/packages/js/tests/ai-assessment-fixes/components/AIAssessmentFixesButton.test.js +++ b/packages/js/tests/ai-assessment-fixes/components/AIAssessmentFixesButton.test.js @@ -1,4 +1,3 @@ -import React from "react"; import { fireEvent, render, screen } from "../../test-utils"; import { useSelect, useDispatch } from "@wordpress/data"; diff --git a/packages/js/tests/components/SidebarCollapsibleTest.js b/packages/js/tests/components/SidebarCollapsibleTest.js index 473117a7717..3aa70d99366 100644 --- a/packages/js/tests/components/SidebarCollapsibleTest.js +++ b/packages/js/tests/components/SidebarCollapsibleTest.js @@ -1,4 +1,3 @@ -import React from "react"; import SidebarCollapsible from "../../src/components/SidebarCollapsible"; import { fireEvent, render, screen } from "../test-utils"; diff --git a/packages/js/tests/insights/components/text-formality-upsell.test.js b/packages/js/tests/insights/components/text-formality-upsell.test.js index 4b789b70065..4aee85a66ba 100644 --- a/packages/js/tests/insights/components/text-formality-upsell.test.js +++ b/packages/js/tests/insights/components/text-formality-upsell.test.js @@ -1,5 +1,4 @@ import TextFormalityUpsell from "../../../src/insights/components/text-formality-upsell"; -import React from "react"; import renderer from "react-test-renderer"; window.wpseoAdminL10n = { diff --git a/packages/js/tests/setupTests.js b/packages/js/tests/setupTests.js index c3eb5a5a55d..6407b6ba80e 100644 --- a/packages/js/tests/setupTests.js +++ b/packages/js/tests/setupTests.js @@ -3,6 +3,7 @@ import { createElement } from "@wordpress/element"; import { setLocaleData } from "@wordpress/i18n"; import "jest-styled-components"; import "raf/polyfill"; +// eslint-disable-next-line no-restricted-imports -- We need to import React to set up the global React object. import React from "react"; setLocaleData( { From 013bf3026fd509ff12140f491e4669ec5ebc84ac Mon Sep 17 00:00:00 2001 From: Diede Exterkate <5352634+diedexx@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:26:58 +0100 Subject: [PATCH 51/92] Autofix ESLint indentation issues --- packages/js/src/analysis-worker.js | 2 +- packages/js/src/components/SidebarButton.js | 4 ++-- packages/js/src/components/WincherTableRow.js | 2 +- packages/js/src/containers/SEMrushRelatedKeyphrases.js | 2 +- .../src/dashboard/scores/components/content-type-filter.js | 2 +- .../tailwind-components/base/combo-box.js | 2 +- .../first-time-configuration/tailwind-components/stepper.js | 4 ++-- .../tailwind-components/steps/finish/finish-step.js | 2 +- .../tailwind-components/steps/indexation/indexation.js | 2 +- packages/js/src/general/app.js | 2 +- packages/js/src/general/components/problems.js | 6 +++--- packages/js/src/initializers/admin.js | 4 ++-- packages/js/src/insights/components/prominent-words.js | 2 +- packages/js/src/redux/reducers/WincherRequest.js | 2 +- packages/js/src/redux/reducers/advancedSettings.js | 2 +- packages/js/src/services/IndexingService.js | 4 ++-- .../js/src/settings/components/formik-autocomplete-field.js | 2 +- packages/js/src/workouts/components/WorkoutCard.js | 2 +- packages/js/src/workouts/components/WorkoutsPage.js | 4 ++-- packages/js/tests/InstallationSuccessPage.test.js | 2 +- packages/js/tests/redux/selectors/analysisSelectors.test.js | 2 +- packages/js/tests/redux/selectors/fallbackSelectors.test.js | 6 +++--- 22 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/js/src/analysis-worker.js b/packages/js/src/analysis-worker.js index e7f01942714..ec919058a96 100644 --- a/packages/js/src/analysis-worker.js +++ b/packages/js/src/analysis-worker.js @@ -42,7 +42,7 @@ function loadDependencies( dependencies ) { if ( dependency === "lodash" ) { // eslint-disable-next-line no-undef - self.lodash = _.noConflict(); + self.lodash = _.noConflict(); } } } diff --git a/packages/js/src/components/SidebarButton.js b/packages/js/src/components/SidebarButton.js index ec5bc0415d0..20589bf1bc1 100644 --- a/packages/js/src/components/SidebarButton.js +++ b/packages/js/src/components/SidebarButton.js @@ -22,10 +22,10 @@ const SidebarButton = ( props ) => { style={ { fill: `${ props.prefixIcon && props.prefixIcon.color || "" }` } } > { - + /> } ) } diff --git a/packages/js/src/components/WincherTableRow.js b/packages/js/src/components/WincherTableRow.js index a8b6001468f..45723316ef0 100644 --- a/packages/js/src/components/WincherTableRow.js +++ b/packages/js/src/components/WincherTableRow.js @@ -283,7 +283,7 @@ export function getPositionalDataByState( props ) { { formatLastUpdated( rowData.updated_at ) } - + ); } diff --git a/packages/js/src/containers/SEMrushRelatedKeyphrases.js b/packages/js/src/containers/SEMrushRelatedKeyphrases.js index a379dcd6ddc..652922952ea 100644 --- a/packages/js/src/containers/SEMrushRelatedKeyphrases.js +++ b/packages/js/src/containers/SEMrushRelatedKeyphrases.js @@ -42,7 +42,7 @@ export default compose( [ setSEMrushRequestFailed, setSEMrushSetRequestLimitReached, setSEMrushNoResultsFound, - } = dispatch( "yoast-seo/editor" ); + } = dispatch( "yoast-seo/editor" ); return { setCountry: ( countryCode ) => { setSEMrushChangeCountry( countryCode ); diff --git a/packages/js/src/dashboard/scores/components/content-type-filter.js b/packages/js/src/dashboard/scores/components/content-type-filter.js index 5e03d00a39c..f21a5e8f82f 100644 --- a/packages/js/src/dashboard/scores/components/content-type-filter.js +++ b/packages/js/src/dashboard/scores/components/content-type-filter.js @@ -53,7 +53,7 @@ export const ContentTypeFilter = ( { idSuffix, contentTypes, selected, onChange onQueryChange={ handleQueryChange } > { filtered.map( ( { name, label } ) => { - const decodedLabel = decodeString( label ); + const decodedLabel = decodeString( label ); return { decodedLabel } ; diff --git a/packages/js/src/first-time-configuration/tailwind-components/base/combo-box.js b/packages/js/src/first-time-configuration/tailwind-components/base/combo-box.js index 9f27e34ef01..c60208831ae 100644 --- a/packages/js/src/first-time-configuration/tailwind-components/base/combo-box.js +++ b/packages/js/src/first-time-configuration/tailwind-components/base/combo-box.js @@ -125,7 +125,7 @@ export default function YoastComboBox( { id, value, label, onChange, onQueryChan ; } } - ) ) } + ) ) } ) }
diff --git a/packages/js/src/first-time-configuration/tailwind-components/stepper.js b/packages/js/src/first-time-configuration/tailwind-components/stepper.js index ba836c91a11..0145cb0f0cb 100644 --- a/packages/js/src/first-time-configuration/tailwind-components/stepper.js +++ b/packages/js/src/first-time-configuration/tailwind-components/stepper.js @@ -27,9 +27,9 @@ const StepperContext = createContext(); export function useStepperContext() { const context = useContext( StepperContext ); if ( ! context ) { - throw new Error( + throw new Error( "Stepper compound components cannot be rendered outside the Stepper component" - ); + ); } return context; } diff --git a/packages/js/src/first-time-configuration/tailwind-components/steps/finish/finish-step.js b/packages/js/src/first-time-configuration/tailwind-components/steps/finish/finish-step.js index 04e4a0b4d64..c3fa208813c 100644 --- a/packages/js/src/first-time-configuration/tailwind-components/steps/finish/finish-step.js +++ b/packages/js/src/first-time-configuration/tailwind-components/steps/finish/finish-step.js @@ -34,7 +34,7 @@ export default function FinishStep() { __( "Great work! Thanks to the details you've provided, %1$s has enhanced your site for search engines, giving them a clearer picture of what your site is all about.", "wordpress-seo" ), "Yoast" ) - } + }

{ __( "If your goal is to increase your rankings, you need to work on your SEO regularly. That can be overwhelming, so let's tackle it one step at a time!", "wordpress-seo" ) } diff --git a/packages/js/src/first-time-configuration/tailwind-components/steps/indexation/indexation.js b/packages/js/src/first-time-configuration/tailwind-components/steps/indexation/indexation.js index ad76028a1eb..677880bea6f 100644 --- a/packages/js/src/first-time-configuration/tailwind-components/steps/indexation/indexation.js +++ b/packages/js/src/first-time-configuration/tailwind-components/steps/indexation/indexation.js @@ -392,7 +392,7 @@ class Indexation extends Component { * * @returns {WPElement} The rendered component. */ - render() { + render() { if ( this.settings.disabled ) { return this.renderDisabledTool(); } diff --git a/packages/js/src/general/app.js b/packages/js/src/general/app.js index 832ca60b497..c51d18d2a64 100644 --- a/packages/js/src/general/app.js +++ b/packages/js/src/general/app.js @@ -140,7 +140,7 @@ const App = () => { > { notice.content } - ) + ) }

}
} diff --git a/packages/js/src/general/components/problems.js b/packages/js/src/general/components/problems.js index 74ed0a3739d..4a1badb2d73 100644 --- a/packages/js/src/general/components/problems.js +++ b/packages/js/src/general/components/problems.js @@ -38,9 +38,9 @@ export const Problems = () => {

{ problemsList.length > 0 - ? __( "We have detected the following issues that affect the SEO of your site.", "wordpress-seo" ) - : __( "Good job! We could detect no serious SEO problems.", "wordpress-seo" ) - } + ? __( "We have detected the following issues that affect the SEO of your site.", "wordpress-seo" ) + : __( "Good job! We could detect no serious SEO problems.", "wordpress-seo" ) + }

diff --git a/packages/js/src/initializers/admin.js b/packages/js/src/initializers/admin.js index 81776fc11ca..9a55453c54e 100644 --- a/packages/js/src/initializers/admin.js +++ b/packages/js/src/initializers/admin.js @@ -77,7 +77,7 @@ export default function initAdmin( jQuery ) { * * @returns {void} */ - function setInitialActiveTab() { + function setInitialActiveTab() { var activeTabId = window.location.hash.replace( "#top#", "" ); /* In some cases, the second # gets replace by %23, which makes the tab * switching not work unless we do this. */ @@ -108,7 +108,7 @@ export default function initAdmin( jQuery ) { jQuery( window ).on( "hashchange", function() { setInitialActiveTab(); wpseoSetTabHash(); - } ); + } ); /** * Hides or shows the Author without posts toggle. diff --git a/packages/js/src/insights/components/prominent-words.js b/packages/js/src/insights/components/prominent-words.js index 2a8780f412f..60c15f339e0 100644 --- a/packages/js/src/insights/components/prominent-words.js +++ b/packages/js/src/insights/components/prominent-words.js @@ -95,7 +95,7 @@ const ProminentWords = ( { location } ) => { // eslint-disable-line complexity ) }