summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bennett <lbennett@gitlab.com>2019-04-23 20:04:11 +0100
committerLuke Bennett <lbennett@gitlab.com>2019-05-20 20:25:32 +0100
commit95afdfaeeb301699df3bbac0fde9cad0dda4d5f1 (patch)
tree5ffe60d88969bec005c09965faeabadfa440de4d
parent712282cdcc4a97df23829284bfa031613bb05571 (diff)
downloadgitlab-ce-haml-lint-no-plain-nodes.tar.gz
Add HamlLint::Linter::NoPlainNodes linterhaml-lint-no-plain-nodes
Add a simple haml_lint linter to report all plain nodes. "Plain nodes" in HAML are scritpless plaintext leaf nodes. Add haml-lint_todo to onboard new haml linters. Excludes existing NoPlainNodes lints.
-rw-r--r--.haml-lint.yml4
-rw-r--r--.haml-lint_todo.yml523
-rw-r--r--lib/haml_lint/linter/no_plain_nodes.rb84
-rw-r--r--spec/lib/haml_lint/linter/no_plain_nodes_spec.rb55
4 files changed, 666 insertions, 0 deletions
diff --git a/.haml-lint.yml b/.haml-lint.yml
index e9cc4a91a21..30f94aa8507 100644
--- a/.haml-lint.yml
+++ b/.haml-lint.yml
@@ -1,9 +1,13 @@
+inherits_from:
+ - .haml-lint_todo.yml
# Whether to ignore frontmatter at the beginning of HAML documents for
# frameworks such as Jekyll/Middleman
skip_frontmatter: false
exclude:
- 'vendor/**/*'
- 'spec/**/*'
+require:
+ - './lib/haml_lint/linter/no_plain_nodes.rb'
linters:
AltText:
diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml
new file mode 100644
index 00000000000..61805c2d8d2
--- /dev/null
+++ b/.haml-lint_todo.yml
@@ -0,0 +1,523 @@
+# This configuration was generated by
+# `haml-lint --auto-gen-config`
+# on 2019-05-07 19:04:08 +0100 using Haml-Lint version 0.30.0.
+# The point is for the user to remove these configuration records
+# one by one as the lints are removed from the code base.
+# Note that changes in the inspected code, or installation of new
+# versions of Haml-Lint, may require this file to be generated again.
+
+linters:
+
+ # Offense count: 2075
+ NoPlainNodes:
+ enabled: true
+ exclude:
+ - "app/views/admin/abuse_reports/_abuse_report.html.haml"
+ - "app/views/admin/abuse_reports/index.html.haml"
+ - "app/views/admin/appearances/_form.html.haml"
+ - "app/views/admin/application_settings/_abuse.html.haml"
+ - "app/views/admin/application_settings/_diff_limits.html.haml"
+ - "app/views/admin/application_settings/_gitaly.html.haml"
+ - "app/views/admin/application_settings/_influx.html.haml"
+ - "app/views/admin/application_settings/_ip_limits.html.haml"
+ - "app/views/admin/application_settings/_logging.html.haml"
+ - "app/views/admin/application_settings/_performance.html.haml"
+ - "app/views/admin/application_settings/_plantuml.html.haml"
+ - "app/views/admin/application_settings/_prometheus.html.haml"
+ - "app/views/admin/application_settings/_realtime.html.haml"
+ - "app/views/admin/application_settings/_repository_check.html.haml"
+ - "app/views/admin/application_settings/_repository_storage.html.haml"
+ - "app/views/admin/application_settings/_signin.html.haml"
+ - "app/views/admin/application_settings/_signup.html.haml"
+ - "app/views/admin/application_settings/_spam.html.haml"
+ - "app/views/admin/application_settings/_terminal.html.haml"
+ - "app/views/admin/application_settings/_usage.html.haml"
+ - "app/views/admin/application_settings/_visibility_and_access.html.haml"
+ - "app/views/admin/applications/_delete_form.html.haml"
+ - "app/views/admin/applications/_form.html.haml"
+ - "app/views/admin/applications/edit.html.haml"
+ - "app/views/admin/applications/index.html.haml"
+ - "app/views/admin/applications/new.html.haml"
+ - "app/views/admin/applications/show.html.haml"
+ - "app/views/admin/background_jobs/show.html.haml"
+ - "app/views/admin/broadcast_messages/index.html.haml"
+ - "app/views/admin/dashboard/index.html.haml"
+ - "app/views/admin/deploy_keys/new.html.haml"
+ - "app/views/admin/groups/show.html.haml"
+ - "app/views/admin/health_check/show.html.haml"
+ - "app/views/admin/hook_logs/_index.html.haml"
+ - "app/views/admin/hook_logs/show.html.haml"
+ - "app/views/admin/hooks/_form.html.haml"
+ - "app/views/admin/hooks/edit.html.haml"
+ - "app/views/admin/hooks/index.html.haml"
+ - "app/views/admin/labels/_form.html.haml"
+ - "app/views/admin/logs/show.html.haml"
+ - "app/views/admin/projects/_projects.html.haml"
+ - "app/views/admin/projects/show.html.haml"
+ - "app/views/admin/requests_profiles/index.html.haml"
+ - "app/views/admin/runners/_runner.html.haml"
+ - "app/views/admin/runners/index.html.haml"
+ - "app/views/admin/runners/show.html.haml"
+ - "app/views/admin/services/_form.html.haml"
+ - "app/views/admin/services/index.html.haml"
+ - "app/views/admin/spam_logs/_spam_log.html.haml"
+ - "app/views/admin/spam_logs/index.html.haml"
+ - "app/views/admin/system_info/show.html.haml"
+ - "app/views/admin/users/_access_levels.html.haml"
+ - "app/views/admin/users/_form.html.haml"
+ - "app/views/admin/users/_head.html.haml"
+ - "app/views/admin/users/_profile.html.haml"
+ - "app/views/admin/users/_projects.html.haml"
+ - "app/views/admin/users/new.html.haml"
+ - "app/views/admin/users/projects.html.haml"
+ - "app/views/admin/users/show.html.haml"
+ - "app/views/clusters/clusters/_cluster.html.haml"
+ - "app/views/clusters/clusters/_form.html.haml"
+ - "app/views/clusters/clusters/_gcp_signup_offer_banner.html.haml"
+ - "app/views/clusters/clusters/gcp/_form.html.haml"
+ - "app/views/clusters/clusters/new.html.haml"
+ - "app/views/dashboard/milestones/index.html.haml"
+ - "app/views/dashboard/projects/_blank_state_admin_welcome.html.haml"
+ - "app/views/dashboard/projects/_blank_state_welcome.html.haml"
+ - "app/views/dashboard/projects/_zero_authorized_projects.html.haml"
+ - "app/views/dashboard/snippets/index.html.haml"
+ - "app/views/dashboard/todos/_todo.html.haml"
+ - "app/views/dashboard/todos/index.html.haml"
+ - "app/views/devise/confirmations/almost_there.haml"
+ - "app/views/devise/mailer/_confirmation_instructions_account.html.haml"
+ - "app/views/devise/mailer/_confirmation_instructions_secondary.html.haml"
+ - "app/views/devise/mailer/email_changed.html.haml"
+ - "app/views/devise/mailer/password_change.html.haml"
+ - "app/views/devise/mailer/reset_password_instructions.html.haml"
+ - "app/views/devise/mailer/unlock_instructions.html.haml"
+ - "app/views/devise/passwords/edit.html.haml"
+ - "app/views/devise/sessions/_new_base.html.haml"
+ - "app/views/devise/sessions/_new_crowd.html.haml"
+ - "app/views/devise/sessions/_new_ldap.html.haml"
+ - "app/views/devise/sessions/new.html.haml"
+ - "app/views/devise/sessions/two_factor.html.haml"
+ - "app/views/devise/shared/_omniauth_box.html.haml"
+ - "app/views/devise/shared/_sign_in_link.html.haml"
+ - "app/views/devise/shared/_signup_box.html.haml"
+ - "app/views/devise/shared/_tabs_normal.html.haml"
+ - "app/views/discussions/_discussion.html.haml"
+ - "app/views/discussions/_headline.html.haml"
+ - "app/views/discussions/_notes.html.haml"
+ - "app/views/discussions/_resolve_all.html.haml"
+ - "app/views/doorkeeper/applications/_delete_form.html.haml"
+ - "app/views/doorkeeper/authorized_applications/_delete_form.html.haml"
+ - "app/views/errors/encoding.html.haml"
+ - "app/views/errors/git_not_found.html.haml"
+ - "app/views/errors/omniauth_error.html.haml"
+ - "app/views/errors/precondition_failed.html.haml"
+ - "app/views/events/_commit.html.haml"
+ - "app/views/events/_event_push.atom.haml"
+ - "app/views/events/event/_push.html.haml"
+ - "app/views/groups/_create_chat_team.html.haml"
+ - "app/views/groups/_group_admin_settings.html.haml"
+ - "app/views/groups/group_members/_new_group_member.html.haml"
+ - "app/views/groups/group_members/index.html.haml"
+ - "app/views/groups/labels/edit.html.haml"
+ - "app/views/groups/labels/new.html.haml"
+ - "app/views/groups/milestones/edit.html.haml"
+ - "app/views/groups/milestones/index.html.haml"
+ - "app/views/groups/milestones/new.html.haml"
+ - "app/views/groups/projects.html.haml"
+ - "app/views/groups/runners/edit.html.haml"
+ - "app/views/groups/settings/_advanced.html.haml"
+ - "app/views/groups/settings/_lfs.html.haml"
+ - "app/views/help/_shortcuts.html.haml"
+ - "app/views/help/index.html.haml"
+ - "app/views/help/instance_configuration.html.haml"
+ - "app/views/help/instance_configuration/_gitlab_ci.html.haml"
+ - "app/views/help/instance_configuration/_gitlab_pages.html.haml"
+ - "app/views/help/instance_configuration/_ssh_info.html.haml"
+ - "app/views/help/ui.html.haml"
+ - "app/views/import/bitbucket/status.html.haml"
+ - "app/views/import/bitbucket_server/status.html.haml"
+ - "app/views/instance_statistics/cohorts/_cohorts_table.html.haml"
+ - "app/views/instance_statistics/cohorts/_usage_ping.html.haml"
+ - "app/views/invites/show.html.haml"
+ - "app/views/layouts/_mailer.html.haml"
+ - "app/views/layouts/header/_default.html.haml"
+ - "app/views/layouts/header/_new_dropdown.haml"
+ - "app/views/layouts/mailer/devise.html.haml"
+ - "app/views/layouts/nav/sidebar/_profile.html.haml"
+ - "app/views/layouts/notify.html.haml"
+ - "app/views/notify/_failed_builds.html.haml"
+ - "app/views/notify/_reassigned_issuable_email.html.haml"
+ - "app/views/notify/_removal_notification.html.haml"
+ - "app/views/notify/autodevops_disabled_email.html.haml"
+ - "app/views/notify/changed_milestone_email.html.haml"
+ - "app/views/notify/import_issues_csv_email.html.haml"
+ - "app/views/notify/issue_moved_email.html.haml"
+ - "app/views/notify/member_access_denied_email.html.haml"
+ - "app/views/notify/member_invite_accepted_email.html.haml"
+ - "app/views/notify/member_invite_declined_email.html.haml"
+ - "app/views/notify/member_invited_email.html.haml"
+ - "app/views/notify/new_gpg_key_email.html.haml"
+ - "app/views/notify/new_mention_in_issue_email.html.haml"
+ - "app/views/notify/new_ssh_key_email.html.haml"
+ - "app/views/notify/new_user_email.html.haml"
+ - "app/views/notify/pages_domain_disabled_email.html.haml"
+ - "app/views/notify/pages_domain_enabled_email.html.haml"
+ - "app/views/notify/pages_domain_verification_failed_email.html.haml"
+ - "app/views/notify/pages_domain_verification_succeeded_email.html.haml"
+ - "app/views/notify/pipeline_failed_email.html.haml"
+ - "app/views/notify/pipeline_success_email.html.haml"
+ - "app/views/notify/project_was_exported_email.html.haml"
+ - "app/views/notify/project_was_moved_email.html.haml"
+ - "app/views/notify/project_was_not_exported_email.html.haml"
+ - "app/views/notify/push_to_merge_request_email.html.haml"
+ - "app/views/notify/remote_mirror_update_failed_email.html.haml"
+ - "app/views/notify/removed_milestone_issue_email.html.haml"
+ - "app/views/notify/removed_milestone_merge_request_email.html.haml"
+ - "app/views/notify/repository_push_email.html.haml"
+ - "app/views/peek/views/_gc.html.haml"
+ - "app/views/peek/views/_redis.html.haml"
+ - "app/views/peek/views/_sidekiq.html.haml"
+ - "app/views/profiles/_event_table.html.haml"
+ - "app/views/profiles/active_sessions/_active_session.html.haml"
+ - "app/views/profiles/active_sessions/index.html.haml"
+ - "app/views/profiles/audit_log.html.haml"
+ - "app/views/profiles/chat_names/_chat_name.html.haml"
+ - "app/views/profiles/chat_names/index.html.haml"
+ - "app/views/profiles/chat_names/new.html.haml"
+ - "app/views/profiles/emails/index.html.haml"
+ - "app/views/profiles/gpg_keys/_key.html.haml"
+ - "app/views/profiles/gpg_keys/index.html.haml"
+ - "app/views/profiles/keys/_key.html.haml"
+ - "app/views/profiles/keys/_key_details.html.haml"
+ - "app/views/profiles/keys/index.html.haml"
+ - "app/views/profiles/notifications/show.html.haml"
+ - "app/views/profiles/passwords/edit.html.haml"
+ - "app/views/profiles/personal_access_tokens/index.html.haml"
+ - "app/views/profiles/preferences/show.html.haml"
+ - "app/views/profiles/show.html.haml"
+ - "app/views/profiles/two_factor_auths/_codes.html.haml"
+ - "app/views/profiles/two_factor_auths/codes.html.haml"
+ - "app/views/profiles/two_factor_auths/create.html.haml"
+ - "app/views/profiles/two_factor_auths/show.html.haml"
+ - "app/views/projects/_bitbucket_import_modal.html.haml"
+ - "app/views/projects/_customize_workflow.html.haml"
+ - "app/views/projects/_deletion_failed.html.haml"
+ - "app/views/projects/_fork_suggestion.html.haml"
+ - "app/views/projects/_gitlab_import_modal.html.haml"
+ - "app/views/projects/_home_panel.html.haml"
+ - "app/views/projects/_import_project_pane.html.haml"
+ - "app/views/projects/_issuable_by_email.html.haml"
+ - "app/views/projects/_md_preview.html.haml"
+ - "app/views/projects/_new_project_fields.html.haml"
+ - "app/views/projects/_readme.html.haml"
+ - "app/views/projects/artifacts/_tree_file.html.haml"
+ - "app/views/projects/artifacts/browse.html.haml"
+ - "app/views/projects/blame/_age_map_legend.html.haml"
+ - "app/views/projects/blame/show.html.haml"
+ - "app/views/projects/blob/_editor.html.haml"
+ - "app/views/projects/blob/_header_content.html.haml"
+ - "app/views/projects/blob/_new_dir.html.haml"
+ - "app/views/projects/blob/_remove.html.haml"
+ - "app/views/projects/blob/_render_error.html.haml"
+ - "app/views/projects/blob/_template_selectors.html.haml"
+ - "app/views/projects/blob/_upload.html.haml"
+ - "app/views/projects/blob/edit.html.haml"
+ - "app/views/projects/blob/new.html.haml"
+ - "app/views/projects/blob/preview.html.haml"
+ - "app/views/projects/blob/viewers/_empty.html.haml"
+ - "app/views/projects/blob/viewers/_stl.html.haml"
+ - "app/views/projects/branches/_branch.html.haml"
+ - "app/views/projects/branches/_commit.html.haml"
+ - "app/views/projects/branches/_delete_protected_modal.html.haml"
+ - "app/views/projects/branches/new.html.haml"
+ - "app/views/projects/ci/builds/_build.html.haml"
+ - "app/views/projects/ci/lints/_create.html.haml"
+ - "app/views/projects/commit/_change.html.haml"
+ - "app/views/projects/commits/_commit.html.haml"
+ - "app/views/projects/commits/_inline_commit.html.haml"
+ - "app/views/projects/compare/_form.html.haml"
+ - "app/views/projects/compare/index.html.haml"
+ - "app/views/projects/cycle_analytics/_empty_stage.html.haml"
+ - "app/views/projects/cycle_analytics/_no_access.html.haml"
+ - "app/views/projects/cycle_analytics/_overview.html.haml"
+ - "app/views/projects/cycle_analytics/show.html.haml"
+ - "app/views/projects/deploy_keys/_form.html.haml"
+ - "app/views/projects/deploy_keys/_index.html.haml"
+ - "app/views/projects/deploy_keys/edit.html.haml"
+ - "app/views/projects/deploy_tokens/_revoke_modal.html.haml"
+ - "app/views/projects/deploy_tokens/_table.html.haml"
+ - "app/views/projects/deployments/_deployment.html.haml"
+ - "app/views/projects/diffs/_file_header.html.haml"
+ - "app/views/projects/diffs/_replaced_image_diff.html.haml"
+ - "app/views/projects/diffs/_stats.html.haml"
+ - "app/views/projects/empty.html.haml"
+ - "app/views/projects/environments/show.html.haml"
+ - "app/views/projects/forks/error.html.haml"
+ - "app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml"
+ - "app/views/projects/graphs/charts.html.haml"
+ - "app/views/projects/hook_logs/_index.html.haml"
+ - "app/views/projects/hook_logs/show.html.haml"
+ - "app/views/projects/hooks/_index.html.haml"
+ - "app/views/projects/hooks/edit.html.haml"
+ - "app/views/projects/imports/new.html.haml"
+ - "app/views/projects/imports/show.html.haml"
+ - "app/views/projects/issues/_issue.html.haml"
+ - "app/views/projects/issues/_new_branch.html.haml"
+ - "app/views/projects/issues/import_csv/_modal.html.haml"
+ - "app/views/projects/issues/show.html.haml"
+ - "app/views/projects/jobs/_header.html.haml"
+ - "app/views/projects/jobs/_table.html.haml"
+ - "app/views/projects/jobs/index.html.haml"
+ - "app/views/projects/labels/edit.html.haml"
+ - "app/views/projects/labels/new.html.haml"
+ - "app/views/projects/mattermosts/_no_teams.html.haml"
+ - "app/views/projects/mattermosts/_team_selection.html.haml"
+ - "app/views/projects/mattermosts/new.html.haml"
+ - "app/views/projects/merge_requests/_commits.html.haml"
+ - "app/views/projects/merge_requests/_discussion.html.haml"
+ - "app/views/projects/merge_requests/_how_to_merge.html.haml"
+ - "app/views/projects/merge_requests/_merge_request.html.haml"
+ - "app/views/projects/merge_requests/_mr_title.html.haml"
+ - "app/views/projects/merge_requests/conflicts/_commit_stats.html.haml"
+ - "app/views/projects/merge_requests/conflicts/_file_actions.html.haml"
+ - "app/views/projects/merge_requests/conflicts/_submit_form.html.haml"
+ - "app/views/projects/merge_requests/conflicts/components/_diff_file_editor.html.haml"
+ - "app/views/projects/merge_requests/conflicts/components/_inline_conflict_lines.html.haml"
+ - "app/views/projects/merge_requests/conflicts/show.html.haml"
+ - "app/views/projects/merge_requests/creations/_diffs.html.haml"
+ - "app/views/projects/merge_requests/creations/_new_compare.html.haml"
+ - "app/views/projects/merge_requests/creations/_new_submit.html.haml"
+ - "app/views/projects/merge_requests/diffs/_different_base.html.haml"
+ - "app/views/projects/merge_requests/diffs/_diffs.html.haml"
+ - "app/views/projects/merge_requests/diffs/_version_controls.html.haml"
+ - "app/views/projects/merge_requests/invalid.html.haml"
+ - "app/views/projects/merge_requests/widget/open/_error.html.haml"
+ - "app/views/projects/mirrors/_regenerate_public_ssh_key_confirm_modal.html.haml"
+ - "app/views/projects/mirrors/_ssh_host_keys.html.haml"
+ - "app/views/projects/new.html.haml"
+ - "app/views/projects/no_repo.html.haml"
+ - "app/views/projects/pages/_access.html.haml"
+ - "app/views/projects/pages/_destroy.haml"
+ - "app/views/projects/pages/_https_only.html.haml"
+ - "app/views/projects/pages/_list.html.haml"
+ - "app/views/projects/pages/_no_domains.html.haml"
+ - "app/views/projects/pages/_use.html.haml"
+ - "app/views/projects/pages/show.html.haml"
+ - "app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml"
+ - "app/views/projects/pipelines/_info.html.haml"
+ - "app/views/projects/pipelines/charts/_pipelines.haml"
+ - "app/views/projects/protected_branches/shared/_branches_list.html.haml"
+ - "app/views/projects/protected_branches/shared/_create_protected_branch.html.haml"
+ - "app/views/projects/protected_branches/shared/_dropdown.html.haml"
+ - "app/views/projects/protected_branches/shared/_index.html.haml"
+ - "app/views/projects/protected_branches/shared/_matching_branch.html.haml"
+ - "app/views/projects/protected_branches/shared/_protected_branch.html.haml"
+ - "app/views/projects/protected_branches/show.html.haml"
+ - "app/views/projects/protected_tags/shared/_create_protected_tag.html.haml"
+ - "app/views/projects/protected_tags/shared/_dropdown.html.haml"
+ - "app/views/projects/protected_tags/shared/_index.html.haml"
+ - "app/views/projects/protected_tags/shared/_matching_tag.html.haml"
+ - "app/views/projects/protected_tags/shared/_protected_tag.html.haml"
+ - "app/views/projects/protected_tags/shared/_tags_list.html.haml"
+ - "app/views/projects/protected_tags/show.html.haml"
+ - "app/views/projects/registry/repositories/_tag.html.haml"
+ - "app/views/projects/repositories/_feed.html.haml"
+ - "app/views/projects/runners/_shared_runners.html.haml"
+ - "app/views/projects/runners/edit.html.haml"
+ - "app/views/projects/services/_form.html.haml"
+ - "app/views/projects/services/_index.html.haml"
+ - "app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml"
+ - "app/views/projects/services/mattermost_slash_commands/_help.html.haml"
+ - "app/views/projects/services/prometheus/_metrics.html.haml"
+ - "app/views/projects/services/slack_slash_commands/_help.html.haml"
+ - "app/views/projects/settings/ci_cd/_badge.html.haml"
+ - "app/views/projects/settings/ci_cd/_form.html.haml"
+ - "app/views/projects/stage/_stage.html.haml"
+ - "app/views/projects/tags/index.html.haml"
+ - "app/views/projects/tags/new.html.haml"
+ - "app/views/projects/tags/releases/edit.html.haml"
+ - "app/views/projects/tree/_tree_row.html.haml"
+ - "app/views/projects/tree/_truncated_notice_tree_row.html.haml"
+ - "app/views/projects/triggers/_content.html.haml"
+ - "app/views/projects/triggers/_form.html.haml"
+ - "app/views/projects/triggers/_index.html.haml"
+ - "app/views/projects/triggers/_trigger.html.haml"
+ - "app/views/projects/triggers/edit.html.haml"
+ - "app/views/projects/wikis/_new.html.haml"
+ - "app/views/projects/wikis/_pages_wiki_page.html.haml"
+ - "app/views/projects/wikis/edit.html.haml"
+ - "app/views/projects/wikis/history.html.haml"
+ - "app/views/repository_check_mailer/notify.html.haml"
+ - "app/views/search/_form.html.haml"
+ - "app/views/search/results/_issue.html.haml"
+ - "app/views/search/results/_note.html.haml"
+ - "app/views/search/results/_snippet_blob.html.haml"
+ - "app/views/search/results/_snippet_title.html.haml"
+ - "app/views/shared/_auto_devops_implicitly_enabled_banner.html.haml"
+ - "app/views/shared/_commit_message_container.html.haml"
+ - "app/views/shared/_confirm_modal.html.haml"
+ - "app/views/shared/_delete_label_modal.html.haml"
+ - "app/views/shared/_group_form.html.haml"
+ - "app/views/shared/_group_tips.html.haml"
+ - "app/views/shared/_milestone_expired.html.haml"
+ - "app/views/shared/_no_password.html.haml"
+ - "app/views/shared/_no_ssh.html.haml"
+ - "app/views/shared/_outdated_browser.html.haml"
+ - "app/views/shared/_personal_access_tokens_created_container.html.haml"
+ - "app/views/shared/_personal_access_tokens_table.html.haml"
+ - "app/views/shared/_ping_consent.html.haml"
+ - "app/views/shared/_project_limit.html.haml"
+ - "app/views/shared/_service_settings.html.haml"
+ - "app/views/shared/boards/components/_board.html.haml"
+ - "app/views/shared/boards/components/_sidebar.html.haml"
+ - "app/views/shared/boards/components/sidebar/_due_date.html.haml"
+ - "app/views/shared/boards/components/sidebar/_labels.html.haml"
+ - "app/views/shared/boards/components/sidebar/_milestone.html.haml"
+ - "app/views/shared/empty_states/_priority_labels.html.haml"
+ - "app/views/shared/hook_logs/_content.html.haml"
+ - "app/views/shared/issuable/_assignees.html.haml"
+ - "app/views/shared/issuable/_board_create_list_dropdown.html.haml"
+ - "app/views/shared/issuable/_bulk_update_sidebar.html.haml"
+ - "app/views/shared/issuable/_close_reopen_report_toggle.html.haml"
+ - "app/views/shared/issuable/_form.html.haml"
+ - "app/views/shared/issuable/_search_bar.html.haml"
+ - "app/views/shared/issuable/_sidebar.html.haml"
+ - "app/views/shared/issuable/form/_default_templates.html.haml"
+ - "app/views/shared/issuable/form/_issue_assignee.html.haml"
+ - "app/views/shared/issuable/form/_template_selector.html.haml"
+ - "app/views/shared/issuable/form/_title.html.haml"
+ - "app/views/shared/labels/_form.html.haml"
+ - "app/views/shared/members/_member.html.haml"
+ - "app/views/shared/milestones/_form_dates.html.haml"
+ - "app/views/shared/milestones/_issuable.html.haml"
+ - "app/views/shared/milestones/_milestone.html.haml"
+ - "app/views/shared/milestones/_sidebar.html.haml"
+ - "app/views/shared/milestones/_top.html.haml"
+ - "app/views/shared/notes/_hints.html.haml"
+ - "app/views/shared/notes/_note.html.haml"
+ - "app/views/shared/notifications/_button.html.haml"
+ - "app/views/shared/notifications/_custom_notifications.html.haml"
+ - "app/views/shared/notifications/_new_button.html.haml"
+ - "app/views/shared/notifications/_notification_dropdown.html.haml"
+ - "app/views/shared/plugins/_index.html.haml"
+ - "app/views/shared/projects/_dropdown.html.haml"
+ - "app/views/shared/projects/_list.html.haml"
+ - "app/views/shared/projects/_project.html.haml"
+ - "app/views/shared/runners/_runner_description.html.haml"
+ - "app/views/shared/runners/show.html.haml"
+ - "app/views/shared/snippets/_embed.html.haml"
+ - "app/views/shared/snippets/_header.html.haml"
+ - "app/views/shared/snippets/_snippet.html.haml"
+ - "app/views/shared/tokens/_scopes_list.html.haml"
+ - "app/views/shared/web_hooks/_form.html.haml"
+ - "app/views/shared/web_hooks/_test_button.html.haml"
+ - "app/views/u2f/_authenticate.html.haml"
+ - "app/views/u2f/_register.html.haml"
+ - "app/views/users/_deletion_guidance.html.haml"
+ - "ee/app/views/admin/_namespace_plan_info.html.haml"
+ - "ee/app/views/admin/application_settings/_elasticsearch_form.html.haml"
+ - "ee/app/views/admin/application_settings/_slack.html.haml"
+ - "ee/app/views/admin/application_settings/_snowplow.html.haml"
+ - "ee/app/views/admin/application_settings/_templates.html.haml"
+ - "ee/app/views/admin/audit_logs/index.html.haml"
+ - "ee/app/views/admin/dashboard/stats.html.haml"
+ - "ee/app/views/admin/emails/show.html.haml"
+ - "ee/app/views/admin/geo/nodes/edit.html.haml"
+ - "ee/app/views/admin/geo/nodes/new.html.haml"
+ - "ee/app/views/admin/geo/projects/_registry_failed.html.haml"
+ - "ee/app/views/admin/geo/projects/_registry_never.html.haml"
+ - "ee/app/views/admin/licenses/_breakdown.html.haml"
+ - "ee/app/views/admin/licenses/_upload_trial_license.html.haml"
+ - "ee/app/views/admin/licenses/missing.html.haml"
+ - "ee/app/views/admin/licenses/new.html.haml"
+ - "ee/app/views/admin/licenses/show.html.haml"
+ - "ee/app/views/admin/monitoring/ee/_nav.html.haml"
+ - "ee/app/views/admin/projects/_shared_runner_status.html.haml"
+ - "ee/app/views/admin/push_rules/show.html.haml"
+ - "ee/app/views/admin/users/_limits.html.haml"
+ - "ee/app/views/admin/users/_user_detail_note.html.haml"
+ - "ee/app/views/dashboard/projects/_blank_state_ee_trial.html.haml"
+ - "ee/app/views/errors/kerberos_denied.html.haml"
+ - "ee/app/views/groups/analytics/show.html.haml"
+ - "ee/app/views/groups/audit_events/index.html.haml"
+ - "ee/app/views/groups/ee/_settings_nav.html.haml"
+ - "ee/app/views/groups/epics/_epic.html.haml"
+ - "ee/app/views/groups/group_members/_ldap_sync.html.haml"
+ - "ee/app/views/groups/group_members/_sync_button.html.haml"
+ - "ee/app/views/groups/hooks/_project_hook.html.haml"
+ - "ee/app/views/groups/hooks/index.html.haml"
+ - "ee/app/views/groups/ldap_group_links/index.html.haml"
+ - "ee/app/views/groups/pipeline_quota/index.html.haml"
+ - "ee/app/views/jira_connect/subscriptions/index.html.haml"
+ - "ee/app/views/layouts/jira_connect.html.haml"
+ - "ee/app/views/layouts/nav/ee/_epic_link.html.haml"
+ - "ee/app/views/layouts/nav/ee/admin/_new_monitoring_sidebar.html.haml"
+ - "ee/app/views/layouts/service_desk.html.haml"
+ - "ee/app/views/ldap_group_links/_form.html.haml"
+ - "ee/app/views/ldap_group_links/_ldap_group_link.html.haml"
+ - "ee/app/views/ldap_group_links/_ldap_group_links.html.haml"
+ - "ee/app/views/ldap_group_links/_ldap_group_links_show.html.haml"
+ - "ee/app/views/ldap_group_links/_ldap_group_links_synchronizations.html.haml"
+ - "ee/app/views/namespaces/_shared_runner_status.html.haml"
+ - "ee/app/views/namespaces/_shared_runners_minutes_setting.html.haml"
+ - "ee/app/views/namespaces/pipelines_quota/_extra_shared_runners_minutes_quota.html.haml"
+ - "ee/app/views/namespaces/pipelines_quota/_list.haml"
+ - "ee/app/views/notify/approved_merge_request_email.html.haml"
+ - "ee/app/views/notify/epic_status_changed_email.html.haml"
+ - "ee/app/views/notify/issues_csv_email.html.haml"
+ - "ee/app/views/notify/new_review_email.html.haml"
+ - "ee/app/views/notify/prometheus_alert_fired_email.html.haml"
+ - "ee/app/views/notify/send_admin_notification.html.haml"
+ - "ee/app/views/notify/send_unsubscribed_notification.html.haml"
+ - "ee/app/views/notify/unapproved_merge_request_email.html.haml"
+ - "ee/app/views/oauth/geo_auth/error.html.haml"
+ - "ee/app/views/profiles/pipeline_quota/index.haml"
+ - "ee/app/views/projects/audit_events/index.html.haml"
+ - "ee/app/views/projects/blob/_owners.html.haml"
+ - "ee/app/views/projects/commits/_mirror_status.html.haml"
+ - "ee/app/views/projects/feature_flags/_configure_feature_flags_modal.html.haml"
+ - "ee/app/views/projects/issues/_issue_weight.html.haml"
+ - "ee/app/views/projects/issues/_related_issues.html.haml"
+ - "ee/app/views/projects/issues/export_csv/_modal.html.haml"
+ - "ee/app/views/projects/jobs/_shared_runner_limit_warning.html.haml"
+ - "ee/app/views/projects/merge_requests/_approvals_count.html.haml"
+ - "ee/app/views/projects/merge_requests/widget/open/_geo.html.haml"
+ - "ee/app/views/projects/mirrors/_mirrored_repositories_count.html.haml"
+ - "ee/app/views/projects/protected_branches/ee/_create_protected_branch.html.haml"
+ - "ee/app/views/projects/protected_branches/ee/_dropdown.html.haml"
+ - "ee/app/views/projects/protected_branches/ee/_fallback_update_protected_branch.html.haml"
+ - "ee/app/views/projects/protected_tags/_protected_tag_extra_create_access_levels.haml"
+ - "ee/app/views/projects/protected_tags/ee/_create_protected_tag.html.haml"
+ - "ee/app/views/projects/push_rules/_index.html.haml"
+ - "ee/app/views/projects/services/gitlab_slack_application/_help.html.haml"
+ - "ee/app/views/projects/services/gitlab_slack_application/_slack_integration_form.html.haml"
+ - "ee/app/views/projects/services/prometheus/_metrics.html.haml"
+ - "ee/app/views/projects/settings/slacks/edit.html.haml"
+ - "ee/app/views/shared/_additional_email_text.html.haml"
+ - "ee/app/views/shared/_geo_info_modal.html.haml"
+ - "ee/app/views/shared/_mirror_update_button.html.haml"
+ - "ee/app/views/shared/_shared_runners_minutes_limit.html.haml"
+ - "ee/app/views/shared/audit_events/_event_table.html.haml"
+ - "ee/app/views/shared/boards/components/_list_weight.html.haml"
+ - "ee/app/views/shared/boards/components/sidebar/_epic.html.haml"
+ - "ee/app/views/shared/ee/_import_form.html.haml"
+ - "ee/app/views/shared/epic/_search_bar.html.haml"
+ - "ee/app/views/shared/issuable/_approvals.html.haml"
+ - "ee/app/views/shared/issuable/_board_create_list_dropdown.html.haml"
+ - "ee/app/views/shared/issuable/_filter_weight.html.haml"
+ - "ee/app/views/shared/issuable/_sidebar_item_epic.haml"
+ - "ee/app/views/shared/members/ee/_ldap_tag.html.haml"
+ - "ee/app/views/shared/members/ee/_override_member_buttons.html.haml"
+ - "ee/app/views/shared/members/ee/_sso_badge.html.haml"
+ - "ee/app/views/shared/milestones/_burndown.html.haml"
+ - "ee/app/views/shared/milestones/_weight.html.haml"
+ - "ee/app/views/shared/promotions/_promote_audit_events.html.haml"
+ - "ee/app/views/shared/promotions/_promote_burndown_charts.html.haml"
+ - "ee/app/views/shared/promotions/_promote_csv_export.html.haml"
+ - "ee/app/views/shared/promotions/_promote_issue_weights.html.haml"
+ - "ee/app/views/shared/promotions/_promote_repository_features.html.haml"
+ - "ee/app/views/shared/promotions/_promote_servicedesk.html.haml"
+ - "ee/app/views/shared/push_rules/_form.html.haml"
+ - "ee/app/views/unsubscribes/show.html.haml"
+ - "ee/app/views/admin/users/_auditor_access_level_radio.html.haml"
+ - "ee/app/views/admin/users/_auditor_user_badge.html.haml"
+ - "ee/app/views/projects/protected_branches/_update_protected_branch.html.haml"
diff --git a/lib/haml_lint/linter/no_plain_nodes.rb b/lib/haml_lint/linter/no_plain_nodes.rb
new file mode 100644
index 00000000000..d5cea0d07cf
--- /dev/null
+++ b/lib/haml_lint/linter/no_plain_nodes.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'active_support/core_ext/array/grouping'
+
+module HamlLint
+ class Linter
+ class NoPlainNodes < Linter
+ include LinterRegistry
+
+ def visit_tag(node)
+ if inline_plain_node?(node)
+ check_inline(node)
+ elsif !node.script.empty?
+ check_script(node)
+ else
+ check(node)
+ end
+ end
+
+ private
+
+ def check(node)
+ text_in_node(node).each { |string| record(node, string) }
+ end
+
+ def check_inline(node)
+ text = inline_text(node)
+ record(node, text) unless text.empty?
+ end
+
+ def check_script(node)
+ text = inline_text(node)
+ record(node, text) unless text.start_with?('=') || text.empty?
+ end
+
+ # Build an array of all strings in child text nodes.
+ # non text nodes are nil, where we'll split the sentences.
+ def text_in_node(node)
+ texts = node.children.map do |child|
+ child.text.strip if text_node?(child)
+ end
+
+ texts.split(nil).map { |sentence| sentence.join(' ') unless sentence.empty? }.compact
+ end
+
+ # Removes a node's attributes and tag from the source code,
+ # returning the inline text of a node.
+ def inline_text(node)
+ text = node.source_code.gsub("%#{node.tag_name}", '')
+
+ attributes = node.attributes_source.map(&:last)
+ attributes.each { |attribute| text = text.gsub(attribute, '') }
+
+ text.strip
+ end
+
+ def record(node, string)
+ record_lint(node, message(string))
+ end
+
+ def message(string)
+ "`#{string}` is a plain node. Please use an i18n method like `#{fixed(string)}`"
+ end
+
+ def fixed(string)
+ "= _('#{string}')"
+ end
+
+ def inline_plain_node?(node)
+ node.children.empty? && node.script.empty?
+ end
+
+ def plain_node?(node)
+ node.is_a?(::HamlLint::Tree::PlainNode)
+ end
+
+ def text_node?(node)
+ return false unless plain_node?(node)
+
+ !node.text.empty?
+ end
+ end
+ end
+end
diff --git a/spec/lib/haml_lint/linter/no_plain_nodes_spec.rb b/spec/lib/haml_lint/linter/no_plain_nodes_spec.rb
new file mode 100644
index 00000000000..99cc9b9bc8d
--- /dev/null
+++ b/spec/lib/haml_lint/linter/no_plain_nodes_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'haml_lint'
+require 'haml_lint/spec'
+
+describe HamlLint::Linter::NoPlainNodes do
+ include_context 'linter'
+
+ context 'reports when a tag has an inline plain node' do
+ let(:haml) { '%tag Hello Tanuki' }
+ let(:message) { "`Hello Tanuki` is a plain node. Please use an i18n method like `= _('Hello Tanuki')`" }
+
+ it { is_expected.to report_lint message: message }
+ end
+
+ context 'reports when a tag has multiline plain nodes' do
+ let(:haml) { <<-HAML }
+ %tag
+ Hello
+ Tanuki
+ HAML
+
+ it { is_expected.to report_lint count: 1 }
+ end
+
+ context 'reports when a tag has an inline plain node with interpolation' do
+ let(:haml) { '%tag Hello #{"Tanuki"}!' } # rubocop:disable Lint/InterpolationCheck
+
+ it { is_expected.to report_lint }
+ end
+
+ context 'does not report when a tag has an inline script' do
+ let(:haml) { '%tag= "Hello Tanuki"' }
+
+ it { is_expected.not_to report_lint }
+ end
+
+ context 'does not report when a tag is empty' do
+ let(:haml) { '%tag' }
+
+ it { is_expected.not_to report_lint }
+ end
+
+ context 'reports multiple when a tag has multiline plain nodes split by non-text nodes' do
+ let(:haml) { <<-HAML }
+ %tag
+ Hello
+ .split-node There
+ Tanuki
+ HAML
+
+ it { is_expected.to report_lint count: 3 }
+ end
+end