-
-
Notifications
You must be signed in to change notification settings - Fork 530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce suspenders:lint
generator
#1148
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
module Suspenders | ||
module Generators | ||
class LintGenerator < Rails::Generators::Base | ||
include Suspenders::Generators::Helpers | ||
|
||
source_root File.expand_path("../../templates/lint", __FILE__) | ||
desc "Creates a holistic linting solution that covers JavaScript, CSS, Ruby and ERB." | ||
|
||
def install_dependencies | ||
run "yarn add stylelint@^15.10.1 eslint @thoughtbot/stylelint-config@3.0.0 @thoughtbot/eslint-config npm-run-all prettier --dev" | ||
end | ||
|
||
def install_gems | ||
gem_group :development, :test do | ||
gem "better_html", require: false | ||
gem "erb_lint", require: false | ||
gem "erblint-github", require: false | ||
gem "standard" | ||
end | ||
Bundler.with_unbundled_env { run "bundle install" } | ||
end | ||
|
||
def configure_stylelint | ||
copy_file "stylelintrc.json", ".stylelintrc.json" | ||
end | ||
|
||
def configure_eslint | ||
copy_file "eslintrc.json", ".eslintrc.json" | ||
end | ||
Comment on lines
+27
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would an API only ever have JavaScript? |
||
|
||
def configure_prettier | ||
copy_file "prettierrc", ".prettierrc" | ||
end | ||
|
||
def configure_erb_lint | ||
copy_file "erb-lint.yml", ".erb-lint.yml" | ||
copy_file "config_better_html.yml", "config/better_html.yml" | ||
copy_file "config_initializers_better_html.rb", "config/initializers/better_html.rb" | ||
copy_file "erblint.rake", "lib/tasks/erblint.rake" | ||
template "rubocop.yml.tt", ".rubocop.yml" | ||
|
||
if default_test_suite? | ||
copy_file "better_html_test.rb", "test/views/better_html_test.rb" | ||
elsif rspec_test_suite? | ||
copy_file "better_html_spec.rb", "spec/views/better_html_spec.rb" | ||
end | ||
end | ||
|
||
def update_package_json | ||
content = File.read package_json | ||
json = JSON.parse content | ||
json["scripts"] ||= {} | ||
|
||
json["scripts"]["lint"] = "run-p lint:eslint lint:stylelint lint:prettier" | ||
json["scripts"]["lint:eslint"] = "eslint --max-warnings=0 --no-error-on-unmatched-pattern 'app/javascript/**/*.js'" | ||
json["scripts"]["lint:stylelint"] = "stylelint 'app/assets/stylesheets/**/*.css'" | ||
json["scripts"]["lint:prettier"] = "prettier --check '**/*' --ignore-unknown" | ||
json["scripts"]["fix:prettier"] = "prettier --write '**/*' --ignore-unknown" | ||
|
||
File.write package_json, JSON.pretty_generate(json) | ||
end | ||
|
||
# This needs to be the last method definition to ensure everything is | ||
# properly configured | ||
def fix_violations | ||
run "yarn run fix:prettier" | ||
run "bundle exec rake standard:fix_unsafely" | ||
end | ||
|
||
private | ||
|
||
def package_json | ||
Rails.root.join("package.json") | ||
end | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
require "spec_helper" | ||
|
||
describe "ERB Implementation" do | ||
def self.erb_lint | ||
configuration = ActiveSupport::ConfigurationFile.parse(".erb-lint.yml") | ||
|
||
ActiveSupport::OrderedOptions.new.merge!(configuration.deep_symbolize_keys!) | ||
end | ||
|
||
Rails.root.glob(erb_lint.glob).each do |template| | ||
it "raises no html errors in #{template.relative_path_from(Rails.root)}" do | ||
validator = BetterHtml::BetterErb::ErubiImplementation.new(template.read) | ||
|
||
validator.validate! | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
require "test_helper" | ||
|
||
class ErbImplementationTest < ActiveSupport::TestCase | ||
def self.erb_lint | ||
configuration = ActiveSupport::ConfigurationFile.parse(".erb-lint.yml") | ||
|
||
ActiveSupport::OrderedOptions.new.merge!(configuration.deep_symbolize_keys!) | ||
end | ||
|
||
Rails.root.glob(erb_lint.glob).each do |template| | ||
test "html errors in #{template.relative_path_from(Rails.root)}" do | ||
validator = BetterHtml::BetterErb::ErubiImplementation.new(template.read) | ||
|
||
validator.validate! | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
--- | ||
allow_single_quoted_attributes: false |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
Rails.configuration.to_prepare do | ||
if Rails.env.test? | ||
require "better_html" | ||
|
||
BetterHtml.config = BetterHtml::Config.new(Rails.configuration.x.better_html) | ||
|
||
BetterHtml.config.template_exclusion_filter = proc { |filename| !filename.start_with?(Rails.root.to_s) } | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--- | ||
glob: "app/views/**/*.{html,turbo_stream}{+*,}.erb" | ||
|
||
linters: | ||
AllowedScriptType: | ||
enabled: true | ||
allowed_types: | ||
- "module" | ||
- "text/javascript" | ||
ErbSafety: | ||
enabled: true | ||
better_html_config: "config/better_html.yml" | ||
GitHub::Accessibility::AvoidBothDisabledAndAriaDisabledCounter: | ||
enabled: true | ||
GitHub::Accessibility::AvoidGenericLinkTextCounter: | ||
enabled: true | ||
GitHub::Accessibility::DisabledAttributeCounter: | ||
enabled: true | ||
GitHub::Accessibility::IframeHasTitleCounter: | ||
enabled: true | ||
GitHub::Accessibility::ImageHasAltCounter: | ||
enabled: true | ||
GitHub::Accessibility::LandmarkHasLabelCounter: | ||
enabled: true | ||
GitHub::Accessibility::LinkHasHrefCounter: | ||
enabled: true | ||
GitHub::Accessibility::NestedInteractiveElementsCounter: | ||
enabled: true | ||
GitHub::Accessibility::NoAriaLabelMisuseCounter: | ||
enabled: true | ||
GitHub::Accessibility::NoPositiveTabIndexCounter: | ||
enabled: true | ||
GitHub::Accessibility::NoRedundantImageAltCounter: | ||
enabled: true | ||
GitHub::Accessibility::NoTitleAttributeCounter: | ||
enabled: true | ||
GitHub::Accessibility::SvgHasAccessibleTextCounter: | ||
enabled: true | ||
Rubocop: | ||
enabled: true | ||
rubocop_config: | ||
inherit_from: | ||
- .rubocop.yml | ||
|
||
Lint/EmptyBlock: | ||
Enabled: false | ||
Layout/InitialIndentation: | ||
Enabled: false | ||
Layout/TrailingEmptyLines: | ||
Enabled: false | ||
Layout/TrailingWhitespace: | ||
Enabled: false | ||
Layout/LeadingEmptyLines: | ||
Enabled: false | ||
Style/FrozenStringLiteralComment: | ||
Enabled: false | ||
Style/MultilineTernaryOperator: | ||
Enabled: false | ||
Comment on lines
+57
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we allow this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might be misunderstanding, but we are not allowing this since |
||
Lint/UselessAssignment: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we allow this? |
||
Exclude: | ||
- "app/views/**/*" | ||
|
||
EnableDefaultLinters: true |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
module ERBLint | ||
module RakeSupport | ||
# Allow command line flags set in STANDARDOPTS (like MiniTest's TESTOPTS) | ||
def self.argvify | ||
if ENV["ERBLINTOPTS"] | ||
ENV["ERBLINTOPTS"].split(/\s+/) | ||
else | ||
[] | ||
end | ||
end | ||
|
||
# DELETE THIS FILE AFTER MERGE: | ||
# | ||
# * https://github.com/Shopify/better-html/pull/95 | ||
# | ||
def self.backport! | ||
BetterHtml::TestHelper::SafeErb::AllowedScriptType::VALID_JAVASCRIPT_TAG_TYPES.push("module") | ||
end | ||
end | ||
end | ||
|
||
desc "Lint templates with erb_lint" | ||
task "erblint" do | ||
require "erb_lint/cli" | ||
require "erblint-github/linters" | ||
|
||
ERBLint::RakeSupport.backport! | ||
|
||
cli = ERBLint::CLI.new | ||
success = cli.run(ERBLint::RakeSupport.argvify + ["--lint-all", "--format=compact"]) | ||
fail unless success | ||
end | ||
|
||
desc "Lint and automatically fix templates with erb_lint" | ||
task "erblint:autocorrect" do | ||
require "erb_lint/cli" | ||
require "erblint-github/linters" | ||
|
||
ERBLint::RakeSupport.backport! | ||
|
||
cli = ERBLint::CLI.new | ||
success = cli.run(ERBLint::RakeSupport.argvify + ["--lint-all", "--autocorrect"]) | ||
fail unless success | ||
end | ||
|
||
task "standard" => "erblint" | ||
task "standard:fix" => "erblint:autocorrect" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": ["@thoughtbot/eslint-config/prettier"], | ||
"parserOptions": { | ||
"ecmaVersion": "latest", | ||
"sourceType": "module" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"singleQuote": true, | ||
"overrides": [ | ||
{ | ||
"files": ["**/*.css", "**/*.scss", "**/*.html"], | ||
"options": { | ||
"singleQuote": false | ||
} | ||
} | ||
] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
AllCops: | ||
TargetRubyVersion: <%= RUBY_VERSION %> | ||
|
||
require: standard | ||
|
||
inherit_gem: | ||
standard: config/base.yml |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": "@thoughtbot/stylelint-config" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we need this for API only applications? Mailers requires styles, but those are usually inline.