diff --git a/.github/workflows/stylelint.yml b/.github/workflows/stylelint.yml index 3547c7d357..d93d0fc6c0 100644 --- a/.github/workflows/stylelint.yml +++ b/.github/workflows/stylelint.yml @@ -43,5 +43,14 @@ jobs: if: steps.cache-npm.outputs.cache-hit != 'true' run: npm ci --include=dev --legacy-peer-deps + - name: Set up WP environment + run: npm run env start + + # css/formidableforms.css is a runtime-rendered stylesheet (see + # FrmStyle::save_settings()), not a build artifact, so there's nothing + # on disk for stylelint to check without this. + - name: Generate default stylesheet for lint coverage + run: npx wp-env run cli wp eval 'require FrmAppHelper::plugin_path() . "/bin/generate-default-stylesheet.php";' + - name: Run Stylelint run: npx stylelint "**/*.{css,scss}" diff --git a/.stylelintrc.json b/.stylelintrc.json index 443983e4c1..0f87a25fbf 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -9,8 +9,7 @@ "**/frm-legacy-paypal.css", "**/font_icons.css", "**/frm_testing_mode.css", - "**/welcome-tour.css", - "**/css/formidableforms.css" + "**/welcome-tour.css" ], "rules": { "no-descending-specificity": null, @@ -32,5 +31,19 @@ "font-family-no-missing-generic-family-keyword": null, "scss/at-import-no-partial-leading-underscore": null, "scss/load-no-partial-leading-underscore": null - } + }, + "overrides": [ + { + "files": ["**/css/formidableforms.css"], + "rules": { + "rule-empty-line-before": null, + "at-rule-empty-line-before": null, + "selector-attribute-quotes": null, + "selector-pseudo-element-colon-notation": null, + "color-hex-length": null, + "font-weight-notation": null, + "length-zero-no-unit": null + } + } + ] } diff --git a/bin/generate-default-stylesheet.php b/bin/generate-default-stylesheet.php new file mode 100644 index 0000000000..d751c27d96 --- /dev/null +++ b/bin/generate-default-stylesheet.php @@ -0,0 +1,46 @@ +save_settings(); + +// save_settings() writes wherever add_css_to_uploads_dir() resolves to, +// which can be outside this checkout (wp_upload_dir()) depending on file +// mod permissions - confirm the file actually landed where stylelint +// will look, rather than letting a silent miss pass as a green run. +$target = FrmStyle::get_generated_css_file_path( FrmStyle::add_css_to_uploads_dir() ) . '/' . FrmStylesController::get_file_name(); + +if ( ! is_file( $target ) || ! filesize( $target ) ) { + WP_CLI::error( "No stylesheet generated at $target" ); +} + +// Several of the style templates gate a selector's only declarations behind +// a single `! empty( $defaults[...] )` check with no fallback (e.g. a +// font-family rule that only prints when a custom font is set) - under the +// stock defaults that selector renders with nothing between its braces. +// That's inert in real output either way, but stylelint's block-no-empty +// has no way to tell "false setting produced this on purpose" from "typo'd +// selector" without evaluating the template's PHP, so strip empty rules +// (including any block left empty once its only content is removed, e.g. a +// media query whose sole rule was itself emptied) before lint sees the file. +$css = file_get_contents( $target ); +do { + $before = $css; + $css = preg_replace( '/[^{}]*\{\}/', '', $css ); +} while ( $css !== $before ); +file_put_contents( $target, $css ); + +WP_CLI::success( "Generated $target" );